0
点赞
收藏
分享

微信扫一扫

作品展示与播放-作者列表与详情

接口准备

创建 author.js

作品展示与播放-作者列表与详情_Project

import request from '@/utils/request';

const api_name = '/service_video/author';

export default {
authorWebList(page, limit) {
return request({
url: `${api_name}/pageList/${page}/${limit}`,
method: 'post',
headers: {
'Content-Type': 'application/json'
}
});
},
// 获取作者的信息 个人信息与作品信息
getAuthorById(authorId) {
return request({
url: `${api_name}/getAuthorById/${authorId}`,
method: 'get'
});
}
}

后端服务

修改 AuthorController.java

作品展示与播放-作者列表与详情_数据_02

/**
* <b> 根据作者ID查询作者信息以及作者的作品 </b>
*/
@GetMapping(value = "getAuthorById/{id}")
public ResponseResult getById(@PathVariable String id) {
return ResponseResult.ok().data("author", authorService.getById(id)).data("contentList",
contentService.selectByAuthorId(id));
}

修改 ContentService.java

/**
* <b> 根据作者id查询这个作者的作品列表 </b>
*
* @param authorId
* 作者ID
* @return 作品
*/
List<Content> selectByAuthorId(String authorId);

修改 ContentServiceImpl.java

@Override
public List<Content> selectByAuthorId(String authorId) {
QueryWrapper<Content> queryWrapper = new QueryWrapper<Content>();
queryWrapper.eq("author_id", authorId);

// 按照最后更新时间倒序排列
queryWrapper.orderByDesc("gmt_modified");

return baseMapper.selectList(queryWrapper);
}

列表展示

在 pages 下创建 author 文件夹,在 author 文件夹下面创建两个 vue 组件页面如下图

作品展示与播放-作者列表与详情_Project_03

两个页面的内容都是之前写过的,不在一一说明直接上代码了,里面就用到了一个新的内容就是异步加载如下图所示

作品展示与播放-作者列表与详情_ide_04

_id.vue

<template>
<section class="container">
<header class="comm-title">
<h2 class="fl tac">
<span class="c-333">作者介绍</span>
</h2>
</header>
<div class="t-infor-wrap">
<!--
作者基本信息
-->
<section class="fl t-infor-box c-desc-content">
<div class="mt20 ml20">
<section class="t-infor-pic">
<img :src="author.avatar">
</section>
<h3 class="hLh30">
<span class="fsize24 c-333">
{{ author.name }}&nbsp; {{ author.level === 1 ? '普通作者' : '特邀作者' }}
</span>
</h3>
<section class="mt10">
<span class="t-tag-bg">{{ author.intro }}</span>
</section>
<section class="t-infor-txt">
<p class="mt20">{{ author.career }}</p>
</section>
<div ></div>
</div>
</section>
<div ></div>
</div>
<section class="mt30">
<div>
<header class="comm-title all-teacher-title c-course-content">
<h2 class="fl tac">
<span class="c-333">作品信息</span>
</h2>
<section class="c-tab-title">
<a href="javascript: void(0)">&nbsp;</a>
</section>
</header>

<!--
没有数据
-->
<section class="no-data-wrap" v-if="contentList.length==0">
<em class="icon30 no-data-ico">&nbsp;</em>
<span class="c-666 fsize14 ml10 vam">该作品还未发布作品</span>
</section>
<article class="comm-video-list">
<ul class="of" id="bna">
<li v-for="content in contentList" :key="content.id">
<div class="cc-l-wrap">
<section class="video-img">
<img :src="content.cover" class="img-responsive">
<div class="cc-mask">
<a :href="'/video/'+content.id" class="comm-btn c-btn-1">播放</a>
</div>
</section>
<h3 class="hLh30 txtOf mt10">
<a :href="'/video/'+content.id" class="course-title fsize18 c-333">{{ content.title }}</a>
</h3>
<section class="mt10 hLh20 of">
<span class="fr jgTag bg-orange" v-if="Number(content.price) === 0">
<i class="c-fff fsize12 f-fA">免费</i>
</span>
<span class="fr jgTag bg-orange" v-else>
<i class="c-fff fsize12 f-fA"> ¥{{ content.price }}</i>
</span>
<span class="fl jgAttr c-ccc f-fA">
<i class="c-999 f-fA">{{ content.buyCount }} 人学习</i>
|
<i class="c-999 f-fA">{{ content.viewCount }} 人浏览</i>
</span>
</section>
</div>
</li>
</ul>
<div ></div>
</article>
</div>
</section>
</section>
</template>

<script>
import author from "@/api/author";

export default {
/*
接收参数:params内容为路由参数
* */
asyncData({params, error}) {
return author.getAuthorById(params.id).then(response => {
return {
// 作者信息
author: response.data.author,
// 作品列表
contentList: response.data.contentList
}
});
}
}
</script>

<style scoped>
</style>

index.vue

<template>
<div id="videoList" class="bg-fa of">
<section class="container" style="min-height: 600px;">
<section class="c-sort-box unBr">
<div>
<!--
列表展示
-->
<article class="i-author-list" style="padding-top: 50px;">
<div class="yd-open-course-card open-course-card" v-for="author in list" :key="author.id">
<a :href="'/author/'+author.id" style="color: #7F828B;text-decoration:none;">
<div class="yd-open-course-card_avatar">
<img :src="author.avatar" :alt="author.name"></div>
<div class="yd-open-course-card_content_teacher">
<div class="yd-open-course-card_content_teacher_tag">{{ author.name }}</div>
</div>
<div>{{ author.intro }}</div>
<span>-------------------------</span>
<div>{{ author.career }}</div>
</a>
</div>
<div ></div>
</article>
<!--
没有数据
-->
<section class="no-data-wrap" v-if="total==0">
<em class="icon30 no-data-ico">&nbsp;</em>
<span class="c-666 fsize14 ml10 vam">没有相关数据...</span>
</section>
</div>

<!--
分页
-->
<el-pagination
style="padding: 30px 0; text-align: center"
background
:current-page="page"
:page-size="limit"
layout="total, prev, pager, next, jumper "
:total="total"
@current-change="getData"
/>
</section>
</section>
</div>
</template>

<script>
import author from "@/api/author";

export default {
asyncData({params, error}) {
return author.authorWebList(1, 3).then(response => {
if (response.success === true) {
return {
// 作者信息
list: response.data.rows,
// 作品列表
total: response.data.total
}
}
});
},
data() {
// 定义变量与初始值
return {
// 数据列表
list: null,
// 总记录数
total: 0,
// 页码
page: 1,
// 每页记录数
limit: 3
}
},
methods: {
// 分页切换 page:当前页
getData(page = 1) {
// 调用api层获取数据库中的数据
this.page = page;
author.authorWebList(this.page, this.limit).then(response => {
if (response.success === true) {
this.list = response.data.rows;
this.total = response.data.total;
}
});
}
}
}
</script>

<style scoped>

::v-deep .el-pagination.is-background .el-pager li:not(.disabled).active {
background-color: orangered;
color: #fff;
}

.open-course-card {
width: 375px;
margin-top: 5px;
background: white;
}

.yd-open-course-card_avatar {
float: left;
width: 80px;
height: 102px;
margin-right: 20px;
}

.yd-open-course-card_avatar img {
width: 100%;
height: 100%;
border-radius: 4px;
}

.yd-open-course-card {
font-family: PingFang SC;
padding: 12px;
box-sizing: border-box;
border: 1px solid rgba(153, 153, 153, 0.15);
border-radius: 8px;
height: 143px;
min-width: 300px;
max-width: 385px;
cursor: pointer;
float: left;
margin-right: 5px;
}

.yd-open-course-card_content_teacher_tag {
display: inline-block;
height: 17px;
font-weight: 600;
font-size: 12px;
line-height: 17px;
color: #f4ad0b;
background: rgba(244, 173, 11, 0.06);
border: 0.5px solid rgba(244, 173, 11, 0.4);
border-radius: 4px;
padding: 2px 4px;
margin-bottom: 10px;
}
</style>

修改前端

创建 content.js

import request from '@/utils/request';

export default {
getPageList(page, limit, searchObj) {
return request({
url: `/service_video/content/getContentPageQuery/${page}/${limit}`,
method: 'get',
data: searchObj
});
},
// 查询所有分类的方法
getAllCategory() {
return request({
url: '/service_video/category/getTreeCategory',
method: 'get'
});
},
// 根据作品id获取作品详情信息
geContentDetailById(contentId) {
return request({
url: `/service_video/content/getContentDeatail/${contentId}`,
method: 'get'
});
}
}

在 pages 目录下的 video 文件夹下创建一个 _id.vue 组件如下图并且修改 index.vue 的内容, 修改内容如下

作品展示与播放-作者列表与详情_ico_05

index.vue

<template>
<div id="aCoursesList" class="bg-fa of">
<section class="container">
<header class="comm-title">
</header>
<section class="c-sort-box">
<section class="c-s-dl">
<dl>
<dt>
<span class="c-999 fsize14">作品分类</span>
</dt>
<dd class="c-s-dl-li">
<ul class="clearfix">
<li v-for="(item,index) in oneCategoryList" :key="index" :class="{active:oneIndex==index}">
<a :title="item.title" href="#" @click="searchOne(item.id,index)">{{ item.title }} </a>
</li>
</ul>
</dd>
</dl>
<dl>
<dt>
<span class="c-999 fsize14"></span>
</dt>
<dd class="c-s-dl-li">
<ul class="clearfix">
<li v-for="(item,index) in twoCategoryList" :key="index" :class="{active:twoIndex==index}">
<a :title="item.title" href="#" @click="searchTwo(item.id,index)">{{ item.title }}</a>
</li>
</ul>
</dd>
</dl>
<div ></div>
</section>
<div class="js-wrap">
<section class="fr">
<span class="c-ccc">
<i class="c-master f-fM">1</i>/
<i class="c-666 f-fM">1</i>
</span>
</section>
<section class="fl">
<ol class="js-tap clearfix">
<li :class="{'current bg-orangered':buyCountSort!=''}">
<a title="销量" href="javascript:void(0);" @click="searchBuyCount()">畅销
<span :class="{hide:buyCountSort==''}">↓</span>
</a>
</li>
<li :class="{'current bg-orangered':gmtCreateSort!=''}">
<a title="最新" href="javascript:void(0);" @click="searchGmtCreate()">最新
<span :class="{hide:gmtCreateSort==''}">↓</span>
</a>
</li>
<li :class="{'current bg-orangered':priceSort!=''}">
<a title="价格" href="javascript:void(0);" @click="searchPrice()">价格&nbsp;
<span :class="{hide:priceSort==''}">↓</span>
</a>
</li>
</ol>
</section>
</div>
<div class="mt40">
<!--
无数据提示 开始
-->
<section class="no-data-wrap" v-if="data.length == 0">
<em class="icon30 no-data-ico">&nbsp;</em>
<span class="c-666 fsize14 ml10 vam">没有相关数据...</span>
</section>

<article class="comm-video-list" style="min-height: 450px;">
<ul class="of" id="bna">
<li v-for="item in data" :key="item.id">
<div class="cc-l-wrap">
<section class="video-img">
<img :src="item.cover" class="img-responsive">
<div class="cc-mask">
<a :href="'/video/'+item.id" class="comm-btn c-btn-1">播放</a>
</div>
</section>
<h3 class="hLh30 txtOf mt10">
<a :href="'/video/'+item.id" class="course-title fsize18 c-333">{{ item.title }}</a>
</h3>
<section class="mt10 hLh20 of">
<span class="fr jgTag bg-orangered" v-if="Number(item.price) === 0">
<i class="c-fff fsize12 f-fA">免费</i>
</span>
<span class="fr jgTag bg-orangered" v-else>
<i class="c-fff fsize12 f-fA"> ¥{{ item.price }}</i>
</span>
<span class="fl jgAttr c-ccc f-fA">
<i class="c-999 f-fA">{{ item.buyCount }} 人学习</i>
|
<i class="c-999 f-fA">{{ item.viewCount }} 人浏览</i>
</span>
</section>
</div>
</li>
</ul>
<div ></div>
</article>
</div>

<!--
分页
-->
<el-pagination
style="padding: 30px 0; text-align: center"
background
:current-page="page"
:page-size="limit"
layout="total, prev, pager, next, jumper "
:total="total"
@current-change="gotoPage"
/>
</section>
</section>
<!--
课程列表 结束
-->
</div>
</template>

<script>
import content from '@/api/content';

export default {
data() {
// 定义变量与初始值
return {
// 数据列表
list: null,

// 总记录数
total: 0,

// 页码
page: 1,

// 每页记录数
limit: 4,
data: [],

// 查询表单对象
searchObj: {},

// 一级分类列表
oneCategoryList: [],

// 二级分类列表
twoCategoryList: [],

// 记录一级选中状态角标
oneIndex: -1,

// 记录二级选中状态角标
twoIndex: -1,

// 畅销排序
buyCountSort: "",

// 日期排序
gmtCreateSort: "",

// 价格排序
priceSort: ""
}
},
// 加载数据(异步)
async asyncData({params, error}) {
let [request1Data, request2Data] = await Promise.all([
content.getPageList(1, 4, {}),
content.getAllCategory()
]);
return {
data: request1Data.data.rows,
total: request1Data.data.total,
oneCategoryList: request2Data.data.list,
}
},
methods: {
// 分页查询
gotoPage(page) {
this.page = page;
content.getPageList(page, this.limit, this.searchObj).then(response => {
this.data = response.data.rows;
this.total = response.data.total;
});
},
// 点击某个一级分类,查询对应二级分类
searchOne(categoryParentId, index) {
// 把传递index值赋值给oneIndex,为了active样式生效
this.oneIndex = index;

this.twoIndex = -1;
this.searchObj.categoryId = "";
this.twoCategoryList = [];

// 把一级分类点击id值,赋值给searchObj
this.searchObj.categoryParentId = categoryParentId;

// 点击某个一级分类进行条件查询;
this.gotoPage(1);

// 拿着点击一级分类id 和 所有一级分类id进行比较,
// 如果id相同,从一级分类里面获取对应的二级分类
for (let i = 0; i < this.oneCategoryList.length; i++) {
// 获取每个一级分类
let oneCategory = this.oneCategoryList[i];
// 比较id是否相同
if (categoryParentId === oneCategory.id) {
// 从一级分类里面获取对应的二级分类
this.twoCategoryList = oneCategory.children;
}
}
},

// 点击某个二级分类实现查询
searchTwo(categoryId, index) {
// 把index赋值,为了样式生效
this.twoIndex = index;

// 把二级分类点击id值,赋值给searchObj
this.searchObj.categoryId = categoryId;

//点击某个二级分类进行条件查询
this.gotoPage(1);
},

// 根据销量排序
searchBuyCount() {
// 设置对应变量值,为了样式生效
this.buyCountSort = "1";
this.gmtCreateSort = "";
this.priceSort = "";

// 把值赋值到searchObj
this.searchObj.buyCountSort = this.buyCountSort;
this.searchObj.gmtCreateSort = this.gmtCreateSort;
this.searchObj.priceSort = this.priceSort;

// 调用方法查询
this.gotoPage(1);
},

// 最新排序
searchGmtCreate() {
// 设置对应变量值,为了样式生效
this.buyCountSort = "";
this.gmtCreateSort = "1";
this.priceSort = "";

// 把值赋值到searchObj
this.searchObj.buyCountSort = this.buyCountSort;
this.searchObj.gmtCreateSort = this.gmtCreateSort;
this.searchObj.priceSort = this.priceSort;

// 调用方法查询
this.gotoPage(1);
},

// 价格排序
searchPrice() {
// 设置对应变量值,为了样式生效
this.buyCountSort = "";
this.gmtCreateSort = "";
this.priceSort = "1";

// 把值赋值到searchObj
this.searchObj.buyCountSort = this.buyCountSort;
this.searchObj.gmtCreateSort = this.gmtCreateSort;
this.searchObj.priceSort = this.priceSort;

// 调用方法查询
this.gotoPage(1);
}
}
}
</script>

<style scoped>
/*
如果需要修改 element-ui的样式前面需要加上如下前缀 ::v-deep
*/
::v-deep .el-pagination.is-background .el-pager li:not(.disabled).active {
background-color: orangered;
color: #fff;
}

.active {
background: orangered;
}

.active a {
color: white;
}

.active a:hover {
color: white;
}

.hide {
display: none;
}

.show {
display: block;
}
</style>

前面的章节当中已经讲解过了所以这里就直接上代码了, 如上是 index.vue 的内容 _id.vue 组件的内容如下

<template>
<div id="videoList" class="bg-fa of">
<section class="container">
<section class="path-wrap txtOf hLh30">
<a href="#" title class="c-999 fsize14">首页</a>
\
<a href="/course" title class="c-999 fsize14">作品列表</a>
\
<span class="c-333 fsize14">{{ content.oneCategoryName }}</span>
\
<span class="c-333 fsize14">{{ content.twoCategoryName }}</span>
</section>
<div>
<div class="content-box">
<div class="fl">
<img width="450" height="250" :src="content.cover"/>
</div>
<div class="fl u-coursetitle">
<h2>
<span class="u-coursetitle_title">{{ content.title }}</span>
</h2>
<div style="margin-top: 10px; ">
<div class="fl">{{ content.buyCount }}人学过</div>
<div class="fl hot">
<el-rate
v-model="value"
disabled
show-score
text-color="#ff9900"
score-template="{value}">
</el-rate>
</div>
<div ></div>
</div>
<div v-if="Number(content.price) != 0" style="font-size: 28px; margin-top: 30px;">
¥ {{ content.price }}
</div>
<div class="join">
<a @click="createOrders" class="learnbtn"
v-if="Number(content.price) != 0 && isBuy == false"><span>立即购买</span></a>
<a href="#" class="j-do-trailer"
v-if="Number(content.price) === 0 || isBuy== true"><span>立即学习</span>
</a>
</div>
</div>
</div>
<div ></div>
</div>
<div class="mt20 c-infor-box">
<article class="fl col-7">
<section class="mr30">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane style="padding-left: 20px" label="视频介绍" name="first">
<div>
<h6 class="c-i-content c-infor-title">
<span>课程介绍</span>
</h6>
<div class="course-txt-body-wrap">
<section class="course-txt-body" style="padding: 20px;">
<div v-html="content.description"></div>
</section>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="视频目录" name="second">
<div>
<div class="f-cb">
<h2 class="u-ctit f-thide f-fl">目录</h2>
</div>
<div class="m-chapterList f-pr">
<div class="chapter" v-for="(chapter,index) in chapterList" :key="chapter.id">
<div class="chapterhead">
<span class="f-fl f-thide chaptertitle">章节{{ index + 1 }}:</span>
<span class="f-fl f-thide chaptername">{{ chapter.title }}</span>
</div>
<div>
<div class="section" v-for="(video,i) in chapter.children" :key="video.id">
<!--
<a :href="'/player/'+video.videoSourceId+'_'+contentId" >
-->
<a @click="playClick(video.videoSourceId+'_'+contentId,video.isFree,$event)">
<span class="f-fl f-thide ks">小节{{ i + 1 }}</span><span class="f-fl type-title">视频</span>
<span class="f-fl f-thide ksname">{{ video.title }}</span>
<a class="f-fr ksjbtn j-hovershow" style="display: none;">
<span class="f-fr" v-if="video.isFree === true">可试看</span>
<div class="f-fr ksjicon-look"></div>
</a>
<span class="f-fr ksinfo j-hoverhide" style="display: block;">
<span class="f-fr f-thide kstime">{{ video.duration }}</span>
<span class="f-fr ksinfoicon ksinfoicon-2" title="视频"></span>
<span class="f-fr canPreview" v-if="video.isFree === true">可试看</span>
</span>
</a>
</div>
</div>
</div>
</div>
</div>
</el-tab-pane>
</el-tabs>
</section>
</article>
<aside class="fl col-3">
<div class="i-box">
<div>
<section class="c-infor-tabTitle c-tab-title">
<a title href="javascript:void(0)">作者</a>
</section>
<section class="stud-act-list">
<ul style="height: auto;">
<li>
<div class="u-face">
<a :href="'/author/'+content.authorId">
<img :src="content.avatar" width="50" height="50" alt>
</a>
</div>
<section class="hLh30 txtOf">
<a class="c-333 fsize16 fl" href="#">{{ content.authorName }}</a>
</section>
<section class="hLh20 txtOf">
<span class="c-999">{{ content.intro }}</span>
</section>
</li>
</ul>
</section>
</div>
</div>
</aside>
<div ></div>
</div>
</section>
</div>
</template>

<script>
import content from "@/api/content";
import order from "@/api/order";
import cookie from 'js-cookie';

export default {
async asyncData(app) {
//在nuxt中如果没有做任何处理, 是不能直接获取到cookie node.js
let content_id = app.params.id;
return content.geContentDetailById(content_id, app).then(response => {
return {
contentId: content_id,
content: response.data.content,
chapterList: response.data.chapterVoList,
isBuy: response.data.isBuyContent
}
});
},
data() {
return {
content: '',
chapterList: '',
contentId: '',
activeName: 'second',
value: 4.5,
isBuy: false
};
},
methods: {
playClick(videoId, isFree, e) {
if (isFree) {
// nuxt 中 使用到了jquery
$(e.currentTarget).attr('href', '/player/' + videoId);
$(e.currentTarget).trigger('click');
} else {
// 有没有登录
if (this.isLogin()) {
if (this.isBuy) {
$(e.currentTarget).attr('href', '/player/' + videoId);
$(e.currentTarget).trigger('click');
} else {
this.$message.warning("购买后才能观看");
}
} else {
this.$message.warning("请先登录...");
}
}
},
handleClick(tab, event) {
this.activeName = tab.paneName;
},
// 生成订单
createOrders() {
if (this.isLogin()) {
order.createOrders(this.contentId)
.then(response => {
// 获取返回订单号
// 生成订单之后,跳转订单显示页面
this.$router.push({path: '/order/' + response.data.orderId});
})
} else {
this.$message.warning("请先登录...");
return;
}
},
isLogin() {
let user = cookie.get('portal_user', {domain: 'localhost'});
if (user) {
return true;
} else {
false;
}
}
}
}
</script>

<style scoped>
>>> .el-tabs__nav-scroll {
background: white;
height: 40px;
}

>>> .el-tabs__nav:first-child {
margin-left: 15px;
}

>>> .el-tab-pane {
background: white;
border: 1px solid #f0f0f0;
}

>>> .el-tab-pane:first-child {
padding-top: 20px;
}

>>> .el-rate__icon {
margin-right: -2px;
}
</style>




举报

相关推荐

0 条评论