├── php-api/ # 改造后的PHP接口层 ├── java-ad-service/ # 若依框架微服务(广告+VIP+分账) ├── uniapp-reader/ # UniApp前端项目 │ ├── pages/ # 各端页面 │ └──
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

index.vue 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. <template>
  2. <scroll-view scroll-y class="welfare-page">
  3. <!-- 用户信息栏 -->
  4. <view class="user-header">
  5. <image :src="userAvatar" class="avatar" />
  6. <view class="info">
  7. <text class="name">{{ userName }}</text>
  8. <text class="coins">金币: {{ coins }}</text>
  9. </view>
  10. <view class="vip-tag" v-if="isVIP">
  11. <uni-icons type="crown" size="16" color="#ffc53d"></uni-icons>
  12. <text>VIP会员</text>
  13. </view>
  14. </view>
  15. <!-- 签到区域 -->
  16. <view class="signin-section">
  17. <view class="sign-header">
  18. <text class="title">每日签到</text>
  19. <text class="subtitle">已连续签到 {{ signedDays }} 天</text>
  20. </view>
  21. <view class="sign-calendar">
  22. <view
  23. v-for="day in 7"
  24. :key="day"
  25. :class="[
  26. 'sign-day',
  27. {
  28. 'signed': day <= signedDays,
  29. 'today': day === currentDay && !todaySigned,
  30. 'active': day === currentDay && todaySigned
  31. }
  32. ]"
  33. @click="handleSign(day)"
  34. >
  35. <text class="day-label">第{{ day }}天</text>
  36. <text class="reward">+{{ getReward(day) }}金币</text>
  37. </view>
  38. </view>
  39. <text class="tip">已连续签到 {{ signedDays }} 天</text>
  40. </view>
  41. <!-- 合作任务 -->
  42. <PartnerTask />
  43. <!-- 任务中心 -->
  44. <view class="task-center">
  45. <view class="section-header">
  46. <text class="title">每日任务</text>
  47. <text class="more">查看更多</text>
  48. </view>
  49. <view class="task-list">
  50. <view
  51. v-for="task in dailyTasks"
  52. :key="task.id"
  53. class="task-item"
  54. >
  55. <view class="task-info">
  56. <uni-icons :type="task.icon" size="20" :color="task.completed ? '#52c41a' : '#666'"></uni-icons>
  57. <text class="name">{{ task.name }}</text>
  58. </view>
  59. <button
  60. class="action-btn"
  61. :class="{ completed: task.completed }"
  62. @click="completeTask(task)"
  63. >
  64. {{ task.completed ? '已完成' : '+'+task.reward+'金币' }}
  65. </button>
  66. </view>
  67. </view>
  68. </view>
  69. <!-- 外部合作任务 -->
  70. <view class="partner-tasks">
  71. <text class="title">合作任务</text>
  72. <view class="partner-grid">
  73. <view
  74. v-for="partner in partners"
  75. :key="partner.id"
  76. class="partner-item"
  77. @click="goPartnerTask(partner)"
  78. >
  79. <image :src="partner.icon" class="partner-icon" />
  80. <text class="partner-name">{{ partner.name }}</text>
  81. </view>
  82. </view>
  83. </view>
  84. </scroll-view>
  85. </template>
  86. <script setup>
  87. import { ref, onMounted } from 'vue'
  88. import { useSignSystem } from '@/utils/signUtils'
  89. import PartnerTask from '@/components/PartnerTask.vue'
  90. import { useUserStore } from '@/stores/user'
  91. const userStore = useUserStore()
  92. const { signedDays, todaySigned, signRewards, loadSignStatus, doSign } = useSignSystem()
  93. // 用户数据
  94. const userName = ref('哎呀用户')
  95. const userAvatar = ref('/static/avatar/default.png')
  96. const coins = ref(350)
  97. const isVIP = ref(true)
  98. // 每日任务
  99. const dailyTasks = ref([
  100. { id: 1, name: '阅读30分钟', icon: 'eye', reward: 50, completed: false },
  101. { id: 2, name: '分享给好友', icon: 'redo', reward: 30, completed: true },
  102. { id: 3, name: '评论本章节', icon: 'chat', reward: 20, completed: false },
  103. { id: 4, name: '完善个人资料', icon: 'person', reward: 10, completed: false }
  104. ])
  105. // 当前星期几(0-6)
  106. const currentDay = ref(new Date().getDay() + 1)
  107. // 获取每日奖励
  108. const getReward = (day) => {
  109. const reward = signRewards.value.find(r => r.day === day)
  110. return reward ? reward.reward : 10 + day * 5
  111. }
  112. // 合作平台
  113. const partners = ref([
  114. { id: 1, name: '百度地图', icon: '/static/partners/baidu.png', url: 'https://map.baidu.com' },
  115. { id: 2, name: '快手', icon: '/static/partners/kuaishou.png', url: 'https://www.kuaishou.com' },
  116. { id: 3, name: '京东金融', icon: '/static/partners/jd.png', url: 'https://jr.jd.com' },
  117. { id: 4, name: '饿了么', icon: '/static/partners/eleme.png', url: 'https://www.ele.me' }
  118. ])
  119. // 处理签到
  120. const handleSign = async (day) => {
  121. if (day !== currentDay.value) {
  122. uni.showToast({ title: '请先完成今日签到', icon: 'none' })
  123. return
  124. }
  125. if (todaySigned.value) {
  126. uni.showToast({ title: '今日已签到', icon: 'none' })
  127. return
  128. }
  129. const reward = await doSign()
  130. if (reward) {
  131. coins.value += reward
  132. }
  133. }
  134. // 完成任务
  135. const completeTask = (task) => {
  136. if (task.completed) return
  137. task.completed = true
  138. coins.value += task.reward
  139. uni.showToast({ title: `任务完成!获得${task.reward}金币`, icon: 'success' })
  140. }
  141. // 初始化
  142. onMounted(async () => {
  143. await loadSignStatus()
  144. // 加载用户信息
  145. if (userStore.userInfo) {
  146. userName.value = userStore.userInfo.nickname || '哎呀用户'
  147. userAvatar.value = userStore.userInfo.avatar || '/static/avatar/default.png'
  148. coins.value = userStore.userInfo.coins || 0
  149. isVIP.value = userStore.isVIP
  150. }
  151. })
  152. // 跳转合作平台
  153. const goPartnerTask = (partner) => {
  154. uni.navigateTo({
  155. url: `/pages/webview/webview?url=${encodeURIComponent(partner.url)}`
  156. })
  157. }
  158. </script>
  159. <style scoped>
  160. .welfare-page {
  161. height: 100vh;
  162. background-color: var(--bg-color);
  163. padding: 20px;
  164. box-sizing: border-box;
  165. }
  166. .user-header {
  167. display: flex;
  168. align-items: center;
  169. margin-bottom: 25px;
  170. }
  171. .avatar {
  172. width: 60px;
  173. height: 60px;
  174. border-radius: 50%;
  175. margin-right: 15px;
  176. }
  177. .info {
  178. flex: 1;
  179. }
  180. .name {
  181. font-size: 18px;
  182. font-weight: bold;
  183. display: block;
  184. }
  185. .coins {
  186. font-size: 14px;
  187. color: #faad14;
  188. display: block;
  189. margin-top: 5px;
  190. }
  191. .vip-tag {
  192. background: linear-gradient(135deg, #ffd666 0%, #ffc53d 100%);
  193. color: #1a3353;
  194. padding: 4px 10px;
  195. border-radius: 15px;
  196. font-size: 12px;
  197. display: flex;
  198. align-items: center;
  199. }
  200. .sign-card {
  201. background-color: var(--card-bg);
  202. border-radius: 16px;
  203. padding: 20px;
  204. margin-bottom: 20px;
  205. }
  206. .sign-header {
  207. display: flex;
  208. justify-content: space-between;
  209. align-items: center;
  210. margin-bottom: 15px;
  211. }
  212. .title {
  213. font-size: 18px;
  214. font-weight: bold;
  215. }
  216. .subtitle {
  217. font-size: 14px;
  218. color: #666;
  219. }
  220. .sign-calendar {
  221. display: grid;
  222. grid-template-columns: repeat(7, 1fr);
  223. gap: 8px;
  224. }
  225. .sign-day {
  226. border: 1px solid #eee;
  227. border-radius: 8px;
  228. padding: 10px 5px;
  229. text-align: center;
  230. background-color: #fafafa;
  231. }
  232. .sign-day.signed {
  233. background-color: #e6fffb;
  234. border-color: #36cfc9;
  235. }
  236. .sign-day.today {
  237. background-color: #fff7e6;
  238. border-color: #ffc53d;
  239. }
  240. .sign-day.active {
  241. background-color: #fff1b8;
  242. border-color: #ffc53d;
  243. }
  244. .day-label {
  245. font-size: 13px;
  246. display: block;
  247. }
  248. .reward {
  249. font-size: 12px;
  250. color: #faad14;
  251. font-weight: bold;
  252. display: block;
  253. margin-top: 3px;
  254. }
  255. .task-center {
  256. background-color: var(--card-bg);
  257. border-radius: 16px;
  258. padding: 20px;
  259. }
  260. .section-header {
  261. display: flex;
  262. justify-content: space-between;
  263. align-items: center;
  264. margin-bottom: 15px;
  265. }
  266. .more {
  267. font-size: 14px;
  268. color: var(--primary-color);
  269. }
  270. .task-list {
  271. border-top: 1px solid #f0f0f0;
  272. }
  273. .task-item {
  274. display: flex;
  275. justify-content: space-between;
  276. align-items: center;
  277. padding: 15px 0;
  278. border-bottom: 1px solid #f0f0f0;
  279. }
  280. .task-info {
  281. display: flex;
  282. align-items: center;
  283. }
  284. .name {
  285. font-size: 15px;
  286. margin-left: 10px;
  287. }
  288. .action-btn {
  289. background-color: var(--primary-color);
  290. color: white;
  291. border: none;
  292. border-radius: 16px;
  293. height: 30px;
  294. line-height: 30px;
  295. padding: 0 12px;
  296. font-size: 13px;
  297. }
  298. .action-btn.completed {
  299. background-color: #bfbfbf;
  300. }
  301. </style>