OnboardingGuide.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. <template>
  2. <view class="onboarding-overlay" v-if="show">
  3. <view class="onboarding-card">
  4. <!-- 顶部品牌条 -->
  5. <view class="onboarding-topbar"></view>
  6. <!-- 步骤内容 -->
  7. <view class="onboarding-content" :key="currentStep" :class="{ 'onboarding-content--intro': steps[currentStep].isIntro }">
  8. <text class="onboarding-icon">{{ steps[currentStep].icon }}</text>
  9. <text class="onboarding-title" :class="{ 'onboarding-title--intro': steps[currentStep].isIntro }">{{ steps[currentStep].title }}</text>
  10. <text class="onboarding-desc">{{ steps[currentStep].desc }}</text>
  11. </view>
  12. <!-- 步进器 -->
  13. <view class="onboarding-dots">
  14. <view
  15. v-for="(s, i) in steps"
  16. :key="i"
  17. class="dot"
  18. :class="{ active: i === currentStep }">
  19. </view>
  20. </view>
  21. <!-- 按钮 -->
  22. <view class="onboarding-action">
  23. <view
  24. class="onboarding-btn"
  25. :class="{ 'onboarding-btn--last': currentStep === steps.length - 1 }"
  26. @click="handleNext">
  27. <text>{{ currentStep < steps.length - 1 ? '下一步' : '开始体验!' }}</text>
  28. </view>
  29. </view>
  30. </view>
  31. </view>
  32. </template>
  33. <script>
  34. var PARENT_STEPS = [
  35. {
  36. icon: '🔍',
  37. title: '你真的了解孩子的状态吗?',
  38. desc: '情绪低落没察觉、习惯变化没注意、能力短板没发现——很多问题等爆发了才看见。浠艾福帮你在问题发生前,看清孩子真实的身心状态。',
  39. isIntro: true
  40. },
  41. {
  42. icon: '🌏',
  43. title: '五维沙盘,看见全家',
  44. desc: '身·心·智·行·富,一张全景图看清每个维度。孩子身体好不好、情绪怎么样、能力到哪了——不用猜,看得见。'
  45. },
  46. {
  47. icon: '📋',
  48. title: '小任务,大改变',
  49. desc: '布置每日小任务,完成就能攒星星。每天一点点积累,好习惯自然养成。'
  50. },
  51. {
  52. icon: '🎁',
  53. title: '心愿墙,看得见努力',
  54. desc: '孩子攒够星星就能兑换心愿。努力有回报,目标感和坚持力一起培养。'
  55. }
  56. ]
  57. var CHILD_STEPS = [
  58. {
  59. icon: '🔍',
  60. title: '你的每一点成长,都被看见',
  61. desc: '今天完成了几个任务?比昨天进步了多少?浠艾福帮你记录每一点努力,让成长看得见。',
  62. isIntro: true
  63. },
  64. {
  65. icon: '🌟',
  66. title: '赚星星',
  67. desc: '完成爸爸妈妈布置的任务,就能获得星星积分,越努力越多!'
  68. },
  69. {
  70. icon: '🎮',
  71. title: '玩中学',
  72. desc: '完成任务后可以玩小游戏、兑换心愿,学习和快乐两不误!'
  73. },
  74. {
  75. icon: '🏆',
  76. title: '升级挑战',
  77. desc: '从星星宝宝到宇宙小英雄,一步步升级,看看你能走多远!'
  78. }
  79. ]
  80. export default {
  81. name: 'OnboardingGuide',
  82. props: {
  83. role: { type: String, default: 'parent' },
  84. show: { type: Boolean, default: false }
  85. },
  86. data() {
  87. return {
  88. currentStep: 0
  89. }
  90. },
  91. computed: {
  92. steps() {
  93. if (this.role === 'child') return CHILD_STEPS
  94. return PARENT_STEPS
  95. }
  96. },
  97. watch: {
  98. show(val) {
  99. if (val) {
  100. this.currentStep = 0
  101. }
  102. }
  103. },
  104. methods: {
  105. handleNext() {
  106. if (this.currentStep < this.steps.length - 1) {
  107. this.currentStep++
  108. } else {
  109. uni.setStorageSync('_onboardingDone', true)
  110. this.$emit('close')
  111. }
  112. }
  113. }
  114. }
  115. </script>
  116. <style scoped>
  117. /* ============================================================
  118. OnboardingGuide — 首次登录引导浮层
  119. 设计体系:统一使用 uni.scss design tokens
  120. ============================================================ */
  121. .onboarding-overlay {
  122. position: fixed;
  123. top: 0;
  124. left: 0;
  125. width: 100%;
  126. height: 100%;
  127. background: rgba(0, 0, 0, 0.5);
  128. display: flex;
  129. align-items: center;
  130. justify-content: center;
  131. z-index: 9998;
  132. animation: fadeIn 0.25s ease;
  133. }
  134. .onboarding-card {
  135. width: 640rpx;
  136. min-height: 680rpx;
  137. background: var(--surface, #FFFFFF);
  138. border-radius: var(--radius-xl, 32rpx);
  139. display: flex;
  140. flex-direction: column;
  141. align-items: center;
  142. overflow: hidden;
  143. box-shadow: var(--shadow-lg, 0 8rpx 32rpx rgba(91, 155, 213, 0.10));
  144. animation: scaleIn 0.3s cubic-bezier(0.16, 1, 0.3, 1);
  145. }
  146. /* 顶部品牌装饰条 — 暖珊瑚色 */
  147. .onboarding-topbar {
  148. width: 100%;
  149. height: 12rpx;
  150. background: var(--color-primary, #F97316);
  151. flex-shrink: 0;
  152. }
  153. /* ============================================================
  154. 内容区 — flex 居中,带淡入动画
  155. ============================================================ */
  156. .onboarding-content {
  157. flex: 1;
  158. display: flex;
  159. flex-direction: column;
  160. align-items: center;
  161. justify-content: center;
  162. padding: 80rpx 56rpx 48rpx;
  163. animation: fadeIn 0.3s ease;
  164. }
  165. .onboarding-icon {
  166. font-size: 80rpx;
  167. margin-bottom: 32rpx;
  168. display: block;
  169. }
  170. .onboarding-title {
  171. font-size: 36rpx;
  172. font-weight: 700;
  173. color: var(--text, #1E293B);
  174. text-align: center;
  175. margin-bottom: 20rpx;
  176. display: block;
  177. line-height: 1.3;
  178. }
  179. .onboarding-desc {
  180. font-size: 28rpx;
  181. color: var(--text-secondary, #64748B);
  182. text-align: center;
  183. line-height: 1.6;
  184. display: block;
  185. padding: 0 16rpx;
  186. }
  187. /* ============================================================
  188. 介绍步骤 — 开场身份定义页
  189. ============================================================ */
  190. .onboarding-content--intro {
  191. padding: 64rpx 56rpx 48rpx;
  192. }
  193. .onboarding-title--intro {
  194. font-size: 32rpx;
  195. font-weight: 800;
  196. color: var(--color-primary, #F97316);
  197. line-height: 1.4;
  198. }
  199. /* ============================================================
  200. 步进器圆点
  201. ============================================================ */
  202. .onboarding-dots {
  203. display: flex;
  204. align-items: center;
  205. justify-content: center;
  206. gap: 16rpx;
  207. padding: 0 56rpx 40rpx;
  208. flex-shrink: 0;
  209. }
  210. .dot {
  211. width: 14rpx;
  212. height: 14rpx;
  213. border-radius: 50%;
  214. background: var(--border, #CBD5E1);
  215. transition: background 0.3s ease, transform 0.3s ease;
  216. }
  217. .dot.active {
  218. background: var(--color-primary, #F97316);
  219. transform: scale(1.3);
  220. }
  221. /* ============================================================
  222. 底部按钮
  223. ============================================================ */
  224. .onboarding-action {
  225. width: 100%;
  226. padding: 0 56rpx 48rpx;
  227. flex-shrink: 0;
  228. box-sizing: border-box;
  229. }
  230. .onboarding-btn {
  231. width: 100%;
  232. height: 88rpx;
  233. border-radius: 999rpx;
  234. background: var(--color-primary, #5B9BD5);
  235. color: #FFFFFF;
  236. font-size: 32rpx;
  237. font-weight: 700;
  238. display: flex;
  239. align-items: center;
  240. justify-content: center;
  241. transition: opacity 0.2s ease, transform 0.15s ease;
  242. box-shadow: 0 4rpx 16rpx rgba(91, 155, 213, 0.25);
  243. }
  244. .onboarding-btn:active {
  245. opacity: 0.85;
  246. transform: scale(0.97);
  247. }
  248. /* 最后一步:暖珊瑚色按钮 */
  249. .onboarding-btn--last {
  250. background: var(--color-primary, #F97316);
  251. box-shadow: 0 4rpx 16rpx rgba(249, 115, 22, 0.30);
  252. }
  253. </style>