southnote-mini-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. package/app.js +22 -0
  2. package/app.json +53 -0
  3. package/app.wxss +15 -0
  4. package/assets/file/badwords.js +63008 -0
  5. package/assets/file/rules.js +38 -0
  6. package/assets/images/emoji/smile001.png +0 -0
  7. package/assets/images/emoji/smile002.png +0 -0
  8. package/assets/images/emoji/smile003.png +0 -0
  9. package/assets/images/emoji/smile004.png +0 -0
  10. package/assets/images/emoji/smile005.png +0 -0
  11. package/assets/images/emoji/smile006.png +0 -0
  12. package/assets/images/emoji/smile007.png +0 -0
  13. package/assets/images/emoji/smile008.png +0 -0
  14. package/assets/images/emoji/smile009.png +0 -0
  15. package/assets/images/emoji/smile010.png +0 -0
  16. package/assets/images/emoji/smile011.png +0 -0
  17. package/assets/images/emoji/smile012.png +0 -0
  18. package/assets/images/emoji/smile013.png +0 -0
  19. package/assets/images/emoji/smile014.png +0 -0
  20. package/assets/images/emoji/smile015.png +0 -0
  21. package/assets/images/emoji/smile016.png +0 -0
  22. package/assets/images/emoji/smile017.png +0 -0
  23. package/assets/images/emoji/smile018.png +0 -0
  24. package/assets/images/emoji/smile019.png +0 -0
  25. package/assets/images/emoji/smile020.png +0 -0
  26. package/assets/images/emoji/smile021.png +0 -0
  27. package/assets/images/emoji/smile022.png +0 -0
  28. package/assets/images/emoji/smile023.png +0 -0
  29. package/assets/images/emoji/smile024.png +0 -0
  30. package/assets/images/emoji/smile025.png +0 -0
  31. package/assets/images/emoji/smile026.png +0 -0
  32. package/assets/images/emoji/smile027.png +0 -0
  33. package/assets/images/emoji/smile028.png +0 -0
  34. package/assets/images/emoji/smile029.png +0 -0
  35. package/assets/images/emoji/smile030.png +0 -0
  36. package/assets/images/emoji/smile031.png +0 -0
  37. package/assets/images/emoji/smile032.png +0 -0
  38. package/assets/images/emoji/smile033.png +0 -0
  39. package/assets/images/emoji/smile034.png +0 -0
  40. package/assets/images/emoji/smile035.png +0 -0
  41. package/assets/images/emoji/smile036.png +0 -0
  42. package/assets/images/emoji/smile037.png +0 -0
  43. package/assets/images/emoji/smile038.png +0 -0
  44. package/assets/images/emoji/smile039.png +0 -0
  45. package/assets/images/emoji/smile040.png +0 -0
  46. package/assets/images/emoji/smile041.png +0 -0
  47. package/assets/images/emoji/smile042.png +0 -0
  48. package/assets/images/emoji/smile043.png +0 -0
  49. package/assets/images/emoji/smile044.png +0 -0
  50. package/assets/images/emoji/smile045.png +0 -0
  51. package/assets/images/emoji/smile046.png +0 -0
  52. package/assets/images/emoji/smile047.png +0 -0
  53. package/assets/images/emoji/smile048.png +0 -0
  54. package/assets/images/emoji/smile049.png +0 -0
  55. package/assets/images/emoji/smile050.png +0 -0
  56. package/assets/images/emoji/smile051.png +0 -0
  57. package/assets/images/emoji/smile052.png +0 -0
  58. package/assets/images/icons/age1.png +0 -0
  59. package/assets/images/icons/age2.png +0 -0
  60. package/assets/images/icons/age3.png +0 -0
  61. package/assets/images/icons/attachment.png +0 -0
  62. package/assets/images/icons/clear.png +0 -0
  63. package/assets/images/icons/edit_input.png +0 -0
  64. package/assets/images/icons/header_placeholder.png +0 -0
  65. package/assets/images/icons/home_collect.png +0 -0
  66. package/assets/images/icons/home_collected.png +0 -0
  67. package/assets/images/icons/home_comment.png +0 -0
  68. package/assets/images/icons/home_like.png +0 -0
  69. package/assets/images/icons/home_liked.png +0 -0
  70. package/assets/images/icons/home_message.png +0 -0
  71. package/assets/images/icons/home_share.png +0 -0
  72. package/assets/images/icons/icon_more.png +0 -0
  73. package/assets/images/icons/input_game.png +0 -0
  74. package/assets/images/icons/logo.png +0 -0
  75. package/assets/images/icons/lv1.png +0 -0
  76. package/assets/images/icons/lv2.png +0 -0
  77. package/assets/images/icons/lv3.png +0 -0
  78. package/assets/images/icons/lv4.png +0 -0
  79. package/assets/images/icons/search.png +0 -0
  80. package/assets/images/icons/sex1.png +0 -0
  81. package/assets/images/icons/sex2.png +0 -0
  82. package/assets/images/icons/sign_empty.png +0 -0
  83. package/assets/images/icons/sign_login.png +0 -0
  84. package/assets/wheel/wheel_bg.png +0 -0
  85. package/assets/wheel/wheel_bg2.png +0 -0
  86. package/assets/wheel/wheel_fore.png +0 -0
  87. package/assets/wheel/wheel_to.png +0 -0
  88. package/components/bottomSheet/bottomSheet.js +473 -0
  89. package/components/bottomSheet/bottomSheet.json +3 -0
  90. package/components/bottomSheet/bottomSheet.wxml +73 -0
  91. package/components/bottomSheet/bottomSheet.wxss +238 -0
  92. package/components/experience-item/experience-item.js +105 -0
  93. package/components/experience-item/experience-item.json +4 -0
  94. package/components/experience-item/experience-item.wxml +39 -0
  95. package/components/experience-item/experience-item.wxss +110 -0
  96. package/components/grid-item/grid-item.js +8 -0
  97. package/components/grid-item/grid-item.json +4 -0
  98. package/components/grid-item/grid-item.wxml +62 -0
  99. package/components/grid-item/grid-item.wxss +191 -0
  100. package/components/post-item/post-item.js +1085 -0
  101. package/components/post-item/post-item.json +4 -0
  102. package/components/post-item/post-item.wxml +427 -0
  103. package/components/post-item/post-item.wxss +525 -0
  104. package/components/wiki-renderer/wiki-renderer.js +636 -0
  105. package/components/wiki-renderer/wiki-renderer.json +12 -0
  106. package/components/wiki-renderer/wiki-renderer.wxml +150 -0
  107. package/components/wiki-renderer/wiki-renderer.wxss +412 -0
  108. package/components/wiki-tabs/wiki-tabs.js +52 -0
  109. package/components/wiki-tabs/wiki-tabs.json +3 -0
  110. package/components/wiki-tabs/wiki-tabs.wxml +28 -0
  111. package/components/wiki-tabs/wiki-tabs.wxss +43 -0
  112. package/index.js +49 -0
  113. package/package.json +35 -0
  114. package/pages/addGame/addGame.js +454 -0
  115. package/pages/addGame/addGame.json +3 -0
  116. package/pages/addGame/addGame.wxml +71 -0
  117. package/pages/addGame/addGame.wxss +110 -0
  118. package/pages/addSubject/addSubject.js +199 -0
  119. package/pages/addSubject/addSubject.json +4 -0
  120. package/pages/addSubject/addSubject.wxml +78 -0
  121. package/pages/addSubject/addSubject.wxss +85 -0
  122. package/pages/commonLogin/commonLogin.js +269 -0
  123. package/pages/commonLogin/commonLogin.json +4 -0
  124. package/pages/commonLogin/commonLogin.wxml +57 -0
  125. package/pages/commonLogin/commonLogin.wxss +177 -0
  126. package/pages/copyOfficial/copyOfficial.js +25 -0
  127. package/pages/copyOfficial/copyOfficial.json +3 -0
  128. package/pages/copyOfficial/copyOfficial.wxml +22 -0
  129. package/pages/copyOfficial/copyOfficial.wxss +49 -0
  130. package/pages/demo/demo.js +23 -0
  131. package/pages/demo/demo.json +3 -0
  132. package/pages/demo/demo.wxml +8 -0
  133. package/pages/demo/demo.wxss +24 -0
  134. package/pages/game/game.js +1254 -0
  135. package/pages/game/game.json +8 -0
  136. package/pages/game/game.wxml +371 -0
  137. package/pages/game/game.wxss +672 -0
  138. package/pages/home/home.js +665 -0
  139. package/pages/home/home.json +10 -0
  140. package/pages/home/home.wxml +115 -0
  141. package/pages/home/home.wxss +231 -0
  142. package/pages/lottery-winners/lottery-winners.js +60 -0
  143. package/pages/lottery-winners/lottery-winners.json +4 -0
  144. package/pages/lottery-winners/lottery-winners.wxml +53 -0
  145. package/pages/lottery-winners/lottery-winners.wxss +127 -0
  146. package/pages/message/messageCommentsAndAt/messageCommentsAndAt.js +178 -0
  147. package/pages/message/messageCommentsAndAt/messageCommentsAndAt.json +5 -0
  148. package/pages/message/messageCommentsAndAt/messageCommentsAndAt.wxml +93 -0
  149. package/pages/message/messageCommentsAndAt/messageCommentsAndAt.wxss +177 -0
  150. package/pages/message/messageEntire/messageEntire.js +112 -0
  151. package/pages/message/messageEntire/messageEntire.json +4 -0
  152. package/pages/message/messageEntire/messageEntire.wxml +44 -0
  153. package/pages/message/messageEntire/messageEntire.wxss +88 -0
  154. package/pages/message/messageLikeAndCollect/messageLikeAndCollect.js +147 -0
  155. package/pages/message/messageLikeAndCollect/messageLikeAndCollect.json +5 -0
  156. package/pages/message/messageLikeAndCollect/messageLikeAndCollect.wxml +84 -0
  157. package/pages/message/messageLikeAndCollect/messageLikeAndCollect.wxss +166 -0
  158. package/pages/message/messageNewFans/messageNewFans.js +139 -0
  159. package/pages/message/messageNewFans/messageNewFans.json +5 -0
  160. package/pages/message/messageNewFans/messageNewFans.wxml +35 -0
  161. package/pages/message/messageNewFans/messageNewFans.wxss +85 -0
  162. package/pages/officialWebview/officialWebview.js +13 -0
  163. package/pages/officialWebview/officialWebview.json +3 -0
  164. package/pages/officialWebview/officialWebview.wxml +2 -0
  165. package/pages/officialWebview/officialWebview.wxss +1 -0
  166. package/pages/post/post.js +1856 -0
  167. package/pages/post/post.json +6 -0
  168. package/pages/post/post.wxml +694 -0
  169. package/pages/post/post.wxss +1003 -0
  170. package/pages/post-editor/post-editor.js +465 -0
  171. package/pages/post-editor/post-editor.json +4 -0
  172. package/pages/post-editor/post-editor.wxml +63 -0
  173. package/pages/post-editor/post-editor.wxss +195 -0
  174. package/pages/postDialog/postDialog.js +560 -0
  175. package/pages/postDialog/postDialog.json +6 -0
  176. package/pages/postDialog/postDialog.wxml +377 -0
  177. package/pages/postDialog/postDialog.wxss +979 -0
  178. package/pages/report-category/report-category.js +29 -0
  179. package/pages/report-category/report-category.json +4 -0
  180. package/pages/report-category/report-category.wxml +14 -0
  181. package/pages/report-category/report-category.wxss +43 -0
  182. package/pages/report-form/report-form.js +65 -0
  183. package/pages/report-form/report-form.json +3 -0
  184. package/pages/report-form/report-form.wxml +11 -0
  185. package/pages/report-form/report-form.wxss +44 -0
  186. package/pages/sevenDaySignDetail/sevenDaySignDetail.js +273 -0
  187. package/pages/sevenDaySignDetail/sevenDaySignDetail.json +3 -0
  188. package/pages/sevenDaySignDetail/sevenDaySignDetail.wxml +82 -0
  189. package/pages/sevenDaySignDetail/sevenDaySignDetail.wxss +173 -0
  190. package/pages/topic/topic.js +266 -0
  191. package/pages/topic/topic.json +6 -0
  192. package/pages/topic/topic.wxml +77 -0
  193. package/pages/topic/topic.wxss +162 -0
  194. package/pages/user/user.js +939 -0
  195. package/pages/user/user.json +5 -0
  196. package/pages/user/user.wxml +179 -0
  197. package/pages/user/user.wxss +340 -0
  198. package/pages/userDatum/userDatum.js +24 -0
  199. package/pages/userDatum/userDatum.json +4 -0
  200. package/pages/userDatum/userDatum.wxml +36 -0
  201. package/pages/userDatum/userDatum.wxss +41 -0
  202. package/pages/userGameLib/userGameLib.js +105 -0
  203. package/pages/userGameLib/userGameLib.json +4 -0
  204. package/pages/userGameLib/userGameLib.wxml +42 -0
  205. package/pages/userGameLib/userGameLib.wxss +119 -0
  206. package/pages/webview/webview.js +25 -0
  207. package/pages/webview/webview.json +3 -0
  208. package/pages/webview/webview.wxml +22 -0
  209. package/pages/webview/webview.wxss +50 -0
  210. package/pages/wheelActivivty/wheelActivivty.js +492 -0
  211. package/pages/wheelActivivty/wheelActivivty.json +8 -0
  212. package/pages/wheelActivivty/wheelActivivty.wxml +131 -0
  213. package/pages/wheelActivivty/wheelActivivty.wxss +459 -0
  214. package/pages/wiki/wiki.js +138 -0
  215. package/pages/wiki/wiki.json +6 -0
  216. package/pages/wiki/wiki.wxml +20 -0
  217. package/pages/wiki/wiki.wxss +44 -0
  218. package/request/JKRequest.js +177 -0
  219. package/services/home.js +603 -0
  220. package/towxml/config.js +291 -0
  221. package/towxml/decode.js +35 -0
  222. package/towxml/decode.json +11 -0
  223. package/towxml/decode.wxml +137 -0
  224. package/towxml/decode.wxss +0 -0
  225. package/towxml/img/img.js +98 -0
  226. package/towxml/img/img.json +3 -0
  227. package/towxml/img/img.wxml +1 -0
  228. package/towxml/img/img.wxss +0 -0
  229. package/towxml/index.js +19 -0
  230. package/towxml/latex/latex.js +53 -0
  231. package/towxml/latex/latex.json +5 -0
  232. package/towxml/latex/latex.wxml +1 -0
  233. package/towxml/latex/latex.wxss +0 -0
  234. package/towxml/parse/highlight/highlight.js +1 -0
  235. package/towxml/parse/highlight/index.js +8 -0
  236. package/towxml/parse/highlight/languages/bash.js +111 -0
  237. package/towxml/parse/highlight/languages/c-like.js +236 -0
  238. package/towxml/parse/highlight/languages/c.js +22 -0
  239. package/towxml/parse/highlight/languages/css.js +132 -0
  240. package/towxml/parse/highlight/languages/dart.js +134 -0
  241. package/towxml/parse/highlight/languages/go.js +63 -0
  242. package/towxml/parse/highlight/languages/htmlbars.js +80 -0
  243. package/towxml/parse/highlight/languages/java.js +125 -0
  244. package/towxml/parse/highlight/languages/javascript.js +265 -0
  245. package/towxml/parse/highlight/languages/json.js +52 -0
  246. package/towxml/parse/highlight/languages/less.js +148 -0
  247. package/towxml/parse/highlight/languages/nginx.js +101 -0
  248. package/towxml/parse/highlight/languages/php.js +161 -0
  249. package/towxml/parse/highlight/languages/python-repl.js +29 -0
  250. package/towxml/parse/highlight/languages/python.js +131 -0
  251. package/towxml/parse/highlight/languages/scss.js +122 -0
  252. package/towxml/parse/highlight/languages/shell.js +22 -0
  253. package/towxml/parse/highlight/languages/typescript.js +215 -0
  254. package/towxml/parse/highlight/languages/xml.js +139 -0
  255. package/towxml/parse/highlight/style/github.wxss +99 -0
  256. package/towxml/parse/highlight/style/monokai.wxss +70 -0
  257. package/towxml/parse/index.js +118 -0
  258. package/towxml/parse/markdown/index.js +67 -0
  259. package/towxml/parse/markdown/markdown.js +4 -0
  260. package/towxml/parse/markdown/plugins/echarts.js +11 -0
  261. package/towxml/parse/markdown/plugins/emoji.js +2 -0
  262. package/towxml/parse/markdown/plugins/ins.js +1 -0
  263. package/towxml/parse/markdown/plugins/latex.js +158 -0
  264. package/towxml/parse/markdown/plugins/mark.js +1 -0
  265. package/towxml/parse/markdown/plugins/sub.js +1 -0
  266. package/towxml/parse/markdown/plugins/sup.js +1 -0
  267. package/towxml/parse/markdown/plugins/todo.js +147 -0
  268. package/towxml/parse/markdown/plugins/yuml.js +20 -0
  269. package/towxml/parse/parse2/Parser.js +492 -0
  270. package/towxml/parse/parse2/Tokenizer.js +903 -0
  271. package/towxml/parse/parse2/domelementtype/index.js +55 -0
  272. package/towxml/parse/parse2/domhandler/index.js +145 -0
  273. package/towxml/parse/parse2/domhandler/node.js +474 -0
  274. package/towxml/parse/parse2/entities/decode.js +179 -0
  275. package/towxml/parse/parse2/entities/decode_codepoint.js +60 -0
  276. package/towxml/parse/parse2/entities/encode.js +77 -0
  277. package/towxml/parse/parse2/entities/escape.js +112 -0
  278. package/towxml/parse/parse2/entities/generated/decode-data-html.js +9 -0
  279. package/towxml/parse/parse2/entities/generated/decode-data-xml.js +9 -0
  280. package/towxml/parse/parse2/entities/generated/encode-html.js +12 -0
  281. package/towxml/parse/parse2/entities/index.js +137 -0
  282. package/towxml/parse/parse2/index.js +8 -0
  283. package/towxml/style/main.wxss +419 -0
  284. package/towxml/style/theme/dark.wxss +73 -0
  285. package/towxml/style/theme/light.wxss +63 -0
  286. package/towxml/table/table.js +11 -0
  287. package/towxml/table/table.json +6 -0
  288. package/towxml/table/table.wxml +24 -0
  289. package/towxml/table/table.wxss +0 -0
  290. package/towxml/todogroup/todogroup.js +20 -0
  291. package/towxml/todogroup/todogroup.json +6 -0
  292. package/towxml/todogroup/todogroup.wxml +12 -0
  293. package/towxml/todogroup/todogroup.wxss +3 -0
  294. package/towxml/towxml.js +22 -0
  295. package/towxml/towxml.json +6 -0
  296. package/towxml/towxml.wxml +5 -0
  297. package/towxml/towxml.wxss +8 -0
  298. package/towxml/yuml/yuml.js +51 -0
  299. package/towxml/yuml/yuml.json +5 -0
  300. package/towxml/yuml/yuml.wxml +5 -0
  301. package/towxml/yuml/yuml.wxss +0 -0
  302. package/utils/auth.js +17 -0
  303. package/utils/base64.js +67 -0
  304. package/utils/compressImage.js +41 -0
  305. package/utils/exp.js +49 -0
  306. package/utils/formatPost.js +18 -0
  307. package/utils/parseContent.js +191 -0
  308. package/utils/query-select.js +9 -0
  309. package/utils/sensitive.js +82 -0
@@ -0,0 +1,1254 @@
1
+ import {
2
+ queryGameInfo,
3
+ queryGameWiki,
4
+ queryGameWikiUsers,
5
+ queryGamePosts,
6
+ addGame,
7
+ deleteContent,
8
+ collectPost,
9
+ setUserPostTop,
10
+ queryGameBannerVideo
11
+ } from "../../services/home";
12
+ import {
13
+ decompressBase64Gzip,
14
+ isEmptyObject
15
+ } from "../../utils/base64"
16
+ import {
17
+ formatUTCYear
18
+ } from "../../utils/formatPost";
19
+ import formatUTC from "../../utils/formatPost";
20
+ import {
21
+ getLevelByExp,
22
+ getLevelImg
23
+ } from "../../utils/exp";
24
+ import {
25
+ checkLogin
26
+ } from "../../utils/auth"
27
+ import sdk from '../../index'
28
+ const rulesData = require("../../assets/file/rules.js");
29
+
30
+ Page({
31
+ data: {
32
+ gameId: 0,
33
+ gameInfo: {},
34
+ introduceInfo: {},
35
+ protocolInfo: {},
36
+ empiricInfo: {},
37
+ tabs: [],
38
+ currentTab: 1,
39
+ gameWikiJson: [],
40
+ wikiUsers: [],
41
+ wiki_created_at: '',
42
+
43
+ postTabs: [{
44
+ title: "最新",
45
+ filter: 1
46
+ },
47
+ {
48
+ title: "最热",
49
+ filter: 2
50
+ },
51
+ {
52
+ title: "24小时榜",
53
+ filter: 3
54
+ },
55
+ {
56
+ title: "官方",
57
+ filter: 4
58
+ },
59
+ {
60
+ title: "精品",
61
+ filter: 5
62
+ },
63
+ {
64
+ title: "文章",
65
+ filter: 6
66
+ }
67
+ ],
68
+ subTab: 1,
69
+ activities: [],
70
+ posts: {}, // {1: [...], 2: [...], ...}
71
+ page: {}, // {1: 1, 2: 1, ...}
72
+ hasMore: {}, // {1: true, 2: false, ...}
73
+ loading: {},
74
+
75
+ ruleList: [],
76
+ avatar: '',
77
+ nickname: '',
78
+
79
+ moreSheetVisible: false,
80
+ moreSheetItem: {},
81
+ isOwner: false, //当前cell是否是自己
82
+
83
+ currentBanner: 0,
84
+ bannerRect: null,
85
+
86
+ currentPlayingVideoId: null, //当前播放视频帖子id
87
+
88
+ },
89
+
90
+ onPageScroll(e) {
91
+
92
+ const scrollTop = e.scrollTop
93
+ if (scrollTop >= 350 && this.data.gameInfo.landscape === 1) {
94
+ this.pauseFirstVideo()
95
+ }
96
+ if (scrollTop >= 400 && this.data.gameInfo.landscape === 0) {
97
+ this.pauseFirstVideo()
98
+ }
99
+ },
100
+
101
+ // 发布按钮点击
102
+ onPublish() {
103
+ this.onPauseAllVideo()
104
+ const token = wx.getStorageSync('token'); // 读取缓存里的 token
105
+ const {
106
+ gameId,
107
+ gameInfo
108
+ } = this.data; // 获取当前游戏信息
109
+ if (token) {
110
+ // 已登录,跳转到发布页面
111
+ wx.navigateTo({
112
+ url: `/pages/post-editor/post-editor?gameId=${gameId}&gameName=${encodeURIComponent(gameInfo.name || '')}`,
113
+ });
114
+ } else {
115
+ // 未登录,跳转登录页面
116
+ wx.navigateTo({
117
+ url: '/pages/commonLogin/commonLogin',
118
+ // url:'/pages/login/login'
119
+ });
120
+ }
121
+ },
122
+ gotoUserDetail(e) {
123
+ this.onPauseAllVideo()
124
+ const userId = e.currentTarget.dataset.id;
125
+ wx.navigateTo({
126
+ url: `/pages/user/user?id=${userId}`
127
+ });
128
+ },
129
+ // 游戏详情页分享逻辑
130
+ onShareAppMessage() {
131
+ const {
132
+ gameInfo,
133
+ gameId
134
+ } = this.data;
135
+
136
+ // 使用游戏名称作为分享标题,如果没有则显示默认文案
137
+ const title = gameInfo?.name || '查看游戏详情';
138
+
139
+ return {
140
+ title,
141
+ // 分享路径携带 gameId 参数
142
+ path: `/pages/game/game?id=${gameId}`
143
+ };
144
+ },
145
+
146
+
147
+ onLoad(options) {
148
+ const gameId = options.id || sdk.gameId;
149
+
150
+ if (!gameId) {
151
+ wx.showToast({
152
+ title: '缺少gameId参数',
153
+ icon: 'none'
154
+ });
155
+ return;
156
+ }
157
+ this.setData({
158
+ gameId,
159
+
160
+ });
161
+
162
+ this.getGameInfo();
163
+ this.getGameIntroduce();
164
+ this.getGameProtocol();
165
+ this.getGameEmpiricValue();
166
+ this.getGameWikiInfo()
167
+
168
+ // 默认加载 最热
169
+ this.loadPosts(2);
170
+
171
+ this.setData({
172
+ nickname: wx.getStorageSync('nickname'),
173
+ avatar: wx.getStorageSync('avatar')
174
+ })
175
+
176
+
177
+ },
178
+
179
+ changeSubTab(e) {
180
+ const index = e.detail.index;
181
+ const filter = this.data.postTabs[index].filter;
182
+ this.setData({
183
+ subTab: index
184
+ });
185
+
186
+ // 如果当前tab还没加载过数据,则加载
187
+ if (!this.data.posts[filter]) {
188
+ this.loadPosts(filter);
189
+ }
190
+ },
191
+
192
+ /** 获取帖子列表(已改造 ✅) */
193
+ /** 获取帖子列表(已改造 ✅) */
194
+ async loadPosts(filter, append = false) {
195
+ const {
196
+ gameId,
197
+ page,
198
+ posts,
199
+ loading
200
+ } = this.data;
201
+
202
+ if (loading[filter]) return;
203
+
204
+ const nextPage = append ? (page[filter] || 1) + 1 : 1;
205
+ this.setData({
206
+ [`loading.${filter}`]: true
207
+ });
208
+
209
+ try {
210
+ const res = await queryGamePosts(gameId, nextPage, filter);
211
+ if (res?.code === 0 && Array.isArray(res.data)) {
212
+ // 格式化帖子数据
213
+ const list = res.data.map(item => {
214
+ const p = item.post || {};
215
+ const shared = item.shared;
216
+
217
+ const user = item.user || {};
218
+ const game = item.game || {};
219
+ if (game.exp != null) {
220
+ user.level = getLevelByExp(game?.exp);
221
+ user.levelImg = getLevelImg(user.level)
222
+ }
223
+
224
+ return {
225
+ ...item,
226
+ post: {
227
+ ...p,
228
+ imageArray: p.images ? p.images.split(",") : [],
229
+ formatTime: formatUTC(p.created_at)
230
+ },
231
+ shared: shared?.post ? {
232
+ ...shared,
233
+ post: {
234
+ ...shared.post,
235
+ imageArray: shared.post.images ? shared.post.images.split(",") : [],
236
+ formatTime: formatUTC(shared.post.created_at)
237
+ }
238
+ } : shared
239
+ };
240
+ });
241
+
242
+ const got = list.length > 0;
243
+
244
+ if (append) {
245
+ // ✅ 只追加新增数据,避免重渲染旧数据
246
+ const currentLength = posts[filter]?.length || 0;
247
+ let update = {};
248
+ list.forEach((item, idx) => {
249
+ update[`posts.${filter}[${currentLength + idx}]`] = item;
250
+ });
251
+
252
+ this.setData({
253
+ ...update,
254
+ [`page.${filter}`]: nextPage,
255
+ [`hasMore.${filter}`]: got,
256
+ [`loading.${filter}`]: false
257
+ });
258
+
259
+ } else {
260
+ // 首次加载直接覆盖
261
+ this.setData({
262
+ [`posts.${filter}`]: list,
263
+ [`page.${filter}`]: nextPage,
264
+ [`hasMore.${filter}`]: got,
265
+ [`loading.${filter}`]: false
266
+ });
267
+ }
268
+
269
+ } else {
270
+ this.setData({
271
+ [`hasMore.${filter}`]: false,
272
+ [`loading.${filter}`]: false
273
+ });
274
+ }
275
+
276
+ } catch (e) {
277
+ console.error("获取帖子失败", e);
278
+ this.setData({
279
+ [`loading.${filter}`]: false
280
+ });
281
+ }
282
+ },
283
+
284
+ /** 点击加载更多 */
285
+ loadMore(e) {
286
+ const filter = e.currentTarget.dataset.filter;
287
+ this.loadPosts(filter, true);
288
+ },
289
+
290
+ toggleRule(e) {
291
+ const index = e.currentTarget.dataset.index;
292
+ const key = `ruleList[${index}].open`;
293
+ this.setData({
294
+ [key]: !this.data.ruleList[index].open
295
+ });
296
+ },
297
+
298
+ async getGameInfo() {
299
+ try {
300
+ const res = await queryGameInfo(this.data.gameId, 1, 1);
301
+ if (res.code === 0) {
302
+ const info = res.data;
303
+
304
+ // releaseTime
305
+ if (info.download?.android?.release_at) {
306
+ info.releaseTime = formatUTC(info.download.android.release_at);
307
+ } else {
308
+ info.releaseTime = "暂无";
309
+ }
310
+
311
+ // managers
312
+ info.managers = Array.isArray(info.managers) ? info.managers : [];
313
+ info.chiefManagers = info.managers.filter(m => m.role === 'chief')
314
+ info.normalManagers = info.managers.filter(m => m.role !== 'chief')
315
+ // activities
316
+ info.activities = Array.isArray(info.activities) ? info.activities : [];
317
+ // 分组:is_face_slap === 1 的单独存,最多取一个
318
+ const faceSlapActivity = info.activities.find(a => a.is_face_slap === 1);
319
+ info.faceSlapActivity = faceSlapActivity || null; // 单个对象或 null
320
+
321
+ // 其余的(不含 is_face_slap === 1 的)还放回 activities
322
+ info.activities = info.activities.filter(a => a.is_face_slap !== 1);
323
+
324
+
325
+ let banners = Array.isArray(info.banners) ?
326
+ info.banners.map(url => ({
327
+ type: 'image',
328
+ url
329
+ })) : [];
330
+
331
+ // 如果有视频封面,则插入视频 banner
332
+ if (info.video_cover_url) {
333
+ banners.unshift({
334
+ type: 'video',
335
+ poster: info.video_cover_url,
336
+ videoUrl: '', // 点击播放时再获取
337
+ needFetch: true
338
+ });
339
+ }
340
+
341
+ info.banners = banners;
342
+
343
+ // 生成 tabs 动态列表
344
+ const baseTabs = ["简介", "帖子", "攻略", "版规", "我的"];
345
+ if (info.activities.length > 0) {
346
+ baseTabs.push('活动'); // 在帖子前插入活动
347
+ }
348
+
349
+
350
+
351
+ this.setData({
352
+ gameInfo: info,
353
+ tabs: baseTabs
354
+ });
355
+
356
+ wx.setNavigationBarTitle({
357
+ title: info.name || '社区中心',
358
+ })
359
+ }
360
+ } catch (e) {
361
+ console.error("获取游戏信息失败", e);
362
+ }
363
+ },
364
+
365
+
366
+ async getGameIntroduce() {
367
+ try {
368
+ const res = await queryGameInfo(this.data.gameId, 1, 2);
369
+ if (res.code === 0) {
370
+ this.setData({
371
+ introduceInfo: res.data
372
+ });
373
+ }
374
+ } catch (e) {
375
+ console.error("获取研发商信息失败", e);
376
+ }
377
+ },
378
+
379
+ async getGameWikiInfo() {
380
+ try {
381
+ const res = await queryGameWiki(this.data.gameId);
382
+ if (res.code === 0) {
383
+ if (res.data?.images && Array.isArray(res.data?.images)) {
384
+ this.setData({
385
+ images: res.data?.images
386
+ })
387
+ }
388
+ if (res.data?.page) {
389
+ try {
390
+ const result = decompressBase64Gzip(res.data.page?.payload)
391
+
392
+
393
+
394
+ // 递归将所有图片 url 中的 http:// 替换为 https://
395
+ function replaceHttpToHttps(obj) {
396
+ if (Array.isArray(obj)) {
397
+ return obj.map(replaceHttpToHttps)
398
+ } else if (obj !== null && typeof obj === 'object') {
399
+ const newObj = {}
400
+ Object.keys(obj).forEach(function (key) {
401
+ const value = obj[key]
402
+ if (key === 'url' && typeof value === 'string') {
403
+ newObj[key] = value.replace(/^http:\/\//i, 'https://')
404
+ } else {
405
+ newObj[key] = replaceHttpToHttps(value)
406
+ }
407
+ })
408
+ return newObj
409
+ }
410
+ return obj
411
+ }
412
+
413
+ let httpsResult = replaceHttpToHttps(result)
414
+
415
+ if (res.data.stats) {
416
+ httpsResult = httpsResult.map(item =>
417
+ item.type === 6 ? {
418
+ ...item,
419
+ stats: res.data.stats
420
+ } : item
421
+ )
422
+ }
423
+
424
+ console.log('解压后的 JSON:', httpsResult)
425
+
426
+ this.setData({
427
+ wiki_created_at: formatUTCYear(res.data.page?.created_at),
428
+ gameWikiJson: httpsResult
429
+ })
430
+
431
+ } catch (err) {
432
+ console.error('解压失败', err)
433
+ }
434
+ } else {
435
+ this.setData({
436
+ gameWikiJson: null
437
+ })
438
+ }
439
+ }
440
+
441
+ const usersData = await queryGameWikiUsers(this.data.gameId);
442
+ if (usersData.code === 0) {
443
+ this.setData({
444
+ wikiUsers: Array.isArray(usersData.data) ? usersData.data : []
445
+ })
446
+ }
447
+ } catch (e) {
448
+ console.error("获取研发商信息失败", e);
449
+ }
450
+ },
451
+
452
+ async getGameProtocol() {
453
+ try {
454
+ const res = await queryGameInfo(this.data.gameId, 1, 3);
455
+ if (res.code === 0) {
456
+ // 处理接口返回的版规
457
+ const apiRules = (Array.isArray(res.data?.rules) ? res.data?.rules : []).map(item => ({
458
+ icon: item.level,
459
+ title: item.content,
460
+ desc: item.supplement || '',
461
+ open: false
462
+ }));
463
+
464
+ // 默认版规
465
+ const defaultRules = rulesData.rules.map(i => ({
466
+ ...i,
467
+ open: false
468
+ }));
469
+
470
+ // 合并并排序: 只按 icon 升序
471
+ const mergedRules = [...apiRules, ...defaultRules].sort((a, b) => {
472
+ return a.icon - b.icon;
473
+ });
474
+
475
+ this.setData({
476
+ protocolInfo: res.data ?? {},
477
+ ruleList: mergedRules
478
+ });
479
+ }
480
+ } catch (e) {
481
+ console.error("获取版规信息失败", e);
482
+ }
483
+ },
484
+
485
+ async getGameEmpiricValue() {
486
+ try {
487
+ const res = await queryGameInfo(this.data.gameId, 1, 4);
488
+ if (res.code === 0) {
489
+ this.setData({
490
+ empiricInfo: res.data
491
+ });
492
+ }
493
+ } catch (e) {
494
+ console.error("获取经验信息失败", e);
495
+ }
496
+ },
497
+
498
+ changeTab(e) {
499
+ const index = e.currentTarget.dataset.index;
500
+ this.onPauseAllVideo()
501
+ this.setData({
502
+ currentTab: index
503
+ });
504
+ },
505
+
506
+ toggleJoin(e) {
507
+ if (!checkLogin()) return; // 🔥 登录校验
508
+
509
+ const is_fans = this.data.gameInfo.is_fans;
510
+ const gameInfo = e.currentTarget.dataset.gameinfo
511
+ const nType = is_fans !== 1 ? 1 : 2
512
+ addGame(gameInfo.id, nType).then(res => {
513
+ wx.showToast({
514
+ title: nType === 1 ? '加入游戏库成功' : '移出游戏库',
515
+ })
516
+ this.setData({
517
+ "gameInfo.is_fans": is_fans === 1 ? 0 : 1
518
+ });
519
+ })
520
+ },
521
+ // 前往活动详情
522
+ goActivityDetail(e) {
523
+ this.onPauseAllVideo()
524
+ const item = e.currentTarget.dataset.item;
525
+ // h5活动直接跳官网
526
+ if (item.activity_type === 2) {
527
+ wx.navigateTo({
528
+ url: `/pages/copyOfficial/copyOfficial?url=${encodeURIComponent('https://www.southnote.cn')}`
529
+ });
530
+ }
531
+ // 签到跳转
532
+ if (item.activity_type === 1) {
533
+ wx.navigateTo({
534
+ url: `/pages/sevenDaySignDetail/sevenDaySignDetail?activity_id=${item.activity_id}`
535
+ });
536
+ }
537
+ // 大转盘跳转
538
+ if (item.activity_type === 4) {
539
+ if (!checkLogin()) return; // 🔥 登录校验
540
+
541
+ wx.navigateTo({
542
+ url: `/pages/wheelActivivty/wheelActivivty?activity_id=${item.activity_id}`
543
+ });
544
+ }
545
+ // 话题活动跳转话题
546
+ if (item.activity_type === 3) {
547
+ wx.navigateTo({
548
+ url: `/pages/topic/topic?id=${item.activity_topic}`
549
+ });
550
+ }
551
+ },
552
+
553
+ /** 页面触底事件(上拉加载更多) */
554
+ /** 页面触底事件(上拉加载更多) */
555
+ onReachBottom() {
556
+ const {
557
+ currentTab,
558
+ subTab,
559
+ postTabs,
560
+ hasMore,
561
+ loading
562
+ } = this.data;
563
+
564
+ // 只在「帖子」这个主 Tab 下才加载更多
565
+ if (currentTab !== 1) return;
566
+
567
+ const filter = postTabs[subTab].filter;
568
+
569
+ // 如果当前过滤条件下还有更多且未在加载中,则加载下一页
570
+ if (hasMore[filter] && !loading[filter]) {
571
+ this.loadPosts(filter, true);
572
+ }
573
+ },
574
+
575
+
576
+ // 底部弹窗
577
+
578
+ onMoreTap(e) {
579
+ const index = e.currentTarget.dataset.index; // 当前帖子在列表中的索引
580
+
581
+ const item = e.detail.item;
582
+ const currentUserId = wx.getStorageSync('appuid'); // 当前登录用户id
583
+ const isOwner = item.user.id === currentUserId;
584
+ this.setData({
585
+ isOwner,
586
+ moreSheetVisible: true,
587
+ moreSheetItem: item,
588
+ currentPostIndex: index
589
+
590
+ });
591
+ },
592
+
593
+ onPinTap() {
594
+ const post = this.data.moreSheetItem.post;
595
+ const type = this.data.isPinned ? 2 : 1; // 1置顶,2取消置顶
596
+
597
+ wx.showLoading({
598
+ title: '处理中...'
599
+ });
600
+ setUserPostTop(post.id, type).then(res => {
601
+ wx.hideLoading();
602
+ if (res.code === 0) {
603
+ wx.showToast({
604
+ title: type === 1 ? '置顶成功' : '取消置顶成功',
605
+ icon: 'success'
606
+ });
607
+
608
+ // 更新当前组件状态
609
+ this.setData({
610
+ 'item.post.is_user_top': type === 1 ? 1 : 0,
611
+ isPinned: type === 1 ? 1 : 0
612
+ });
613
+
614
+ this.onCloseMoreSheet();
615
+
616
+ // 如果置顶,则需要移动帖子到列表第一位,取消其他帖子置顶,并滚动到顶部
617
+ if (type === 1) {
618
+ const pages = getCurrentPages();
619
+ const currentPage = pages[pages.length - 1];
620
+
621
+ if (currentPage.route === 'pages/user/user') {
622
+ let postsData = currentPage.data.posts;
623
+
624
+ if (Array.isArray(postsData)) {
625
+ // 先取消其他帖子置顶
626
+ postsData = postsData.map(p => {
627
+ if (p.post.id !== post.id && p.post.is_user_top === 1) {
628
+ p.post.is_user_top = 0;
629
+ }
630
+ return p;
631
+ });
632
+
633
+ // 找到当前帖子在数组中的索引
634
+ const currentIndex = postsData.findIndex(p => p.post.id === post.id);
635
+ if (currentIndex > -1) {
636
+ const [pinnedPost] = postsData.splice(currentIndex, 1);
637
+ pinnedPost.post.is_user_top = 1
638
+ // 插入到数组第一个位置
639
+ postsData.unshift(pinnedPost);
640
+ }
641
+
642
+ currentPage.setData({
643
+ posts: postsData
644
+ });
645
+
646
+ // 页面滚动到顶部
647
+ wx.pageScrollTo({
648
+ scrollTop: 0,
649
+ duration: 300
650
+ });
651
+ } else if (postsData && typeof postsData === 'object') {
652
+ const newPostsObj = {};
653
+ Object.keys(postsData).forEach(key => {
654
+ if (Array.isArray(postsData[key])) {
655
+ // 取消其他帖子置顶
656
+ let arr = postsData[key].map(p => {
657
+ if (p.post.id !== post.id && p.post.is_user_top === 1) {
658
+ p.post.is_user_top = 0;
659
+ }
660
+ return p;
661
+ });
662
+
663
+ // 将当前帖子移动到第一个
664
+ const currentIndex = arr.findIndex(p => p.post.id === post.id);
665
+ if (currentIndex > -1) {
666
+ const [pinnedPost] = arr.splice(currentIndex, 1);
667
+ pinnedPost.post.is_user_top = 1
668
+ arr.unshift(pinnedPost);
669
+ }
670
+
671
+ newPostsObj[key] = arr;
672
+ } else {
673
+ newPostsObj[key] = postsData[key];
674
+ }
675
+ });
676
+
677
+ currentPage.setData({
678
+ posts: newPostsObj
679
+ });
680
+
681
+ wx.pageScrollTo({
682
+ scrollTop: 0,
683
+ duration: 300
684
+ });
685
+ }
686
+ }
687
+ }
688
+ } else {
689
+ wx.showToast({
690
+ title: res.msg || '操作失败',
691
+ icon: 'error'
692
+ });
693
+ }
694
+ });
695
+ },
696
+ // 关闭弹窗
697
+ onCloseMoreSheet() {
698
+ this.setData({
699
+ moreSheetVisible: false
700
+ });
701
+ },
702
+
703
+ // 弹窗选项点击
704
+ onDelete() {
705
+ const postId = this.data.moreSheetItem.post.id;
706
+ deleteContent(postId).then(res => {
707
+ if (res.code === 0) {
708
+ wx.showToast({
709
+ title: '删除成功',
710
+ icon: 'success'
711
+ });
712
+
713
+ // 删除父页面列表里的帖子(兼容数组和对象)
714
+ const pages = getCurrentPages();
715
+ const currentPage = pages[pages.length - 1]; // 当前页
716
+
717
+ const postsData = currentPage.data.posts;
718
+ if (Array.isArray(postsData)) {
719
+ // posts 是数组
720
+ currentPage.setData({
721
+ posts: postsData.filter(p => p.post.id !== postId)
722
+ });
723
+ } else if (postsData && typeof postsData === 'object') {
724
+ // posts 是对象,每个 value 都可能是帖子数组
725
+ const newPosts = {};
726
+ Object.keys(postsData).forEach(key => {
727
+ if (Array.isArray(postsData[key])) {
728
+ newPosts[key] = postsData[key].filter(p => p.post.id !== postId);
729
+ } else {
730
+ newPosts[key] = postsData[key]; // 保留原值
731
+ }
732
+ });
733
+ currentPage.setData({
734
+ posts: newPosts
735
+ });
736
+ }
737
+
738
+
739
+ this.triggerEvent('deletePost', {
740
+ post: this.data.moreSheetItem.post
741
+ });
742
+ this.onCloseMoreSheet();
743
+ } else {
744
+ wx.showToast({
745
+ title: res.msg || '删除失败',
746
+ icon: 'error'
747
+ });
748
+ }
749
+ });
750
+ },
751
+
752
+ // 举报帖子
753
+ onReport() {
754
+ this.onPauseAllVideo()
755
+ wx.navigateTo({
756
+ url: `/pages/report-category/report-category?postId=${this.data.moreSheetItem.post.id}`,
757
+ })
758
+
759
+ this.triggerEvent('reportPost', {
760
+ post: this.data.moreSheetItem.post
761
+ });
762
+ this.onCloseMoreSheet();
763
+ },
764
+
765
+ // 收藏/取消收藏
766
+ // 收藏/取消收藏(放在 Page({ ... }) 里)
767
+ async onFavorite() {
768
+ const post = this.data.moreSheetItem.post;
769
+ const nType = post.is_collect === 1 ? 2 : 1; // 1收藏,2取消收藏
770
+
771
+ // 可选:先显示 loading,防止重复点击
772
+ wx.showLoading({
773
+ title: nType === 1 ? '收藏中...' : '取消中...'
774
+ });
775
+
776
+ try {
777
+ const res = await collectPost(post.id, nType);
778
+ wx.hideLoading();
779
+
780
+ if (res.code === 0) {
781
+ wx.showToast({
782
+ title: nType === 1 ? '已收藏' : '取消收藏',
783
+ icon: 'success'
784
+ });
785
+
786
+ // 1) 更新当前页面的 moreSheetItem(弹窗)
787
+ const updatedMoreSheetItem = {
788
+ ...this.data.moreSheetItem,
789
+ post: {
790
+ ...this.data.moreSheetItem.post,
791
+ is_collect: nType === 1 ? 1 : 0
792
+ }
793
+ };
794
+
795
+ // 2) 更新当前页面的 posts(兼容两种结构:object map 或 数组)
796
+ const {
797
+ posts
798
+ } = this.data;
799
+ let newPosts;
800
+
801
+ if (Array.isArray(posts)) {
802
+ // posts 本身是数组
803
+ newPosts = posts.map(p => {
804
+ if (p.post && p.post.id === post.id) {
805
+ return {
806
+ ...p,
807
+ post: {
808
+ ...p.post,
809
+ is_collect: nType === 1 ? 1 : 0
810
+ }
811
+ };
812
+ }
813
+ return p;
814
+ });
815
+ } else if (posts && typeof posts === 'object') {
816
+ // posts 是按 filter 分组的对象 {1: [...], 2: [...], ...}
817
+ newPosts = {};
818
+ Object.keys(posts).forEach(key => {
819
+ const arr = posts[key];
820
+ if (Array.isArray(arr)) {
821
+ newPosts[key] = arr.map(p => {
822
+ if (p.post && p.post.id === post.id) {
823
+ return {
824
+ ...p,
825
+ post: {
826
+ ...p.post,
827
+ is_collect: nType === 1 ? 1 : 0
828
+ }
829
+ };
830
+ }
831
+ return p;
832
+ });
833
+ } else {
834
+ // 保持原样(防止意外结构)
835
+ newPosts[key] = posts[key];
836
+ }
837
+ });
838
+ } else {
839
+ // posts 为空或未知结构,直接保持 undefined
840
+ newPosts = posts;
841
+ }
842
+
843
+ // 3) 批量 setData 更新(保持 atomic)
844
+ this.setData({
845
+ moreSheetItem: updatedMoreSheetItem,
846
+ posts: newPosts
847
+ });
848
+
849
+ // 4) 可选:同步更新其他页面(如果你项目里还有 userDetail / postDetail 也需要同步)
850
+ // 这里做一个遍历所有页面并更新它们的 posts,如果存在的话
851
+ const pages = getCurrentPages();
852
+ pages.forEach(pg => {
853
+ if (!pg || !pg.data) return;
854
+ const pgPosts = pg.data.posts;
855
+ if (!pgPosts) return;
856
+
857
+ // 同上:支持 array 或 object
858
+ if (Array.isArray(pgPosts)) {
859
+ const updated = pgPosts.map(p => {
860
+ if (p.post && p.post.id === post.id) {
861
+ return {
862
+ ...p,
863
+ post: {
864
+ ...p.post,
865
+ is_collect: nType === 1 ? 1 : 0
866
+ }
867
+ };
868
+ }
869
+ return p;
870
+ });
871
+ pg.setData({
872
+ posts: updated
873
+ });
874
+ } else if (pgPosts && typeof pgPosts === 'object') {
875
+ const updatedObj = {};
876
+ let needSet = false;
877
+ Object.keys(pgPosts).forEach(k => {
878
+ const arr = pgPosts[k];
879
+ if (Array.isArray(arr)) {
880
+ const newArr = arr.map(p => {
881
+ if (p.post && p.post.id === post.id) {
882
+ needSet = true;
883
+ return {
884
+ ...p,
885
+ post: {
886
+ ...p.post,
887
+ is_collect: nType === 1 ? 1 : 0
888
+ }
889
+ };
890
+ }
891
+ return p;
892
+ });
893
+ updatedObj[k] = newArr;
894
+ } else {
895
+ updatedObj[k] = pgPosts[k];
896
+ }
897
+ });
898
+ if (needSet) {
899
+ pg.setData({
900
+ posts: updatedObj
901
+ });
902
+ }
903
+ }
904
+ });
905
+
906
+ // 5) 关闭弹窗(如果你希望操作后自动关闭)
907
+ this.onCloseMoreSheet();
908
+
909
+ } else {
910
+ wx.showToast({
911
+ title: res.msg || (nType === 1 ? '收藏失败' : '取消收藏失败'),
912
+ icon: 'error'
913
+ });
914
+ }
915
+
916
+ } catch (err) {
917
+ wx.hideLoading();
918
+ console.error('收藏接口失败', err);
919
+ wx.showToast({
920
+ title: '网络错误,请稍后重试',
921
+ icon: 'error'
922
+ });
923
+ }
924
+ },
925
+
926
+ onFollowChanged(e) {
927
+ const {
928
+ userId,
929
+ isFans
930
+ } = e.detail;
931
+
932
+ const {
933
+ posts
934
+ } = this.data;
935
+ let updatedPosts;
936
+
937
+ if (Array.isArray(posts)) {
938
+ // posts 是数组
939
+ updatedPosts = posts.map(p => {
940
+ if (p.user.id === userId) {
941
+ p.user.is_fans = isFans ? 1 : 0;
942
+ }
943
+ return p;
944
+ });
945
+ } else if (posts && typeof posts === 'object') {
946
+ // posts 是按 filter 分组的对象 {1: [...], 2: [...], ...}
947
+ updatedPosts = {};
948
+ Object.keys(posts).forEach(key => {
949
+ const arr = posts[key];
950
+ if (Array.isArray(arr)) {
951
+ updatedPosts[key] = arr.map(p => {
952
+ if (p.user.id === userId) {
953
+ p.user.is_fans = isFans ? 1 : 0;
954
+ }
955
+ return p;
956
+ });
957
+ } else {
958
+ updatedPosts[key] = arr;
959
+ }
960
+ });
961
+ } else {
962
+ updatedPosts = posts;
963
+ }
964
+
965
+ this.setData({
966
+ posts: updatedPosts
967
+ });
968
+
969
+ wx.showToast({
970
+ title: isFans ? '关注成功' : '已取消关注',
971
+ icon: 'success'
972
+ });
973
+ },
974
+
975
+ // 下拉刷新
976
+ async onPullDownRefresh() {
977
+ const {
978
+ currentTab,
979
+ subTab,
980
+ postTabs
981
+ } = this.data;
982
+
983
+ // ✅ 只在「帖子」tab 下刷新
984
+ if (currentTab !== 1) {
985
+ wx.stopPullDownRefresh();
986
+ return;
987
+ }
988
+
989
+ const filter = postTabs[subTab].filter;
990
+
991
+ try {
992
+ // 1️⃣ 重置当前 filter 的状态
993
+ this.setData({
994
+ [`page.${filter}`]: 0,
995
+ [`hasMore.${filter}`]: true,
996
+ [`loading.${filter}`]: false
997
+ });
998
+
999
+ // 2️⃣ 重新拉第一页(append = false)
1000
+ await this.loadPosts(filter, false);
1001
+
1002
+ } catch (e) {
1003
+ console.error('下拉刷新失败', e);
1004
+ } finally {
1005
+ // 3️⃣ 结束下拉动画
1006
+ wx.stopPullDownRefresh();
1007
+ }
1008
+ },
1009
+ // 点击video内部按钮视频回调
1010
+ handlePlayVideo() {
1011
+
1012
+ this.pausePostVideo()
1013
+ },
1014
+ // 点击banner播放
1015
+ async onBannerVideoPlay(e) {
1016
+ const index = e.currentTarget.dataset.index;
1017
+ const banners = this.data.gameInfo.banners;
1018
+ const item = banners[index];
1019
+
1020
+ if (item.videoUrl || item.loading) return;
1021
+
1022
+
1023
+ // 暂停当前播放的帖子视频
1024
+ this.pausePostVideo()
1025
+
1026
+
1027
+ // 加载 banner 视频
1028
+ item.loading = true;
1029
+ this.setData({
1030
+ 'gameInfo.banners': banners
1031
+ });
1032
+
1033
+ wx.showLoading({
1034
+ title: '加载中...'
1035
+ });
1036
+
1037
+ try {
1038
+ const res = await queryGameBannerVideo(this.data.gameId);
1039
+
1040
+ if (res.code === 0 && res.data) {
1041
+ item.videoUrl = res.data;
1042
+ item.loading = false;
1043
+
1044
+ this.setData({
1045
+ 'gameInfo.banners': banners
1046
+ }, () => {
1047
+ // 自动播放
1048
+ wx.createVideoContext(`bannerVideo-${index}`, this).play();
1049
+ });
1050
+ } else {
1051
+ throw new Error('无视频地址');
1052
+ }
1053
+ } catch (err) {
1054
+ item.loading = false;
1055
+ this.setData({
1056
+ 'gameInfo.banners': banners
1057
+ });
1058
+ wx.showToast({
1059
+ title: '视频加载失败',
1060
+ icon: 'none'
1061
+ });
1062
+ } finally {
1063
+ wx.hideLoading();
1064
+ }
1065
+ },
1066
+
1067
+ pausePostVideo() {
1068
+ const prevId = this.data.currentPlayingVideoId;
1069
+ if (prevId) {
1070
+ const posts = this.data.posts;
1071
+ for (const key in posts) {
1072
+ const arr = posts[key];
1073
+ if (Array.isArray(arr)) {
1074
+ const idx = arr.findIndex(p => p.post.id === prevId);
1075
+ if (idx !== -1) {
1076
+ const prevComponent = this.selectComponent(`#postItem-${key}-${idx}`);
1077
+ if (prevComponent && prevComponent.pauseVideo) {
1078
+ prevComponent.pauseVideo();
1079
+ }
1080
+ break;
1081
+ }
1082
+ }
1083
+ }
1084
+ this.setData({
1085
+ currentPlayingVideoId: null
1086
+ });
1087
+ }
1088
+ },
1089
+ onBannerChange(e) {
1090
+ // 暂停第一个视频
1091
+ const videoContext = wx.createVideoContext('bannerVideo-0', this);
1092
+ videoContext.pause();
1093
+
1094
+ // 记录的时间存下来,下次播放用
1095
+ const time = this.data.videoCurrentTime;
1096
+
1097
+ // seek 到记录时间
1098
+ videoContext.seek(time);
1099
+
1100
+ this.setData({
1101
+ currentBanner: e.detail.current
1102
+ })
1103
+ },
1104
+
1105
+ onVideoTimeUpdate(e) {
1106
+ this.setData({
1107
+ videoCurrentTime: e.detail.currentTime
1108
+ });
1109
+ },
1110
+
1111
+
1112
+
1113
+
1114
+
1115
+ pauseFirstVideo() {
1116
+ // video 可能还没加载
1117
+ const ctx = wx.createVideoContext('bannerVideo-0', this)
1118
+ ctx.pause()
1119
+ },
1120
+ onBannerScroll(e) {
1121
+ const now = Date.now()
1122
+ if (now - (this._lastScrollTime || 0) < 100) return
1123
+ this._lastScrollTime = now
1124
+
1125
+ const scrollLeft = e.detail.scrollLeft
1126
+
1127
+ const bannerWidthPx = wx.getWindowInfo().windowWidth * 300 / 750
1128
+ const threshold = bannerWidthPx * 0.8
1129
+
1130
+ if (scrollLeft > threshold) {
1131
+ this.pauseFirstVideo()
1132
+ }
1133
+ },
1134
+
1135
+ prevBanner() {
1136
+ const total = this.data.gameInfo.banners.length
1137
+ let cur = this.data.currentBanner
1138
+
1139
+ cur = cur === 0 ? total - 1 : cur - 1
1140
+
1141
+ this.setData({
1142
+ currentBanner: cur
1143
+ })
1144
+ },
1145
+
1146
+ nextBanner() {
1147
+ const total = this.data.gameInfo.banners.length
1148
+ let cur = this.data.currentBanner
1149
+
1150
+ cur = cur === total - 1 ? 0 : cur + 1
1151
+
1152
+ this.setData({
1153
+ currentBanner: cur
1154
+ })
1155
+ },
1156
+
1157
+
1158
+ onVideoPlay(e) {
1159
+ const postId = e.detail.id;
1160
+ const prevId = this.data.currentPlayingVideoId;
1161
+
1162
+ if (prevId && prevId !== postId) {
1163
+
1164
+ let prevComponent = null;
1165
+ const posts = this.data.posts;
1166
+ for (const key in posts) {
1167
+ const arr = posts[key];
1168
+ const idx = arr.findIndex(p => p.post.id === prevId);
1169
+
1170
+ if (idx !== -1) {
1171
+ prevComponent = this.selectComponent(`#postItem-${key}-${idx}`);
1172
+ break;
1173
+ }
1174
+ }
1175
+
1176
+ if (prevComponent) prevComponent.pauseVideo();
1177
+ }
1178
+
1179
+ // 暂停 banner 视频
1180
+ this.pauseFirstVideo()
1181
+
1182
+ this.setData({
1183
+ currentPlayingVideoId: postId
1184
+ });
1185
+ },
1186
+
1187
+ /**
1188
+ * 暂停当前页面所有正在播放的视频
1189
+ * - 帖子视频
1190
+ * - banner 视频
1191
+ */
1192
+ onPauseAllVideo() {
1193
+ // 1️⃣ 暂停帖子视频
1194
+ const prevId = this.data.currentPlayingVideoId;
1195
+ if (prevId) {
1196
+ const posts = this.data.posts;
1197
+
1198
+ for (const key in posts) {
1199
+ const arr = posts[key];
1200
+ if (!Array.isArray(arr)) continue;
1201
+
1202
+ const idx = arr.findIndex(p => p.post?.id === prevId);
1203
+ if (idx !== -1) {
1204
+ const comp = this.selectComponent(`#postItem-${key}-${idx}`);
1205
+ if (comp && typeof comp.pauseVideo === 'function') {
1206
+ comp.pauseVideo();
1207
+ }
1208
+ break;
1209
+ }
1210
+ }
1211
+
1212
+ this.setData({
1213
+ currentPlayingVideoId: null
1214
+ });
1215
+ }
1216
+
1217
+ // 2️⃣ 暂停 banner 视频(可能还没渲染,try-catch 保命)
1218
+ this.pauseFirstVideo()
1219
+ },
1220
+
1221
+ /**
1222
+ * 复制QQ号到剪贴板
1223
+ * @param {string} qqNumber
1224
+ */
1225
+ copyQQNumber() {
1226
+ const qq = this.data.introduceInfo.qq
1227
+
1228
+ if (!qq) {
1229
+ wx.showToast({
1230
+ title: '暂无QQ号',
1231
+ icon: 'none'
1232
+ })
1233
+ return
1234
+ }
1235
+
1236
+ wx.setClipboardData({
1237
+ data: qq,
1238
+ success: () => {
1239
+ wx.showToast({
1240
+ title: 'QQ号已复制',
1241
+ icon: 'success'
1242
+ })
1243
+ }
1244
+ })
1245
+ }
1246
+
1247
+
1248
+
1249
+
1250
+
1251
+
1252
+
1253
+
1254
+ });