index.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. <template>
  2. <view class="wisdom-container">
  3. <!-- Tabbar 切换过渡页 -->
  4. <tab-transition v-if="showTabTransition" dimCode="wisdom" />
  5. <!-- 1. 品牌头部 -->
  6. <PageBanner theme="wisdom"
  7. tagline="学以启智 · 慧及未来"
  8. quote="知者不惑,仁者不忧" />
  9. <!-- 2. 游客专属区块 -->
  10. <template v-if="!isLoggedIn">
  11. <LoginGuideCard
  12. title="登录后查看全家智慧成长数据"
  13. :items="[
  14. '查看全家认知能量数据和测评报告',
  15. '记录每日成长,获取智慧能量',
  16. '参与认知训练,提升综合能力'
  17. ]" />
  18. </template>
  19. <!-- 3. 五维能量条(登录后) -->
  20. <FamilyEnergyBar
  21. v-if="isLoggedIn"
  22. dimensionCode="wisdom"
  23. :sandboxData="sandboxData"
  24. :dualDimension="dualDimension" />
  25. <!-- 4. 认知雷达图(登录后) -->
  26. <view class="section" v-if="isLoggedIn && cognitiveReport">
  27. <view class="section-header">
  28. <text class="section-title">认知雷达</text>
  29. <text class="section-more" @click="goCognitiveReport">查看详情 ›</text>
  30. </view>
  31. <RadarChart
  32. :dimensions="cognitiveDimensions"
  33. :scores="cognitiveScores"
  34. :avg-scores="cognitiveAvgScores"
  35. :childName="activeChildName"
  36. fillColor="#6366F1"
  37. gridColor="#E0E7FF"
  38. labelColor="#3730A3" />
  39. </view>
  40. <!-- 5. 家庭成员关系图谱(登录后) -->
  41. <FamilyRelationGraph
  42. v-if="isLoggedIn && familyMembersVisible.length > 0"
  43. dimensionCode="wisdom"
  44. :selfId="activeChildId"
  45. :members="familyMembersVisible"
  46. :energyMap="energyMapForGraph"
  47. :intimacyMap="intimacyMapForGraph"
  48. @memberTap="goMemberDetail" />
  49. <!-- 6. 用户快捷入口 -->
  50. <UserQuickEntry
  51. v-if="isLoggedIn"
  52. :userName="userName"
  53. roleName="家长"
  54. :currentChildName="activeChildName"
  55. :children="children"
  56. @childChanged="onChildChanged"
  57. @scrollTo="scrollToSection" />
  58. <!-- 7. 功能入口 -->
  59. <view class="func-section" v-if="sectionVisible('func_entries')">
  60. <view class="func-grid">
  61. <view class="func-item" v-for="item in funcList" :key="item.label" @click="onFuncClick(item)">
  62. <view class="func-icon-wrap">
  63. <text class="func-icon">{{ item.icon }}</text>
  64. </view>
  65. <text class="func-label">{{ item.label }}</text>
  66. </view>
  67. </view>
  68. </view>
  69. <!-- 8. 维度任务 -->
  70. <DimensionTasks
  71. v-if="isLoggedIn"
  72. dimensionCode="wisdom"
  73. :tasks="dimensionTasks"
  74. @taskClick="onTaskClick"
  75. @moreTasks="goTasks" />
  76. <!-- 9. 维度活动 -->
  77. <DimensionActivities
  78. dimensionCode="wisdom"
  79. :activities="dimensionActivities"
  80. :isLoggedIn="isLoggedIn"
  81. @activityClick="goActivityDetail"
  82. @moreActivities="goMoreActivities" />
  83. <!-- 10. 维度商品 -->
  84. <DimensionProducts
  85. dimensionCode="wisdom"
  86. :products="dimensionProducts"
  87. @productClick="goProductDetail"
  88. @moreProducts="goMoreProducts" />
  89. <!-- 11. 推荐阅读 -->
  90. <DimensionArticles
  91. v-if="sectionVisible('recommended_reading')"
  92. dimensionCode="wisdom"
  93. :articles="wisdomArticles"
  94. :isLoggedIn="isLoggedIn"
  95. @articleClick="goArticleDetail"
  96. @moreArticles="goMoreArticles" />
  97. <!-- 12. 智慧小贴士 -->
  98. <view class="section" v-if="sectionVisible('wisdom_tips')">
  99. <view class="section-header">
  100. <text class="section-title">智慧小贴士</text>
  101. </view>
  102. <view class="tips-list">
  103. <view class="tip-card" v-for="item in wisdomTips" :key="item.id">
  104. <text class="tip-title">{{ item.title }}</text>
  105. <text class="tip-summary">{{ item.summary }}</text>
  106. </view>
  107. </view>
  108. </view>
  109. <!-- 13. 快捷操作按钮 -->
  110. <view class="section quick-actions" v-if="isLoggedIn">
  111. <view class="action-btn" @click="goCognitiveReport">
  112. <text class="action-icon">📊</text>
  113. <text class="action-text">认知报告</text>
  114. </view>
  115. <view class="action-btn" @click="goTrainingHub">
  116. <text class="action-icon">🧠</text>
  117. <text class="action-text">认知训练</text>
  118. </view>
  119. <view class="action-btn" @click="goAssessment">
  120. <text class="action-icon">📋</text>
  121. <text class="action-text">测评预约</text>
  122. </view>
  123. <view class="action-btn" @click="goHome">
  124. <text class="action-icon">🏠</text>
  125. <text class="action-text">返回首页</text>
  126. </view>
  127. </view>
  128. <!-- ===== 重要关系维护 + 关系健康概览 ===== -->
  129. <FamilyRelationshipSection
  130. :contactList="contactList"
  131. :healthAlerts="healthAlerts"
  132. :milestones="milestones"
  133. :isLoggedIn="isLoggedIn"
  134. @manage="goFamilyMembers" />
  135. <!-- 底部占位 -->
  136. <view class="bottom-spacer"></view>
  137. <AIFloatingAvatar />
  138. </view>
  139. </template>
  140. <script>
  141. import TabTransition from '../../components/tab-transition.vue'
  142. import PageBanner from '../../components/PageBanner.vue'
  143. import LoginGuideCard from '../../components/LoginGuideCard.vue'
  144. import RadarChart from '../../components/RadarChart.vue'
  145. import FamilyEnergyBar from '../../components/FamilyEnergyBar.vue'
  146. import UserQuickEntry from '../../components/UserQuickEntry.vue'
  147. import DimensionTasks from '../../components/DimensionTasks.vue'
  148. import DimensionActivities from '../../components/DimensionActivities.vue'
  149. import DimensionProducts from '../../components/DimensionProducts.vue'
  150. import DimensionArticles from '../../components/DimensionArticles.vue'
  151. import FamilyRelationGraph from '../../components/FamilyRelationGraph.vue'
  152. import AIFloatingAvatar from '../../components/AIFloatingAvatar.vue'
  153. import FamilyRelationshipSection from '../../components/FamilyRelationshipSection.vue'
  154. import { getVisibleSections, getChildren, getTodayTasksByCategory, getActivityList, getProductsByDomain, getFamilyEnergySandbox, getAssessmentLatestResult, getFeaturedArticles, getContactList, getHealthAlerts, getMilestones } from '../../utils/api.js'
  155. export default {
  156. components: { TabTransition, PageBanner, LoginGuideCard, RadarChart, FamilyEnergyBar, UserQuickEntry, DimensionTasks, DimensionActivities, DimensionProducts, DimensionArticles, FamilyRelationGraph, AIFloatingAvatar, FamilyRelationshipSection },
  157. data() {
  158. return {
  159. isLoggedIn: false,
  160. role: null,
  161. showTabTransition: true,
  162. activeChildId: null,
  163. activeChildName: '',
  164. userName: '',
  165. children: [],
  166. familyMembersVisible: [],
  167. sandboxData: null,
  168. dualDimension: null,
  169. visibleSections: [],
  170. cognitiveReport: null,
  171. dimensionTasks: [],
  172. dimensionActivities: [],
  173. dimensionProducts: [],
  174. articles: [],
  175. wisdomTips: [],
  176. /** Mock 平均值(6维认知):感知/专注/记忆/逻辑/空间/加工速度 */
  177. cognitiveAvgScores: [70, 65, 72, 68, 66, 71],
  178. contactList: [],
  179. healthAlerts: [],
  180. milestones: [],
  181. funcList: [
  182. { icon: '\u{1F4CA}', label: '认知报告', needLogin: true, page: '/pages/wisdom-detail/cognitive-report' },
  183. { icon: '\u{270F}\uFE0F', label: '自己出题', needLogin: true, page: '/pages/wisdom-detail/self-quiz' },
  184. { icon: '\u{1F9E0}', label: '训练中心', needLogin: true, page: '/pages/wisdom-detail/training-hub' },
  185. { icon: '\u{1F3AF}', label: '测评预约', needLogin: false, page: '/pages/assessment/apply' },
  186. { icon: '\u{1F4D6}', label: '阅读天地', needLogin: false, page: '/pages/mind/articles' }
  187. ]
  188. }
  189. },
  190. computed: {
  191. energyMapForGraph: function() {
  192. var map = {}
  193. if (this.sandboxData && this.sandboxData.members) {
  194. for (var i = 0; i < this.sandboxData.members.length; i++) {
  195. var m = this.sandboxData.members[i]
  196. map[m.memberId || m.id] = {
  197. bodyScore: m.bodyScore || 0,
  198. mindScore: m.mindScore || 0,
  199. actionScore: m.actionScore || 0,
  200. wisdomScore: m.wisdomScore || 0
  201. }
  202. }
  203. }
  204. return map
  205. },
  206. intimacyMapForGraph: function() {
  207. return {}
  208. },
  209. wisdomArticles: function() {
  210. if (!this.articles || this.articles.length === 0) return []
  211. var result = []
  212. for (var i = 0; i < this.articles.length; i++) {
  213. var a = this.articles[i]
  214. if (a.relatedDimensions && a.relatedDimensions.indexOf('wisdom') !== -1) {
  215. result.push(a)
  216. }
  217. }
  218. if (result.length === 0) return this.articles.slice(0, 5)
  219. return result.slice(0, 5)
  220. },
  221. cognitiveDimensions: function() {
  222. return [
  223. { label: '感知能力', key: 'perceptionScore' },
  224. { label: '专注力', key: 'focusScore' },
  225. { label: '记忆力', key: 'memoryScore' },
  226. { label: '逻辑思维', key: 'logicScore' },
  227. { label: '空间思维', key: 'spatialScore' },
  228. { label: '加工速度', key: 'processingSpeedScore' }
  229. ]
  230. },
  231. cognitiveScores: function() {
  232. if (!this.cognitiveReport) return []
  233. var dims = this.cognitiveDimensions
  234. var scores = []
  235. for (var i = 0; i < dims.length; i++) {
  236. scores.push(this.cognitiveReport[dims[i].key] || 0)
  237. }
  238. return scores
  239. }
  240. },
  241. onShow() {
  242. this.showTabTransition = true
  243. var token = uni.getStorageSync('token')
  244. this.isLoggedIn = !!token
  245. if (this.isLoggedIn) {
  246. this.role = uni.getStorageSync('currentRole') || uni.getStorageSync('role') || null
  247. this.userName = uni.getStorageSync('nickname') || uni.getStorageSync('userName') || '家长'
  248. }
  249. this.loadSectionConfig()
  250. if (this.isLoggedIn) {
  251. this.loadChildren()
  252. this.loadFamilyMembersVisible()
  253. this.loadCognitiveReport()
  254. this.loadRelationshipHealth()
  255. }
  256. this.loadDimensionActivities()
  257. this.loadDimensionProducts()
  258. // 游客也能浏览文章
  259. this.loadFeaturedArticles()
  260. this._watchPageReady()
  261. },
  262. methods: {
  263. loadSectionConfig: function() {
  264. var baseSections = ['func_entries', 'wisdom_tips', 'recommended_reading']
  265. if (!uni.getStorageSync('token')) {
  266. this.visibleSections = baseSections
  267. return
  268. }
  269. var role = uni.getStorageSync('currentRole') || uni.getStorageSync('role') || null
  270. var self = this
  271. getVisibleSections({ pageKey: 'wisdom', role: role }).then(function(res) {
  272. if (res.code === 200 && res.data) {
  273. var keys = res.data.map(function(s) { return s.sectionKey })
  274. var merged = baseSections.slice()
  275. keys.forEach(function(k) { if (merged.indexOf(k) === -1) merged.push(k) })
  276. self.visibleSections = merged
  277. }
  278. }).catch(function(e) {
  279. self.visibleSections = ['func_entries', 'wisdom_tips']
  280. })
  281. },
  282. loadChildren: function() {
  283. var self = this
  284. getChildren().then(function(res) {
  285. if (res.code === 200 && res.data) {
  286. self.children = res.data
  287. if (self.children.length > 0) {
  288. var activeId = uni.getStorageSync('currentChildId')
  289. if (activeId) {
  290. for (var i = 0; i < self.children.length; i++) {
  291. if (self.children[i].id == activeId) {
  292. self.activeChildId = activeId
  293. self.activeChildName = self.children[i].nickname || self.children[i].name || ''
  294. break
  295. }
  296. }
  297. }
  298. if (!self.activeChildId) {
  299. self.activeChildId = self.children[0].id
  300. self.activeChildName = self.children[0].nickname || self.children[0].name || ''
  301. uni.setStorageSync('currentChildId', self.activeChildId)
  302. }
  303. }
  304. // Load cognitive report AFTER activeChildId is confirmed set
  305. self.loadCognitiveReport()
  306. }
  307. self.loadContacts()
  308. }).catch(function(e) {})
  309. },
  310. loadFamilyMembersVisible: function() {
  311. var self = this
  312. getFamilyEnergySandbox().then(function(res) {
  313. if (res && res.data) {
  314. self.sandboxData = res.data.sandboxData || null
  315. self.dualDimension = res.data.dualDimension || null
  316. if (res.data.members) {
  317. self.familyMembersVisible = res.data.members
  318. }
  319. }
  320. }).catch(function(e) {})
  321. },
  322. loadCognitiveReport: function() {
  323. var self = this
  324. var childId = this.activeChildId
  325. if (!childId) return
  326. getAssessmentLatestResult(childId).then(function(res) {
  327. if (res.code === 200 && res.data) {
  328. self.cognitiveReport = res.data
  329. }
  330. }).catch(function(e) {})
  331. },
  332. onChildChanged: function(childId) {
  333. this.activeChildId = childId
  334. uni.setStorageSync('currentChildId', childId)
  335. for (var i = 0; i < this.children.length; i++) {
  336. if (this.children[i].id == childId) {
  337. this.activeChildName = this.children[i].nickname || this.children[i].name || ''
  338. break
  339. }
  340. }
  341. this.loadFamilyMembersVisible()
  342. this.loadCognitiveReport()
  343. },
  344. loadDimensionTasks: function() {
  345. var self = this
  346. var childId = this.activeChildId
  347. if (!childId) return
  348. getTodayTasksByCategory(childId, 'wisdom').then(function(res) {
  349. if (res && res.data) {
  350. self.dimensionTasks = res.data.slice(0, 5)
  351. }
  352. }).catch(function(e) {})
  353. },
  354. loadDimensionActivities: function() {
  355. var self = this
  356. getActivityList({ dimensionCode: 'wisdom', page: 1, size: 5 }).then(function(res) {
  357. if (res && res.data) {
  358. self.dimensionActivities = res.data.records || res.data
  359. }
  360. }).catch(function(e) {})
  361. },
  362. loadDimensionProducts: function() {
  363. var self = this
  364. getProductsByDomain('wisdom', 1, 4).then(function(res) {
  365. if (res && res.data) {
  366. self.dimensionProducts = res.data.records || res.data
  367. }
  368. }).catch(function(e) {})
  369. },
  370. sectionVisible: function(key) {
  371. return this.visibleSections.length === 0 || this.visibleSections.indexOf(key) !== -1
  372. },
  373. onFuncClick: function(item) {
  374. if (item.needLogin && !this.isLoggedIn) {
  375. uni.showModal({
  376. title: '提示',
  377. content: '请先登录后使用此功能',
  378. success: function(res) { if (res.confirm) uni.navigateTo({ url: '/pages/login/login' }) }
  379. })
  380. return
  381. }
  382. if (item.page) {
  383. var nativeTabs = ['/pages/tasks/tasks', '/pages/index/index', '/pages/body/index', '/pages/mind/index', '/pages/action/index', '/pages/wisdom/index', '/pages/profile/profile']
  384. if (nativeTabs.indexOf(item.page) !== -1) {
  385. uni.switchTab({ url: item.page })
  386. } else {
  387. uni.navigateTo({ url: item.page })
  388. }
  389. }
  390. },
  391. scrollToSection: function(section) {},
  392. goMemberDetail: function(memberId) {
  393. uni.navigateTo({ url: '/pages/member-detail/member-detail?memberId=' + memberId + '&entrySource=relation-graph&dimensionCode=wisdom' })
  394. },
  395. goFamilyMembers: function() {
  396. uni.navigateTo({ url: '/pages/profile/family-members' })
  397. },
  398. goCognitiveReport: function() {
  399. uni.navigateTo({ url: '/pages/wisdom-detail/cognitive-report' })
  400. },
  401. goSelfQuiz: function() {
  402. uni.navigateTo({ url: '/pages/wisdom-detail/self-quiz' })
  403. },
  404. goTrainingHub: function() {
  405. uni.navigateTo({ url: '/pages/wisdom-detail/training-hub' })
  406. },
  407. goAssessment: function() {
  408. uni.navigateTo({ url: '/pages/assessment/apply' })
  409. },
  410. goHome: function() {
  411. uni.switchTab({ url: '/pages/index/index' })
  412. },
  413. onTaskClick: function(task) {},
  414. goTasks: function() { uni.switchTab({ url: '/pages/tasks/tasks' }) },
  415. goActivityDetail: function(id) {},
  416. goMoreActivities: function() {
  417. uni.navigateTo({ url: '/pages/activity/index' })
  418. },
  419. goActivityDetail: function(act) {
  420. if (!act || !act.id) return
  421. uni.navigateTo({ url: '/pages/discover-detail/activity-detail/activity-detail?id=' + act.id })
  422. },
  423. goProductDetail: function(prod) {
  424. if (prod && prod.id) {
  425. var token = uni.getStorageSync('token')
  426. if (token) {
  427. uni.navigateTo({ url: '/pages/discover-detail/product-detail/product-detail?id=' + prod.id })
  428. } else {
  429. uni.navigateTo({ url: '/pages/login/login?redirect=' + encodeURIComponent('/pages/wisdom/index') })
  430. }
  431. }
  432. },
  433. goMoreProducts: function() {
  434. uni.navigateTo({ url: '/pages/shop/index' })
  435. },
  436. parseRelatedDimensions: function(val) {
  437. if (!val) return []
  438. if (Array.isArray(val)) return val
  439. if (typeof val === 'string') {
  440. try {
  441. var parsed = JSON.parse(val)
  442. return Array.isArray(parsed) ? parsed : []
  443. } catch (e) {
  444. return val.split(',').map(function(s) { return s.trim() }).filter(function(s) { return s })
  445. }
  446. }
  447. return []
  448. },
  449. loadFeaturedArticles: function() {
  450. var self = this
  451. getFeaturedArticles({ size: 5, dimensionCode: 'wisdom' }).then(function(res) {
  452. if (res.code === 200 && res.data) {
  453. var gradientColors = [
  454. 'linear-gradient(135deg, #6366F1, #818CF8)',
  455. 'linear-gradient(135deg, #8B5CF6, #A78BFA)',
  456. 'linear-gradient(135deg, #5B9BD5, #8FC5E8)',
  457. 'linear-gradient(135deg, #10B981, #34D399)',
  458. 'linear-gradient(135deg, #F97316, #FB923C)'
  459. ]
  460. var list = Array.isArray(res.data) ? res.data : (res.data.records || [])
  461. self.articles = list.map(function(item, index) {
  462. return {
  463. id: item.id,
  464. category: item.categoryName || '智慧文章',
  465. categoryColor: gradientColors[index % gradientColors.length],
  466. title: item.title || '',
  467. summary: item.summary || '',
  468. views: item.viewCount ? String(item.viewCount) : '0',
  469. likes: '0',
  470. date: item.publishedAt ? item.publishedAt.slice(0, 10) : '',
  471. relatedDimensions: self.parseRelatedDimensions(item.relatedDimensions)
  472. }
  473. })
  474. }
  475. }).catch(function() {})
  476. },
  477. goMoreArticles: function() {
  478. uni.navigateTo({ url: '/pages/article-center/index?dimension=wisdom' })
  479. },
  480. goArticleDetail: function(article) {
  481. uni.navigateTo({ url: '/pages/mind-detail/article-detail?id=' + (article.id || article) })
  482. },
  483. // ===== 重要关系 =====
  484. loadContacts: function() {
  485. var self = this
  486. getContactList({}).then(function(res) {
  487. if (res.code === 200 && res.data) {
  488. self.contactList = Array.isArray(res.data) ? res.data : []
  489. }
  490. }).catch(function(e) {
  491. console.log('获取联系人失败', e)
  492. })
  493. },
  494. loadRelationshipHealth: function() {
  495. var self = this
  496. getHealthAlerts({}).then(function(res) {
  497. if (res.code === 200 && res.data) {
  498. self.healthAlerts = Array.isArray(res.data) ? res.data : []
  499. }
  500. }).catch(function() {
  501. self.healthAlerts = []
  502. })
  503. getMilestones({}, 30).then(function(res) {
  504. if (res.code === 200 && res.data) {
  505. self.milestones = Array.isArray(res.data) ? res.data : []
  506. }
  507. }).catch(function() {
  508. self.milestones = []
  509. })
  510. },
  511. onContactClick: function(item) {
  512. uni.navigateTo({ url: '/pages/wisdom-detail/contact-detail?id=' + item.id })
  513. },
  514. onShowImport: function() {
  515. uni.showToast({ title: '导入通讯录', icon: 'none' })
  516. },
  517. goInteractionLog: function(memberId) {
  518. if (memberId) {
  519. uni.navigateTo({ url: '/pages/wisdom-detail/interaction-log?memberId=' + memberId })
  520. } else {
  521. uni.navigateTo({ url: '/pages/wisdom-detail/interaction-log' })
  522. }
  523. },
  524. goRelationshipQuestionnaire: function() {
  525. uni.navigateTo({ url: '/pages/wisdom-detail/relationship-questionnaire' })
  526. },
  527. _watchPageReady() {
  528. var self = this
  529. var unwatch = this.$watch(function() {
  530. if (self.isLoggedIn) {
  531. return !!(self.cognitiveReport || self.energyOverview)
  532. }
  533. return !!(self.dimensionActivities && self.dimensionActivities.length > 0) ||
  534. !!(self.dimensionProducts && self.dimensionProducts.length > 0)
  535. }, function(val) {
  536. if (val) {
  537. if (unwatch) unwatch()
  538. self.showTabTransition = false
  539. }
  540. })
  541. setTimeout(function() {
  542. if (unwatch) unwatch()
  543. self.showTabTransition = false
  544. }, 5000)
  545. }
  546. }
  547. }
  548. </script>
  549. <style scoped>
  550. .wisdom-container {
  551. min-height: 100vh;
  552. background: #f5f7fa;
  553. padding-bottom: 120rpx;
  554. }
  555. .func-section {
  556. margin: -40rpx 20rpx 0;
  557. position: relative;
  558. z-index: 2;
  559. }
  560. .func-grid {
  561. background: #fff;
  562. border-radius: 24rpx;
  563. padding: 30rpx 16rpx;
  564. display: flex;
  565. box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.06);
  566. }
  567. .func-item {
  568. flex: 1;
  569. display: flex;
  570. flex-direction: column;
  571. align-items: center;
  572. }
  573. .func-item:active {
  574. opacity: 0.7;
  575. }
  576. .func-icon-wrap {
  577. width: 88rpx;
  578. height: 88rpx;
  579. border-radius: 50%;
  580. background: #FFF8E1;
  581. display: flex;
  582. align-items: center;
  583. justify-content: center;
  584. margin-bottom: 10rpx;
  585. }
  586. .func-icon {
  587. font-size: 40rpx;
  588. }
  589. .func-label {
  590. font-size: 24rpx;
  591. color: #333;
  592. font-weight: 500;
  593. }
  594. /* ===== Section ===== */
  595. .section {
  596. margin: 20rpx 20rpx;
  597. }
  598. .section-header {
  599. display: flex;
  600. justify-content: space-between;
  601. align-items: center;
  602. margin-bottom: 20rpx;
  603. }
  604. .section-title {
  605. font-size: 30rpx;
  606. font-weight: bold;
  607. color: #333;
  608. }
  609. .section-more {
  610. font-size: 24rpx;
  611. color: #999;
  612. }
  613. /* ===== 智慧小贴士 ===== */
  614. .tips-list {
  615. display: flex;
  616. flex-direction: column;
  617. }
  618. .tip-card {
  619. background: #fff;
  620. border-radius: 16rpx;
  621. padding: 24rpx 20rpx;
  622. box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
  623. margin-bottom: 16rpx;
  624. }
  625. .tip-title {
  626. font-size: 28rpx;
  627. font-weight: bold;
  628. color: #333;
  629. display: block;
  630. margin-bottom: 8rpx;
  631. }
  632. .tip-summary {
  633. font-size: 24rpx;
  634. color: #888;
  635. line-height: 1.5;
  636. display: block;
  637. }
  638. /* ===== 快捷操作按钮 ===== */
  639. .quick-actions {
  640. display: flex;
  641. flex-direction: row;
  642. flex-wrap: wrap;
  643. justify-content: space-between;
  644. }
  645. .action-btn {
  646. width: 48%;
  647. background: #fff;
  648. border-radius: 16rpx;
  649. padding: 24rpx 0;
  650. box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
  651. display: flex;
  652. flex-direction: column;
  653. align-items: center;
  654. margin-bottom: 20rpx;
  655. }
  656. .action-btn:active {
  657. opacity: 0.8;
  658. }
  659. .action-icon {
  660. font-size: 40rpx;
  661. margin-bottom: 10rpx;
  662. }
  663. .action-text {
  664. font-size: 26rpx;
  665. color: #333;
  666. font-weight: 500;
  667. }
  668. /* ===== 底部占位 ===== */
  669. .bottom-spacer {
  670. height: 120rpx;
  671. }
  672. </style>