diff --git a/app/api/web/comment.go b/app/api/web/comment.go
deleted file mode 100644
index a62c99e..0000000
--- a/app/api/web/comment.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package web
-
-import (
- "net/http"
- "strconv"
- "videoweb/app/service/commentser"
-
- "github.com/gin-gonic/gin"
-)
-
-// CommentList BFF:代理 GET /api/app/comment/list。
-// 文档:http://172.104.181.99:25319/swagger/index.html#/评论APP/get_api_app_comment_list
-func CommentList(c *gin.Context) {
- objectID, _ := strconv.ParseInt(c.Query("objectId"), 10, 64)
- objectType, _ := strconv.Atoi(c.Query("objectType"))
- pageNum, _ := strconv.Atoi(c.Query("pageNum"))
- pageSize, _ := strconv.Atoi(c.Query("pageSize"))
- sortOrder, _ := strconv.Atoi(c.Query("sortOrder"))
- if objectID <= 0 {
- c.JSON(http.StatusBadRequest, gin.H{
- "code": 400,
- "msg": "objectId required",
- "tip": "缺少评论对象",
- "data": nil,
- })
- return
- }
- data := commentser.FetchListOrEmpty(c, commentser.ListQuery{
- ObjectID: objectID,
- ObjectType: objectType,
- PageNum: pageNum,
- PageSize: pageSize,
- SortOrder: sortOrder,
- })
- c.JSON(http.StatusOK, gin.H{
- "code": 200,
- "msg": "ok",
- "tip": "成功",
- "data": data,
- })
-}
-
-// CommentSend BFF:代理 POST /api/app/comment/send。
diff --git a/app/api/web/help.go b/app/api/web/help.go
index eff84f5..f1830fa 100644
--- a/app/api/web/help.go
+++ b/app/api/web/help.go
@@ -10,14 +10,12 @@ import (
func Help(c *gin.Context) {
HTMLOK(c, "help.html", gin.H{
"faqItems": []seoser.FAQItem{
- {Question: "黄果短剧网页版可以看全集吗?", Answer: "可以。免费集直接观看,付费集可用金币按集解锁,解锁后永久有效。"},
- {Question: "解锁过的剧集还需要再付费吗?", Answer: "不需要。已解锁的剧集可在登录后继续观看,无需重复付费。"},
- {Question: "如何充值金币?", Answer: "登录后进入个人中心,选择金币充值,即可查看可用的充值方式。"},
- {Question: "支持哪些支付方式?", Answer: "可用的支付方式会在充值页面列出,请以页面显示为准。"},
- {Question: "忘记密码怎么办?", Answer: "请通过意见反馈联系我们,提交账号信息后由客服协助处理。"},
+ {Question: "黄果短剧网页版可以看全集吗?", Answer: "免费集可直接在网页观看;标记为 App 专享的剧集,下载黄果短剧 App 即可免费观看完整内容。"},
+ {Question: "网页版需要注册账号吗?", Answer: "不需要。网页版无需注册或登录,打开即可浏览和观看。"},
+ {Question: "如何下载黄果短剧 App?", Answer: "点击页面顶部或播放页的「下载 App」按钮,按提示完成安装即可。"},
+ {Question: "网站打不开怎么办?", Answer: "请收藏页脚的最新地址、备用地址与海外永久地址,任一地址均可访问。"},
{Question: "内容多久更新一次?", Answer: "黄果短剧持续更新内容,欢迎关注首页的新剧和最近上新。"},
{Question: "如何联系客服或洽谈合作?", Answer: "请发送邮件至 support@huanguoai.net,我们会尽快回复。"},
- {Question: "如何注销账号?", Answer: "请通过意见反馈或客服邮箱提交注销申请。"},
},
})
}
diff --git a/app/api/web/play.go b/app/api/web/play.go
index 9798e42..5763d6a 100644
--- a/app/api/web/play.go
+++ b/app/api/web/play.go
@@ -2,7 +2,6 @@ package web
import (
"strings"
- "videoweb/app/service/commentser"
"videoweb/app/service/playletser"
"videoweb/app/service/videoser"
@@ -76,20 +75,6 @@ func Play(c *gin.Context) {
})
}
- commentObjectID := playlet.ID
- commentObjectType := commentser.ObjectTypePlaylet
- if chapterID > 0 {
- commentObjectID = chapterID
- commentObjectType = commentser.ObjectTypeChapter
- }
- comments := commentser.FetchListOrEmpty(c, commentser.ListQuery{
- ObjectID: commentObjectID,
- ObjectType: commentObjectType,
- PageNum: 1,
- PageSize: 4,
- SortOrder: commentser.SortHot,
- })
-
canWatch := false
episode := 0
if chapter != nil {
@@ -119,45 +104,36 @@ func Play(c *gin.Context) {
}
data := gin.H{
- "title": title,
- "navActive": "list",
- "seoInfo": seo,
- "playlet": playlet,
- "chapter": chapter,
- "chapterID": chapterID,
- "episode": episode,
- "canWatch": canWatch,
- "mainURL": mainURL,
- "previewURL": previewURL,
- "hasPreview": previewURL != "",
- "nextChapterID": playletser.NextChapterID(playlet, chapterID),
- "advitise": playlet.Advitise,
- "related": playlet.RelatedRecommendData,
- "guessLike": guessLike.List,
- "guessPage": guessLike.PageNum,
- "guessPageSize": guessLike.PageSize,
- "guessTotal": guessLike.TotalCount,
- "hotList": hotList,
- "hotMoreURL": playletser.AllListURL("all", 0, 0, 2, 1),
- "comments": comments.List,
- "commentTotal": comments.TotalCount,
- "commentPage": comments.PageNum,
- "commentSize": comments.PageSize,
- "commentObjectID": commentObjectID,
- "commentObjectType": commentObjectType,
+ "title": title,
+ "navActive": "list",
+ "seoInfo": seo,
+ "playlet": playlet,
+ "chapter": chapter,
+ "chapterID": chapterID,
+ "episode": episode,
+ "canWatch": canWatch,
+ "mainURL": mainURL,
+ "previewURL": previewURL,
+ "hasPreview": previewURL != "",
+ "nextChapterID": playletser.NextChapterID(playlet, chapterID),
+ "advitise": playlet.Advitise,
+ "related": playlet.RelatedRecommendData,
+ "guessLike": guessLike.List,
+ "guessPage": guessLike.PageNum,
+ "guessPageSize": guessLike.PageSize,
+ "guessTotal": guessLike.TotalCount,
+ "hotList": hotList,
+ "hotMoreURL": playletser.AllListURL("all", 0, 0, 2, 1),
"playResponse": gin.H{
- "playlet": playlet,
- "chapter": chapter,
- "chapterID": chapterID,
- "canWatch": canWatch,
- "mainURL": mainURL,
- "previewURL": previewURL,
- "hasPreview": previewURL != "",
- "guessLike": guessLike,
- "hotList": hotList,
- "comments": comments,
- "commentObjectID": commentObjectID,
- "commentObjectType": commentObjectType,
+ "playlet": playlet,
+ "chapter": chapter,
+ "chapterID": chapterID,
+ "canWatch": canWatch,
+ "mainURL": mainURL,
+ "previewURL": previewURL,
+ "hasPreview": previewURL != "",
+ "guessLike": guessLike,
+ "hotList": hotList,
},
}
data["canonicalPath"] = playletser.PlayPath(playlet.Slug, playlet.ID)
@@ -192,27 +168,6 @@ func SeriesPlay(c *gin.Context) {
videoURL := strings.TrimSpace(video.Video.URL)
canWatch := videoURL != ""
- commentObjectID := video.ID
- // 视频评论:objectType=20(swagger:10-短剧 11-短剧剧集 20-视频)
- commentObjectType := commentser.ObjectTypeVideo
- comments := commentser.FetchListOrEmpty(c, commentser.ListQuery{
- ObjectID: commentObjectID,
- ObjectType: commentObjectType,
- PageNum: 1,
- PageSize: 4,
- SortOrder: commentser.SortHot,
- })
- if comments.PageNum <= 0 {
- comments.PageNum = 1
- }
- if comments.PageSize <= 0 {
- comments.PageSize = 4
- }
- commentTotal := comments.TotalCount
- if commentTotal <= 0 && video.CountComment > 0 {
- commentTotal = video.CountComment
- }
-
hot := playletser.FetchAllListOrEmpty(c, playletser.AllListQuery{
PageNum: 1,
PageSize: 8,
@@ -245,51 +200,30 @@ func SeriesPlay(c *gin.Context) {
}
data := gin.H{
- "title": title,
- "navActive": "aiSeries",
- "seoInfo": video.SeoInfo,
- "video": video,
- "videoID": video.ID,
- "videoSlug": video.Slug,
- "cover": cover,
- "videoURL": videoURL,
- "canWatch": canWatch,
- "guessLike": guessLike.List,
- "guessPage": guessLike.PageNum,
- "guessPageSize": guessLike.PageSize,
- "guessTotal": guessLike.TotalCount,
- "guessPlayletID": guessPlayletID,
- "advitise": video.Advitise,
- "comments": comments.List,
- "commentTotal": commentTotal,
- "commentPage": comments.PageNum,
- "commentSize": comments.PageSize,
- "commentObjectID": commentObjectID,
- "commentObjectType": commentObjectType,
- "hotList": hotList,
- "hotMoreURL": playletser.AllListURL("all", 0, 0, 2, 1),
+ "title": title,
+ "navActive": "aiSeries",
+ "seoInfo": video.SeoInfo,
+ "video": video,
+ "videoID": video.ID,
+ "videoSlug": video.Slug,
+ "cover": cover,
+ "videoURL": videoURL,
+ "canWatch": canWatch,
+ "guessLike": guessLike.List,
+ "guessPage": guessLike.PageNum,
+ "guessPageSize": guessLike.PageSize,
+ "guessTotal": guessLike.TotalCount,
+ "guessPlayletID": guessPlayletID,
+ "advitise": video.Advitise,
+ "hotList": hotList,
+ "hotMoreURL": playletser.AllListURL("all", 0, 0, 2, 1),
"videoResponse": gin.H{
- "video": video,
- "videoURL": videoURL,
- "canWatch": canWatch,
- "comments": comments,
- "hotList": hotList,
- "guessLike": guessLike,
- "guessPlayletID": guessPlayletID,
- "commentObjectID": commentObjectID,
- "commentObjectType": commentObjectType,
- },
- "commentDebug": gin.H{
- "path": "/api/app/comment/list",
- "objectId": commentObjectID,
- "objectType": commentObjectType, // 20-视频
- "pageNum": comments.PageNum,
- "pageSize": comments.PageSize,
- "totalCount": commentTotal,
- "list": comments.List,
- "apis": []string{
- "GET /api/app/comment/list",
- },
+ "video": video,
+ "videoURL": videoURL,
+ "canWatch": canWatch,
+ "hotList": hotList,
+ "guessLike": guessLike,
+ "guessPlayletID": guessPlayletID,
},
"playDebug": gin.H{
"canWatch": canWatch,
diff --git a/app/deploy_prod.sh b/app/deploy_prod.sh
index 744701b..5157cbb 100755
--- a/app/deploy_prod.sh
+++ b/app/deploy_prod.sh
@@ -1,6 +1,8 @@
#!/bin/bash
set -e
echo "开始"
+# 本机 Go 装在 ~/sdk/go,未加入 PATH 时在这里补上
+command -v go >/dev/null 2>&1 || export PATH="$HOME/sdk/go/bin:$PATH"
rm -rf ./web_huangguo2_h5 ./web_huangguo2_h5.tar.gz
GOOS=linux GOARCH=amd64 go build -o web_huangguo2_h5
tar zvcf web_huangguo2_h5.tar.gz \
diff --git a/app/router/gin.go b/app/router/gin.go
index 876f290..652752b 100644
--- a/app/router/gin.go
+++ b/app/router/gin.go
@@ -8,7 +8,6 @@ import (
"strings"
"videoweb/app/api/web"
"videoweb/app/appg"
- "videoweb/app/service/commentser"
"videoweb/app/service/playletser"
"videoweb/app/service/seoser"
"videoweb/app/service/translationser"
@@ -62,9 +61,6 @@ func setGinMode() {
func setupEngine(engine *gin.Engine) {
tplFuncs := playletser.TemplateFuncs()
- for name, fn := range commentser.TemplateFuncs() {
- tplFuncs[name] = fn
- }
tplFuncs["InJSONScript"] = inJSONScript
tplFuncs["navHref"] = translationser.NavHref
tplFuncs["navIsDownload"] = translationser.NavIsDownload
@@ -209,7 +205,6 @@ func registerRoutes(r *gin.Engine) {
// 播放页 BFF
r.GET("/api/playlet/guess-like/list", web.GuessLikeList)
- r.GET("/api/comment/list", web.CommentList)
r.GET("/api/web/search/suggest", web.SearchSuggest)
// 搜索引擎抓取、发现与站点所有权验证。
diff --git a/app/service/commentser/list.go b/app/service/commentser/list.go
deleted file mode 100644
index 05c41f4..0000000
--- a/app/service/commentser/list.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package commentser
-
-import (
- "fmt"
- "net/url"
- "strconv"
- "strings"
- "time"
- "videoweb/app/service/upstream"
- "videoweb/pub/common/log"
-
- "github.com/gin-gonic/gin"
-)
-
-const (
- listPath = "/api/app/comment/list"
- defaultCommentSize = 10
-)
-
-// ListQuery 评论列表查询参数。
-type ListQuery struct {
- ObjectID int64
- ObjectType int
- PageNum int
- PageSize int
- SortOrder int
-}
-
-// Normalize 校正分页与排序默认值。
-func (q *ListQuery) Normalize() {
- if q.PageNum <= 0 {
- q.PageNum = 1
- }
- if q.PageSize <= 0 {
- q.PageSize = defaultCommentSize
- }
- if q.PageSize > 50 {
- q.PageSize = 50
- }
- q.ObjectType = NormalizeObjectType(q.ObjectType)
- if q.SortOrder != SortLatest {
- q.SortOrder = SortHot
- }
-}
-
-// FetchList 分页查询评论。
-func FetchList(c *gin.Context, q ListQuery) (*GetCommentListResp, error) {
- q.Normalize()
- if q.ObjectID <= 0 {
- return nil, fmt.Errorf("comment list invalid objectId")
- }
- params := url.Values{}
- params.Set("objectId", strconv.FormatInt(q.ObjectID, 10))
- params.Set("objectType", strconv.Itoa(q.ObjectType))
- params.Set("pageNum", strconv.Itoa(q.PageNum))
- params.Set("pageSize", strconv.Itoa(q.PageSize))
- params.Set("sortOrder", strconv.Itoa(q.SortOrder))
-
- requestPath := listPath + "?" + params.Encode()
- env, err := fetchListOnce(c, requestPath)
- if err != nil {
- return nil, err
- }
- if env.Code != 200 {
- return nil, fmt.Errorf("comment list code=%d msg=%s", env.Code, env.Msg)
- }
- return &env.Data, nil
-}
-
-func fetchListOnce(c *gin.Context, path string) (*APIEnvelope[GetCommentListResp], error) {
- var env APIEnvelope[GetCommentListResp]
- if err := upstream.GetJSON(c, path, &env); err != nil {
- return nil, err
- }
- return &env, nil
-}
-
-// FetchListOrEmpty 失败时返回空列表。
-func FetchListOrEmpty(c *gin.Context, q ListQuery) *GetCommentListResp {
- data, err := FetchList(c, q)
- if err != nil {
- log.Error("fetch comment list failed", log.E(err))
- return &GetCommentListResp{
- ObjectID: q.ObjectID,
- PageNum: q.PageNum,
- PageSize: q.PageSize,
- }
- }
- if data == nil {
- return &GetCommentListResp{
- ObjectID: q.ObjectID,
- PageNum: q.PageNum,
- PageSize: q.PageSize,
- }
- }
- return data
-}
-
-// ParseSortOrder 解析站点评论排序(1 热门 / 2 最新)。
-func ParseSortOrder(s string) int {
- n, err := strconv.Atoi(strings.TrimSpace(s))
- if err != nil || n != SortLatest {
- return SortHot
- }
- return SortLatest
-}
-
-// FormatCreatedAt 展示用时间格式化(非字段映射)。
-func FormatCreatedAt(raw string) string {
- raw = strings.TrimSpace(raw)
- if raw == "" {
- return ""
- }
- layouts := []string{
- time.RFC3339Nano,
- time.RFC3339,
- "2006-01-02T15:04:05Z07:00",
- "2006-01-02 15:04:05",
- }
- for _, layout := range layouts {
- if t, err := time.Parse(layout, raw); err == nil {
- return t.Local().Format("2006/1/2 15:04")
- }
- }
- return raw
-}
-
-// AvatarOrDefault 头像空时回退默认图。
-func AvatarOrDefault(avatar string) string {
- avatar = strings.TrimSpace(avatar)
- if avatar == "" {
- return "/static/images/profile/avatar.png"
- }
- return avatar
-}
diff --git a/app/service/commentser/tplfuncs.go b/app/service/commentser/tplfuncs.go
deleted file mode 100644
index 999a11c..0000000
--- a/app/service/commentser/tplfuncs.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package commentser
-
-import "html/template"
-
-// TemplateFuncs 评论展示辅助。
-func TemplateFuncs() template.FuncMap {
- return template.FuncMap{
- "formatCommentTime": FormatCreatedAt,
- "commentAvatar": AvatarOrDefault,
- }
-}
diff --git a/app/service/commentser/types.go b/app/service/commentser/types.go
deleted file mode 100644
index dad8fa1..0000000
--- a/app/service/commentser/types.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package commentser
-
-// CommentSendReq 对应 swagger proto.CommentSendReq
-// parentsId 为 0 发一级评论,大于 0 发二级评论;replyCommentId 为实际被回复的评论。
-type CommentSendReq struct {
- ObjectID int64 `json:"objectId"`
- ObjectType int `json:"objectType"`
- Text string `json:"text"`
- ParentsID int64 `json:"parentsId"`
- ReplyCommentID int64 `json:"replyCommentId"`
-}
-
-// CommentLikeSetReq 对应 swagger proto.CommentLikeSetReq
-type CommentLikeSetReq struct {
- CommentID int64 `json:"commentId"`
- IsLike bool `json:"isLike"`
-}
-
-// CommentLikeSetResp 对应 swagger proto.CommentLikeSetResp
-type CommentLikeSetResp struct {
- CommentID int64 `json:"commentId"`
- CountLike int64 `json:"countLike"`
- IsLike int `json:"isLike"`
-}
-
-// CommentInfo 对应 swagger proto.CommentInfo
-type CommentInfo struct {
- ID int64 `json:"id"`
- ObjectID int64 `json:"objectId"`
- ObjectType int `json:"objectType"`
- Text string `json:"text"`
- UserID int64 `json:"userId"`
- UserName string `json:"userName"`
- UserAvatar string `json:"userAvatar"`
- CountLike int64 `json:"countLike"`
- CommentCount int64 `json:"commentCount"`
- IsLike int `json:"isLike"`
- CreatedAt string `json:"createdAt"`
- Level int `json:"level,omitempty"`
- ParentsID int64 `json:"parentsId,omitempty"`
- ReplyCommentID int64 `json:"replyCommentId,omitempty"`
- ReplyUserName string `json:"replyUserName,omitempty"`
- Children []CommentInfo `json:"children,omitempty"`
-}
-
-// GetCommentListResp 对应 swagger proto.GetCommentListResp
-type GetCommentListResp struct {
- List []CommentInfo `json:"list"`
- ObjectID int64 `json:"objectId"`
- PageNum int `json:"pageNum"`
- PageSize int `json:"pageSize"`
- TotalCount int64 `json:"totalCount"`
-}
-
-// APIEnvelope 上游统一响应壳
-type APIEnvelope[T any] struct {
- Code int `json:"code"`
- Msg string `json:"msg"`
- Tip string `json:"tip"`
- Data T `json:"data"`
-}
-
-const (
- // ObjectTypePlaylet 短剧评论
- ObjectTypePlaylet = 10
- // ObjectTypeChapter 短剧剧集评论
- ObjectTypeChapter = 11
- // ObjectTypeVideo 视频评论
- ObjectTypeVideo = 20
-
- SortHot = 1 // 热门
- SortLatest = 2 // 最新
-)
-
-// NormalizeObjectType 校正评论对象类型:10-短剧 11-短剧剧集 20-视频。
-func NormalizeObjectType(objectType int) int {
- switch objectType {
- case ObjectTypeChapter, ObjectTypeVideo:
- return objectType
- default:
- return ObjectTypePlaylet
- }
-}
diff --git a/app/static/css/play.css b/app/static/css/play.css
index bffa0b1..e545974 100644
--- a/app/static/css/play.css
+++ b/app/static/css/play.css
@@ -1857,3 +1857,32 @@ a.play-synopsis__tag:hover {
line-height: 16px;
}
}
+
+/* 猜你喜欢放在左栏(原评论位置),右栏为热门榜单 */
+.play-dual > .play-like {
+ flex: 1;
+ min-width: 0;
+ padding: 0;
+}
+
+.play-dual .play-like__grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
+ gap: 20px 16px;
+}
+
+.play-dual .card--play {
+ width: auto;
+ min-width: 0;
+}
+
+@media (max-width: 768px) {
+ .play-dual > .play-like {
+ padding: 0;
+ }
+
+ .play-dual .play-like__grid {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 14px 8px;
+ }
+}
diff --git a/app/static/css/playComments.css b/app/static/css/playComments.css
deleted file mode 100644
index bd4ff3f..0000000
--- a/app/static/css/playComments.css
+++ /dev/null
@@ -1,396 +0,0 @@
-/* 播放页评论区(含输入框、列表、内联回复) */
-
-.play-comments {
- flex: 1 1 0;
- min-width: 0;
- display: flex;
- flex-direction: column;
- gap: 16px;
-}
-
-.play-comments__head {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 14px;
-}
-
-.play-comments__title {
- margin: 0;
- font-size: 22px;
- font-weight: 600;
- line-height: 30px;
-}
-
-.play-comments__count {
- color: var(--text-dim);
- font-size: 14px;
- line-height: 22px;
-}
-
-.play-composer {
- display: flex;
- align-items: center;
- gap: 12px;
-}
-
-.play-composer__avatar {
- width: 40px;
- height: 40px;
- flex-shrink: 0;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- background: #232328;
- border-radius: 999px;
- overflow: hidden;
-}
-
-.play-composer__avatar-img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- display: block;
-}
-
-.play-composer__field {
- flex: 1 1 0;
- min-width: 0;
- height: 44px;
- padding: 0 16px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 10px;
- background: rgba(255, 255, 255, 0.06);
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
-}
-
-.play-composer__input {
- flex: 1 1 0;
- min-width: 0;
- height: 100%;
- padding: 0;
- border: 0;
- outline: none;
- background: transparent;
- color: var(--text);
- font: inherit;
- font-size: 15px;
- line-height: 24px;
-}
-
-.play-composer__input::placeholder {
- color: var(--text-dim);
-}
-
-.play-composer__count {
- flex-shrink: 0;
- color: var(--text-dim);
- font-size: 14px;
- line-height: 20px;
-}
-
-.play-composer__login,
-.play-composer__send {
- flex-shrink: 0;
-}
-
-.play-composer__send:disabled {
- opacity: 0.6;
- cursor: not-allowed;
-}
-
-.play-comment-list {
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.play-comment {
- display: flex;
- align-items: flex-start;
- gap: 12px;
- padding: 16px 0;
- border-bottom: 1px solid var(--line-soft);
-}
-
-.play-comment:last-child {
- border-bottom: 0;
-}
-
-.play-comment__avatar {
- width: 40px;
- height: 40px;
- flex-shrink: 0;
- border-radius: 999px;
- object-fit: cover;
-}
-
-.play-comment__body {
- flex: 1 1 0;
- min-width: 0;
- display: flex;
- flex-direction: column;
- gap: 8px;
-}
-
-.play-comment__meta {
- display: flex;
- align-items: center;
- gap: 10px;
-}
-
-.play-comment__name {
- font-size: 14px;
- font-weight: 500;
- line-height: 20px;
-}
-
-.play-comment__time {
- color: var(--text-dim);
- font-size: 12px;
- line-height: 18px;
-}
-
-.play-comment__text {
- margin: 0;
- color: var(--text-muted);
- font-size: 14px;
- line-height: 22px;
-}
-
-.play-comment--empty {
- justify-content: center;
- align-items: center;
- border-bottom: 0;
-}
-
-.play-comment--empty .play-comment__text {
- padding: 12px 0;
- color: var(--muted, #888);
- text-align: center;
- width: 100%;
-}
-
-.play-comment__reply {
- padding: 10px 14px;
- color: var(--text-muted);
- font-size: 13px;
- line-height: 20px;
- background: rgba(255, 255, 255, 0.04);
- border-radius: var(--radius-sm);
-}
-
-.play-comment__actions {
- display: flex;
- align-items: center;
- gap: 20px;
-}
-
-.play-comment__action {
- display: inline-flex;
- align-items: center;
- gap: 6px;
- padding: 0;
- border: 0;
- background: transparent;
- color: var(--text-dim);
- font: inherit;
- font-size: 12px;
- line-height: 18px;
- cursor: pointer;
-}
-
-.play-comment__action:disabled {
- cursor: default;
- opacity: 0.7;
-}
-
-.play-comment__action.is-active {
- color: var(--brand, #e9c977);
-}
-
-.play-comment__action.is-active .icon {
- opacity: 1;
- filter: none;
-}
-
-.play-comment__action .icon {
- width: 14px;
- height: 14px;
- opacity: 0.75;
-}
-
-.play-comment__inline {
- width: 100%;
- margin-top: 4px;
- padding: 10px 12px;
- display: flex;
- flex-direction: column;
- gap: 8px;
- background: rgba(255, 255, 255, 0.04);
- border: 1px solid var(--line-soft);
- border-radius: var(--radius-sm);
- box-sizing: border-box;
-}
-
-.play-comment__inline-hint {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 8px;
- color: var(--text-dim);
- font-size: 12px;
- line-height: 18px;
-}
-
-.play-comment__inline-hint button {
- flex-shrink: 0;
- padding: 0;
- border: 0;
- background: transparent;
- color: var(--brand, #e9c977);
- font: inherit;
- font-size: 12px;
- line-height: 18px;
- cursor: pointer;
-}
-
-.play-comment__inline-row {
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-.play-comment__inline-input {
- flex: 1 1 0;
- min-width: 0;
- height: 36px;
- padding: 0 12px;
- border: 1px solid var(--line);
- border-radius: 999px;
- background: rgba(0, 0, 0, 0.35);
- color: var(--text);
- font: inherit;
- font-size: 13px;
- line-height: 20px;
- outline: none;
-}
-
-.play-comment__inline-input::placeholder {
- color: var(--text-dim);
-}
-
-.play-comment__inline-input:focus,
-.play-comment__inline-input:focus-visible {
- border-color: rgba(233, 201, 119, 0.55);
-}
-
-.play-comment__inline-send {
- flex-shrink: 0;
- height: 36px;
- padding: 0 14px;
- border: 0;
- border-radius: 999px;
- background: var(--brand, #e9c977);
- color: #141417;
- font: inherit;
- font-size: 13px;
- font-weight: 600;
- line-height: 20px;
- cursor: pointer;
-}
-
-.play-comment__inline-send:disabled {
- opacity: 0.6;
- cursor: not-allowed;
-}
-
-.play-comments__more {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: 6px;
- padding-top: 12px;
- color: var(--text-muted);
- font-size: 14px;
- line-height: 22px;
- background: transparent;
- border: 0;
- cursor: pointer;
-}
-
-.play-comments__more[hidden] {
- display: none;
-}
-
-.play-comments__more:disabled {
- opacity: 0.6;
- cursor: default;
-}
-
-.play-comments__more .icon {
- width: 16px;
- height: 16px;
- transform: rotate(90deg);
-}
-
-@media (max-width: 768px) {
- .play-comments {
- width: 100%;
- padding: 0;
- gap: 16px;
- }
-
- .play-comments__head {
- gap: 14px;
- flex-wrap: nowrap;
- overflow-x: auto;
- -webkit-overflow-scrolling: touch;
- scrollbar-width: none;
- }
-
- .play-comments__head::-webkit-scrollbar {
- display: none;
- }
-
- .play-comments__title {
- flex-shrink: 0;
- font-size: 22px;
- line-height: 30px;
- }
-
- .play-comments__count {
- flex-shrink: 0;
- }
-
- .play-composer {
- width: 100%;
- gap: 12px;
- }
-
- .play-composer__avatar {
- flex-shrink: 0;
- }
-
- .play-composer__field {
- min-width: 0;
- }
-
- .play-composer__login,
- .play-composer__send {
- flex-shrink: 0;
- height: 40px;
- padding: 0 16px;
- }
-
- .play-comment-list {
- width: 100%;
- }
-
- .play-comments__more {
- width: 100%;
- }
-}
diff --git a/app/static/js/pages/play.js b/app/static/js/pages/play.js
index b37c619..3422ad2 100644
--- a/app/static/js/pages/play.js
+++ b/app/static/js/pages/play.js
@@ -702,7 +702,7 @@
if (btn.getAttribute("data-play-bound") === "1") return;
btn.setAttribute("data-play-bound", "1");
btn.addEventListener("click", function (event) {
- // 预告片免登录 / 免解锁;仅正片未解锁时拦充值
+ // 预告片直接播放;仅正片为 App 专享时弹下载提示
if (
btn.hasAttribute("data-play-coin-open") &&
!isPreviewMode()
diff --git a/app/static/js/pages/playComments.js b/app/static/js/pages/playComments.js
deleted file mode 100644
index aa4a69e..0000000
--- a/app/static/js/pages/playComments.js
+++ /dev/null
@@ -1,260 +0,0 @@
-// 播放页评论:只读列表 + 「查看更多评论」追加翻页
-(function () {
- var commentsRoot = document.querySelector("[data-play-comments]");
- if (!commentsRoot) return;
-
- var listEl = document.querySelector("[data-comment-list]");
- var totalEl = document.querySelector("[data-comment-total-label]");
- var moreBtn = document.querySelector("[data-comment-more]");
- var loadingMore = false;
- var PAGE_SIZE = 4;
-
- function toast(message, type) {
- if (typeof window.showToast === "function") {
- window.showToast(message, type);
- return;
- }
- }
-
- function toInt(v, fallback) {
- var n = parseInt(v, 10);
- return isNaN(n) ? fallback || 0 : n;
- }
-
- function escapeHtml(s) {
- return String(s == null ? "" : s)
- .replace(/&/g, "&")
- .replace(//g, ">")
- .replace(/"/g, """);
- }
-
- function getPageSize() {
- return Math.max(
- 1,
- toInt(commentsRoot.getAttribute("data-comment-size"), PAGE_SIZE)
- );
- }
-
- function getPage() {
- return Math.max(
- 1,
- toInt(commentsRoot.getAttribute("data-comment-page"), 1)
- );
- }
-
- function getLoaded() {
- if (!listEl) return 0;
- return listEl.querySelectorAll(".play-comment:not(.play-comment--empty)").length;
- }
-
- function setPagerState(page, loaded, total) {
- if (page != null) commentsRoot.setAttribute("data-comment-page", String(page));
- if (loaded != null) commentsRoot.setAttribute("data-comment-loaded", String(loaded));
- if (total != null) commentsRoot.setAttribute("data-comment-total", String(total));
- syncMoreButton(total != null ? total : toInt(commentsRoot.getAttribute("data-comment-total"), 0));
- }
-
- function syncMoreButton(total) {
- if (!moreBtn) return;
- var loaded = getLoaded();
- var hasMore = total > loaded;
- if (hasMore) {
- moreBtn.hidden = false;
- moreBtn.removeAttribute("hidden");
- } else {
- moreBtn.hidden = true;
- moreBtn.setAttribute("hidden", "");
- }
- }
-
- function formatTime(raw) {
- var s = String(raw || "").trim();
- if (!s) return "刚刚";
- var d = new Date(s);
- if (isNaN(d.getTime())) return s;
- return (
- d.getFullYear() +
- "/" +
- (d.getMonth() + 1) +
- "/" +
- d.getDate() +
- " " +
- String(d.getHours()).padStart(2, "0") +
- ":" +
- String(d.getMinutes()).padStart(2, "0")
- );
- }
-
- function renderCommentItem(item) {
- item = item || {};
- var avatar = String(item.userAvatar || "").trim();
- var name = escapeHtml(item.userName || "匿名用户");
- var text = escapeHtml(item.text || "");
- var time = escapeHtml(formatTime(item.createdAt));
- var like = toInt(item.countLike, 0);
- var avatarHtml = avatar
- ? '
'
- : '
';
- var children = Array.isArray(item.children) ? item.children : [];
- var replies = children
- .map(function (child) {
- var cName = escapeHtml(child.userName || "用户");
- var replyTo = child.replyUserName
- ? " 回复 " + escapeHtml(child.replyUserName)
- : "";
- return (
- '
' + - text + - "
" + - replies + - '
' +
- "" +
- escapeHtml(like) +
- "" +
- "" +
- "请发送邮件至 support@huanguoai.net,我们会尽快回复。
-请通过意见反馈或客服邮箱提交注销申请。
-
{{.Text}}
- {{range .Children}} -暂无评论
-