allinssl/frontend/scripts/tools/notice-handle.sh

695 lines
16 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/bin/bash
#######################################
# 通知处理脚本
#
# 此脚本提供了一系列用于在终端中显示不同类型通知的函数,
# 包括普通信息、成功、警告、错误、调试信息等,以及交互式
# 的用户输入、确认、单选和多选菜单功能。
#
# 作者: chudong
# 版本: 1.0.0
#######################################
# 定义颜色
RED='\033[0;31m' # 错误
GREEN='\033[0;32m' # 成功
YELLOW='\033[0;33m' # 警告
BLUE='\033[0;34m' # 信息
PURPLE='\033[0;35m' # 调试
CYAN='\033[0;36m' # 提示
NC='\033[0m' # 无颜色
#######################################
# 普通信息通知
# 参数:
# $1: 消息内容
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
notice_info() {
local message="$1"
if [ -z "$message" ]; then
echo "${BLUE}[信息] 未提供消息内容${NC}"
return 1
fi
echo "${BLUE}[信息] $message${NC}"
return 0
}
#######################################
# 成功信息通知
# 参数:
# $1: 消息内容
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
notice_success() {
local message="$1"
if [ -z "$message" ]; then
echo "${GREEN}[成功] 未提供消息内容${NC}"
return 1
fi
echo "${GREEN}[成功] $message${NC}"
return 0
}
#######################################
# 警告信息通知
# 参数:
# $1: 消息内容
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
notice_warning() {
local message="$1"
if [ -z "$message" ]; then
echo "${YELLOW}[警告] 未提供消息内容${NC}"
return 1
fi
echo "${YELLOW}[警告] $message${NC}"
return 0
}
#######################################
# 错误信息通知
# 参数:
# $1: 消息内容
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
notice_error() {
local message="$1"
if [ -z "$message" ]; then
echo "${RED}[错误] 未提供消息内容${NC}"
return 1
fi
echo "${RED}[错误] $message${NC}"
return 0
}
#######################################
# 调试信息通知(仅在调试模式下显示)
# 参数:
# $1: 消息内容
# 环境变量:
# DEBUG: 设置为 "true" 时启用调试输出
# 返回值:
# 0 - 成功
# 1 - 失败(仅在调试模式下且未提供消息内容时)
#######################################
notice_debug() {
local message="$1"
local debug_mode="${DEBUG:-false}"
if [ "$debug_mode" = "true" ]; then
if [ -z "$message" ]; then
echo "${PURPLE}[调试] 未提供消息内容${NC}"
return 1
fi
echo "${PURPLE}[调试] $message${NC}"
fi
return 0
}
#######################################
# 系统通知(使用系统原生通知功能)
# 参数:
# $1: 通知标题
# $2: 通知消息内容
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
notice_system() {
local title="$1"
local message="$2"
if [ -z "$title" ] || [ -z "$message" ]; then
echo "${RED}[错误] 系统通知需要标题和消息内容${NC}"
return 1
fi
# 检测系统类型,使用适当的系统通知方法
if [ "$(uname)" = "Darwin" ]; then
# MacOS
osascript -e "display notification \"$message\" with title \"$title\""
elif [ "$(uname)" = "Linux" ] && command -v notify-send &> /dev/null; then
# Linux 并且有 notify-send
notify-send "$title" "$message"
else
# 回退到普通输出
echo "${CYAN}[系统通知] $title: $message${NC}"
fi
return 0
}
#######################################
# 进度条通知
# 参数:
# $1: 当前进度值
# $2: 总进度值
# $3: 进度描述 (可选,默认为"处理中")
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
notice_progress() {
local current="$1"
local total="$2"
local description="${3:-处理中}"
if [ -z "$current" ] || [ -z "$total" ]; then
echo "${RED}[错误] 进度条需要当前值和总值${NC}"
return 1
fi
# 计算百分比
local percent=$((current * 100 / total))
local completed=$((percent / 2))
local remaining=$((50 - completed))
# 创建进度条
local bar="["
for ((i=0; i<completed; i++)); do
bar+="#"
done
for ((i=0; i<remaining; i++)); do
bar+="-"
done
bar+="] $percent%"
# 显示进度条
echo -n "${CYAN}$description: $bar\r${NC}"
# 如果完成了,添加换行
if [ "$current" -ge "$total" ]; then
echo ""
fi
return 0
}
#######################################
# 用户输入提示
# 参数:
# $1: 提示文本
# $2: 用于存储用户输入的变量名
# $3: 默认值 (可选)
# 返回值:
# 0 - 成功
# 1 - 失败
# 注意:
# 此函数通过 eval 设置调用者环境中的变量,
# 必须通过 source 方式调用脚本才能生效
#######################################
notice_prompt() {
local prompt="$1"
local variable_name="$2"
local default_value="$3"
if [ -z "$prompt" ] || [ -z "$variable_name" ]; then
echo "${RED}[错误] 用户输入提示需要提示文本和变量名${NC}"
return 1
fi
local input=""
# 显示带有默认值的提示(如果有)
if [ -n "$default_value" ]; then
echo -n "${CYAN}$prompt [${default_value}]: ${NC}"
read input
# 如果用户未输入任何内容,使用默认值
if [ -z "$input" ]; then
input="$default_value"
fi
else
echo -n "${CYAN}$prompt: ${NC}"
read input
fi
# 为调用脚本设置变量
# 注意:这只在 source 调用此脚本时有效
eval "$variable_name=\"$input\""
return 0
}
#######################################
# 确认消息通知(询问用户是/否)
# 参数:
# $1: 提示文本
# $2: 默认选项 (可选,"y"或"n",默认为"n")
# 返回值:
# 0 - 用户确认是
# 1 - 用户确认否
#######################################
notice_confirm() {
local message="$1"
local default="${2:-n}" # 默认为否
if [ -z "$message" ]; then
echo "${RED}[错误] 确认消息需要提示文本${NC}"
return 1
fi
local prompt=""
# 根据默认值设置提示
if [ "$default" = "y" ]; then
prompt="[Y/n]"
else
prompt="[y/N]"
fi
# 询问用户
while true; do
echo -n "${CYAN}$message $prompt ${NC}"
read response
# 如果用户未输入任何内容,使用默认值
if [ -z "$response" ]; then
response="$default"
fi
# 检查响应
case "$response" in
[Yy]*)
return 0
;;
[Nn]*)
return 1
;;
*)
echo "${YELLOW}请输入 y 或 n${NC}"
;;
esac
done
}
#######################################
# 单选菜单函数,支持键盘方向键控制
# 参数:
# $1: 菜单标题
# $2: 用于存储选择结果的变量名
# $3...$n: 菜单选项
# 使用方法:
# notice_select_menu "请选择一个选项" "selected_option" "选项1" "选项2" "选项3"
# echo "用户选择了: $selected_option"
# 返回值:
# 0 - 用户选择了一个选项
# 1 - 用户取消选择 (按q)
# 2 - 参数错误
#######################################
notice_select_menu() {
local title="$1"
local return_var="$2"
# 检查参数
if [ -z "$title" ] || [ -z "$return_var" ] || [ $# -lt 3 ]; then
echo "${RED}[错误] 单选菜单需要标题、返回变量名和至少一个选项${NC}"
return 2
fi
# 移除前两个参数,剩下的是菜单选项
shift 2
local options=("$@")
local selected=0
local option_count=${#options[@]}
local result=""
# 检查是否支持 tput (但不强制依赖)
local has_tput=false
if command -v tput &>/dev/null; then
has_tput=true
fi
# 隐藏光标 (如果支持)
if [ "$has_tput" = true ]; then
tput civis 2>/dev/null || true
fi
# 保存终端设置
local saved_tty=""
if [ -t 0 ]; then
saved_tty=$(stty -g)
fi
# 设置终端为非规范模式,禁用回显
stty -icanon -echo 2>/dev/null || true
while true; do
# 清屏和显示标题
clear 2>/dev/null || printf "\033c" || echo -e "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
echo "${CYAN}$title${NC}"
echo "${CYAN}(使用方向键↑↓移动回车确认q退出)${NC}"
echo ""
# 显示选项
for i in "${!options[@]}"; do
if [ $i -eq $selected ]; then
echo "${GREEN}>> $((i+1)). ${options[$i]} <<${NC}"
else
echo " $((i+1)). ${options[$i]}"
fi
done
# 读取用户输入
local key=""
IFS= read -r -s -n1 key
# 处理特殊键
if [[ $key == $'\e' ]]; then
if read -r -s -n2 -t 0.1 key2; then
key+="$key2"
fi
case "$key" in
$'\e[A') # 上箭头
((selected--))
if [ $selected -lt 0 ]; then
selected=$((option_count - 1))
fi
;;
$'\e[B') # 下箭头
((selected++))
if [ $selected -ge $option_count ]; then
selected=0
fi
;;
$'\e[C'|$'\e[D') # 左右箭头 (忽略)
;;
*) # 其他ESC序列 (忽略)
;;
esac
continue
fi
# 处理其他键
case "$key" in
"q"|"Q")
# 恢复终端设置
if [ -n "$saved_tty" ]; then
stty "$saved_tty" 2>/dev/null || true
fi
# 显示光标 (如果支持)
if [ "$has_tput" = true ]; then
tput cnorm 2>/dev/null || true
fi
echo ""
return 1
;;
"w"|"W") # 向上兼容原始的 w/s 控制
((selected--))
if [ $selected -lt 0 ]; then
selected=$((option_count - 1))
fi
;;
"s"|"S") # 向上兼容原始的 w/s 控制
((selected++))
if [ $selected -ge $option_count ]; then
selected=0
fi
;;
"") # 回车键
result="$selected"
break
;;
[0-9]) # 数字键 - 直接跳转
local num=$((key - 1))
if [ $num -ge 0 ] && [ $num -lt $option_count ]; then
selected=$num
result="$selected"
break
fi
;;
esac
done
# 恢复终端设置
if [ -n "$saved_tty" ]; then
stty "$saved_tty" 2>/dev/null || true
fi
# 显示光标 (如果支持)
if [ "$has_tput" = true ]; then
tput cnorm 2>/dev/null || true
fi
# 设置返回变量
eval "$return_var=\"$result\""
echo ""
echo "${GREEN}已选择: ${options[$result]}${NC}"
return 0
}
#######################################
# 多选菜单函数,支持键盘方向键控制
# 参数:
# $1: 菜单标题
# $2: 用于存储选择结果的变量名 (将存储为选中项的索引,用逗号分隔)
# $3...$n: 菜单选项
# 使用方法:
# notice_multi_select_menu "请选择多个选项" "selected_options" "选项1" "选项2" "选项3"
# echo "用户选择了索引: $selected_options"
# IFS=',' read -ra SELECTED_INDICES <<< "$selected_options"
# for i in "${SELECTED_INDICES[@]}"; do
# echo "选中了选项: ${原选项数组[$i]}"
# done
# 返回值:
# 0 - 用户完成选择
# 1 - 用户取消选择 (按q)
# 2 - 参数错误
#######################################
notice_multi_select_menu() {
local title="$1"
local return_var="$2"
# 检查参数
if [ -z "$title" ] || [ -z "$return_var" ] || [ $# -lt 3 ]; then
echo "${RED}[错误] 多选菜单需要标题、返回变量名和至少一个选项${NC}"
return 2
fi
# 移除前两个参数,剩下的是菜单选项
shift 2
local options=("$@")
local cursor=0
local option_count=${#options[@]}
local result=""
# 初始化选中状态数组 (0表示未选中1表示已选中)
local selected_status=()
for ((i=0; i<option_count; i++)); do
selected_status[$i]=0
done
# 检查是否支持 tput (但不强制依赖)
local has_tput=false
if command -v tput &>/dev/null; then
has_tput=true
fi
# 隐藏光标 (如果支持)
if [ "$has_tput" = true ]; then
tput civis 2>/dev/null || true
fi
# 保存终端设置
local saved_tty=""
if [ -t 0 ]; then
saved_tty=$(stty -g)
fi
# 设置终端为非规范模式,禁用回显
stty -icanon -echo 2>/dev/null || true
while true; do
# 清屏和显示标题
clear 2>/dev/null || printf "\033c" || echo -e "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
echo "${CYAN}$title${NC}"
echo "${CYAN}(使用方向键↑↓移动,空格键选择/取消回车确认q退出)${NC}"
echo ""
# 显示选项
for i in "${!options[@]}"; do
if [ $i -eq $cursor ]; then
if [ ${selected_status[$i]} -eq 1 ]; then
echo "${GREEN}>> [X] ${options[$i]} <<${NC}"
else
echo "${GREEN}>> [ ] ${options[$i]} <<${NC}"
fi
else
if [ ${selected_status[$i]} -eq 1 ]; then
echo " [X] ${options[$i]}"
else
echo " [ ] ${options[$i]}"
fi
fi
done
# 读取用户输入
local key=""
IFS= read -r -s -n1 key
# 处理特殊键
if [[ $key == $'\e' ]]; then
if read -r -s -n2 -t 0.1 key2; then
key+="$key2"
fi
case "$key" in
$'\e[A') # 上箭头
((cursor--))
if [ $cursor -lt 0 ]; then
cursor=$((option_count - 1))
fi
;;
$'\e[B') # 下箭头
((cursor++))
if [ $cursor -ge $option_count ]; then
cursor=0
fi
;;
$'\e[C') # 右箭头 (忽略)
;;
$'\e[D') # 左箭头 (忽略)
;;
*) # 其他ESC序列 (忽略)
;;
esac
continue
fi
# 处理其他键
case "$key" in
"q"|"Q")
# 恢复终端设置
if [ -n "$saved_tty" ]; then
stty "$saved_tty" 2>/dev/null || true
fi
# 显示光标 (如果支持)
if [ "$has_tput" = true ]; then
tput cnorm 2>/dev/null || true
fi
echo ""
return 1
;;
" ") # 空格键
# 切换选中状态
if [ ${selected_status[$cursor]} -eq 0 ]; then
selected_status[$cursor]=1
else
selected_status[$cursor]=0
fi
;;
"") # 回车键
# 构建结果字符串 (选中项的索引,用逗号分隔)
local first=true
for i in "${!selected_status[@]}"; do
if [ ${selected_status[$i]} -eq 1 ]; then
if [ "$first" = true ]; then
result="$i"
first=false
else
result="$result,$i"
fi
fi
done
break
;;
[0-9]) # 数字键 - 直接跳转
local num=$((key))
if [ $num -lt $option_count ]; then
cursor=$num
fi
;;
esac
done
# 恢复终端设置
if [ -n "$saved_tty" ]; then
stty "$saved_tty" 2>/dev/null || true
fi
# 显示光标 (如果支持)
if [ "$has_tput" = true ]; then
tput cnorm 2>/dev/null || true
fi
# 设置返回变量
eval "$return_var=\"$result\""
echo ""
echo "${GREEN}已选择索引: $result${NC}"
# 显示已选项
if [ -n "$result" ]; then
echo "${GREEN}已选择选项:${NC}"
IFS=',' read -ra SELECTED_INDICES <<< "$result"
for i in "${SELECTED_INDICES[@]}"; do
echo "${GREEN} - ${options[$i]}${NC}"
done
else
echo "${YELLOW}未选择任何选项${NC}"
fi
return 0
}
#######################################
# 使用示例
#######################################
# notice_info "这是一条信息通知"
# notice_success "操作成功完成"
# notice_warning "请注意这个警告"
# notice_error "发生了错误"
# DEBUG=true notice_debug "这是调试信息"
# notice_system "系统通知" "这是一条系统通知消息"
# # 进度条示例
# for i in {1..10}; do
# notice_progress $i 10 "文件下载中"
# sleep 0.5
# done
# # 用户输入示例
# notice_prompt "请输入您的名字" "user_name"
# echo "您好, $user_name!"
# # 确认示例
# if notice_confirm "是否继续?"; then
# echo "用户选择继续"
# else
# echo "用户选择取消"
# fi
# # 单选菜单示例
# notice_select_menu "请选择一个操作系统" "selected_os" "Linux" "MacOS" "Windows" "其他"
# echo "您选择了: $selected_os"
# # 多选菜单示例
# notice_multi_select_menu "请选择您喜欢的编程语言" "selected_langs" "Python" "JavaScript" "Bash" "Go" "Rust" "Java"
# echo "选择的索引: $selected_langs"