feat: 增加手机号脱敏显示

This commit is contained in:
zerosaturation 2026-04-08 10:59:46 +08:00
parent baf56d5ecf
commit eff7b8d6f0
5 changed files with 82 additions and 144 deletions

View File

@ -34,6 +34,7 @@ type UserWithIdentityDTO struct {
SlotLimit int32 `json:"slot_limit"` SlotLimit int32 `json:"slot_limit"`
AssetsNum int32 `json:"assets_num"` // assets_count AssetsNum int32 `json:"assets_num"` // assets_count
CrystalBalance int64 `json:"crystal_balance"` CrystalBalance int64 `json:"crystal_balance"`
MobileMasked string `json:"mobile_masked,omitempty"` // 脱敏手机号,如 139****0001
} }
// ========== 认证相关响应 ========== // ========== 认证相关响应 ==========

View File

@ -57,6 +57,11 @@ func ToUserWithIdentityDTO(user *pb.User, profile *pb.FanProfile, star *pb.Star)
dto.FanIdentity = ToFanIdentityDTO(star) dto.FanIdentity = ToFanIdentityDTO(star)
} }
// 脱敏手机号139****0001
if user.Mobile != "" && len(user.Mobile) == 11 {
dto.MobileMasked = user.Mobile[:3] + "****" + user.Mobile[7:]
}
return dto return dto
} }

View File

@ -45,12 +45,8 @@ NC='\033[0m'
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR" cd "$SCRIPT_DIR"
# ==================== 镜像仓库配置 ==================== # ==================== 镜像配置 ====================
# ⚠️ 需要修改为你的阿里云仓库地址 # 本地构建后打包传输到服务器,不需要镜像仓库
REGISTRY_HOST="registry.cn-hangzhou.aliyuncs.com"
NAMESPACE="你的命名空间" # ⚠️ 修改这里
# 服务列表(必须与 docker-compose 中的服务名一致)
SERVICES=( SERVICES=(
"gateway" "gateway"
"userservice" "userservice"
@ -62,7 +58,7 @@ SERVICES=(
# ==================== 服务器配置 ==================== # ==================== 服务器配置 ====================
# ⚠️ 修改为你的服务器信息 # ⚠️ 修改为你的服务器信息
SERVER_HOST="" # 服务器 IP 或域名 SERVER_HOST="101.132.250.62" # 服务器 IP 或域名
SERVER_PORT="22" # SSH 端口 SERVER_PORT="22" # SSH 端口
SERVER_USER="root" # SSH 用户名 SERVER_USER="root" # SSH 用户名
SERVER_PATH="/opt/topfans/docker" # 服务器上 docker 目录路径 SERVER_PATH="/opt/topfans/docker" # 服务器上 docker 目录路径
@ -90,31 +86,30 @@ ${YELLOW}用法:${NC}
$0 <命令> [版本号] [选项] $0 <命令> [版本号] [选项]
${YELLOW}命令:${NC} ${YELLOW}命令:${NC}
${GREEN}build${NC} <版本号> 本地构建镜像并推送到仓库 ${GREEN}build${NC} <版本号> 本地构建镜像并打包传输到服务器
${GREEN}deploy${NC} <版本号> 远程部署(从仓库拉取 + 启动服务) ${GREEN}deploy${NC} <版本号> 远程部署(加载镜像 + 启动服务)
${GREEN}rollback${NC} <版本号> 回滚到指定版本 ${GREEN}rollback${NC} <版本号> 回滚到指定版本
${GREEN}history${NC} 查看部署历史 ${GREEN}history${NC} 查看部署历史
${GREEN}all${NC} <版本号> 一键构建 + 推送 + 部署 ${GREEN}all${NC} <版本号> 一键构建 + 传输 + 部署
${GREEN}clean${NC} 清理本地镜像(谨慎使用) ${GREEN}clean${NC} 清理本地镜像(谨慎使用)
${YELLOW}选项:${NC} ${YELLOW}选项:${NC}
--server <IP> 指定服务器(覆盖配置文件) --server <IP> 指定服务器(覆盖配置文件)
--skip-build 跳过构建(用于已构建过的情况) --skip-build 跳过构建(用于已构建过的情况)
--skip-push 跳过推送(用于已推送过的情况) --skip-push 跳过传输(用于已传输过的情况)
--force 强制执行(不确认) --force 强制执行(不确认)
--help, -h 显示此帮助 --help, -h 显示此帮助
${YELLOW}示例:${NC} ${YELLOW}示例:${NC}
$0 build v1.0.0 # 构建并推送 $0 build v1.0.0 # 构建并打包传输到服务器
$0 deploy v1.0.0 --server 192.168.1.100 # 部署到服务器 $0 deploy v1.0.0 --server 192.168.1.100 # 部署到服务器
$0 rollback v0.9.0 # 回滚到 v0.9.0 $0 rollback v0.9.0 # 回滚到 v0.9.0
$0 history # 查看部署历史 $0 history # 查看部署历史
$0 all v1.0.0 --server 192.168.1.100 # 一键完成所有操作 $0 all v1.0.0 --server 192.168.1.100 # 一键完成所有操作
${YELLOW}前提准备:${NC} ${YELLOW}前提准备:${NC}
1. 阿里云容器镜像: https://cr.console.aliyun.com/ 1. 修改 SERVER_HOST 为你的服务器 IP
2. 修改脚本中的 REGISTRY_HOST 和 NAMESPACE 2. 配置服务器 SSH 免密登录(建议)
3. 修改 SERVER_HOST 为你的服务器 IP
EOF EOF
} }
@ -123,11 +118,6 @@ EOF
check_config() { check_config() {
local errors=0 local errors=0
if [ "$NAMESPACE" = "你的命名空间" ]; then
print_msg "$RED" "错误: 请修改 deploy.sh 中的 NAMESPACE 为你的阿里云仓库命名空间"
errors=$((errors + 1))
fi
if [ -z "$SERVER_HOST" ]; then if [ -z "$SERVER_HOST" ]; then
print_msg "$YELLOW" "警告: SERVER_HOST 未设置,远程部署功能将不可用" print_msg "$YELLOW" "警告: SERVER_HOST 未设置,远程部署功能将不可用"
fi fi
@ -150,71 +140,66 @@ do_build() {
print_msg "$GREEN" "✅ 镜像构建完成" print_msg "$GREEN" "✅ 镜像构建完成"
} }
# ==================== 2. 推送镜像 ==================== # ==================== 2. 打包并传输镜像到服务器 ====================
do_push() { do_push() {
local version=$1 local version=$1
print_step "🔑 登录镜像仓库" if [ -z "$SERVER_HOST" ]; then
print_msg "$RED" "错误: 请设置 SERVER_HOST"
# 登录(可能需要输入密码)
docker login --username="${NAMESPACE}" "${REGISTRY_HOST}" || {
print_msg "$RED" "❌ 登录失败"
exit 1 exit 1
} fi
print_msg "$GREEN" "✅ 登录成功" print_step "📦 打包镜像为 tar 文件"
print_step "📦 推送镜像到仓库" local tmp_dir="/tmp/topfans-images-${version}"
mkdir -p "${tmp_dir}"
local failed=() local failed=()
local pushed=() local packed=()
for SERVICE in "${SERVICES[@]}"; do for SERVICE in "${SERVICES[@]}"; do
local local_image="topfans/${SERVICE}:latest" local local_image="topfans/${SERVICE}:latest"
local remote_image="${REGISTRY_HOST}/${NAMESPACE}/topfans-${SERVICE}:v${version}" local tar_file="${tmp_dir}/${SERVICE}.tar"
local latest_image="${REGISTRY_HOST}/${NAMESPACE}/topfans-${SERVICE}:latest"
echo "" echo ""
print_msg "$YELLOW" "处理 ${SERVICE}..." print_msg "$YELLOW" "处理 ${SERVICE}..."
# 打标签 if docker save "${local_image}" -o "${tar_file}"; then
docker tag "${local_image}" "${remote_image}" echo -e " ${GREEN}✅ 已打包${NC}"
docker tag "${local_image}" "${latest_image}" packed+=("${SERVICE}")
# 推送版本标签
echo -e " ${CYAN}${remote_image}${NC}"
if docker push "${remote_image}"; then
echo -e " ${GREEN}✅ 已推送${NC}"
pushed+=("${SERVICE}")
else else
echo -e " ${RED}推送失败${NC}" echo -e " ${RED}❌ 打包失败${NC}"
failed+=("${SERVICE}") failed+=("${SERVICE}")
fi fi
done done
# 推送 latest if [ ${#failed[@]} -ne 0 ]; then
echo "" print_msg "$RED" "❌ 打包失败: ${failed[*]}"
print_msg "$YELLOW" "推送 latest 标签..." rm -rf "${tmp_dir}"
for SERVICE in "${SERVICES[@]}"; do exit 1
local latest_image="${REGISTRY_HOST}/${NAMESPACE}/topfans-${SERVICE}:latest"
docker push "${latest_image}" 2>/dev/null || true
done
print_step "📊 推送结果"
if [ ${#failed[@]} -eq 0 ]; then
print_msg "$GREEN" "✅ 全部推送成功"
else
print_msg "$RED" "❌ 失败: ${failed[*]}"
fi fi
echo "" print_msg "$GREEN" "✅ 全部打包完成"
print_msg "$CYAN" "已推送的镜像: v${version}"
for SERVICE in "${pushed[@]}"; do print_step "📤 传输镜像到服务器"
echo -e " ${GREEN}${REGISTRY_HOST}/${NAMESPACE}/topfans-${SERVICE}:v${version}${NC}"
print_msg "$YELLOW" "正在传输到 ${SERVER_USER}@${SERVER_HOST}:${SERVER_PATH}..."
# 创建服务器目录
ssh -p "${SERVER_PORT}" "${SERVER_USER}@${SERVER_HOST}" "mkdir -p ${SERVER_PATH}/images && rm -f ${SERVER_PATH}/images/*.tar 2>/dev/null || true"
# 传输 tar 文件
for SERVICE in "${packed[@]}"; do
local tar_file="${tmp_dir}/${SERVICE}.tar"
print_msg "$YELLOW" "传输 ${SERVICE}.tar..."
scp -P "${SERVER_PORT}" "${tar_file}" "${SERVER_USER}@${SERVER_HOST}:${SERVER_PATH}/images/"
print_msg "$GREEN" "${SERVICE}.tar 传输完成"
done done
return $([ ${#failed[@]} -eq 0 ] && echo 0 || echo 1) # 清理本地临时文件
rm -rf "${tmp_dir}"
print_msg "$GREEN" "✅ 镜像传输完成"
} }
# ==================== 3. 远程部署 ==================== # ==================== 3. 远程部署 ====================
@ -229,54 +214,7 @@ do_deploy() {
print_step "🚀 远程部署到 ${SERVER_HOST}" print_step "🚀 远程部署到 ${SERVER_HOST}"
# 构建远程部署脚本 print_msg "$YELLOW" "检查 Docker 环境..."
local remote_script="
set -e
echo '=== 1. 创建部署目录 ==='
mkdir -p ${SERVER_PATH}
cd ${SERVER_PATH}
echo '=== 2. 登录镜像仓库 ==='
# 注意:需要提前在服务器上配置 docker login或者使用阿里云 AccessKey 登录
# 这里假设已配置免密登录或使用 docker-credential-ecr-login
echo '使用镜像: ${REGISTRY_HOST}/${NAMESPACE}'
echo '=== 3. 拉取镜像 ==='
for service in ${SERVICES[*]}; do
echo \"拉取 topfans-\$service:v${version}...\"
docker pull ${REGISTRY_HOST}/${NAMESPACE}/topfans-\$service:v${version}
done
echo '=== 4. 打 latest 标签 ==='
for service in ${SERVICES[*]}; do
docker tag ${REGISTRY_HOST}/${NAMESPACE}/topfans-\$service:v${version} \
${REGISTRY_HOST}/${NAMESPACE}/topfans-\$service:latest
done
echo '=== 5. 停止现有服务 ==='
docker-compose -f docker-compose.prod.yml down 2>/dev/null || true
echo '=== 6. 启动服务 ==='
docker-compose -f docker-compose.prod.yml --profile prod up -d
echo '=== 7. 等待服务就绪 ==='
sleep 10
echo '=== 8. 健康检查 ==='
curl -s http://localhost:8080/health > /dev/null && echo '✅ Gateway 健康' || echo '⚠️ Gateway 可能未就绪'
echo '=== 9. 记录部署历史 ==='
echo '{\"version\":\"${version}\",\"deployed_at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"services\":${#SERVICES[@]}}' \
>> ${SERVER_PATH}/deploy_history.json
echo ''
echo '✅ 部署完成!'
docker-compose -f docker-compose.prod.yml ps
"
# 执行远程脚本
print_msg "$YELLOW" "正在连接 ${SERVER_USER}@${SERVER_HOST}..."
ssh -p "${SERVER_PORT}" -T "${SERVER_USER}@${SERVER_HOST}" << 'ENDSSH' ssh -p "${SERVER_PORT}" -T "${SERVER_USER}@${SERVER_HOST}" << 'ENDSSH'
set -e set -e
@ -295,32 +233,26 @@ fi
echo '✅ Docker 环境就绪' echo '✅ Docker 环境就绪'
ENDSSH ENDSSH
# 由于 heredoc 在复杂脚本中有问题,这里简化为直接执行关键命令 # 确保服务器目录存在
print_msg "$YELLOW" "执行部署命令..." ssh -p "${SERVER_PORT}" "${SERVER_USER}@${SERVER_HOST}" "mkdir -p ${SERVER_PATH}/images"
# 分步执行远程命令
ssh -p "${SERVER_PORT}" "${SERVER_USER}@${SERVER_HOST}" "
mkdir -p ${SERVER_PATH} && \
echo '目录就绪'
"
print_msg "$GREEN" "✅ 服务器目录就绪" print_msg "$GREEN" "✅ 服务器目录就绪"
# 拉取镜像(逐个拉取以便查看进度) # 从 tar 文件加载镜像
print_step "📥 从 tar 文件加载镜像"
for SERVICE in "${SERVICES[@]}"; do for SERVICE in "${SERVICES[@]}"; do
print_msg "$YELLOW" "拉取 ${SERVICE}..." print_msg "$YELLOW" "加载 ${SERVICE}..."
ssh -p "${SERVER_PORT}" "${SERVER_USER}@${SERVER_HOST}" " ssh -p "${SERVER_PORT}" "${SERVER_USER}@${SERVER_HOST}" "
docker pull ${REGISTRY_HOST}/${NAMESPACE}/topfans-${SERVICE}:v${version} docker load -i ${SERVER_PATH}/images/${SERVICE}.tar
" "
print_msg "$GREEN" "${SERVICE} 拉取完成" print_msg "$GREEN" "${SERVICE} 加载完成"
done done
# 打标签 # 打 latest 标签
print_msg "$YELLOW" "打 latest 标签..." print_msg "$YELLOW" "打 latest 标签..."
ssh -p "${SERVER_PORT}" "${SERVER_USER}@${SERVER_HOST}" " ssh -p "${SERVER_PORT}" "${SERVER_USER}@${SERVER_HOST}" "
for service in ${SERVICES[*]}; do for service in ${SERVICES[*]}; do
docker tag ${REGISTRY_HOST}/${NAMESPACE}/topfans-\$service:v${version} \ docker tag topfans/\${service}:latest topfans/\${service}:v${version}
${REGISTRY_HOST}/${NAMESPACE}/topfans-\$service:latest docker tag topfans/\${service}:latest topfans/\${service}:latest
done done
echo '标签完成' echo '标签完成'
" "
@ -376,13 +308,13 @@ do_rollback() {
docker-compose -f docker-compose.prod.yml down docker-compose -f docker-compose.prod.yml down
" "
# 拉取指定版本镜像并打标签 # 从已有的 tar 文件加载镜像并打标签
for SERVICE in "${SERVICES[@]}"; do for SERVICE in "${SERVICES[@]}"; do
print_msg "$YELLOW" "拉取 ${SERVICE}:v${version}..." print_msg "$YELLOW" "加载 ${SERVICE}:v${version}..."
ssh -p "${SERVER_PORT}" "${SERVER_USER}@${SERVER_HOST}" " ssh -p "${SERVER_PORT}" "${SERVER_USER}@${SERVER_HOST}" "
docker pull ${REGISTRY_HOST}/${NAMESPACE}/topfans-${SERVICE}:v${version} docker load -i ${SERVER_PATH}/images/${SERVICE}.tar
docker tag ${REGISTRY_HOST}/${NAMESPACE}/topfans-${SERVICE}:v${version} \ docker tag topfans/${SERVICE}:latest topfans/${SERVICE}:v${version}
${REGISTRY_HOST}/${NAMESPACE}/topfans-${SERVICE}:latest docker tag topfans/${SERVICE}:latest topfans/${SERVICE}:latest
" "
print_msg "$GREEN" "${SERVICE} 回滚完成" print_msg "$GREEN" "${SERVICE} 回滚完成"
done done
@ -512,7 +444,7 @@ main() {
fi fi
echo -e "${CYAN}版本: v${version}${NC}" echo -e "${CYAN}版本: v${version}${NC}"
echo -e "${CYAN}仓库: ${REGISTRY_HOST}/${NAMESPACE}${NC}" echo -e "${CYAN}目标: ${SERVER_USER}@${SERVER_HOST}${NC}"
if [ "$skip_build" = false ]; then if [ "$skip_build" = false ]; then
do_build do_build
@ -573,7 +505,7 @@ main() {
echo -e "${MAGENTA}一键部署流程:${NC}" echo -e "${MAGENTA}一键部署流程:${NC}"
echo " 1. 构建镜像" echo " 1. 构建镜像"
echo " 2. 推送到仓库" echo " 2. 打包传输到服务器"
echo " 3. 部署到 ${SERVER_HOST}" echo " 3. 部署到 ${SERVER_HOST}"
echo "" echo ""

View File

@ -318,13 +318,9 @@ const avatarKey = ref(0); // 用于强制刷新Avatar组件
// //
const mobile = ref(''); const mobile = ref('');
// //
const displayMobile = computed(() => { const displayMobile = computed(() => {
const phone = mobile.value; return mobile.value || '';
if (!phone) return '';
if (phone.length !== 11) return phone;
// 138****8888
return phone.substring(0, 3) + '****' + phone.substring(7);
}); });
// //

View File

@ -76,11 +76,13 @@ const actions = {
uni.setStorageSync('access_token', accessToken) uni.setStorageSync('access_token', accessToken)
commit('SET_TOKEN', accessToken) commit('SET_TOKEN', accessToken)
// 缓存登录手机号
uni.setStorageSync('login_mobile', mobile)
// 缓存用户信息 // 缓存用户信息
const user = res.data.user const user = res.data.user
// 缓存登录手机号(优先使用后端返回的脱敏手机号)
const loginMobile = user.mobile_masked || mobile
uni.setStorageSync('login_mobile', loginMobile)
uni.setStorageSync('user', JSON.stringify(user)) uni.setStorageSync('user', JSON.stringify(user))
commit('SET_USER_INFO', user) commit('SET_USER_INFO', user)
@ -133,11 +135,13 @@ const actions = {
uni.setStorageSync('access_token', accessToken) uni.setStorageSync('access_token', accessToken)
commit('SET_TOKEN', accessToken) commit('SET_TOKEN', accessToken)
// 缓存登录手机号
uni.setStorageSync('login_mobile', mobile)
// 缓存用户信息 // 缓存用户信息
const user = res.data.user const user = res.data.user
// 缓存登录手机号(优先使用后端返回的脱敏手机号)
const loginMobile = user.mobile_masked || mobile
uni.setStorageSync('login_mobile', loginMobile)
uni.setStorageSync('user', JSON.stringify(user)) uni.setStorageSync('user', JSON.stringify(user))
commit('SET_USER_INFO', user) commit('SET_USER_INFO', user)