更新:我的课程
This commit is contained in:
@@ -376,3 +376,60 @@ export async function getIosPayment(transactionId : string, productId : string,
|
|||||||
})
|
})
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 我的课程
|
||||||
|
* @param page 当前页码
|
||||||
|
* @param limit 每页数量
|
||||||
|
* @param userId 用户id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
export async function getCourseExpireList(page : number, limit : number, userId : string) {
|
||||||
|
const res = await mainClient.request<IApiResponse>({
|
||||||
|
url: 'medical/course/getCourseExpire',
|
||||||
|
method: 'POST',
|
||||||
|
data: { page, limit, userId }
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加入学习
|
||||||
|
* @param courseId 商品id
|
||||||
|
* @param userId 用户id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
export async function addUserCourseStudyingList(userId : string, courseId : string) {
|
||||||
|
const res = await mainClient.request<IApiResponse>({
|
||||||
|
url: 'medical/course/addUserCourseStudying',
|
||||||
|
method: 'POST',
|
||||||
|
data: { userId, courseId }
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消学习
|
||||||
|
* @param courseId 商品id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
export async function delUserCourseStudyingList(courseId : string) {
|
||||||
|
const res = await mainClient.request<IApiResponse>({
|
||||||
|
url: 'medical/course/delUserCourseStudying',
|
||||||
|
method: 'POST',
|
||||||
|
data: { courseId }
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类标签数
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
export async function getCourseMedicalTreeList() {
|
||||||
|
const res = await mainClient.request<IApiResponse>({
|
||||||
|
url: 'medical/home/getCourseMedicalTree',
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
391
pages/user/myCourses/index.vue
Normal file
391
pages/user/myCourses/index.vue
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
<template>
|
||||||
|
<view class="courses-page">
|
||||||
|
<z-paging ref="paging" v-model="bookList" auto-show-back-to-top class="my-book-page" @query="getDataList"
|
||||||
|
:default-page-size="10">
|
||||||
|
<template #top>
|
||||||
|
<!-- 自定义导航栏 -->
|
||||||
|
<nav-bar :title="$t('user.myCourses')"></nav-bar>
|
||||||
|
</template>
|
||||||
|
<wd-tabs v-model="tab" @change="switchTab" auto-line-width animated>
|
||||||
|
<block v-for="item in tabs" :key="item.id">
|
||||||
|
<wd-tab :title="`${item.name}`" :name="item.id">
|
||||||
|
<view v-if="item.id === 0">
|
||||||
|
<wd-search v-model="title" placeholder-right placeholder="请输入课程名称" cancel-txt="搜索" @search="search"
|
||||||
|
@cancel="search" light style="margin-top: 10rpx;" />
|
||||||
|
<view class="courses-row">
|
||||||
|
<view class="courses-category">{{ !tagData ? '已显示全部课程' : `已选择分类:${tagName}`}}
|
||||||
|
<wd-button size="small" type="warning" style="margin-left: 20rpx;" v-if="tagData" @click="clear">清除</wd-button>
|
||||||
|
</view>
|
||||||
|
<view class="courses-category" @click="openwindow">
|
||||||
|
<wd-icon name="app" size="36rpx" color="#2979ff"></wd-icon>
|
||||||
|
<text>按分类筛选</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="myCourse-data" v-for="(item, index) in bookList" :key="index"
|
||||||
|
@click="onPageJump('/pages/course/details/course',item.id)">
|
||||||
|
<view>
|
||||||
|
<image class="myCourse-data-image" :src="item.image" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
|
<view class="myCourse-data-row">
|
||||||
|
<view class="myCourse-data-row-text">
|
||||||
|
<view class="title">{{item.title}}</view>
|
||||||
|
<view class="introduction" v-html="item.content"></view>
|
||||||
|
</view>
|
||||||
|
<view class="row-button">
|
||||||
|
<wd-button plain size="small" class="button"
|
||||||
|
@click.stop="onPageJump('/pages/course/details/course',item.id)" v-if="tab !==2">去学习</wd-button>
|
||||||
|
<view v-if="tab !==2">
|
||||||
|
<wd-button type="warning" size="small" plain class="button" @click.stop="joinStudy(item.id)"
|
||||||
|
v-if="item.isStudying === 0">加入在学习</wd-button>
|
||||||
|
<wd-button type="warning" size="small" class="button" @click.stop="cancelStudy(item.id)"
|
||||||
|
v-else>取消在学习</wd-button>
|
||||||
|
</view>
|
||||||
|
<wd-button size="small" class="button" @click.stop="renewal(item.catalogueId)" v-else>续费课程</wd-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</wd-tab>
|
||||||
|
</block>
|
||||||
|
</wd-tabs>
|
||||||
|
</z-paging>
|
||||||
|
<!-- 商品选择器 -->
|
||||||
|
<GoodsSelector :show="showGoodsSelector" :goods="goodsList" @select="handleGoodsSelect"
|
||||||
|
@confirm="handleGoodsConfirm" @close="closeGoodsSelector" />
|
||||||
|
<!-- 搜索分类弹窗 -->
|
||||||
|
<wd-popup v-model="showState" position="right" custom-style="border-radius: 0px !important;width: 70%;">
|
||||||
|
<wd-button @click="collapse?.toggleAll(true)">测试</wd-button>
|
||||||
|
<view class="_text">请选择课程分类</view>
|
||||||
|
<wd-collapse ref="collapse" v-model="levelOne" accordion v-for="item in labelTree" :key="item.id"
|
||||||
|
:title="item.title" :name="item.name">
|
||||||
|
<wd-collapse-item :title="item?.title" :name="item?.title" custom-body-style="padding:0">
|
||||||
|
<view v-for="itm in item?.children" :key="itm?.id" class="content-text" @click.stop="gettagId1(itm)">
|
||||||
|
<view style="margin-bottom: 10rpx;">{{itm?.title}}</view>
|
||||||
|
<view v-for="it in itm?.children" :key="it?.id" class="row" @click.stop="gettagId2(it)">
|
||||||
|
{{it?.title}}
|
||||||
|
<view>
|
||||||
|
<wd-button class="_r" size="small" plain v-for="i in it?.children" :key="i?.id"
|
||||||
|
@click.stop="gettagId3(i)">{{i?.title}}</wd-button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</wd-collapse-item>
|
||||||
|
</wd-collapse>
|
||||||
|
</wd-popup>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { onShow } from '@dcloudio/uni-app'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { courseApi } from '@/api/modules/course'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import GoodsSelector from '@/components/order/GoodsSelector.vue'
|
||||||
|
import {
|
||||||
|
getUserCourseBuyList,
|
||||||
|
getUserCourseStudyingList,
|
||||||
|
getCourseExpireList,
|
||||||
|
addUserCourseStudyingList,
|
||||||
|
delUserCourseStudyingList,
|
||||||
|
getCourseMedicalTreeList
|
||||||
|
} from '@/api/modules/user'
|
||||||
|
import type { CollapseInstance } from '@/uni_modules/wot-design-uni/components/wd-collapse/types'
|
||||||
|
|
||||||
|
const collapse = ref<CollapseInstance>()
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const tabs = ref([
|
||||||
|
{ name: "我的课程", id: 0 },
|
||||||
|
{ name: "正在学习", id: 1 },
|
||||||
|
{ name: "已过期", id: 2 }
|
||||||
|
])
|
||||||
|
const tab = ref(0)
|
||||||
|
const bookList = ref([])
|
||||||
|
const loading = ref(false)
|
||||||
|
const firstLoad = ref(true)
|
||||||
|
const paging = ref<any>()
|
||||||
|
const title = ref('') // 搜索数据
|
||||||
|
const pageNoData = ref(0)
|
||||||
|
const pageSizeData = ref(0)
|
||||||
|
const goodsList = ref([])
|
||||||
|
const selectedGoods = ref(null) // 上坡数据
|
||||||
|
// 商品选择
|
||||||
|
const showGoodsSelector = ref(false) // 商品价格选择弹窗
|
||||||
|
const showState = ref(false) // 搜索分类弹窗
|
||||||
|
const apiMap = [
|
||||||
|
getUserCourseBuyList, // 我的课程
|
||||||
|
getUserCourseStudyingList, // 正在学习
|
||||||
|
getCourseExpireList // 已过期
|
||||||
|
];
|
||||||
|
const levelOne = ref('')
|
||||||
|
const labelTree = ref([]) // 课程分类数据
|
||||||
|
const tagData = ref('') // 标签数据
|
||||||
|
const tagName = ref('')
|
||||||
|
|
||||||
|
// 我的课程
|
||||||
|
async function getDataList(pageNo : number, pageSize : number) {
|
||||||
|
console.log(userStore.id);
|
||||||
|
loading.value = true
|
||||||
|
pageNoData.value = pageNo ?? pageNoData.value
|
||||||
|
pageSizeData.value = pageSize ?? pageSizeData.value
|
||||||
|
const targetApi = apiMap[tab.value];
|
||||||
|
console.log(tagData, 'tagData');
|
||||||
|
try {
|
||||||
|
const res = await targetApi(pageNoData.value, pageSizeData.value, tab.value === 0 ? title.value : userStore.id, tagData?.value.id ?? '')
|
||||||
|
paging.value.complete(tab.value === 0 ? res.courseList.records : res.courseList)
|
||||||
|
} catch (error) {
|
||||||
|
paging.value.complete(false)
|
||||||
|
console.error('Failed to load book list:', error)
|
||||||
|
} finally {
|
||||||
|
firstLoad.value = false
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换tab
|
||||||
|
*/
|
||||||
|
const switchTab = (e) => {
|
||||||
|
tab.value = e.index
|
||||||
|
bookList.value = []
|
||||||
|
tagData.value = {}
|
||||||
|
getDataList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索
|
||||||
|
*/
|
||||||
|
const search = () => {
|
||||||
|
bookList.value = []
|
||||||
|
getDataList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加入学习
|
||||||
|
*/
|
||||||
|
const joinStudy = async (id : string) => {
|
||||||
|
console.log(id, 'id');
|
||||||
|
try {
|
||||||
|
await addUserCourseStudyingList(userStore.id, id)
|
||||||
|
getDataList()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加入学习', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消学习
|
||||||
|
*/
|
||||||
|
const cancelStudy = async (id : string) => {
|
||||||
|
try {
|
||||||
|
await delUserCourseStudyingList(id)
|
||||||
|
getDataList()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('取消学习', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 续费课程
|
||||||
|
*/
|
||||||
|
const renewal = async (id : any) => {
|
||||||
|
const res = await courseApi.getProductListForCourse(id)
|
||||||
|
if (res.code === 0 && res.productList.length > 0) {
|
||||||
|
goodsList.value = res.productList
|
||||||
|
showGoodsSelector.value = true
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: '此课程暂无购买方式', icon: 'none' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择商品
|
||||||
|
*/
|
||||||
|
const handleGoodsSelect = (goods : IGoods) => selectedGoods.value = goods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认购买
|
||||||
|
*/
|
||||||
|
const handleGoodsConfirm = () => {
|
||||||
|
showGoodsSelector.value = false
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/order/goodsConfirm?goods=${selectedGoods.value.productId}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭商品选择器
|
||||||
|
*/
|
||||||
|
const closeGoodsSelector = () => showGoodsSelector.value = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开商品分类弹窗
|
||||||
|
*/
|
||||||
|
const openwindow = () => showState.value = true
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取标签树
|
||||||
|
*/
|
||||||
|
const getTreeList = async () => {
|
||||||
|
try {
|
||||||
|
const data = await getCourseMedicalTreeList()
|
||||||
|
labelTree.value = data.labels
|
||||||
|
console.log(data, '分类标签数');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('分类标签数', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取一级标签id
|
||||||
|
*/
|
||||||
|
const gettagId1 = (item : any) => publicMethod(item)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取二级标签id
|
||||||
|
*/
|
||||||
|
const gettagId2 = (item : any) => publicMethod(item)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取三级标签id
|
||||||
|
*/
|
||||||
|
const gettagId3 = (item : any) => publicMethod(item)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公共方法
|
||||||
|
*/
|
||||||
|
const publicMethod = (item : { title ?: any }) => {
|
||||||
|
console.log(item,'item');
|
||||||
|
tagName.value = item.title
|
||||||
|
tagData.value = item
|
||||||
|
showState.value = false
|
||||||
|
getDataList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除按钮
|
||||||
|
*/
|
||||||
|
const clear = () =>{
|
||||||
|
tagData.value = ''
|
||||||
|
getDataList()
|
||||||
|
}
|
||||||
|
// 跳转
|
||||||
|
const onPageJump = (url : any, id : any) => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `${url}?id=${id}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onShow(() => {
|
||||||
|
getTreeList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.courses-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.courses-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20rpx 20rpx 10rpx 20rpx;
|
||||||
|
|
||||||
|
.courses-category {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
text {
|
||||||
|
color: #2979ff;
|
||||||
|
margin-left: 4rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.myCourse-data {
|
||||||
|
margin: 20rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
box-shadow: 0px 0px 10px 0px #a7bbe4;
|
||||||
|
display: flex;
|
||||||
|
//border: 1px solid #2979ff;
|
||||||
|
|
||||||
|
.myCourse-data-image {
|
||||||
|
display: block;
|
||||||
|
width: 260rpx;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
height: 200rpx;
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #edf3ff;
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 100%;
|
||||||
|
height: 200rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.myCourse-data-row {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.myCourse-data-row-text {
|
||||||
|
.title {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.introduction {
|
||||||
|
color: #9c9c9c;
|
||||||
|
font-size: 26rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: 10rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.row-button {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
|
||||||
|
.button {
|
||||||
|
margin-left: 10rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
._text {
|
||||||
|
text-align: center;
|
||||||
|
padding: 30px 0;
|
||||||
|
margin-top: 130rpx;
|
||||||
|
color: #888;
|
||||||
|
font-size: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-text {
|
||||||
|
color: #1b2a32;
|
||||||
|
padding: 20rpx 0 20rpx 60rpx;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
// line-height: 40px;
|
||||||
|
|
||||||
|
.row {
|
||||||
|
padding: 10rpx 0 10rpx 30rpx;
|
||||||
|
|
||||||
|
._r {
|
||||||
|
margin: 20rpx 20rpx 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user