diff --git a/.gitignore b/.gitignore index e29a7d4..d441386 100644 --- a/.gitignore +++ b/.gitignore @@ -136,3 +136,5 @@ wecom-it-desk-server-deploy.zip .workbuddy/logs/ .workbuddy/*.log .workbuddy/*.log.err +# workbuddy 记忆目录(个人上下文,不 入仓) +.workbuddy/memory/ diff --git a/README.md b/README.md index 25e0608..ce53283 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 企微 IT 智能服务台 (IT Smart Desk) +# 企微智能IT支持服务台 (IT Smart Desk) > **环境状态**: 预生产(独立主机,共享域名)→ 正式环境迁移 K8s > **维护者**: 税友集团 IT支持组(宋献) diff --git a/backend/app/api/agents.py b/backend/app/api/agents.py index 5de8486..2c73cab 100644 --- a/backend/app/api/agents.py +++ b/backend/app/api/agents.py @@ -36,6 +36,7 @@ from app.models.agent import Agent from app.schemas.agent import AgentLogin, AgentResponse, AgentStatusUpdate from app.services.wecom_service import WecomService from app.utils.response import AppException, ERR_UNAUTHORIZED, success_response +from app.utils.error_codes import ErrorCode # 速率限制器实例(与 main.py 共享同一配置) # 移除 env_file=None 参数:slowapi 0.1.9 不支持该参数 @@ -217,24 +218,18 @@ async def agent_login( logger.warning( f"企微API不可达,已注册坐席降级放行: user_id={body.user_id}" ) - # P1 修复: 降级放行时,如果 agent 有 password_hash 则必须验证本地密码 - if existing_agent and existing_agent.password_hash: + # P0 修复: 降级放行时,如果 agent 已设置密码则必须验证本地密码 + if existing_agent: + if existing_agent.password_hash is None: + # 已注册坐席但未设置密码,要求先设置密码 + raise AppException( + 1012, + "首次登录请先设置密码。管理后台 → 坐席管理 → 设置本地密码" + ) if not body.password: - raise AppException(1011, "请输入本地密码") + raise AppException(ErrorCode.AUTH_PASSWORD_WRONG, "请输入本地密码") if not bcrypt.checkpw(body.password.encode('utf-8'), existing_agent.password_hash.encode('utf-8')): - raise AppException(1011, "本地密码错误") - - # P0-#5: 本地密码认证(企微验证失败时的备用认证) - # 检查是否需要本地密码验证 - local_password_verified = False - if body.password and agent and agent.password_hash: - # 验证本地密码 - if bcrypt.checkpw(body.password.encode('utf-8'), agent.password_hash.encode('utf-8')): - local_password_verified = True - logger.info(f"本地密码验证通过: user_id={body.user_id}") - else: - # 本地密码错误,拒绝登录 - raise AppException(1011, "本地密码错误") + raise AppException(ErrorCode.AUTH_PASSWORD_WRONG, "本地密码错误") # 1. 查找或创建坐席记录 stmt = select(Agent).where(Agent.user_id == body.user_id) @@ -571,9 +566,11 @@ async def update_agent_password( # 如果已有旧密码,验证旧密码 if agent.password_hash: if not body.old_password: - raise AppException(1012, "请输入旧密码") + # 2026-06-15 修复: 改用专用 ErrorCode,避免与登录 1012 冲突 + raise AppException(ErrorCode.AUTH_OLD_PASSWORD_REQUIRED, "请输入旧密码") if not bcrypt.checkpw(body.old_password.encode('utf-8'), agent.password_hash.encode('utf-8')): - raise AppException(1013, "旧密码错误") + # 2026-06-15 修复: 改用专用 ErrorCode + raise AppException(ErrorCode.AUTH_OLD_PASSWORD_WRONG, "旧密码错误") # 设置新密码 agent.password_hash = bcrypt.hashpw(body.new_password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8') diff --git a/backend/app/api/approval.py b/backend/app/api/approval.py index 1966de4..cc3a635 100644 --- a/backend/app/api/approval.py +++ b/backend/app/api/approval.py @@ -16,23 +16,36 @@ router = APIRouter() # 审批模板配置(可配置化,后续可存入数据库) # ============================================================================= -# 企微审批模板配置 -APPROVAL_TEMPLATES = { - # 模板124 - 资源申请(跳转审批) - "Bs7ucTLPo42dtj8Y1LzBoujijsa6geRWaRxZJjk4X": { - "id": "Bs7ucTLPo42dtj8Y1LzBoujijsa6geRWaRxZJjk4X", +# ============================================================================= +# 企微审批模板配置(从环境变量读取) +# ============================================================================= +# 环境变量: +# APPROVAL_TEMPLATE_RESOURCE - 资源申请模板ID +# APPROVAL_TEMPLATE_DEVICE - 设备申请模板ID + +import os + +APPROVAL_TEMPLATE_RESOURCE = os.getenv("APPROVAL_TEMPLATE_RESOURCE", "") +APPROVAL_TEMPLATE_DEVICE = os.getenv("APPROVAL_TEMPLATE_DEVICE", "") + +# 动态构建审批模板配置 +APPROVAL_TEMPLATES = {} + +if APPROVAL_TEMPLATE_RESOURCE: + APPROVAL_TEMPLATES[APPROVAL_TEMPLATE_RESOURCE] = { + "id": APPROVAL_TEMPLATE_RESOURCE, "name": "资源申请", "type": "jump", # 跳转审批 "keywords": ["申请资源", "要资源", "申请"], - }, - # 模板122 - 设备申请(API提交) - "Bs7ucTGsPuFhxfk8pn8EydxrWxkVetB4JR8Pb6PHS": { - "id": "Bs7ucTGsPuFhxfk8pn8EydxrWxkVetB4JR8Pb6PHS", + } + +if APPROVAL_TEMPLATE_DEVICE: + APPROVAL_TEMPLATES[APPROVAL_TEMPLATE_DEVICE] = { + "id": APPROVAL_TEMPLATE_DEVICE, "name": "设备申请", "type": "api", # API提交 "keywords": ["申请设备", "要设备", "电脑", "笔记本"], - }, -} + } # ============================================================================= diff --git a/backend/app/config.py b/backend/app/config.py index bec15aa..41a73da 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -99,6 +99,14 @@ class Settings(BaseSettings): # 是否启用 Mock 登录(默认 false,生产环境必须关闭) mock_login_enabled: bool = False + # ---------------------------------------------------------------------- + # 审批模板配置(企微审批应用) + # ---------------------------------------------------------------------- + # 资源申请审批模板ID(在企微审批应用设置中获取) + approval_template_resource: str = "" + # 设备申请审批模板ID(在企微审批应用设置中获取) + approval_template_device: str = "" + # ---------------------------------------------------------------------- # Pydantic-settings 配置 # ---------------------------------------------------------------------- diff --git a/backend/app/main.py b/backend/app/main.py index 4720ebe..a8205f0 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -15,7 +15,9 @@ import logging from contextlib import asynccontextmanager from fastapi import FastAPI, Request +from fastapi.responses import JSONResponse from fastapi.middleware.cors import CORSMiddleware +from sqlalchemy import text # 导入配置(读取环境变量) from app.config import settings @@ -514,6 +516,79 @@ def create_app() -> FastAPI: """ return {"status": "ok", "service": "wecom-it-smart-desk"} + @app.get("/ready", tags=["系统"]) + async def readiness_check(): + """就绪检查端点。 + + 检查服务依赖(DB + Redis),不调用企微 API(避免阻塞)。 + 用于 K8s readinessProbe。 + """ + try: + # 检查数据库 + from app.database import engine + async with engine.connect() as conn: + await conn.execute(text("SELECT 1")) + db_status = "ok" + except Exception as e: + db_status = f"error: {str(e)}" + + try: + # 检查 Redis + from app.config import get_settings + settings = get_settings() + redis_client = settings.create_redis_client() + await redis_client.ping() + redis_status = "ok" + except Exception as e: + redis_status = f"error: {str(e)}" + + if db_status == "ok" and redis_status == "ok": + return {"status": "ready", "db": db_status, "redis": redis_status} + else: + return JSONResponse( + status_code=503, + content={"status": "not_ready", "db": db_status, "redis": redis_status} + ) + + @app.get("/metrics", tags=["系统"]) + async def metrics(): + """指标端点。 + + 返回服务运行指标,用于 Prometheus 采集。 + """ + import psutil + + return { + "status": "ok", + "metrics": { + "cpu_percent": psutil.cpu_percent(interval=0.1), + "memory_percent": psutil.virtual_memory().percent, + "disk_percent": psutil.disk_usage("/").percent, + } + } + + @app.get("/version", tags=["系统"]) + async def version(): + """版本信息端点。 + + 返回服务版本信息。 + """ + import subprocess + try: + git_hash = subprocess.check_output( + ["git", "rev-parse", "HEAD"], + cwd=app_root, + text=True + ).strip()[:8] + except Exception: + git_hash = "unknown" + + return { + "service": "wecom-it-smart-desk", + "version": "1.1.0", + "build": git_hash, + } + # ---------------------------------------------------------------------- # 打印所有已注册的路由(调试用) # ---------------------------------------------------------------------- diff --git a/backend/app/utils/error_codes.py b/backend/app/utils/error_codes.py new file mode 100644 index 0000000..2f6dcf7 --- /dev/null +++ b/backend/app/utils/error_codes.py @@ -0,0 +1,158 @@ +# ============================================================================= +# IT智能服务台 — 错误码定义 +# ============================================================================= +# 说明:统一管理系统错误码,便于前端解析和国际化 +# 格式:E{模块}{序号} +# ============================================================================= + +from enum import Enum + + +class ErrorCode(str, Enum): + """系统错误码枚举""" + + # -------------------------------------------------------------------------- + # 通用错误 (0xxx) + # -------------------------------------------------------------------------- + SUCCESS = "E0000" # 成功 + UNKNOWN_ERROR = "E0001" # 未知错误 + INVALID_PARAMETER = "E0002" # 参数错误 + MISSING_PARAMETER = "E0003" # 缺少参数 + NOT_FOUND = "E0004" # 资源不存在 + UNAUTHORIZED = "E0005" # 未授权 + FORBIDDEN = "E0006" # 禁止访问 + INTERNAL_ERROR = "E0007" # 内部错误 + SERVICE_UNAVAILABLE = "E0008" # 服务不可用 + TIMEOUT = "E0009" # 请求超时 + + # -------------------------------------------------------------------------- + # 认证相关 (1xxx) + # -------------------------------------------------------------------------- + AUTH_FAILED = "E1001" # 认证失败 + AUTH_TOKEN_EXPIRED = "E1002" # Token过期 + AUTH_TOKEN_INVALID = "E1003" # Token无效 + AUTH_PASSWORD_REQUIRED = "E1012" # 登录:首次登录请先设置密码 + AUTH_PASSWORD_WRONG = "E1011" # 登录:本地密码错误 + AUTH_OLD_PASSWORD_REQUIRED = "E1015" # 改密:请输入旧密码(2026-06-15 WB反馈 1012 上下文冲突后拆分) + AUTH_OLD_PASSWORD_WRONG = "E1016" # 改密:旧密码错误(2026-06-15 拆分) + + # -------------------------------------------------------------------------- + # 企微API错误 (2xxx) + # -------------------------------------------------------------------------- + WECOM_API_ERROR = "E2001" # 企微API调用失败 + WECOM_API_TIMEOUT = "E2002" # 企微API超时 + WECOM_TOKEN_INVALID = "E2003" # 企微token无效 + WECOM_USER_NOT_FOUND = "E2004" # 企微用户不存在 + + # -------------------------------------------------------------------------- + # 会话/消息错误 (3xxx) + # -------------------------------------------------------------------------- + CONVERSATION_NOT_FOUND = "E3001" # 会话不存在 + MESSAGE_NOT_FOUND = "E3002" # 消息不存在 + MESSAGE_TOO_LONG = "E3003" # 消息过长 + CONVERSATION_CLOSED = "E3004" # 会话已关闭 + + # -------------------------------------------------------------------------- + # 坐席错误 (4xxx) + # -------------------------------------------------------------------------- + AGENT_NOT_FOUND = "E4001" # 坐席不存在 + AGENT_OFFLINE = "E4002" # 坐席不在线 + AGENT_BUSY = "E4003" # 坐席忙碌 + AGENT_MAX_LOAD = "E4004" # 坐席已达最大接待量 + + # -------------------------------------------------------------------------- + # 审批错误 (5xxx) + # -------------------------------------------------------------------------- + APPROVAL_TEMPLATE_NOT_FOUND = "E5001" # 审批模板不存在 + APPROVAL_FAILED = "E5002" # 审批提交失败 + + # -------------------------------------------------------------------------- + # 文件上传错误 (6xxx) + # -------------------------------------------------------------------------- + FILE_TOO_LARGE = "E6001" # 文件过大 + FILE_TYPE_NOT_ALLOWED = "E6002" # 文件类型不允许 + FILE_UPLOAD_FAILED = "E6003" # 文件上传失败 + + +# 错误码到 HTTP 状态码的映射 +ERROR_CODE_TO_STATUS = { + ErrorCode.SUCCESS: 200, + ErrorCode.INVALID_PARAMETER: 400, + ErrorCode.MISSING_PARAMETER: 400, + ErrorCode.NOT_FOUND: 404, + ErrorCode.UNAUTHORIZED: 401, + ErrorCode.FORBIDDEN: 403, + ErrorCode.INTERNAL_ERROR: 500, + ErrorCode.SERVICE_UNAVAILABLE: 503, + # 认证 + ErrorCode.AUTH_FAILED: 401, + ErrorCode.AUTH_TOKEN_EXPIRED: 401, + ErrorCode.AUTH_TOKEN_INVALID: 401, + ErrorCode.AUTH_PASSWORD_REQUIRED: 401, + ErrorCode.AUTH_PASSWORD_WRONG: 401, + ErrorCode.AUTH_OLD_PASSWORD_REQUIRED: 400, + ErrorCode.AUTH_OLD_PASSWORD_WRONG: 400, + # 企微 + ErrorCode.WECOM_API_ERROR: 502, + ErrorCode.WECOM_API_TIMEOUT: 504, + ErrorCode.WECOM_TOKEN_INVALID: 401, + ErrorCode.WECOM_USER_NOT_FOUND: 404, + # 会话 + ErrorCode.CONVERSATION_NOT_FOUND: 404, + ErrorCode.MESSAGE_NOT_FOUND: 404, + ErrorCode.MESSAGE_TOO_LONG: 400, + ErrorCode.CONVERSATION_CLOSED: 400, + # 坐席 + ErrorCode.AGENT_NOT_FOUND: 404, + ErrorCode.AGENT_OFFLINE: 400, + ErrorCode.AGENT_BUSY: 400, + ErrorCode.AGENT_MAX_LOAD: 400, + # 审批 + ErrorCode.APPROVAL_TEMPLATE_NOT_FOUND: 404, + ErrorCode.APPROVAL_FAILED: 502, + # 文件 + ErrorCode.FILE_TOO_LARGE: 413, + ErrorCode.FILE_TYPE_NOT_ALLOWED: 400, + ErrorCode.FILE_UPLOAD_FAILED: 500, +} + + +def get_error_message(code: ErrorCode) -> str: + """获取错误码对应的默认消息""" + messages = { + ErrorCode.SUCCESS: "操作成功", + ErrorCode.UNKNOWN_ERROR: "未知错误,请稍后重试", + ErrorCode.INVALID_PARAMETER: "参数错误", + ErrorCode.MISSING_PARAMETER: "缺少必要参数", + ErrorCode.NOT_FOUND: "资源不存在", + ErrorCode.UNAUTHORIZED: "未授权,请先登录", + ErrorCode.FORBIDDEN: "禁止访问", + ErrorCode.INTERNAL_ERROR: "服务器内部错误", + ErrorCode.SERVICE_UNAVAILABLE: "服务暂时不可用", + ErrorCode.TIMEOUT: "请求超时", + ErrorCode.AUTH_FAILED: "认证失败", + ErrorCode.AUTH_TOKEN_EXPIRED: "登录已过期,请重新登录", + ErrorCode.AUTH_TOKEN_INVALID: "无效的登录凭证", + ErrorCode.AUTH_PASSWORD_REQUIRED: "首次登录请先设置密码", + ErrorCode.AUTH_PASSWORD_WRONG: "密码错误", + ErrorCode.AUTH_OLD_PASSWORD_REQUIRED: "请输入旧密码", + ErrorCode.AUTH_OLD_PASSWORD_WRONG: "旧密码错误", + ErrorCode.WECOM_API_ERROR: "企业微信服务异常", + ErrorCode.WECOM_API_TIMEOUT: "企业微信服务响应超时", + ErrorCode.WECOM_TOKEN_INVALID: "企业微信凭证无效", + ErrorCode.WECOM_USER_NOT_FOUND: "企业微信用户不存在", + ErrorCode.CONVERSATION_NOT_FOUND: "会话不存在", + ErrorCode.MESSAGE_NOT_FOUND: "消息不存在", + ErrorCode.MESSAGE_TOO_LONG: "消息内容过长", + ErrorCode.CONVERSATION_CLOSED: "会话已结束", + ErrorCode.AGENT_NOT_FOUND: "坐席不存在", + ErrorCode.AGENT_OFFLINE: "坐席不在线", + ErrorCode.AGENT_BUSY: "坐席忙碌中", + ErrorCode.AGENT_MAX_LOAD: "坐席已达到最大接待量", + ErrorCode.APPROVAL_TEMPLATE_NOT_FOUND: "审批模板不存在", + ErrorCode.APPROVAL_FAILED: "审批提交失败", + ErrorCode.FILE_TOO_LARGE: "文件过大", + ErrorCode.FILE_TYPE_NOT_ALLOWED: "不支持的文件类型", + ErrorCode.FILE_UPLOAD_FAILED: "文件上传失败", + } + return messages.get(code, "未知错误") diff --git a/backend/app/utils/logging_config.py b/backend/app/utils/logging_config.py new file mode 100644 index 0000000..05b98a2 --- /dev/null +++ b/backend/app/utils/logging_config.py @@ -0,0 +1,99 @@ +# ============================================================================= +# IT智能服务台 — 日志配置 +# ============================================================================= +# 说明:统一日志格式,支持 JSON 输出便于日志收集 +# ============================================================================= + +import json +import logging +import sys +from datetime import datetime +from typing import Any + + +class JSONFormatter(logging.Formatter): + """JSON 格式日志 formatter""" + + def format(self, record: logging.LogRecord) -> str: + """将日志记录格式化为 JSON""" + log_data: dict[str, Any] = { + "timestamp": datetime.utcnow().isoformat() + "Z", + "level": record.levelname, + "logger": record.name, + "message": record.getMessage(), + "module": record.module, + "function": record.funcName, + "line": record.lineno, + } + + # 添加异常信息 + if record.exc_info: + log_data["exception"] = self.formatException(record.exc_info) + + # 添加额外字段 + if hasattr(record, "request_id"): + log_data["request_id"] = record.request_id + if hasattr(record, "user_id"): + log_data["user_id"] = record.user_id + if hasattr(record, "extra"): + log_data.update(record.extra) + + return json.dumps(log_data, ensure_ascii=False) + + +class PlainFormatter(logging.Formatter): + """普通格式日志 formatter(开发环境使用)""" + + def __init__(self): + super().__init__( + fmt="%(asctime)s [%(levelname)s] %(name)s: %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + + +def setup_logging(level: str = "INFO", json_format: bool = False) -> None: + """配置日志系统 + + Args: + level: 日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL) + json_format: 是否使用 JSON 格式输出 + """ + log_level = getattr(logging, level.upper(), logging.INFO) + + # 获取 root logger + root_logger = logging.getLogger() + root_logger.setLevel(log_level) + + # 清除现有 handlers + for handler in root_logger.handlers[:]: + root_logger.removeHandler(handler) + + # 创建 console handler + console_handler = logging.StreamHandler(sys.stdout) + console_handler.setLevel(log_level) + + # 设置 formatter + if json_format: + formatter = JSONFormatter() + else: + formatter = PlainFormatter() + + console_handler.setFormatter(formatter) + root_logger.addHandler(console_handler) + + # 设置第三方库日志级别 + logging.getLogger("uvicorn").setLevel(logging.WARNING) + logging.getLogger("fastapi").setLevel(logging.WARNING) + logging.getLogger("sqlalchemy.engine").setLevel(logging.WARNING) + + +def get_logger(name: str) -> logging.Logger: + """获取 logger 实例 + + Args: + name: logger 名称,通常使用 __name__ + + Returns: + Logger 实例 + """ + return logging.getLogger(name) diff --git a/backend/requirements.txt b/backend/requirements.txt index d380190..693a37d 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -9,11 +9,11 @@ # Web 框架 # -------------------------------------------------------------------------- # FastAPI: 高性能异步 Web 框架,自动生成 Swagger API 文档 -fastapi==0.111.0 +fastapi==0.111.1 # Uvicorn: ASGI 服务器,支持热重载和 WebSocket uvicorn[standard]==0.30.1 # python-multipart: FastAPI 文件上传支持(处理 multipart/form-data 请求) -python-multipart==0.0.9 +python-multipart==0.0.12 # -------------------------------------------------------------------------- # 数据库 @@ -37,7 +37,7 @@ redis==5.0.7 # 数据验证 # -------------------------------------------------------------------------- # pydantic: 数据验证和设置管理,FastAPI 的核心依赖 -pydantic==2.7.4 +pydantic==2.7.5 # pydantic-settings: 从环境变量读取配置,支持 .env 文件 pydantic-settings==2.3.4 @@ -78,3 +78,9 @@ passlib[bcrypt]==1.7.4 qrcode[pil]==7.4.2 # pillow: 图片处理(qrcode[pil] 依赖) pillow==10.4.0 + +# -------------------------------------------------------------------------- +# 监控 +# -------------------------------------------------------------------------- +# psutil: 系统监控(用于 /metrics 端点) +psutil==5.9.8 diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py index e92ed21..cb32fca 100644 --- a/backend/tests/conftest.py +++ b/backend/tests/conftest.py @@ -33,6 +33,32 @@ from app.models.quick_reply_template import QuickReplyTemplate from app.models.agent_note import AgentNote +# ============================================================================= +# 2026-06-15 修复: monkey-patch starlette.config.Config 强制 UTF-8 读 .env +# 原因: Windows pytest 默认 GBK 读 .env 会 UnicodeDecodeError(0xb0 字节) +# 必须在 conftest 顶部应用,否则 reset_rate_limiter 等 autouse fixture +# 提前 import app 模块触发 .env 读取时会失败 +# ============================================================================= +import starlette.config as _starlette_config + + +def _read_file_utf8(self, file_name): + """强制以 UTF-8 编码读 .env,避免 Windows GBK 默认编码触发 UnicodeDecodeError。""" + result = {} + with open(file_name, encoding='utf-8') as f: + for line in f: + line = line.strip() + if not line or line.startswith('#'): + continue + if '=' in line: + k, v = line.split('=', 1) + result[k.strip()] = v.strip().strip('"').strip("'") + return result + + +_starlette_config.Config._read_file = _read_file_utf8 + + # ============================================================================= # SQLite 内存数据库引擎 # ============================================================================= @@ -184,6 +210,70 @@ def mock_redis() -> MockRedis: return MockRedis() +# ============================================================================= +# 模块级 Mock 外部服务(让子测试可覆盖其行为) +# ============================================================================= +# 2026-06-15 修复: 把 WecomService / AIService mock 提升到模块级 +# 原因: client fixture 内的局部 mock 无法被测试内 `with patch.object(...)` 覆盖 +# → 降级登录测试(需让企微 API "不可达")无法触发降级分支 +# 修复: 新增 mock_wecom_instance fixture,测试通过它改写 side_effect +# client fixture 改用模块级 mock,改写对当前请求立即生效 +# ============================================================================= +mock_wecom_module = AsyncMock() +mock_wecom_module.send_message.return_value = {"errcode": 0, "errmsg": "ok"} + + +async def _mock_get_user_info_default(user_id: str, **kwargs): + """默认的企微 get_user_info 行为:返回动态生成的用户名。 + + 测试可通过 mock_wecom_instance.get_user_info.side_effect = ... 改写。 + """ + return { + "user_id": user_id, + "name": f"用户{user_id}", + "department": "测试部", + "avatar": "", + } + + +mock_wecom_module.get_user_info.side_effect = _mock_get_user_info_default +mock_wecom_module.get_department_users.return_value = [] + +mock_ai_module = AsyncMock() +mock_ai_module.generate_response.return_value = "这是AI的模拟回复" + + +@pytest.fixture +def mock_wecom_instance(): + """暴露模块级 WecomService mock 实例,让测试可改写其行为(模拟降级等)。 + + 使用示例 — 触发降级登录路径: + async def fail(*args, **kwargs): + raise Exception("企微 API 不可达") + mock_wecom_instance.get_user_info.side_effect = fail + # ...发起请求后,用 try/finally 恢复原 side_effect + """ + return mock_wecom_module + + +@pytest.fixture(autouse=True) +def reset_rate_limiter(): + """每个测试前后重置 slowapi 限流器状态,避免 IP 限流干扰测试。 + + 背景: /agents/login 限流 10/min per IP,pytest 连续跑多个测试会撞 429。 + """ + from app.api.agents import limiter as agents_limiter + try: + agents_limiter._storage.reset() + except Exception: + pass + yield + try: + agents_limiter._storage.reset() + except Exception: + pass + + @pytest_asyncio.fixture async def client(db_session: AsyncSession, mock_redis: MockRedis) -> AsyncGenerator[AsyncClient, None]: """提供 FastAPI 异步测试客户端。""" @@ -194,6 +284,9 @@ async def client(db_session: AsyncSession, mock_redis: MockRedis) -> AsyncGenera async def _override_get_redis(): return mock_redis + # 注: 2026-06-15 UTF-8 monkey-patch 已提升到 conftest 模块级,见文件顶部 + # 原因: reset_rate_limiter 等 autouse fixture 提前 import 触发 .env 读取 + from app.main import create_app from app.database import get_db @@ -210,24 +303,11 @@ async def client(db_session: AsyncSession, mock_redis: MockRedis) -> AsyncGenera # 为什么:测试中不应调用真实企微API/AI大模型 # 怎么做:patch 类构造函数,返回配置了默认返回值的 mock 对象 # ------------------------------------------------------------------ - mock_wecom = AsyncMock() - # 企微消息发送:默认成功 - mock_wecom.send_message.return_value = {"errcode": 0, "errmsg": "ok"} - # 企微通讯录查询:动态返回(根据传入的 user_id 生成对应的名称) - # 为什么:坐席登录时会调用 get_user_info 获取员工姓名 - # 如果返回固定名字,登录接口会用 mock 名字覆盖请求中的 name 参数 - async def _mock_get_user_info(user_id: str, **kwargs): - return { - "user_id": user_id, - "name": f"用户{user_id}", - "department": "测试部", - "avatar": "", - } - mock_wecom.get_user_info.side_effect = _mock_get_user_info - mock_wecom.get_department_users.return_value = [] - - mock_ai = AsyncMock() - mock_ai.generate_response.return_value = "这是AI的模拟回复" + # 使用模块级 mock_wecom_module / mock_ai_module(2026-06-15 修复) + # 原因: 模块级 mock 允许测试通过 mock_wecom_instance fixture 改写行为 + # 例如降级登录测试改 side_effect = raise Exception("企微不可达") + mock_wecom = mock_wecom_module + mock_ai = mock_ai_module # Patch WecomService 类(端点函数中会新建实例) # 注意:只 patch 模块中实际引用的名字 diff --git a/backend/tests/test_agents.py b/backend/tests/test_agents.py new file mode 100644 index 0000000..1e1c608 --- /dev/null +++ b/backend/tests/test_agents.py @@ -0,0 +1,180 @@ +# ============================================================================= +# 企微智能IT支持服务台 — 坐席降级登录测试 +# ============================================================================= +# 覆盖 P0 修复 Fix-4: 企微 API 不可达时,已注册坐席必须验证本地密码 +# 创建日期: 2026-06-15 (Claude Code 补最小测试,因 WB 提交时未含此测试) +# ============================================================================= + +import pytest +import pytest_asyncio +from unittest.mock import AsyncMock, patch + +from app.models.agent import Agent +from app.utils.error_codes import ErrorCode +from tests.conftest import create_test_agent + + +class TestAgentDegradedLogin: + """P0 修复 Fix-4: 降级登录密码验证""" + + @pytest.mark.asyncio + async def test_degraded_login_wrong_password_rejected( + self, client, db_session, mock_redis, mock_wecom_instance + ): + """场景: 企微 API 不可达,坐席有 password_hash,登录用错密码 → 拒绝 + + 验证: + - 状态码非 200(或响应 code 非 0) + - 错误码属于 AUTH_PASSWORD_WRONG 类(1011 当前,2006 改完后) + """ + # 1. 预置坐席:有 password_hash + import bcrypt + + correct_pw = "CorrectP@ss123" + pw_hash = bcrypt.hashpw(correct_pw.encode("utf-8"), bcrypt.gensalt()).decode( + "utf-8" + ) + + agent = create_test_agent( + user_id="degraded_agent_001", + name="降级坐席", + ) + agent.password_hash = pw_hash + db_session.add(agent) + await db_session.flush() + + # 2. 改写 conftest 模块级 mock 行为,让企微 API 抛异常(降级场景触发) + original_side_effect = mock_wecom_instance.get_user_info.side_effect + + async def fail_get_user_info(*args, **kwargs): + raise Exception("企微 API 不可达 - 验证降级路径") + + mock_wecom_instance.get_user_info.side_effect = fail_get_user_info + + try: + # 3. 用错误密码登录 + response = await client.post( + "/agents/login", + json={ + "user_id": "degraded_agent_001", + "name": "降级坐席", + "password": "WrongPassword", + }, + ) + finally: + # 恢复默认 side_effect,避免污染后续测试 + mock_wecom_instance.get_user_info.side_effect = original_side_effect + + # 4. 断言:被拒绝 + assert response.status_code in (200, 401, 403), ( + f"预期被拒绝,实际 status={response.status_code}, body={response.text}" + ) + body = response.json() + # 业务 code 应该非 0 + assert body.get("code") != 0, f"预期失败 code,实际成功: {body}" + + # 错误码: WB 修复后是 AUTH_PASSWORD_WRONG=2006,旧码 1011 也接受 + error_code = body.get("code") + assert error_code in ( + ErrorCode.AUTH_PASSWORD_WRONG.value, # 2006 + 1011, # 旧数字码,WB 接入 ErrorCode 前的过渡 + ), f"错误码不匹配: {error_code}, body={body}" + + @pytest.mark.asyncio + async def test_degraded_login_no_password_blocked( + self, client, db_session, mock_redis, mock_wecom_instance + ): + """场景: 企微 API 不可达,坐席有 password_hash,登录不传密码 → 拒绝""" + # 1. 预置坐席 + import bcrypt + + pw_hash = bcrypt.hashpw(b"AnyP@ss", bcrypt.gensalt()).decode("utf-8") + agent = create_test_agent( + user_id="degraded_agent_002", + name="降级坐席2", + ) + agent.password_hash = pw_hash + db_session.add(agent) + await db_session.flush() + + # 2. 改写 conftest 模块级 mock,让企微 API 抛异常 + original_side_effect = mock_wecom_instance.get_user_info.side_effect + + async def fail_get_user_info(*args, **kwargs): + raise Exception("企微 API 不可达 - 验证降级路径") + + mock_wecom_instance.get_user_info.side_effect = fail_get_user_info + + try: + # 3. 不传 password 登录 + response = await client.post( + "/agents/login", + json={ + "user_id": "degraded_agent_002", + "name": "降级坐席2", + }, + ) + finally: + mock_wecom_instance.get_user_info.side_effect = original_side_effect + + # 4. 断言:被拒绝 + body = response.json() + assert body.get("code") != 0, f"预期被拒绝: {body}" + error_code = body.get("code") + # 2006 (AUTH_PASSWORD_WRONG) 或 1011 (旧码) + assert error_code in ( + ErrorCode.AUTH_PASSWORD_WRONG.value, + 1011, + ), f"错误码不匹配: {error_code}, body={body}" + + @pytest.mark.asyncio + async def test_degraded_login_correct_password_succeeds( + self, client, db_session, mock_redis, mock_wecom_instance + ): + """场景: 企微 API 不可达,坐席有 password_hash,登录用对密码 → 成功 + + 验证降级路径正常工作时,正确密码可以登录 + """ + import bcrypt + + correct_pw = "CorrectP@ss456" + pw_hash = bcrypt.hashpw(correct_pw.encode("utf-8"), bcrypt.gensalt()).decode( + "utf-8" + ) + + agent = create_test_agent( + user_id="degraded_agent_003", + name="降级坐席3", + ) + agent.password_hash = pw_hash + db_session.add(agent) + await db_session.flush() + + # 改写 conftest 模块级 mock,让企微 API 抛异常 + original_side_effect = mock_wecom_instance.get_user_info.side_effect + + async def fail_get_user_info(*args, **kwargs): + raise Exception("企微 API 不可达 - 验证降级路径") + + mock_wecom_instance.get_user_info.side_effect = fail_get_user_info + + try: + response = await client.post( + "/agents/login", + json={ + "user_id": "degraded_agent_003", + "name": "降级坐席3", + "password": correct_pw, + }, + ) + finally: + mock_wecom_instance.get_user_info.side_effect = original_side_effect + + # 降级 + 正确密码应能登录 + body = response.json() + assert body.get("code") == 0, ( + f"预期降级登录成功,实际失败: {body}" + ) + assert "token" in body.get("data", {}), ( + f"响应缺 token: {body}" + ) diff --git a/deploy-server/DEPLOY-GUIDE.md b/deploy-server/DEPLOY-GUIDE.md index b7a14c1..658363b 100644 --- a/deploy-server/DEPLOY-GUIDE.md +++ b/deploy-server/DEPLOY-GUIDE.md @@ -1,4 +1,4 @@ -# 企微IT智能服务台 — 服务器部署指南 +# 企微智能IT支持服务台 — 服务器部署指南 > 目标服务器:`10.90.5.110`(Linux) > 域名:`itsupport.servyou.com.cn` diff --git a/deploy-server/README.md b/deploy-server/README.md index 441641a..51ec67f 100644 --- a/deploy-server/README.md +++ b/deploy-server/README.md @@ -1,4 +1,4 @@ -# IT智能服务台 — 新服务器部署手册 +# 智能IT支持服务台 — 新服务器部署手册 > **目标服务器**:`10.80.0.136`(公司内网) > **域名**:`itsupport.servyou.com.cn` @@ -53,7 +53,7 @@ Host bastion Port 2222 User sxn -# IT智能服务台服务器 +# 智能IT支持服务台服务器 Host itdesk HostName 10.80.0.136 User sxn diff --git a/deploy-server/build-and-deploy.ps1 b/deploy-server/build-and-deploy.ps1 index fac8662..aa455df 100644 --- a/deploy-server/build-and-deploy.ps1 +++ b/deploy-server/build-and-deploy.ps1 @@ -1,5 +1,5 @@ # ============================================================================= -# 企微IT智能服务台 — 打包 + 构建后端镜像 + 部署脚本 +# 企微智能IT支持服务台 — 打包 + 构建后端镜像 + 部署脚本 # ============================================================================= # 功能: # 1. 打包前端构建产物 + nginx配置 + docker-compose.yml + .env @@ -51,7 +51,7 @@ function Write-Error { Write-Host "" Write-Host "========================================" -ForegroundColor Cyan -Write-Host " 企微IT智能服务台 — 打包部署自动化" -ForegroundColor Cyan +Write-Host " 企微智能IT支持服务台 — 打包部署自动化" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host " 模式:$Mode" -ForegroundColor White Write-Host "" diff --git a/deploy-server/build-package.ps1 b/deploy-server/build-package.ps1 index a120a71..d104592 100644 --- a/deploy-server/build-package.ps1 +++ b/deploy-server/build-package.ps1 @@ -1,5 +1,5 @@ # ============================================================================= -# 企微IT智能服务台 — 打包部署脚本 +# 企微智能IT支持服务台 — 打包部署脚本 # ============================================================================= # 功能:将所有部署所需文件打包成一个 zip 文件 # 用法:在 PowerShell 中运行此脚本 @@ -19,7 +19,7 @@ $packageDir = "$deployDir\_package" $zipFile = "$deployDir\it-smart-desk-server-deploy.zip" Write-Host "========================================" -ForegroundColor Cyan -Write-Host " 企微IT智能服务台 — 打包部署文件" -ForegroundColor Cyan +Write-Host " 企微智能IT支持服务台 — 打包部署文件" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" diff --git a/deploy-server/deploy-ragflow.sh b/deploy-server/deploy-ragflow.sh index 6542e51..10266a7 100644 --- a/deploy-server/deploy-ragflow.sh +++ b/deploy-server/deploy-ragflow.sh @@ -1,6 +1,6 @@ #!/bin/bash # ============================================================================= -# IT智能服务台 — RAGFlow 集成部署脚本 +# 智能IT支持服务台 — RAGFlow 集成部署脚本 # 目标服务器:10.90.5.110 # 部署路径:/opt/wecom-it-desk # ============================================================================= @@ -11,7 +11,7 @@ DEPLOY_DIR="/opt/wecom-it-desk" BACKUP_DIR="/opt/wecom-it-desk-backup-$(date +%Y%m%d_%H%M%S)" echo "==========================================" -echo "IT智能服务台 — RAGFlow 集成部署" +echo "智能IT支持服务台 — RAGFlow 集成部署" echo "时间: $(date)" echo "==========================================" diff --git a/deploy-server/deploy.sh b/deploy-server/deploy.sh index 5bd356a..055cf9b 100644 --- a/deploy-server/deploy.sh +++ b/deploy-server/deploy.sh @@ -1,6 +1,6 @@ #!/bin/bash # ============================================================================= -# IT智能服务台 — 生产部署脚本 +# 智能IT支持服务台 — 生产部署脚本 # 目标服务器:10.90.5.110 # 部署路径:/opt/wecom-it-desk # ============================================================================= @@ -11,7 +11,7 @@ DEPLOY_DIR="/opt/wecom-it-desk" BACKUP_DIR="/opt/wecom-it-desk-backup-$(date +%Y%m%d_%H%M%S)" echo "==========================================" -echo "IT智能服务台 生产部署" +echo "智能IT支持服务台 生产部署" echo "时间: $(date)" echo "==========================================" diff --git a/deploy-server/docker-compose.yml b/deploy-server/docker-compose.yml index c9a70ae..21eb809 100644 --- a/deploy-server/docker-compose.yml +++ b/deploy-server/docker-compose.yml @@ -1,5 +1,5 @@ # ============================================================================= -# 企微IT智能服务台 — Docker Compose(公司内网服务器版) +# 企微智能IT支持服务台 — Docker Compose(公司内网服务器版) # ============================================================================= # 目标服务器:10.90.5.110 # 域名:itsupport.servyou.com.cn diff --git a/deploy-server/nginx.conf b/deploy-server/nginx.conf index e14210d..0e326b8 100644 --- a/deploy-server/nginx.conf +++ b/deploy-server/nginx.conf @@ -1,5 +1,5 @@ # ============================================================================= -# 企微IT智能服务台 — Nginx 配置(公司内网服务器版 + HTTPS) +# 企微智能IT支持服务台 — Nginx 配置(公司内网服务器版 + HTTPS) # ============================================================================= # 目标服务器:10.90.5.110 # 域名:itsupport.servyou.com.cn @@ -47,6 +47,23 @@ http { application/javascript application/xml+rss application/json application/ld+json; + # ------------------------------------------------------------------ + # 安全响应头 + # ------------------------------------------------------------------ + # 隐藏 nginx 版本号 + server_tokens off; + + # 基础安全头(应用到所有响应) + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; + add_header X-Frame-Options "DENY" always; + add_header X-XSS-Protection "0" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always; + add_header Cross-Origin-Opener-Policy "same-origin" always; + + # API 路径特殊处理(不加 CSP,只加基础安全头) + # 前端路径的 CSP 在各前端 index.html 中单独配置 + # ================================================================= # 上游服务定义(Docker 内部网络) # ================================================================= diff --git a/deploy-server/nginx/nginx.conf b/deploy-server/nginx/nginx.conf index 379be9c..23ae517 100644 --- a/deploy-server/nginx/nginx.conf +++ b/deploy-server/nginx/nginx.conf @@ -1,5 +1,5 @@ # ============================================================================= -# 企微IT智能服务台 — Nginx 配置(公司内网服务器版) +# 企微智能IT支持服务台 — Nginx 配置(公司内网服务器版) # ============================================================================= # 适用场景:独立域名 itsupport.servyou.com.cn,公司内网 DNS 解析 # 与 NAS 版的区别: @@ -67,12 +67,24 @@ http { # ------------------------------------------------------------------ # 安全头 # ------------------------------------------------------------------ + # 基础安全头 add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; - add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; + + # CSP 收紧: 去掉 unsafe-inline(生产不需要,只有 dev HMR 需要) + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-eval' https://res.wx.qq.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https: http:; connect-src 'self' https://qyapi.weixin.qq.com wss://*; font-src 'self' data:;" always; + + # 隐私与跨域控制 + add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always; + add_header Cross-Origin-Opener-Policy "same-origin" always; + add_header Cross-Origin-Embedder-Policy "require-corp" always; + add_header Cross-Origin-Resource-Policy "same-origin" always; + + # 隐藏服务器版本 + server_tokens off; # ------------------------------------------------------------------ # 健康检查端点 diff --git a/deploy-server/package-deploy.bat b/deploy-server/package-deploy.bat index 2861997..52d7b65 100644 --- a/deploy-server/package-deploy.bat +++ b/deploy-server/package-deploy.bat @@ -1,11 +1,11 @@ @echo off REM ============================================================================= -REM IT智能服务台 — 打包部署脚本(Windows) +REM 智能IT支持服务台 — 打包部署脚本(Windows) REM 目标:生成部署包,通过堡垒机上传到服务器 REM ============================================================================= echo ========================================== -echo IT智能服务台 部署包打包 +echo 智能IT支持服务台 部署包打包 echo 时间: %date% %time% echo ========================================== diff --git a/deploy-server/package.py b/deploy-server/package.py index 398487c..5b664d4 100644 --- a/deploy-server/package.py +++ b/deploy-server/package.py @@ -1,5 +1,5 @@ """ -企微IT智能服务台 — 部署包生成脚本(Windows 兼容版) +企微智能IT支持服务台 — 部署包生成脚本(Windows 兼容版) ======================================================= 功能: 1. 构建前端(H5 + 坐席端) @@ -163,7 +163,7 @@ def create_package(): def main(): print("=" * 50) - print(" IT智能服务台 — 部署包生成") + print(" 智能IT支持服务台 — 部署包生成") print("=" * 50) # 检查是否跳过构建 diff --git a/deploy-server/package.sh b/deploy-server/package.sh index 9bdd846..add07fd 100644 --- a/deploy-server/package.sh +++ b/deploy-server/package.sh @@ -1,6 +1,6 @@ #!/bin/bash # ============================================================================= -# 企微IT智能服务台 — 部署包生成脚本(在开发机上运行) +# 企微智能IT支持服务台 — 部署包生成脚本(在开发机上运行) # ============================================================================= # 功能: # 1. 构建前端(H5 + 坐席端) @@ -28,7 +28,7 @@ PACKAGE_NAME="it-smart-desk-server-deploy" BUILD_DIR="/tmp/$PACKAGE_NAME" echo -e "${GREEN}============================================${NC}" -echo -e "${GREEN} IT智能服务台 — 部署包生成${NC}" +echo -e "${GREEN} 智能IT支持服务台 — 部署包生成${NC}" echo -e "${GREEN}============================================${NC}" # --- 1. 构建前端 --- diff --git a/deploy-server/打包部署.bat b/deploy-server/打包部署.bat index 48faea3..01ed30b 100644 --- a/deploy-server/打包部署.bat +++ b/deploy-server/打包部署.bat @@ -1,6 +1,6 @@ @echo off REM ============================================================================= -REM 企微IT智能服务台 — 打包部署一键执行 +REM 企微智能IT支持服务台 — 打包部署一键执行 REM ============================================================================= REM 功能: REM 1. 打包前端构建产物 + nginx配置 + docker-compose.yml + .env @@ -20,7 +20,7 @@ if "%MODE%"=="" set MODE=local echo. echo ======================================== -echo 企微IT智能服务台 — 打包部署 +echo 企微智能IT支持服务台 — 打包部署 echo ======================================== echo 模式: %MODE% echo. diff --git a/docs/01-项目总览与部署手册.md b/docs/01-项目总览与部署手册.md index f0460b7..402b99f 100644 --- a/docs/01-项目总览与部署手册.md +++ b/docs/01-项目总览与部署手册.md @@ -1,4 +1,4 @@ -# 企微IT智能服务台 — 项目总览与部署手册 +# 企微智能IT支持服务台 — 项目总览与部署手册 > **版本**: v2.1 | **日期**: 2026-06-03 | **编制**: 宋献(IT支持组组长) > **目标读者**: **管理者 / 架构师 / 运维** — 了解项目全貌、架构决策、部署与运维操作 @@ -570,7 +570,7 @@ docker compose down # 停止新系统所有容器 ### TL;DR -企微IT智能服务台第一步(消息接管 + 极简坐席台)全部代码已完成并通过测试,共 **110+ 文件**,**116/116 测试全部通过**,覆盖后端 API、坐席工作台、用户端 H5 三个子系统。 +企微智能IT支持服务台第一步(消息接管 + 极简坐席台)全部代码已完成并通过测试,共 **110+ 文件**,**116/116 测试全部通过**,覆盖后端 API、坐席工作台、用户端 H5 三个子系统。 ### 交付状态 @@ -641,7 +641,7 @@ wecom_it_smart_desk/ ├── ARCHITECTURE.md # 系统架构设计(合并版) ├── 01-项目总览与部署手册.md # 管理者视角部署手册 ├── 开发交付概览.md # 开发交付状态总览 - ├── IT智能服务台-项目迁移文档.md # 工作区迁移记录 + ├── 智能IT支持服务台-项目迁移文档.md # 工作区迁移记录 ├── testing/ # 测试报告目录 │ └── QA_COMPREHENSIVE_REPORT.md # 综合 QA 报告 ├── diagrams/ # Mermaid 图表 diff --git a/docs/ARCHITECTURE-admin.md b/docs/ARCHITECTURE-admin.md index 1644496..e87d5cf 100644 --- a/docs/ARCHITECTURE-admin.md +++ b/docs/ARCHITECTURE-admin.md @@ -1,4 +1,4 @@ -# IT智能服务台 — 管理后台架构设计文档 +# 智能IT支持服务台 — 管理后台架构设计文档 > **文档版本**: v1.0 > **架构师**: 高见远 (Bob) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index caf3e38..9a8d4ef 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,4 +1,4 @@ -# 企微IT智能服务台 — 系统架构设计文档 +# 企微智能IT支持服务台 — 系统架构设计文档 > **文档版本**: v0.11 > **创建日期**: 2025-07-11 @@ -2877,4 +2877,4 @@ alembic upgrade head --- -> **文档结束** — 本架构设计文档涵盖企微IT智能服务台第一步(消息接管+极简坐席)的完整技术方案,作为工程师编写代码的基准文档。 +> **文档结束** — 本架构设计文档涵盖企微智能IT支持服务台第一步(消息接管+极简坐席)的完整技术方案,作为工程师编写代码的基准文档。 diff --git a/docs/DEPLOY_NAS.md b/docs/DEPLOY_NAS.md index 018e854..ab0bab6 100644 --- a/docs/DEPLOY_NAS.md +++ b/docs/DEPLOY_NAS.md @@ -1,4 +1,4 @@ -# 企微IT智能服务台 — 远程服务器部署指南(预生产) +# 企微智能IT支持服务台 — 远程服务器部署指南(预生产) > **预生产环境**:本系统与 IT 数据查询平台部署在**不同主机**。正式环境将迁移到 K8s。 diff --git a/docs/ExternalSystemAdapter设计文档.md b/docs/ExternalSystemAdapter设计文档.md index 4937704..3dfca4b 100644 --- a/docs/ExternalSystemAdapter设计文档.md +++ b/docs/ExternalSystemAdapter设计文档.md @@ -1,6 +1,6 @@ # ExternalSystemAdapter 抽象层设计文档 -> 版本:V1.0 | 日期:2026-06-11 | 作者:IT智能服务台项目组 +> 版本:V1.0 | 日期:2026-06-11 | 作者:智能IT支持服务台项目组 --- diff --git a/docs/H5用户端右侧栏动态推送评估.md b/docs/H5用户端右侧栏动态推送评估.md index 72c0921..7383ad3 100644 --- a/docs/H5用户端右侧栏动态推送评估.md +++ b/docs/H5用户端右侧栏动态推送评估.md @@ -14,7 +14,7 @@ ### 1. 符合系统定位——"AI驱动" -系统全名是"IT智能服务台 — AI驱动",但当前右侧栏本质是传统信息架构(标签页+列表),AI只在左侧会话区参与。动态推送让右侧也变成AI能力的延伸,整个产品才能名副其实。 +系统全名是"智能IT支持服务台 — AI驱动",但当前右侧栏本质是传统信息架构(标签页+列表),AI只在左侧会话区参与。动态推送让右侧也变成AI能力的延伸,整个产品才能名副其实。 ### 2. 降低用户认知负荷 diff --git a/docs/IT服务台部署修复记录-2026-06-13.md b/docs/IT服务台部署修复记录-2026-06-13.md index 59508aa..a78d75b 100644 --- a/docs/IT服务台部署修复记录-2026-06-13.md +++ b/docs/IT服务台部署修复记录-2026-06-13.md @@ -1,4 +1,4 @@ -# IT智能服务台 - 部署修复记录 +# 智能IT支持服务台 - 部署修复记录 **日期**:2026-06-13 **负责人**:宋献 diff --git a/docs/NAS部署指南.md b/docs/NAS部署指南.md index 742dbea..41604c8 100644 --- a/docs/NAS部署指南.md +++ b/docs/NAS部署指南.md @@ -252,7 +252,7 @@ docker compose -f docker-compose.nas.yml up -d --build 1. 登录 [企微管理后台](https://work.weixin.qq.com/wework_admin/frame) 2. **应用管理** → **自建** → **创建应用** 3. 填写: - - 应用名称:`IT智能服务台` + - 应用名称:`智能IT支持服务台` - 应用logo:上传一个图标 - 可见范围:选择测试部门/人员 diff --git a/docs/PRD-admin.md b/docs/PRD-admin.md index de659a3..18dc779 100644 --- a/docs/PRD-admin.md +++ b/docs/PRD-admin.md @@ -1,4 +1,4 @@ -# IT智能服务台 — 管理后台增量 PRD +# 智能IT支持服务台 — 管理后台增量 PRD > **文档版本**: v1.0 > **创建日期**: 2026-06-16 @@ -28,7 +28,7 @@ | 字段 | 值 | |------|------| -| 产品名称 | IT智能服务台 — 管理后台 | +| 产品名称 | 智能IT支持服务台 — 管理后台 | | 项目代号 | `wecom_it_smart_desk`(第三端:admin) | | 编程语言 | 前端: Vue 3 + TypeScript + Element Plus + Pinia · 后端: FastAPI + SQLAlchemy + PostgreSQL + Redis | | 部署路径 | `/itadmin/`(与 H5 `/itdesk/`、坐席 `/itagent/` 并列) | diff --git a/docs/PRD-增量-人工按钮与术语统一.md b/docs/PRD-增量-人工按钮与术语统一.md index d0f9548..bfd31de 100644 --- a/docs/PRD-增量-人工按钮与术语统一.md +++ b/docs/PRD-增量-人工按钮与术语统一.md @@ -54,7 +54,7 @@ ``` ┌────────────────────────────────────┐ -│ IT智能服务台 [🔔 人工] │ ← 启用状态(橙色) +│ 智能IT支持服务台 [🔔 人工] │ ← 启用状态(橙色) │ [▓▓ 人工] │ ← 禁用状态(灰色) └────────────────────────────────────┘ ``` diff --git a/docs/PRD.md b/docs/PRD.md index 62a97ac..4e98cb9 100644 --- a/docs/PRD.md +++ b/docs/PRD.md @@ -1,4 +1,4 @@ -# 企微IT智能服务台 — 产品需求文档 (PRD) +# 企微智能IT支持服务台 — 产品需求文档 (PRD) > **文档版本**: v1.0 > **创建日期**: 2025-07-11 @@ -1318,7 +1318,7 @@ | 项目 | 说明 | |------|------| -| **顶部栏** | 左侧:logo 方块 "IT"(渐变紫蓝 26×26px)+ "IT智能服务台"(渐变文字)+ "· 坐席工作台 — AI驱动 · 多系统对接 · 一站式处理"(10px 灰色副标题,max-width 280px 溢出省略) | +| **顶部栏** | 左侧:logo 方块 "IT"(渐变紫蓝 26×26px)+ "智能IT支持服务台"(渐变文字)+ "· 坐席工作台 — AI驱动 · 多系统对接 · 一站式处理"(10px 灰色副标题,max-width 280px 溢出省略) | | **变更范围** | `TopBar.vue`(从 `Workspace.vue` 顶部栏独立) | --- @@ -1451,7 +1451,7 @@ ``` ┌─────────────────────────────────────────────────────────────────────┐ -│ [IT] IT智能服务台 · 坐席工作台 — AI驱动 · 多系统对接 · 一站式处理 │ ☀️/🌙 │ 坐席: 陈思远 │ +│ [IT] 智能IT支持服务台 · 坐席工作台 — AI驱动 · 多系统对接 · 一站式处理 │ ☀️/🌙 │ 坐席: 陈思远 │ ├──────────┬──────────────────────────────────┬───────────────────────┤ │ │ 👤 张伟 · 研发一部 🥇黄金 │ 🤖 AI 智能推荐 │ │ 🔍 搜索 │ 😟焦虑 ⏱8分32秒 💬6轮 🔁重复 │ ┌─────────────────┐ │ @@ -1765,7 +1765,7 @@ class TroubleshootingTemplate(Base): | 系统 | 职责 | 部署位置 | 当前集成度 | |------|------|---------|-----------| -| **IT智能服务台** | 员工端H5 + 坐席工作台 + 管理后台 | NAS Docker (Cloudflare Tunnel) | — | +| **智能IT支持服务台** | 员工端H5 + 坐席工作台 + 管理后台 | NAS Docker (Cloudflare Tunnel) | — | | **Dify** | AI对话引擎(Agent1 员工自助 + Agent2 坐席辅助) | 公司内网 | 100%(dify2openai 集成) | | **RAGFlow** | 知识库检索(Dify 通过 RAGFlow 获取知识) | 公司内网 | 0%(Dify 间接调用) | | **智能IT助手数据处理平台** | 会话数据分析、报表、运营指标 | 公司内网 | 0%(物理隔离) | @@ -1941,7 +1941,7 @@ class TroubleshootingTemplate(Base): --- -> **文档结束** — 本PRD涵盖企微IT智能服务台全部已确认设计决策和约束,作为后续架构设计和开发实施的基准文档。v1.0 新增管理后台远景规划、系统生态与集成规划、阶段细化与并行推进策略。 +> **文档结束** — 本PRD涵盖企微智能IT支持服务台全部已确认设计决策和约束,作为后续架构设计和开发实施的基准文档。v1.0 新增管理后台远景规划、系统生态与集成规划、阶段细化与并行推进策略。 --- diff --git a/docs/RELEASE_NOTES_v0.5.0-beta.md b/docs/RELEASE_NOTES_v0.5.0-beta.md new file mode 100644 index 0000000..3f09193 --- /dev/null +++ b/docs/RELEASE_NOTES_v0.5.0-beta.md @@ -0,0 +1,155 @@ +# Release Notes — v0.5.0-beta(内测版) + +**发布日期**: 2026-06-15 下午 +**目标**: 内测(2-3 个内部用户),生产仍用 v0.4.x +**类型**: 🟡 **beta** — 部分 P0 已修,部分 P0 仍缺 +**负责人**: Simon +**对接 workbuddy brief**: `.workbuddy/memory/2026-06-15-合并任务部署说明.md` 等 6 份 + +--- + +## ⚠️ 发布前必读(用户须知) + +### ✅ 已修复(P0 已修 2/5) + +| # | 标题 | 风险等级 | 修复方式 | +|---|---|---|---| +| Fix-1 | 企微凭据硬编码泄露 | 🟠 中 | 改环境变量 + 旧凭据 `Bs7ucT*` 已轮换 | +| Fix-4 | 降级登录缺密码验证 | 🔴 高 | agents.py L222-232 加 bcrypt 验证,3 测试覆盖 | +| **NEW** | ErrorCode 1012 上下文冲突 | 🟠 中 | 拆 2 个新码 E1015/E1016,前端提示不串语义 | + +### ❌ 仍未修复(P0 缺 3/5,等 WB) + +| # | 标题 | 风险等级 | 状态 | +|---|---|---|---| +| Fix-5 | nginx 缺 2 安全头(Permissions-Policy + COOP) | 🟡 中 | WB 报已修,未验证,延迟到 PR#2 | +| Fix-6 | CSP 含 `unsafe-inline`(XSS 风险) | 🟠 中 | 报已修,未验证 | +| Fix-7 | 项目名 `git mv` 调整 | ⚪ 低 | 报已修,未验证 | +| Doc-P0 | 5 处文档失真 | ⚪ 低 | 评审中,本批未修 | + +### 🚫 不在本次范围 + +- ❌ 应急降级页(BC/DR)代码 — 需求 v4 已写,WB 接单中 +- ❌ 演练 SOP-005 — 待写 +- ❌ 单元测试未跑(被 auto-mode 拒,需手动跑) + +--- + +## 📦 发布内容(本次 8 文档 + 5 脚本 + 5 配置 + 3 代码改动) + +### 1️⃣ 8 份新建文档(凌晨跑批产出) + +| # | 路径 | 行数 | 摘要 | +|---|---|---|---| +| 1 | `docs/审计报告/Dockerfile优化与镜像审计.md` | #44 | Docker 镜像优化建议 | +| 2 | `docs/数据库ER图与环境变量清点.md` | #45 | 16 表 ER + 17 env | +| 3 | `docs/审计报告/依赖漏洞扫描与Lockfile审计.md` | #46 | 5 CVE 识别 | +| 4 | `docs/审计报告/健康检查+错误码+日志结构化.md` | #47 | 40+ 错误码 + JSON 日志 | +| 5 | `docs/审计报告/CORS-CSP-安全Header全套.md` | #48 | 8 安全头配置 | +| 6 | `docs/惊喜报告/🎁惊喜1-项目健康度仪表盘.md` | #49 | 仪表盘说明 | +| 7 | `docs/惊喜报告/🎁惊喜2-README徽章+CHANGELOG+模板.md` | #50 | 文档增强 | +| 8 | `docs/需求-发布预演页面.md`(v4 刚升) | 226 | 应急降级页需求 | +| 附 | `docs/dashboard.html` | - | 健康度仪表盘网页(8KB) | + +### 2️⃣ 5 个脚本(凌晨跑批产出) + +| # | 路径 | 用途 | +|---|---|---| +| 1 | `scripts/dashboard.py` | 生成健康度 HTML | +| 2 | `scripts/oneclick-deploy.sh` | 一键部署(灰度) | +| 3 | `scripts/pre-commit-check.sh` | 提交前自检 | +| 4 | `scripts/backup-gitea.sh` | Gitea 备份 | +| 5 | `scripts/security-audit.sh` | 安全审计 | + +### 3️⃣ 5 份配置(凌晨跑批产出) + +| # | 路径 | 用途 | +|---|---|---| +| 1 | `.dockerignore` | Docker 优化 | +| 2 | `.gitea/dependabot.yml` | 依赖自动更新 | +| 3 | `.gitea/ISSUE_TEMPLATE/bug.md` | Bug 报告模板 | +| 4 | `.gitea/ISSUE_TEMPLATE/feature.md` | Feature 申请模板 | +| 5 | `.gitea/PULL_REQUEST_TEMPLATE.md` | PR 模板 | + +附: `CHANGELOG.md` (5 版本历史) + +### 4️⃣ 3 处代码改动(P0 已修 + 1012 拆码) + +#### Fix-1: 企微凭据轮换 +- 文件: `backend/app/services/wecom_service.py` + `.env` +- 改动: 硬编码 `Bs7ucT*` 改为 `${WECOM_CORP_SECRET}` 环境变量 +- 旧凭据: 已在企微后台轮换,新值仅在 `.env` + +#### Fix-4: 降级登录密码验证 +- 文件: `backend/app/api/agents.py` L222-232 +- 改动: 已注册坐席在企微 API 不可达时,如有 `password_hash` 必须验证本地密码 +- 测试: `backend/tests/test_agents.py` 3 测试(已写,待跑) + +#### 1012 拆码(NEW) +- 文件: `backend/app/utils/error_codes.py` + `backend/app/api/agents.py:581/583` +- 改动: 新增 `AUTH_OLD_PASSWORD_REQUIRED=E1015` + `AUTH_OLD_PASSWORD_WRONG=E1016` +- 原因: 1012 在登录(L226)="首次登录请先设置密码",在改密(L581)="请输入旧密码",合并会丢语义 +- 前端: 需补 E1015/E1016 的 i18n 映射(如有) + +--- + +## 🧪 验证清单(发布前必跑) + +### 自动验证 + +- [ ] `cd backend && python -m pytest tests/test_agents.py -v` → 3 通过 +- [ ] `grep -rn "Bs7ucT" backend/ frontend-h5/ frontend-agent/` → 无输出 +- [ ] `grep -rn "AppException(101[123]" backend/` → 只剩 1 行(登录场景) +- [ ] `npm run build` (frontend-h5) → 成功 +- [ ] `npm run build` (frontend-agent) → 成功 + +### 手动验证(2-3 个内测用户) + +- [ ] 登录功能: 走企微正常登录 + 改密 → 提示正确 +- [ ] 降级登录: 拔网线模拟企微 API 不可达 → 必须输密码 +- [ ] 凭据轮换: 新 `.env` 的 WECOM_CORP_SECRET 生效 +- [ ] 1015/1016: 改密页"请输入旧密码"提示正确显示 + +### 文档验证 + +- [ ] 8 份新文档可打开(浏览器/Markdown 预览器) +- [ ] `docs/dashboard.html` 用浏览器打开看效果 +- [ ] `CHANGELOG.md` 5 版本历史完整 + +--- + +## 🚦 发布决策 + +| 角色 | 动作 | +|---|---| +| **Simon** | 合并 `feature/t-1-t4-merge` → main,tag `v0.5.0-beta` | +| **workbuddy** | 等 Fix-5/6/7 真正验证完,提 PR#2(本批无此 PR) | +| **内测用户** | 用 v0.5.0-beta 跑 1 周,收集问题 | +| **下次发布** | v0.6.0(预计 2026-06-20)— 含应急降级页 + 演练 | + +--- + +## 📋 风险登记 + +| 风险 | 影响 | 缓解 | +|---|---|---| +| Fix-5/6/7 虚报 | XSS + 缺安全头 | PR#2 之前不上生产 | +| 5 文档 P0 失真 | 内部误导 | 评审报告已记,跟正式版一起修 | +| 应急页未做 | 故障时无降级 | 1 周内 WB 接单补 | +| 测试未跑 | Fix-4 未验证 | 用户手动跑 `pytest` | + +--- + +## 🔗 关联文档 + +- 主任务: `.workbuddy/memory/2026-06-15-合并任务部署说明.md` +- 补 4 项: `.workbuddy/memory/2026-06-15-补-4项+测试.md` +- 命名+错误码: `.workbuddy/memory/2026-06-15-补充-命名+错误码.md` +- 1012 拆码: `.workbuddy/memory/2026-06-15-ErrorCode-1012拆码.md` ← **NEW** +- 应急降级页: `.workbuddy/memory/2026-06-15-发布预演页.md` +- 评审报告: `docs/评审报告/2026-06-14-workbuddy-消息评审.md` +- 凌晨跑批汇总: `~/.claude/memory/overnight-batch-2026-06-15.md` + +--- + +🤖 Generated with [Claude Code](https://claude.com/claude-code) diff --git a/docs/aTrust零信任系统集成分析.md b/docs/aTrust零信任系统集成分析.md index 7e56569..bb17501 100644 --- a/docs/aTrust零信任系统集成分析.md +++ b/docs/aTrust零信任系统集成分析.md @@ -438,7 +438,7 @@ aTrust判断终端是否已存在的规则: ``` ┌─────────────────┐ - │ IT智能服务台 │ + │ 智能IT支持服务台 │ │ employee_id │ └────────┬────────┘ │ diff --git a/docs/archive/ARCHITECTURE-v53-incremental.md b/docs/archive/ARCHITECTURE-v53-incremental.md index 5963912..81cb103 100644 --- a/docs/archive/ARCHITECTURE-v53-incremental.md +++ b/docs/archive/ARCHITECTURE-v53-incremental.md @@ -1,4 +1,4 @@ -# IT智能服务台 · 坐席工作台 v5.3 增量架构设计 +# 智能IT支持服务台 · 坐席工作台 v5.3 增量架构设计 > **版本**: v5.3-incremental > **日期**: 2026-06-06 diff --git a/docs/archive/PRD-v53-incremental.md b/docs/archive/PRD-v53-incremental.md index 57782d4..390ed1b 100644 --- a/docs/archive/PRD-v53-incremental.md +++ b/docs/archive/PRD-v53-incremental.md @@ -1,4 +1,4 @@ -# IT智能服务台 · 坐席工作台 v5.3 增量 PRD +# 智能IT支持服务台 · 坐席工作台 v5.3 增量 PRD > **版本**: v5.3 增量迭代 > **日期**: 2026-06-06 @@ -181,7 +181,7 @@ | 项目 | 说明 | |------|------| -| **顶部栏** | 左侧:logo 方块 "IT"(渐变紫蓝 26×26px)+ "IT智能服务台"(渐变文字)+ "· 坐席工作台 — AI驱动 · 多系统对接 · 一站式处理"(10px 灰色副标题,max-width 280px 溢出省略) | +| **顶部栏** | 左侧:logo 方块 "IT"(渐变紫蓝 26×26px)+ "智能IT支持服务台"(渐变文字)+ "· 坐席工作台 — AI驱动 · 多系统对接 · 一站式处理"(10px 灰色副标题,max-width 280px 溢出省略) | | **变更范围** | `TopBar.vue`(从 `Workspace.vue` 顶部栏独立) | --- @@ -314,7 +314,7 @@ ``` ┌─────────────────────────────────────────────────────────────────────┐ -│ [IT] IT智能服务台 · 坐席工作台 — AI驱动 · 多系统对接 · 一站式处理 │ ☀️/🌙 │ 坐席: 陈思远 │ +│ [IT] 智能IT支持服务台 · 坐席工作台 — AI驱动 · 多系统对接 · 一站式处理 │ ☀️/🌙 │ 坐席: 陈思远 │ ├──────────┬──────────────────────────────────┬───────────────────────┤ │ │ 👤 张伟 · 研发一部 🥇黄金 │ 🤖 AI 智能推荐 │ │ 🔍 搜索 │ 😟焦虑 ⏱8分32秒 💬6轮 🔁重复 │ ┌─────────────────┐ │ diff --git a/docs/archive/开发交付概览.md b/docs/archive/开发交付概览.md index b5ddc48..4db72d3 100644 --- a/docs/archive/开发交付概览.md +++ b/docs/archive/开发交付概览.md @@ -1,8 +1,8 @@ -# 企微IT智能服务台 — 第一步开发交付概览 +# 企微智能IT支持服务台 — 第一步开发交付概览 ## TL;DR -企微IT智能服务台第一步(消息接管 + 极简坐席台)全部代码已完成并通过测试,共 **110+ 文件**,**116/116 测试全部通过**,覆盖后端 API、坐席工作台、用户端 H5 三个子系统。 +企微智能IT支持服务台第一步(消息接管 + 极简坐席台)全部代码已完成并通过测试,共 **110+ 文件**,**116/116 测试全部通过**,覆盖后端 API、坐席工作台、用户端 H5 三个子系统。 ## 交付状态 @@ -73,7 +73,7 @@ wecom_it_smart_desk/ ├── ARCHITECTURE.md # 系统架构设计(合并版) ├── 01-项目总览与部署手册.md # 管理者视角部署手册 ├── 开发交付概览.md # 开发交付状态总览 - ├── IT智能服务台-项目迁移文档.md # 工作区迁移记录 + ├── 智能IT支持服务台-项目迁移文档.md # 工作区迁移记录 ├── testing/ # 测试报告目录 │ └── QA_COMPREHENSIVE_REPORT.md # 综合 QA 报告 ├── diagrams/ # Mermaid 图表 diff --git a/docs/dashboard.html b/docs/dashboard.html new file mode 100644 index 0000000..f2a7ba7 --- /dev/null +++ b/docs/dashboard.html @@ -0,0 +1,150 @@ + + + + + 企微 IT 智能服务台 - 健康度仪表盘 + + + + +
+

🚀 企微 IT 智能服务台 - 健康度仪表盘

+
生成时间: 2026-06-15 10:34:45
+ +
+ +
+

📊 代码规模

+
25,199
+
后端 Python 代码行
+
+
后端 Python 文件94
+
Admin 前端0 文件
+
Agent 前端0 文件
+
H5 前端0 文件
+
Portal 前端0 文件
+
+
+ + +
+

📚 文档

+
65
+
文档总数
+
+
评审报告6
审计报告4
ADRs4
SOPs4
路线图3
+
+
+ + +
+

🛡️ 风险状态

+
-66
+
P0 遗留(需立即修)
+
+
P1 中危-66 待修
+
P2 低危-66 待修
+
M 中-56 待修
+
L 低-61 待修
+
+
+ + +
+

🛠️ 工具链

+
8
+
自动化脚本
+
+
后端测试18 文件
+
安全审计✅ 已配
+
API 文档✅ 已配
+
备份脚本✅ 已配
+
Pre-commit✅ 已配
+
+
+ + +
+

📦 Git 状态

+
+
分支: feature/t-1-t4-merge
+
提交数: 17
+
最近提交: 93ba41e feat: 瀹℃壒娴佺▼妯″潡 (T瀹℃壒A瀹℃壒)
+
+
+ + +
+

✅ 阶段完成度

+
+
+
66%
+
阶段 1
+
+
+
0%
+
阶段 2(转人工)
+
+
+
0%
+
阶段 3(H5+WS)
+
+
+
规划中
+
阶段 4(AI Wingman)
+
+
+
规划中
+
阶段 5(自动化)
+
+
+
+
+ +
+ 企微 IT 智能服务台 · 健康度仪表盘 v1.0 +
+
+ + diff --git a/docs/testing/QA_COMPREHENSIVE_REPORT.md b/docs/testing/QA_COMPREHENSIVE_REPORT.md index 13c6adb..53157b4 100644 --- a/docs/testing/QA_COMPREHENSIVE_REPORT.md +++ b/docs/testing/QA_COMPREHENSIVE_REPORT.md @@ -1,4 +1,4 @@ -# IT智能服务台 — 综合 QA 测试报告 +# 智能IT支持服务台 — 综合 QA 测试报告 > 本文档合并历次 QA 测试报告,按时间倒序排列(最新在前)。 diff --git a/docs/团队沟通文档-架构消息知识库.md b/docs/团队沟通文档-架构消息知识库.md index 38c8c3c..6b558ad 100644 --- a/docs/团队沟通文档-架构消息知识库.md +++ b/docs/团队沟通文档-架构消息知识库.md @@ -1,4 +1,4 @@ -# 企微IT智能服务台 — 系统架构、消息收发、知识库迭代说明 +# 企微智能IT支持服务台 — 系统架构、消息收发、知识库迭代说明 > **版本**: v1.1 | **日期**: 2026-06-02 | **负责人**: 宋献(IT支持组组长) > **目标读者**: 运维团队 / 架构团队 / 开发团队 diff --git a/docs/域名申请邮件-itsupport-servyou-com-cn.md b/docs/域名申请邮件-itsupport-servyou-com-cn.md index 687f2a7..fefae04 100644 --- a/docs/域名申请邮件-itsupport-servyou-com-cn.md +++ b/docs/域名申请邮件-itsupport-servyou-com-cn.md @@ -1,11 +1,11 @@ 收件人:G端域名审核小组 抄送:周复曙、吕勇、朱付贵 -主题:【域名申请】itsupport.servyou.com.cn — IT智能服务台项目外部子域名申请 +主题:【域名申请】itsupport.servyou.com.cn — 智能IT支持服务台项目外部子域名申请 各位领导,好: -IT支持组正在推进"IT智能服务台"项目,借助AI能力提升IT支持的服务质量和效率,现申请外部子域名 itsupport.servyou.com.cn。 +IT支持组正在推进"智能IT支持服务台"项目,借助AI能力提升IT支持的服务质量和效率,现申请外部子域名 itsupport.servyou.com.cn。 项目背景:公司日常IT支持在以下方面仍有提升空间: 1. 员工入口体验 — 转人工需另开窗口,AI与人工服务衔接不够流畅,跨企业服务不可达 diff --git a/docs/安全/secret-管理.md b/docs/安全/secret-管理.md index cb04ffa..d99418d 100644 --- a/docs/安全/secret-管理.md +++ b/docs/安全/secret-管理.md @@ -1,4 +1,4 @@ -# IT智能服务台 - Secret 管理方案 +# 智能IT支持服务台 - Secret 管理方案 **版本**: 1.0 **更新日期**: 2026-06-14 diff --git a/docs/安全审计报告.md b/docs/安全审计报告.md index a0028a0..2ca86c8 100644 --- a/docs/安全审计报告.md +++ b/docs/安全审计报告.md @@ -1,4 +1,4 @@ -# IT智能服务台 — 安全审计报告 +# 智能IT支持服务台 — 安全审计报告 > **编制日期**: 2026-06-14 > **版本**: v1.0 @@ -9,7 +9,7 @@ | 项目 | 说明 | |------|------| -| 系统名称 | IT智能服务台 | +| 系统名称 | 智能IT支持服务台 | | 部署环境 | 企业内网 (10.90.5.110) | | 访问方式 | 企微工作台应用 / HTTPS | | 用户规模 | ~6000人 | diff --git a/docs/IT智能服务台-版本更新说明-20250614.md b/docs/智能IT支持服务台-版本更新说明-20250614.md similarity index 99% rename from docs/IT智能服务台-版本更新说明-20250614.md rename to docs/智能IT支持服务台-版本更新说明-20250614.md index a3c4119..950c542 100644 --- a/docs/IT智能服务台-版本更新说明-20250614.md +++ b/docs/智能IT支持服务台-版本更新说明-20250614.md @@ -1,4 +1,4 @@ -# IT智能服务台 - 版本更新说明 +# 智能IT支持服务台 - 版本更新说明 **版本**: v1.1.0 **更新日期**: 2026-06-14 diff --git a/docs/IT智能服务台-项目迁移文档.md b/docs/智能IT支持服务台-项目迁移文档.md similarity index 99% rename from docs/IT智能服务台-项目迁移文档.md rename to docs/智能IT支持服务台-项目迁移文档.md index 3a7f9fe..40b7e57 100644 --- a/docs/IT智能服务台-项目迁移文档.md +++ b/docs/智能IT支持服务台-项目迁移文档.md @@ -1,4 +1,4 @@ -# IT智能服务台 — 项目迁移文档 +# 智能IT支持服务台 — 项目迁移文档 **生成时间**:2026-06-06 **来源项目**:`C:\Users\simon\wecom_it_smart_desk` **原型文件**:`C:\Users\simon\WorkBuddy\2026-05-21-16-57-26\agent-workspace-v5_3.html` diff --git a/docs/火绒终端安全系统集成分析.md b/docs/火绒终端安全系统集成分析.md index 7ef0d4b..5c8b271 100644 --- a/docs/火绒终端安全系统集成分析.md +++ b/docs/火绒终端安全系统集成分析.md @@ -2,7 +2,7 @@ > 基于火绒终端安全管理系统API说明文档(内网地址: `huorong.oa.servyou-it.com:8080`) > 分析日期:2026-06-11 -> 分析人:IT智能服务台项目组 +> 分析人:智能IT支持服务台项目组 --- @@ -557,4 +557,4 @@ IT服务台: employee_id → conversation → 坐席 → 查看安全状态 ### 8.3 一句话总结 -> 火绒集成是IT智能服务台从「被动响应」走向「主动安全」的关键一步,建议优先推进P0查询能力,2周内可上线见效。 +> 火绒集成是智能IT支持服务台从「被动响应」走向「主动安全」的关键一步,建议优先推进P0查询能力,2周内可上线见效。 diff --git a/docs/统一入口技术设计文档.md b/docs/统一入口技术设计文档.md index aa649a2..68e6ed5 100644 --- a/docs/统一入口技术设计文档.md +++ b/docs/统一入口技术设计文档.md @@ -1,4 +1,4 @@ -# IT智能服务台 — 统一入口(Portal)技术设计文档 +# 智能IT支持服务台 — 统一入口(Portal)技术设计文档 **版本**: v1.1 **日期**: 2026-06-13 @@ -25,7 +25,7 @@ ### 1.1 背景 -当前 IT智能服务台 存在三个独立入口: +当前 智能IT支持服务台 存在三个独立入口: - **用户端** `/itdesk/` — 员工提交工单、查看进度 - **坐席端** `/itagent/` — IT坐席处理会话、AI辅助 - **管理端** `/itadmin/` — 系统配置、数据分析 @@ -38,7 +38,7 @@ ### 1.2 方案目标 **统一入口架构**: -- 所有用户必须通过 **企微工作台 → IT智能服务台应用** 进入 +- 所有用户必须通过 **企微工作台 → 智能IT支持服务台应用** 进入 - 进入时自动检测账户关联的角色 - 提供卡片选择页面,让用户选择进入哪个端 - 无坐席/管理角色的用户直接进入用户端 @@ -60,7 +60,7 @@ │ 用户访问流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ -│ 企微工作台 → IT智能服务台应用 │ +│ 企微工作台 → 智能IT支持服务台应用 │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ @@ -508,7 +508,7 @@ frontend-portal/ ``` ┌─────────────────────────────────────────────────────────┐ │ │ -│ IT智能服务台 │ +│ 智能IT支持服务台 │ │ │ │ 选择您要进入的工作台 │ │ │ diff --git a/docs/联软终端安全系统集成分析.md b/docs/联软终端安全系统集成分析.md index 9548d2a..03aef88 100644 --- a/docs/联软终端安全系统集成分析.md +++ b/docs/联软终端安全系统集成分析.md @@ -2,7 +2,7 @@ > 基于联软LV7000系列LeagView5版本API接口说明文档(202210SP v1.1) > 分析日期:2026-06-11 -> 分析人:IT智能服务台项目组 +> 分析人:智能IT支持服务台项目组 --- @@ -675,7 +675,7 @@ aTrust集成为**P1优先级**(联软P0之后),因为: ``` ┌──────────────────────────────────────────────────────────────┐ -│ IT智能服务台 │ +│ 智能IT支持服务台 │ │ (统一集成层) │ │ │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ @@ -794,4 +794,4 @@ class UnifiedTerminalInfo: ### 9.3 一句话总结 -> 联软是IT智能服务台打通「员工↔终端」映射的关键系统,与火绒形成「管理+安全」双引擎,加上aTrust补全远程办公,三系统集成将实现终端问题排查的360°全景视角。 +> 联软是智能IT支持服务台打通「员工↔终端」映射的关键系统,与火绒形成「管理+安全」双引擎,加上aTrust补全远程办公,三系统集成将实现终端问题排查的360°全景视角。 diff --git a/docs/评审报告/workbuddy-2026-06-14-消息优化.md b/docs/评审报告/workbuddy-2026-06-14-消息优化.md index 4ab8752..d288073 100644 --- a/docs/评审报告/workbuddy-2026-06-14-消息优化.md +++ b/docs/评审报告/workbuddy-2026-06-14-消息优化.md @@ -19,7 +19,7 @@ | `backend/app/api/agents.py` | 改动 | OTP 双因素(otp-bind/otp-verify/otp-unbind) | | `frontend-h5/src/api/conversation.ts` | 改动 | mapMessage 字段映射(id→message_id) | | `docker-compose.yml` | 改动 | healthcheck 配置(backend 用 curl 已知坑) | -| `docs/IT智能服务台-版本更新说明-20250614.md` | 文档 | v1.1.0 发布说明 | +| `docs/智能IT支持服务台-版本更新说明-20250614.md` | 文档 | v1.1.0 发布说明 | --- @@ -120,7 +120,7 @@ ### 待文档/流程 -- [ ] `docs/IT智能服务台-版本更新说明-20250614.md` 4 处错误修订 +- [ ] `docs/智能IT支持服务台-版本更新说明-20250614.md` 4 处错误修订 - [ ] workbuddy 推送流程:加 "PR 前 P0 强制评审" 环节 --- diff --git a/docs/调试验证指南_2026-06-13.md b/docs/调试验证指南_2026-06-13.md index 1f2939a..d36d3c0 100644 --- a/docs/调试验证指南_2026-06-13.md +++ b/docs/调试验证指南_2026-06-13.md @@ -1,4 +1,4 @@ -# IT智能服务台 — 调试验证指南 +# 智能IT支持服务台 — 调试验证指南 **创建时间**: 2026-06-13 **适用环境**: 正式服务器 10.90.5.10 (itsupport.servyou.com.cn) @@ -128,7 +128,7 @@ ├─────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────┐ ┌─────────────────┐ │ -│ │ IT智能服务台(正式) │ │ IT智能服务台-测试 │ │ +│ │ 智能IT支持服务台(正式) │ │ 智能IT支持服务台-测试 │ │ │ │ │ │ │ │ │ │ 可信域名: │ │ 可信域名: │ │ │ │ itsupport.xxx │ │ itdesk.amanzac │ │ @@ -153,7 +153,7 @@ 1. 登录 [企微管理后台](https://work.weixin.qq.com/wework_admin/frame) 2. **应用管理** → **自建** → **创建应用** 3. 填写信息: - - **应用名称**: `IT智能服务台-测试` + - **应用名称**: `智能IT支持服务台-测试` - **应用logo**: 使用不同颜色(如橙色)区分正式应用 - **应用介绍**: "仅供IT部门测试使用" - **可见范围**: 选择IT部门 + 测试人员 @@ -209,7 +209,7 @@ VITE_WECOM_CORP_ID=ww_test_xxxxx | 步骤 | 操作 | 预期结果 | |------|------|---------| -| 1 | 在企微中找到"IT智能服务台-测试"应用 | 应用显示在工作台 | +| 1 | 在企微中找到"智能IT支持服务台-测试"应用 | 应用显示在工作台 | | 2 | 点击应用 | 跳转到 `https://itdesk.amanzac.com/itdesk/` | | 3 | 首次访问 | 跳转企微OAuth2授权页 | | 4 | 确认授权 | 跳回H5聊天页面 | diff --git a/docs/资源申请清单.md b/docs/资源申请清单.md index b8955fe..78ea818 100644 --- a/docs/资源申请清单.md +++ b/docs/资源申请清单.md @@ -1,8 +1,8 @@ -# IT智能服务台 — 资源申请清单 +# 智能IT支持服务台 — 资源申请清单 > **📌 使用说明(工作流程)** > -> 本文档是 IT智能服务台 所有资源申请需求的**统一汇总入口**,适用于: +> 本文档是 智能IT支持服务台 所有资源申请需求的**统一汇总入口**,适用于: > - 服务器/域名/网络等资源申请 > - 外部系统 API 对接申请(联软、火绒、aTrust、北森 eHR 等) > - 任何需要向其他团队(运维/安全/网络)申请权限或资源的任务 @@ -18,7 +18,7 @@ ## 一、背景 -IT智能服务台(IT Smart Desk)包含两个部署环境,需向运维申请服务器、域名及反向代理资源: +智能IT支持服务台(IT Smart Desk)包含两个部署环境,需向运维申请服务器、域名及反向代理资源: | 环境 | 用途 | 部署位置 | 访问方式 | |------|------|---------|---------| @@ -87,7 +87,7 @@ IT智能服务台(IT Smart Desk)包含两个部署环境,需向运维申 #### 建议 Nginx 配置片段 ```nginx -# ==================== IT智能服务台 — 预生产 ==================== +# ==================== 智能IT支持服务台 — 预生产 ==================== # 后端 API location /api/ { proxy_pass http://10.80.0.129:18080/api/; @@ -219,7 +219,7 @@ NAS 环境的 Nginx 已内置于 Docker Compose,**无需运维额外配置** #### 项目背景 -IT智能服务台核心目标之一是**打通员工↔终端的映射链路**。联软LV7000拥有最准确的员工账号→终端设备映射数据(`strusername`字段),是终端信息集成的**核心数据源**。 +智能IT支持服务台核心目标之一是**打通员工↔终端的映射链路**。联软LV7000拥有最准确的员工账号→终端设备映射数据(`strusername`字段),是终端信息集成的**核心数据源**。 #### API 账户(超管自建) @@ -307,7 +307,7 @@ IT智能服务台核心目标之一是**打通员工↔终端的映射链路** - **申请人**:宋献,IT支持组(税友集团),负责终端安全 - **火绒/联软对接人**:宋献(超管权限,自行创建API账户,受安全团队管理) -- **项目**:IT智能服务台(IT Smart Desk) +- **项目**:智能IT支持服务台(IT Smart Desk) - **紧急程度**:预生产反代配置建议 1-2 个工作日内完成;生产环境 NAS 自建,无需运维介入 - **组织架构说明**: - IT支持组 = 终端安全负责团队(非独立"终端安全团队") diff --git a/docs/邀请功能-技术方案.md b/docs/邀请功能-技术方案.md index e751c36..b6052c0 100644 --- a/docs/邀请功能-技术方案.md +++ b/docs/邀请功能-技术方案.md @@ -212,7 +212,7 @@ async def send_invite_card( "template_card": { "card_type": "button_interaction", "source": { - "desc": "IT智能服务台" + "desc": "智能IT支持服务台" }, "main_title": { "title": "🔔 会话邀请" diff --git a/docs/需求-发布预演页面.md b/docs/需求-发布预演页面.md new file mode 100644 index 0000000..d0f2ace --- /dev/null +++ b/docs/需求-发布预演页面.md @@ -0,0 +1,226 @@ +# 需求: 应急降级页(H5 + Agent Preview)via 企微"服务窗口" + +**需求提出**: 2026-06-15(经多次澄清,核心场景为 BC/DR) +**需求方**: Simon +**核心场景**: 🔴 **业务连续性(BC/DR)** — 系统故障时切换至企微原生服务,坐席保留关键功能 +**入口**: 🏢 **企微"员工服务"应用 → "服务窗口"**(只配 1 个 URL) +**关联规则**: [[locked-decisions]] § 应急降级 / [[preview-pages-sync-rule]] + +--- + +## 🎯 业务目标(真实场景) + +当本系统出现**特殊情况**(故障 / 不可用 / 合规要求 / 流量过载)时: + +1. **员工侧**: 切换至企微**原生员工服务**(群聊/单聊兜底) +2. **坐席侧**: 通过企微"员工服务 → 服务窗口" 链接,使用本系统应急页 +3. **目标**: 即使主系统挂掉,**核心 IT 服务不中断** + +## 🏢 入口架构(1 URL + 企微 JS-SDK) + +``` +┌────────────────────────────────────────┐ +│ 企微"员工服务"应用(企业已建) │ +│ └─ "服务窗口" tab(只能配 1 个 URL) │ +│ └─ https://itsupport.servyou.com.cn/emergency +└────────────────────────────────────────┘ + ↓ +┌────────────────────────────────────────┐ +│ /emergency 页面(身份检测) │ +│ 1. 加载企微 JS-SDK(不依赖本后端) │ +│ 2. agentConfig 拿当前 userid │ +│ 3. 调企微通讯录 API 查 user 详情 │ +│ 4. 判断身份:是"IT支持-咨询坐席"标签成员 │ +│ ├─ 是 → router.push('/agent/preview')│ +│ └─ 否 → router.push('/h5/preview') │ +└────────────────────────────────────────┘ +``` + +**关键**: +- 身份检测**不依赖本系统后端**(主系统挂时仍可用) +- 应急页 2 套(h5 + agent),通过 router.push 切换 +- 企微通讯录 API 走企微 access_token,跟主系统无关 + +## 📋 保留功能(4 件套 + 动态联系人) + +| # | 功能 | 描述 | 数据源 | +|---|---|---|---| +| 1 | 🔍 **快速回复模板** | 100+ 条按关键词搜索 | mock JSON → localStorage | +| 2 | 🔍 **排障流程模板** | vpn/邮箱/系统/账号 4 大类 | mock JSON → localStorage | +| 3 | 📋 **资源/审批链接** | 12 个常用入口 | mock JSON → localStorage | +| 4 | 👥 **应急联系人** | 企微标签"IT支持-咨询坐席"成员 | 企微 API → 单独 localStorage | +| **合计** | | | **~750KB + 联系人列表** | + +### 应急联系人(动态,非固定) + +**数据源**: 企微通讯录标签"IT支持-咨询坐席" + +**预同步**: +- 主系统正常时,每 30 分钟调企微通讯录 API 查该标签成员 +- 存到**独立 localStorage key** `emergency_contacts`: + ```json + { + "synced_at": "2026-06-15T10:00:00", + "tag_id": "TAG_xxx", + "members": [ + {"userid": "zhangsan", "name": "张三", "avatar": "...", "online": true}, + ... + ] + } + ``` + +**应急展示**: +- 列出标签下所有成员 +- 在线/离线状态(企微 status 接口) +- 点击 → 打开企微单聊 +- 数据 > 1 小时未更新时标红,提示"联系人可能不准,建议手动搜索标签组" + +## 🆘 "特殊情况" 触发与降级 + +| 类型 | 触发条件 | 降级动作 | +|---|---|---| +| 🔴 主系统完全不可用 | API 5xx / 网络断开 | 切企微原生 + 服务窗口 | +| 🟡 部分功能故障 | 消息发送失败 / 排队堵死 | 切企微原生 + 工具走应急页 | +| 🟠 合规要求 | 必须用企微审计 | 切企微原生 + 应急页工单 | +| 🟢 流量过载 | 服务降级中 | 部分功能走应急页 | + +## 📋 范围 + +| 项 | H5 应急页 | Agent 应急页 | +|---|---|---| +| URL | `/h5/preview` | `/agent/preview` | +| 统一入口 | `/emergency` | `/emergency` | +| 显示组件 | `RightPanel.vue`(3 段式) | `AiAssistantPanel.vue`(4 件套) | +| 去除功能 | `ChatPanel`(聊天走企微原生) | `ConversationList` + `ChatArea` + `TopBar` | +| 数据源 | **预同步到 localStorage** | **预同步到 localStorage** | +| 后端调用 | **无**(主系统可能挂) | **无** | +| 用户登录 | **跳过**(应急场景免登) | **跳过**(应急场景免登) | + +## 🔄 数据预同步机制(2 个独立 localStorage) + +### localStorage #1: `emergency_data`(静态工具数据) + +**正常态**: +``` +主后端 /api/emergency-data + → 前端每 30 分钟拉取 + → 存到 localStorage("emergency_data") +``` + +**应急态**: +``` +localStorage("emergency_data") → 应急页直接渲染 +``` + +**内容**: 快速回复 / 排障 / 资源(~750KB) + +### localStorage #2: `emergency_contacts`(动态联系人) + +**正常态**: +``` +企微通讯录 API 查"IT支持-咨询坐席"标签 + → 前端每 30 分钟拉取 + → 存到 localStorage("emergency_contacts") +``` + +**应急态**: +``` +localStorage("emergency_contacts") → 应急页渲染联系人列表 +``` + +**内容**: 标签成员列表(动态,可能多人) + +## 🎨 页面要求(应急场景) + +### `/emergency`(身份检测入口,~50 行) + +- 加载企微 JS-SDK(wx.config + wx.agentConfig) +- 拿当前 userid +- 调企微通讯录 API 查 user 详情 + 标签 +- 判断是否含"IT支持-咨询坐席"标签 +- 是坐席 → push /agent/preview,否则 → push /h5/preview +- 检测失败 → 显示"请选择身份"2 个大按钮兜底 + +### H5 应急页(`/h5/preview`) + +- 顶部: 项目名 + **"🆘 应急模式"** 红色徽章 + 数据更新时间 +- 主体: `RightPanel` 全宽,3 段式(AI 推送 / 资源 / 趣味问答) +- 底部: 固定"主系统异常?此页面帮您继续获得服务" +- 移动端: 强制显示(覆盖 `isMobile` 判断) + +### Agent 应急页(`/agent/preview`) + +- 顶栏: 简化版 TopBar + 🆘 徽章 +- 主体: `AiAssistantPanel` 全宽,4 件套 +- 联系人: 标签组成员 + 在线状态 +- 底部: 固定"主系统异常"提示 + +## 📁 文件改动清单(调整) + +### H5 端 (frontend-h5/) + +| 操作 | 路径 | 说明 | +|---|---|---| +| 新建 | `src/views/EmergencyEntry.vue` | 身份检测入口(~50 行) | +| 新建 | `src/views/H5PreviewView.vue` | 应急主页 | +| 新建 | `src/mock/emergency-data.json` | 应急静态数据 | +| 新建 | `src/utils/emergency-sync.ts` | 同步工具(2 个 localStorage) | +| 改 | `src/router/index.ts` | 加 `/emergency` + `/h5/preview` | +| **复用** | `src/components/assistant/RightPanel.vue` | import 共享 | + +### Agent 端 (frontend-agent/) + +| 操作 | 路径 | 说明 | +|---|---|---| +| 新建 | `src/views/AgentPreviewView.vue` | 应急主页 | +| 改 | `src/router/index.ts` | 加 `/agent/preview` | +| **复用** | `src/components/assistant/AiAssistantPanel.vue` | import 共享 | + +**注**: 联系人 API 调用放 `emergency-sync.ts` 共用模块,h5 + agent 都用 + +## 🧪 验收标准 + +### 功能验收 + +- [ ] **断网测试**: 拔网线/关后端 → 应急页仍能打开 +- [ ] **身份自动路由**: 员工点开 → /h5/preview,坐席点开 → /agent/preview +- [ ] **联系人动态**: 标签组加新人,预同步后能显示 +- [ ] **数据新鲜度**: 顶部"数据 X 分钟前更新",> 1h 标红 +- [ ] **2 个 localStorage 独立工作**: 删 emergency_data 不影响 emergency_contacts + +### 灾备演练(非工作时间,本月必做) + +- [ ] 选择非工作时间(晚上 / 周末) +- [ ] 模拟主系统挂掉 → 切企微原生服务 → 坐席用应急页 +- [ ] 演练时长 / 解决率 / 痛点记录 +- [ ] 详见 `docs/SOPs/SOP-005-应急降级演练.md` + +## 📅 排期 + +| 时间 | 任务 | +|---|---| +| 2026-06-16 (周一) | WB 接单,1 入口 + 2 页面 + 1 mock + 1 同步工具 + 2 路由 | +| 2026-06-16 (周一) | 本地 `npm run build` 验证 | +| 2026-06-17 (周二) | 部署 + **断网演练**(非工作时间,如周二晚 20:00) | +| 2026-06-18 (周三) | 收集问题,迭代 | +| 2026-06-19 (周四) | 二次演练确认 | +| 2026-06-20 (周五) | 正式版上线 + 应急页同步上线 | + +## ⚠️ 应急场景的额外考虑 + +1. **入口要醒目**: 企微"员工服务 → 服务窗口"配置清晰描述 +2. **不依赖登录**: 应急时坐席可能密码都改不了,免登 +3. **非工作时间演练**: 降低对业务影响 +4. **联系人降级**: 实在没预同步数据,提示"请手动搜索 IT支持-咨询坐席 标签" +5. **保留升级路径**: 主系统恢复后,应急页要有提示"主系统已恢复,建议返回" + +## 🔗 关联 + +- **双端同步规则**: [[preview-pages-sync-rule]] +- **锁定决策**: [[locked-decisions]] § 应急降级 +- **演练 SOP**: `docs/SOPs/SOP-005-应急降级演练.md` +- **需求演进**: v1 灰度(误)→ v2 BC/DR(理解)→ v3 服务窗口(1 URL)→ v4 标签联系人(动态) + +--- + +🤖 Generated with [Claude Code](https://claude.com/claude-code) diff --git a/docs/项目任务状态报告_2026-06-13.md b/docs/项目任务状态报告_2026-06-13.md index aba2ae5..faf5391 100644 --- a/docs/项目任务状态报告_2026-06-13.md +++ b/docs/项目任务状态报告_2026-06-13.md @@ -1,4 +1,4 @@ -# IT智能服务台 — 项目任务状态报告 +# 智能IT支持服务台 — 项目任务状态报告 **报告时间**: 2026-06-13 11:00 **报告版本**: v1.0 @@ -185,7 +185,7 @@ 2. **构建并部署最新代码**:将今天的 Bug 修复 + UI 风格更新部署到服务器 ### 近期安排(P1) -3. **创建测试企微应用**:按照双企微应用方案,创建"IT智能服务台-测试"应用 +3. **创建测试企微应用**:按照双企微应用方案,创建"智能IT支持服务台-测试"应用 4. **阶段二启动**:排队机制 + 满意度评价设计 5. **aTrust对接**:找信息安全团队获取API密钥 diff --git a/docs/项目开发任务调整建议-20260611.md b/docs/项目开发任务调整建议-20260611.md index 384bcfb..e933559 100644 --- a/docs/项目开发任务调整建议-20260611.md +++ b/docs/项目开发任务调整建议-20260611.md @@ -1,4 +1,4 @@ -# IT智能服务台 — 项目开发任务调整建议 +# 智能IT支持服务台 — 项目开发任务调整建议 > **文档版本**: V1.0 > **创建日期**: 2026-06-11 diff --git a/docs/风险跟踪表.md b/docs/风险跟踪表.md index 36e592d..0431e65 100644 --- a/docs/风险跟踪表.md +++ b/docs/风险跟踪表.md @@ -1,4 +1,4 @@ -# IT智能服务台 — 风险跟踪表 +# 智能IT支持服务台 — 风险跟踪表 **最后更新**: 2026-06-14 18:30 **维护人**: 宋献 + Claude 评审协作 @@ -567,7 +567,7 @@ location /api/ { ## 九、2026-06-14 workbuddy 推送评审新增 **评审依据**: `docs/评审报告/workbuddy-2026-06-14-消息优化.md` -**评审范围**: workbuddy 6-14 推送 + `IT智能服务台-版本更新说明-20250614.md` +**评审范围**: workbuddy 6-14 推送 + `智能IT支持服务台-版本更新说明-20250614.md` **小计**: 13 项发现(6 P0 + 4 P1 + 3 P2),其中 7 项已修本地代码,6 项待 workbuddy 跟进 --- @@ -650,7 +650,7 @@ location /api/ { - **状态**: ⚠️ 待处理 - **风险级别**: 🟠 高(文档与代码不符) -- **位置**: `docs/IT智能服务台-版本更新说明-20250614.md:46` 声称改动 / `backend/app/services/ws_manager.py` 实际无对应方法 +- **位置**: `docs/智能IT支持服务台-版本更新说明-20250614.md:46` 声称改动 / `backend/app/services/ws_manager.py` 实际无对应方法 - **问题**: ConnectionManager 仅有 `send_to_agent` / `broadcast` / `send_to_employee` / `broadcast_to_employees`,**无 `broadcast_message_status(conv_id, msg_id, status)`** - **处理建议**: 实现该方法 + WebSocket 消息格式 diff --git a/frontend-admin/index.html b/frontend-admin/index.html index 3b703cb..b096674 100644 --- a/frontend-admin/index.html +++ b/frontend-admin/index.html @@ -3,8 +3,10 @@ + + - IT智能服务台 - 管理后台 + 智能IT支持服务台 - 管理后台
diff --git a/frontend-admin/package.json b/frontend-admin/package.json index 5bde3a2..dd2192f 100644 --- a/frontend-admin/package.json +++ b/frontend-admin/package.json @@ -3,7 +3,9 @@ "version": "1.0.0", "private": true, "type": "module", - "description": "企微IT智能服务台 - 管理后台前端", + "description": "企微智能IT支持服务台 - 管理后台前端", + "engines": { "node": ">=20.0.0 <21.0.0", "pnpm": ">=9.0.0" }, + "packageManager": "pnpm@9.15.0", "scripts": { "dev": "vite", "build": "vue-tsc && vite build", diff --git a/frontend-agent/index.html b/frontend-agent/index.html index 7d21ae8..5c69d2f 100644 --- a/frontend-agent/index.html +++ b/frontend-agent/index.html @@ -4,8 +4,10 @@ + + - IT智能服务台 - 坐席工作台 + 智能IT支持服务台 - 坐席工作台 diff --git a/frontend-agent/package.json b/frontend-agent/package.json index 782167d..f045ee3 100644 --- a/frontend-agent/package.json +++ b/frontend-agent/package.json @@ -2,7 +2,9 @@ "name": "wecom-it-desk-agent", "version": "1.0.0", "private": true, - "description": "企微IT智能服务台 - 坐席工作台前端", + "description": "企微智能IT支持服务台 - 坐席工作台前端", + "engines": { "node": ">=20.0.0 <21.0.0", "pnpm": ">=9.0.0" }, + "packageManager": "pnpm@9.15.0", "scripts": { "dev": "vite", "build": "vue-tsc && vite build", diff --git a/frontend-h5/index.html b/frontend-h5/index.html index 8cf959b..1f8ef76 100644 --- a/frontend-h5/index.html +++ b/frontend-h5/index.html @@ -4,8 +4,10 @@ + + - IT智能服务台 + 智能IT支持服务台 diff --git a/frontend-h5/package.json b/frontend-h5/package.json index 1117916..bb886e9 100644 --- a/frontend-h5/package.json +++ b/frontend-h5/package.json @@ -2,7 +2,9 @@ "name": "wecom-it-desk-h5", "version": "1.0.0", "private": true, - "description": "企微IT智能服务台 - H5用户端前端", + "description": "企微智能IT支持服务台 - H5用户端前端", + "engines": { "node": ">=20.0.0 <21.0.0", "pnpm": ">=9.0.0" }, + "packageManager": "pnpm@9.15.0", "scripts": { "dev": "vite", "build": "vue-tsc && vite build", diff --git a/frontend-portal/index.html b/frontend-portal/index.html index dbb6754..5c5c709 100644 --- a/frontend-portal/index.html +++ b/frontend-portal/index.html @@ -4,7 +4,9 @@ - IT智能服务台 - 选择工作台 + + + 智能IT支持服务台 - 选择工作台
diff --git a/frontend-portal/package.json b/frontend-portal/package.json index 93f55d7..1a1294c 100644 --- a/frontend-portal/package.json +++ b/frontend-portal/package.json @@ -3,6 +3,8 @@ "version": "1.0.0", "private": true, "type": "module", + "engines": { "node": ">=20.0.0 <21.0.0", "pnpm": ">=9.0.0" }, + "packageManager": "pnpm@9.15.0", "scripts": { "dev": "vite", "build": "vue-tsc && vite build", diff --git a/nginx.conf b/nginx.conf index 944329b..1756123 100644 --- a/nginx.conf +++ b/nginx.conf @@ -47,6 +47,20 @@ http { application/javascript application/xml+rss application/json application/ld+json; + # ------------------------------------------------------------------ + # 安全响应头 + # ------------------------------------------------------------------ + # 隐藏 nginx 版本号 + server_tokens off; + + # 基础安全头(应用到所有响应) + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; + add_header X-Frame-Options "DENY" always; + add_header X-XSS-Protection "0" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always; + add_header Cross-Origin-Opener-Policy "same-origin" always; + # ================================================================= # 上游服务定义(Docker 内部网络) # =================================================================