Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

206 строки
4.7 KiB

  1. <template>
  2. <view class="page">
  3. <!-- 顶部横幅 -->
  4. <image class="banner" src="https://cdn.csybhelp.com/images/cytx/index-bg.png" mode="widthFix" />
  5. <!-- 正文内容区域 -->
  6. <view class="content-area">
  7. <view v-if="content" class="letter">
  8. <view class="body">
  9. <mp-html :content="content" />
  10. </view>
  11. </view>
  12. <view v-else-if="!loaded" class="loading-text">加载中...</view>
  13. <button class="join-btn" :class="btnClass" @tap="handleJoin">{{ btnText }}</button>
  14. </view>
  15. </view>
  16. </template>
  17. <script setup>
  18. import { ref, computed } from 'vue'
  19. import { onShow } from '@dcloudio/uni-app'
  20. import { get } from '@/utils/request.js'
  21. import { getToken, getUserInfo, setUserInfo } from '@/utils/cache.js'
  22. import mpHtml from '@/uni_modules/mp-html/components/mp-html/mp-html.vue'
  23. const CONTENT_CACHE_KEY = 'cytx-index-content'
  24. const content = ref('')
  25. const loaded = ref(false)
  26. const userInfo = ref(null)
  27. const isLoggedIn = ref(false)
  28. // 患者状态
  29. const patient = computed(() => userInfo.value?.patient || null)
  30. const isAuthed = computed(() => patient.value?.auth_status === 1)
  31. const patientStatus = computed(() => patient.value?.status ?? null)
  32. // 按钮文案和样式
  33. const btnText = computed(() => {
  34. if (!isLoggedIn.value) return '加入项目'
  35. if (!isAuthed.value) return '加入项目'
  36. if (patientStatus.value === null || patientStatus.value === undefined) return '加入项目'
  37. if (patientStatus.value === -1) return '加入项目'
  38. if (patientStatus.value === 1) return '已加入'
  39. if (patientStatus.value === 0) return '已申请,审核中'
  40. if (patientStatus.value === 2) return '已拒绝,重新申请'
  41. return '加入项目'
  42. })
  43. const btnClass = computed(() => {
  44. if (!isLoggedIn.value || !isAuthed.value) return ''
  45. if (patientStatus.value === 1) return 'joined'
  46. if (patientStatus.value === 0) return 'pending'
  47. if (patientStatus.value === 2) return 'rejected'
  48. return ''
  49. })
  50. const loadContent = async () => {
  51. // 先读缓存
  52. try {
  53. const cached = uni.getStorageSync(CONTENT_CACHE_KEY)
  54. if (cached) content.value = cached
  55. } catch (e) {}
  56. // 再请求最新
  57. try {
  58. const res = await get('/api/content', { key: 'index_content' })
  59. if (res.data && res.data.content) {
  60. content.value = res.data.content
  61. uni.setStorageSync(CONTENT_CACHE_KEY, res.data.content)
  62. }
  63. } catch (e) {
  64. console.error('获取首页内容失败', e)
  65. } finally {
  66. loaded.value = true
  67. }
  68. }
  69. const refreshUserState = async () => {
  70. isLoggedIn.value = !!getToken()
  71. userInfo.value = getUserInfo()
  72. if (isLoggedIn.value) {
  73. try {
  74. const res = await get('/api/mp/userinfo')
  75. userInfo.value = res.data
  76. setUserInfo(res.data)
  77. } catch (e) {}
  78. }
  79. }
  80. const handleJoin = () => {
  81. // 未登录 -> 去登录
  82. if (!isLoggedIn.value) {
  83. uni.navigateTo({ url: '/pages/login/index' })
  84. return
  85. }
  86. // 未实名 -> 提示去认证
  87. if (!isAuthed.value) {
  88. uni.showModal({
  89. title: '提示',
  90. content: '请先完成实名认证',
  91. confirmText: '去认证',
  92. success: (res) => {
  93. if (res.confirm) uni.navigateTo({ url: '/pages/verify/verify' })
  94. }
  95. })
  96. return
  97. }
  98. // 审核通过 -> 跳转到个人中心
  99. if (patientStatus.value === 1) {
  100. uni.switchTab({ url: '/pages/profile/profile' })
  101. return
  102. }
  103. // 待审核 -> 跳转到个人中心
  104. if (patientStatus.value === 0) {
  105. uni.switchTab({ url: '/pages/profile/profile' })
  106. return
  107. }
  108. // 已拒绝 -> 跳转资料页重新提交
  109. if (patientStatus.value === 2) {
  110. uni.navigateTo({ url: '/pages/myinfo/myinfo' })
  111. return
  112. }
  113. // 已实名但未提交资料(status=-1)-> 去提交资料
  114. uni.navigateTo({ url: '/pages/myinfo/myinfo' })
  115. }
  116. onShow(() => {
  117. if (!loaded.value) loadContent()
  118. refreshUserState()
  119. })
  120. </script>
  121. <style lang="scss" scoped>
  122. .page {
  123. min-height: 100vh;
  124. background: #f0f0f0;
  125. padding-bottom: 20rpx;
  126. }
  127. .banner {
  128. width: 100%;
  129. display: block;
  130. }
  131. .content-area {
  132. background: #fff;
  133. border-radius: 24rpx;
  134. margin: -30% 24rpx 0;
  135. position: relative;
  136. z-index: 1;
  137. padding: 56rpx 40rpx 32rpx;
  138. }
  139. .letter {
  140. .body {
  141. font-size: 28rpx;
  142. color: #606266;
  143. line-height: 2;
  144. text-align: justify;
  145. }
  146. }
  147. .loading-text {
  148. text-align: center;
  149. color: #909399;
  150. padding: 40rpx 0;
  151. }
  152. .join-btn {
  153. display: block;
  154. width: 100%;
  155. margin: 56rpx 0 0;
  156. height: 88rpx;
  157. line-height: 88rpx;
  158. background: linear-gradient(135deg, #1890ff, #096dd9);
  159. color: #fff;
  160. border: none;
  161. border-radius: 44rpx;
  162. font-size: 32rpx;
  163. font-weight: 500;
  164. letter-spacing: 4rpx;
  165. padding: 0;
  166. &::after {
  167. border: none;
  168. }
  169. &.joined {
  170. background: linear-gradient(135deg, #52c41a, #389e0d);
  171. color: #fff;
  172. letter-spacing: 2rpx;
  173. }
  174. &.pending {
  175. background: linear-gradient(135deg, #faad14, #d48806);
  176. letter-spacing: 2rpx;
  177. }
  178. &.rejected {
  179. background: linear-gradient(135deg, #ff4d4f, #cf1322);
  180. letter-spacing: 2rpx;
  181. }
  182. }
  183. </style>