当前位置: 首页 > news >正文

JP4-8-MyLesson前台前端(二)

Java道经 - 项目 - MyLesson - 前台前端(二)

文章目录

  • S03. 导航栏 - 课程
    • E01. 课程列表
    • E02. 课程详情
      • 1. 智能客服
  • S04. 导航栏 - 购物车
    • E01. 购物车模块

S03. 导航栏 - 课程

心法:本模块包含课程列表页面和课程详情页面,这两个页面均不需要用户登录即可访问。

课程列表:课程列表是导航页面,当用户点击底部导航栏 “课程” 按钮时进行分页展示全部课程列表。

课程详情:当点击课程列表中的某个具体课程封面时,跳转到对应该课程的详情页面。

E01. 课程列表

心法:当用户点击底部选项卡 “课程” 的时候,跳转到课程列表页面,页面加载后,向后台请求课程列表(ElasticSearch 数据库)并渲染到页面,出于性能考虑,页面默认显示 12 条课程数据,当滚动条触底时,进行下一次分页查询(再查 12 条)。

页面要素(自上而下)描述
搜索框用户可通过课程名称或者作者名称进行分词搜索
课程列表向后台请求课程列表(ElasticSearch 数据库)并渲染到页面

图示如下

在这里插入图片描述

武技:开发课程列表相关页面。

  1. 开发 pages/course/course.json 文件:
{"usingComponents": {"van-sticky": "@vant/weapp/sticky/index","van-search": "@vant/weapp/search/index","van-divider": "@vant/weapp/divider/index","van-grid": "@vant/weapp/grid/index","van-grid-item": "@vant/weapp/grid-item/index","van-image": "@vant/weapp/image/index","van-icon": "@vant/weapp/icon/index","van-rate": "@vant/weapp/rate/index"}
}
  1. 开发 pages/course/course.wxml 文件:
<van-sticky><van-search class="search-ipt"value="{{keyword}}"bind:search="searchByKeyword"bind:clear="cancelSearch"background="#252a34"shape="round"clear-trigger="always"input-align="center"placeholder="请输入课程标题进行搜索"/>
</van-sticky>
<scroll-view class="course-list"bindscrolltolower="onListEnd"scroll-y="true"><van-divider contentPosition="center" dashed>课程列表</van-divider><van-grid class="course-list-grid"column-num="2"gutter="20rpx"><van-grid-item content-class="course-item"wx:for="{{courses}}"wx:key="id"data-course-id="{{item['id']}}"bind:tap="showDetail"use-slot><van-image src="{{MINIO_COURSE_COVER}}/{{item['cover']}}" width="300rpx" height="200rpx"/><view class="title">{{ item['title'] }}</view><view class="info"><view><van-icon name="user-o"/>作者: {{item['author']}}</view><view><van-icon name="gold-coin-o"/>价格: {{item['price']}} 元</view></view></van-grid-item></van-grid><van-divider contentPosition="center" dashed>没有更多课程了</van-divider>
</scroll-view>
<view class="baseline"><van-divider contentPosition="center" dashed>底线</van-divider>
</view>
  1. 开发 pages/course/course.scss 文件:
@import "app";.course-list {height: 90vh; // 高度.course-item {background-color: $black; // 背景色.title {font-weight: bold; // 加粗white-space: nowrap; // 不换行overflow: hidden; // 超出隐藏text-overflow: ellipsis; // 超出部分显示...color: $yellow; // 字体颜色font-size: 30rpx; // 字体大小margin-top: 10rpx; // 上边距margin-left: 20rpx; // 左边距margin-bottom: 20rpx; // 下边距text-align: left; // 文字左对齐width: 100%; // 宽度}.info {font-size: small; // 字体大小text-align: left; // 文字左对齐line-height: 40rpx; // 行高width: 100%; // 宽度margin-left: 20rpx; // 左边距}}
}
  1. 开发 pages/course/course.js 文件:
import util, {isNull} from '../../utils/util.js';
import api from "../../utils/api.js";
import constant from "../../utils/const.js";Page({data: {MINIO_COURSE_COVER: constant.MINIO_COURSE_COVER, // 课程封面路径pageInfo: {pageNum: 1, pageSize: 12, totalPage: 0, totalRow: 0}, // 分页信息courses: null, // 课程列表对象keyword: '', // 课程标题},// 分页搜索课程记录page: function () {let that = this;let keyword = this.data.keyword;let pageNum = isNull(this.data.pageInfo['pageNum']) ? 1 : this.data.pageInfo['pageNum'];let pageSize = isNull(this.data.pageInfo['pageSize']) ? 5 : this.data.pageInfo['pageSize'];// 搜索关键字不能超过42个字if (keyword.length > 42){util.error('搜索关键字过长');return;}// 请求数据let params = {pageNum, pageSize, keyword: keyword.trim()};api.search('course', '/search', params).then(res => {that.setData({'courses': pageNum === 1 ? res['records'] : that.data.courses.concat(res['records']),'pageInfo.pageNum': res['pageNum'],'pageInfo.pageSize': res['pageSize'],'pageInfo.totalPage': res['totalPage'],'pageInfo.totalRow': res['totalRow'],});}).catch(err => console.error(err));},// 列表触底时onListEnd: function () {let that = this;let pageNum = that.data.pageInfo['pageNum'];let totalPage = that.data.pageInfo['totalPage'];if (pageNum < totalPage) {this.setData({'pageInfo.pageNum': pageNum + 1});this.page();}},// 按课程标题搜索课程searchByKeyword: function (ev) {this.setData({'keyword': ev.detail,'pageInfo.pageNum': 1,});this.page();},// 取消搜索cancelSearch: function (ev) {this.setData({'keyword': '','pageInfo.pageNum': 1,});this.page();},// 查看课程详情showDetail: function (ev) {let courseId = ev.currentTarget.dataset['courseId'];util.page('/pages/course/detail/detail?courseId=' + courseId, false);},// 加载函数onLoad: function (options) {this.page();this.getTabBar().setData({"activeTab": 1});}
});

E02. 课程详情

心法:当用户在课程列表界面点击某个课程封面时,会跳转到对应的课程详情页面。

页面要素(自上而下)描述
视频组件点击可播放当前课程的第一章第一集的视频内容
课程详情列表展示当前课程的详情,如类别,标题,作者,价格等
课程摘要选项卡,点击可展示课程摘要图片
课程目录选项卡,点击可展示课程章集目录
客服按钮点击跳入 AI 客服页面
购物车按钮点击跳入购物车选项卡
加入购物车按钮点击将当前课程加入我的购物车列表
立即购买按钮点击立刻购买该课程

图示如下

在这里插入图片描述
在这里插入图片描述

武技:开发课程详情相关页面。

  1. 开发 pages/course/detail/detail.json 文件:
{"usingComponents": {"van-sticky": "@vant/weapp/sticky/index","van-divider": "@vant/weapp/divider/index","van-cell-group": "@vant/weapp/cell-group/index","van-cell": "@vant/weapp/cell/index","van-tabs": "@vant/weapp/tabs/index","van-tab": "@vant/weapp/tab/index","van-rate": "@vant/weapp/rate/index","van-image": "@vant/weapp/image/index","van-goods-action": "@vant/weapp/goods-action/index","van-goods-action-icon": "@vant/weapp/goods-action-icon/index","van-goods-action-button": "@vant/weapp/goods-action-button/index","van-empty": "@vant/weapp/empty/index"}
}
  1. 开发 pages/course/detail/detail.wxml 文件:
<van-sticky><video class="free-video"wx:if="{{videoSrc && videoPoster}}"src="{{videoSrc}}"title="{{videoTitle}}"poster="{{videoPoster}}"danmu-list="{{welcomeBarrage}}"controlsshow-mute-btnenable-danmudanmu-btn/><van-empty class="free-video-empty"wx:elseimage="error"description="暂无免费视频"/>
</van-sticky>
<view class="course-info"wx:if="{{course}}"><van-divider contentPosition="center" dashed>课程详情</van-divider><van-cell-group inset><van-cell title="课程类别" value="{{course['category']['title']}}" icon="flag-o"/><van-cell title="课程标题" value="{{course['title']}}" icon="notes-o"/><van-cell title="课程作者" value="{{course['author']}}" icon="user-o"/><van-cell title="创建日期" value="{{course['created']}}" icon="clock-o"/><van-cell title="更新日期" value="{{course['updated']}}" icon="clock-o"/><van-cell title="课程价格" value="{{course['price'] + ''}}" icon="cash-o"/><van-cell title="课程简介" value="{{course['info']}}" icon="font-o"/></van-cell-group>
</view>
<view class="operation-tabs"><van-tabs active="{{activeTab}}"color="orange"type="card"animatedtab-class="tab"><van-tab title="课程摘要" name="摘要"><view class="summary"wx:if="{{course['summary']}}"><van-image src="{{MINIO_COURSE_SUMMARY}}{{course['summary']}}"width="100%"fit="widthFix"/></view><van-empty class="summary-empty"wx:elseimage="error"description="暂无摘要图片"/><view class="baseline"><van-divider contentPosition="center" dashed>底线</van-divider></view></van-tab><van-tab title="课程目录" name="目录"><view class="catalog"wx:if="{{course['seasons'].length > 0}}"><view wx:for="{{course['seasons']}}"wx:key="id"wx:for-item="season"wx:for-index="si"><van-cell-group title="{{'' + (si + 1) + '季:' + season['title']}}"><view wx:if="{{season['episodes'].length > 0}}"><van-cell wx:for="{{season['episodes']}}"wx:key="id"wx:for-item="episode"wx:for-index="ei"title="{{'' + (ei + 1) + '集:' + episode['title']}}"use-label-slot><view slot="label" class="van-multi-ellipsis--l2">{{episode['info']}}</view></van-cell></view></van-cell-group></view><view class="baseline"><van-divider contentPosition="center" dashed>底线</van-divider></view></view><van-empty class="catalog-empty"wx:elseimage="error"description="该课程暂无季次信息,请联系运维人员。"/></van-tab></van-tabs>
</view>
<view class="detail-foot"><van-goods-action><van-goods-action-icon text="客服" bind:click="chatMe" icon="chat-o"/><van-goods-action-icon text="购物车" bind:click="toCart" icon="cart-o"/><van-goods-action-button text="加入购物车" bind:click="addToCart" type="warning"/><van-goods-action-button text="立即购买" bind:click="pay"/></van-goods-action>
</view>
  1. 开发 pages/course/detail/detail.scss 文件:
@import "app";.free-video {video {width: 98%; // 宽度outline: 10rpx solid $black; // 轮廓box-sizing: border-box; // 边框}
}.course-info {.van-cell {background-color: $bg-gray; // 背景色color: $yellow; // 文字颜色.van-cell__title {text-align: left; // 文字对齐方式}.van-cell__value {color: $white; // 文字颜色}}
}.operation-tabs {height: 80vh; // 高度margin: 20rpx 30rpx; // 外边距.van-tab {color: $subBlack !important; // 文字颜色font-weight: bold !important; // 字体粗细}.summary {padding-top: 20rpx; // 内边距}.catalog {padding-top: 20rpx; // 内边距padding-bottom: 150rpx; // 内边距.van-cell-group__title {color: $black; // 文字颜色font-weight: bold; // 字体粗细background: $yellow; // 背景色padding-bottom: 15px; // 内边距}.van-cell {color: $white; // 文字颜色background: $black; // 背景色text-align: left !important; // 文字对齐方式}}
}
  1. 开发 pages/course/detail/detail.js 文件:
import api from '../../../utils/api.js';
import util from '../../../utils/util.js';
import constant from "../../../utils/const.js";Page({data: {MINIO_COURSE_SUMMARY: constant.MINIO_COURSE_SUMMARY, // 视频封面MINIO地址course: null, // 课程对象videoSrc: null, // 免费视频地址videoPoster: null, // 免费视频封面videoTitle: null, // 免费视频标题welcomeBarrage: [{text: '一大波弹幕即将来袭', color: '#ff0000', time: 1}], // 欢迎弹幕activeTab: '摘要' // 当前选中的tab的name值},// 查询视频详情getCourseInfo: function (courseId) {let that = this;let param = '/select/' + courseId;api.get('course', param).then(res => {res['created'] = util.dateFormat(res['created']);res['updated'] = util.dateFormat(res['updated']);if (res['seasons'].length > 0 && res['seasons'][0]['episodes'].length > 0) {let firstEpisode = res['seasons'][0]['episodes'][0];that.setData({'videoSrc': constant.MINIO_EPISODE_VIDEO + firstEpisode['video'],'videoPoster': constant.MINIO_EPISODE_VIDEO_COVER + firstEpisode['cover'],'videoTitle': firstEpisode['title'],});}that.setData({'course': res});}).catch(err => console.error(err));},// 跳转到购物车页面toCart: function () {if (util.isLogin()) {util.tab('/pages/cart/cart');}},// 添加购物车addToCart: function () {if (util.isLogin()) {let that = this;let params = {'fkUserId': wx.getStorageSync('user').id,"fkCourseId": that.data.course['id'],};api.post('cart', '/insert', params).then(res => {util.error('加购成功');setTimeout(() => {util.tab('/pages/cart/cart', true);}, 500);}).catch(err => console.error(err))}},// 客服chatMe: function () {util.page('/pages/course/detail/chat/chat')},// 立即购买pay: function () {if (util.isLogin()) {util.error('功能暂未开放');}},// 加载函数onLoad: function (ev) {// 查询视频详情:获取路径传递过来的值this.getCourseInfo(ev['courseId']);}
});

1. 智能客服

心法:当用户在课程详情左下角点击客服图标时跳转到本页面。

页面要素(自上而下)描述
对话框显示用户和智能客服的对话内容
输入框采集用户问题
提问按钮请求后台智能客服的回复内容并渲染在对话框中

图示如下

在这里插入图片描述

武技:开发智能客服页面。

  1. 开发 pages/course/detail/chat/chat.json 文件:
{"usingComponents": {"van-field": "@vant/weapp/field/index","van-button": "@vant/weapp/button/index","van-steps": "@vant/weapp/steps/index"}
}
  1. 开发 pages/course/detail/chat/chat.wxml 文件:
<scroll-view class="chat-board"scroll-top="{{scrollTop}}" scroll-y="{{true}}"><van-steps custom-class="chat-dialog"id="chatDialog" steps="{{ steps }}" active="{{ active }}"direction="vertical" active-color="#f9ed69" desc-class="desc"/>
</scroll-view>
<view class="tips">{{isReplying ? '客服回复中...' : '回复完毕'}}
</view>
<van-field custom-class="chat-textarea"value="{{ message }}" bindinput="changeMessage" type="textarea"maxlength="{{500}}" show-word-limit="{{true}}" autosize border="{{false}}" placeholder="请输入你的问题"/>
<van-button custom-class="submit-btn"bind:tap="sendMessage"type="info" block>提问
</van-button>
  1. 开发 pages/course/detail/chat/chat.scss 文件:
@import "app";.chat-board {height: 1000rpx; // 高度text-align: left; // 文本对齐方式margin: 20rpx auto 50rpx; // 外边距.chat-dialog {background-color: $bg-gray; // 背景色.van-step:nth-child(even) {text-align: right; // 文本对齐方式}.van-step--finish {color: $white; // 字体颜色}.desc {margin-top: 20rpx; // 上边距font-size: larger; // 字体大小font-weight: bolder; // 字体粗细line-height: 1.5; // 行高}}
}.tips {font-size: smaller; // 字体大小text-align: right; // 文本对齐方式margin-right: 30rpx; // 右边距color: $gray; // 字体颜色
}.chat-textarea {border: 3rpx solid $black; // 边框width: auto !important; // 宽度margin: 20rpx; // 外边距;border-radius: 15rpx; // 圆角;background-color: $bg-gray !important; // 背景色
}.van-field__control {color: $white !important; // 字体颜色height: 100rpx !important; // 高度
}.submit-btn {width: auto !important; // 宽度margin: 20rpx; // 外边距;font-size: large; // 字体大小border-radius: 15rpx; // 圆角
}
  1. 开发 pages/course/detail/chat/chat.js 文件:
import util from "../../../../utils/util.js";Page({data: {message: '一首李白的诗', // 用户输入的问题active: 0, // 当前激活的步骤steps: [{text: `${util.dateFormat(new Date())}`,desc: '你好,有什么可以帮助您?'}],sseServerUrl: 'http://localhost:5900/api/v1/base/chat', // SSE服务端地址isReplying: false, // AI是否正在回复中scrollTop: 0 // 滚动条位置},// 当内容改变时触发changeMessage: function (ev) {this.setData({'message': ev.detail});},// 发送消息sendMessage: function () {let that = this;// 如果AI正在回复中或用户输入的内容为空,均不处理if (this.data.isReplying || util.isEmpty(this.data.message)) return;// 加入用户输入的信息this.data.steps.push({text: `${util.dateFormat(new Date())}`,desc: this.data.message});// 加入AI回复的信息this.data.steps.push({text: `${util.dateFormat(new Date())}`,desc: 'waiting...'});// 更新聊天框this.setData({steps: this.data.steps,active: this.data.active + 2,isReplying: true});// 发送请求并接收分块响应的消息wx.request({url: this.data.sseServerUrl + '?msg=' + this.data.message,enableChunked: true // 启用分块传输}).onChunkReceived((res) => {// 获取当前AI回复的信息let desc = that.data.steps[that.data.active]['desc'];// 如果当前AI回复的信息是 "waiting...",则移除它if (desc === 'waiting...') {that.data.steps[that.data.active]['desc'] = desc.replaceAll('waiting...', '');}// AI回复的信息类型固定为arrayBuffer,需要开发者自己进行转换为字符串let str = new TextDecoder('utf-8').decode(res.data, {stream: true});// 移除 "data:"str = str.replaceAll('data:', '').trim();// 如果不是 "[over]",则拼接AI回复的信息if (!str.includes('[over]')) {that.data.steps[that.data.active]['desc'] += str;// 更新that.setData({steps: that.data.steps});}// 否则,AI回复完毕else {// 更新that.setData({isReplying: false});}// 滚动到底部const query = wx.createSelectorQuery().in(this);query.select('#chatDialog').boundingClientRect((rect) => {if (rect) this.setData({scrollTop: rect.height});}).exec();});// 清空用户输入的内容that.setData({'message': ''});},onLoad: function (options) {}
});

S04. 导航栏 - 购物车

心法:本模块包含购物车列表页面,该页面必须用户登录才可访问。

E01. 购物车模块

心法:以下几种情况,均会跳入到购物车选项卡:

  1. 当用户在课程详情页面点击 “添加购物车” 按钮时。
  2. 当用户在课程详情页面点击底部购物车图标时。
  3. 当用户在小程序底部直接点击购物车图标时。
页面要素(自上而下)描述
优惠卷兑换框用户可通过口令兑换优惠卷,可使用 twgdh 测试
清空购物车按钮向后台请求清空用户的全部购物车记录
购物车列表展示用户的全部购物车记录
购物提示提示用户虚拟物品不退不换
优惠卷详情按钮点击弹出当前使用的优惠卷
合计价格提示前端根据用户选择的购物车记录和优惠卷自动计算总金额
提交订单按钮向后台请求结算,将当前选中的全部购物车记录进行统一支付

图示如下

在这里插入图片描述
在这里插入图片描述

  1. 开发 pages/cart/cart.json 文件:
{"usingComponents": {"van-search": "@vant/weapp/search/index","van-divider": "@vant/weapp/divider/index","van-swipe-cell": "@vant/weapp/swipe-cell/index","van-button": "@vant/weapp/button/index","van-card": "@vant/weapp/card/index","van-icon": "@vant/weapp/icon/index","van-submit-bar": "@vant/weapp/submit-bar/index","van-action-sheet": "@vant/weapp/action-sheet/index","van-count-down": "@vant/weapp/count-down/index","van-dialog": "@vant/weapp/dialog/index","van-tag": "@vant/weapp/tag/index","van-cell-group": "@vant/weapp/cell-group/index","van-cell": "@vant/weapp/cell/index","van-radio-group": "@vant/weapp/radio-group/index","van-radio": "@vant/weapp/radio/index","van-field": "@vant/weapp/field/index","van-image": "@vant/weapp/image/index","van-row": "@vant/weapp/row/index","van-col": "@vant/weapp/col/index","van-checkbox": "@vant/weapp/checkbox/index","van-checkbox-group": "@vant/weapp/checkbox-group/index","van-empty": "@vant/weapp/empty/index"}
}
  1. 开发 pages/cart/cart.wxml 文件:
<view class="search-coupons"><van-search class="search-coupons-ipt"value="{{couponsCode}}"bind:search="getCoupons"background="#252a34"shape="round"clear-trigger="always"input-align="center"placeholder="请输入口令兑换优惠卷"/>
</view>
<scroll-view class="cart-list"wx:if="{{carts && carts.length > 0}}"bindscrolltolower="pageMore"scroll-y="true"><van-divider class="clear-cart-divider"bind:tap="clearCart"contentPosition="right"dashed><van-icon name="delete-o"/><text>清空购物车</text></van-divider><van-checkbox-group class="cart-card-group"value="{{ courseIds }}"bind:change="changeCourseIds"><van-swipe-cell class="cart-card-cell"wx:for="{{carts}}"wx:key="id"right-width="{{ 55 }}"><van-card class="cart-card"title="{{item['courseTitle']}}"price="{{item['coursePrice']}} 元"origin-price="{{item['coursePrice'] / 0.8}} 元"tag="热卖"desc="精品课程【爆款】【热卖】"><view slot="thumb"><van-row><van-col span="8"><van-checkbox class="cart-cbx"name="{{item['fkCourseId']}}"data-price="{{item['coursePrice']}}"/></van-col><van-col span="8"><van-image class="cart-image"src="{{MINIO_COURSE_COVER}}/{{item['courseCover']}}"bind:tap="showDetail"data-course-id="{{item['fkCourseId']}}"width="130"height="90"/></van-col></van-row></view></van-card><view class="cart-card-right-slot" slot="right"><van-button class="remove-btn"bind:tap="removeCart"data-id="{{item['id']}}"type="danger"><view></view><view></view></van-button></view></van-swipe-cell></van-checkbox-group>
</scroll-view>
<van-empty class="cart-list-empty"wx:elseimage="error"description="暂无购物车记录"/>
<view class="submit-order"><van-submit-bar custom-class="submit-bar"price="{{ payAmount * 100 }}"bind:submit="openPayDialog"button-text="提交订单"tip="{{ true }}"><van-tag class="coupons-btn"bind:tap="openCouponsSheet"type="warning">优惠卷详情</van-tag><view slot="tip">课程属于虚拟产品,购买后不支持退换!</view></van-submit-bar>
</view>
<van-action-sheet class="coupons-sheet"title="优惠卷详情"show="{{ couponsShow }}"bind:close="closeCouponsSheet"><van-cell-group class="coupons-sheet-body"wx:if="{{coupons['id']}}"inset><van-cell title="兑换口令"value="{{coupons['code']}}"icon="gift-o"title-width="100rpx"/><van-cell title="标题名称"value="{{coupons['title']}}"icon="notes-o"title-width="100rpx"/><van-cell title="优惠金额"value="减免 {{coupons['cpPrice']}} 元"icon="coupon-o"title-width="100rpx"/><van-cell title="详情描述"value="{{coupons['info']}}"icon="comment-o"title-width="100rpx"/><van-cell title="生效时间"value="{{coupons['startTime']}}"icon="clock-o"title-width="100rpx"/><van-cell title="过期时间"value="{{coupons['endTime']}}"icon="clock-o"title-width="100rpx"/></van-cell-group><van-empty class="coupons-sheet-body-empty"wx:elseimage="error"description="暂未使用优惠卷"/>
</van-action-sheet>
<van-dialog class="pay-dialog" title="支付订单"show="{{ payDialogShow }}"show-confirm-button="{{false}}"use-slotwidth="400px"><van-divider dashed/><view class="countdown-time"><van-count-down class="pay-countdown" wx:if="{{countDownShow}}"time="{{ time }}"bind:change="countDown"bind:finish="onCountDownFinish"use-slot><view class="title">【请在15分钟内完成付款】</view><text class="item">{{ timeData.hours }}</text><text class="delimiter"></text><text class="item">{{ timeData.minutes }}</text><text class="delimiter"></text><text class="item">{{ timeData.seconds }}</text><text class="delimiter"></text></van-count-down></view><van-divider dashed/><view class="pay-dialog-label">支付宝扫码</view><van-image class="qrcode-image" src="{{qrCodeImage}}"width="300" height="200"/><van-divider dashed/><van-button class="cancel-btn" bind:click="cancelPay"block type="info">取消支付</van-button>
</van-dialog>
  1. 开发 pages/cart/cart.scss 文件:
@import "app";.cart-list {height: 75vh; // 高度.van-swipe-cell {margin: 10rpx; // 外边距.van-card {color: $yellow; // 文字颜色background: $bg-gray; // 背景颜色border: 1rpx solid $black; // 边框颜色text-align: left; // 文字对齐方式border-radius: 15rpx; // 圆角padding: 30rpx; // 内边距.van-card__thumb {width: 230rpx; // 宽度}.van-card__content {padding-left: 120rpx; // 内边距}.van-card__title {font-size: large; // 字号margin-bottom: 10rpx; // 下边距}.van-card__price {color: $orange; // 文字颜色}}.cart-card-right-slot, .van-button {height: 100%; // 高度font-size: large; // 字号line-height: 50rpx; // 行高border-radius: 15rpx; // 圆角background-color: $orange; // 背景颜色border: 0; // 边框}}.van-checkbox__icon {margin-top: 60rpx; // 上边距}.van-card__tag {left: 65rpx; // 左边距}
}.submit-order {.van-submit-bar, .van-action-sheet {margin-bottom: 100rpx; // 下边距}
}.pay-dialog {.van-popup {padding: 30rpx; // 内边距background-color: $bg-gray !important; // 背景颜色border: 10rpx solid $black !important; // 边框颜色}.countdown-time {.title, .delimiter {color: $yellow; // 文字颜色}.title {margin-bottom: 20rpx; // 下边距}.item {display: inline-block; // 显示方式width: 60rpx; // 宽度margin-right: 10rpx; // 右边距color: $white; // 文字颜色font-weight: bold; // 字体粗细text-align: center; // 文字对齐方式background-color: $black; // 背景颜色border-radius: 5rpx; // 圆角}}.pay-dialog-label {color: $orange; // 文字颜色text-align: center; // 文字对齐方式margin: 40rpx 0; // 外边距}
}
  1. 开发 pages/cart/cart.js 文件:
import util from "../../utils/util.js";
import api from "../../utils/api.js";
import constant, {GATEWAY_HOST} from "../../utils/const.js";Page({data: {couponsCode: '', // 优惠卷兑换口令coupons: {}, // 优惠卷对象totalAmount: 0.0, // 总金额payAmount: 0.0, // 应付金额couponsShow: false, // 是否显示优惠卷面板carts: null, // 购物车列表courseIdAndPrice: {}, // 存储课程id和对应价格的对象courseIds: [], // 存储课程id的数组MINIO_COURSE_COVER: constant.MINIO_COURSE_COVER, // 课程封面MINIO地址pageInfo: {pageNum: 1, pageSize: 8, totalPage: 0, totalRow: 0}, // 分页信息payDialogShow: false, // 是否显示支付对话框time: 15 * 60 * 1000, // 倒计时起始时间timeData: {}, // 倒计时数据countDownShow: false, // 是否显示倒计时qrCodeImage: '', // 二维码图片路径sn: '', // 订单流水号timer: null // 支付倒计时定时器},// 分页查询购物车记录page: function () {let that = this;let pageNum = that.data.pageInfo['pageNum'];let pageSize = that.data.pageInfo['pageSize'];let userId = wx.getStorageSync('user').id;let params = {pageNum: pageNum,pageSize: pageSize,'fkUserId': userId};api.get('cart', '/page', params).then(res => {that.setData({'carts': pageNum === 1 ? res['records'] : that.data.carts.concat(res['records']),'pageInfo.pageNum': res['pageNumber'],'pageInfo.pageSize': res['pageSize'],'pageInfo.totalPage': res['totalPage'],'pageInfo.totalRow': res['totalRow'],});// 将课程id和对应价格存入 courseIdAndPrice 变量let courseIdAndPrice = {};for (let i in that.data.carts) {let cart = that.data.carts[i];courseIdAndPrice[cart['fkCourseId']] = cart['coursePrice'];}that.setData({'courseIdAndPrice': courseIdAndPrice});}).catch(err => console.error(err));},// 列表触底时追查下一页数据pageMore: function () {let that = this;let pageNum = that.data.pageInfo['pageNum'];let totalPage = that.data.pageInfo['totalPage'];if (pageNum < totalPage) {this.setData({'pageInfo.pageNum': this.data.pageInfo['pageNum'] + 1});this.page();}},// 兑换优惠卷getCoupons: function (ev) {let that = this;let code = ev.detail;if (code) {let url = '/selectByCode/' + code;api.get('coupons', url).then(res => {if (util.isNull(res)) {util.error('优惠卷无效');return;}res['endTime'] = util.dateFormat(res['endTime']);res['startTime'] = util.dateFormat(res['startTime']);res['created'] = util.dateFormat(res['created']);res['updated'] = util.dateFormat(res['updated']);// 优惠金额大于总金额,直接设置为0,否则减去优惠金额if (res['cpPrice'] > this.data.totalAmount) {that.setData({payAmount: 0});} else {that.setData({payAmount: that.data.totalAmount - res['cpPrice']});}that.setData({'couponsCode': '','coupons': res,'couponsShow': true,});util.success('优惠卷已生效');}).catch(err => console.log(err));}},// 打开优惠卷面板openCouponsSheet: function () {this.setData({'couponsShow': true});},// 关闭优惠卷面板closeCouponsSheet() {this.setData({'couponsShow': false});},// 删除购物车记录removeCart: function (ev) {let id = ev.currentTarget.dataset['id'];util.confirm('课程将被移出购物车,确定吗?', () => {api.del('cart', `/delete/${id}`).then(res => {util.success('移出成功');this.setData({'carts': null});this.page();}).catch(err => console.log(err));});},// 清空购物车记录clearCart: function (ev) {util.confirm('清空购物车中的全部课程,确定吗?', () => {let url = '/clearByUserId/' + wx.getStorageSync('user').id;api.del('cart', url).then(res => {util.success('清空成功');this.setData({'carts': null,'totalAmount': 0.0,'payAmount': 0.0,'coupons': null,});}).catch(err => console.log(err));});},// 打开支付对话框openPayDialog: function () {let that = this;// 若选择内容为空,则不进行支付动作if (this.data.courseIds.length <= 0) {util.error('至少选择一项');return;}// 发送预支付请求let params = {'fkUserId': wx.getStorageSync('user').id,'courseIds': this.data.courseIds,'totalAmount': this.data.totalAmount,'payAmount': this.data.payAmount,'fkCouponsId': this.data.coupons['id'] ? this.data.coupons['id'] : null,};api.post('order', '/prePay', params).then(res => {this.setData({'sn': res})// 获取支付二维码wx.request({url: GATEWAY_HOST + '/order-server/api/v1/order/getQrCode',method: 'POST',data: {'sn': that.data.sn,'payAmount': this.data.payAmount},header: {'token': wx.getStorageSync('token')},responseType: 'arraybuffer',success(res) {if (res.statusCode !== 200) {util.error('获取二维码失败');return;}// 显示二维码that.setData({'qrCodeImage': 'data:image/png;base64,' + wx.arrayBufferToBase64(res.data),'payDialogShow': true,'countDownShow': true});// 每隔2秒钟轮询查询订单状态that.data.timer = setInterval(function () {api.get('order', '/checkStatusBySn/' + that.data.sn).then(res => {if (res === true) {util.success('支付成功');clearInterval(that.data.timer);that.setData({'payDialogShow': false,'countDownShow': true});// 跳转到订单页面util.page('/pages/order/order');}}).catch(err => util.error('查询订单状态失败', err));}, 2000);},});}).catch(err => console.log(err));},// 取消支付cancelPay: function () {util.success('取消支付成功');clearInterval(this.data.timer);this.setData({'payDialogShow': false,'countDownShow': false});this.page();},// 倒计时countDown: function (ev) {if (this.data.countDownShow) {this.setData({'timeData': ev.detail});}},// 当倒计时结束时触发onCountDownFinish: function (ev) {util.error('支付超时');this.setData({'payDialogShow': false,'countDownShow': false});},// 计算总金额(点击全选按钮时触发)getTotalAmount: function () {let param = '/totalAmountByUserId/' + wx.getStorageSync('user').id;api.get('cart', param).then(res => {this.setData({'totalAmount': res,'payAmount': res});}).catch(err => util.error('总金额查询失败', err));},// 查看课程详情showDetail: function (ev) {let courseId = ev.currentTarget.dataset['courseId'];util.page('/pages/course/detail/detail?courseId=' + courseId, false);},// 选择课程时触发changeCourseIds: function (ev) {let courseIds = ev.detail;this.setData({'courseIds': courseIds});// 从 courseIdAndPrice 中获取当前选中的全部课程的价格let courseIdAndPrice = this.data.courseIdAndPrice;let payAmount = 0;let totalAmount = 0;for (let i in courseIds) {let courseId = courseIds[i];payAmount += courseIdAndPrice[courseId];totalAmount += courseIdAndPrice[courseId];}this.setData({payAmount, totalAmount});},// 加载函数onLoad: function (options) {if (util.isLogin()) {this.page();}this.getTabBar().setData({"activeTab": 2});}
});

Java道经 - 项目 - MyLesson - 前台前端(二)

http://www.dtcms.com/a/466735.html

相关文章:

  • 做js题目的网站上海网站建设公司推荐排名
  • 网站建设效益分析代运营合同模板
  • 京东商品关键字搜索接口深度开发:从精准检索到商业机会挖掘的技术实现
  • 怎么看网站开发的发展wordpress能开发app
  • 项目学习总结:LVGL图形参数动态变化、开发板的GDB调试、sqlite3移植、MQTT协议、心跳包
  • 统一高效图像生成与编辑!百度新加坡国立提出Query-Kontext,多项任务“反杀”专用模型
  • 网站建设要那些东西适合个人开店的外贸平台
  • window安装wsl
  • 命题逻辑基础,形式系统,定理证明(二)
  • 如何利用数字源表进行纳米材料电特性表征?
  • 网络层协议之ICMP协议
  • 怎样做自己的网站钻钱宁波seo怎么选
  • skynet debug_console控制台中debug指令使用
  • 做棋盘游戏辅助的网站python和php做网站
  • 如何查看局域网内IP冲突问题?如何查看局域网IP环绕问题?arp -a命令如何使用?
  • 网站建设成都市南京做网站公司哪家好
  • 做电影视频网站赚钱嘛网站制作公司杭州
  • 建站平台哪个最好网站建设需要什么技术
  • 网页制作与网站建设实战大全pdf做网站的分辨率要多大
  • 主动学习:用“聪明提问”提升模型效率的迭代艺术
  • 数据链路层协议之MSTP协议
  • Debezium日常分享系列之:Debezium 3.3.0.Final发布
  • 网站的换肤功能怎么做哪个网站可以做验证码兼职
  • wordpress建站要钱吗中小型网站建设价格
  • gitee中的一些开源项目整理20251010
  • [JS]面试八股文
  • Linux中的进程监控,top界面解析
  • 构建一个属于组件的组件库
  • 【Linux笔记】网络部分——socket 编程 TCP实现多台虚拟机使用指令访问云服务器
  • 4.5 IP多播 (答案见原书 P208)