|
@@ -0,0 +1,206 @@
|
|
|
|
|
+<script setup lang='ts'>
|
|
|
|
|
+import Back from '@/components/back.uvue'
|
|
|
|
|
+import Loading from '@/components/loading.uvue'
|
|
|
|
|
+import { ref, onMounted, nextTick } from 'vue'
|
|
|
|
|
+import { type SubjectKnowledgeCardResult, getSubjectKnowledgeCard } from '@/services/subject/card'
|
|
|
|
|
+import { fetchSubjectConfigInfo } from '@/services/subject/info'
|
|
|
|
|
+import type { SubjectCatalogResult } from '@/services/subject/catalog'
|
|
|
|
|
+import { config } from '@/config'
|
|
|
|
|
+import { dict } from '@/.cool/store'
|
|
|
|
|
+
|
|
|
|
|
+const activeCategory = ref<string>()
|
|
|
|
|
+const activeTab = ref<string>('knowledge')
|
|
|
|
|
+const isLoading = ref(true)
|
|
|
|
|
+const categories = ref<SubjectCatalogResult[]>([])
|
|
|
|
|
+const cards = ref<SubjectKnowledgeCardResult[]>([])
|
|
|
|
|
+const cardsScrollView = ref<any>(null)
|
|
|
|
|
+const categoryRefs = ref<any>()
|
|
|
|
|
+async function getDataList() {
|
|
|
|
|
+ const id = dict.getValueByLabelMapByType('index_subject_id')['物理']
|
|
|
|
|
+ const res = await getSubjectKnowledgeCard({ subjectId: id })
|
|
|
|
|
+ cards.value = res.userCardList || []
|
|
|
|
|
+ categories.value = res.catalogList || []
|
|
|
|
|
+}
|
|
|
|
|
+function handleSelect(categoryId: string) {
|
|
|
|
|
+ activeCategory.value = categoryId
|
|
|
|
|
+ uni.createSelectorQuery().select(`.category-${categoryId}`).boundingClientRect().exec((rect) => {
|
|
|
|
|
+ if (cardsScrollView.value && rect[0]) {
|
|
|
|
|
+ cardsScrollView.value.scrollTo({
|
|
|
|
|
+ top: rect[0].top - 70, // 减去顶部偏移
|
|
|
|
|
+ animated: true
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function onScroll(e: any) {
|
|
|
|
|
+ categories.value.forEach(async (category) => {
|
|
|
|
|
+ const selector = `.category-${category.id}`
|
|
|
|
|
+ await uni.createSelectorQuery().selectAll(selector).boundingClientRect().exec((rects) => {
|
|
|
|
|
+ // 检查元素是否在可视区域内
|
|
|
|
|
+ for (const rect of rects[0]) {
|
|
|
|
|
+ if (rect.top <= 150 && rect.bottom >= 150) {
|
|
|
|
|
+ activeCategory.value = category.id
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+onMounted(async () => {
|
|
|
|
|
+ await getDataList()
|
|
|
|
|
+ isLoading.value = false
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ handleSelect(categories.value[0].id as string)
|
|
|
|
|
+ })
|
|
|
|
|
+})
|
|
|
|
|
+</script>
|
|
|
|
|
+<template>
|
|
|
|
|
+ <Loading v-show="isLoading" />
|
|
|
|
|
+ <cl-page v-show="!isLoading">
|
|
|
|
|
+ <Back />
|
|
|
|
|
+ <!-- 顶部标题栏 -->
|
|
|
|
|
+ <view class="content">
|
|
|
|
|
+ <!-- 左侧导航菜单 -->
|
|
|
|
|
+ <scroll-view direction="vertical" :show-scrollbar="false" class="sidebar">
|
|
|
|
|
+ <view v-for="category in categories" :key="category.id" class="sidebar-item"
|
|
|
|
|
+ :class="{ active: activeCategory === category.id }" @tap="handleSelect(category.id as string)">
|
|
|
|
|
+ <cl-image :src="config.baseUrl + category?.fileList?.[0]?.url" mode="heightFix" class="!h-[28px]"></cl-image>
|
|
|
|
|
+ <text class="sidebar-text">{{ category.name }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </scroll-view>
|
|
|
|
|
+ <!-- 右侧卡片网格 -->
|
|
|
|
|
+ <view class="cards-container">
|
|
|
|
|
+ <view class="header">
|
|
|
|
|
+ <view class="title-tabs">
|
|
|
|
|
+ <view class="tab" :class="{ active: activeTab === 'knowledge' }" @tap="activeTab = 'knowledge'">知识卡
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="tab" :class="{ active: activeTab === 'honor' }" @tap="activeTab = 'honor'">荣誉</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <scroll-view direction="vertical" :show-scrollbar="false" class="cards" ref="cardsScrollView"
|
|
|
|
|
+ @scroll="onScroll">
|
|
|
|
|
+ <view class="grid grid-cols-5 gap-4">
|
|
|
|
|
+ <view class="card" v-for="card in cards" :key="card.id" :class="`category-${card.catalogId}`"
|
|
|
|
|
+ ref="categoryRefs">
|
|
|
|
|
+ <image v-if="card.userCardId" :src="config.baseUrl + card.iconPath" class="w-full h-full" />
|
|
|
|
|
+ <image v-else src="https://oss.xiaoxiongcode.com/static/home/21.png" class="w-full h-full" />
|
|
|
|
|
+ <view class="card-title">{{ card.cardName }}</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </scroll-view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </cl-page>
|
|
|
|
|
+</template>
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.header {
|
|
|
|
|
+ @apply absolute left-1/2 top-5;
|
|
|
|
|
+ transform: translateX(-50%);
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+
|
|
|
|
|
+ .title-tabs {
|
|
|
|
|
+ @apply flex flex-row items-center justify-center rounded-full;
|
|
|
|
|
+ background-color: #9AD2FA;
|
|
|
|
|
+
|
|
|
|
|
+ .tab {
|
|
|
|
|
+ @apply rounded-full;
|
|
|
|
|
+ padding: 5px 10px;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+
|
|
|
|
|
+ &.active {
|
|
|
|
|
+ background-color: white;
|
|
|
|
|
+ color: #1E88E5;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.content {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: row;
|
|
|
|
|
+
|
|
|
|
|
+ .sidebar {
|
|
|
|
|
+ width: 200px;
|
|
|
|
|
+ background-color: #116FE9;
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+ padding-top: 70px;
|
|
|
|
|
+ height: 100vh;
|
|
|
|
|
+
|
|
|
|
|
+ .sidebar-item {
|
|
|
|
|
+ @apply text-white rounded-full py-1 cursor-pointer flex flex-row items-center;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+
|
|
|
|
|
+ &.active {
|
|
|
|
|
+ background-color: rgba(255, 255, 255, 1);
|
|
|
|
|
+ color: #1E88E5;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .sidebar-icon {
|
|
|
|
|
+ font-size: 28px;
|
|
|
|
|
+ margin-right: 2px;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .cards-container {
|
|
|
|
|
+ @apply relative;
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+ padding-top: 70px;
|
|
|
|
|
+ background: linear-gradient(0deg, #2EB2FD, #0B85F4);
|
|
|
|
|
+
|
|
|
|
|
+ .cards {
|
|
|
|
|
+ height: calc(100vh - 90px);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .category-section {
|
|
|
|
|
+ margin-bottom: 40px;
|
|
|
|
|
+
|
|
|
|
|
+ .category-title {
|
|
|
|
|
+ @apply text-white font-bold text-xl mb-4;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .card {
|
|
|
|
|
+ // background-color: rgba(255, 255, 255, 0.9);
|
|
|
|
|
+ // border-radius: 16px;
|
|
|
|
|
+ // padding: 16px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ // box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
|
|
+ aspect-ratio: 3/4;
|
|
|
|
|
+
|
|
|
|
|
+ .card-content {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 120px;
|
|
|
|
|
+ background-color: #E3F2FD;
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ aspect-ratio: 3/4;
|
|
|
|
|
+
|
|
|
|
|
+ .question-mark {
|
|
|
|
|
+ font-size: 60px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #1E88E5;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .card-title {
|
|
|
|
|
+ @apply text-center font-bold absolute left-0 w-full text-[#0E3E87] text-[1.5vw];
|
|
|
|
|
+ bottom: 13%;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|