# 计划执行：P2 级检测模块移植

## 文档信息

- 创建时间：2026-07-22
- 关联需求文档：`Docs/需求文档/服务监测/PRD_需求文档_P2级移植.md`
- 预计改动文件：4 个
- 预计新增文件：4 个

---

## 执行步骤

### Step 1：系统类型识别模块 — 50_system_profile.sh

**文件**：`skill/code/web/service_monitor/assets/system/50_system_profile.sh`（新增）

**检测项**：

| KEY | 输出 |
|-----|------|
| `SYS_PROFILE_PLATFORM_TYPE` | new/old |
| `SYS_PROFILE_PLATFORM_TYPE_LEVEL` | 正常/跳过 |
| `SYS_PROFILE_CONTAINER_TYPE` | ujava/upython/upython_voice/unknown |
| `SYS_PROFILE_CONTAINER_TYPE_LEVEL` | 正常/跳过 |
| `SYS_PROFILE_UJAVA_VARIANT` | unified/meeting/none |
| `SYS_PROFILE_UJAVA_VARIANT_LEVEL` | 正常/跳过 |

**实现要点**：

```bash
#!/bin/bash
################################################################################
# 50_system_profile.sh — 系统类型识别
# 功能: 检测平台类型、容器类型、ujava 变体
# 参考: ServerProfile.psm1
# 日期: 2026-07-22
################################################################################

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"

source "$LIB_DIR/lib/config.sh"
source "$LIB_DIR/lib/common.sh"

# ==================== 平台类型检测 ====================
detect_platform_type() {
    if [ -d "/data/services" ]; then
        output_result "SYS_PROFILE_PLATFORM_TYPE" "new"
    else
        output_result "SYS_PROFILE_PLATFORM_TYPE" "old"
    fi
    output_result "SYS_PROFILE_PLATFORM_TYPE_LEVEL" "正常"
}

# ==================== 容器类型检测 ====================
detect_container_type() {
    local containers
    containers=$(docker ps --format '{{.Names}}' 2>/dev/null)
    
    if echo "$containers" | grep -qE '^ujava[0-9]*$'; then
        output_result "SYS_PROFILE_CONTAINER_TYPE" "ujava"
    elif echo "$containers" | grep -qE '^upython_voice[0-9]*$'; then
        output_result "SYS_PROFILE_CONTAINER_TYPE" "upython_voice"
    elif echo "$containers" | grep -qE '^upython[0-9]*$'; then
        output_result "SYS_PROFILE_CONTAINER_TYPE" "upython"
    else
        output_result "SYS_PROFILE_CONTAINER_TYPE" "unknown"
    fi
    output_result "SYS_PROFILE_CONTAINER_TYPE_LEVEL" "正常"
}

# ==================== ujava 变体检测 ====================
detect_ujava_variant() {
    local container_type
    container_type=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^ujava[0-9]*$' | head -1)
    
    if [ -n "$container_type" ]; then
        if [ -d "/var/www/java/unifiedPlatform" ]; then
            output_result "SYS_PROFILE_UJAVA_VARIANT" "unified"
        else
            output_result "SYS_PROFILE_UJAVA_VARIANT" "meeting"
        fi
    else
        output_result "SYS_PROFILE_UJAVA_VARIANT" "none"
    fi
    output_result "SYS_PROFILE_UJAVA_VARIANT_LEVEL" "正常"
}

# 主函数
main() {
    detect_platform_type
    detect_container_type
    detect_ujava_variant
}

main "$@"
```

**依赖**：`docker` 命令

---

### Step 2：平台服务检测模块 — 51_service_check.sh

**文件**：`skill/code/web/service_monitor/assets/service/51_service_check.sh`（新增）

**检测项**：约 20 个（服务状态 + 端口状态）

**实现要点**：

```bash
#!/bin/bash
################################################################################
# 51_service_check.sh — 平台服务检测
# 功能: 检测核心业务服务进程状态 + 容器端口监听
# 参考: ServiceCheck.psm1, check_server_health.sh
# 日期: 2026-07-22
################################################################################

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"

source "$LIB_DIR/lib/config.sh"
source "$LIB_DIR/lib/common.sh"

# 服务匹配模式（从 config.sh 读取或使用默认值）
UJAVA_SERVICES="${UJAVA_SERVICES:-auth:ubains-auth.jar,gateway:ubains-gateway.jar,system:ubains-modules-system.jar,meeting:ubains-meeting-inner-api-1.0-SNAPSHOT.jar,mqtt:ubains-meeting-mqtt-1.0-SNAPSHOT.jar,quartz:ubains-meeting-quartz-1.0-SNAPSHOT.jar,message:ubains-meeting-message-scheduling-1.0-SNAPSHOT.jar}"
UJAVA_HOST_SERVICES="${UJAVA_HOST_SERVICES:-extapi:ubains-meeting-api-1.0-SNAPSHOT.jar}"
UJAVA_OLD_CONTAINER_SERVICES="${UJAVA_OLD_CONTAINER_SERVICES:-nginx:nginx: master process,meeting:ubains-meeting-inner-api-1.0-SNAPSHOT.jar}"
UJAVA_OLD_HOST_SERVICES="${UJAVA_OLD_HOST_SERVICES:-extapi:ubains-meeting-api-1.0-SNAPSHOT.jar}"

# 端口列表
UPYTHON_PORTS_NEW="${UPYTHON_PORTS_NEW:-8000:uwsgi,11211:memcached}"
UPYTHON_VOICE_PORTS_NEW="${UPYTHON_VOICE_PORTS_NEW:-8000:uwsgi,11211:memcached,8080:nginx,1883:mosquitto,9001:mosquitto}"
UPYTHON_PORTS_OLD="${UPYTHON_PORTS_OLD:-8000:uwsgi,11211:memcached,8081:nginx,8443:nginx,8002:httpd}"

# 先检测平台类型和容器类型（内部实现，不依赖 50 模块）
detect_platform_type() {
    [ -d "/data/services" ] && echo "new" || echo "old"
}

detect_container_type() {
    local containers
    containers=$(docker ps --format '{{.Names}}' 2>/dev/null)
    if echo "$containers" | grep -qE '^ujava[0-9]*$'; then
        echo "ujava"
    elif echo "$containers" | grep -qE '^upython_voice[0-9]*$'; then
        echo "upython_voice"
    elif echo "$containers" | grep -qE '^upython[0-9]*$'; then
        echo "upython"
    else
        echo "unknown"
    fi
}

# 检测服务进程（容器内）
check_service_in_container() {
    local container="$1"
    local pattern="$2"
    local key="$3"
    local display_name="$4"
    
    local count
    count=$(docker exec "$container" ps aux 2>/dev/null | grep -F "$pattern" | grep -v grep | wc -l)
    
    if [ "$count" -gt 0 ]; then
        output_result "${key}_STATUS" "运行中"
        output_result "${key}_STATUS_LEVEL" "正常"
    else
        output_result "${key}_STATUS" "未运行"
        output_result "${key}_STATUS_LEVEL" "严重"
    fi
}

# 检测服务进程（宿主机）
check_service_on_host() {
    local pattern="$1"
    local key="$2"
    local path_hint="$3"  # 可选路径匹配
    
    local count
    if [ -n "$path_hint" ]; then
        count=$(ps aux 2>/dev/null | grep -F "$pattern" | grep -F "$path_hint" | grep -v grep | wc -l)
    else
        count=$(ps aux 2>/dev/null | grep -F "$pattern" | grep -v grep | wc -l)
    fi
    
    if [ "$count" -gt 0 ]; then
        output_result "${key}_STATUS" "运行中"
        output_result "${key}_STATUS_LEVEL" "正常"
    else
        output_result "${key}_STATUS" "未运行"
        output_result "${key}_STATUS_LEVEL" "严重"
    fi
}

# 检测端口监听（容器内，用进程检查代替 ss）
check_port_in_container() {
    local container="$1"
    local port="$2"
    local process="$3"
    local key="$4"
    
    local count
    count=$(docker exec "$container" ps aux 2>/dev/null | grep "$process" | grep -v grep | wc -l)
    
    if [ "$count" -gt 0 ]; then
        output_result "SVC_CHECK_PORT_${port}_STATUS" "监听"
        output_result "SVC_CHECK_PORT_${port}_STATUS_LEVEL" "正常"
    else
        output_result "SVC_CHECK_PORT_${port}_STATUS" "未监听"
        output_result "SVC_CHECK_PORT_${port}_STATUS_LEVEL" "严重"
    fi
}

# 主函数
main() {
    local platform_type container_type ujava_container upython_container
    
    platform_type=$(detect_platform_type)
    container_type=$(detect_container_type)
    
    # 获取容器名
    ujava_container=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^ujava[0-9]*$' | head -1)
    upython_container=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^upython' | head -1)
    
    if [ "$platform_type" = "new" ]; then
        # 新平台服务检测
        if [ "$container_type" = "ujava" ]; then
            # 容器内服务
            IFS=',' read -ra services <<< "$UJAVA_SERVICES"
            for svc in "${services[@]}"; do
                IFS=':' read -r key pattern <<< "$svc"
                check_service_in_container "$ujava_container" "$pattern" "SVC_CHECK_${key^^}" "$key"
            done
        fi
        
        # 宿主机 extapi
        IFS=',' read -ra host_services <<< "$UJAVA_HOST_SERVICES"
        for svc in "${host_services[@]}"; do
            IFS=':' read -r key pattern <<< "$svc"
            check_service_on_host "$pattern" "SVC_CHECK_${key^^}"
        done
        
        # upython/upython_voice 端口
        if [ "$container_type" = "upython" ]; then
            IFS=',' read -ra ports <<< "$UPYTHON_PORTS_NEW"
        elif [ "$container_type" = "upython_voice" ]; then
            IFS=',' read -ra ports <<< "$UPYTHON_VOICE_PORTS_NEW"
        fi
        for port_proc in "${ports[@]}"; do
            IFS=':' read -r port process <<< "$port_proc"
            check_port_in_container "$upython_container" "$port" "$process"
        done
    else
        # 传统平台服务检测
        if [ "$container_type" = "ujava" ]; then
            IFS=',' read -ra services <<< "$UJAVA_OLD_CONTAINER_SERVICES"
            for svc in "${services[@]}"; do
                IFS=':' read -r key pattern <<< "$svc"
                check_service_in_container "$ujava_container" "$pattern" "SVC_CHECK_${key^^}_OLD" "$key"
            done
        fi
        
        # 传统平台 extapi（宿主机）
        check_service_on_host "ubains-meeting-api-1.0-SNAPSHOT.jar" "SVC_CHECK_EXTAPI_OLD" "/var/www/java/external-meeting-api"
        
        # 传统平台 upython 端口
        IFS=',' read -ra ports <<< "$UPYTHON_PORTS_OLD"
        for port_proc in "${ports[@]}"; do
            IFS=':' read -r port process <<< "$port_proc"
            check_port_in_container "$upython_container" "$port" "$process"
        done
    fi
}

main "$@"
```

**依赖**：`docker`、`ps` 命令

---

### Step 3：配置IP检测模块 — 52_config_ip_check.sh

**文件**：`skill/code/web/service_monitor/assets/system/52_config_ip_check.sh`（新增）

**检测项**：

| KEY | 输出 |
|-----|------|
| `CFG_IP_STATUS` | OK/WARN |
| `CFG_IP_STATUS_LEVEL` | 正常/警告 |
| `CFG_IP_TOTAL_FILES` | 整数 |
| `CFG_IP_UNAUTHORIZED_COUNT` | 整数 |
| `CFG_IP_UNAUTHORIZED_LINES` | JSON 数组字符串 |

**实现要点**：

```bash
#!/bin/bash
################################################################################
# 52_config_ip_check.sh — 配置IP检测
# 功能: 扫描配置文件中的未授权 IP 地址
# 参考: ConfigIPCheck.psm1, config_check.sh
# 日期: 2026-07-22
################################################################################

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"

source "$LIB_DIR/lib/config.sh"
source "$LIB_DIR/lib/common.sh"

# IP 正则
IP_REGEX='([0-9]{1,3}\.){3}[0-9]{1,3}'

# 允许列表（从 config.sh 读取或使用默认值）
SERVER_IP="${SERVER_IP:-}"
ALLOWED_IPS="${SERVER_IP} 127.0.0.1 172.17.0.1"

# 新平台配置目录
NEW_PLATFORM_CONFIG_DIRS=(
    "/data/services/api/auth/auth-sso-auth/config"
    "/data/services/api/auth/auth-sso-gateway/config"
    "/data/services/api/auth/auth-sso-system/config"
    "/data/services/api/java-meeting/java-meeting2.0/config"
    "/data/services/api/java-meeting/java-meeting-extapi/config"
    "/data/services/api/java-meeting/java-message-scheduling/config"
    "/data/services/api/java-meeting/java-mqtt/config"
    "/data/services/api/java-meeting/java-quartz/config"
    "/data/services/api/python-cmdb"
    "/data/services/web/pc/pc-vue2-ai/static"
    "/data/services/web/mobile/mobile-vue2/static"
    "/data/middleware/nginx/config"
)

# 传统平台配置目录
OLD_PLATFORM_CONFIG_DIRS=(
    "/var/www/java/api-java-meeting2.0/config"
    "/var/www/java/external-meeting-api/config"
    "/var/www/java/ubains-web-2.0/static"
    "/var/www/java/ubains-web-admin/static"
    "/var/www/java/ubains-web-h5/static/h5"
    "/var/www/java/nginx-conf.d"
)

# 检测平台类型
detect_platform_type() {
    [ -d "/data/services" ] && echo "new" || echo "old"
}

# 扫描 IP
scan_config_ips() {
    local platform_type="$1"
    local -a config_dirs
    local total_files=0
    local unauthorized_count=0
    local unauthorized_lines=()
    
    if [ "$platform_type" = "new" ]; then
        config_dirs=("${NEW_PLATFORM_CONFIG_DIRS[@]}")
    else
        config_dirs=("${OLD_PLATFORM_CONFIG_DIRS[@]}")
    fi
    
    for dir in "${config_dirs[@]}"; do
        if [ ! -d "$dir" ]; then
            continue
        fi
        
        while IFS= read -r file; do
            ((total_files++))
            
            local line_num=0
            while IFS= read -r line; do
                ((line_num++))
                local ips
                ips=$(echo "$line" | grep -oE "$IP_REGEX" 2>/dev/null)
                
                for ip in $ips; do
                    if ! echo "$ALLOWED_IPS" | grep -qF "$ip"; then
                        ((unauthorized_count++))
                        unauthorized_lines+=("{\"file\":\"$file\",\"line\":$line_num,\"ip\":\"$ip\"}")
                    fi
                done
            done < "$file"
        done < <(find "$dir" -type f \( -name "*.yml" -o -name "*.properties" -o -name "config.js" -o -name "config.json" -o -name "*.conf" \) 2>/dev/null)
    done
    
    # 输出结果
    if [ "$unauthorized_count" -eq 0 ]; then
        output_result "CFG_IP_STATUS" "OK"
        output_result "CFG_IP_STATUS_LEVEL" "正常"
    else
        output_result "CFG_IP_STATUS" "WARN"
        output_result "CFG_IP_STATUS_LEVEL" "警告"
    fi
    
    output_result "CFG_IP_TOTAL_FILES" "$total_files"
    output_result "CFG_IP_UNAUTHORIZED_COUNT" "$unauthorized_count"
    
    # JSON 数组输出
    if [ ${#unauthorized_lines[@]} -gt 0 ]; then
        local json_array="["
        json_array+=$(IFS=,; echo "${unauthorized_lines[*]}")
        json_array+="]"
        output_result "CFG_IP_UNAUTHORIZED_LINES" "$json_array"
    else
        output_result "CFG_IP_UNAUTHORIZED_LINES" "[]"
    fi
}

main() {
    local platform_type
    platform_type=$(detect_platform_type)
    scan_config_ips "$platform_type"
}

main "$@"
```

**依赖**：`find`、`grep`、`SERVER_IP` 配置

---

### Step 4：Console配置检测模块 — 53_config_console_check.sh

**文件**：`skill/code/web/service_monitor/assets/system/53_config_console_check.sh`（新增）

**检测项**：

| KEY | 输出 |
|-----|------|
| `CFG_CONSOLE_STATUS` | OK/WARN |
| `CFG_CONSOLE_STATUS_LEVEL` | 正常/警告 |
| `CFG_CONSOLE_TOTAL_FILES` | 整数 |
| `CFG_CONSOLE_FOUND_COUNT` | 整数 |
| `CFG_CONSOLE_FOUND_FILES` | JSON 数组字符串 |

**实现要点**：

```bash
#!/bin/bash
################################################################################
# 53_config_console_check.sh — Console配置检测
# 功能: 检测 console=true 配置项未关闭问题（只检测不修复）
# 参考: check_server_health.sh (第1582-1708行)
# 日期: 2026-07-22
################################################################################

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"

source "$LIB_DIR/lib/config.sh"
source "$LIB_DIR/lib/common.sh"

# console 正则（不区分大小写）
CONSOLE_REGEX='console[[:space:]]*[:=][[:space:]]*true'

# 新平台配置目录（复用 IP 检测的目录列表）
NEW_PLATFORM_CONFIG_DIRS=(
    "/data/services/api/auth/auth-sso-auth/config"
    "/data/services/api/auth/auth-sso-gateway/config"
    "/data/services/api/auth/auth-sso-system/config"
    "/data/services/api/java-meeting/java-meeting2.0/config"
    "/data/services/api/java-meeting/java-meeting-extapi/config"
    "/data/services/api/java-meeting/java-message-scheduling/config"
    "/data/services/api/java-meeting/java-mqtt/config"
    "/data/services/api/java-meeting/java-quartz/config"
    "/data/services/api/python-cmdb"
    "/data/services/web/pc/pc-vue2-ai/static"
    "/data/services/web/mobile/mobile-vue2/static"
    "/data/middleware/nginx/config"
)

# 传统平台配置目录
OLD_PLATFORM_CONFIG_DIRS=(
    "/var/www/java/api-java-meeting2.0/config"
    "/var/www/java/external-meeting-api/config"
    "/var/www/java/ubains-web-2.0/static"
    "/var/www/java/ubains-web-admin/static"
    "/var/www/java/ubains-web-h5/static/h5"
    "/var/www/java/nginx-conf.d"
)

# 检测平台类型
detect_platform_type() {
    [ -d "/data/services" ] && echo "new" || echo "old"
}

# 扫描 console=true
scan_console_config() {
    local platform_type="$1"
    local -a config_dirs
    local total_files=0
    local found_count=0
    local found_files=()
    
    if [ "$platform_type" = "new" ]; then
        config_dirs=("${NEW_PLATFORM_CONFIG_DIRS[@]}")
    else
        config_dirs=("${OLD_PLATFORM_CONFIG_DIRS[@]}")
    fi
    
    for dir in "${config_dirs[@]}"; do
        if [ ! -d "$dir" ]; then
            continue
        fi
        
        while IFS= read -r file; do
            ((total_files++))
            
            if grep -qiE "$CONSOLE_REGEX" "$file" 2>/dev/null; then
                ((found_count++))
                found_files+=("\"$file\"")
            fi
        done < <(find "$dir" -type f \( -name "*.yml" -o -name "*.properties" -o -name "config.js" -o -name "config.json" \) 2>/dev/null)
    done
    
    # 输出结果
    if [ "$found_count" -eq 0 ]; then
        output_result "CFG_CONSOLE_STATUS" "OK"
        output_result "CFG_CONSOLE_STATUS_LEVEL" "正常"
    else
        output_result "CFG_CONSOLE_STATUS" "WARN"
        output_result "CFG_CONSOLE_STATUS_LEVEL" "警告"
    fi
    
    output_result "CFG_CONSOLE_TOTAL_FILES" "$total_files"
    output_result "CFG_CONSOLE_FOUND_COUNT" "$found_count"
    
    # JSON 数组输出
    if [ ${#found_files[@]} -gt 0 ]; then
        local json_array="["
        json_array+=$(IFS=,; echo "${found_files[*]}")
        json_array+="]"
        output_result "CFG_CONSOLE_FOUND_FILES" "$json_array"
    else
        output_result "CFG_CONSOLE_FOUND_FILES" "[]"
    fi
}

main() {
    local platform_type
    platform_type=$(detect_platform_type)
    scan_console_config "$platform_type"
}

main "$@"
```

**依赖**：`find`、`grep`

---

### Step 5：模块注册 — check_modules.py

**文件**：`skill/code/web/service_monitor/utils/check_modules.py`

**改动位置**：`ALL_MODULES` 列表

**新增内容**：

```python
# 在 system 类区块（46_security_deep 之后）
CheckModule("50_system_profile", "系统类型识别", "system",
            {SUITE_FULL}, "50_system_profile.sh"),
CheckModule("52_config_ip_check", "配置IP检测", "system",
            {SUITE_FULL}, "52_config_ip_check.sh"),
CheckModule("53_config_console_check", "Console配置检测", "system",
            {SUITE_FULL}, "53_config_console_check.sh"),

# 在 service 类区块（39_middleware_conn 之后）
CheckModule("51_service_check", "平台服务检测", "service",
            {SUITE_FULL}, "51_service_check.sh"),
```

**注意顺序**：`50_system_profile` 应在 `51_service_check` 之前，确保平台类型先被识别。

---

### Step 6：显示名映射 — display_names.py

**文件**：`skill/code/web/service_monitor/utils/display_names.py`

**新增内容**（约 35 个 KEY）：

```python
# ==================== 系统类型识别 (50_system_profile) ====================
"SYS_PROFILE_PLATFORM_TYPE": "平台类型",
"SYS_PROFILE_PLATFORM_TYPE_LEVEL": "平台类型状态等级",
"SYS_PROFILE_CONTAINER_TYPE": "容器类型",
"SYS_PROFILE_CONTAINER_TYPE_LEVEL": "容器类型状态等级",
"SYS_PROFILE_UJAVA_VARIANT": "ujava变体",
"SYS_PROFILE_UJAVA_VARIANT_LEVEL": "ujava变体状态等级",

# ==================== 平台服务检测 (51_service_check) ====================
"SVC_CHECK_AUTH_STATUS": "认证服务状态",
"SVC_CHECK_AUTH_STATUS_LEVEL": "认证服务状态等级",
"SVC_CHECK_GATEWAY_STATUS": "网关服务状态",
"SVC_CHECK_GATEWAY_STATUS_LEVEL": "网关服务状态等级",
"SVC_CHECK_SYSTEM_STATUS": "系统服务状态",
"SVC_CHECK_SYSTEM_STATUS_LEVEL": "系统服务状态等级",
"SVC_CHECK_MEETING_STATUS": "会议服务状态",
"SVC_CHECK_MEETING_STATUS_LEVEL": "会议服务状态等级",
"SVC_CHECK_MQTT_STATUS": "MQTT服务状态",
"SVC_CHECK_MQTT_STATUS_LEVEL": "MQTT服务状态等级",
"SVC_CHECK_QUARTZ_STATUS": "定时任务服务状态",
"SVC_CHECK_QUARTZ_STATUS_LEVEL": "定时任务服务状态等级",
"SVC_CHECK_MESSAGE_STATUS": "消息调度服务状态",
"SVC_CHECK_MESSAGE_STATUS_LEVEL": "消息调度服务状态等级",
"SVC_CHECK_EXTAPI_STATUS": "对外API服务状态",
"SVC_CHECK_EXTAPI_STATUS_LEVEL": "对外API服务状态等级",
# 传统平台服务
"SVC_CHECK_NGINX_OLD_STATUS": "Nginx服务状态(传统)",
"SVC_CHECK_NGINX_OLD_STATUS_LEVEL": "Nginx服务状态等级(传统)",
"SVC_CHECK_MEETING_OLD_STATUS": "会议服务状态(传统)",
"SVC_CHECK_MEETING_OLD_STATUS_LEVEL": "会议服务状态等级(传统)",
"SVC_CHECK_EXTAPI_OLD_STATUS": "对外API服务状态(传统)",
"SVC_CHECK_EXTAPI_OLD_STATUS_LEVEL": "对外API服务状态等级(传统)",
# 端口检测
"SVC_CHECK_PORT_8000_STATUS": "uWSGI端口8000状态",
"SVC_CHECK_PORT_8000_STATUS_LEVEL": "uWSGI端口8000状态等级",
"SVC_CHECK_PORT_11211_STATUS": "Memcached端口11211状态",
"SVC_CHECK_PORT_11211_STATUS_LEVEL": "Memcached端口11211状态等级",
"SVC_CHECK_PORT_8080_STATUS": "Nginx端口8080状态",
"SVC_CHECK_PORT_8080_STATUS_LEVEL": "Nginx端口8080状态等级",
"SVC_CHECK_PORT_1883_STATUS": "MQTT端口1883状态",
"SVC_CHECK_PORT_1883_STATUS_LEVEL": "MQTT端口1883状态等级",

# ==================== 配置IP检测 (52_config_ip_check) ====================
"CFG_IP_STATUS": "配置IP检测状态",
"CFG_IP_STATUS_LEVEL": "配置IP检测状态等级",
"CFG_IP_TOTAL_FILES": "扫描文件数",
"CFG_IP_UNAUTHORIZED_COUNT": "未授权IP数",
"CFG_IP_UNAUTHORIZED_LINES": "未授权IP明细",

# ==================== Console配置检测 (53_config_console_check) ====================
"CFG_CONSOLE_STATUS": "Console配置检测状态",
"CFG_CONSOLE_STATUS_LEVEL": "Console配置检测状态等级",
"CFG_CONSOLE_TOTAL_FILES": "扫描文件数",
"CFG_CONSOLE_FOUND_COUNT": "发现问题数",
"CFG_CONSOLE_FOUND_FILES": "问题文件列表",
```

---

### Step 7：阈值配置 — thresholds.py

**文件**：`skill/code/web/service_monitor/utils/thresholds.py`

**新增内容**（可选，状态检测通常用 LEVEL 字段）：

```python
# 如果需要数值型阈值，可添加：
# "CFG_IP_UNAUTHORIZED_COUNT": {"warning": 1, "critical": 10},
# "CFG_CONSOLE_FOUND_COUNT": {"warning": 1, "critical": 5},
```

**状态词映射**（在 `_VALUE_STATUS_MAP` 中添加）：

```python
# 状态词 → 状态等级映射
"运行中": "正常",
"未运行": "严重",
"监听": "正常",
"未监听": "严重",
```

---

### Step 8：配置模板 — config.sh.template

**文件**：`skill/code/web/service_monitor/assets/config.sh.template`

**新增内容**：

```bash
# ==================== 平台服务检测配置 ====================
# ujava 服务匹配模式（新平台）
export UJAVA_SERVICES="auth:ubains-auth.jar,gateway:ubains-gateway.jar,system:ubains-modules-system.jar,meeting:ubains-meeting-inner-api-1.0-SNAPSHOT.jar,mqtt:ubains-meeting-mqtt-1.0-SNAPSHOT.jar,quartz:ubains-meeting-quartz-1.0-SNAPSHOT.jar,message:ubains-meeting-message-scheduling-1.0-SNAPSHOT.jar"

# ujava 宿主机服务
export UJAVA_HOST_SERVICES="extapi:ubains-meeting-api-1.0-SNAPSHOT.jar"

# 传统平台 ujava 容器服务
export UJAVA_OLD_CONTAINER_SERVICES="nginx:nginx: master process,meeting:ubains-meeting-inner-api-1.0-SNAPSHOT.jar"

# 传统平台 ujava 宿主机服务
export UJAVA_OLD_HOST_SERVICES="extapi:ubains-meeting-api-1.0-SNAPSHOT.jar"

# upython 端口列表（新平台）
export UPYTHON_PORTS_NEW="8000:uwsgi,11211:memcached"

# upython_voice 端口列表（新平台）
export UPYTHON_VOICE_PORTS_NEW="8000:uwsgi,11211:memcached,8080:nginx,1883:mosquitto,9001:mosquitto"

# upython 端口列表（传统平台）
export UPYTHON_PORTS_OLD="8000:uwsgi,11211:memcached,8081:nginx,8443:nginx,8002:httpd"

# ==================== 配置IP检测配置 ====================
# 允许的 IP 列表（服务器IP 在运行时注入）
# 格式：空格分隔的 IP 列表
# export ALLOWED_IPS="__SERVER_IP__ 127.0.0.1 172.17.0.1"
```

---

## 验收标准

| 验收项 | 验证方法 |
|--------|---------|
| 4 个脚本语法正确 | `bash -n script.sh` 无报错 |
| 模块已注册 | `get_suite('full')` 返回 34 个模块 |
| 显示名已添加 | 新 KEY 在 `DISPLAY_NAMES` 中存在 |
| 单元测试通过 | `pytest` 全绿（218 个 + 新增测试） |
| 服务检测正确 | 在 5.44 目标运行，结果与 `docker ps` 一致 |
| 配置 IP 检测正确 | 人工抽查配置文件验证 |
| Console 检测正确 | 人工抽查配置文件验证 |

---

## 测试计划

### 单元测试

1. **check_modules.test_get_suite**：验证 `get_suite('full')` 包含新模块
2. **check_modules.test_render_config**：验证新配置项渲染正确

### 集成测试

1. 在 5.44 目标运行 `full` 套件
2. 检查报告中新检测项输出
3. 对比 `docker ps` 验证服务检测准确性
4. 抽查配置文件验证 IP/Console 检测准确性

---

## 风险与缓解

| 风险 | 缓解措施 |
|------|---------|
| 配置目录不存在 | 脚本内做存在性检查，graceful 跳过 |
| 容器名匹配失败 | 使用 `grep -iE` 模糊匹配 + 默认值 |
| 新旧平台混合 | 先检测平台类型，分支执行 |
| 端口检测容器内无 ss | 用进程检查代替端口检测 |

---

## 实施记录

| 步骤 | 状态 | 说明 |
|------|------|------|
| Step 1: 50_system_profile.sh | ⬜ 待实施 | |
| Step 2: 51_service_check.sh | ⬜ 待实施 | |
| Step 3: 52_config_ip_check.sh | ⬜ 待实施 | |
| Step 4: 53_config_console_check.sh | ⬜ 待实施 | |
| Step 5: check_modules.py | ⬜ 待实施 | |
| Step 6: display_names.py | ⬜ 待实施 | |
| Step 7: thresholds.py | ⬜ 待实施 | |
| Step 8: config.sh.template | ⬜ 待实施 | |
| 集成测试 | ⬜ 待实施 | |
| 部署验证 | ⬜ 待实施 | |

---

## 后续工作

- P3 级模块移植：文件权限、定时任务预期、FastDFS 等
- 服务检测扩展：支持自定义服务匹配模式
- 配置 IP 检测增强：IP 白名单可配置化
