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,199 @@
1
+ import {
2
+ queryUserTopics,
3
+ queryTopicRank
4
+ } from "../../services/home"
5
+
6
+ Page({
7
+ data: {
8
+ activeKey: 0,
9
+ recentTopics: [], // 最近讨论
10
+ userTopics: [],
11
+ rankTopics: [],
12
+ userPage: 1,
13
+ rankPage: 1,
14
+ userHasMore: true,
15
+ rankHasMore: true,
16
+ loading: false,
17
+ refreshing: false,
18
+
19
+ searchValue: "",
20
+ showSearchResult: false,
21
+ },
22
+ onLoad() {
23
+ this.loadRecentTopics(); // 加载缓存的最近讨论
24
+ this.loadUserTopics(true);
25
+ },
26
+
27
+ loadRecentTopics() {
28
+ const recentTopics = wx.getStorageSync('recentTopics') || [];
29
+ this.setData({
30
+ recentTopics
31
+ });
32
+ },
33
+
34
+ /** 保存最近讨论缓存,最新的在前,最多 10 条 */
35
+ saveRecentTopic(topic) {
36
+ let recentTopics = wx.getStorageSync('recentTopics') || [];
37
+ // 先去重
38
+ recentTopics = recentTopics.filter(item => item.name !== topic.name);
39
+ // 插入到最前面
40
+ recentTopics.unshift(topic);
41
+ // 保留最多 10 条
42
+ if (recentTopics.length > 10) {
43
+ recentTopics = recentTopics.slice(0, 10);
44
+ }
45
+ wx.setStorageSync('recentTopics', recentTopics);
46
+ this.setData({
47
+ recentTopics
48
+ });
49
+ },
50
+
51
+ onSearchInput(e) {
52
+ const value = e.detail.value.trim();
53
+ this.setData({
54
+ searchValue: value,
55
+ showSearchResult: !!value,
56
+ });
57
+ },
58
+
59
+ onCreateTopic() {
60
+ const name = this.data.searchValue;
61
+ if (!name) return;
62
+
63
+ const topic = {
64
+ name,
65
+ isNew: true
66
+ };
67
+ this.saveRecentTopic(topic); // 保存到最近讨论缓存
68
+
69
+ const pages = getCurrentPages();
70
+ const prevPage = pages[pages.length - 2];
71
+ prevPage.setData({
72
+ selectedTopic: topic
73
+ });
74
+ wx.navigateBack();
75
+ },
76
+
77
+ onChangeTab(e) {
78
+ const key = e.detail;
79
+ this.setData({
80
+ activeKey: key
81
+ });
82
+ if (key === 1 && this.data.userTopics.length === 0) {
83
+ this.loadUserTopics(true);
84
+ } else if (key === 2 && this.data.rankTopics.length === 0) {
85
+ this.loadRankTopics(true);
86
+ }
87
+ },
88
+
89
+ onSelectTopic(e) {
90
+ const topic = e.currentTarget.dataset.topic;
91
+ this.saveRecentTopic(topic);
92
+
93
+ const pages = getCurrentPages();
94
+ const prevPage = pages[pages.length - 2];
95
+
96
+ if (!prevPage) {
97
+ console.warn('未找到上一个页面');
98
+ wx.navigateBack();
99
+ return;
100
+ }
101
+ const bottomSheet = prevPage.selectComponent?.('#bottomSheet');
102
+ if (bottomSheet) {
103
+ setTimeout(() => {
104
+ bottomSheet.setData({
105
+ selectedTopic: topic,
106
+ });
107
+ }, 100);
108
+ } else {
109
+ prevPage.setData({
110
+ selectedTopic: topic
111
+ });
112
+ }
113
+
114
+ wx.navigateBack();
115
+ },
116
+
117
+ /** 加载我的收藏 */
118
+ async loadUserTopics(reset = false) {
119
+ if (this.data.loading || (!this.data.userHasMore && !reset)) return;
120
+ this.setData({
121
+ loading: true
122
+ });
123
+ const page = reset ? 1 : this.data.userPage + 1;
124
+ try {
125
+ const res = await queryUserTopics(page);
126
+ if (res.code === 0) {
127
+ const list = reset ? res.data : [...this.data.userTopics, ...res.data];
128
+ this.setData({
129
+ userTopics: list,
130
+ userPage: page,
131
+ userHasMore: res.data.length > 0,
132
+ });
133
+ }
134
+ } catch (err) {
135
+ console.error("加载我的收藏失败:", err);
136
+ } finally {
137
+ this.setData({
138
+ loading: false,
139
+ refreshing: false
140
+ });
141
+ }
142
+ },
143
+
144
+ /** 加载热门话题 */
145
+ async loadRankTopics(reset = false) {
146
+ if (this.data.loading || (!this.data.rankHasMore && !reset)) return;
147
+ this.setData({
148
+ loading: true
149
+ });
150
+ const page = reset ? 1 : this.data.rankPage + 1;
151
+ try {
152
+ const res = await queryTopicRank(page);
153
+ if (res.code === 0) {
154
+ const list = reset ? res.data : [...this.data.rankTopics, ...res.data];
155
+ this.setData({
156
+ rankTopics: list,
157
+ rankPage: page,
158
+ rankHasMore: res.data.length > 0,
159
+ });
160
+ }
161
+ } catch (err) {
162
+ console.error("加载热门话题失败:", err);
163
+ } finally {
164
+ this.setData({
165
+ loading: false,
166
+ refreshing: false
167
+ });
168
+ }
169
+ },
170
+
171
+ onRefresh() {
172
+ this.setData({
173
+ refreshing: true
174
+ });
175
+ const {
176
+ activeKey
177
+ } = this.data;
178
+ if (activeKey === 1) {
179
+ this.loadUserTopics(true);
180
+ } else if (activeKey === 2) {
181
+ this.loadRankTopics(true);
182
+ } else {
183
+ this.setData({
184
+ refreshing: false
185
+ });
186
+ }
187
+ },
188
+
189
+ onReachBottom() {
190
+ const {
191
+ activeKey
192
+ } = this.data;
193
+ if (activeKey === 1) {
194
+ this.loadUserTopics();
195
+ } else if (activeKey === 2) {
196
+ this.loadRankTopics();
197
+ }
198
+ }
199
+ });
@@ -0,0 +1,4 @@
1
+ {
2
+ "usingComponents": {},
3
+ "navigationBarTitleText": "添加话题"
4
+ }
@@ -0,0 +1,78 @@
1
+ <view class="page">
2
+ <!-- 搜索框 -->
3
+ <view class="search-bar">
4
+ <image class="search-icon" src="/assets/images/icons/search.png" style="width: 15px;height: 15px;position: absolute;margin-left: 10px;"></image>
5
+ <input class="search-input" placeholder="请输入话题" placeholder-style="color:#ccc" value="{{searchValue}}" bindinput="onSearchInput" />
6
+ </view>
7
+
8
+
9
+ <view wx:if="{{showSearchResult}}" class="search-overlay">
10
+ <view class="topic-item" bindtap="onCreateTopic">
11
+ <view class="hash-icon">#</view>
12
+ <view class="topic-info">
13
+ <view class="topic-name">#{{searchValue}}#</view>
14
+ <view class="topic-sub">创建话题</view>
15
+ </view>
16
+ </view>
17
+ </view>
18
+
19
+ <view class="main" wx:else>
20
+ <!-- 左侧侧边栏 -->
21
+ <van-sidebar active-key="{{activeKey}}" bind:change="onChangeTab" class="sidebar">
22
+ <van-sidebar-item title="最近讨论" />
23
+ <van-sidebar-item title="我的收藏" />
24
+ <van-sidebar-item title="热门话题" />
25
+ </van-sidebar> <!-- 右侧内容 -->
26
+ <scroll-view scroll-y="true" class="content" refresher-enabled="true" refresher-triggered="{{refreshing}}" bindrefresherrefresh="onRefresh" bindscrolltolower="onReachBottom">
27
+ <!-- 最近讨论 -->
28
+ <view wx:if="{{activeKey === 0}}">
29
+ <block wx:if="{{recentTopics.length}}">
30
+ <block wx:for="{{recentTopics}}" wx:key="name">
31
+ <view class="topic-item" bindtap="onSelectTopic" data-topic="{{item}}">
32
+ <view class="hash-icon">#</view>
33
+ <view class="topic-info">
34
+ <view class="topic-name">#{{item.name}}#</view>
35
+ <view class="topic-sub">{{item.posts_count > 0 ? '帖子:' + item.posts_count : '选择话题'}}</view>
36
+ </view>
37
+ </view>
38
+ </block>
39
+ </block>
40
+ <view wx:else class="empty">暂无最近讨论</view>
41
+ </view>
42
+
43
+ <!-- 我的收藏 -->
44
+ <view wx:if="{{activeKey === 1}}">
45
+ <block wx:if="{{userTopics.length}}">
46
+ <block wx:for="{{userTopics}}" wx:key="name">
47
+ <view class="topic-item" bindtap="onSelectTopic" data-topic="{{item}}">
48
+ <view class="hash-icon">#</view>
49
+ <view class="topic-info">
50
+ <view class="topic-name">#{{item.name}}#</view>
51
+ <view class="topic-sub">{{item.posts_count > 0 ? '帖子:' + item.posts_count : '选择话题'}}</view>
52
+ </view>
53
+ </view>
54
+ </block>
55
+ <view wx:if="{{loading}}" class="loading">加载中...</view>
56
+ <view wx:if="{{!userHasMore && !loading}}" class="no-more">没有更多数据</view>
57
+ </block>
58
+ <view wx:else class="empty">暂无收藏话题</view>
59
+ </view> <!-- 热门话题 -->
60
+ <view wx:if="{{activeKey === 2}}">
61
+ <block wx:if="{{rankTopics.length}}">
62
+ <block wx:for="{{rankTopics}}" wx:key="name">
63
+ <view class="topic-item" bindtap="onSelectTopic" data-topic="{{item}}">
64
+ <view class="hash-icon">#</view>
65
+ <view class="topic-info">
66
+ <view class="topic-name">#{{item.name}}#</view>
67
+ <view class="topic-sub">选择话题</view>
68
+ </view>
69
+ </view>
70
+ </block>
71
+ <view wx:if="{{loading}}" class="loading">加载中...</view>
72
+ <view wx:if="{{!rankHasMore && !loading}}" class="no-more">没有更多数据</view>
73
+ </block>
74
+ <view wx:else class="empty">暂无热门话题</view>
75
+ </view>
76
+ </scroll-view>
77
+ </view>
78
+ </view>
@@ -0,0 +1,85 @@
1
+ .page {
2
+ display: flex;
3
+ flex-direction: column;
4
+ height: 100vh;
5
+ background-color: #fff;
6
+ }
7
+
8
+ .search-bar {
9
+ position: relative;
10
+ display: flex;
11
+ align-items: center;
12
+ padding: 16rpx 24rpx;
13
+ border-bottom: 1px solid #f2f2f2;
14
+ }
15
+
16
+ .search-input {
17
+ flex: 1;
18
+ background-color: #f5f5f5;
19
+ border-radius: 30rpx;
20
+ padding: 10rpx 24rpx;
21
+ padding-left: 60rpx;
22
+ font-size: 26rpx;
23
+ color: #333;
24
+ }
25
+
26
+ .main {
27
+ display: flex;
28
+ flex: 1;
29
+ overflow: hidden;
30
+ }
31
+
32
+ .sidebar {
33
+ width: 160rpx;
34
+ border-right: 1px solid #f5f5f5;
35
+ background-color: #fafafa;
36
+ }
37
+
38
+ .content {
39
+ flex: 1;
40
+ padding: 0 0 0 20rpx;
41
+ overflow-y: scroll;
42
+ }
43
+
44
+ .topic-item {
45
+ display: flex;
46
+ align-items: center;
47
+ background: #fff;
48
+ padding: 20rpx;
49
+ border-bottom: 1px solid #f5f5f5;
50
+ }
51
+
52
+ .hash-icon {
53
+ width: 60rpx;
54
+ height: 60rpx;
55
+ border-radius: 50%;
56
+ background-color: #002d7f;
57
+ color: #fff;
58
+ text-align: center;
59
+ line-height: 60rpx;
60
+ font-size: 36rpx;
61
+ margin-right: 20rpx;
62
+ flex-shrink: 0;
63
+ }
64
+
65
+ .topic-info {
66
+ display: flex;
67
+ flex-direction: column;
68
+ }
69
+
70
+ .topic-name {
71
+ font-size: 28rpx;
72
+ color: #000;
73
+ }
74
+
75
+ .topic-sub {
76
+ font-size: 24rpx;
77
+ color: #999;
78
+ margin-top: 4rpx;
79
+ }
80
+
81
+ .empty {
82
+ text-align: center;
83
+ color: #999;
84
+ padding: 80rpx 0;
85
+ }
@@ -0,0 +1,269 @@
1
+ import {
2
+ passwdLogin,
3
+ blueBookLogin,
4
+ sendSMS,
5
+ phoneLogin
6
+ } from "../../services/home"
7
+
8
+ Page({
9
+ data: {
10
+ loginType: 'code', // 'code' 或 'password'
11
+ phone: '',
12
+ code: '',
13
+ password: '',
14
+ showPassword: false,
15
+ agreed: false,
16
+ countdown: 0,
17
+ canLogin: false,
18
+ },
19
+
20
+ onLoad() {
21
+ this.updateCanLogin();
22
+ },
23
+
24
+ gotoAgrement(e) {
25
+ let url = ''
26
+ if (e.currentTarget.dataset.type == 1) {
27
+ url = 'https://www.southnote.cn/private?type=2'
28
+ } else
29
+ if (e.currentTarget.dataset.type == 2) {
30
+ url = 'https://www.southnote.cn/private?type=1'
31
+ } else
32
+ if (e.currentTarget.dataset.type == 3) {
33
+ url = 'https://www.southnote.cn/private?type=3'
34
+ }
35
+ wx.navigateTo({
36
+ url: `/pages/officialWebview/officialWebview?url=${encodeURIComponent(url)}`
37
+ });
38
+ },
39
+ onClose() {
40
+
41
+ // 关闭逻辑:如果是 modal,可 wx.navigateBack 或 wx.switchTab 等
42
+ wx.navigateBack({
43
+ delta: 1
44
+ });
45
+ },
46
+
47
+ /* 输入处理 */
48
+ onPhoneInput(e) {
49
+ const v = (e.detail && e.detail.value) || '';
50
+ this.setData({
51
+ phone: v
52
+ }, () => this.updateCanLogin());
53
+ },
54
+
55
+ onCodeInput(e) {
56
+ const v = (e.detail && e.detail.value) || '';
57
+ this.setData({
58
+ code: v
59
+ }, () => this.updateCanLogin());
60
+ },
61
+
62
+ onPasswordInput(e) {
63
+ const v = (e.detail && e.detail.value) || '';
64
+ this.setData({
65
+ password: v
66
+ }, () => this.updateCanLogin());
67
+ },
68
+
69
+ onAgreeChange(e) {
70
+ this.setData({
71
+ agreed: e.detail
72
+ }, () => this.updateCanLogin());
73
+ },
74
+
75
+ toggleLoginType() {
76
+ const next = this.data.loginType === 'code' ? 'password' : 'code';
77
+ this.setData({
78
+ loginType: next,
79
+ code: '',
80
+ password: '',
81
+ // 重置密码可见状态
82
+ showPassword: false,
83
+ }, () => this.updateCanLogin());
84
+ },
85
+
86
+ toggleShowPassword() {
87
+ this.setData({
88
+ showPassword: !this.data.showPassword
89
+ });
90
+ },
91
+
92
+ /* 发送验证码(演示) */
93
+ /* 发送验证码 */
94
+ async onSendCode() {
95
+ if (!/^1[3-9]\d{9}$/.test(this.data.phone)) {
96
+ wx.showToast({
97
+ title: '请输入正确的手机号',
98
+ icon: 'none'
99
+ });
100
+ return;
101
+ }
102
+ if (this.data.countdown > 0) return;
103
+
104
+ try {
105
+ // 调用后端发送验证码接口
106
+ const res = await sendSMS(this.data.phone);
107
+ if (res.code !== 0) {
108
+ throw new Error(res.msg || '发送失败');
109
+ }
110
+
111
+ wx.showToast({
112
+ title: '验证码已发送',
113
+ icon: 'success'
114
+ });
115
+
116
+ // 倒计时 60s
117
+ this.setData({
118
+ countdown: 60
119
+ });
120
+ const timer = setInterval(() => {
121
+ const next = this.data.countdown - 1;
122
+ if (next <= 0) {
123
+ clearInterval(timer);
124
+ this.setData({
125
+ countdown: 0
126
+ });
127
+ } else {
128
+ this.setData({
129
+ countdown: next
130
+ });
131
+ }
132
+ }, 1000);
133
+
134
+ } catch (err) {
135
+ wx.showToast({
136
+ title: err.message || '发送失败,请稍后重试',
137
+ icon: 'none'
138
+ });
139
+ }
140
+ },
141
+
142
+
143
+ /* 忘记密码 */
144
+ onForgot() {
145
+ // 跳转到忘记密码页面(你可以自己实现)
146
+ wx.navigateTo({
147
+ url: '/pages/forgot/forgot'
148
+ });
149
+ },
150
+
151
+ /* 登录 */
152
+ async onLogin() {
153
+ if (!this.data.agreed) {
154
+ wx.showToast({
155
+ title: '请先同意协议',
156
+ icon: 'none'
157
+ });
158
+ return;
159
+ }
160
+ // 基本校验
161
+ if (!/^1[3-9]\d{9}$/.test(this.data.phone)) {
162
+ wx.showToast({
163
+ title: '请输入正确手机号',
164
+ icon: 'none'
165
+ });
166
+ return;
167
+ }
168
+
169
+ try {
170
+ // 显示 loading
171
+ wx.showLoading({
172
+ title: '登录中...',
173
+ mask: true
174
+ });
175
+
176
+ let loginRes;
177
+
178
+ if (this.data.loginType === 'code') {
179
+ // 验证码登录
180
+ if (this.data.code.length < 4) {
181
+ wx.showToast({
182
+ title: '请输入正确验证码',
183
+ icon: 'none'
184
+ });
185
+ return;
186
+ }
187
+
188
+ loginRes = await phoneLogin(this.data.phone, this.data.code);
189
+ if (loginRes.code !== 0) {
190
+ wx.hideLoading()
191
+ throw new Error(loginRes.msg || '登录失败');
192
+ }
193
+
194
+ } else {
195
+ // 密码登录
196
+ if (!this.data.password || this.data.password.length < 6) {
197
+ wx.showToast({
198
+ title: '请输入正确密码',
199
+ icon: 'none'
200
+ });
201
+ return;
202
+ }
203
+ loginRes = await passwdLogin(this.data.phone, this.data.password);
204
+ if (loginRes.code !== 0) {
205
+ wx.hideLoading()
206
+ throw new Error(loginRes.msg);
207
+ }
208
+ }
209
+
210
+ const {
211
+ appuid,
212
+ token
213
+ } = loginRes.data;
214
+ if (!appuid || !token) {
215
+ throw new Error('登录返回缺少 appuid 或 token');
216
+ }
217
+
218
+ // 调用 blueBookLogin 接口
219
+ blueBookLogin(appuid, token).then(res => {
220
+ wx.hideLoading()
221
+ setTimeout(() => {
222
+
223
+ wx.showToast({
224
+ title: '登录成功',
225
+ icon: 'success'
226
+ });
227
+ }, 200);
228
+
229
+ wx.setStorageSync('appuid', res.data.user_id);
230
+ wx.setStorageSync('token', res.data.token);
231
+ wx.setStorageSync('nickname', res.data.nickname);
232
+ wx.setStorageSync('avatar', res.data.avatar);
233
+ wx.navigateBack();
234
+ });
235
+
236
+ } catch (err) {
237
+ wx.hideLoading()
238
+ setTimeout(() => {
239
+
240
+ console.error('登录失败:', err);
241
+ wx.showToast({
242
+ title: err.message || '登录失败,请稍后重试',
243
+ icon: 'none'
244
+ });
245
+ }, 200);
246
+ }
247
+ },
248
+
249
+ /* 协议跳转:我们在 wxml 中使用 navigator 指向页面 */
250
+ /* 公共方法:根据当前输入和勾选计算是否允许登录 */
251
+ updateCanLogin() {
252
+ const phoneOk = /^1[3-9]\d{9}$/.test(this.data.phone);
253
+ let inputOk = false;
254
+ if (this.data.loginType === 'code') {
255
+ inputOk = this.data.code && this.data.code.length >= 4; // 实际要求按你后台校验
256
+ } else {
257
+ inputOk = this.data.password && this.data.password.length >= 6;
258
+ }
259
+ const can = phoneOk && inputOk && this.data.agreed;
260
+ this.setData({
261
+ canLogin: can
262
+ }, () => {
263
+ // 动态设置按钮样式(active class)
264
+ const pages = getCurrentPages();
265
+ if (!pages || pages.length === 0) return;
266
+ const page = pages[pages.length - 1];
267
+ });
268
+ },
269
+ });
@@ -0,0 +1,4 @@
1
+ {
2
+ "usingComponents": {},
3
+ "navigationBarTitleText": "登录"
4
+ }
@@ -0,0 +1,57 @@
1
+ <view class="page">
2
+
3
+ <!-- 标题 / 副标题 -->
4
+ <view class="header">
5
+ <text class="title">{{ loginType === 'code' ? '短信验证码登录' : '密码登录' }}</text>
6
+ <text class="subtitle">未注册的手机号登录成功后将自动注册</text>
7
+ </view>
8
+
9
+ <!-- 手机号输入 -->
10
+ <view class="field">
11
+ <view class="phone-left">
12
+ <text class="flag">+86</text>
13
+ <text class="caret">▾</text>
14
+
15
+ </view>
16
+ <view style="width: 1px;height: 15px;background-color: #919191;margin-right:10px;"></view>
17
+ <input class="input" placeholder="请输入手机号" type="number" maxlength="11" value="{{phone}}" bindinput="onPhoneInput" />
18
+ </view>
19
+
20
+ <!-- 验证码输入 -->
21
+ <view wx:if="{{loginType === 'code'}}" class="field code-field">
22
+ <input class="input" placeholder="验证码" type="number" maxlength="6" value="{{code}}" bindinput="onCodeInput" />
23
+ <view class="send" bindtap="onSendCode" disabled="{{countdown>0}}">{{ countdown>0 ? countdown + 's' : '发送验证码' }}</view>
24
+ </view>
25
+
26
+ <!-- 密码输入 -->
27
+ <view wx:else class="field password-field">
28
+ <input class="input" placeholder="请输入密码" password="{{!showPassword}}" value="{{password}}" bindinput="onPasswordInput" />
29
+ <view style="width: 30px;display: flex;align-items: center;justify-content: center;" catchtap="toggleShowPassword">
30
+ <van-icon size="20" name="{{showPassword ? 'eye-o':'closed-eye'}}" />
31
+ </view>
32
+ </view>
33
+
34
+ <!-- 切换登录方式 & 忘记密码 -->
35
+ <view class=" row">
36
+ <view class="switch" bindtap="toggleLoginType">
37
+ <van-icon style="margin-right: 5px;" name="exchange" />
38
+ {{ loginType === 'code' ? '密码登录' : '验证码登录' }}
39
+ </view>
40
+ <!-- <view wx:if="{{loginType === 'password'}}" class="forget" bindtap="onForgot">忘记密码?</view> -->
41
+ </view>
42
+
43
+ <!-- 登录按钮 -->
44
+ <view class="login-btn {{canLogin ?'active':'disabled'}}" disabled="{{!canLogin}}" bindtap="onLogin">登录</view>
45
+
46
+ <!-- 协议勾选 -->
47
+ <view class="agreement">
48
+ <van-checkbox value="{{ agreed }}" shape="square" bind:change="onAgreeChange" size="20" />
49
+
50
+ <view style="margin-left: 10px;">
51
+ <span class="agree-text">我已阅读并同意</span>
52
+ <span class="link" catch:tap="gotoAgrement" data-type="1">《用户协议》</span>
53
+ <span class="link" catch:tap="gotoAgrement" data-type="2">《隐私政策》</span>
54
+ <span class="link" catch:tap="gotoAgrement" data-type="3">《未成年人个人信息保护规则》</span>
55
+ </view>
56
+ </view>
57
+ </view>