【 课程预览 】

1 课程预览技术方案

1.1 需求分析

课程预览是为了保证课程发布后的正确性,通过课程预览可以直观的通过课程详情页面看到课程的信息是否正确,通过课程预览看到的页面内容和课程发布后的页面内容是一致的。

下图是课程详情页面的预览图:
在这里插入图片描述

3.2 课程详情页面技术方案

课程预览所浏览到的页面就是课程详情页面,需要先确定课程详情页面的技术方案后方可确定课程预览的技术方
案。

3.2.1 技术需求

课程详情页面是向用户展示课程信息的窗口,课程相当于网站的商品,本页面的访问量会非常大。此页面的内容设
计不仅要展示出课程核心重要的内容而且用户访问页面的速度要有保证,有统计显示打开一个页面超过4秒用户就
走掉了,所以本页面的性能要求是本页面的重要需求。
本页面另一个需求就是SEO,要非常有利于爬虫抓取页面上信息,并且生成页面快照,利于用户通过搜索引擎搜索课程信息。

3.2.2 解决方案

如何在保证SEO的前提下提高页面的访问速度 :

方案1:
对于信息获取类的需求,要想提高页面速度就要使用缓存来减少或避免对数据库的访问,从而提高页面的访问速
度。下图是使用缓存与不使用缓存的区别

在这里插入图片描述

此页面为动态页面,会根据课程的不同而不同,方案一采用传统的JavaEE Servlet/jsp的方式在Tomcat完成页面渲
染,相比不加缓存速度会有提升。
优点:使用redis作为缓存,速度有提升。
缺点:采用Servlet/jsp动态页面渲染技术,服务器使用Tomcat,面对高并发量的访问存在性能瓶颈。

方案2:
对于不会频繁改变的信息可以采用页面静态化的技术,提前让页面生成html静态页面存储在nginx服务器,用户直
接访问nginx即可,对于一些动态信息可以访问服务端获取json数据在页面渲染。

在这里插入图片描述

优点:使用Nginx作为web服务器,并且直接访问html页面,性能出色。
缺点:需要维护大量的静态页面,增加了维护的难度。
选择方案2作为课程详情页面的技术解决方案,将课程详情页面生成Html静态化页面,并发布到Nginx上。

3.3 课程预览技术方案

根据要求:课程详情页面采用静态化技术生成Html页面,课程预览的效果要与最终静态化的Html页面内容一致。
所以,课程预览功能也采用静态化技术生成Html页面,课程预览使用的模板与课程详情页面模板一致,这样就可
以保证课程预览的效果与最终课程详情页面的效果一致。
操作流程:
1、制作课程详情页面模板
2、开发课程详情页面数据模型的查询接口(为静态化提供数据)
3、调用cms课程预览接口通过浏览器浏览静态文件

在这里插入图片描述

4 课程详情页面静态化

4.1 静态页面测试

4.1.1 页面内容组成

我们在编写一个页面时需要知道哪些信息是静态信息,哪些信息为动态信息,下图是页面的设计图:
在这里插入图片描述

打开静态页面,观察每部分的内容。
红色表示动态信息,红色以外表示静态信息。
红色动态信息:表示一个按钮,根据用户的登录状态、课程的购买状态显示按钮的名称及按钮的事件。
包括以下信息内容:
1、课程信息
课程标题、价格、课程等级、授课模式、课程图片、课程介绍、课程目录。
2、课程统计信息
课程时长、评分、收藏人数
3、教育机构信息
公司名称、公司简介
4、教育机构统计信息
好评数、课程数、学生人数
5、教师信息
老师名称、老师介绍

4.1.2 页面拆分

将页面拆分成如下页面:
1、页头
本页头文件和门户使用的页头为同一个文件。
参考:代码\页面与模板\include\header.html
2、页面尾
本页尾文件和门户使用的页尾为同一个文件。
参考:代码\页面与模板\include\footer.html
3、课程详情主页面
每个课程对应一个文件,命名规则为:课程id.html(课程id动态变化)
模板页面参考:\代码\页面与模板\course\detail\course_main_template.html
4、教育机构页面
每个教育机构对应一个文件,文件的命名规则为:company_info_公司id.html(公司id动态变化)
参考:代码\页面与模板\company\company_info_template.html
5、老师信息页面
每个教师信息对应一个文件,文件的命名规则为:teacher_info_教师id.html(教师id动态变化)
参考:代码\页面与模板\teacher\teacher_info_template01.html
6、课程统计页面
每个课程对应一个文件,文件的命名规则为:course_stat_课程id.json(课程id动态变化)
参考:\代码\页面与模板\stat\course\course_stat_template.json
7、教育机构统计页面
每个教育机构对应一个文件,文件的命名规则为:company_stat_公司id.json(公司id动态变化)
参考:\代码\页面与模板\stat\company\company_stat_template.json

2.3.3 静态页面测试

2.3.3.1页面加载思路

打开课程资料中的“静态页面目录”中的课程详情模板页面,研究页面加载的思路。
模板页面路径如下:

静态页面目录\static\course\detail\course_main_template.html

1、主页面
我们需要在主页面中通过SSI加载:页头、页尾、教育机构、教师信息
2、异步加载课程统计与教育机构统计信息
课程统计信息(json)、教育机构统计信息(json)
3、马上学习按钮事件
用户点击“马上学习”会根据课程收费情况、课程购买情况执行下一步操作。

2.3.3.2 静态资源虚拟主机

1、配置静态资源虚拟主机
静态资源虚拟主机负责处理课程详情、公司信息、老师信息、统计信息等页面的请求:
将课程资料中的“静态页面目录”中的目录拷贝到F:/develop/xuecheng/static下
在nginx中配置静态虚拟主机如下:

# 学成网静态资源
server {
    listen 91;
    server_name localhost;

    # 公司信息
    location /static/company/ {
        alias F:/develop/xuecheng/static/company/;
    }
    # 老师信息
    location /static/teacher/ {
        alias F:/develop/xuecheng/static/teacher/;
    }
    # 统计信息
    location /static/stat/ {
        alias F:/develop/xuecheng/static/stat/;
    }
    location /course/detail/ {
        alias F:/develop/xuecheng/static/course/detail/;
    }
}

2、通过www.xuecheng.com虚拟主机转发到静态资源
由于课程页面需要通过SSI加载页头和页尾所以需要通过www.xuecheng.com虚拟主机转发到静态资源
在www.xuecheng.com虚拟主机加入如下配置:

location /static/company/ {
    proxy_pass http://static_server_pool;
}
location /static/teacher/ {
    proxy_pass http://static_server_pool;
}
location /static/stat/ {
    proxy_pass http://static_server_pool;
}
location /course/detail/ {
    proxy_pass http://static_server_pool;
}

配置upstream实现请求转发到资源服务虚拟主机:

# 静态资源服务
upstream static_server_pool{
    server 127.0.0.1:91 weight=10;
}

2.3.3.3 门户静态资源路径

门户中的一些图片、样式等静态资源统一通过/static路径对外提供服务,在www.xuecheng.com虚拟主机中配置如
下:

# 静态资源,包括系统所需要的图片,js、css等静态资源
location /static/img/ {
    alias F:/develop/xc_portal_static/img/;
}
location /static/css/ {
    alias F:/develop/xc_portal_static/css/;
}
location /static/js/ {
    alias F:/develop/xc_portal_static/js/;
}
location /static/plugins/ {
    alias F:/develop/xc_portal_static/plugins/;
    add_header Access‐Control‐Allow‐Origin http://ucenter.xuecheng.com;
    add_header Access‐Control‐Allow‐Credentials true;
    add_header Access‐Control‐Allow‐Methods GET;
}

cors跨域参数:
Access-Control-Allow-Origin:允许跨域访问的外域地址
如果允许任何站点跨域访问则设置为*,通常这是不建议的。
Access-Control-Allow-Credentials: 允许客户端携带证书访问
Access-Control-Allow-Methods:允许客户端跨域访问的方法

2.3.3.4 页面测试

请求:http://www.xuecheng.com/course/detail/course_main_template.html测试课程详情页面模板是否可以正
常浏览。
在这里插入图片描述

2.3.3.5 页面动态脚本

为了方便日后的维护,我们将javascript实现的动态部分单独编写一个html 文件,在门户的include目录下定义
course_detail_dynamic.html文件,此文件通过ssi包含在课程详情页面中.

文件地址:资料\静态页面目录\include\course_detail_dynamic.html
所有的课程公用一个 页面动态脚本。
在课程详情主页面下端添加如下代码,通过SSI技术包含课程详情页面动态脚本文件:

<script>var courseId = "template"</script>
<!‐‐#include virtual="/include/course_detail_dynamic.html"‐‐>
</body>
</html>

本页面使用vue.js动态获取信息,vue实例创建的代码如下:
主要查看 created钩子函数的内容。

var body= new Vue({ //创建一个Vue的实例
el: "#body", //挂载点是id="app"的地方
data: {
editLoading: false,
title:'测试',
courseId:'',
charge:'',//203001免费,203002收费
learnstatus:0,//课程状态,1:马上学习,2:立即报名、3:立即购买
course:{},
companyId:'template',
company_stat:[],
course_stat:{"s601001":"","s601002":"","s601003":""}
},
methods: {
//学习报名
addopencourse(){
...
},
//立即购买
buy(){
...
},
createOrder(){
...
},
getLearnstatus(){//获取学习状态
...
}
},
created() {
// this.charge = '203002'
this.courseId = courseId;
//获取教育机构的统计数据
queryCompanyStat(this.companyId).then((res)=>{
console.log(res)
if(res.stat){
this.company_stat = res.stat
console.log(this.company_stat)
}
})
//获取课程的统计数据
queryCourseStat(this.courseId).then((res)=>{
console.log(res)
if(res.stat){
let stat = res.stat
for(var i=0;i<stat.length;i++){
this.course_stat['s'+stat[i].id] = stat[i].value
}
}
console.log(this.course_stat)
})
},
mounted(){
// alert(courseId)
}
})

4.2 课程数据模型查询接口

静态化操作需要模型数据方可进行静态化,课程数据模型由课程管理服务提供,仅供课程静态化程序调用使用。
4.2.1 接口定义
1、响应结果类型

@Data
@ToString
@NoArgsConstructor
public class CourseView implements Serializable {
    CourseBase courseBase;//基础信息
    CourseMarket courseMarket;//课程营销
    CoursePic coursePic;//课程图片
    TeachplanNode TeachplanNode;//教学计划
}

2、请求类型
String:课程id

3、接口定义如下

@ApiOperation("课程视图查询")
public CourseView courseview(String id);

4.2.2 Dao

需要对course_base、course_market、course_pic、teachplan等信息进行查询,
新建课程营销的dao,其它dao已经存在不用再建。

public interface CourseMarketRepository extends JpaRepository<CourseMarket,String> {
}

4.2.3 Service

//课程视图查询
public CourseView getCoruseView(String id) {
    CourseView courseView = new CourseView();
    //查询课程基本信息
    Optional<CourseBase> optional = courseBaseRepository.findById(id);
    if(optional.isPresent()){
        CourseBase courseBase = optional.get();
        courseView.setCourseBase(courseBase);
    }
    //查询课程营销信息
    Optional<CourseMarket> courseMarketOptional = courseMarketRepository.findById(id);
    if(courseMarketOptional.isPresent()){
        CourseMarket courseMarket = courseMarketOptional.get();
        courseView.setCourseMarket(courseMarket);
    }
    //查询课程图片信息
    Optional<CoursePic> picOptional = coursePicRepository.findById(id);
    if(picOptional.isPresent()){
        CoursePic coursePic = picOptional.get();
        courseView.setCoursePic(picOptional.get());
    }
    //查询课程计划信息
    TeachplanNode teachplanNode = teachplanMapper.selectList(id);
    courseView.setTeachplanNode(teachplanNode);
    return courseView;
}

4.2.4 Controller

@Override
@GetMapping("/courseview/{id}")
public CourseView courseview(@PathVariable("id") String id) {
    return courseService.getCoruseView(id);
}

4.2.5 测试

使用swagger-ui或postman测试本接口。

4.3 课程信息模板设计

在确定了静态化所需要的数据模型之后,就可以编写页面模板了,课程详情页面由多个静态化页面组成,所以我们
需要创建多个页面模板,本章节创建课程详情页面的主模板,即课程信息模板。

4.3.1 模板内容

完整的模板请参考 “资料\课程详情页面模板\course.ftl“ 文件,下边列出模板中核心的内容:
课程基本信息:

<div class="banner-left">
    <p class="tit">${courseBase.name}</p>
    <p class="pic"><span class="new-pic">特惠价格¥${(courseMarket.price)!""}</span> <span class="old-pic">原价¥${(courseMarket.price_old)!""}</span></p>
    <p class="info">
        <a href="http://ucenter.xuecheng.com/#/learning/${courseBase.id}/0"  target="_blank" v-if="learnstatus == 1" v-cloak>马上学习</a>
        <a href="#"  @click="addopencourse" v-if="learnstatus == 2" v-cloak>立即报名</a>
        <a href="#"  @click="buy" v-if="learnstatus == 3" v-cloak>立即购买</a>
        <span><em>难度等级</em>
 <#if courseBase.grade=='200001'>
低级
        <#elseif courseBase.grade=='200002'>
中级
 <#elseif courseBase.grade=='200003'>
高级
</#if>
        </span>
        <span><em>课程时长</em><stat v-text="course_stat.s601001"></stat>
        </span>
        <span><em>评分</em><stat v-text="course_stat.s601002"></stat></span>
        <span><em>授课模式</em>
          <#if courseBase.studymodel=='201001'>
自由学习
        <#elseif courseBase.studymodel=='201002'>
任务式学习
</#if>
        </span>
    </p>
</div>
<div class="banner-rit">

<#if (coursePic.pic)??>
 <p><img src="http://img.xuecheng.com/${coursePic.pic}" alt="" width="270" height="156"> </p>
 <#else>
 <p><img src="/static/img/widget-video.png" alt="" width="270" height="156"> </p>
</#if>
   
    <p class="vid-act"><span> <i class="i-heart"></i>收藏 <stat v-text="course_stat.s601003"></stat> </span> <span>分享 <i class="i-weixin"></i><i class="i-qq"></i></span></p>
</div>

课程计划:

<div class="content">
<#if teachplanNode.children??>
<#list teachplanNode.children as firstNode>
<div class="item">
<div class="title act"><i class="i‐chevron‐top">
</i>${firstNode.pname}</div>
<div class="about">${firstNode.description!}</div>
<div class="drop‐down" style="height: ${firstNode.children?
size * 50}px;">
<ul class="list‐box">
<#list firstNode.children as secondNode>
<li>${secondNode.pname}</li>
</#list>
</ul>
</div>
</div>
</#list>
</#if>
</div>

页头:
局部代码如下:

<body data‐spy="scroll" data‐target="#articleNavbar" data‐offset="150">
<!‐‐ 页面头部 ‐‐>
<!‐‐#include virtual="/include/header.html"‐‐>

页尾:
局部代码如下:

<!‐‐ 页面底部 ‐‐>
<!‐‐底部版权‐‐>
<!‐‐#include virtual="/include/footer.html"‐‐>

动态脚本文件:

<script>
//课程id
var courseId = "template"
</script>
<!‐‐#include virtual="/include/course_detail_dynamic.html"‐‐>

教师信息文件:
从课程数据中获取课程所属的教师Id,这里由于教师信息管理功能没有开发我们使用固定的教师信息文件:

<div class="content‐com course">
<div class="title"><span>课程制作</span></div>
<!‐‐#include virtual="/teacher/teacher_info_template01.html"‐‐>
</div>

教育机构文件:
同教师信息一样,由于教育机构功能模块没有开发,这里我们使用固定的教育机构文件:

<div class="about‐teach">
<!‐‐机构信息‐‐>
<!‐‐#include virtual="/company/company_info_template.html"‐‐>
</div>

4.3.2 模板测试

使用test-freemarker工程测试模板
编写模板过程采用test-freemarker工程测试模板。
将course.ftl拷贝到test-freemarker工程的resources/templates下,并在test-freemarker工程的controller中添加
测试方法

//课程详情页面测试
@RequestMapping("/course")
public String course(Map<String,Object> map){
ResponseEntity<Map> forEntity =
restTemplate.getForEntity("http://localhost:31200/course/courseview/4028e581617f945f01617f9dabc4
0000", Map.class);
Map body = forEntity.getBody();
map.put("model",body);
return "course";
}

注意:上边的测试页面不显示样式,原因是页面通过SSI包含了页面头,而使用test-freemarker工程无法加载页
头,测试模板主要查看html页面内容是否正确,待课程预览时解决样式不显示问题。

4.3.3 模板保存

模板编写并测试通过后要在数据库保存:
1、模板信息保存在xc_cms数据库(mongodb)的cms_template表
2、模板文件保存在mongodb的GridFS中。
第一步:将模板文件上传到GridFS中
由于本教学项目中模板管理模块没有开发,所以我们使用Junit代码向GridFS中保存:

//文件存储2
@Test
public void testStore2() throws FileNotFoundException {
File file = new File("C:\\Users\\admin\\Desktop\\course.ftl");
FileInputStream inputStream = new FileInputStream(file);
//保存模版文件内容
GridFSFile gridFSFile = gridFsTemplate.store(inputStream, "课程详情模板文件","");
String fileId = gridFSFile.getId().toString();
System.out.println(fileId);
}

保存成功需要记录模板文件的id,即上边代码中的fileId。
第二步:向cms_template表添加模板记录(请不要重复添加)
使用Studio 3T连接mongodb,向cms_template添加记录:

"_class" : "com.xuecheng.framework.domain.cms.CmsTemplate",
"siteId" : "5a751fab6abb5044e0d19ea1",
"templateName" : "课程详情页面正式模板",
"templateFileId" : "这里填写上边代码返回的模板文件id"

4.3.4 其它模板
除了课程详情主页面需要设计模板所有静态化的页面都要设计模板,如下:
教育机构页面模板、教师信息页面模板、课程统计信息json模板、教育机构统计信息json模板。
本项目我们实现课程详情主页面模板的制作和测试,其它页面模板的开发参考课程详情页面去实现。

5 课程预览功能开发

5.1 需求分析

课程预览功能将使用cms系统提供的页面预览功能,业务流程如下:
1、用户进入课程管理页面,点击课程预览,请求到课程管理服务
2、课程管理服务远程调用cms添加页面接口向cms添加课程详情页面
3、课程管理服务得到cms返回课程详情页面id,并拼接生成课程预览Url
4、课程管理服务将课程预览Url给前端返回
5、用户在前端页面请求课程预览Url,打开新窗口显示课程详情内容
在这里插入图片描述

5.2 CMS页面预览测试

CMS已经提供了页面预览功能,课程预览功能要使用CMS页面预览接口实现,下边通过cms页面预览接口测试课
程预览的效果。
1、向cms_page表插入一条页面记录或者从cms_page找一个页面进行测试。
注意:页面配置一定要正确,需设置正确的模板id和dataUrl。
如下,是一条页面的记录。

{
"_id" : ObjectId("5b3469f794db44269cb2bff1"),
"_class" : "com.xuecheng.framework.domain.cms.CmsPage",
"siteId" : "5a751fab6abb5044e0d19ea1",
"pageName" : "4028e581617f945f01617f9dabc40000.html",
"pageAliase" : "课程详情页面测试01",
"pageWebPath" : "/course/detail/",
"pagePhysicalPath" : "/course/detail/",
"pageType" : "1",
"pageCreateTime" : ISODate("2018‐02‐25T01:37:25.974+0000"),
"templateId" : "5b345a6b94db44269cb2bfec",
"dataUrl" : "http://localhost:31200/course/courseview/4028e581617f945f01617f9dabc40000"
}

2、课程详细页面 使用ssi注意
由于Nginx先请求cms的课程预览功能得到html页面,再解析页面中的ssi标签,这里必须保证cms页面预览返回的
页面的Content-Type为text/html;charset=utf-8
在cms页面预览的controller方法中添加:

response.setHeader("Content‐type","text/html;charset=utf‐8");

3、测试
请求:http://www.xuecheng.com/cms/preview/5b3469f794db44269cb2bff1传入页面Id,测试效果如下:

在这里插入图片描述

5.3 CMS添加页面接口

cms服务对外提供添加页面接口,实现:如果不存在页面则添加,否则就更新页面信息。
此接口由课程管理服务在课程预览时调用。

5.3.1 Api接口

@ApiOperation("保存页面")
public CmsPageResult save(CmsPage cmsPage);

5.3.2 Service

//添加页面,如果已存在则更新页面
public CmsPageResult save(CmsPage cmsPage){
//校验页面是否存在,根据页面名称、站点Id、页面webpath查询
CmsPage cmsPage1 =
cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(),
cmsPage.getSiteId(), cmsPage.getPageWebPath());
if(cmsPage1 !=null){
//更新
return this.update(cmsPage1.getPageId(),cmsPage);
}else{
//添加
return this.add(cmsPage);
}
}

5.3.3 Controller

@Override
@PostMapping("/save")
public CmsPageResult save(@RequestBody CmsPage cmsPage) {
return pageService.save(cmsPage);
}

5.4 课程预览服务端

5.4.1 Api定义
此Api是课程管理前端请求服务端进行课程预览的Api
请求:课程Id
响应:课程预览Url
1、定义响应类型

@Data
@ToString
@NoArgsConstructor
public class CoursePublishResult extends ResponseResult {
String previewUrl;
public CoursePublishResult(ResultCode resultCode,String previewUrl) {
super(resultCode);
this.previewUrl = previewUrl;
}
}

2、接口定义如下

@ApiOperation("预览课程")
public CoursePublishResult preview(String id);

5.4.2 创建 Feign Client

在课程管理工程创建CMS服务的Feign Client,通过此Client远程请求cms添加页面。

@FeignClient(value = XcServiceList.XC_SERVICE_MANAGE_CMS)
public interface CmsPageClient{
//保存页面
@PostMapping("/cms/page/save")
public CmsPageResult save(@RequestBody CmsPage cmsPage);
}

5.4.3 Service

1、配置添加页面参数信息
在application.yml中配置:

course‐publish:
  siteId: 5b30cba5f58b4411fc6cb1e5
  templateId: 5b345a6b94db44269cb2bfec
  previewUrl: http://www.xuecheng.com/cms/preview/
  pageWebPath: /course/detail/
  pagePhysicalPath: /course/detail/
  dataUrlPre: http://localhost:31200/course/courseview/

2、代码如下:

@Value("${course‐publish.dataUrlPre}")
private String publish_dataUrlPre;
@Value("${course‐publish.pagePhysicalPath}")
private String publish_page_physicalpath;
@Value("${course‐publish.pageWebPath}")
private String publish_page_webpath;
@Value("${course‐publish.siteId}")
private String publish_siteId;
@Value("${course‐publish.templateId}")
private String publish_templateId;
@Value("${course‐publish.previewUrl}")
private String previewUrl;
//根据id查询课程基本信息
public CourseBase findCourseBaseById(String courseId){
Optional<CourseBase> baseOptional = courseBaseRepository.findById(courseId);
if(baseOptional.isPresent()){
CourseBase courseBase = baseOptional.get();
return courseBase;
}
ExceptionCast.cast(CourseCode.COURSE_GET_NOTEXISTS);
return null;
}
//课程预览
public CoursePublishResult preview(String courseId){
CourseBase one = this.findCourseBaseById(courseId);
//发布课程预览页面
CmsPage cmsPage = new CmsPage();
//站点
cmsPage.setSiteId(publish_siteId);//课程预览站点
//模板
cmsPage.setTemplateId(publish_templateId);
//页面名称
cmsPage.setPageName(courseId+".html");
//页面别名
cmsPage.setPageAliase(one.getName());
//页面访问路径
cmsPage.setPageWebPath(publish_page_webpath);
//页面存储路径
cmsPage.setPagePhysicalPath(publish_page_physicalpath);
//数据url
cmsPage.setDataUrl(publish_dataUrlPre+courseId);
//远程请求cms保存页面信息
CmsPageResult cmsPageResult = cmsPageClient.save(cmsPage);
if(!cmsPageResult.isSuccess()){
return new CoursePublishResult(CommonCode.FAIL,null);
}
//页面id
String pageId = cmsPageResult.getCmsPage().getPageId();
//页面url
String pageUrl = previewUrl+pageId;
return new CoursePublishResult(CommonCode.SUCCESS,pageUrl);
}

5.4.4 Controller

@Override
@PostMapping("/preview/{id}")
public CoursePublishResult preview(@PathVariable("id") String id) {
return courseService.preview(id);
}

5.5 前端开发

5.5.1 api方法

/*预览课程*/
export const preview = id => {
return http.requestPost(apiUrl+'/course/preview/'+id);
}

5.5.2 页面
创建 course_pub.vue

<template>
<div>
<el‐card class="box‐card">
<div slot="header" class="clearfix">
<span>课程预览</span>
</div>
<div class="text item">
<el‐button type="primary" @click.native="preview" >课程预览</el‐button>
<br/><br/>
<span v‐if="previewurl && previewurl!=''"><a :href="previewurl" target="_blank">点我查看课
程预览页面 </a> </span>
</div>
</el‐card>
</div>
</template>

数据对象:

data() {
return {
dotype:'',
courseid:'',
course: {"id":"","name":"","status":""},
previewurl:''
}

方法 :

//预览
preview(){
courseApi.preview(this.courseid).then((res) => {
if(res.success){
this.$message.error('预览页面生成成功,请点击下方预览链接');
if(res.url){
//预览url
this.previewurl = res.url
}
}else{
this.$message.error(res.message);
}
});
}

猜你喜欢

转载自blog.csdn.net/weixin_42112635/article/details/89206684