提交 0a0cb7e0 编写于 作者: guangjun.yang's avatar guangjun.yang

Merge branch 'dev-purchase-0901' into 'release'

微信内、外购买学习卡功能: code reviewer:张平

微信内、外购买学习卡功能: code reviewer:张平

See merge request !3
<template>
<div
:class="{ 'button-dis': isDisabled, 'button-plain': isPlain }"
class="button-container"
@click="submit"
>
{{ buttonText }}
</div>
</template>
<script>
export default {
name: 'ButtonComponent',
props: {
isPlain: {
type: Boolean,
default: false
},
isDisabled: {
type: Boolean,
default: false
},
buttonText: {
type: String,
default: "继续学习"
},
},
methods: {
submit() {
if (this.isDisabled) {
return;
}
this.$emit('handlerClick'); //点击按钮的操作,触发父组件相应的方法
}
}
};
</script>
<style scoped lang="less">
.button-container {
/*按钮本身样式没有设置margin,可根据具体页面的ui在父页面中进行设置*/
// width: 325px;
width: 90%;
height: 44px;
background: #449284;
border-radius: 22px;
color: #fff;
font-size: 16px;
font-weight: 700;
line-height: 44px;
text-align: center;
margin: 16px auto;
}
.button-dis {
opacity: 0.5;
}
.button-plain {
color: #449284;
background: #fff;
border: 1px solid rgba(68,146,132, 0.4);
}
</style>
......@@ -9,7 +9,7 @@
<van-collapse-item
v-for="(portalModule, index) in component.portalModuleDTOS"
:key="index"
:title="(parseInt(index) + 1) + '.' + portalModule.moduleName | shortName(19)"
:title="portalModule.moduleName | shortName(19)"
:name="portalModule.expandKey"
:value="portalModule.value"
@click.native="chooseItem(portalModule)"
......@@ -137,7 +137,11 @@ export default {
projectId: {
type: Number | String,
default: 0
}
},
goodsId: {
type: Number | String,
default: 0
},
},
components: {
MergeTitle,
......@@ -164,15 +168,28 @@ export default {
if(type == 'sk') {
this.$sendBuriedData({
component_tag: `882#88216#${item.id}#${item.name}`
});
});
}
// 在浏览器中
if(!isWeiXin()) {
if(item.type == 1) {
Toast('请前往云鹊医APP参加考试');
} else if(item.type == 2){
Toast('请前往云鹊医APP学习课程');
}
return;
// 没有绑定则提示去购买/激活
if(!this.hasBindCard) {
if(item.type == 1) {
Toast('激活/购买后可参加考试');
} else if(item.type == 2){
Toast('激活/购买后可学习完整课程');
}
return;
// 已经绑定则前往云鹊医APP
} else {
if(item.type == 1) {
Toast('请前往云鹊医APP参加考试');
} else if(item.type == 2){
Toast('请前往云鹊医APP学习课程');
}
return;
}
}
if(!this.logged) {
......@@ -237,7 +254,7 @@ export default {
Toast('请前往云鹊医APP学习课程');
return;
}
let jumpUrl = getWebPageUrl(`profexam/#/course-detail?courseId=${item.id}&projectId=${this.projectId}&token=${this.token}`);
let jumpUrl = getWebPageUrl(`profexam/#/course-detail?courseId=${item.id}&projectId=${this.projectId}&goodsId=${this.goodsId}`);
window.location.href = jumpUrl;
},
......@@ -282,7 +299,7 @@ export default {
if(item) {
this.$sendBuriedData({
component_tag: `882#88215#${item.id}#${item.name}`
});
});
}
Toast(toastMsg);
}
......
......@@ -9,7 +9,7 @@
<van-collapse-item
v-for="(portalModule, index) in component.portalModuleDTOS"
:key="index"
:title="(parseInt(index) + 1) + '.' + portalModule.moduleName | shortName(19)"
:title="portalModule.moduleName | shortName(19)"
:name="portalModule.expandKey"
:value="portalModule.value"
@click.native="chooseItem(portalModule)"
......@@ -281,6 +281,12 @@ export default {
type: 4,
seqNo: 1
},
{
key: "projectId",
value: this.projectId,
type: 4,
seqNo: 1
},
];
if(trySee) {
......
......@@ -77,6 +77,10 @@ export default {
courseRequire: {
type: Number,
default: 0,
},
projectId: {
type: Number | String,
default: 0,
}
},
computed: {
......@@ -143,7 +147,14 @@ export default {
type: 4,
seqNo: 1
},
{
key: "projectId",
value: this.projectId,
type: 4,
seqNo: 1
},
];
console.log('gotoCourse', paramList);
rocNative.dispatchEventByModuleCode({
modeCode: "M200",
jsonString: paramList
......
<template>
<section class="bind-cart-wrapper">
<article class="left">
<div class="top">
<span class="discount">{{(cardInfo.preferentialPrice || cardInfo.costPrice) | formatMoney}}</span>
<span v-show="cardInfo.preferentialPrice" class="price">
<del>原价¥{{cardInfo.costPrice | formatMoney}}</del>
</span>
</div>
<div class="bottom">
<img src="../../images/cme/phrase2/info.png" />
<span>激活或购买后可学习课程</span>
</div>
</article>
<article class="right">
<span class="left" @click="changeClick">去激活</span>
<span @click="gotoBuy" class="right">去购买</span>
</article>
</section>
</template>
<script>
export default {
props: {
cardInfo: {
type: Object,
default: () => {}
}
},
data() {
return {};
},
methods: {
changeClick(){
this.$emit("changeClick")
},
gotoBuy() {
this.$emit("gotoBuy");
}
}
};
</script>
<style lang="less" scoped>
.bind-cart-wrapper {
position: fixed;
left: 0;
bottom: 0;
z-index: 100;
width: 100%;
display: flex;
flex-direction: row;
height: 60px;
line-height: 1;
justify-content: space-between;
padding: 10px 15px;
font-size: 14px;
background: rgba(255, 255, 255, 1);
box-shadow: 0px -2px 10px 0px rgba(0, 0, 0, 0.1);
.left {
display: flex;
flex-direction: column;
height: 40px;
line-height: 1;
font-size: 12px;
// align-items: ;
.top {
margin-top: 3px;
height: 24px;
.discount {
color: #fb5b52;
font-size: 18px;
font-weight: 700;
margin-right: 4px;
}
.price {
color: #979899;
}
}
.bottom {
display: flex;
flex-direction: row;
img {
width: 12px;
height: 12px;
margin-left: 1px;
margin-right: 4px;
}
color: #979899;
}
}
.right {
display: flex;
flex-direction: row;
span {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
width: 80px;
font-size: 14px;
font-weight: 400;
text-align: center;
color: #7f7f7f;
border: 1px solid #d2b573;
&.left {
border-radius: 20px 0px 0px 20px;
border-right-style: none;
// color: #ff7a4b;
}
&.right {
// background: linear-gradient(
// 137deg,
// rgba(255, 166, 95, 1) 0%,
// rgba(255, 122, 75, 1) 100%
// );
border-radius: 0px 20px 20px 0px;
// color: #fff;
}
}
}
}
</style>
\ No newline at end of file
......@@ -87,7 +87,10 @@ export default {
margin-left: 1px;
margin-right: 4px;
}
color: #979899;
& > span {
font-size: 12px;
color: #979899;
}
}
}
.right {
......
......@@ -31,9 +31,15 @@ export default {
},
methods: {
changeClick(){
this.$sendBuriedData({
component_tag: `882#88224`
});
this.$emit("changeClick")
},
gotoBuy() {
this.$sendBuriedData({
component_tag: `882#88223`
});
this.$emit("gotoBuy");
}
}
......@@ -84,7 +90,10 @@ export default {
margin-left: 1px;
margin-right: 4px;
}
color: #979899;
& > span {
font-size: 12px;
color: #979899;
}
}
}
.right {
......
......@@ -88,7 +88,8 @@ export default {
},
confirm() {
this.$sendBuriedData({
component_tag: `882#88207`
// component_tag: `882#88207`
component_tag: `882#88225`
});
if(!this.activationCode) {
this.errorMsg = '请输入激活码';
......
<template>
<div class="teacter-intro-container">
<div class="basic-title">讲师介绍</div>
<div class="leader-info" v-for="(item,index) in doctorList" :key="index">
<img :src="item.appImageUrl"/>
<div class="leader-text">
<div class="leader-con">
<span>{{item.name}}</span>
<span class="leader-title">{{item.title}}</span>
</div>
<div class="address">{{item.hospital}}</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
doctorList: {
type: Array,
default: () => []
}
},
data() {
return {
}
},
created() {
},
mounted() {
},
methods: {
}
}
</script>
<style lang="less" scoped>
.teacter-intro-container {
margin: 30px 15px 0px;
.basic-title {
font-size: 18px;
line-height: 18px;
color: #373839;
font-weight: 700;
}
.leader-info {
display: flex;
flex-direction: row;
margin-top: 16px;
padding-bottom: 16px;
img {
display: inline-block;
width: 44px;
height: 44px;
border-radius: 50%;
}
.leader-text {
flex: 1;
width: 100px;
margin-left: 16px;
margin-top: 6px;
.leader-con {
line-height: 14px;
display: flex;
flex-direction: row;
white-space: nowrap;
span {
font-size: 16px;
color: #676869;
}
span:first-child {
font-size: 16px;
color: #373839;
font-weight: 700;
line-height: 1.1;
}
.leader-title {
width: 220px;
overflow : hidden;
text-overflow: ellipsis;
white-space:nowrap;
line-height: 16px;
margin-left: 10px;
}
}
.address {
margin-top: 5px;
font-size: 13px;
color: #979899;
width: 240px;
overflow : hidden;
text-overflow: ellipsis;
white-space:nowrap;
}
}
}
}
</style>
<template>
<div class="teacter-intro-container">
<div class="basic-title">讲师介绍</div>
<div class="leader-info" v-for="(item,index) in doctorList" :key="index">
<img :src="item.appImageUrl"/>
<div class="leader-text">
<div class="leader-con">
<span>{{item.name}}</span>
<span class="leader-title">{{item.title}}</span>
</div>
<div class="address">{{item.hospital}}</div>
</div>
<div class="teacter-intro-container">
<div class="basic-title">讲师介绍</div>
<div class="leader-info" v-for="(item,index) in current" :key="index">
<img :src="item.appImageUrl" />
<div class="leader-text">
<div class="leader-con">
<span>{{item.name}}</span>
<span class="leader-title">{{item.title}}</span>
</div>
<div class="address">{{item.hospital}}</div>
</div>
</div>
<div v-show="doctorList.length > 1" class="toggle-btn" @click="toggle">
<span class="btn">{{ isUp ? '展开更多' : '向上收起'}}</span>
<img v-if="isUp" src="../../images/cme/arrow-grey-down.png" />
<img v-if="!isUp" src="../../images/cme/arrow-grey-up.png" />
</div>
</div>
</template>
<script>
export default {
props: {
doctorList: {
type: Array,
default: () => []
}
},
data() {
return {
}
},
created() {
},
mounted() {
},
methods: {
props: {
doctorList: {
type: Array,
default: () => []
}
}
},
data() {
return {
isUp: true,
one: [],
all: [],
current: []
};
},
created() {},
mounted() {
this.one = this.doctorList.slice(0, 1);
this.current = this.one;
this.all = this.doctorList.slice(0);
},
methods: {
toggle() {
this.isUp = !this.isUp;
if (this.isUp) {
this.current = this.one;
this.$sendBuriedData({
component_tag: `882#88222`
});
} else {
this.$sendBuriedData({
component_tag: `882#88221`
});
this.current = this.all;
}
}
}
};
</script>
<style lang="less" scoped>
.teacter-intro-container {
margin: 30px 15px 0px;
.basic-title {
font-size: 18px;
line-height: 18px;
color: #373839;
font-weight: 700;
margin: 30px 15px 0px;
.basic-title {
font-size: 18px;
line-height: 18px;
color: #373839;
font-weight: 700;
}
.leader-info {
display: flex;
flex-direction: row;
margin-top: 16px;
padding-bottom: 16px;
img {
display: inline-block;
width: 44px;
height: 44px;
border-radius: 50%;
}
.leader-info {
.leader-text {
flex: 1;
width: 100px;
margin-left: 16px;
margin-top: 6px;
.leader-con {
line-height: 14px;
display: flex;
flex-direction: row;
margin-top: 16px;
padding-bottom: 16px;
img {
display: inline-block;
width: 44px;
height: 44px;
border-radius: 50%;
white-space: nowrap;
span {
font-size: 16px;
color: #676869;
}
span:first-child {
font-size: 16px;
color: #373839;
font-weight: 700;
line-height: 1.1;
}
.leader-text {
flex: 1;
width: 100px;
margin-left: 16px;
margin-top: 6px;
.leader-con {
line-height: 14px;
display: flex;
flex-direction: row;
white-space: nowrap;
span {
font-size: 16px;
color: #676869;
}
span:first-child {
font-size: 16px;
color: #373839;
font-weight: 700;
line-height: 1.1;
}
.leader-title {
width: 220px;
overflow : hidden;
text-overflow: ellipsis;
white-space:nowrap;
line-height: 16px;
margin-left: 10px;
}
}
.address {
margin-top: 5px;
font-size: 13px;
color: #979899;
width: 240px;
overflow : hidden;
text-overflow: ellipsis;
white-space:nowrap;
}
.leader-title {
width: 220px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 16px;
margin-left: 10px;
}
}
.address {
margin-top: 5px;
font-size: 13px;
color: #979899;
width: 240px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.toggle-btn {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
margin-bottom: 20px;
& > span {
font-size: 14px;
color: #979899;
font-weight: 400;
}
& > img {
width: 15px;
height: 15px;
}
}
}
</style>
</style>
\ No newline at end of file
<template>
<div class="common-dialog-wrraper" v-if="isShowDialog">
<div class="dialog-mask"></div>
<div class="dialog-container">
<div class="dialog-content">{{content}}</div>
<div v-show="needSubContent" class="dialog-sub-content" v-html="subContent"></div>
<div class="dialog-footer v-hairline-top">
<span :class="{'single-btn': isSingle}" @click="handlerAction(1)">{{cancleBtnText}}</span>
<span v-show="!isSingle" class="confirm-btn v-hairline-left" @click="handlerAction(2)">{{confirmBtnText}}</span>
</div>
</div>
</div>
</template>
<script>
export default {
name: "common-dialog",
data() {
return {
};
},
props: {
content: {
type: String,
default: ''
},
needSubContent: {
type: Boolean,
default: false
},
subContent: {
type: String,
default: ''
},
cancleBtnText: {
type: String,
default: '取消'
},
confirmBtnText: {
type: String,
default: '确定'
},
isShowDialog: {
type: Boolean,
default: false
},
isSingle: {
type: Boolean,
default: false
},
},
methods: {
handlerAction(type) {
this.$emit("handlerAction", type);
}
}
};
</script>
<style lang="less" scoped>
.common-dialog-wrraper {
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: 2019;
.dialog-mask {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 2020;
}
.dialog-container {
z-index: 2021;
position: absolute;
top: 50%;
left: 50%;
overflow: hidden;
width: 300px;
font-size: 18px;
-webkit-transition: 0.3s;
transition: 0.3s;
border-radius: 4px;
background-color: #fff;
-webkit-transform: translate3d(-50%, -50%, 0);
transform: translate3d(-50%, -50%, 0);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
.dialog-content {
// margin: 30px 22px;
margin: 30px;
text-align: center;
font-size: 18px;
font-weight: 400;
color: #373839;
}
.dialog-sub-content {
margin: 5px 30px 20px;
// margin: -16px 22px 30px;
text-align: left;
font-size: 14px;
line-height: 24px;
font-weight: 400;
color: #676869;
}
.dialog-footer {
height: 50px;
display: flex;
align-items: center;
&.v-hairline-top::after {
border-top-width: 1px;
}
span {
display: inline-block;
// width: 50%;
flex: 1;
height: 50px;
line-height: 50px;
font-size: 17px;
text-align: center;
color: #979899;
&.v-hairline-left::after {
border-left-width: 1px;
}
&.confirm-btn {
color: #449284;
}
&.single-btn {
color: #449284;
}
}
}
}
[class*="v-hairline"] {
position: relative;
&::after {
content: " ";
position: absolute;
pointer-events: none;
box-sizing: border-box;
top: -50%;
left: -50%;
right: -50%;
bottom: -50%;
-webkit-transform: scale(0.5);
transform: scale(0.5);
border: 0 solid #f0f1f2;
}
}
&.shikan {
.dialog-sub-content {
text-align: center;
font-size: 16px;
}
}
}
</style>
......@@ -27,6 +27,14 @@ export default {
visible: {
type: Boolean,
default: true,
},
hidePpt: {
type: Number,
default: 0,
},
showFlag: {
type: Number,
default: 0,
}
},
data() {
......@@ -88,7 +96,7 @@ export default {
canvas.style['-webkit-filter'] = 'blur(3px)';
canvas.style.filter = 'blur(3px)';
}
let ctx = canvas.getContext("2d");
let renderTask = pdfPage.render({
canvasContext: ctx,
......@@ -110,7 +118,7 @@ export default {
this.$store.dispatch('goLogin');
return;
}
this.$toast('前往APP购买查看')
this.$toast((this.hidePpt && this.showFlag === 0) ? '请前往App查看' : '购买/激活后可查看课件')
}
box.appendChild(cover);
}
......
......@@ -23,10 +23,8 @@ export default {
this.$sendBuriedData({
component_tag: `882#${this.tag}`
});
setTimeout(() => {
window.location.href =
"https://a.app.qq.com/o/simple.jsp?pkgname=com.picahealth.yunque";
}, 100);
window.location.href =
"https://a.app.qq.com/o/simple.jsp?pkgname=com.picahealth.yunque";
},
},
created() {
......
......@@ -74,7 +74,7 @@
<slot></slot>
<!-- 试看提示 -->
<div class="proved-box" v-show="logged && showProved">
可试看{{ dealTime(proved) }},观看完整版请<span @click="download">云鹊医App</span>
可试看{{ dealTime(proved) }},观看完整版请 <span @click="download">购买课程</span>
</div>
<!-- 重新播放,只有试看有 -->
<div class="replay-box" v-show="showReplay" @click="onReplay">重新播放</div>
......
......@@ -13,6 +13,7 @@ import BuriedPoint, { sendBuriedData } from 'web-buried-point';
import Vant from 'vant';
import 'vant/lib/index.css';
import clipboard from 'clipboard';
import { querystring } from '@/utils';
//注册到vue原型上
Vue.prototype.clipboard = clipboard;
......@@ -68,10 +69,28 @@ function fliterRoute(query, path) {
delete query.projectId;
has = true;
}
// 商品详情页去掉code
if (path === '/goods-detail' && query.code) {
store.dispatch('getWxUserInfo', query.code);
delete query.code;
let goodsDetailParams = sessionStorage.getItem('goodsDetailParams');
goodsDetailParams = goodsDetailParams ? JSON.parse(goodsDetailParams) : {};
Object.assign(query, goodsDetailParams);
has = true;
}
return [query, has];
}
router.beforeEach((to, from, next) => {
// 商品页授权登录路由处理
if (to.path === '/goods-detail') {
let searchQuery = querystring(location.search);
if (searchQuery.code) {
let newUrl = location.origin + location.pathname + '#/goods-detail?code=' + searchQuery.code;
location.replace(newUrl);
return;
}
}
let query = { ...to.query };
// 登录token保存并替换路径
let [newQuery, has] = fliterRoute(query, to.path);
......
import App from '../App'
const index = r => require.ensure([], () => r(require('../views/index')), 'index')
const complist = r => require.ensure([], () => r(require('../views/component-details')), 'complist')
const parent = r => require.ensure([], () => r(require('../views/parent-page')), 'parent')
const merge = r => require.ensure([], () => r(require('../views/merge-detail')), 'merge')
const test = r => require.ensure([], () => r(require('../views/test-components')), 'test-components')
export default [{
path: '/',
component: App,
children: [
{
path: '',
redirect: '/index'
},
{
path: '/index',
component: index
},
{
path: '/home',
component: index
},
{
path: '/comp2',
component: complist
},
{
path: '/parent',
component: parent
},
{
path: '/coop',
component: merge
},
{
path: '/test',
component: test
},
]
}]
......@@ -6,6 +6,8 @@ const shareMerge = r => require.ensure([], () => r(require('../views/share-merge
const test = r => require.ensure([], () => r(require('../views/test-components')), 'test-components')
const courseDetail = r => require.ensure([], () => r(require('../views/course-detail')), 'course-detail')
const notFound = r => require.ensure([], () => r(require('../views/not-found')), 'not-found')
const goodsDetail = r => require.ensure([], () => r(require('../views/goods-detail')), 'goods-detail')
const purchaseRezult = r => require.ensure([], () => r(require('../views/purchase-rezult')), 'purchase-rezult')
export default [{
path: '/',
......@@ -43,5 +45,13 @@ export default [{
path: '/not-found',
component: notFound
},
{
path: '/goods-detail',
component: goodsDetail
},
{
path: '/prezult',
component: purchaseRezult
},
]
}]
......@@ -2,12 +2,17 @@ import { Toast } from 'vant';
import fetch from '@/utils/fetch';
import { getBaseUrl } from '@/utils/index'
import { setCookie, delCookie } from '@/utils/index';
import { envConfig } from '@/utils/env-config'
import { envConfig } from '@/utils/env-config';
let wxInfo = sessionStorage.getItem('wxInfo');
wxInfo = wxInfo ? JSON.parse(wxInfo) : {};
const user = {
state: {
token: localStorage.getItem('token') || '',
info: {}, // 用户信息
wxInfo, // 微信信息,openid等
wxCode: '', // 微信code
},
mutations: {
SET_TOKEN: (state, payload) => {
......@@ -16,6 +21,12 @@ const user = {
SET_USER_INFO_2: (state, payload) => {
state.info = payload;
},
SET_WX_INFO: (state, payload) => {
state.wxInfo = payload;
},
SET_WX_CODE: (state, payload) => {
state.wxCode = payload;
},
},
actions: {
// 外部登陆返回设置token
......@@ -69,6 +80,21 @@ const user = {
window.location.href = envConfig[process.env.BUILD_ENV]['webPageUrl'] + "/pica_login?target_url=" + encodeURIComponent(location.href);
},
getWxUserInfo({ state, commit }, code) {
commit('SET_WX_CODE', code);
const type = 15;
// let url = getBaseUrl(`wechats/users/info/${type}/${code}`);
let url = `https://sc.yunqueyi.com/wechats/users/info/${type}/${code}`; // 测试支付,暂时使用线上
fetch({
url,
method: 'get',
headers: { token: state.token }
}).then(res => {
sessionStorage.setItem('wxInfo', JSON.stringify(res.data));
commit('SET_WX_INFO', res.data)
});
},
// 登出
logout({ state, commit }) {
commit('SET_TOKEN', '');
......
......@@ -96,6 +96,11 @@ html,body{
zoom:1;
}
.deep-img-w100 img{
display: block;
width: 100%;
}
.back_img{
background-repeat: no-repeat;
background-size: 100% 100%;
......
......@@ -180,3 +180,7 @@
color: #449284;
}
}
.van-loading__spinner {
width: 40px !important;
height: 40px !important;
}
......@@ -8,19 +8,21 @@ export const envConfig = {
// baseUrl: 'http://10.177.15.180:10202/',
// baseUrl: 'http://192.168.140.14:10201/',
// apiUrl: 'https://dev-api.yunqueyi.com/',
// webPageUrl: 'https://dev-phome.yunqueyi.com/',
// baseUrl: 'https://dev-sc.yunqueyi.com/',
// hactiveUrl: 'https://dev-hactive.yunqueyi.com',
// fileUrl: 'https://dev-www.yunqueyi.com',
// appId: 'wxf4e66242d31c81c2', // 用于微信授权登录
baseUrl: 'https://test1-sc.yunqueyi.com/',
apiUrl: 'https://test1-api.yunqueyi.com/',
webPageUrl: 'https://test1-phome.yunqueyi.com/',
apiUrl: 'https://dev-api.yunqueyi.com/',
baseUrl: 'https://dev-sc.yunqueyi.com/',
webPageUrl: 'https://dev-phome.yunqueyi.com/',
hactiveUrl: 'https://dev-hactive.yunqueyi.com',
fileUrl: 'https://test1-www.yunqueyi.com',
appId: 'wxcaad75b7fff5659c', // 用于微信授权登录
fileUrl: 'https://dev-www.yunqueyi.com',
appId: 'wx08b383d002c73f26', // 用于微信授权登录
// appId: 'wxf4e66242d31c81c2', // 用于微信授权登录
// baseUrl: 'https://test1-sc.yunqueyi.com/',
// apiUrl: 'https://test1-api.yunqueyi.com/',
// webPageUrl: 'https://test1-phome.yunqueyi.com/',
// hactiveUrl: 'https://dev-hactive.yunqueyi.com',
// fileUrl: 'https://test1-www.yunqueyi.com',
// appId: 'wxcaad75b7fff5659c', // 用于微信授权登录
// baseUrl: 'https://uat-sc.yunqueyi.com/',
// apiUrl: 'https://uat-api.yunqueyi.com/',
......@@ -47,7 +49,7 @@ export const envConfig = {
webPageUrl: 'https://dev-phome.yunqueyi.com/',
hactiveUrl: 'https://dev-hactive.yunqueyi.com',
fileUrl: 'https://dev-www.yunqueyi.com',
appId: 'wxf4e66242d31c81c2', // 用于微信授权登录
appId: 'wx2c577552a2d28550', // 用于微信授权登录
},
test: {
baseUrl: 'https://test1-sc.yunqueyi.com/',
......@@ -55,7 +57,8 @@ export const envConfig = {
webPageUrl: 'https://test1-phome.yunqueyi.com/',
hactiveUrl: 'https://test1-hactive.yunqueyi.com',
fileUrl: 'https://test1-www.yunqueyi.com',
appId: 'wxcaad75b7fff5659c', // 用于微信授权登录
// appId: 'wxcaad75b7fff5659c', // 用于微信授权登录
appId: 'wx2c577552a2d28550', // 用于微信授权登录
},
uat: {
baseUrl: 'https://uat-sc.yunqueyi.com/',
......@@ -63,7 +66,8 @@ export const envConfig = {
webPageUrl: 'https://uat-phome.yunqueyi.com/',
hactiveUrl: 'https://uat-hactive.yunqueyi.com',
fileUrl: 'https://uat-www.yunqueyi.com',
appId: 'wx342ef0e5afee54a7', // 用于微信授权登录
// appId: 'wx342ef0e5afee54a7', // 用于微信授权登录
appId: 'wx2c577552a2d28550', // 用于微信授权登录
},
pro: {
baseUrl: 'https://sc.yunqueyi.com/',
......
......@@ -205,6 +205,16 @@ export function isWeiXin() {
}
}
//弹出微信授权
export const wxOauth = () => {
let url = location.href, redirectUrl;
let appId = getAPPID();
url = url.split('?')[0];
redirectUrl = encodeURIComponent(url);
console.log('wxOauth redirectUrl => ', redirectUrl);
window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUrl}&response_type=code&scope=snsapi_userinfo&#wechat_redirect`;
}
export const setCookie = (name, value, time) => {
var expires = 30 * 24 * 60 * 60 * 1000; //一天
var date = new Date(+new Date() + expires);
......@@ -237,4 +247,31 @@ export const getCookie = key => {
}
}
return '';
};
\ No newline at end of file
};
export function debounce(fn, wait = 50) {
let timer;
return function() {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arguments);
timer = null;
}, wait)
}
}
function decode(input) {
return decodeURIComponent(input.replace(/\+/g, ' '));
}
export function querystring(query) {
var parser = /([^=?&]+)=?([^&]*)/g
, result = {}
, part;
for (;
part = parser.exec(query);
result[decode(part[1])] = decode(part[2])
);
return result;
}
......@@ -212,7 +212,23 @@ module.exports = {
return null
},
onAvatarError(e) {
e.target.src = 'https://file.yunqueyi.com/File/doctor_default.png';
e.target.src = 'https://file.yunqueyi.com/File/doctor_default.png';
},
// 通用token校验
commonCheckToken(noLoggedCallback) {
let param = {
token: this.token,
setEntry: true
};
this.GET("campaign/admin/task/checkToken", param).then(res => {
if (res.code !== "000000") {
this.goLogin();
} else {
noLoggedCallback && noLoggedCallback()
}
});
}
}
}
......@@ -8,7 +8,8 @@ export const wxConfig = (link) => {
// const params = { resetURI: true, url: encodeURIComponent(location.href) };
// 上线前是需要把域名改为线上的sc
let baseUrl = getBaseUrl("");
request({ url: `https://sc.yunqueyi.com/wechats/signs?url=${encodeURIComponent(link)}` }).then(res => {
let type = '&type=15'; // 本来没有,暂时改成线上
request({ url: `https://sc.yunqueyi.com/wechats/signs?url=${encodeURIComponent(link)}${type}` }).then(res => {
// request({ url: `${baseUrl}/wechats/signs?url=${encodeURIComponent(link)}` }).then(res => {
let configs = res.data.signMap;
wx.config({
......@@ -122,6 +123,12 @@ export const wechatShare = (option = {}, successCB = () => {}, hideMenu) => {
}
};
export function chooseWXPay(params) {
wx.ready(() => {
wx.chooseWXPay(params);
})
}
Vue.prototype.wechatShare = wechatShare;
Vue.prototype.wxDisabledShare = wxDisabledShare;
......
......@@ -2,10 +2,15 @@
<div class="course-detail">
<!-- 视频 -->
<div class="video-box">
<pica-video ref="picaVideo" :coverType="coverType" :download="download" @onVideoEnd="onVideoEnd" @onReplay="onReplay">
<pica-video ref="picaVideo" :coverType="coverType" :download="btnClick1" @onVideoEnd="onVideoEnd" @onReplay="onReplay">
<!-- 试看结束 -->
<div class="cover" v-if="logged && coverType === 1">
<course-covers coverTips="试看结束<br />请来云鹊医App学习完整课程" :isSingle="true" rightBtnText="APP购买更优惠" @btnClick="btnClick" />
<course-covers
coverTips="试看结束<br />请来云鹊医App学习完整课程"
:isSingle="true"
rightBtnText="立即购买"
@btnClick="btnClick1"
/>
</div>
<!-- 付费课程,下载App -->
<div class="cover" v-if="logged && coverType === 2">
......@@ -62,7 +67,7 @@
</div>
<brief-intro v-show="curtTabIdx === 0" :doctor-list="doctors" :intro="course.intro" :harvest="harvest" />
<course-catalog v-show="curtTabIdx === 1" :list="chapters" :curtId="curtLectureId" :onToggle="onToggle" :onSelect="selectLecture" :download="download" />
<course-ware v-show="curtTabIdx === 2" :url="pdfUrl" :visible="pdfVisible" />
<course-ware v-show="curtTabIdx === 2" :url="pdfUrl" :visible="pdfVisible" :hidePpt="course.hidePpt" :showFlag="course.showFlag" />
<course-comment v-show="curtTabIdx === 3" :list="qsList" :download="download" />
</div>
</div>
......@@ -150,6 +155,7 @@ export default {
this.$store.dispatch('getUserInfo');
}
this.projectId = sessionStorage.getItem('projectId');
this.goodsId = this.$route.query.goodsId;
if (!this.projectId) {
this.$router.replace('/not-found');
return;
......@@ -299,6 +305,9 @@ export default {
//
}
},
btnClick1() {
this.$router.push({ path: '/goods-detail', query: { goodsId: this.goodsId, projectId: this.projectId } })
},
// 折叠、展开目录
onToggle(index) {
const item = this.chapters[index];
......
此差异已折叠。
......@@ -86,6 +86,7 @@
:courseRequire="courseRequire"
:hasBindCard="hasBindCard"
:limitTimes="limitTimes"
:projectId="projectId"
/>
</div>
</div>
......@@ -145,6 +146,14 @@
:isShowDialog="isShowIOSDownloadDialog"
@handlerAction="goBack"
/>
<CourseDialog
:subContent="subContent"
confirmBtnText="激活并去学习"
needSubContent
:isShowDialog="showBindCardTips"
@handlerAction="handlerAction"
></CourseDialog>
</div>
</template>
<script>
......@@ -162,6 +171,7 @@ import ItemIntro from "@/components/cme/item-intro";
import ItemLeader from "@/components/cme/item-leader";
import TeacterIntro from "@/components/cme/teacter-intro";
import CommonDialog from "@/components/cme/common-dialog";
import CourseDialog from "@/components/course/course-dialog";
import ExjumperButton from "@/components/cme/exjumper-button";
import NoMoreContent from "@/components/business/no-more-content";
import CommonAdertImg from "@/components/common/common-advert-img";
......@@ -269,6 +279,14 @@ export default {
isShowSkDialog: false,
isShowIOSDownloadDialog: false,
shareUrl: location.href,
showBindCardTips: false,
cmeCardModels: {
cardNo: "",
cardKey: "",
cardType: 3,
orderId: 0
},
subContent: ``,
};
},
components: {
......@@ -284,6 +302,7 @@ export default {
ItemLeader,
TeacterIntro,
CommonDialog,
CourseDialog,
ExjumperButton,
CommonAdertImg,
NoMoreContent,
......@@ -355,8 +374,37 @@ export default {
this.showChangeCard = false;
},
// 处理提示信息框
handlerAction(type) {
if(type == 1) {
this.$sendBuriedData({
component_tag: `882#88219`
});
this.showBindCardTips = false;
} else {
this.$sendBuriedData({
component_tag: `882#88218`
});
this.changeCardAction(this.cmeCardModels.cardKey, true)
}
},
// 查询是否买过类似的卡,但还没有绑定
hasNoUsedCard() {
let param = {
setEntry: true
};
this.GET(`cme/projectCard/queryNoUsedCard/3`, param).then(({ data }) => {
this.hasNoUsedCard = data.hasNoUsedCard;
if (data.hasNoUsedCard == 1) {
this.cmeCardModels = data.cmeCardModels[0] || {};
this.showBindCardTips = true;
}
});
},
// 激活 返回值:0绑定失败,1绑定成功
changeCardAction(cardKey) {
changeCardAction(cardKey, isInTips) {
let _this = this;
let param = {
cardKey: cardKey,
......@@ -366,9 +414,14 @@ export default {
};
_this.changeCardErrorMsg = "";
this.POST("cme/projectCard/bind", param).then(res => {
isInTips && (_this.showBindCardTips = false);
if (res.code == "000000") {
if(res.data == 0) {
_this.changeCardErrorMsg = "请输入正确的激活码";
if(isInTips) {
Toast(res.message);
} else {
_this.changeCardErrorMsg = "请输入正确的激活码";
}
} else {
_this.$refs.tcPlayerRef && _this.$refs.tcPlayerRef.pause();
_this.showChangeCard = false;
......@@ -376,9 +429,16 @@ export default {
_this.getProjectInfoById();
}
} else {
Toast(res.message);
}
}).catch( e => {
_this.changeCardErrorMsg = "请输入正确的激活码";
console.log('in catch', isInTips);
if(isInTips) {
Toast("无效的激活码");
_this.showBindCardTips = false;
} else {
_this.changeCardErrorMsg = "请输入正确的激活码";
}
});
},
......@@ -501,7 +561,8 @@ export default {
this.POST("trade/goods/cardList", param).then(res => {
if (res.code == "000000") {
this.showLoading = false;
this.cardInfo = (res.data && res.data[0]) || { id: 0 };
this.cardInfo = (res.data && res.data[0]) || { id: 0, name: "职称考精讲课程卡" };
this.subContent = `您已购买“${this.cardInfo.goodsName}”,是否用此卡绑定并激活当前课程。学习卡激活码一旦使用,不可更改不可退回`
}
});
},
......@@ -528,8 +589,7 @@ export default {
return;
}
// let pageUrl = this.project.examBtnUrl;
// 直接传入项目ID(projectId)
// 直接传入职称考项目ID(projectId)
let projectId = this.project.projectId;
let pageUrl = getWebPageUrl(
`/profexam/#/index?id=${projectId}&projectName=${this.project.projectName}&profexamProjectId=${projectId}`
......@@ -761,6 +821,9 @@ export default {
if(_this.hasBindCard) {
_this.videoOptions.trySeeTime = 300000;
_this.videoOptions.autoplay = false;
// 如果没有绑定卡,则查询是否有未绑定的卡
} else {
_this.hasNoUsedCard();
}
let mp4Url = _this.videoOptions.mp4;
// 判断是否是mp4
......@@ -1025,10 +1088,6 @@ export default {
return;
}
let paramList = []
// let limitTimes = this.limitTimes - 0;
// if(this.hasBindCard) {
// limitTimes = -1;
// }
paramList = [
{
key: "className",
......@@ -1054,12 +1113,12 @@ export default {
type: 4,
seqNo: 1
},
// {
// key: "limitTimes",
// value: limitTimes,
// type: 4,
// seqNo: 1
// },
{
key: "projectId",
value: this.projectId,
type: 4,
seqNo: 1
},
];
console.log('gotoCourse', paramList);
rocNative.dispatchEventByModuleCode({
......
<template>
<div class="not-found">
<img class="img" src="~@/images/no-content.png" alt="" />
<p class="tip">此课程已下架,无法查看</p>
<img class="img" src="~@/images/no-content.png" alt />
<p class="tip">{{tips}}</p>
<p class="tip-2">更多内容,请前往云鹊医APP学习</p>
</div>
</template>
<script>
export default {
data() {
return {};
return {
tips: "此课程已下架,无法查看",
fromPage: "2"
};
},
mounted() {
this.fromPage = this.$route.query.fromPage || '1'; // 1: 来处项目详情页; 2: 来处课程详情页
if(this.fromPage == 2) {
this.tips = "此项目已下架, 无法查看";
}
},
methods: {
}
methods: {}
};
</script>
<style lang="less" scoped>
.not-found {
.img{
display: block;
display: flex;
flex-direction: column;
align-items: center;
padding-top: 100px;
.img {
width: 120px;
margin: 100px auto 0;
}
.tip{
font-size: 15px;
.tip {
font-size: 18px;
font-weight: 700;
color: #373839;
text-align: center;
padding: 0 15px;
}
.tip-2 {
margin-top: 12px;
font-size: 14px;
font-weight: 400;
color: #676869;
text-align: center;
padding: 0 15px;
}
}
</style>
......
<template>
<div class="purchase-wrapper">
<img v-show="isCorrect" class="status-img" src="../images/puchase/correct.png" />
<img v-show="!isCorrect" class="status-img" src="../images/puchase/warning.png" />
<div class="msg-content-wrapper">
<p class="msg-content" v-html="msgContent"></p>
<!-- 直接从商品过来的 -->
<p v-if="!projectId" class="msg-content-2">订单详情页打开/下载云鹊医APP查看</p>
</div>
<Button v-show="projectId" @handlerClick="gotoProject"></Button>
<Button :isPlain="!!projectId" buttonText="去云鹊医APP" @handlerClick="download"></Button>
<CourseDialog
subContent='请在微信内完成支付,如果您已支付成功,请点击“已完成支付”按钮'
confirmBtnText="已完成支付"
needSubContent
:isShowDialog="isShowDialog"
@handlerAction="handlerAction"
></CourseDialog>
<van-overlay :show="loading" @click="show = false" class="v-overlay">
<div class="loading-wrapper" >
<van-loading type="spinner" />
<p class="text">{{projectId ? '课程解锁中' : '正在交易中'}} {{loadingTimes}}s</p>
</div>
</van-overlay>
</div>
</template>
<script>
import { getWebPageUrl, getCookie } from "@/utils/index";
import CourseDialog from "@/components/course/course-dialog";
import Button from "@/components/business/button"
let intervalId = null;
export default {
components: {
Button,
CourseDialog
},
data() {
return {
projectId: 1,
orderId: '1595497912391728990',
htmlTitle: "支付结果",
isCorrect: true,
// msgContent: "此项目已被其他学习卡绑定,您可以去绑定新的项目,或去云鹊医APP查看订单详情",
msgContent: "购买成功",
loading: true,
loadingTimes: 3,
// 返回值data:0:订单进行中 1:支付并绑定成功 2:订单反馈延时,请稍后再试 3:支付失败,请重新购买 4:订单已被取消,请重新购买
bindStatus: 0,
showGoApp: true,
hasShowed: false,
isShowDialog: false,
returnUrl: "",
}
},
created() {
let { projectId, orderId } = this.$route.query;
this.projectId = projectId || 0;
this.orderId = orderId || 0;
this.returnUrl = localStorage.getItem('returnUrl');
console.log('projectId', 'orderId', this.projectId, this.orderId, this.returnUrl);
// 直接从商品过来的
// if(!this.projectId) {
// this.msgContent = "购买成功";
// }
// 等待
intervalId = setInterval( () => {
if(this.loadingTimes <= 0) {
intervalId && clearInterval(intervalId);
// 从项目购买过来的
if(this.projectId) {
this.getBindCardStatus();
// 直接从商品过来的
} else {
this.getStatusByOrderId();
}
} else {
this.loadingTimes -= 1;
}
}, 1000)
},
mounted() {
document.title = this.htmlTitle;
},
methods: {
// 弹框:手动点击“已完成支付”
handlerAction(type) {
this.isShowDialog = false;
if(type == 1) {
// if(this.projectId) {
// this.gotoProject();
// } else {
// this.download();
// }
} else {
if(this.projectId) {
this.getBindCardStatus();
} else {
this.getStatusByOrderId();
}
}
},
// 查询一次绑卡状态
getBindCardStatus() {
let _this = this;
let param = {
projectId: this.projectId,
orderId: this.orderId,
setEntry: true
};
this.GET(`cme/projectCard/status/${this.projectId}/${this.orderId}`, param).then(({ data }) => {
this.loading = false;
this.bindStatus = data;
// 绑定成功
if( data == 1 ) {
this.msgContent = "购买成功";
this.isCorrect = true;
} else {
if(!this.hasShowed) {
this.hasShowed = true;
this.isShowDialog = true;
}
this.msgContent = "解锁延时,您可返回项目继续学习";
this.isCorrect = false;
}
}).catch( e => {
console.log("getBindCardStatus", "调用失败...");
});
},
// 直接根据订单ID获取订单状态
getStatusByOrderId() {
let _this = this;
let param = {
orderId: this.orderId,
};
this.GET(`trade/center/order/query`, param).then(({ data }) => {
this.loading = false;
this.msgContent = "购买失败";
this.isCorrect = false;
// 订单状态: 订单状态:1待支付, 2支付中, 3支付失败, 4订单超时, 5支付成功, 6交易完成, 7交易关闭
if( data.orderDto.status == 6 ) {
this.msgContent = "购买成功";
this.isCorrect = true;
} else {
if(!this.hasShowed) {
this.hasShowed = true;
this.isShowDialog = true;
}
}
}).catch( e => {
console.log("getStatusByOrderId", "调用失败...");
});
},
// 返回到项目详情页面
gotoProject() {
this.$sendBuriedData({
component_tag: `889#88901`
});
this.returnUrl && location.replace(this.returnUrl);
},
// 下载
download() {
this.$sendBuriedData({
component_tag: `889#88902`
});
window.location.href = "https://a.app.qq.com/o/simple.jsp?pkgname=com.picahealth.yunque";
}
},
}
</script>
<style lang="less" scoped>
.purchase-wrapper {
padding-top: 60px;
// display: flex;
// flex-direction: column;
text-align: center;
.status-img {
width: 60px;
height: 60px;
}
.msg-content-wrapper {
margin-bottom: 30px;
.msg-content {
margin: 0 20px 10px;
color: #48494A;
font-size: 16px;
font-weight: 700;
line-height: 1.5;
}
.msg-content-2 {
color: #676869;
font-size: 14px;
}
}
.v-overlay {
background-color: #fff;
padding-top: 200px;
.loading-wrapper {
text-align: center;
.text {
margin-top: 12px;
color: #A1A2A3;
font-size: 14px;
}
}
}
}
</style>
\ No newline at end of file
此差异已折叠。
......@@ -2,7 +2,7 @@
<div class="test-container">
<!-- <CommonButton btnText="去学习"></CommonButton> -->
<!-- <CommonDialog content="该项目仅对河北省石家庄市的用户开放" :isShowDialog="isShowDialog" @handlerAction="handlerDialogAction"></CommonDialog> -->
<!-- <CommonDialog content="您暂未认证身份,完成认证身份后可申请学分" confirmBtnText="去认证" :isShowDialog="isShowDialog" @handlerAction="handlerDialogAction"></CommonDialog> -->
<CommonDialog content="您暂未认证身份,完成认证身份后可申请学分" confirmBtnText="去认证" :isShowDialog="isShowDialog" @handlerAction="handlerDialogAction"></CommonDialog>
<!-- <CommonDialog content="您暂未加入机构,加入机构后且认证身份后可申请学分" confirmBtnText="加入机构" :isShowDialog="isShowDialog" @handlerAction="handlerDialogAction"></CommonDialog> -->
<!-- <CommonDialog content="您的所属机构不在可申请范围(河北省石家庄市)内" cancleBtnText="我知道了" isSingle :isShowDialog="isShowDialog" @handlerAction="handlerDialogAction"></CommonDialog> -->
<!-- <CommonDialog content="提交成功" subContent="您可在“个人中心-证书与学分”中查看审核结果" cancleBtnText="我知道了" isSingle needSubContent :isShowDialog="isShowDialog" @handlerAction="handlerDialogAction"></CommonDialog> -->
......@@ -39,7 +39,7 @@ export default {
},
components: {
// CommonButton,
// CommonDialog,
CommonDialog,
// CommonBottomInfo,
// CommonErrorTips,
CourseButton,
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册