Compare commits
2 Commits
79aa8e3fe6
...
c3b84946fb
| Author | SHA1 | Date | |
|---|---|---|---|
| c3b84946fb | |||
| b671e8d76c |
@@ -159,7 +159,7 @@ export function uploadImage(filePath: string): Promise<string> {
|
|||||||
url: `${SERVICE_MAP.MAIN}oss/fileoss`,
|
url: `${SERVICE_MAP.MAIN}oss/fileoss`,
|
||||||
filePath,
|
filePath,
|
||||||
name: 'file',
|
name: 'file',
|
||||||
success: (res) => {
|
success: (res: any) => {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(res.data)
|
const data = JSON.parse(res.data)
|
||||||
if (data.url) {
|
if (data.url) {
|
||||||
@@ -304,9 +304,10 @@ export async function getPointsData(current : number, limit : number, userId : s
|
|||||||
* 迁移用户数据
|
* 迁移用户数据
|
||||||
* @param tel 旧账号
|
* @param tel 旧账号
|
||||||
* @param code 迁移验证码
|
* @param code 迁移验证码
|
||||||
|
* @param type 未迁移数据类型
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
export async function migrateUserData(data: { tel: string, code: string }) {
|
export async function migrateUserData(data: { tel: string, code: string, type: string }) {
|
||||||
const res = await mainClient.request<IApiResponse>({
|
const res = await mainClient.request<IApiResponse>({
|
||||||
url: 'common/user/migrationWumenData',
|
url: 'common/user/migrationWumenData',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -314,3 +315,18 @@ export async function migrateUserData(data: { tel: string, code: string }) {
|
|||||||
})
|
})
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户迁移信息
|
||||||
|
* @return {
|
||||||
|
* alreadyMigration: 已迁移用户数
|
||||||
|
* notMigration: 未迁移用户数
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export async function getUserMigrateInfo() {
|
||||||
|
const res = await mainClient.request<IApiResponse>({
|
||||||
|
url: 'common/user/getMigrationList',
|
||||||
|
method: 'POST',
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<!-- 商品列表 -->
|
<!-- 商品列表 -->
|
||||||
<view class="selector-header">
|
<view class="selector-header">
|
||||||
<text class="title">{{ isFudu ? t('order.selectFuduScheme') : t('order.selectPurchaseScheme') }}</text>
|
<text class="title">{{ t('order.goodsList') }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="goods-list">
|
<view class="goods-list">
|
||||||
<view
|
<view
|
||||||
@@ -54,7 +54,6 @@ const { t } = useI18n()
|
|||||||
interface Props {
|
interface Props {
|
||||||
show: boolean
|
show: boolean
|
||||||
goods: IGoods[]
|
goods: IGoods[]
|
||||||
isFudu?: boolean // 是否为复读
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
|
|||||||
@@ -227,6 +227,9 @@
|
|||||||
"instruction2": "After data migration is complete, the chinese account data will be cleared, and all purchased Tianyi Coins, points, courses, E-book, VIP, certificate, and User Contribution will be transferred to the current account",
|
"instruction2": "After data migration is complete, the chinese account data will be cleared, and all purchased Tianyi Coins, points, courses, E-book, VIP, certificate, and User Contribution will be transferred to the current account",
|
||||||
"instruction3": "The migration process may take a few minutes, please be patient.",
|
"instruction3": "The migration process may take a few minutes, please be patient.",
|
||||||
"instruction4": "If you encounter any issues, please contact customer service for assistance.",
|
"instruction4": "If you encounter any issues, please contact customer service for assistance.",
|
||||||
|
"alreadyMigrated": "You have already migrated:",
|
||||||
|
"notMigration": "This migration:",
|
||||||
|
"migratedCompleted": "You have completed all migrations:",
|
||||||
"closeWindow": "Close the payment pop-up window"
|
"closeWindow": "Close the payment pop-up window"
|
||||||
},
|
},
|
||||||
"book": {
|
"book": {
|
||||||
@@ -435,8 +438,7 @@
|
|||||||
"orderCreateFailed": "Failed to create order"
|
"orderCreateFailed": "Failed to create order"
|
||||||
},
|
},
|
||||||
"order": {
|
"order": {
|
||||||
"selectFuduScheme": "Select Fudu Scheme",
|
"goodsList": "Product List",
|
||||||
"selectPurchaseScheme": "Select Purchase Scheme",
|
|
||||||
"confirmTitle": "Confirm Order",
|
"confirmTitle": "Confirm Order",
|
||||||
"goodsInfo": "Product Information",
|
"goodsInfo": "Product Information",
|
||||||
"priceDetail": "Price Details",
|
"priceDetail": "Price Details",
|
||||||
|
|||||||
@@ -228,6 +228,9 @@
|
|||||||
"instruction2": "数据迁移完成后,旧账号数据将被清空,已购买的天医币、积分、课程、电子书、VIP、证书、湖分将转移到当前账号。",
|
"instruction2": "数据迁移完成后,旧账号数据将被清空,已购买的天医币、积分、课程、电子书、VIP、证书、湖分将转移到当前账号。",
|
||||||
"instruction3": "迁移过程可能需要几分钟时间,请耐心等待。",
|
"instruction3": "迁移过程可能需要几分钟时间,请耐心等待。",
|
||||||
"instruction4": "如遇到问题,请联系客服获取帮助。",
|
"instruction4": "如遇到问题,请联系客服获取帮助。",
|
||||||
|
"alreadyMigrated": "您已迁移过:",
|
||||||
|
"notMigration": "本次迁移:",
|
||||||
|
"migratedCompleted": "您已迁移过所有可迁移数据:",
|
||||||
"closeWindow": "关闭支付弹窗"
|
"closeWindow": "关闭支付弹窗"
|
||||||
},
|
},
|
||||||
"book": {
|
"book": {
|
||||||
@@ -435,8 +438,7 @@
|
|||||||
"orderCreateFailed": "订单创建失败"
|
"orderCreateFailed": "订单创建失败"
|
||||||
},
|
},
|
||||||
"order": {
|
"order": {
|
||||||
"selectFuduScheme": "选择复读方案",
|
"goodsList": "商品列表",
|
||||||
"selectPurchaseScheme": "选择购买方案",
|
|
||||||
"confirmTitle": "确认订单",
|
"confirmTitle": "确认订单",
|
||||||
"goodsInfo": "商品信息",
|
"goodsInfo": "商品信息",
|
||||||
"priceDetail": "价格明细",
|
"priceDetail": "价格明细",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"id": "uni-taimed-international-app",
|
"id": "uni-wumen-international-app",
|
||||||
"name": "TaimedInternationalApp",
|
"name": "wumen-international-app",
|
||||||
"displayName": "太湖国际",
|
"displayName": "太湖国际",
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"description": "太湖国际",
|
"description": "太湖国际",
|
||||||
|
|||||||
@@ -55,12 +55,8 @@
|
|||||||
<wd-button size="small" type="warning" @click="handlePurchase">
|
<wd-button size="small" type="warning" @click="handlePurchase">
|
||||||
{{ $t('courseDetails.purchase') }}
|
{{ $t('courseDetails.purchase') }}
|
||||||
</wd-button>
|
</wd-button>
|
||||||
<wd-button
|
<!-- 如果是复读显示复读按钮 -->
|
||||||
v-if="showRenewBtn"
|
<wd-button v-if="canRenlearn" size="small" type="success" @click="handleRenlearn">
|
||||||
size="small"
|
|
||||||
type="success"
|
|
||||||
@click="handleRenew"
|
|
||||||
>
|
|
||||||
{{ $t('courseDetails.relearn') }}
|
{{ $t('courseDetails.relearn') }}
|
||||||
</wd-button>
|
</wd-button>
|
||||||
<wd-button size="small" type="primary" @click="goToVip">
|
<wd-button size="small" type="primary" @click="goToVip">
|
||||||
@@ -134,28 +130,42 @@
|
|||||||
<text>暂无章节内容</text>
|
<text>暂无章节内容</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 商品选择器 -->
|
||||||
|
<GoodsSelector
|
||||||
|
:show="showGoodsSelector"
|
||||||
|
:goods="goodsList"
|
||||||
|
@select="handleGoodsSelect"
|
||||||
|
@confirm="handleGoodsConfirm"
|
||||||
|
@close="closeGoodsSelector"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 购买协议弹窗 -->
|
||||||
|
<Protocol :visible="showProtocol" @confirmPurchase="confirmPurchase" />
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, watch } from 'vue'
|
import { ref, computed, watch } from 'vue'
|
||||||
import { courseApi } from '@/api/modules/course'
|
import { courseApi } from '@/api/modules/course'
|
||||||
|
import GoodsSelector from '@/components/order/GoodsSelector.vue'
|
||||||
|
import Protocol from './Protocol.vue'
|
||||||
import type { IChapter, ICatalogue, IVipInfo } from '@/types/course'
|
import type { IChapter, ICatalogue, IVipInfo } from '@/types/course'
|
||||||
|
import type { IGoods } from '@/types/order'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
catalogues: ICatalogue[]
|
catalogues: ICatalogue[]
|
||||||
userVip: IVipInfo | null
|
userVip: IVipInfo | null
|
||||||
showRenewBtn?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
click: [chapter: IChapter],
|
click: [chapter: IChapter],
|
||||||
purchase: [catalogue: ICatalogue],
|
change: [index: number],
|
||||||
renew: [catalogue: ICatalogue],
|
toVip: [],
|
||||||
toVip: [catalogue: ICatalogue],
|
toDetail: [chapter: IChapter, catalogue: ICatalogue],
|
||||||
change: [index: number]
|
loadPageData: [],
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
// 当前目录索引
|
// 当前目录索引
|
||||||
@@ -167,14 +177,21 @@ const currentCatalogue = computed(() => {
|
|||||||
// 当前目录的章节
|
// 当前目录的章节
|
||||||
const chapterList = ref<IChapter[]>([])
|
const chapterList = ref<IChapter[]>([])
|
||||||
|
|
||||||
// 显示续费按钮
|
// 当前目录是否是复读
|
||||||
const showRenewBtn = ref<boolean>(false)
|
const isRelearn = ref<boolean>(false)
|
||||||
|
const canRenlearn = ref<boolean>(false)
|
||||||
|
|
||||||
// 判断目录是否已购买
|
// 判断目录是否已购买
|
||||||
const isPurchased = computed(() => {
|
const isPurchased = computed(() => {
|
||||||
return currentCatalogue.value.isBuy === 1
|
return currentCatalogue.value.isBuy === 1
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 商品选择
|
||||||
|
const showGoodsSelector = ref(false)
|
||||||
|
const goodsList = ref<IGoods[]>([])
|
||||||
|
const selectedGoods = ref<IGoods | null>(null)
|
||||||
|
const showProtocol = ref(false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 选择目录
|
* 选择目录
|
||||||
*/
|
*/
|
||||||
@@ -201,9 +218,9 @@ const getChapters = async () => {
|
|||||||
const checkRenewPayment = async () => {
|
const checkRenewPayment = async () => {
|
||||||
if (currentCatalogue.value.isBuy === 0 && !props.userVip) {
|
if (currentCatalogue.value.isBuy === 0 && !props.userVip) {
|
||||||
const renewRes = await courseApi.checkRenewPayment(currentCatalogue.value.id)
|
const renewRes = await courseApi.checkRenewPayment(currentCatalogue.value.id)
|
||||||
showRenewBtn.value = renewRes.canRelearn || false
|
canRenlearn.value = renewRes.canRelearn || false
|
||||||
} else {
|
} else {
|
||||||
showRenewBtn.value = false
|
canRenlearn.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,23 +236,98 @@ watch(() => props.catalogues, (newVal: ICatalogue[]) => {
|
|||||||
}, { immediate: true, deep: true })
|
}, { immediate: true, deep: true })
|
||||||
|
|
||||||
// 购买
|
// 购买
|
||||||
const handlePurchase = () => {
|
const handlePurchase = async () => {
|
||||||
emit('purchase', currentCatalogue.value)
|
if (!currentCatalogue.value) return
|
||||||
|
|
||||||
|
isRelearn.value = false
|
||||||
|
const res = await courseApi.getProductListForCourse(currentCatalogue.value.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
|
||||||
|
showProtocol.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭商品选择器
|
||||||
|
*/
|
||||||
|
const closeGoodsSelector = () => {
|
||||||
|
showGoodsSelector.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认购买协议
|
||||||
|
*/
|
||||||
|
const confirmPurchase = () => {
|
||||||
|
showProtocol.value = false
|
||||||
|
if (!selectedGoods.value) return
|
||||||
|
|
||||||
|
showProtocol.value = false
|
||||||
|
|
||||||
|
if (isRelearn.value) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/order/goodsConfirm?isRelearn=1`,
|
||||||
|
success: () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.$emit('selectedGoods', selectedGoods.value)
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 跳转到购买确认订单页
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/order/goodsConfirm?goods=${selectedGoods.value.productId}`
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 去开通vip
|
// 去开通vip
|
||||||
const goToVip = () => {
|
const goToVip = () => {
|
||||||
emit('toVip', currentCatalogue.value)
|
emit('toVip')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 续费/复读
|
// 续费/复读
|
||||||
const handleRenew = () => {
|
const handleRenlearn = async () => {
|
||||||
emit('renew', currentCatalogue.value)
|
if (!currentCatalogue.value) return
|
||||||
|
|
||||||
|
isRelearn.value = true
|
||||||
|
const res = await courseApi.getRenewProductList(currentCatalogue.value.id)
|
||||||
|
if (res.productList.length > 0) {
|
||||||
|
goodsList.value = res.productList
|
||||||
|
showGoodsSelector.value = true
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: '暂无复读方案', icon: 'none' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 领取免费课程
|
// 领取免费课程
|
||||||
const handleGetFreeCourse = async () => {
|
const handleGetFreeCourse = async () => {
|
||||||
emit('getFreeCourse', currentCatalogue.value)
|
if (!currentCatalogue.value) return
|
||||||
|
|
||||||
|
const res = await courseApi.startStudyForMF(currentCatalogue.value.id)
|
||||||
|
if (res.code === 0) {
|
||||||
|
uni.showToast({ title: '领取成功', icon: 'success' })
|
||||||
|
// 刷新页面数据
|
||||||
|
emit('loadPageData')
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: res.msg || '领取失败', icon: 'none' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -260,7 +352,7 @@ const canAccess = (chapter: IChapter): boolean => {
|
|||||||
/**
|
/**
|
||||||
* 点击章节
|
* 点击章节
|
||||||
*/
|
*/
|
||||||
const handleChapterClick = (chapter: IChapter, catalogue: ICatalogue) => {
|
const handleChapterClick = (chapter: IChapter) => {
|
||||||
if (!canAccess(chapter)) {
|
if (!canAccess(chapter)) {
|
||||||
if (currentCatalogue.value.type === 0) {
|
if (currentCatalogue.value.type === 0) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
|
|||||||
91
pages/course/details/components/Protocol.vue
Normal file
91
pages/course/details/components/Protocol.vue
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<wd-popup v-model="showProtocol" position="center">
|
||||||
|
<view class="protocol-popup">
|
||||||
|
<view class="protocol-title">温馨提示</view>
|
||||||
|
<view class="protocol-content">
|
||||||
|
<text>
|
||||||
|
用户您好,本软件对于一个用户名及密码仅允许一部电子设备登陆,多部设备使用同一用户名操作软件的行为属于违规操作,发现违规一次将提出警告,再次违规您的用户名将被封号,无法正常登陆,如因此对您使用带来不便,敬请谅解。
|
||||||
|
</text>
|
||||||
|
<text>
|
||||||
|
课程购买之后一年内不打开,此一年内不会计算有效学习时间,一年后会自动开始计算有效学习时间。
|
||||||
|
</text>
|
||||||
|
<text>
|
||||||
|
本课程一经购买,暂不支持退款,敬请谅解。
|
||||||
|
</text>
|
||||||
|
<view style="color: red; font-weight: bold"> 注: </view>
|
||||||
|
<view>
|
||||||
|
1.手机、pad、电脑均为可登陆电子设备,均有唯一标识码,一个用户名仅允许在一个手机或一个ipad或一个电脑登陆,请根据您的使用习惯自行选择。<br />
|
||||||
|
2.如若申请变更登陆设备请联系客服,<br />
|
||||||
|
客服电话:021-08371305<br />
|
||||||
|
客服微信号:yilujiankangkefu<br />
|
||||||
|
3.如因违反上述使用规定...概不退款,本公司保留追究用户相关法律责任的权利。<br />
|
||||||
|
4.点击“同意”按钮即表示您同意遵守以上条款。
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="protocol-actions">
|
||||||
|
<wd-button type="info" plain @click="showProtocol = false">不同意</wd-button>
|
||||||
|
<wd-button type="primary" @click="confirmPurchase">同意</wd-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</wd-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
visible: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
console.log(props.visible)
|
||||||
|
|
||||||
|
const showProtocol = computed({
|
||||||
|
get: () => props.visible,
|
||||||
|
set: (val) => emit('update:visible', val)
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update:visible': [boolean],
|
||||||
|
confirmPurchase: []
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const confirmPurchase = () => {
|
||||||
|
emit('confirmPurchase')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.protocol-popup {
|
||||||
|
width: 600rpx;
|
||||||
|
padding: 40rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
|
||||||
|
.protocol-title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.protocol-content {
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
font-size: 26rpx;
|
||||||
|
line-height: 1.8;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
|
||||||
|
text {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.protocol-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -20,10 +20,8 @@
|
|||||||
v-if="catalogueList.length > 0"
|
v-if="catalogueList.length > 0"
|
||||||
:catalogues="catalogueList"
|
:catalogues="catalogueList"
|
||||||
:userVip="userVip"
|
:userVip="userVip"
|
||||||
@getFreeCourse="handleGetFreeCourse"
|
|
||||||
@purchase="handlePurchase"
|
|
||||||
@toVip="goToVip"
|
@toVip="goToVip"
|
||||||
@renew="handleRenew"
|
@loadPageData="loadPageData"
|
||||||
@toDetail="handleToDetail"
|
@toDetail="handleToDetail"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -89,55 +87,14 @@
|
|||||||
/>
|
/>
|
||||||
</view> -->
|
</view> -->
|
||||||
|
|
||||||
<!-- 商品选择器 -->
|
|
||||||
<GoodsSelector
|
|
||||||
:show="showGoodsSelector"
|
|
||||||
:goods="goodsList"
|
|
||||||
:isFudu="isFudu"
|
|
||||||
@select="handleGoodsSelect"
|
|
||||||
@confirm="handleGoodsConfirm"
|
|
||||||
@close="closeGoodsSelector"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 购买协议弹窗 -->
|
|
||||||
<wd-popup v-model="showProtocol" position="center">
|
|
||||||
<view class="protocol-popup">
|
|
||||||
<view class="protocol-title">温馨提示</view>
|
|
||||||
<view class="protocol-content">
|
|
||||||
<text>
|
|
||||||
用户您好,本软件对于一个用户名及密码仅允许一部电子设备登陆,多部设备使用同一用户名操作软件的行为属于违规操作,发现违规一次将提出警告,再次违规您的用户名将被封号,无法正常登陆,如因此对您使用带来不便,敬请谅解。
|
|
||||||
</text>
|
|
||||||
<text>
|
|
||||||
课程购买之后一年内不打开,此一年内不会计算有效学习时间,一年后会自动开始计算有效学习时间。
|
|
||||||
</text>
|
|
||||||
<text>
|
|
||||||
本课程一经购买,暂不支持退款,敬请谅解。
|
|
||||||
</text>
|
|
||||||
<view style="color: red; font-weight: bold"> 注: </view>
|
|
||||||
<view>
|
|
||||||
1.手机、pad、电脑均为可登陆电子设备,均有唯一标识码,一个用户名仅允许在一个手机或一个ipad或一个电脑登陆,请根据您的使用习惯自行选择。<br />
|
|
||||||
2.如若申请变更登陆设备请联系客服,<br />
|
|
||||||
客服电话:021-08371305<br />
|
|
||||||
客服微信号:yilujiankangkefu<br />
|
|
||||||
3.如因违反上述使用规定...概不退款,本公司保留追究用户相关法律责任的权利。<br />
|
|
||||||
4.点击“同意”按钮即表示您同意遵守以上条款。
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="protocol-actions">
|
|
||||||
<wd-button type="info" plain @click="showProtocol = false">不同意</wd-button>
|
|
||||||
<wd-button type="primary" @click="confirmPurchase">同意</wd-button>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</wd-popup>
|
|
||||||
|
|
||||||
<!-- 评论编辑器 -->
|
<!-- 评论编辑器 -->
|
||||||
<CommentEditor
|
<!-- <CommentEditor
|
||||||
:show="showEditor"
|
:show="showEditor"
|
||||||
:parentComment="replyComment"
|
:parentComment="replyComment"
|
||||||
type="course"
|
type="course"
|
||||||
@submit="handleCommentSubmit"
|
@submit="handleCommentSubmit"
|
||||||
@close="closeCommentEditor"
|
@close="closeCommentEditor"
|
||||||
/>
|
/> -->
|
||||||
|
|
||||||
<!-- 返回顶部 -->
|
<!-- 返回顶部 -->
|
||||||
<wd-backtop :scrollTop="scrollTop" custom-class="back-top">
|
<wd-backtop :scrollTop="scrollTop" custom-class="back-top">
|
||||||
@@ -153,7 +110,6 @@ import { useUserStore } from '@/stores/user'
|
|||||||
import { courseApi } from '@/api/modules/course'
|
import { courseApi } from '@/api/modules/course'
|
||||||
import CourseInfo from './components/CourseInfo.vue'
|
import CourseInfo from './components/CourseInfo.vue'
|
||||||
import CatalogueList from './components/CatalogueList.vue'
|
import CatalogueList from './components/CatalogueList.vue'
|
||||||
import GoodsSelector from '@/components/order/GoodsSelector.vue'
|
|
||||||
import CommentList from '@/components/comment/CommentList.vue'
|
import CommentList from '@/components/comment/CommentList.vue'
|
||||||
import CommentEditor from '@/components/comment/CommentEditor.vue'
|
import CommentEditor from '@/components/comment/CommentEditor.vue'
|
||||||
import type { ICourseDetail, ICatalogue, IChapter, IVipInfo } from '@/types/course'
|
import type { ICourseDetail, ICatalogue, IChapter, IVipInfo } from '@/types/course'
|
||||||
@@ -172,14 +128,6 @@ const vipModuleList = ref<string[]>([])
|
|||||||
const learningProgress = ref(0)
|
const learningProgress = ref(0)
|
||||||
const relatedBooks = ref<IGoods[]>([])
|
const relatedBooks = ref<IGoods[]>([])
|
||||||
|
|
||||||
// 商品选择
|
|
||||||
const showGoodsSelector = ref(false)
|
|
||||||
const goodsList = ref<IGoods[]>([])
|
|
||||||
const selectedGoods = ref<IGoods | null>(null)
|
|
||||||
const showProtocol = ref(false)
|
|
||||||
const isFudu = ref(false)
|
|
||||||
const fuduCatalogueId = ref<number>(0)
|
|
||||||
|
|
||||||
// 评论相关
|
// 评论相关
|
||||||
const commentList = ref<IComment[]>([])
|
const commentList = ref<IComment[]>([])
|
||||||
const commentsLoading = ref(false)
|
const commentsLoading = ref(false)
|
||||||
@@ -301,92 +249,6 @@ const goToVip = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 领取免费课程
|
|
||||||
*/
|
|
||||||
const handleGetFreeCourse = async (catalogue: ICatalogue) => {
|
|
||||||
if (!catalogue) return
|
|
||||||
|
|
||||||
const res = await courseApi.startStudyForMF(catalogue.id)
|
|
||||||
if (res.code === 0) {
|
|
||||||
uni.showToast({ title: '领取成功', icon: 'success' })
|
|
||||||
// 刷新页面数据
|
|
||||||
loadPageData()
|
|
||||||
} else {
|
|
||||||
uni.showToast({ title: res.msg || '领取失败', icon: 'none' })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 购买课程
|
|
||||||
*/
|
|
||||||
const handlePurchase = async (catalogue: ICatalogue) => {
|
|
||||||
if (!catalogue) return
|
|
||||||
|
|
||||||
isFudu.value = false
|
|
||||||
const res = await courseApi.getProductListForCourse(catalogue.id)
|
|
||||||
if (res.code === 0 && res.productList.length > 0) {
|
|
||||||
goodsList.value = res.productList
|
|
||||||
showGoodsSelector.value = true
|
|
||||||
} else {
|
|
||||||
uni.showToast({ title: '此课程暂无购买方式', icon: 'none' })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 续费/复读
|
|
||||||
*/
|
|
||||||
const handleRenew = async () => {
|
|
||||||
// if (!currentCatalogue.value) return
|
|
||||||
|
|
||||||
// isFudu.value = true
|
|
||||||
// fuduCatalogueId.value = currentCatalogue.value.id
|
|
||||||
// const res = await courseApi.getRenewProductList(currentCatalogue.value.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
|
|
||||||
showProtocol.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关闭商品选择器
|
|
||||||
*/
|
|
||||||
const closeGoodsSelector = () => {
|
|
||||||
showGoodsSelector.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 确认购买协议
|
|
||||||
*/
|
|
||||||
const confirmPurchase = () => {
|
|
||||||
showProtocol.value = false
|
|
||||||
if (!selectedGoods.value) return
|
|
||||||
|
|
||||||
showProtocol.value = false
|
|
||||||
|
|
||||||
// 跳转到确认订单页
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `/pages/order/goodsConfirm?goods=${selectedGoods.value.productId}`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跳转到书籍详情
|
* 跳转到书籍详情
|
||||||
*/
|
*/
|
||||||
@@ -740,40 +602,6 @@ onReachBottom(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.protocol-popup {
|
|
||||||
width: 600rpx;
|
|
||||||
padding: 40rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
|
|
||||||
.protocol-title {
|
|
||||||
font-size: 32rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #333;
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 30rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.protocol-content {
|
|
||||||
max-height: 60vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
font-size: 26rpx;
|
|
||||||
line-height: 1.8;
|
|
||||||
color: #666;
|
|
||||||
margin-bottom: 30rpx;
|
|
||||||
|
|
||||||
text {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.protocol-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 20rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.back-top) {
|
:deep(.back-top) {
|
||||||
background-color: #fff !important;
|
background-color: #fff !important;
|
||||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
|||||||
@@ -91,15 +91,23 @@ const orderType = computed(() => {
|
|||||||
* 页面加载
|
* 页面加载
|
||||||
*/
|
*/
|
||||||
onLoad(async (options: any) => {
|
onLoad(async (options: any) => {
|
||||||
if (options.goods) {
|
|
||||||
try {
|
try {
|
||||||
|
if (options.isRelearn == 1) {
|
||||||
|
uni.$on('selectedGoods', async (data: IOrderGoods) => {
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
await getUserInfo()
|
await getUserInfo()
|
||||||
|
|
||||||
|
// 处理商品数据
|
||||||
|
console.log('监听到传入的商品数据:', data)
|
||||||
|
goodsList.value = [ data ]
|
||||||
|
})
|
||||||
|
} else if (options.goods) {
|
||||||
|
// 获取用户信息
|
||||||
|
await getUserInfo()
|
||||||
// 根据商品ID获取商品详细信息
|
// 根据商品ID获取商品详细信息
|
||||||
goodsIds.value = options.goods || ''
|
goodsIds.value = options.goods || ''
|
||||||
isRelearn.value = options.isRelearn == '1'
|
|
||||||
getGoodsList()
|
getGoodsList()
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('解析商品数据失败:', error)
|
console.error('解析商品数据失败:', error)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -107,7 +115,6 @@ onLoad(async (options: any) => {
|
|||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -56,10 +56,10 @@ const orderType = ref<string>('')
|
|||||||
/**
|
/**
|
||||||
* 页面加载
|
* 页面加载
|
||||||
*/
|
*/
|
||||||
onLoad(async () => {
|
onLoad(() => {
|
||||||
try {
|
try {
|
||||||
// 获取商品列表
|
// 获取商品列表
|
||||||
await uni.$on('selectedGoods', async (data: IOrderGoods) => {
|
uni.$on('selectedGoods', async (data: IOrderGoods) => {
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
await getUserInfo()
|
await getUserInfo()
|
||||||
|
|
||||||
|
|||||||
@@ -255,7 +255,7 @@
|
|||||||
$theme-color: #54a966;
|
$theme-color: #54a966;
|
||||||
|
|
||||||
.user-page {
|
.user-page {
|
||||||
min-height: 100vh;
|
min-height: calc(100vh - 50px);
|
||||||
background-color: #f7faf9;
|
background-color: #f7faf9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,20 @@
|
|||||||
<!-- 自定义导航栏 -->
|
<!-- 自定义导航栏 -->
|
||||||
<nav-bar :title="$t('user.dataMigrate')"></nav-bar>
|
<nav-bar :title="$t('user.dataMigrate')"></nav-bar>
|
||||||
|
|
||||||
<view class="text-red-500 text-center mb-[20rpx]! font-bold">{{ $t('user.migrateWarning') }}</view>
|
<view v-if="!!migrateInfo.notMigration" class="text-center mb-[20rpx]!">
|
||||||
|
<view v-if="!!migrateInfo.alreadyMigration">{{ $t('user.alreadyMigrated') }}{{ migrateInfo.alreadyMigration }}</view>
|
||||||
|
<view>{{ $t('user.notMigration') }}<text class="font-bold">{{ migrateInfo.notMigration }}</text></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-else class="text-center mb-[20rpx]! bg-white p-[20rpx] rounded-[10rpx] shadow-[0_4rpx_12rpx_rgba(0,0,0,0.05)]">
|
||||||
|
<wd-text :text="$t('user.migratedCompleted')" type="warning" />
|
||||||
|
<wd-text :text="migrateInfo.alreadyMigration" type="warning" bold />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="!!migrateInfo.notMigration" class="text-red-500 text-center mb-[20rpx]! font-bold">{{ $t('user.migrateWarning') }}</view>
|
||||||
|
|
||||||
<!-- 主要内容区域 -->
|
<!-- 主要内容区域 -->
|
||||||
<wd-form ref="migrateForm" :model="formData" :rules="rules" :label-width="120" class="migrate-card p-[10rpx]">
|
<wd-form v-if="!!migrateInfo.notMigration" ref="migrateForm" :model="formData" :rules="rules" :label-width="120" class="migrate-card p-[10rpx]">
|
||||||
<wd-cell-group border>
|
<wd-cell-group border>
|
||||||
<wd-input
|
<wd-input
|
||||||
v-model="formData.tel"
|
v-model="formData.tel"
|
||||||
@@ -60,22 +70,40 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { t } from '@/utils/i18n'
|
import { t } from '@/utils/i18n'
|
||||||
import { migrateUserData } from '@/api/modules/user'
|
import { migrateUserData, getUserMigrateInfo } from '@/api/modules/user'
|
||||||
import { useMessage } from '@/uni_modules/wot-design-uni'
|
import { useMessage } from '@/uni_modules/wot-design-uni'
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
|
||||||
|
const migrateInfo = ref({
|
||||||
|
alreadyMigration: '',
|
||||||
|
notMigration: ''
|
||||||
|
})
|
||||||
|
|
||||||
// 表单引用
|
// 表单引用
|
||||||
const migrateForm = ref()
|
const migrateForm = ref()
|
||||||
|
|
||||||
// 表单数据
|
// 表单数据
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
tel: '',
|
tel: '',
|
||||||
code: ''
|
code: '',
|
||||||
|
type: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 获取用户迁移信息
|
||||||
|
const getMigrateInfo = async () => {
|
||||||
|
const res = await getUserMigrateInfo()
|
||||||
|
migrateInfo.value.alreadyMigration = res.alreadyMigration
|
||||||
|
// migrateInfo.value.notMigration = res.notMigration
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
getMigrateInfo()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 表单验证规则
|
// 表单验证规则
|
||||||
const rules = ref({
|
const rules = ref({
|
||||||
tel: [
|
tel: [
|
||||||
@@ -113,6 +141,7 @@ const handleSubmit = async () => {
|
|||||||
}
|
}
|
||||||
// 处理迁移
|
// 处理迁移
|
||||||
const submitMigrate = async () => {
|
const submitMigrate = async () => {
|
||||||
|
formData.value.type = migrateInfo.value.notMigration
|
||||||
await migrateUserData(formData.value)
|
await migrateUserData(formData.value)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: t('user.migrateSuccess'),
|
title: t('user.migrateSuccess'),
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
|
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
|
||||||
"Courier New", monospace;
|
"Courier New", monospace;
|
||||||
--color-red-500: oklch(63.7% 0.237 25.331);
|
--color-red-500: oklch(63.7% 0.237 25.331);
|
||||||
|
--color-white: #fff;
|
||||||
--spacing: 0.25rem;
|
--spacing: 0.25rem;
|
||||||
--text-xs: 0.75rem;
|
--text-xs: 0.75rem;
|
||||||
--text-xs--line-height: calc(1 / 0.75);
|
--text-xs--line-height: calc(1 / 0.75);
|
||||||
@@ -265,16 +266,25 @@
|
|||||||
.flex-wrap {
|
.flex-wrap {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
.rounded-\[10rpx\] {
|
||||||
|
border-radius: 10rpx;
|
||||||
|
}
|
||||||
.border {
|
.border {
|
||||||
border-style: var(--tw-border-style);
|
border-style: var(--tw-border-style);
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
}
|
}
|
||||||
|
.bg-white {
|
||||||
|
background-color: var(--color-white);
|
||||||
|
}
|
||||||
.p-0\! {
|
.p-0\! {
|
||||||
padding: calc(var(--spacing) * 0) !important;
|
padding: calc(var(--spacing) * 0) !important;
|
||||||
}
|
}
|
||||||
.p-\[10rpx\] {
|
.p-\[10rpx\] {
|
||||||
padding: 10rpx;
|
padding: 10rpx;
|
||||||
}
|
}
|
||||||
|
.p-\[20rpx\] {
|
||||||
|
padding: 20rpx;
|
||||||
|
}
|
||||||
.p-\[30rpx\] {
|
.p-\[30rpx\] {
|
||||||
padding: 30rpx;
|
padding: 30rpx;
|
||||||
}
|
}
|
||||||
@@ -337,6 +347,10 @@
|
|||||||
--tw-ordinal: ordinal;
|
--tw-ordinal: ordinal;
|
||||||
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
|
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
|
||||||
}
|
}
|
||||||
|
.shadow-\[0_4rpx_12rpx_rgba\(0\,0\,0\,0\.05\)\] {
|
||||||
|
--tw-shadow: 0 4rpx 12rpx var(--tw-shadow-color, rgba(0,0,0,0.05));
|
||||||
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||||
|
}
|
||||||
.ring {
|
.ring {
|
||||||
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||||
|
|||||||
@@ -116,3 +116,15 @@ export interface IPageData<T> {
|
|||||||
pages: number
|
pages: number
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单接口
|
||||||
|
*/
|
||||||
|
export interface IOrder {
|
||||||
|
id: number
|
||||||
|
orderType: string // 订单类型
|
||||||
|
changeAmount: number
|
||||||
|
remark: string
|
||||||
|
createTime: string
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user