修复支付不跳转
This commit is contained in:
@@ -301,8 +301,14 @@ const checkOrder = async (orderNo: string, silent = false) => {
|
|||||||
ElMessage.success("购买成功,套餐已开通");
|
ElMessage.success("购买成功,套餐已开通");
|
||||||
payVisible.value = false;
|
payVisible.value = false;
|
||||||
loadMyOrders();
|
loadMyOrders();
|
||||||
// 重建动态路由,把新开通模块的「功能未开通」菜单占位页切换为真实页面
|
// 重建动态路由,把新开通模块的「功能未开通」菜单占位页切换为真实页面。
|
||||||
reloadMenusAndDynamicRoutes().catch(() => {});
|
// 必须等重建完成后再跳首页,否则会按旧的菜单路由跳转、落到占位页
|
||||||
|
try {
|
||||||
|
await reloadMenusAndDynamicRoutes();
|
||||||
|
} catch {
|
||||||
|
/* 忽略:进入首页时路由守卫会再拉一次菜单 */
|
||||||
|
}
|
||||||
|
router.replace("/home");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (status === "paid") {
|
if (status === "paid") {
|
||||||
|
|||||||
@@ -312,8 +312,14 @@ const checkOrder = async (silent = false) => {
|
|||||||
ElMessage.success("购买成功,功能已开通");
|
ElMessage.success("购买成功,功能已开通");
|
||||||
payVisible.value = false;
|
payVisible.value = false;
|
||||||
loadMyOrders();
|
loadMyOrders();
|
||||||
// 重建动态路由,把刚开通模块的「功能未开通」菜单占位页切换为真实页面
|
// 重建动态路由,把刚开通模块的「功能未开通」菜单占位页切换为真实页面。
|
||||||
reloadMenusAndDynamicRoutes().catch(() => {});
|
// 必须等重建完成后再跳首页,否则会按旧的菜单路由跳转、落到占位页
|
||||||
|
try {
|
||||||
|
await reloadMenusAndDynamicRoutes();
|
||||||
|
} catch {
|
||||||
|
/* 忽略:进入首页时路由守卫会再拉一次菜单 */
|
||||||
|
}
|
||||||
|
router.replace("/home");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (status === "paid") {
|
if (status === "paid") {
|
||||||
|
|||||||
+9
-1
@@ -92,4 +92,12 @@ payment_secret_key = f656fe85ed6a1caba9f19966d8cdde46114709969bea5875cde7664d4ad
|
|||||||
# TODO: 填你自己服务器的公网 HTTPS 域名(如 https://api.yunzer.com.cn),不是申请来的。
|
# TODO: 填你自己服务器的公网 HTTPS 域名(如 https://api.yunzer.com.cn),不是申请来的。
|
||||||
# 要求:公网可访问、HTTPS、无鉴权无重定向;微信 JSAPI 还需在商户平台「支付授权目录」登记同一域名。
|
# 要求:公网可访问、HTTPS、无鉴权无重定向;微信 JSAPI 还需在商户平台「支付授权目录」登记同一域名。
|
||||||
# 本地开发收不到渠道回调,留空即可(回调地址退化为相对路径 /api/payment/callback/{渠道},由网关补齐域名)。
|
# 本地开发收不到渠道回调,留空即可(回调地址退化为相对路径 /api/payment/callback/{渠道},由网关补齐域名)。
|
||||||
payment_callback_base = https://api.yunzer.cn
|
payment_callback_base = https://api.yunzer.cn
|
||||||
|
|
||||||
|
# 渠道证书落盘根目录(各渠道目录的父目录,实际路径 = {payment_cert_dir}/{渠道}/xxx.pem)。
|
||||||
|
# 留空时按进程工作目录下的 certs/payment 处理。
|
||||||
|
# 历史数据里 cert_json 存的是相对路径(相对「当初上传时」的进程工作目录),
|
||||||
|
# 若服务的工作目录与当初不一致(例如上传时是 /www/wwwroot/api.yunzer.cn,现在跑在 /app),
|
||||||
|
# 把这里配成当初上传用的绝对目录即可继续读到旧证书,无需重新上传:
|
||||||
|
payment_cert_dir = /www/wwwroot/api.yunzer.cn/certs/payment/wechat
|
||||||
|
# payment_cert_dir =
|
||||||
@@ -384,7 +384,9 @@ func (c *PlatformPaymentController) UploadCertificate() {
|
|||||||
}
|
}
|
||||||
defer func() { _ = file.Close() }()
|
defer func() { _ = file.Close() }()
|
||||||
|
|
||||||
dir := filepath.Join("certs", "payment", channel)
|
// 落盘目录:payment_cert_dir 配置优先,未配置时用相对工作目录的 certs/payment/<渠道>。
|
||||||
|
// 入库保持相对路径——本地开发与线上可能共用同一个库,存绝对路径会互相覆盖对方环境。
|
||||||
|
dir := payment.CertDir(channel)
|
||||||
if err := os.MkdirAll(dir, 0o700); err != nil {
|
if err := os.MkdirAll(dir, 0o700); err != nil {
|
||||||
c.jsonErr(500, 500, "创建证书目录失败: "+err.Error())
|
c.jsonErr(500, 500, "创建证书目录失败: "+err.Error())
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package payment
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
beego "github.com/beego/beego/v2/server/web"
|
||||||
|
)
|
||||||
|
|
||||||
|
// =============================================================
|
||||||
|
// 渠道证书落盘路径解析
|
||||||
|
//
|
||||||
|
// 历史实现把证书存成相对路径(certs/payment/<渠道>/xxx.pem),
|
||||||
|
// 该相对路径在「上传时」与「读取时」分别相对各自的进程工作目录解析。
|
||||||
|
// 一旦服务的工作目录发生变化(例如从 /www/wwwroot/api.yunzer.cn 换到 /app),
|
||||||
|
// 库里记的路径就指向不存在的文件,报 “The system cannot find the file specified”。
|
||||||
|
//
|
||||||
|
// 因此读取时统一做一次解析:
|
||||||
|
// - 落盘:写入 payment_cert_dir(未配置时退回工作目录下的 certs/payment),入库仍存相对路径
|
||||||
|
// (本地开发与线上可能共用同一个库,存绝对路径会互相覆盖对方环境);
|
||||||
|
// - 读取:先按当前工作目录解析,再按配置的 payment_cert_dir 根目录兜底解析。
|
||||||
|
// =============================================================
|
||||||
|
|
||||||
|
// legacyCertPrefix 历史相对路径前缀,用于把 certs/payment/<渠道>/xxx.pem 剥成 <渠道>/xxx.pem
|
||||||
|
const legacyCertPrefix = "certs/payment/"
|
||||||
|
|
||||||
|
// CertBaseDir 渠道证书落盘根目录(各渠道目录的父目录)
|
||||||
|
func CertBaseDir() string {
|
||||||
|
dir, _ := beego.AppConfig.String("payment_cert_dir")
|
||||||
|
dir = strings.TrimSpace(dir)
|
||||||
|
if dir == "" {
|
||||||
|
dir = filepath.Join("certs", "payment")
|
||||||
|
}
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
|
||||||
|
// CertDir 某渠道的证书目录
|
||||||
|
func CertDir(channel string) string {
|
||||||
|
return filepath.Join(CertBaseDir(), filepath.Base(channel))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveCertPath 把库中可能存的相对路径解析为当前可读的路径。
|
||||||
|
// 依次尝试:绝对路径 -> 相对当前工作目录 -> 相对 payment_cert_dir 根目录(兼容历史相对路径)。
|
||||||
|
// 都读不到时原样返回,让上层的 os.ReadFile 报出原始路径便于排查。
|
||||||
|
func ResolveCertPath(p string) string {
|
||||||
|
p = strings.TrimSpace(p)
|
||||||
|
if p == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if filepath.IsAbs(p) {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
// 相对当前工作目录(历史行为,能读到就不动)
|
||||||
|
if certPathExists(p) {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
// 兼容历史相对路径:剥掉 certs/payment 前缀后挂到配置的根目录下
|
||||||
|
if cand := filepath.Join(CertBaseDir(), certRelative(p)); certPathExists(cand) {
|
||||||
|
return cand
|
||||||
|
}
|
||||||
|
// 兜底:按文件名在根目录下找
|
||||||
|
if cand := filepath.Join(CertBaseDir(), filepath.Base(p)); certPathExists(cand) {
|
||||||
|
return cand
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// certRelative 从历史相对路径中剥掉 certs/payment 前缀
|
||||||
|
func certRelative(p string) string {
|
||||||
|
norm := filepath.ToSlash(filepath.Clean(p))
|
||||||
|
if i := strings.Index(norm, legacyCertPrefix); i >= 0 {
|
||||||
|
norm = norm[i+len(legacyCertPrefix):]
|
||||||
|
}
|
||||||
|
return filepath.FromSlash(norm)
|
||||||
|
}
|
||||||
|
|
||||||
|
func certPathExists(path string) bool {
|
||||||
|
info, err := os.Stat(path)
|
||||||
|
return err == nil && !info.IsDir()
|
||||||
|
}
|
||||||
@@ -221,6 +221,10 @@ func LoadChannelConfig(channel string) (*ChannelConfig, error) {
|
|||||||
}
|
}
|
||||||
if row.CertJSON != nil && *row.CertJSON != "" {
|
if row.CertJSON != nil && *row.CertJSON != "" {
|
||||||
_ = json.Unmarshal([]byte(*row.CertJSON), &cfg.CertPaths)
|
_ = json.Unmarshal([]byte(*row.CertJSON), &cfg.CertPaths)
|
||||||
|
// 历史数据存的是相对路径,这里统一解析为当前可读路径,避免依赖进程工作目录
|
||||||
|
for key, val := range cfg.CertPaths {
|
||||||
|
cfg.CertPaths[key] = ResolveCertPath(val)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user