提交 c7690386 authored 作者: lihuihui's avatar lihuihui
......@@ -65,7 +65,6 @@
"dependencies": {
"axios": "^0.19.2",
"cross-env": "^7.0.2",
"element-ui": "^2.13.0",
"js-cookie": "^2.2.1",
"lodash": "^4.17.15",
"promise.prototype.finally": "^3.1.2",
......
import BaseAPI from '@/api/base_api'
const httpRequest = new BaseAPI(webConf)
// 登录
export function login(data) {
return httpRequest.post('/passport/rest/login', data, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})
}
// 绑定微信
export function bindWechat(data) {
return httpRequest.post('/passport/rest/wechat/bind-unionid', data, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})
}
// 重置密码
export function resetPassword(data) {
return httpRequest.post('/usercenter/user/update-pwd', data, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})
}
// 发送重置验证码
export function sendResetPasswordCode(data) {
return httpRequest.post('/usercenter/user/send-code', data, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})
}
// 登出
export function logout() {
return httpRequest.post('https://learn-pbcsf.ezijing.com/api/clear/cookie')
}
// 获取用户信息
export function getUser() {
return httpRequest.get('/zy/user/getinfo')
}
<template>
<div style="width: 100%;" id="app">
<router-view></router-view>
<router-view :key="$route.fullPath"></router-view>
</div>
</template>
......
import Cookies from 'js-cookie'
import VueI18n from 'vue-i18n'
import language from './language'
import zhCNLocale from 'element-ui/lib/locale/lang/zh-CN'
import enLocale from 'element-ui/lib/locale/lang/en'
// import zhCNLocale from 'element-ui/lib/locale/lang/zh-CN'
// import enLocale from 'element-ui/lib/locale/lang/en'
export default () => {
let _locale = 'zh-CN'
......@@ -34,8 +34,8 @@ export default () => {
return new VueI18n({
locale: _locale, // 定义默认语言为中文
messages: {
'zh-CN': Object.assign(require('./zh-CN.json'), zhCNLocale),
en: Object.assign(require('./en.json'), enLocale)
'zh-CN': Object.assign(require('./zh-CN.json')),
en: Object.assign(require('./en.json'))
}
})
}
<template>
<van-button
native-type="button"
:disabled="currentDisabled"
:loading="loading"
>
{{ curretnValue }}
</van-button>
</template>
<script>
export default {
name: 'CountdownButton',
props: {
step: { type: Number, default: 1000 },
disabled: { type: Boolean, default: false },
seconds: { type: Number, default: 60 },
defaultValue: { type: String, default: '获取验证码' }
},
data() {
return {
currentDisabled: false,
currentSeconds: 0,
loading: false,
timer: null
}
},
computed: {
curretnValue() {
const longTime = this.seconds - this.currentSeconds
return longTime < this.seconds ? `${longTime}秒后重发` : this.defaultValue
}
},
methods: {
genTimer() {
this.timer && clearInterval(this.timer)
this.timer = setInterval(() => {
this.currentSeconds++
if (this.currentSeconds === this.seconds) {
this.stop()
}
}, this.step)
},
start() {
this.loading = false
this.currentDisabled = true
this.genTimer()
},
stop() {
this.timer && clearInterval(this.timer)
this.currentSeconds = 0
this.currentDisabled = false
}
}
}
</script>
<style lang="scss" scoped>
.van-button {
height: 40px;
line-height: 38px;
}
.van-button--default {
border-color: #999;
}
</style>
......@@ -40,6 +40,9 @@ export default {
}
.course-item-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.course-item-pic {
width: 2.4rem;
......@@ -63,8 +66,11 @@ export default {
overflow: hidden;
}
.course-item__text {
margin: 0.37rem 0 0 0;
font-size: 0.26rem;
color: #999;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
</style>
......@@ -4,8 +4,8 @@
<h3 class="course-item__title">{{data.course_name}}</h3>
<p class="course-item__text" v-if="data.describe">{{data.describe}}</p>
</div>
<div class="course-item-pic" v-if="data.image_url">
<img :src="data.image_url" />
<div class="course-item-pic" v-if="data.picture">
<img :src="data.picture" />
</div>
</div>
</template>
......@@ -16,10 +16,17 @@ export default {
props: {
data: { type: Object, required: true }
},
computed: {
isWeapp() {
return this.$store.state.isWeapp
}
},
methods: {
onClick(data) {
if (this.isWeapp) {
wx.miniProgram.navigateTo(`/pages/course/item?id=${data.course_id}`)
wx.miniProgram.navigateTo({
url: `/pages/course/item?id=${data.course_id}`
})
} else {
window.alert('请在微信小程序中打开')
}
......@@ -36,6 +43,9 @@ export default {
}
.course-item-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.course-item-pic {
width: 2.4rem;
......@@ -58,8 +68,11 @@ export default {
overflow: hidden;
}
.course-item__text {
margin: 0.37rem 0 0 0;
font-size: 0.26rem;
color: #999;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
</style>
......@@ -65,7 +65,7 @@ export default {
padding: 0.2rem 0.2rem 0.2rem 0.9rem;
height: 0.66rem;
font-size: 0.26rem;
line-height: 1;
line-height: 0.26rem;
background: #f7f7f7 url('~@/assets/images/icon_search.png') no-repeat 0.4rem
center;
background-size: 0.31rem;
......
......@@ -4,31 +4,17 @@
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="origin" name="referrer">
<title></title>
<title>道路运输安全知识线上课</title>
<meta name="viewport" id="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, shrink-to-fit=no">
</head>
<body>
<div id="app"></div>
<script src="https://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<!-- es5 兼容 新方法 -->
<script type="text/javascript" src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/compatible/es5-shim.min.js"></script>
<script type="text/javascript" src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/compatible/es5-sham.min.js"></script>
<!-- 三方插件引入 -->
<script type="text/javascript" src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/ckeditor/ckeditor.js"></script>
<!-- common -->
<script type="text/javascript" src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/common/base64.js"></script>
<script type="text/javascript" src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/common/md5.js"></script>
<script type="text/javascript" src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/common/jQuery-2.1.4.min.js"></script>
<script type="text/javascript" src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/common/runtime.js"></script>
<!--[if lt IE 9]>
<script src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/compatible/console-polyfill.js"></script>
<script src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/compatible/html5shiv.min.js"></script>
<script src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/compatible/respond.min.js"></script>
<![endif]-->
</body>
</html>
<style>
html,body{
html,body {
background: #fff;
}
}
</style>
......@@ -9,7 +9,6 @@ import App from './app.vue' // 初始化 vue页面
import './style.scss' // 公共样式
import './assets/rem/rem.js'
import MetaInfo from 'vue-meta-info'
import Element from 'element-ui'
import modules from './modules'
// vant
......@@ -31,7 +30,6 @@ const i18n = createI18n()
Vue.use(MetaInfo)
Vue.use(Element, { i18n: (key, value) => i18n.t(key, value) })
Vue.use(modules, { i18n })
/* 设置全局变量 */
......@@ -44,6 +42,7 @@ window.G = Vue.prototype.$GLOBAL = {
*/
Vue.prototype.VueEvent = new Vue()
Vue.prototype.wx = window.wx.miniProgram
/* 创建实例之前,通过导航守卫,处理部分逻辑,如:是否直接进入系统 */
// const before = createBefore()
/* 导航守卫 */
......@@ -57,3 +56,6 @@ window.G.$instance_vue = new Vue({
i18n,
render: h => h(App)
}).$mount('#app')
// 获取环境
store.dispatch('getEnv')
import Cookies from 'js-cookie'
import VueI18n from 'vue-i18n'
import language from './language'
import zhCNLocale from 'element-ui/lib/locale/lang/zh-CN'
import enLocale from 'element-ui/lib/locale/lang/en'
// import zhCNLocale from 'element-ui/lib/locale/lang/zh-CN'
// import enLocale from 'element-ui/lib/locale/lang/en'
export default () => {
let _locale = 'zh-CN'
......@@ -33,8 +33,8 @@ export default () => {
return new VueI18n({
locale: _locale, // 定义默认语言为中文
messages: {
'zh-CN': Object.assign(require('./zh-CN.json'), zhCNLocale),
en: Object.assign(require('./en.json'), enLocale)
'zh-CN': Object.assign(require('./zh-CN.json')),
en: Object.assign(require('./en.json'))
}
})
}
......@@ -2,7 +2,11 @@
<van-collapse v-model="activeNames">
<van-collapse-item :title="item.name" :name="item.id" v-for="item in data" :key="item.id">
<ul>
<li v-for="subItem in item.children" :key="subItem.id">{{subItem.name}}</li>
<li
v-for="subItem in item.children"
:key="subItem.id"
@click="onClick(subItem)"
>{{subItem.name}}</li>
</ul>
</van-collapse-item>
</van-collapse>
......@@ -11,6 +15,7 @@
<script>
export default {
props: {
courseId: String,
data: {
type: Array,
default: () => []
......@@ -20,6 +25,22 @@ export default {
return {
activeNames: []
}
},
computed: {
isWeapp() {
return this.$store.state.isWeapp
}
},
methods: {
onClick(data) {
if (this.isWeapp) {
wx.miniProgram.navigateTo({
url: `/pages/course/item?id=${this.courseId}&chapter_id=${data.id}`
})
} else {
window.alert('请在微信小程序中打开')
}
}
}
}
</script>
......
......@@ -9,7 +9,7 @@
@click="onTabClick"
>
<van-tab title="课程学习" name="0">
<course-chapter :data="detail.chapters"></course-chapter>
<course-chapter :courseId="courseId" :data="detail.chapters"></course-chapter>
</van-tab>
<van-tab title="知识点速学" name="1">
<course-tag></course-tag>
......
......@@ -6,14 +6,11 @@
<van-swipe-item>
<img src="../../assets/images/banner.png" />
</van-swipe-item>
<van-swipe-item>
<img src="../../assets/images/banner.png" />
</van-swipe-item>
</van-swipe>
</div>
<div class="nav">
<ul class="nav-list">
<li class="nav-item" @click="onClickNav('courseLearn')">
<li class="nav-item" @click="onClickNav('courseLearn', true)">
<img src="../../assets/images/home_menu_01.png" alt="课程学习" />
</li>
<li class="nav-item" @click="onClickNav('courseTest')">
......@@ -24,7 +21,7 @@
</li>
</ul>
</div>
<card title="课程试听">
<card title="课程试听" style="padding-bottom:40px;">
<free-course-item v-for="item in courseList" :data="item" :key="item.course_id"></free-course-item>
</card>
</div>
......@@ -38,14 +35,16 @@ import * as api from '@/api/course.js'
export default {
name: 'Index',
components: { SearchBar, Card, FreeCourseItem },
metaInfo: {
title: '道路运输安全知识学习'
},
data() {
return {
courseList: [] // 免费课程列表
}
},
computed: {
isWeapp() {
return this.$store.state.isWeapp
}
},
methods: {
// 获取课程试听列表
getCourseList() {
......@@ -55,10 +54,43 @@ export default {
},
// 搜索
toSearch() {
if (this.isWeapp) {
wx.miniProgram.navigateTo({
url: `/pages/web/index?src=${window.location.origin}/search`
})
} else {
this.$router.push({ name: 'search' })
}
},
// 点击导航
onClickNav(name) {
async onClickNav(name, requireLogin) {
const map = {
courseLearn: `/pages/web/index?src=${window.location.origin}/course/learn`,
courseTest: `/pages/web/index?src=${window.location.origin}/test`
}
const isLogin = requireLogin
? await this.$store.dispatch('checkLogin')
: false
// 未登录
if (requireLogin && !isLogin) {
if (this.isWeapp) {
// 小程序
wx.miniProgram.navigateTo({
url: `/pages/web/index?src=${
window.location.origin
}/login?is_weapp=1&redirect_uri=${encodeURIComponent(map[name])}`
})
} else {
this.$router.push({ name: 'login' })
}
return
}
if (this.isWeapp) {
// 小程序
wx.miniProgram.navigateTo({ url: map[name] })
return
}
// h5
this.$router.push({ name })
}
},
......
<template>
<div class="account-login">
<van-form class="login-form" ref="form" v-on="$listeners">
<van-field v-model="ruleForm.account" name="account" label="账号" placeholder="请输入账号"></van-field>
<van-field
type="password"
v-model="ruleForm.password"
name="password"
label="密码"
placeholder="请输入密码"
></van-field>
</van-form>
</div>
</template>
<script>
export default {
name: 'AccountLogin',
data() {
return {
ruleForm: { type: 1, account: '', password: '' }
}
},
methods: {
submit() {
if (!this.ruleForm.account) {
this.$notify('请输入手机/邮箱/用户名')
return false
} else if (!this.ruleForm.password) {
this.$notify('请输入密码')
return false
}
return this.$refs.form.submit()
}
}
}
</script>
<template>
<div class="login">
<div class="login-box">
<div class="login-hd">
<h2 class="login-title">绑定</h2>
</div>
<div class="login-bd">
<div class="login-form">
<!-- 账号登录 -->
<account-login ref="form" @submit="onSubmit"></account-login>
<!-- 验证码登录 -->
<!-- <code-login ref="form" @submit="onSubmit"></code-login> -->
<div class="login-button" @click="handleSubmit">立即绑定</div>
</div>
</div>
<div class="login-ft">
<p class="login-tips">
登录遇到困难?请点击
<span class="forget-password" @click="passwordVisible = true">找回密码</span>
</p>
</div>
</div>
</div>
</template>
<script>
import Cookies from 'js-cookie'
import * as api from '@/api/account'
import AccountLogin from './accountLogin.vue'
import CodeLogin from './codeLogin.vue'
export default {
components: { AccountLogin, CodeLogin },
data() {
const UA = navigator.userAgent.toLowerCase()
return {
ruleForm: {
type: 1,
account: '',
password: '',
RememberMe: true,
service: 'https://h5.ezijing.com'
},
passwordVisible: false,
isWechat: /micromessenger/.test(UA),
unionid: Cookies.get('wechat_login_no_phone_error')
}
},
computed: {
// 重定向地址
redirectURI() {
const { query } = this.$route
return query.redirect_uri ? decodeURIComponent(query.redirect_uri) : ''
}
},
methods: {
handleSubmit() {
this.$refs.form.submit()
},
// 提交
onSubmit(data) {
this.unionid ? this.bindWechat(data) : this.loginRequest(data)
},
// 登录
loginRequest(data) {
const params = Object.assign({}, this.ruleForm, data)
api
.login(params)
.then(response => {
this.loginSuccess(response)
})
.catch(error => {
error.response && this.$toast(error.response.data.message)
})
},
// 绑定微信并登录
bindWechat() {
const data = Object.assign({}, this.ruleForm, { unionid: this.unionid })
api
.bindWechat(data)
.then(response => {
this.loginSuccess(response)
})
.catch(error => {
error.response && this.$toast(error.response.data.message)
})
},
// 登录成功
loginSuccess(response) {
if (response.code === 0) {
Cookies.remove('wechat_login_error', { domain: '.ezijing.com' })
Cookies.remove('wechat_login_no_phone_error', {
domain: '.ezijing.com'
})
if (this.redirectURI) {
window.location.href = this.redirectURI
} else {
this.$router.replace('/')
}
// this.$router.replace('/')
} else {
this.$toast(response.msg)
}
},
wechatLogin() {
const appId = 'wx451c01d40d090d7a'
// 回调地址
const redirectURI = `${process.env.VUE_APP_WECHAT_REDIRECT_URL}?needCheck=false&identity=friend&redirectUrl=${window.location.origin}`
// 微信的地址
const wechatUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${encodeURIComponent(
redirectURI
)}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`
// 打开地址
window.location.href = wechatUrl
},
checkWechatLogin() {
return !!(
Cookies.get('wechat_login_error') ||
Cookies.get('wechat_login_no_phone_error')
)
}
},
created() {
// if (this.isWechat && !this.checkWechatLogin()) {
// this.wechatLogin()
// }
}
}
</script>
<style lang="scss">
.login {
position: relative;
min-height: 100vh;
display: flex;
flex-direction: column;
background: url('../../assets/images/login_bg.png') no-repeat;
background-size: contain;
}
.login-box {
position: absolute;
top: 100px;
left: 50px;
right: 50px;
height: 400px;
padding: 20px;
background: rgba(255, 255, 255, 1);
box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.1);
border-radius: 20px;
}
.login-hd {
padding: 10px 0;
}
.login-title {
display: inline-block;
font-size: 24px;
color: #2b7ce9;
border-bottom: 5px solid #2b7ce9;
}
.login-bd {
margin-top: 20px;
flex: 1;
}
.login-button {
margin-top: 20px;
height: 40px;
font-size: 12px;
color: #fff;
line-height: 40px;
background: linear-gradient(
270deg,
rgba(43, 124, 233, 1) 0%,
rgba(103, 168, 255, 1) 100%
);
text-align: center;
border-radius: 3px;
cursor: pointer;
}
.login-ft {
padding: 40px 0;
}
.login-tips {
text-align: center;
font-size: 12px;
color: #999;
.forget-password {
color: #1989fa;
}
}
.login {
.van-field {
margin-bottom: 20px;
padding: 0;
flex-direction: column;
}
.van-field__label {
font-size: 12px;
color: #222;
margin-bottom: 5px;
padding-left: 10px;
}
.van-field__control {
padding: 8px;
border: 1px solid #ccc;
border-radius: 3px;
}
}
</style>
<template>
<div class="code-login">
<van-form class="login-form" ref="form" v-on="$listeners">
<van-field v-model="ruleForm.account" name="account" label="手机号" placeholder="请输入手机号" />
<van-field v-model="ruleForm.password" name="password" label="验证码" placeholder="请输入验证码">
<template slot="button">
<countdown-button @click.native="onSendCode" ref="countdown"></countdown-button>
</template>
</van-field>
</van-form>
</div>
</template>
<script>
import * as api from '@/api/account'
import CountdownButton from '@/components/CountdownButton.vue'
export default {
name: 'CodeLogin',
components: { CountdownButton },
data() {
return {
ruleForm: { account: '', password: '' }
}
},
methods: {
submit() {
if (!this.ruleForm.account) {
this.$notify('请输手机号')
return false
} else if (!this.ruleForm.password) {
this.$notify('请输入验证码')
return false
}
return this.$refs.form.submit()
},
// 发送验证码
onSendCode() {
if (!this.ruleForm.account) {
this.$notify('请输手机号')
return false
}
// 开始倒计时
this.$refs.countdown.start()
this.sendCodeRequest()
},
// 验证码
sendCodeRequest() {
api
.sendResetPasswordCode({ account: this.ruleForm.account })
.then(response => {
if (response.code === 0) {
this.$notify({ type: 'success', message: '验证码发送成功' })
} else {
// 停止计时
this.$refs.countdown.stop()
this.$notify(response.msg)
}
})
.catch(error => {
// 停止计时
this.$refs.countdown.stop()
error.response && this.$notify(error.response.data.message)
})
}
}
}
</script>
<template>
<div class="login">
<h1 class="title">
全国道路运输企业主要负责人和
<br />安全生产管理人员安全考核管理
</h1>
<div class="login-box">
<div class="login-hd">
<h2 class="login-title">登录</h2>
</div>
<div class="login-bd">
<div class="login-form">
<!-- 账号登录 -->
<account-login ref="form" @submit="onSubmit"></account-login>
<!-- 验证码登录 -->
<!-- <code-login ref="form" @submit="onSubmit"></code-login> -->
<div class="login-button" @click="handleSubmit">立即登录</div>
</div>
</div>
<div class="login-ft">
<ul>
<li @click="wechatLogin">
<img src="../../assets/images/login_wechat.png" alt="微信登录" />微信登录
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
import Cookies from 'js-cookie'
import * as api from '@/api/account'
import AccountLogin from './accountLogin.vue'
import CodeLogin from './codeLogin.vue'
export default {
components: { AccountLogin, CodeLogin },
data() {
const UA = navigator.userAgent.toLowerCase()
return {
ruleForm: {
type: 1,
account: '',
password: '',
RememberMe: true,
service: 'https://h5.ezijing.com'
},
passwordVisible: false,
isWechat: /micromessenger/.test(UA),
unionid: Cookies.get('wechat_login_no_phone_error')
}
},
computed: {
isWeapp() {
return this.$store.state.isWeapp
},
// 重定向地址
redirectURI() {
const { query } = this.$route
return query.redirect_uri ? decodeURIComponent(query.redirect_uri) : ''
}
},
methods: {
handleSubmit() {
this.$refs.form.submit()
},
// 提交
onSubmit(data) {
this.unionid ? this.bindWechat(data) : this.loginRequest(data)
},
// 登录
loginRequest(data) {
const params = Object.assign({}, this.ruleForm, data)
api
.login(params)
.then(response => {
this.loginSuccess(response)
})
.catch(error => {
error.response && this.$toast(error.response.data.message)
})
},
// 绑定微信并登录
bindWechat() {
const data = Object.assign({}, this.ruleForm, { unionid: this.unionid })
api
.bindWechat(data)
.then(response => {
this.loginSuccess(response)
})
.catch(error => {
error.response && this.$toast(error.response.data.message)
})
},
// 登录成功
loginSuccess(response) {
if (response.code === 0) {
Cookies.remove('wechat_login_error', { domain: '.ezijing.com' })
Cookies.remove('wechat_login_no_phone_error', {
domain: '.ezijing.com'
})
this.$store.commit('setToken', response.data.TGC)
if (this.isWeapp) {
wx.miniProgram.postMessage({ data: { token: response.data.TGC } })
wx.miniProgram.navigateBack()
return
}
if (this.redirectURI) {
window.location.href = this.redirectURI
} else {
this.$router.replace('/')
}
} else {
this.$toast(response.msg)
}
},
wechatLogin() {
const appId = 'wx451c01d40d090d7a'
// 回调地址
const redirectURI = `${process.env.VUE_APP_WECHAT_REDIRECT_URL}?needCheck=false&identity=friend&redirectUrl=${window.location.origin}`
// 微信的地址
const wechatUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${encodeURIComponent(
redirectURI
)}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`
// 打开地址
window.location.href = wechatUrl
},
checkWechatLogin() {
return !!(
Cookies.get('wechat_login_error') ||
Cookies.get('wechat_login_no_phone_error')
)
}
}
}
</script>
<style lang="scss">
.login {
position: relative;
min-height: 100vh;
display: flex;
flex-direction: column;
background: url('../../assets/images/login_bg.png') no-repeat;
background-size: contain;
}
.login-box {
position: absolute;
top: 100px;
left: 50px;
right: 50px;
height: 400px;
padding: 20px;
background: rgba(255, 255, 255, 1);
box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.1);
border-radius: 20px;
}
.login-hd {
padding: 10px 0;
}
.login-title {
display: inline-block;
font-size: 24px;
color: #2b7ce9;
border-bottom: 5px solid #2b7ce9;
}
.login-bd {
margin-top: 20px;
flex: 1;
}
.login-button {
margin-top: 40px;
height: 40px;
font-size: 12px;
color: #fff;
line-height: 40px;
background: linear-gradient(
270deg,
rgba(43, 124, 233, 1) 0%,
rgba(103, 168, 255, 1) 100%
);
text-align: center;
border-radius: 3px;
cursor: pointer;
}
.login-ft {
padding: 20px 0;
li {
display: inline-block;
height: 30px;
line-height: 30px;
font-size: 12px;
color: #ccc;
cursor: pointer;
}
img {
width: 30px;
margin-right: 5px;
}
}
.login-tips {
text-align: center;
font-size: 12px;
color: #999;
.forget-password {
color: #1989fa;
}
}
.login {
.title {
padding: 30px 0;
font-size: 15px;
font-weight: 600;
color: #fff;
line-height: 30px;
text-align: center;
}
.van-field {
margin-bottom: 20px;
padding: 0;
flex-direction: column;
}
.van-field__label {
font-size: 12px;
color: #222;
line-height: 1;
margin-bottom: 5px;
padding-left: 10px;
}
.van-field__control {
padding: 8px;
border: 1px solid #ccc;
border-radius: 3px;
}
}
</style>
<template>
<van-popup
v-model="show"
overlay-class="password-overlay"
class="password-popup"
position="top"
@closed="onClosed"
>
<div class="password" v-if="!isSuccess">
<van-form ref="form" class="form" validate-trigger="onChange" @submit="onSubmit">
<h2 class="password-title">修改密码</h2>
<van-field
v-model="ruleForm.account"
name="account"
placeholder="请输入手机号/邮箱"
:border="false"
:rules="[
{ required: true, message: '请输入手机号/邮箱' },
{ message: '手机号/邮箱格式错误' }
]"
/>
<van-field
v-model="ruleForm.code"
name="code"
placeholder="请输入验证码"
:border="false"
:rules="[{ required: true, message: '请输入验证码' }]"
>
<template slot="button">
<countdown-button @click.native="onSendCode" ref="countdown"></countdown-button>
</template>
</van-field>
<van-field
v-model="ruleForm.password"
name="password"
type="password"
placeholder="6-20个字符,只能数字/字母/标点符号"
:border="false"
:rules="[{ required: true, message: '请输入密码' }]"
/>
<van-field
v-model="ruleForm.passwordR"
type="password"
name="passwordR"
placeholder="再次确认密码"
:border="false"
:rules="[
{ required: true, message: '请输入确认密码' },
{
trigger: 'onBlur',
validator: validatePass,
message: '两次输入密码不一致'
}
]"
/>
<div style="margin: 16px 0">
<van-button block native-type="submit" class="password-button">立即更改</van-button>
</div>
</van-form>
</div>
<div class="password-success" v-else>
<span class="password-success__icon"></span>
<span class="password-success__text">密码修改成功</span>
<van-button block class="password-button" @click="onClosed">立即登录</van-button>
</div>
</van-popup>
</template>
<script>
import * as api from '@/api/account'
import CountdownButton from '@/components/CountdownButton.vue'
export default {
components: { CountdownButton },
props: {
value: { type: Boolean, default: false }
},
data() {
return {
show: this.value,
isSuccess: false,
ruleForm: {
account: '',
code: '',
password: '',
passwordR: ''
}
}
},
watch: {
value: {
immediate: true,
handler(value) {
this.show = value
}
}
},
methods: {
onClosed() {
this.isSuccess = false
this.$emit('input', false)
},
onSubmit() {
this.resetPasswordRequest()
},
// 发送验证码
onSendCode() {
this.$refs.form.validate('account').then(response => {
if (!response) {
// 开始倒计时
this.$refs.countdown.start()
this.sendCodeRequest()
}
})
},
// 验证码
sendCodeRequest() {
api
.sendResetPasswordCode({ account: this.ruleForm.account })
.then(response => {
if (response.code === 0) {
this.$notify({ type: 'success', message: '验证码发送成功' })
} else {
// 停止计时
this.$refs.countdown.stop()
this.$notify(response.msg)
}
})
.catch(error => {
// 停止计时
this.$refs.countdown.stop()
error.response && this.$notify(error.response.data.message)
})
},
// 重置密码
resetPasswordRequest() {
const data = Object.assign({}, this.ruleForm, {
service: 'h5.ezijing.com'
})
api
.resetPassword(data)
.then(response => {
if (response.code === 0) {
this.isSuccess = true
} else {
this.$notify(response.msg)
}
})
.catch(error => {
error.response && this.$notify(error.response.data.message)
})
},
// 确认密码校验
validatePass(value) {
return value === this.ruleForm.password
}
}
}
</script>
<style lang="scss">
.password-popup {
margin: 30px auto;
right: 0;
max-width: 690px;
width: calc(100vw - 60px);
box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.1);
}
.password {
min-height: 440px;
padding: 0 20px;
}
.password-title {
padding: 30px 16px 10px;
font-size: 18px;
color: #333;
text-align: center;
}
.password-overlay {
background-color: transparent;
}
.password-button {
background: linear-gradient(
180deg,
rgba(255, 155, 150, 1) 0%,
rgba(206, 62, 58, 1) 100%
);
color: #fff;
border: 0;
}
.password-success {
display: flex;
min-height: 440px;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 30px;
}
.password-success__icon {
display: inline-block;
width: 100px;
height: 100px;
// background: url('~@/assets/img/icon_success.png') no-repeat;
background-size: contain;
}
.password-success__text {
display: block;
margin: 40px 0 55px;
font-size: 24px;
color: #333;
}
</style>
<template>
<van-button type="default" @click="logout">退出登录</van-button>
</template>
<script>
import { logout } from '@/api/account.js'
export default {
name: 'my',
methods: {
logout() {
logout().then(response => {
this.$toast('退出成功')
})
}
}
}
</script>
<template>
<div class="list">
<van-list v-model="loading" :finished="finished" @load="onLoad" v-if="list.length"></van-list>
<div class="main-list">
<ul v-if="list.length">
<li v-for="item in list" :key="item.course_id">{{item.chapter_name}}</li>
</ul>
<template v-else>
<slot name="empty">
<div class="empty">暂时没有内容哦,去别处看看吧~</div>
<div class="empty">暂时没有内容哦,换个搜索词试试吧~</div>
</slot>
</template>
</div>
......@@ -19,15 +21,12 @@ export default {
default() {
return {}
}
},
showIndex: { type: Boolean, default: false }
}
},
data() {
return {
list: [],
loading: false,
finished: false,
requestParams: { offset: 0, limit: 20 }
requestParams: {}
}
},
watch: {
......@@ -40,30 +39,12 @@ export default {
},
methods: {
getList() {
this.loading = true
api
.getCourseSearchList(this.requestParams)
.then(response => {
if (response.length) {
this.list = this.list.concat(response)
}
this.loading = false
this.finished = response.length !== this.requestParams.limit
})
.catch(() => {
this.loading = false
this.finished = true
api.getCourseSearchList(this.requestParams).then(response => {
this.list = response
})
},
onLoad() {
this.requestParams.offset =
this.requestParams.offset + this.requestParams.limit
this.getList()
},
// 刷新
refresh() {
this.requestParams.offset = 0
this.list = []
this.getList()
}
},
......@@ -72,3 +53,12 @@ export default {
}
}
</script>
<style lang="scss" scoped>
.main-list li {
padding: 0.3rem 0;
font-size: 0.3rem;
color: #222;
border-bottom: 1px solid #f1f1f1;
}
</style>
<template>
<div class="main-container">
<search-bar v-model="searchValue"></search-bar>
<div class="search-tips">
<search-bar v-model="searchValue" @search="onSearch"></search-bar>
<div class="search-tips" v-if="!searchValue">
<div class="search-tips-item" v-if="historyList.length">
<h3 class="search-tips__title">搜索历史</h3>
<ul class="search-tips__list">
......@@ -23,7 +23,7 @@
</ul>
</div>
</div>
<div class="search-main">
<div class="search-main" v-if="searchValue">
<van-tabs
class="main-tabs"
v-model="tabActive"
......@@ -32,25 +32,13 @@
@click="onTabClick"
>
<van-tab title="知识点" name="0">
<tag-list :params="{ keyworks: searchValue }" ref="list" v-if="tabActive === '0'">
<template #empty>
<div class="search-empty">暂时没有内容哦,换个搜索词试试吧~</div>
</template>
</tag-list>
<tag-list :params="{ keywords: searchValue }" ref="list" v-if="tabActive === '0'"></tag-list>
</van-tab>
<van-tab title="视频课程" name="1">
<video-list :params="{ keyworks: searchValue }" ref="list" v-if="tabActive === '1'">
<template #empty>
<div class="search-empty">暂时没有内容哦,换个搜索词试试吧~</div>
</template>
</video-list>
<video-list :params="{ keywords: searchValue }" ref="list" v-if="tabActive === '1'"></video-list>
</van-tab>
<van-tab title="课程" name="2">
<course-list :params="{ keyworks: searchValue }" ref="list" v-if="tabActive === '2'">
<template #empty>
<div class="search-empty">暂时没有内容哦,换个搜索词试试吧~</div>
</template>
</course-list>
<course-list :params="{ keywords: searchValue }" ref="list" v-if="tabActive === '2'"></course-list>
</van-tab>
</van-tabs>
</div>
......
<template>
<div class="list">
<van-list v-model="loading" :finished="finished" @load="onLoad" v-if="list.length">
<activity-item
v-for="(item, index) in list"
:data="item"
:index="index"
:show-index="showIndex"
:key="item.id"
></activity-item>
</van-list>
<div class="main-list">
<ul v-if="list.length">
<li v-for="item in list" :key="item.id">{{item.title}}</li>
</ul>
<template v-else>
<slot name="empty">
<div class="empty">暂时没有内容哦,去别处看看吧~</div>
<div class="empty">暂时没有内容哦,换个搜索词试试吧~</div>
</slot>
</template>
</div>
......@@ -27,15 +21,12 @@ export default {
default() {
return {}
}
},
showIndex: { type: Boolean, default: false }
}
},
data() {
return {
list: [],
loading: false,
finished: false,
requestParams: { offset: 0, limit: 20 }
requestParams: {}
}
},
watch: {
......@@ -48,30 +39,12 @@ export default {
},
methods: {
getList() {
this.loading = true
api
.getTagSearchList(this.requestParams)
.then(response => {
if (response.length) {
this.list = this.list.concat(response)
}
this.loading = false
this.finished = response.length !== this.requestParams.limit
})
.catch(() => {
this.loading = false
this.finished = true
api.getTagSearchList(this.requestParams).then(response => {
this.list = response
})
},
onLoad() {
this.requestParams.offset =
this.requestParams.offset + this.requestParams.limit
this.getList()
},
// 刷新
refresh() {
this.requestParams.offset = 0
this.list = []
this.getList()
}
},
......@@ -80,3 +53,12 @@ export default {
}
}
</script>
<style lang="scss" scoped>
.main-list li {
padding: 0.3rem 0;
font-size: 0.3rem;
color: #222;
border-bottom: 1px solid #f1f1f1;
}
</style>
<template>
<div class="list">
<van-list v-model="loading" :finished="finished" @load="onLoad" v-if="list.length">
<activity-item
v-for="(item, index) in list"
:data="item"
:index="index"
:show-index="showIndex"
:key="item.id"
></activity-item>
</van-list>
<div class="main-list">
<template v-if="list.length">
<ul>
<li v-for="item in list" :key="item.id">{{item.chapter_name}}</li>
</ul>
</template>
<template v-else>
<slot name="empty">
<div class="empty">暂时没有内容哦,去别处看看吧~</div>
<div class="empty">暂时没有内容哦,换个搜索词试试吧~</div>
</slot>
</template>
</div>
......@@ -27,15 +23,12 @@ export default {
default() {
return {}
}
},
showIndex: { type: Boolean, default: false }
}
},
data() {
return {
list: [],
loading: false,
finished: false,
requestParams: { offset: 0, limit: 20 }
requestParams: {}
}
},
watch: {
......@@ -48,30 +41,12 @@ export default {
},
methods: {
getList() {
this.loading = true
api
.getCourseVideoSearchList(this.requestParams)
.then(response => {
if (response.length) {
this.list = this.list.concat(response)
}
this.loading = false
this.finished = response.length !== this.requestParams.limit
})
.catch(() => {
this.loading = false
this.finished = true
api.getCourseVideoSearchList(this.requestParams).then(response => {
this.list = response
})
},
onLoad() {
this.requestParams.offset =
this.requestParams.offset + this.requestParams.limit
this.getList()
},
// 刷新
refresh() {
this.requestParams.offset = 0
this.list = []
this.getList()
}
},
......@@ -80,3 +55,12 @@ export default {
}
}
</script>
<style lang="scss" scoped>
.main-list li {
padding: 0.3rem 0;
font-size: 0.3rem;
color: #222;
border-bottom: 1px solid #f1f1f1;
}
</style>
......@@ -63,5 +63,17 @@ export default [
path: '/course/learn/:id',
name: 'courseLearnItem',
component: () => import('../pages/course/learn/item.vue')
},
// 登录
{
path: '/login',
name: 'login',
component: () => import('../pages/login/login.vue')
},
// 我的
{
path: '/my',
name: 'my',
component: () => import('../pages/my/index.vue')
}
]
import Vue from 'vue'
import Vuex from 'vuex'
import { getUser } from '@/api/account'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
isWeapp: false,
isLogin: false,
token: '',
user: {}
},
mutations: {
setToken(state, token) {
state.token = token
},
setUser(state, user) {
state.user = user
},
setIsWeapp(state, isWeapp) {
state.isWeapp = isWeapp
},
setIsLogin(state, isLogin) {
state.isLogin = isLogin
}
},
actions: {}
actions: {
getEnv({ commit }) {
wx.miniProgram.getEnv(function(res) {
console.log(res.miniprogram) // true
commit('setIsWeapp', res.miniprogram)
})
},
getUser({ commit }) {
getUser().then(response => {
commit('setUser', response)
})
},
async checkLogin({ commit }) {
const isLogin = await getUser()
.then(response => {
commit('setUser', response)
return true
})
.catch(() => {
return false
})
commit('setIsLogin', isLogin)
return isLogin
}
}
})
......@@ -98,50 +98,14 @@ body {
'Wenquanyi Micro Hei', sans-serif;
background-color: #eee;
}
/* Extra small devices (portrait phones, less than 576px) */
@media (max-width: 575px) {
}
/* Small devices (landscape phones, 576px and up) */
@media (min-width: 576px) and (max-width: 767px) {
}
/* Medium devices (tablets, 768px and up) */
@media (min-width: 768px) and (max-width: 991px) {
}
/* Large devices (desktops, 992px and up) */
@media (min-width: 992px) and (max-width: 1199px) {
}
/* Extra large devices (large desktops, 1200px and up) */
@media (min-width: 1200px) {
}
/* 改变主题色变量 */
$--color-primary: #b80037;
/* 改变 icon 字体路径变量,必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
/* 引入element-ui对应scss文件,重新编译 */
@import '~element-ui/packages/theme-chalk/src/index';
/* 引入隐藏显示样式 */
@import '~element-ui/lib/theme-chalk/display.css';
/* 引入三方 自定义图标库,方法 vue -> 第三方 自建图标库 中有 */
@import '~@/assets/font-icons/iconfont.css';
[class^='el-icon-self-'],
[class*='el-icon-self-'] {
font-family: 'selfAllIcon' !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.main-container {
margin: 0 0.4rem;
}
.main-tabs .van-hairline--top-bottom::after {
border-top: 0;
}
.main-list .empty {
padding: 40px 0;
text-align: center;
color: #999;
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论