更新小程序配置,切换 API 地址为本地开发环境。新增会员详情页面的头像逻辑,确保用户信息展示一致性。优化多个页面的交互提示,提升用户体验。调整图标组件,更新图标映射以支持新样式。

This commit is contained in:
Alex-larget
2026-03-20 10:58:25 +08:00
parent 181f092402
commit e79152c80b
21 changed files with 658 additions and 158 deletions

View File

@@ -3,10 +3,18 @@
"""
soul-api 一键部署到宝塔【测试环境】
打包原则:优先使用本地已有资源,不边打包边下载(省时)。
- 默认:本地 go build → Dockerfile.local 打镜像(--pull=false 不拉 base 镜像)
- 首次部署前请本地先拉好alpine:3.19、redis:7-alpine后续一律用本地缓存
两种模式均部署到测试环境 /www/wwwroot/self/soul-dev
- binaryGo 二进制 + 宝塔 soulDev 项目,用 .env.development
- dockerDocker 镜像 + 蓝绿无缝切换,用 .env.development 打包进镜像
- docker(默认):本地 go build → Dockerfile.local 打镜像 蓝绿无缝切换
- 镜像内包含二进制、soul-api/certs/ → /app/certs/、选定环境文件 → /app/.env
- 环境文件:--env-file 或 DOCKER_ENV_FILE否则自动 .env.development > .env.production > .env.dockerignore 已放行)
- 不加 --docker-in-go 时:本地 Go 编译 + 本地 base 镜像,不联网
- 加 --docker-in-go 时:在 Docker 内用 golang 镜像编译(需本地已有 golang:1.25
环境变量DEPLOY_DOCKER_PATH、DEPLOY_NGINX_CONF、DEPLOY_HOST 等
"""
@@ -117,7 +125,7 @@ def run_build(root):
# ==================== 打包 ====================
DEPLOY_PORT = 8081
DEPLOY_PORT = 9001
def set_env_port(env_path, port=DEPLOY_PORT):
@@ -163,22 +171,32 @@ def set_env_mini_program_state(env_path, state):
f.writelines(new_lines)
def resolve_binary_pack_env_src(root):
"""binary 模式 tar 包内 .env 的来源,与 Docker 自动优先级一致。"""
for name in (".env.development", ".env.production", ".env"):
p = os.path.join(root, name)
if os.path.isfile(p):
return p, name
return None, None
def pack_deploy(root, binary_path, include_env=True):
"""打包二进制和 .env 为 tar.gz"""
print("[2/4] 打包部署文件 ...")
staging = tempfile.mkdtemp(prefix="soul_api_deploy_")
try:
shutil.copy2(binary_path, os.path.join(staging, "soul-api"))
env_src = os.path.join(root, ".env.development")
staging_env = os.path.join(staging, ".env")
if include_env and os.path.isfile(env_src):
shutil.copy2(env_src, staging_env)
print(" [已包含] .env.development -> .env")
else:
env_example = os.path.join(root, ".env.example")
if os.path.isfile(env_example):
shutil.copy2(env_example, staging_env)
print(" [已包含] .env.example -> .env (请服务器上检查配置)")
if include_env:
env_src, env_label = resolve_binary_pack_env_src(root)
if env_src:
shutil.copy2(env_src, staging_env)
print(" [已包含] %s -> .env" % env_label)
else:
env_example = os.path.join(root, ".env.example")
if os.path.isfile(env_example):
shutil.copy2(env_example, staging_env)
print(" [已包含] .env.example -> .env (请服务器上检查配置)")
if os.path.isfile(staging_env):
set_env_port(staging_env, DEPLOY_PORT)
set_env_mini_program_state(staging_env, "developer")
@@ -392,6 +410,37 @@ def deploy_nginx_via_bt_api(cfg, nginx_conf_path, new_port):
# ==================== Docker 部署(蓝绿无缝切换) ====================
def resolve_docker_env_file(root, explicit=None):
"""
选择打入镜像的环境文件(相对 soul-api 根目录,须能被 Docker 构建上下文包含)。
Dockerfile: COPY ${ENV_FILE} /app/.envcerts/ 由 COPY certs/ 一并打入。
优先级explicit → DOCKER_ENV_FILE → 自动 .env.development > .env.production > .env与测试环境默认一致
"""
if explicit:
name = os.path.basename(explicit.replace("\\", "/"))
path = os.path.join(root, name)
if os.path.isfile(path):
print(" [镜像配置] 打入镜像的环境文件: %s--env-file" % name)
return name
print(" [失败] --env-file 不存在: %s" % path)
return None
override = (os.environ.get("DOCKER_ENV_FILE") or "").strip()
if override:
name = os.path.basename(override.replace("\\", "/"))
path = os.path.join(root, name)
if os.path.isfile(path):
print(" [镜像配置] 打入镜像的环境文件: %sDOCKER_ENV_FILE" % name)
return name
print(" [失败] DOCKER_ENV_FILE 指向的文件不存在: %s" % path)
return None
for name in (".env.development", ".env.production", ".env"):
if os.path.isfile(os.path.join(root, name)):
print(" [镜像配置] 打入镜像的环境文件: %s(自动选择)" % name)
return name
print(" [失败] 未找到 .env.development / .env.production / .env无法 COPY 进镜像")
return None
def run_docker_build(root, env_file=".env.development"):
"""本地构建 Docker 镜像(使用 Docker 内的 golang 镜像)"""
print("[1/5] 构建 Docker 镜像 ...(进度见下方 Docker 输出)")
@@ -415,14 +464,14 @@ def run_docker_build(root, env_file=".env.development"):
def run_docker_build_local(root, env_file=".env.development"):
"""使用本地 Go 交叉编译后构建 Docker 镜像(不拉取 golang 镜像)"""
"""使用本地 Go 交叉编译后构建 Docker 镜像(不拉取 golang 镜像--pull=false 不拉 base 镜像"""
print("[1/5] 使用本地 Go 交叉编译 ...")
binary_path = run_build(root)
if not binary_path:
return None
print("[2/5] 使用 Dockerfile.local 构建镜像 ...进度见下方 Docker 输出")
print("[2/5] 使用 Dockerfile.local 构建镜像 ...--pull=false 仅用本地缓存")
try:
cmd = ["docker", "build", "-f", "deploy/Dockerfile.local", "-t", "soul-api:latest",
cmd = ["docker", "build", "--pull=false", "-f", "deploy/Dockerfile.local", "-t", "soul-api:latest",
"--build-arg", "ENV_FILE=%s" % env_file, "--progress=plain", "."]
r = subprocess.run(cmd, cwd=root, shell=False, timeout=120)
if r.returncode != 0:
@@ -444,7 +493,7 @@ def run_docker_build_local(root, env_file=".env.development"):
def pack_docker_image(root):
"""将 soul-api 与 redis 镜像一并导出为 tar.gz服务器无需拉取"""
import gzip
print("[2/5] 导出镜像为 tar.gzsoul-api + redis...")
print("[3/5] 导出镜像为 tar.gzsoul-api + redis...")
out_tar = os.path.join(tempfile.gettempdir(), "soul_api_image.tar.gz")
try:
r = subprocess.run(
@@ -479,7 +528,7 @@ def upload_and_deploy_docker(cfg, image_tar_path, include_env=True, deploy_metho
nginx_conf = os.environ.get("DEPLOY_NGINX_CONF", DEPLOY_NGINX_CONF)
script_dir = os.path.dirname(os.path.abspath(__file__))
print("[3/5] SSH 上传镜像与配置 ...")
print("[4/5] SSH 上传镜像与配置 ...")
if not cfg.get("password") and not cfg.get("ssh_key"):
print(" [失败] 请设置 DEPLOY_PASSWORD 或 DEPLOY_SSH_KEY")
return False
@@ -506,9 +555,11 @@ def upload_and_deploy_docker(cfg, image_tar_path, include_env=True, deploy_metho
if os.path.isfile(deploy_local):
sftp.put(deploy_local, deploy_path + "/docker-deploy-remote.sh")
print(" [已上传] docker-deploy-remote.sh")
# 注意docker-compose.bluegreen.yml 未配置 env_file容器实际以镜像内 /app/.env 为准;
# 此处上传仅供服务器目录备份或手工改 compose 后使用。
if include_env and os.path.isfile(env_local):
sftp.put(env_local, deploy_path.rstrip("/") + "/.env")
print(" [已上传] .env.production -> .env覆盖镜像内配置")
print(" [已上传] .env.production -> 服务器 %s/.env可选默认不挂载进容器" % deploy_path.rstrip("/"))
# btapi 模式:需先读取 .active 计算新端口,脚本内跳过 Nginx
current_active = "blue"
@@ -523,7 +574,7 @@ def upload_and_deploy_docker(cfg, image_tar_path, include_env=True, deploy_metho
sftp.close()
print("[4/5] 执行蓝绿部署 ...")
print("[5/5] 执行蓝绿部署 ...")
env_exports = ""
if nginx_conf:
env_exports += "export DEPLOY_NGINX_CONF='%s'; " % nginx_conf.replace("'", "'\\''")
@@ -546,12 +597,12 @@ def upload_and_deploy_docker(cfg, image_tar_path, include_env=True, deploy_metho
# btapi 模式:通过宝塔 API 更新 Nginx 配置并重载new_port 已在上方计算)
if deploy_method == "btapi" and nginx_conf:
try:
print("[5/5] 宝塔 API 更新 Nginx ...")
print(" [宝塔 API] 更新 Nginx ...")
deploy_nginx_via_bt_api(cfg, nginx_conf, new_port)
except Exception as e:
print(" [警告] 宝塔 Nginx API 失败:", str(e))
print("[5/5] 部署完成,蓝绿无缝切换")
print(" 部署完成,蓝绿无缝切换")
return True
except Exception as e:
print(" [失败] SSH 错误:", str(e))
@@ -568,14 +619,17 @@ def main():
parser.add_argument("--mode", choices=("binary", "docker"), default="docker",
help="docker=Docker 蓝绿部署 (默认), binary=Go 二进制")
parser.add_argument("--no-build", action="store_true", help="跳过本地编译/构建")
parser.add_argument("--no-env", action="store_true", help="不打包 .env")
parser.add_argument("--no-env", action="store_true",
help="binary: 不打进 tardocker: 不上传服务器目录 .env.production镜像内配置不变")
parser.add_argument("--no-restart", action="store_true", help="[binary] 上传后不重启")
parser.add_argument("--restart-method", choices=("auto", "btapi", "ssh"), default="auto",
help="[binary] 重启方式: auto/btapi/ssh")
parser.add_argument("--local-go", action="store_true",
help="[docker] 使用本地 Go 交叉编译后打镜像,不拉取 golang 镜像")
parser.add_argument("--docker-in-go", action="store_true",
help="[docker] 在 Docker 内用 golang 镜像编译(默认:本地 go build → 再打镜像)")
parser.add_argument("--deploy-method", choices=("ssh", "btapi"), default="ssh",
help="[docker] 部署方式: ssh=脚本内 Nginx 切换, btapi=宝塔 API 更新 Nginx 配置并重载 (默认 ssh)")
parser.add_argument("--env-file", default=None, metavar="NAME",
help="[docker] 打入镜像的环境文件名(默认自动:.env.development > .env.production > .env")
args = parser.parse_args()
script_dir = os.path.dirname(os.path.abspath(__file__))
@@ -592,11 +646,19 @@ def main():
print("=" * 60)
if not args.no_build:
ok = run_docker_build_local(root) if args.local_go else run_docker_build(root)
env_for_image = resolve_docker_env_file(root, explicit=args.env_file)
if env_for_image is None:
return 1
# 默认:本地 go build → Dockerfile.local 打镜像;--docker-in-go 时在容器内编译
ok = (
run_docker_build(root, env_file=env_for_image)
if args.docker_in_go
else run_docker_build_local(root, env_file=env_for_image)
)
if not ok:
return 1
else:
print("[1/5] 跳过构建,使用现有 soul-api:latest")
print("[1/5] 跳过构建,使用现有 soul-api:latest(无需本地环境文件)")
image_tar = pack_docker_image(root)
if not image_tar: