diff --git a/internal/handlers/content.go b/internal/handlers/content.go index d35b356..cd01595 100644 --- a/internal/handlers/content.go +++ b/internal/handlers/content.go @@ -124,23 +124,17 @@ func addReviewToContent(jsonResult, itemID string, r *http.Request) string { } } - // 获取基础 URL + // 获取基础 URL(反代场景识别 X-Forwarded-Proto,避免生成 http:// 被 301) cfg := config.GetConfig() baseURL := "" - if cfg != nil { + if r.Host != "" { + baseURL = externalBaseURL(r) + } else if cfg != nil { host := cfg.Server.Host if host == "0.0.0.0" { host = "localhost" } - port := cfg.Server.Port - scheme := "http" - - // 检查是否来自外部请求 - if r.Host != "" { - baseURL = scheme + "://" + r.Host - } else { - baseURL = scheme + "://" + host + ":" + port - } + baseURL = "http://" + host + ":" + cfg.Server.Port } // 生成带段评标记的内容 diff --git a/internal/handlers/review.go b/internal/handlers/review.go index 9fd00d1..5d3cd9c 100644 --- a/internal/handlers/review.go +++ b/internal/handlers/review.go @@ -12,6 +12,16 @@ import ( "time" ) +// externalBaseURL 取外部可访问的基础 URL(nginx 反代下识别 X-Forwarded-Proto, +// 避免生成 http:// 链接被 301,弹窗 WebView 内 fetch 对 301 处理不稳) +func externalBaseURL(r *http.Request) string { + scheme := "http" + if p := r.Header.Get("X-Forwarded-Proto"); p != "" { + scheme = p + } + return scheme + "://" + r.Host +} + // validateParams 验证必需参数 func validateParams(r *http.Request, required ...string) (map[string]string, error) { params := make(map[string]string) @@ -207,7 +217,7 @@ func HandleReviewHTML(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(http.StatusOK) - html := generateReviewHTML(data, params["item_id"], bookID, para, page, pageSize, sort) + html := generateReviewHTML(r, data, params["item_id"], bookID, para, page, pageSize, sort) fmt.Fprint(w, html) } @@ -318,6 +328,7 @@ var reviewTmpl = template.Must(template.New("review").Parse(reviewHTML)) // reviewPageData 评论页模板数据 type reviewPageData struct { ItemID, BookID string + BaseURL string ParaPlus1, Para, Sort int Total, NextOffset int PageSize, CommentCount int @@ -327,7 +338,7 @@ type reviewPageData struct { } // generateReviewHTML 生成评论 HTML 页面 -func generateReviewHTML(data map[string]interface{}, itemID, bookID string, para, page, pageSize, sort int) string { +func generateReviewHTML(r *http.Request, data map[string]interface{}, itemID, bookID string, para, page, pageSize, sort int) string { total := 0 hasMore := false nextOffset := 0 @@ -383,6 +394,7 @@ func generateReviewHTML(data map[string]interface{}, itemID, bookID string, para var b strings.Builder if err := reviewTmpl.Execute(&b, reviewPageData{ ItemID: itemID, BookID: bookID, + BaseURL: externalBaseURL(r), ParaPlus1: para + 1, Para: para, Sort: sort, Total: total, NextOffset: nextOffset, PageSize: pageSize, CommentCount: len(pageComments), diff --git a/internal/handlers/templates/review.html b/internal/handlers/templates/review.html index fbe04da..521775e 100644 --- a/internal/handlers/templates/review.html +++ b/internal/handlers/templates/review.html @@ -49,25 +49,50 @@ box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } + html, body { height: 100%; } body { background-color: var(--bg-primary); color: var(--text-primary); - padding: 15px; max-width: 600px; margin: 0 auto; + display: flex; + flex-direction: column; + overflow: hidden; transition: background-color 0.3s ease, color 0.3s ease; } .header { + flex-shrink: 0; display: flex; justify-content: space-between; align-items: center; - margin-bottom: 20px; - padding: 10px 15px; + padding: 10px 15px 12px; background: var(--bg-secondary); - border-radius: 12px; + border-radius: 20px 20px 0 0; + border-bottom: 1px solid var(--border-color); box-shadow: 0 2px 8px var(--shadow); + position: relative; + z-index: 10; transition: background-color 0.3s ease; } + /* BottomSheet 顶部拖拽把手 */ + .header::before { + content: ''; + position: absolute; + top: 6px; + left: 50%; + transform: translateX(-50%); + width: 36px; + height: 4px; + border-radius: 2px; + background: var(--border-color); + } + #comment-list { + flex: 1; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + padding: 15px; + overscroll-behavior: contain; + } .header h1 { font-size: 18px; color: var(--text-primary); @@ -333,8 +358,8 @@