Browse Source

```
feat(service): 修改useGet函数参数名为data

修改useGet函数中的params参数为data,以保持API调用的一致性

fix(proxy): 更新开发环境代理目标地址

将开发环境、文件服务和API的代理目标地址从192.168.1.11:5001更新为192.168.110.161:5001

feat(card): 添加知识卡片页面功能

添加完整的知识卡片页面,包括左侧导航菜单和右侧卡片网格展示功能

refactor(catalog): 添加加载组件并优化数据获取逻辑

在目录页面中添加Loading组件,并优化数据获取时的异步处理逻辑

refactor(home): 重命名页面跳转方法并添加卡片页面入口

将handleLogin方法重命名为handlePage,并在首页添加知识卡片页面的跳转入口

feat(card): 添加知识卡片相关服务接口

添加知识卡片相关的API服务接口定义,包括获取卡片列表等功能
```

whj 1 tuần trước cách đây
mục cha
commit
59c711a0da

+ 2 - 2
.cool/service/index.ts

@@ -153,10 +153,10 @@ export function request(options: RequestOptions): Promise<any | null> {
 		next();
 	});
 }
-export function useGet(url: string, params?: any, config?: RequestOptions): Promise<Response> {
+export function useGet(url: string, data?: any, config?: RequestOptions): Promise<Response> {
 	const options: RequestOptions = {
 		url,
-		params,
+		data,
 		method: 'GET',
 		...config,
 	}

+ 11 - 0
components/loading.uvue

@@ -0,0 +1,11 @@
+<script setup lang='ts'>
+
+</script>
+<template>
+  <image src="https://oss.xiaoxiongcode.com/static/home/loading.gif" class="loading-image" />
+</template>
+<style lang="scss" scoped>
+.loading-image {
+  @apply w-full h-full object-cover absolute top-0 left-0 z-[100];
+}
+</style>

+ 3 - 3
config/proxy.ts

@@ -2,18 +2,18 @@ export const proxy = {
 	// 开发环境配置
 	dev: {
 		// 本地地址
-		target: "http://192.168.1.11:5001",
+		target: "http://192.168.110.161:5001",
 		changeOrigin: true,
 		rewrite: (path: string) => path.replace("/dev", "")
 	},
 	files: {
 		// 本地地址
-		target: "http://192.168.1.11:5001",
+		target: "http://192.168.110.161:5001",
 		changeOrigin: true,
 	},
 	api: {
 		// 本地地址
-		target: "http://192.168.1.11:5001",
+		target: "http://192.168.110.161:5001",
 		changeOrigin: true,
 		rewrite: (path: string) => path.replace("/api", "")
 	},

+ 7 - 0
pages.json

@@ -19,6 +19,13 @@
 				"navigationStyle": "custom",
 				"disableScroll": true
 			}
+		},
+		{
+			"path": "pages/card/index",
+			"style": {
+				"navigationStyle": "custom",
+				"disableScroll": true
+			}
 		}
 	],
 	"globalStyle": {

+ 167 - 0
pages/card/index.uvue

@@ -0,0 +1,167 @@
+<script setup lang='ts'>
+import Back from '@/components/back.uvue'
+import Loading from '@/components/loading.uvue'
+import { ref, onMounted } from 'vue'
+import { type SubjectKnowledgeCardResult, getSubjectKnowledgeCard } from '@/services/subject/card'
+import { fetchSubjectConfigInfo } from '@/services/subject/info'
+import type { SubjectCatalogResult } from '@/services/subject/catalog'
+
+const activeCategory = ref<string>()
+const isLoading = ref(true)
+const categories = ref<SubjectCatalogResult[]>([])
+
+const cards = ref<SubjectKnowledgeCardResult[]>([])
+async function getDataList() {
+  const res = await fetchSubjectConfigInfo({ id: '69afc7e048070409048c06b6' })
+  categories.value = res.catalogList || []
+  handleSelect(categories.value[0].id as string)
+}
+function handleSelect(subjectId: string) {
+  activeCategory.value = subjectId
+  getSubjectKnowledgeCard({ subjectId }).then(res => {
+    console.log(res)
+    cards.value = res.catalogList || []
+  })
+}
+onMounted(async () => {
+  await getDataList()
+  isLoading.value = false
+})
+</script>
+<template>
+  <Loading v-if="isLoading" />
+  <cl-page v-else>
+    <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="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 active">知识卡</view>
+            <view class="tab">荣誉</view>
+          </view>
+        </view>
+        <scroll-view direction="vertical" :show-scrollbar="false" class="cards">
+          <view class="grid grid-cols-5 gap-4">
+            <view class="card" v-for="card in cards" :key="card.id">
+              <image src="/static/home/21.png" class="w-full h-full" />
+              <view class="card-title">{{ card.title }}</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);
+    }
+
+    .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 bottom-[13%] left-0 w-full text-[#0E3E87] text-[1.5vw];
+      }
+    }
+  }
+}
+</style>

+ 8 - 4
pages/catalog/index.uvue

@@ -1,5 +1,6 @@
 <template>
-  <cl-page>
+  <Loading v-if="isLoading" />
+  <cl-page v-else>
     <Back />
     <img src="/static/home/2.png" alt="" class="w-full h-full object-cover" />
     <!-- 精灵图动画 -->
@@ -14,7 +15,7 @@
       <cl-icon name="arrow-left-right-line" color="primary"></cl-icon>
     </view>
     <view class="boxs">
-      <scroll-view class="scroll-view_H" direction="horizontal" :scroll-left="120" :show-scrollbar="false">
+      <scroll-view class="scroll-view_H" direction="horizontal" :show-scrollbar="false">
         <view class="scroll-view-item_H bg-[white]" v-for="course in catalog?.courseList || []" :key="course.id">
           <cl-image :src="course?.fileList?.[0]?.url" mode="heightFix"
             class="!w-full !h-[26vh] mb-[2px] rounded-xl"></cl-image>
@@ -65,7 +66,9 @@ import { fetchSubjectConfigInfo } from '@/services/subject/info'
 import type { SubjectCatalogResult } from '@/services/subject/catalog'
 import Progress from './components/progress.uvue'
 import Back from '@/components/back.uvue'
+import Loading from '@/components/loading.uvue'
 
+const isLoading = ref(true)
 
 const visible = ref<boolean>(false)
 const dataList = ref<SubjectCatalogResult[]>([])
@@ -75,8 +78,9 @@ async function getDataList() {
   dataList.value = res.catalogList || []
   catalog.value = res?.catalogList?.[0]
 }
-onMounted(() => {
-  getDataList()
+onMounted(async () => {
+  await getDataList()
+  isLoading.value = false
 })
 function handleSelect(item: SubjectCatalogResult) {
   catalog.value = item

+ 3 - 3
pages/index/home.uvue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-function handleLogin(url) {
+function handlePage(url) {
 	uni.navigateTo({
 		url
 	})
@@ -9,7 +9,7 @@ function handleLogin(url) {
 	<cl-page>
 		<img src="/static/home/11.png" alt="" class="w-full h-full object-cover" />
 		<view class="content">
-			<view class="relative w-[25vw] " @click="handleLogin('/pages/catalog/index')">
+			<view class="relative w-[25vw] " @click="handlePage('/pages/catalog/index')">
 				<img src="/static/home/13.png" alt="" class="w-full object-cover" />
 				<view class="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pb-3">
 					<view class="text-2xl font-bold">全部课程</view>
@@ -40,7 +40,7 @@ function handleLogin(url) {
 							</view>
 						</view>
 					</cl-col>
-					<cl-col :span="12" :pt="{ className: '!p-3' }">
+					<cl-col :span="12" :pt="{ className: '!p-3' }" @click="handlePage('/pages/card/index')">
 						<view class="relative w-full ">
 							<img src="/static/home/16.png" alt="" class="w-full object-cover" />
 							<view class="absolute top-4 left-5">

+ 52 - 0
services/subject/card.ts

@@ -0,0 +1,52 @@
+import { usePost, stringify, useGet } from "@/.cool";
+import type { SubjectCourseResult } from './course'
+import type { FileList } from '../types/index'
+
+export interface SubjectKnowledgeCardResult {
+    id?: string
+    name?: string
+    subjectId?: string
+    catalogId?: string
+    iconPath?: string
+    content?: string
+    contentVoicePath?: string
+    sortNum?: string
+    remark?: string
+    updateUserId?: string
+    updateUserName?: string
+    createdUserId?: string
+    createdUserName?: string
+    createdTime?: string
+    updateTime?: string
+}
+export interface SubjectCardResult {
+    userCardList?: string[]
+    catalogList?: SubjectKnowledgeCardResult[]
+}
+export function getSubjectKnowledgeCardPage(parameter: any) {
+    return useGet(`/subject/card/page`, parameter)
+}
+// export function addSubjectKnowledgeCard(parameter: SubjectKnowledgeCardResult) {
+//     return usePost(`/subject/card`, parameter)
+// }
+// export function updateSubjectKnowledgeCard(parameter: SubjectKnowledgeCardResult) {
+//     return usePut(`/subject/card/${parameter.id}`, parameter)
+// }
+export function fetchSubjectKnowledgeCard(parameter: any) {
+    return useGet(`/subject/card/${parameter.id}`)
+}
+export function getSubjectKnowledgeCard(parameter: any) {
+    return useGet(`/subject/user-card/accord/card`, parameter) as Promise<SubjectCardResult>
+}
+// export function deleteSubjectKnowledgeCards(parameter: string[]) {
+//     return useDelete(`/subject/card`, parameter)
+// }
+
+// export function exportSubjectKnowledgeCard(parameter: any) {
+//     return useGet(`/subject/card/export`, parameter, {
+//         responseType: 'blob',
+//         headers: {
+//             'Content-Type': 'application/json;charset=UTF-8',
+//         },
+//     })
+// }