美化终端脚本 UI 并修复对齐与闪屏

- 配色体系:256 色语义色板(primary/accent/success/warn/danger)与统一图标常量
- 修复右边框对齐:ctms_text_width 用 perl 精确计算显示宽度,剥离 sgr0 的 \e(B 序列
- 修复菜单闪屏:改用光标归位原地覆盖重绘,去掉每帧清屏
- 美化各面板:install.sh banner/确认/成功框、根菜单、status.sh 资源表格,标签列对齐
- 新增 ctms_pad_right 按显示宽度填充含中文标签

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Cheng Zhou
2026-06-23 15:24:22 +08:00
parent c351ca59c4
commit efc325568d
10 changed files with 1101 additions and 310 deletions
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=scripts/common.sh
source "$SCRIPT_DIR/common.sh"
usage() {
cat <<EOF
${C_BOLD}用法:${C_RESET}
bash scripts/status.sh <环境>
${C_BOLD}环境:${C_RESET}
dev | main | release
${C_BOLD}说明:${C_RESET}
使用 docker compose stats --no-stream 获取资源快照,并输出整理后的状态面板。
EOF
}
STATS_OUTPUT=""
STATS_ERROR=""
STATUS_BOX_WIDTH=127
collect_compose_stats() {
local env="$1"
local output="" exit_code=0
STATS_OUTPUT=""
STATS_ERROR=""
set +e
output="$(ctms_compose "$env" stats --all --no-stream \
--format '{{.Name}}|{{.CPUPerc}}|{{.MemUsage}}|{{.MemPerc}}|{{.NetIO}}|{{.BlockIO}}|{{.PIDs}}' 2>&1)"
exit_code=$?
set -e
if [[ "$exit_code" -ne 0 ]]; then
set +e
output="$(ctms_compose "$env" stats --all --no-stream \
--format '{{.Container}}|{{.CPUPerc}}|{{.MemUsage}}|{{.MemPerc}}|{{.NetIO}}|{{.BlockIO}}|{{.PIDs}}' 2>&1)"
exit_code=$?
set -e
fi
if [[ "$exit_code" -ne 0 ]]; then
STATS_ERROR="$output"
return "$exit_code"
fi
STATS_OUTPUT="$output"
}
render_stats_panel() {
local env="$1"
local project="$2"
local generated_at
generated_at="$(date '+%Y-%m-%d %H:%M:%S')"
printf '\n'
ctms_box_top "${CC_PRIMARY}${C_BOLD}" "CTMS 资源状态快照" "$STATUS_BOX_WIDTH"
ctms_box_line "${CC_PRIMARY}${C_BOLD}" "$STATUS_BOX_WIDTH" "环境 ${env} Compose 项目 ${project} 时间 ${generated_at}" "${CC_MUTED}环境${C_RESET} ${CC_INFO}${C_BOLD}${env}${C_RESET} ${CC_MUTED}Compose 项目${C_RESET} ${CC_INFO}${C_BOLD}${project}${C_RESET} ${CC_MUTED}时间 ${generated_at}${C_RESET}"
ctms_box_bottom "${CC_PRIMARY}${C_BOLD}" "$STATUS_BOX_WIDTH"
printf '\n'
if [[ -n "$STATS_ERROR" ]]; then
printf ' %s%s%s %s无法获取 docker compose stats 快照%s\n' "${CC_DANGER}${C_BOLD}" "$ICON_FAIL" "${C_RESET}" "${CC_DANGER}" "${C_RESET}"
printf ' %s环境%s %s %sCompose 项目%s %s\n' "${CC_MUTED}" "${C_RESET}" "$env" "${CC_MUTED}" "${C_RESET}" "$project"
printf ' %s原因%s %s\n\n' "${CC_MUTED}" "${C_RESET}" "$STATS_ERROR"
return 1
fi
if [[ -z "$STATS_OUTPUT" ]]; then
printf ' %s%s%s %s未获取到容器资源数据%s\n' "${CC_WARN}${C_BOLD}" "$ICON_WARN" "${C_RESET}" "${CC_WARN}" "${C_RESET}"
printf ' %s可能原因:该环境尚未部署,或所有容器已被移除。%s\n\n' "${CC_MUTED}" "${C_RESET}"
return
fi
ctms_box_top "${CC_ACCENT}${C_BOLD}" "容器资源" "$STATUS_BOX_WIDTH"
ctms_box_line "${CC_ACCENT}${C_BOLD}" "$STATUS_BOX_WIDTH" "$(printf '%-22s %-9s %-27s %-8s %-21s %-21s %-6s' "容器" "CPU" "内存使用 / 限制" "内存%" "网络 I/O" "磁盘 I/O" "PIDs")" "${CC_MUTED}$(printf '%-22s %-9s %-27s %-8s %-21s %-21s %-6s' "容器" "CPU" "内存使用 / 限制" "内存%" "网络 I/O" "磁盘 I/O" "PIDs")${C_RESET}"
printf '%s├%s┤%s\n' "${CC_ACCENT}${C_BOLD}" "$(ctms_repeat_char '─' "$(( STATUS_BOX_WIDTH - 2 ))")" "${C_RESET}"
printf '%s\n' "$STATS_OUTPUT" | while IFS='|' read -r name cpu mem mem_percent net_io block_io pids; do
[[ -n "$name" ]] || continue
ctms_box_line "${CC_ACCENT}${C_BOLD}" "$STATUS_BOX_WIDTH" "$(printf '%-22.22s %-9.9s %-27.27s %-8.8s %-21.21s %-21.21s %-6.6s' "$name" "$cpu" "$mem" "$mem_percent" "$net_io" "$block_io" "$pids")"
done
ctms_box_bottom "${CC_ACCENT}${C_BOLD}" "$STATUS_BOX_WIDTH"
printf '\n'
printf ' %s数据来源%s docker compose stats --all --no-stream\n\n' "${CC_MUTED}" "${C_RESET}"
}
main() {
if [[ $# -ne 1 ]]; then
usage
exit 1
fi
local env="$1"
local project=""
ctms_require_env "$env"
project="$(ctms_project_name "$env")"
ctms_require_docker_compose
cd "$CTMS_ROOT_DIR"
collect_compose_stats "$env" || true
render_stats_panel "$env" "$project"
}
main "$@"