knowledge-page-layout.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. <template>
  2. <z-paging ref="paging" v-model="list" @query="handleQuery" @on-refresh="handleRefresh">
  3. <template #top>
  4. <mx-index-menus :columns="subjectMenus.length" :data="subjectMenus" :rows="1"
  5. class="!mx-0 !rounded-none" custom-action container-wrap-class="px-10 py-20"
  6. icon-size="36" title-class="text-content text-xs" @click="handleMenuClick"/>
  7. </template>
  8. <view v-if="list.length" class="p-30">
  9. <tree-view :tree-data="list">
  10. <template #command="{node}">
  11. <uv-button v-if="empty(node.children)" type="primary" shape="circle" text="开始练习"
  12. plain :custom-style="{height: '32px'}" @click="handleLeafClick(node)"/>
  13. </template>
  14. </tree-view>
  15. </view>
  16. </z-paging>
  17. </template>
  18. <script setup>
  19. import {ref, watchEffect} from 'vue'
  20. import _ from "lodash";
  21. import {useUserStorePageFilter} from "@/hooks/useUserStorePageFilter";
  22. import {empty} from "@/uni_modules/uv-ui-tools/libs/function/test";
  23. import {useTransfer} from "@/hooks/useTransfer";
  24. import TreeView from "@/pages/topic-center/index/components/tree-view.vue";
  25. import {useCacheStore} from "@/hooks/useCacheStore";
  26. import {cacheActions} from "@/hooks/defineCacheActions";
  27. const props = defineProps({
  28. subject: {
  29. type: Object,
  30. default: () => ({})
  31. }
  32. })
  33. const {transferTo} = useTransfer()
  34. const {dispatchCache, removeCache} = useCacheStore()
  35. const paging = ref(null)
  36. const list = ref([])
  37. const {menus} = useUserStorePageFilter("TopicCenter")
  38. const subjectMenus = ref([])
  39. const getSubjectMenus = function (subject) {
  40. return menus.value.filter(m => {
  41. const includeSatisfied = () => m.includeSubjects.includes(subject.subjectName)
  42. const excludeSatisfied = () => !m.excludeSubjects.includes(subject.subjectName)
  43. if (empty(m.includeSubjects) && empty(m.excludeSubjects)) return true
  44. if (m.includeSubjects?.length && m.excludeSubjects?.length) {
  45. const intersect = _.intersection(m.includeSubjects, m.excludeSubjects)
  46. if (intersect.length) throw new Error('conflicting subject: ' + intersect.join(','))
  47. return includeSatisfied() && excludeSatisfied()
  48. }
  49. if (m.includeSubjects?.length) return includeSatisfied()
  50. if (m.excludeSubjects?.length) return excludeSatisfied()
  51. })
  52. }
  53. const handleQuery = async () => {
  54. const {subjectId} = props.subject
  55. try {
  56. const data = await dispatchCache(cacheActions.getKnowledgeTree, {subjectId})
  57. data.forEach(k => k.expanded = false) // 默认收起,因为有缓存,防止用户之前打开过多引起渲染缓慢
  58. paging.value.completeByTotal(data, data.length)
  59. } catch {
  60. paging.value.complete(false)
  61. }
  62. }
  63. const handleRefresh = () => {
  64. const {subjectId} = props.subject
  65. removeCache(cacheActions.getKnowledgeTree, {subjectId})
  66. }
  67. const handleMenuClick = (menu) => {
  68. if (!menu.path) return
  69. transferTo(menu.path, menu.nextData, props.subject)
  70. }
  71. const handleLeafClick = (node) => {
  72. const next = {
  73. type: 1,
  74. knowledgeId: node.id,
  75. testType: 0,
  76. title: '知识点练习'
  77. }
  78. transferTo('/pages/topic-center/paper-exam/paper-exam', next)
  79. }
  80. // hooks
  81. // NOTE:因为dispatchCache要固化getSubjectMenus,所以调用要放在methods定义之后
  82. // NOTE:另外缓存需要用参数区隔,所以这里将prop.subject定义成了参数,否则,几个tabs会命中同一缓存,因为他们调用了相同的方法
  83. // NOTE:直接使用dispatchCache(action[Function]...)时特别要注意通过payload区分缓存结果!
  84. watchEffect(async () => subjectMenus.value = await dispatchCache(getSubjectMenus, props.subject))
  85. </script>
  86. <style scoped>
  87. </style>