Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 

263 rader
6.1 KiB

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