提交 e3d2bcd0 authored 作者: lihuihui's avatar lihuihui

三级认证

上级 f58ccfca
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY----- -----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIFiDCCBHCgAwIBAgIQAepAKb4wAxmrtof7BwPQSDANBgkqhkiG9w0BAQsFADBu MIIFhzCCBG+gAwIBAgIQCzEi4VmynSzbyBV1UEXGojANBgkqhkiG9w0BAQsFADBu
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS0wKwYDVQQDEyRFbmNyeXB0aW9uIEV2ZXJ5d2hlcmUg d3cuZGlnaWNlcnQuY29tMS0wKwYDVQQDEyRFbmNyeXB0aW9uIEV2ZXJ5d2hlcmUg
RFYgVExTIENBIC0gRzEwHhcNMTkxMTA4MDAwMDAwWhcNMjAxMTA3MTIwMDAwWjAa RFYgVExTIENBIC0gRzEwHhcNMjAxMTA5MDAwMDAwWhcNMjExMTA5MjM1OTU5WjAa
MRgwFgYDVQQDEw9kZXYuZXppamluZy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB MRgwFgYDVQQDEw9kZXYuZXppamluZy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQCB10CZ2NYv7glRe+aJH+Wv1xt2hy0QYvB0umcitGUv+hUq5tlO DwAwggEKAoIBAQD0yNQTHE6Pq18xRpT63+TT5WiRWSHUZVkAIs93FHZVyOM6Roiq
sBJ53mkDaQcpRttX2LriI0jOfrrzOLK2K+51GK4YvjAFM922WmRK3L2KPRkdld7b WhjhMrj+7JudwuGiq72CDKIkU2ZdUvF7ZPFF4ZeFHy0BzRFMK5oW/SgcnsdcjjwJ
ehZDvd9XcU1E6nd6QuYhgeqjZ6nmGF+rUDhJ7LsgzVnQD04XoxXtOCqb7xroXLh4 n/NzyyCPJ3tey7JG6srCkdZd/L0UwcTuv/1H4hQcCQg+ZnXuqXCqmGV48rwjV+cN
1uDH31/Sfueq4aNhndFydTSPrHN9CE6o5iaGTh+VCpLHoxvqxKZYztXj+H/nngtD T8s6+CVc8iVHnlNR7o0pWgI9ldAQcc9kKUfSp2dcWJSrkjV/oYxSgYJtXkMsQJs4
Ik1XeeA19PdkWYCaEhm3uf6jey/MirCCGJlKPQr2PITvNtJmNVQERDO0VRx9iA9l Cd0I/+yepqTDyh4uagEZKKD8Uatz/jWXYMnHIjGb8J9oSF+dI3iG85MAVdyuj1yD
B9kUWx2AiQVK9HdxcikiI3yg9/zErqdoCk5fAgMBAAGjggJ0MIICcDAfBgNVHSME LLzwfUF9P9sSEzs475FFopStXkKJ54g4Sa8ZAgMBAAGjggJzMIICbzAfBgNVHSME
GDAWgBRVdE+yck/1YLpQ0dfmUVyaAYca1zAdBgNVHQ4EFgQU28ndXe6qIDlhPWX5 GDAWgBRVdE+yck/1YLpQ0dfmUVyaAYca1zAdBgNVHQ4EFgQUkRHkmubxZAvEWtCY
+gzJoRhaQQowGgYDVR0RBBMwEYIPZGV2LmV6aWppbmcuY29tMA4GA1UdDwEB/wQE IBT9sw/3Yb8wGgYDVR0RBBMwEYIPZGV2LmV6aWppbmcuY29tMA4GA1UdDwEB/wQE
AwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTAYDVR0gBEUwQzA3 AwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTAYDVR0gBEUwQzA3
BglghkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu BglghkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu
Y29tL0NQUzAIBgZngQwBAgEwgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYY Y29tL0NQUzAIBgZngQwBAgEwgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYY
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEoGCCsGAQUFBzAChj5odHRwOi8vY2Fj aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEoGCCsGAQUFBzAChj5odHRwOi8vY2Fj
ZXJ0cy5kaWdpY2VydC5jb20vRW5jcnlwdGlvbkV2ZXJ5d2hlcmVEVlRMU0NBLUcx ZXJ0cy5kaWdpY2VydC5jb20vRW5jcnlwdGlvbkV2ZXJ5d2hlcmVEVlRMU0NBLUcx
LmNydDAJBgNVHRMEAjAAMIIBBQYKKwYBBAHWeQIEAgSB9gSB8wDxAHYApLkJkLQY LmNydDAJBgNVHRMEAjAAMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHYA9lyUL9F3
WBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFuSnTaJgAABAMARzBFAiEAtYCW MCIUVBgIMJRWjuNNExkzv98MLyALzE7xZOMAAAF1qpa6jQAABAMARzBFAiAwHOcp
PLYE6pylBOsB1MmETgxGpYrG64Osn/XXyJlh+/UCIEnttMCBvNif4hpJfAQibP/Q Ua1H0WK4OZUHiQ1rndqnYxPHhP9XWunwpRMoagIhAOB2MPSW9M4qj6Yih7eQkydl
bJ9w0VYC59hi8Tmcf/mfAHcAXqdz+d9WwOe1Nkh90EngMnqRmgyEoRIShBh1loFx lgawpoBZzRzhisU+TN67AHYAXNxDkv7mq0VEsV6a1FbmEDf71fpH3KFzlLJe5vbH
RVgAAAFuSnTZSQAABAMASDBGAiEAsMgDWdSJ5d2jiXoNyxJ5FY7+3PET59vgvxi9 DsoAAAF1qpa63gAABAMARzBFAiEA92ZeW0PgyWW3j+3wypLS0O/wI63C+x0WTvMZ
Eev9MwECIQC3sfR8sRWxJg82xH7lIA9sN87p7fLmr+KyhnuAK+2bcjANBgkqhkiG Vngp6AMCIBoThjaKif+XY11YbaV89ndqs1nDlzbEfBrFftoB9fchMA0GCSqGSIb3
9w0BAQsFAAOCAQEAOXMhz5dapVgYoLe23i+rEbBeO648c3cAO11qubqE0b5ie2bY DQEBCwUAA4IBAQA2geo9wQAd+vx+lwAafVRxCBQyBiS0qT413ewYpZYDnSkLX0l1
4DuatptwiLA47xfSVbFF0Y44cPL1b0zHe+Ki9TpcFP+TQ/+cPD2bPrqovI2uh8Qi 5kRdxDGWQhPzOio0ckj/jOtOlbbSsiovBBVTyYPB8WfkNjMd0psMNx2e6Wy/WKkQ
1RU7baLoYO9t7NxaPXh9RtRLUufJHas7HcWtLw/nPvVi+SuhgiiPytWdVM64dIPz X3DqEOB4XGg0RwpebiAmz6lWxyFwIAbCrwCntkkaIF4LnIvczn6pvPFBtK2nXJJC
+nP9YY6wZhp4S/vNw5T7LARaw28xrEPzgCzWoXBUDyLB1slU3A2Uu+vl4lilcVeF HL0Igbxo+xJLt3Hql7TcwkFDXz/LIB8AwhhkkhhwW45r3Eyjw8eOyzvflDPwSNH+
B/hl/75PWIdlxeRsD2V4TGCg796eL1BTVYEh7+mjvvaft+1/jwofKtGxg34YZHfl ByadQ+AH4H4vYYVo0ILNIPCdaokLQ+u4FttB9VQ+iGmpJ56Yg2muxWh8Qckca+vH
6M22MuuP1pLviPZEE4ZlPXvltUV/Qq47LvZkTg== 40RbC5aK1RSy2RIRpC5fwvq2JuV/CksP5G5Q
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIEqjCCA5KgAwIBAgIQAnmsRYvBskWr+YBTzSybsTANBgkqhkiG9w0BAQsFADBh MIIEqjCCA5KgAwIBAgIQAnmsRYvBskWr+YBTzSybsTANBgkqhkiG9w0BAQsFADBh
......
import httpRequest from '@/utils/axios'
// 上传文件
export function upload(data) {
return httpRequest({
url: '/api/alumni/v1/activities/tool/upload-file',
method: 'post',
headers: {
'Content-Type': 'multipart/form-data'
},
data
})
}
// 获取热门推荐列表
export function getAttestationStatus() {
return httpRequest({
url: '/api/alumni/v1/certification/list',
method: 'get'
})
}
// 提交资料
export function submitInfo(data) {
return httpRequest({
url: '/api/alumni/v1/certification/add',
method: 'post',
data
})
}
// 撤销
export function revoke(id, data) {
return httpRequest({
url: `/api/alumni/v1/certification/change/${id}`,
method: 'post',
data
})
}
// 认证详情
export function getAttestationDetail(id) {
return httpRequest({
url: `/api/alumni/v1/certification/detail/${id}`,
method: 'get'
})
}
// 上传资料
export function addSubmitStudent(id, data) {
console.log(id, data)
return httpRequest({
url: `/api/alumni/v1/certification/edit/${id}`,
method: 'post',
data
})
}
\ No newline at end of file
<template>
<van-form ref="form" class="form" validate-trigger="onChange" v-bind="$attrs" v-on="$listeners">
<template v-for="(item, index) in fields">
<div class="form-item" :key="index">
<!-- 上传图片 -->
<template>
<div class="label">{{ item.label }}</div>
<div class="up-box">
<van-field
class="field"
:border="false"
:required="false"
v-model="ruleForm[item.name]"
v-if="item.isShow ? item.isShow(ruleForm) : true"
>
<template #input>
<upload class="input-item" v-model="ruleForm[item.name]" v-bind="item" :max-count="1" />
</template>
</van-field>
<img class="img" :src="item.examples" @click="onChange(item.examples)" alt="">
</div>
</template>
</div>
</template>
<slot></slot>
<van-image-preview v-model="show" :images="images">
<!-- <template v-slot:index>第{{ index }}页</template> -->
</van-image-preview>
</van-form>
</template>
<script>
// import dayjs from 'dayjs'
import Upload from '@/components/attestationUpload'
// import areaList from '@/utils/area.js'
// import UploadVideo from '@/components/UploadVideo'
// import UpliadMultiple from '@/components/UpliadMultiple'
export default {
name: 'VForm',
components: { Upload },
props: {
model: {
type: Object,
default() {
return {}
}
},
fields: {
type: Array,
required: true,
default() {
return []
}
}
},
watch: {
model: {
immediate: true,
deep: true,
handler(value) {
this.ruleForm = value
}
}
},
data() {
return {
show: false,
index: 0,
images: [],
ruleForm: this.model,
picker: {
visible: false,
fieldType: '',
name: '',
value: '',
valueKey: 'value',
labelKey: 'text',
values: [],
remote: null
},
minDate: new Date(),
pickerActive: {}
}
},
filters: {
pickerValueText(value, field) {
if (!value || !field.values) {
return ''
}
const valueKey = field.valueKey || 'value'
const labelKey = field.labelKey || 'text'
const found = field.values.find(item => item[valueKey] === value)
return found ? found[labelKey] : ''
}
},
methods: {
onChange(src) {
this.images = [src]
this.show = true
},
showPicker(field) {
this.picker = Object.assign(
{
visible: true,
fieldType: '',
name: '',
value: '',
valueKey: 'value',
labelKey: 'text',
values: [],
remote: null
},
field
)
this.picker.value = this.ruleForm[name]
if (field.fieldType === 'select' && field.remote && !field.values) {
this.getPickerOptions(field)
}
},
// 选择确定
onPickerConfirm(data) {
this.ruleForm[this.picker.name] = data[this.picker.valueKey]
this.picker.visible = false
if (this.picker.remote && this.picker.remote.change) {
this.pickerActive = data
}
},
// 地区选择确定
onAreaPickerConfirm(values) {
this.ruleForm[this.picker.name] = values.map(item => item.name).join('-')
this.picker.visible = false
},
submit() {
return this.$refs.form.submit()
},
getPickerOptions(field) {
const remote = field.remote
if (!remote) {
return
}
remote.method(this.pickerActive).then(response => {
if (remote.callback) {
response = remote.callback(response)
}
field.values = response
this.$set(this.picker, 'values', response)
})
}
}
}
</script>
<style lang="scss">
.up-box{
display: flex;
padding-top: 10px;
margin-bottom: 10px;
.field{
width: 40%;
padding: 0;
height: 100%;
}
.img{
width: 40%;
margin-left: 20px;
}
}
</style>
<template>
<van-uploader
v-model="fileList"
upload-icon="plus"
:after-read="afterRead"
:max-size="MaxSize"
@delete="onDelete"
@oversize="oversize"
v-bind="$attrs"
>
<div class="van-uploader__upload">
<i class="van-icon van-icon-plus van-uploader__upload-icon"></i>
<p class="placeholder" v-if="$attrs.placeholder">{{ $attrs.placeholder }}</p>
</div>
</van-uploader>
</template>
<script>
import { upload } from '@/api/index'
export default {
name: 'Upload',
// 最大3M
props: { value: String, MaxSize: { type: Number, default: 3 * 1024 * 1024 } },
data() {
return { fileList: [] }
},
watch: {
value: {
immediate: true,
handler(value) {
this.fileList = value ? [{ url: value }] : []
}
}
},
methods: {
oversize(file) {
const rawFile = file.file
if (rawFile.size > this.MaxSize) {
this.$toast('文件大小不能超过3M')
}
},
afterRead(file) {
file.status = 'uploading'
file.message = '上传中...'
let formData = new FormData()
formData.append('file', file.file)
upload(formData)
.then(response => {
if (response.success) {
file.status = 'done'
this.$emit('input', response.url)
} else {
file.status = 'failed'
file.message = '上传失败'
}
})
.catch(() => {
file.status = 'failed'
file.message = '上传失败'
})
},
onDelete() {
this.$emit('input', '')
}
}
}
</script>
<style lang="scss" scoped>
.van-uploader {
display: block;
width: 100%;
}
.placeholder {
margin-top: 10px;
color: #c9c9c9;
}
::v-deep .van-uploader__input-wrapper,
::v-deep .van-uploader__preview {
width: 100%;
}
::v-deep .van-uploader__upload,
::v-deep .van-uploader__preview-image {
width: 100%;
height: 100%;
background-color: #eaeef0;
border-radius: 0;
}
::v-deep .van-uploader__upload-icon {
font-size: 40px;
color: #dcdcdc;
}
::v-deep .van-cell{
width: auto !important;
}
</style>
...@@ -177,6 +177,34 @@ const routes = [ ...@@ -177,6 +177,34 @@ const routes = [
name: 'submitStudent', name: 'submitStudent',
component: () => import('@/views/submitStudent/submitStudent.vue'), component: () => import('@/views/submitStudent/submitStudent.vue'),
meta: { requiredLogin: true } meta: { requiredLogin: true }
},
//三级认证
{
path: '/attestation/form',
name: 'attestationForm',
component: () => import('@/views/attestation/form.vue'),
meta: { requiredLogin: true }
},
// 打印
{
path: '/attestation/printing',
name: 'printing',
component: () => import('@/views/attestation/printing.vue'),
meta: { requiredLogin: true }
},
// 三级认证首页
{
path: '/attestation',
name: 'printing',
component: () => import('@/views/attestation/index.vue'),
meta: { requiredLogin: true }
},
// 三级认证上传
{
path: '/attestation/upload',
name: 'attteUpload',
component: () => import('@/views/attestation/upload.vue'),
meta: { requiredLogin: true }
} }
] ]
......
import httpRequest from '@/utils/axios'
// const httpRequest = new BaseAPI(webConf)
/**
* 获取openid
*/
export function getOpenId(params) {
return httpRequest({
url: '/api/usercenter/user/get-user-openid',
method: 'get',
params
})
}
/**
* 生成订单
*/
export function genOrder(data) {
return httpRequest({
url: '/api/pay/v1/wechat/order/pre',
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data
})
}
/**
* 获取商品
*/
export function getProduct(productId) {
return httpRequest.get(`/api/pay/v2/mall/product/${productId}`)
}
/**
* 获取订单
*/
export function getOrder(orderId) {
return httpRequest.get(`/api/pay/v2/mall/order/${orderId}`)
}
/**
* 获取订单状态
*/
export function getOrderStatus() {
return httpRequest.get('/api/pay/v2/mall/order/status')
}
<template>
<div class="pay-bg2">
<div class="top-view">
<img src="../../../assets/images/pay/top-bj.png" class="bj" />
<img src="../../../assets/images/pay/top-btn.png" class="btn" @click="goPay" />
<img src="../../../assets/images/pay/c1.png" class="content" />
</div>
<div class="main-cen">
<img src="../../../assets/images/pay/c2.png" class="c2" />
<img src="../../../assets/images/pay/c3.png" class="c3" />
<img src="../../../assets/images/pay/c4.png" class="c4" />
<img src="../../../assets/images/pay/c5.png" class="c5" />
</div>
<div class="btn-box">
<div class="text">
<div class="fle">
<div class="l">特惠价</div>
<div class="c">199.00</div>
<div class="r">原价999.00</div>
</div>
<div class="new-b" v-if="orderStatus === 0">课程有效期剩余{{expireDay}}</div>
</div>
<div class="btn" @click="goPay" v-if="orderStatus === 100">立即购买</div>
<div class="btn" v-if="orderStatus === 1" @click="goHome">已购买</div>
<div class="btn" v-if="orderStatus === -1" @click="goMyOrder">待支付</div>
<div class="btn" @click="goPay" v-if="orderStatus === 0">续费</div>
</div>
<pay-we-chart :requestParam="requestParam"></pay-we-chart>
<!-- isPopShow -->
<div class="succ-pop" v-if="isPopShow">
<div class="pop">
<div class="close" @click="isPopShow = false">×</div>
<div class="tit">恭喜您,课程已购买成功!</div>
<div class="txt">请添加助教微信,有任何问题可随时沟通老师。</div>
<img src="../../../assets/images/pay/pay-izq.png" alt />
<div class="btns">添加客服微信</div>
<!-- <img @click="imagePreview" src="https://zws-imgs-pub.ezijing.com/static/public/dcef7bc62237a077b10d7e49c44a1e51.jpg" alt=""> -->
</div>
</div>
<h5-pay :productId="productId"></h5-pay>
</div>
</template>
<script>
import { mapState } from 'vuex'
import { ImagePreview } from 'vant'
import * as api from '../api'
import h5Pay from './h5Pay.vue'
export default {
components: { h5Pay },
props: {
productId: { type: String, required: true }
},
data() {
return {
isPopShow: false,
expireDay: 0,
orderStatusTime: null,
orderStatus: 100
}
},
computed: {
...mapState(['isWeapp', 'isAndroid', 'isIos', 'isVip', 'isLogin']),
isWeappPay() {
return this.isWeapp && !this.isIos
}
},
mounted() {
this.getOrder()
},
methods: {
// 获取订单状态
getOrder() {
api.getOrderStatus().then(response => {
this.orderStatus = response.status
this.expireDay = response.expire_day
})
},
imagePreview() {
ImagePreview(['https://zws-imgs-pub.ezijing.com/static/public/dcef7bc62237a077b10d7e49c44a1e51.jpg'])
},
tikeOrderStatus() {
if (this.isLogin) {
this.orderStatusTime = setInterval(this.getOrderStatus, 1000)
}
},
// 已购买
goHome() {
this.$toast('您已购买全部服务,可直接使用')
},
// 支付
goPay() {
if (this.orderStatus === 1) {
this.$toast('您已购买全部服务,可直接使用')
return false
}
this.tikeOrderStatus()
wx.miniProgram.navigateTo({
url: `/pages/pay/index?data=${this.productId}`
})
},
// 去我的订单页面
goMyOrder() {
wx.miniProgram.navigateTo({
url: `/pages/web/index?src=${window.location.origin}/my/buyCourses`
})
},
// 获取订单状态
getOrderStatus() {
api.getOrderStatus().then(res => {
this.orderStatus = res.status
if (this.orderStatus === 1) {
this.isPopShow = true
this.orderStatusTime && clearInterval(this.orderStatusTime)
}
})
}
},
destroyed() {
this.orderStatusTime && clearInterval(this.orderStatusTime)
}
}
</script>
<style lang="scss" scoped>
.pay-bg2 {
.top-view {
position: relative;
.bj {
width: 100%;
}
.btn {
position: absolute;
top: 3.25rem;
right: 0.7rem;
width: 3.42rem;
height: 0.85rem;
}
.content {
position: absolute;
bottom: 0;
left: 50%;
-webkit-transform: translate(-50%, 50%);
width: 6.58rem;
height: 2.82rem;
}
}
.main-cen {
padding: 1.9rem 0.52rem 1.5rem 0.52rem;
.c2 {
width: 100%;
}
.c3 {
margin-top: 0.5rem;
width: 100%;
}
.c4 {
margin-top: 0.5rem;
width: 100%;
}
.c5 {
margin-top: 0.5rem;
width: 100%;
}
}
.btn-box {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 1rem;
background: rgba(171, 27, 48, 1);
.btn {
position: absolute;
top: 0;
right: 0;
width: 3.3rem;
height: 1rem;
background: linear-gradient(-90deg, rgba(204, 157, 93, 1), rgba(247, 213, 161, 1));
font-size: 0.37rem;
color: rgba(80, 41, 3, 1);
line-height: 1rem;
text-align: center;
font-weight: bold;
}
.text {
.fle {
display: flex;
div {
line-height: 100%;
}
}
.l {
font-size: 0.22rem;
color: rgba(255, 255, 255, 1);
line-height: 100%;
margin: 0.43rem 0 0 0.34rem;
background: linear-gradient(-90deg, rgba(204, 158, 94, 1) 0%, rgba(247, 214, 161, 1) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
opacity: 0.8;
}
.c {
margin-top: 0.3rem;
margin-left: 0.15rem;
font-size: 0.44rem;
color: rgba(255, 255, 255, 1);
background: linear-gradient(-90deg, rgba(204, 158, 94, 1) 0%, rgba(247, 214, 161, 1) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.r {
font-size: 0.22rem;
color: rgba(204, 158, 94, 1);
line-height: 100%;
opacity: 0.9;
margin: 0.43rem 0 0 0.17rem;
// background:linear-gradient(-90deg,rgba(204,158,94,1) 0%, rgba(247,214,161,1) 100%);
// -webkit-background-clip:text;
// -webkit-text-fill-color:transparent;
text-decoration: line-through;
}
.new-b {
font-size: 0.22rem;
color: rgba(255, 255, 255, 1);
line-height: 100%;
opacity: 0.8;
margin: 0 0 0 0.34rem;
background: linear-gradient(-90deg, rgba(204, 158, 94, 1) 0%, rgba(247, 214, 161, 1) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
}
.succ-pop {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
.pop {
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
width: 5.9rem;
height: 6.98rem;
background: rgba(255, 255, 255, 1);
border-radius: 0.12rem;
.tit {
line-height: 1.1rem;
text-align: center;
font-size: 0.3rem;
color: #222;
font-weight: bold;
}
.txt {
width: 5.1rem;
font-size: 0.3rem;
color: rgba(34, 34, 34, 1);
margin: 0 auto;
}
// img{
// width: 4.3rem;
// height: 4.3rem;
// margin: 0.4rem auto;
// display: block;
// }
img {
width: 3.16rem;
height: 3rem;
margin: 0.6rem auto 0.45rem auto;
display: block;
}
.btns {
width: 4.5rem;
height: 0.7rem;
background: #c62245;
border-radius: 0.12rem;
margin: 0 auto;
text-align: center;
line-height: 0.7rem;
font-size: 0.3rem;
color: #fff;
}
.close {
position: absolute;
top: -0.8rem;
right: 0;
font-size: 0.6rem;
color: #fff;
}
}
}
.b-b-i {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
}
</style>
<template>
<div></div>
</template>
<script>
import * as api from '../api.js'
export default {
name: 'wxPay',
props: {
productId: { type: String, required: true }
},
data() {
return {
openId: '',
order: { options: {} }
}
},
computed: {
// 用户信息
user() {
return this.$store.state.user
},
// 是否登录
isLogin() {
return this.$store.state.isLogin
}
},
mounted() {
console.log(this.user, '====')
},
methods: {
// 获取openid
getOpenId() {
api.getOpenId({ id: this.user.data.id, identity: 'alumni' }).then(response => {
this.openId = response.data.openid
// 生成订单
this.genOrder()
})
},
// 生成订单
genOrder() {
const params = {
product_id: this.productId,
open_id: this.openId,
type: 'almni-h5'
}
api.genOrder(params).then(response => {
this.order = response.data
// 调起微信支付
this.wxPay()
})
},
// 微信支付
wxPay() {
const options = this.order.options
window.WeixinJSBridge.invoke(
'getBrandWCPayRequest',
{
appId: options.appId, // 公众号名称,由商户传入
timeStamp: options.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: options.nonceStr, // 支付签名随机串,不长于 32 位
package: `prepay_id=${this.order.prepay_id}`, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
signType: options.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: options.paySign // 支付签名
},
function (res) {
if (res.err_msg === 'get_brand_wcpay_request:ok') {
// 使用以上方式判断前端返回,微信团队郑重提示:
// res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
this.$toast('支付成功')
// 支付成功后的回调函数
this.$emit('success', res)
} else {
this.$toast('支付失败')
this.$emti('fail', res)
}
}
)
// wx.chooseWXPay({
// timestamp: options.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
// nonceStr: options.nonceStr, // 支付签名随机串,不长于 32 位
// package: `prepay_id=${this.order.prepay_id}`, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
// signType: options.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
// paySign: options.paySign, // 支付签名
// success: res => {
// this.$toast('支付成功')
// // 支付成功后的回调函数
// this.$emit('success', res)
// },
// fail: error => {
// this.$toast('支付失败')
// this.$emti('fail', error)
// }
// })
},
pay() {
this.getOpenId()
}
}
}
</script>
<template>
<div class="pay-bg2">
<div class="top-view">
<img src="../../../assets/images/pay/top-bj-ios.png" class="bj" />
<img src="../../../assets/images/pay/top-btn-ios.png" class="btn" @click="handlePay" />
<img src="../../../assets/images/pay/c1.png" class="content" />
</div>
<div class="main-cen">
<img src="../../../assets/images/pay/c2.png" class="c2" />
<img src="../../../assets/images/pay/c3.png" class="c3" />
<img src="../../../assets/images/pay/c4.png" class="c4" />
<img src="../../../assets/images/pay/c5.png" class="c5" />
</div>
<div class="btn-box" v-if="isVip">
<div class="text">
<div class="fle">
<div class="l">特惠价</div>
<div class="c">199.00</div>
<div class="r">原价999.00</div>
</div>
<div class="new-b" v-if="orderStatus === 0">课程有效期剩余{{expireDay}}</div>
</div>
<div class="btn" @click="goPay" v-if="orderStatus === 100">立即开通</div>
<div class="btn" v-if="orderStatus === 1" @click="goHome">已开通</div>
<div class="btn" v-if="orderStatus === -1" @click="goMyOrder">待支付</div>
<div class="btn" @click="goPay" v-if="orderStatus === 0">续费</div>
</div>
<img @click="goPayIos" src="../../../assets/images/pay/bottom-btn-ios.png" class="b-b-i" v-else />
<pay-we-chart :requestParam="requestParam"></pay-we-chart>
<div class="succ-pop" v-if="isPopShow">
<div class="pop">
<div class="close" @click="isPopShow = false">×</div>
<div class="tit">恭喜您,课程已开通成功!</div>
<div class="txt">请添加助教微信,有任何问题可随时沟通老师。</div>
<img src="../../../assets/images/pay/pay-izq.png" alt />
<div class="btns">添加客服微信</div>
</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import { ImagePreview } from 'vant'
import * as api from '@/api/pay.js'
import { getUser } from '@/api/account'
export default {
metaInfo: {
title: '课程详情'
},
data() {
const productId = webConf.isDev === 'production' ? '6684359515615264768' : '6682927830365372416'
return {
isPopShow: false,
expireDay: 0,
userId: '',
requestParam: {
product_id: productId, // 提前设定
open_id: '', // 通过微信授权获取
prepay_id: '', // 通过调用接口获取
app_id: '', // 提前设定
app_secret: '' // 提前设定
},
orderStatusTime: null,
orderStatus: 100
}
},
computed: {
...mapState(['isWeapp', 'isAndroid', 'isIos', 'isVip', 'isLogin']),
isWeappPay() {
return this.isWeapp && !this.isIos
}
},
methods: {
getOrder() {
this.isLogin &&
api.getOrderStatus().then(res => {
this.expireDay = res.expire_day
this.orderStatus = res.status
})
},
imagePreview() {
ImagePreview(['https://zws-imgs-pub.ezijing.com/static/public/dcef7bc62237a077b10d7e49c44a1e51.jpg'])
},
async tikeOrderStatus() {
const isLogin = await this.$store.dispatch('checkLogin')
if (isLogin) {
this.orderStatusTime = setInterval(this.getOrderStatus, 1000)
}
},
// 已开通
goHome() {
this.$toast('您已开通全部服务,可直接使用')
},
// 支付
goPay() {
if (this.orderStatus === 1) {
this.$toast('您已开通全部服务,可直接使用')
return false
}
this.tikeOrderStatus()
wx.miniProgram.navigateTo({
url: `/pages/pay/index?data=${this.requestParam.product_id}`
})
},
// 去我的订单页面
goMyOrder() {
wx.miniProgram.navigateTo({
url: `/pages/web/index?src=${window.location.origin}/my/buyCourses`
})
},
// 获取订单状态
getOrderStatus() {
api.getOrderStatus().then(res => {
this.orderStatus = res.status
if (this.orderStatus === 1) {
this.isPopShow = true
this.orderStatusTime && clearInterval(this.orderStatusTime)
}
})
},
// 获取openID
getOpenid() {
getUser().then(res => {
api.getOpenid({ id: res.id, identity: 'transport' }).then(res => {
if (res.code === 0) {
this.requestParam.open_id = res.data.openid
}
})
})
},
handlePay() {
this.$emit('pay')
}
},
mounted() {
this.getOrder()
},
destroyed() {
this.orderStatusTime && clearInterval(this.orderStatusTime)
}
}
</script>
<style lang="scss" scoped>
.pay-bg2 {
.top-view {
position: relative;
.bj {
width: 100%;
}
.btn {
position: absolute;
top: 3.25rem;
right: 0.7rem;
width: 3.42rem;
height: 0.85rem;
}
.content {
position: absolute;
bottom: 0;
left: 50%;
-webkit-transform: translate(-50%, 50%);
width: 6.58rem;
height: 2.82rem;
}
}
.main-cen {
padding: 1.9rem 0.52rem 1.5rem 0.52rem;
.c2 {
width: 100%;
}
.c3 {
margin-top: 0.5rem;
width: 100%;
}
.c4 {
margin-top: 0.5rem;
width: 100%;
}
.c5 {
margin-top: 0.5rem;
width: 100%;
}
}
.btn-box {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 1rem;
background: rgba(171, 27, 48, 1);
.btn {
position: absolute;
top: 0;
right: 0;
width: 3.3rem;
height: 1rem;
background: linear-gradient(-90deg, rgba(204, 157, 93, 1), rgba(247, 213, 161, 1));
font-size: 0.37rem;
color: rgba(80, 41, 3, 1);
line-height: 1rem;
text-align: center;
font-weight: bold;
}
.text {
.fle {
display: flex;
div {
line-height: 100%;
}
}
.l {
font-size: 0.22rem;
color: rgba(255, 255, 255, 1);
line-height: 100%;
margin: 0.43rem 0 0 0.34rem;
background: linear-gradient(-90deg, rgba(204, 158, 94, 1) 0%, rgba(247, 214, 161, 1) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
opacity: 0.8;
}
.c {
margin-top: 0.3rem;
margin-left: 0.15rem;
font-size: 0.44rem;
color: rgba(255, 255, 255, 1);
background: linear-gradient(-90deg, rgba(204, 158, 94, 1) 0%, rgba(247, 214, 161, 1) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.r {
font-size: 0.22rem;
color: rgba(204, 158, 94, 1);
line-height: 100%;
opacity: 0.9;
margin: 0.43rem 0 0 0.17rem;
// background:linear-gradient(-90deg,rgba(204,158,94,1) 0%, rgba(247,214,161,1) 100%);
// -webkit-background-clip:text;
// -webkit-text-fill-color:transparent;
text-decoration: line-through;
}
.new-b {
font-size: 0.22rem;
color: rgba(255, 255, 255, 1);
line-height: 100%;
opacity: 0.8;
margin: 0 0 0 0.34rem;
background: linear-gradient(-90deg, rgba(204, 158, 94, 1) 0%, rgba(247, 214, 161, 1) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
}
.succ-pop {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
.pop {
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
width: 5.9rem;
height: 6.98rem;
background: rgba(255, 255, 255, 1);
border-radius: 0.12rem;
.tit {
line-height: 1.1rem;
text-align: center;
font-size: 0.3rem;
color: #222;
font-weight: bold;
}
.txt {
width: 5.1rem;
font-size: 0.3rem;
color: rgba(34, 34, 34, 1);
margin: 0 auto;
}
// img{
// width: 4.3rem;
// height: 4.3rem;
// margin: 0.4rem auto;
// display: block;
// }
img {
width: 3.16rem;
height: 3rem;
margin: 0.6rem auto 0.45rem auto;
display: block;
}
.btns {
width: 4.5rem;
height: 0.7rem;
background: #c62245;
border-radius: 0.12rem;
margin: 0 auto;
text-align: center;
line-height: 0.7rem;
font-size: 0.3rem;
color: #fff;
}
.close {
position: absolute;
top: -0.8rem;
right: 0;
font-size: 0.6rem;
color: #fff;
}
}
}
.b-b-i {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
}
</style>
<template>
<div class="pay-bg2">
<div class="top-view">
<img src="../../assets/images/pay/top-bj.png" class="bj" />
<img src="../../assets/images/pay/top-btn.png" class="btn" @click="goPay" />
<img src="../../assets/images/pay/c1.png" class="content" />
</div>
<div class="main-cen">
<img src="../../assets/images/pay/c2.png" class="c2" />
<img src="../../assets/images/pay/c3.png" class="c3" />
<img src="../../assets/images/pay/c4.png" class="c4" />
<img src="../../assets/images/pay/c5.png" class="c5" />
</div>
<div class="btn-box">
<div class="text">
<div class="fle">
<div class="l">特惠价</div>
<div class="c">199.00</div>
<div class="r">原价999.00</div>
</div>
<div class="new-b" v-if="orderStatus === 0">课程有效期剩余{{expireDay}}</div>
</div>
<div class="btn" @click="goPay" v-if="orderStatus === 100">立即购买</div>
<div class="btn" v-if="orderStatus === 1" @click="goHome">已购买</div>
<div class="btn" v-if="orderStatus === -1" @click="goPay">待支付</div>
<div class="btn" @click="goPay" v-if="orderStatus === 0">续费</div>
</div>
<!-- popVisible -->
<div class="succ-pop" v-if="popVisible">
<div class="pop">
<div class="close" @click="popVisible = false">×</div>
<div class="tit">恭喜您,课程已购买成功!</div>
<div class="txt">请添加助教微信,有任何问题可随时沟通老师。</div>
<img
@click="imagePreview"
src="https://zws-imgs-pub.ezijing.com/static/public/dcef7bc62237a077b10d7e49c44a1e51.jpg"
/>
</div>
</div>
<h5-pay :productId="productId" ref="h5pay"></h5-pay>
</div>
</template>
<script>
import { mapState } from 'vuex'
import { ImagePreview } from 'vant'
import * as api from './api'
import h5Pay from './components/h5Pay.vue'
export default {
components: { h5Pay },
data() {
// const productId = webConf.isDev === 'production' ? '' : '6682927830365372416'
return {
productId: '6684359515615264768',
popVisible: false,
expireDay: 0,
orderStatusTimer: null,
orderStatus: 100
}
},
computed: {
...mapState(['isWeapp', 'isAndroid', 'isIos', 'isVip', 'isLogin']),
isWeappPay() {
return this.isWeapp && !this.isIos
}
},
methods: {
// 获取订单状态
getOrderStatus() {
return api.getOrderStatus().then(response => {
this.orderStatus = response.status
this.expireDay = response.expire_day
return response
})
},
// 自动获取订单状态
autoGetOrderStatus() {
this.orderStatusTimer = setInterval(() => {
this.getOrderStatus().then(response => {
if (this.orderStatus === 1) {
this.popVisible = true
this.clearOrderStatusTimer()
}
})
}, 1000)
},
// 清除订单定时
clearOrderStatusTimer() {
this.orderStatusTimer && clearInterval(this.orderStatusTimer)
},
// 预览图片
imagePreview() {
ImagePreview(['https://zws-imgs-pub.ezijing.com/static/public/dcef7bc62237a077b10d7e49c44a1e51.jpg'])
},
// 已购买
goHome() {
this.$toast('您已购买全部服务,可直接使用')
},
// 支付
goPay() {
if (this.orderStatus === 1) {
this.$toast('您已购买全部服务,可直接使用')
return false
}
// 自动获取订单状态
this.autoGetOrderStatus()
// 调起微信支付
this.$refs.h5pay.pay()
}
},
mounted() {
this.isLogin && this.getOrderStatus()
},
destroyed() {
this.clearOrderStatusTimer()
}
}
</script>
<style lang="scss" scoped>
.pay-bg2 {
.top-view {
position: relative;
.bj {
width: 100%;
}
.btn {
position: absolute;
top: 3.25rem;
right: 0.7rem;
width: 3.42rem;
height: 0.85rem;
}
.content {
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%, 50%);
width: 6.58rem;
height: 2.82rem;
}
}
.main-cen {
padding: 1.9rem 0.52rem 1.5rem 0.52rem;
.c2 {
width: 100%;
}
.c3 {
margin-top: 0.5rem;
width: 100%;
}
.c4 {
margin-top: 0.5rem;
width: 100%;
}
.c5 {
margin-top: 0.5rem;
width: 100%;
}
}
.btn-box {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 1rem;
background: rgba(171, 27, 48, 1);
.btn {
position: absolute;
top: 0;
right: 0;
width: 3.3rem;
height: 1rem;
background: linear-gradient(-90deg, rgba(204, 157, 93, 1), rgba(247, 213, 161, 1));
font-size: 0.37rem;
color: rgba(80, 41, 3, 1);
line-height: 1rem;
text-align: center;
font-weight: bold;
}
.text {
.fle {
display: flex;
div {
line-height: 100%;
}
}
.l {
font-size: 0.22rem;
color: rgba(255, 255, 255, 1);
line-height: 100%;
margin: 0.43rem 0 0 0.34rem;
background: linear-gradient(-90deg, rgba(204, 158, 94, 1) 0%, rgba(247, 214, 161, 1) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
opacity: 0.8;
}
.c {
margin-top: 0.3rem;
margin-left: 0.15rem;
font-size: 0.44rem;
color: rgba(255, 255, 255, 1);
background: linear-gradient(-90deg, rgba(204, 158, 94, 1) 0%, rgba(247, 214, 161, 1) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.r {
font-size: 0.22rem;
color: rgba(204, 158, 94, 1);
line-height: 100%;
opacity: 0.9;
margin: 0.43rem 0 0 0.17rem;
// background:linear-gradient(-90deg,rgba(204,158,94,1) 0%, rgba(247,214,161,1) 100%);
// -webkit-background-clip:text;
// -webkit-text-fill-color:transparent;
text-decoration: line-through;
}
.new-b {
font-size: 0.22rem;
color: rgba(255, 255, 255, 1);
line-height: 100%;
opacity: 0.8;
margin: 0 0 0 0.34rem;
background: linear-gradient(-90deg, rgba(204, 158, 94, 1) 0%, rgba(247, 214, 161, 1) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
}
.succ-pop {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
.pop {
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
width: 5.9rem;
height: 6.98rem;
background: rgba(255, 255, 255, 1);
border-radius: 0.12rem;
.tit {
line-height: 1.1rem;
text-align: center;
font-size: 0.3rem;
color: #222;
font-weight: bold;
}
.txt {
width: 5.1rem;
font-size: 0.3rem;
color: rgba(34, 34, 34, 1);
margin: 0 auto;
}
// img{
// width: 4.3rem;
// height: 4.3rem;
// margin: 0.4rem auto;
// display: block;
// }
img {
width: 3.16rem;
height: 3rem;
margin: 0.6rem auto 0.45rem auto;
display: block;
}
.btns {
width: 4.5rem;
height: 0.7rem;
background: #c62245;
border-radius: 0.12rem;
margin: 0 auto;
text-align: center;
line-height: 0.7rem;
font-size: 0.3rem;
color: #fff;
}
.close {
position: absolute;
top: -0.8rem;
right: 0;
font-size: 0.6rem;
color: #fff;
}
}
}
.b-b-i {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
}
</style>
<template>
<div>
<van-form validate-first @failed="onFailed" @submit="onSubmit">
<div class="tips">注:以下信息请用英文大写字母填写,提交后请下载打印,签字确认信息后上传图片。</div>
<!-- 通过 pattern 进行正则校验 -->
<div class="item">
<p class="txt">姓名 Name<span> (请保证与护照名字顺序一样)</span></p>
<van-field
class="bor"
v-model="form.name"
name="pattern"
placeholder="请填写"
:rules="[{ pattern, message: '请用英文大写填写资料' }]"
/>
</div>
<div class="item">
<p class="txt">性别 Gender</p>
<van-field
@click="seleIsShow = true"
disabled
class="bor"
:value="form.gender == 1 ? '男' : '女'"
name="pattern"
placeholder=""
/>
</div>
<div class="item">
<p class="txt">出生地点 Place of birth</p>
<van-field
class="bor"
v-model="form.birth_place"
name="pattern"
placeholder="请填写"
:rules="[{ pattern, message: '请用英文大写填写资料' }]"
/>
</div>
<div class="item">
<p class="txt">出生日期 Date of birth (yyyy-mm-dd)</p>
<van-field
class="bor"
v-model="form.birth_date"
name="validator"
placeholder="请填写"
:rules="[{ validator, message: '请填写正确日期' }]"
/>
</div>
<div class="item">
<p class="txt">国籍 Nationality</p>
<van-field
class="bor"
v-model="form.nationality"
name="pattern"
placeholder="请填写"
:rules="[{ pattern, message: '请用英文大写填写资料' }]"
/>
</div>
<div class="item">
<p class="txt">职业 Occupatio</p>
<van-field
class="bor"
v-model="form.occupatio"
name="pattern"
placeholder="请填写"
:rules="[{ pattern, message: '请用英文大写填写资料' }]"
/>
</div>
<div class="item">
<p class="txt">护照号码 Passport Number</p>
<van-field
class="bor"
v-model="form.passport_number"
placeholder="请填写"
:rules="[{ pattern, message: '请填写正确的护照号码' }]"
/>
</div>
<div class="item">
<p class="txt">家庭住址 Home address(可填写一个熟悉的美国家庭/酒店地址)</p>
<van-field
class="bor"
v-model="form.address"
name="pattern"
placeholder="请填写"
:rules="[{ pattern, message: '请用英文大写填写资料' }]"
/>
</div>
<div class="item">
<p class="txt">电子邮箱 E-mail address</p>
<van-field
class="bor"
v-model="form.email"
name="pattern"
placeholder="请填写"
/>
</div>
<div class="item">
<p class="txt">住宅电话 Home phone number(请填写美国电话号)</p>
<van-field
class="bor"
type="number"
v-model="form.telephone"
name="pattern"
placeholder="请填写"
/>
</div>
<div class="item">
<p class="txt">手机 Mobile phone number (请填写美国任意一手机号)</p>
<van-field
class="bor"
type="number"
v-model="form.mobile"
name="pattern"
placeholder="请填写"
/>
</div>
<div class="tips">注:以下信息作为为您邮寄三级认证资料使用,请中文填写。</div>
<div class="item">
<p class="txt">您在FMBA项目中所属班级</p>
<van-field
class="bor"
v-model="form.class"
placeholder="请填写"
/>
</div>
<div class="item">
<p class="txt">收件人姓名</p>
<van-field
class="bor"
v-model="form.contact_name"
placeholder="请填写"
/>
</div>
<div class="item">
<p class="txt">联系人手机号码(填写国内手机号)</p>
<van-field
type="number"
class="bor"
v-model="form.contact_mobile"
placeholder="请填写"
/>
</div>
<div class="item">
<p class="txt">收件详细地址</p>
<van-field
class="bor"
v-model="form.contact_address"
name="pattern"
placeholder="请填写"
/>
</div>
<div class="btn-box">
<van-button native-type="submit" class="b" color="linear-gradient(180deg, #FF9B96 0%, #CE3E3A 100%)">提交</van-button>
<!-- <van-button class="b" @click="revokes">撤销</van-button> -->
<div class="revokes" @click="revokes">撤销</div>
</div>
</van-form>
<div class="sele" v-if="seleIsShow">
<van-picker
class="pic"
title="标题"
show-toolbar
:columns="columns"
@confirm="onConfirm"
@cancel="seleIsShow = false"
/>
</div>
</div>
</template>
<script>
import * as api from '@/api/attestation'
import { Form, Button, Dialog, Toast, Picker } from 'vant'
export default {
components: {
[Form.name]: Form,
[Button.name]: Button,
[Dialog.name]: Dialog,
[Toast.name]: Toast,
[Picker.name]: Picker
},
data() {
return {
seleIsShow: false,
columns: ['男', '女'],
form: {
name: '',
gender: '1',
birth_place: '',
birth_date: '',
nationality: '',
occupatio: '',
passport_number: '',
address: '',
email: '',
telephone: '',
mobile: '',
class: '',
contact_name: '',
contact_mobile: '',
contact_address: ''
},
value1: '',
value2: '',
value3: '',
pattern: /^[A-Z0-9\s]+$/
}
},
created() {
if (this.$route.query.edit) {
this.getCertificationDetail()
}
},
methods: {
getCertificationDetail() {
api.getAttestationDetail(this.$route.query.id).then(response => {
this.form = response
})
},
onConfirm(value, index) {
this.form.gender = index + 1
this.seleIsShow = false
},
onCancel() {
Toast('取消');
},
onSubmit() {
if (!this.$route.query.edit) {
api.submitInfo(this.form).then(response => {
if (response.success) {
window.sessionStorage.dataUrl = response.url
window.sessionStorage.dataId = response.id
this.$router.replace({
path: '/attestation/printing',
query: {
id: response.id
}
})
}
})
} else {
const param = this.form
param.type = 1
api.addSubmitStudent(this.$route.query.id, param).then(response => {
if (response.success) {
window.sessionStorage.dataUrl = response.url
window.sessionStorage.dataId = response.id
this.$router.replace({
path: '/attestation/printing',
query: {
id: this.$route.query.id,
edit: 1
}
})
}
})
}
},
getLetterMsg(value) {
if (value.replace(/\s/g, '') === '') {
return '请填写~'
} else {
return '请用英文大写填写资料'
}
},
// 校验函数返回 true 表示校验通过,false 表示不通过
validator(val) {
return /^\d{4}-\d{1,2}-\d{1,2}$/.test(val)
},
onFailed(errorInfo) {
Toast('请完善信息')
console.log('failed', errorInfo)
},
revokes() {
Dialog.confirm({
message: '你确定要撤回申请吗?撤回后,需要重新填写资料提交申请。'
}).then(() => {
const id = window.sessionStorage.dataId
if (id) {
api.revoke(id, { status: -2 }).then(response => {
if (response.success) {
Toast('撤销成功')
window.sessionStorage.removeItem('dataId')
window.sessionStorage.removeItem('dataUrl')
setTimeout(() => {
this.$router.go(0)
}, 1000)
}
})
} else {
this.$router.go(0)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.sele{
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
background: rgba(0,0,0, 0.5);
.pic{
width: 100%;
position: absolute;
bottom: 0;
left: 0;
}
}
.tips{
padding: .2rem;
color: #ee0a24;
}
.item{
border-bottom: .01rem solid #ccc;
margin-bottom: 12px;
.txt{
padding-left: 16px;
color: #000;
span{
color: #ee0a24;
}
}
}
.btn-box{
padding: .3rem 0;
width: 100%;
display: flex;
justify-content: space-around;
.revokes{
width: 1.2rem;
color: #323233;
background-color: #fff;
border: 1px solid #ebedf0;
padding: 0 15px;
font-size: 14px;
border-radius: 2px;
text-align: center;
line-height: 44px;
}
.b{
width: 1.2rem;
}
}
</style>
<template>
<div class="list-box">
<template v-for="(item, index) in data">
<div class="item-box" :key="index">
<div class="left">
<div class="title">三级认证申请</div>
<div :class="isClassText(item.approve_status).class">{{ isClassText(item.approve_status).text }}</div>
<div class="xx" v-if="item.approve_status == 0">
审批备注:<span>{{ item.approve_remark }}</span>
</div>
<div class="xx" v-if="item.approve_status != -1">
审批时间:<span>{{ item.updated_time }}</span>
</div>
</div>
<div class="right">
<template v-if="item.approve_status == -1">
<div class="btn" @click="goEdit(item.id)">编辑</div>
<div class="btn" @click="revoke(item.id)">撤销</div>
</template>
<template v-if="item.approve_status == 0">
<div class="btn" @click="goLook(item.id)">查看</div>
<div class="btn" @click="revoke(item.id, '删除成功')">删除</div>
</template>
<template v-if="item.approve_status == 1">
<div class="btn" @click="goLook(item.id)">查看</div>
<div class="btn" v-if="item.pay == 0" @click="orderPays">支付</div>
</template>
</div>
<!-- <div class="icon-yes"></div> -->
</div>
</template>
<div class="btn" @click="orderPays" style="font-size:30px;position: relative;z-index: 999;">支付</div>
<template v-if="data.length == 0">
<van-empty description="您还没有提交申请"/>
<div class="list-btn" v-if="data.length == 0" @click="apply">申请三级认证</div>
</template>
<h5-pay :productId="productId" ref="h5pay"></h5-pay>
</div>
</template>
<script>
import h5Pay from './buy/components/h5Pay.vue'
import { ImagePreview, Toast, Empty, Dialog } from 'vant'
import * as api from '@/api/attestation'
export default {
components: {
[ImagePreview.name]: ImagePreview,
[Toast.name]: Toast,
[Empty.name]: Empty,
[Dialog.name]: Dialog,
h5Pay
},
data() {
const productId = '6734697826573352960'
return {
productId,
data: []
}
},
mounted() {
this.getStatus()
},
computed: {
isClassText() {
return (type) => {
const types = parseInt(type)
const cont = {
class: '待审核',
text: 'tag'
}
switch(types) {
case -1:
cont.text = '待审核'
cont.class = 'tag'
break
case 0:
cont.text = '审核驳回'
cont.class = 'tag stu2'
break
case 1:
cont.text = '审核通过'
cont.class = 'tag stu3'
break
}
return cont
}
}
},
methods: {
orderPays() {
this.$refs.h5pay.pay()
},
goLook(id) {
this.$router.push({
path: '/attestation/upload',
query: {
id: id,
edit: 1,
look: 1
}
})
},
goEdit(id) {
this.$router.push({
path: '/attestation/printing',
query: {
id: id,
edit: 1
}
})
},
revoke(id, msg) {
Dialog.confirm({
message: '你确定要撤回申请吗?撤回后,需要重新填写资料提交申请。'
}).then(() => {
const id = window.sessionStorage.dataId
if (id) {
api.revoke(id, { status: -2 }).then(response => {
if (response.success) {
msg ? Toast(msg) : Toast('撤销成功')
window.sessionStorage.removeItem('dataId')
window.sessionStorage.removeItem('dataUrl')
setTimeout(() => {
this.$router.go(0)
}, 1000)
}
})
}
})
},
getStatus() {
api.getAttestationStatus().then(response => {
this.data = response
})
},
backEdit() {
this.$router.go(-1)
},
apply() {
this.$router.push({
path: '/attestation/form'
})
}
}
}
</script>
<style lang="scss" scoped>
.list-box{
width: 100%;
height: 100%;
}
.list-btn{
position: absolute;
bottom: 0;
left: 50%;
-webkit-transform: translateX(-50%);
width: 80%;
height: 40px;
line-height: 40px;
background: linear-gradient(180deg, #FF9B96 0%, #CE3E3A 100%);
border-radius: 5px;
font-weight: bold;
color: #FFFFFF;
text-align: center;
margin-bottom: 10px;
}
.item-box{
position: relative;
width: 90%;
background: #FFFFFF;
box-shadow: 0px 3px 20px 0px rgba(0, 0, 0, 0.05);
margin: 15px auto;
display: flex;
align-items: center;
padding: 20px;
box-sizing: border-box;
.left{
.title{
line-height: 100%;
font-size: 15px;
font-weight: bold;
color: #222222;
}
.tag{
font-size: 12px;
font-weight: bold;
color: #999999;
line-height: 100%;
margin-top: 30px;
&.stu1{
color: #FFC224;
}
&.stu2{
color: #AB2824;
}
&.stu3{
color: #24AB55;
}
}
.xx{
font-size: 12px;
color: #999999;
margin-top: 10px;
span{
color: #333333;
}
}
}
.right{
margin-left: auto;
.btn{
text-align: center;
line-height: 25px;
width: 60px;
height: 25px;
border-radius: 5px;
border: 0.5px solid #999999;
font-size: 10px;
color: #666;
&:nth-child(1) {
margin-bottom: 15px;
}
}
}
}
.icon-yes{
position: absolute;
top: 50%;
right: 95px;
-webkit-transform: translateY(-50%);
width: 75px;
height: 57px;
background: url(https://zws-imgs-pub.ezijing.com/static/public/ddd8126a0d9074b0408d3af5960db1f8.png);
background-size: 100% 100%;
}
</style>
<template>
<div>
<div class="img-box">
<img @click="imgShow = true" :src="images[0]" alt="">
</div>
<van-image-preview v-model="imgShow" :images="images"></van-image-preview>
<div class="tips">确认资料信息无误后,可长按图片保存下载,将信息页打印后,请在个人签名处签名后上传,注意签名不要连笔。</div>
<div class="btn-box">
<van-button class="b" @click="backEdit" color="linear-gradient(180deg, #FF9B96 0%, #CE3E3A 100%)">返回修改</van-button>
<van-button @click="goUpload" class="b" color="linear-gradient(180deg, #FF9B96 0%, #CE3E3A 100%)">已签名,去上传</van-button>
</div>
</div>
</template>
<script>
import { ImagePreview } from 'vant'
export default {
components: {
[ImagePreview.name]: ImagePreview
},
data() {
return {
imgShow: false,
images: []
}
},
mounted() {
this.images = [window.sessionStorage.dataUrl]
},
methods: {
backEdit() {
// this.$router.go(-1)
if (this.$route.query.edit) {
this.$router.replace({
path: '/attestation/form',
query: {
id: this.$route.query.id,
edit: 1
}
})
} else {
this.$router.replace({
path: '/attestation/form',
query: {
id: this.$route.query.id
}
})
}
},
goUpload() {
if (this.$route.query.edit) {
this.$router.replace({
path: '/attestation/upload',
query: {
id: this.$route.query.id,
edit: 1
}
})
} else {
this.$router.replace({
path: '/attestation/upload',
query: {
id: this.$route.query.id
}
})
}
}
}
}
</script>
<style lang="scss" scoped>
.img-box{
img{
width: 100%;
}
}
.tips{
padding: .1rem;
}
.btn-box{
margin-top: .8rem;
display: flex;
justify-content: space-around;
.b{
width: 1.3rem;
}
}
</style>
<template>
<div class="upload-box">
<card style="margin:0 20px;" v-if="!isLook">
<v-form
ref="form"
:model="formModel"
:fields="fields"
@submit="onSubmit"
@fileStatus="fileStatus"
>
<div class="btn-box">
<input
type="button"
value="确认提交"
class="submit-button"
@click="handleSubmit"
/>
<input
type="button"
value="撤销"
class="submit-button"
@click="revoke"
/>
</div>
</v-form>
</card>
<template v-else>
<div class="look-form">
<div class="form-item">
<div class="label">1,已签字确认的个人资料页</div>
<div class="up-box">
<img :src="formModel.apply" alt="">
</div>
</div>
</div>
<div class="look-form">
<div class="form-item">
<div class="label">2,个人护照信息页</div>
<div class="up-box">
<img :src="formModel.passport" alt="">
</div>
</div>
</div>
<div class="look-form">
<div class="form-item">
<div class="label">3,学位证书页</div>
<div class="up-box">
<img :src="formModel.degree" alt="">
</div>
</div>
</div>
<div class="status">
审核状态:{{ currentStu }}
</div>
<div class="btn-box">
<input type="button" value="支付" class="submit-button" v-if="auditStatus == 1 && ispay == 0">
<template v-if="auditStatus == -1">
<input @click="goForm" type="button" value="修改" class="submit-button">
<input @click="revoke" type="button" value="撤销" class="submit-button">
</template>
<template v-if="auditStatus == 0">
<input @click="goForm" type="button" value="修改" class="submit-button">
<!-- <input @click="revoke" type="button" value="撤销" class="submit-button"> -->
</template>
</div>
</template>
</div>
</template>
<script>
import Card from '@/components/Card'
import VForm from '@/components/attestationFormUpload'
import { Toast, Dialog } from 'vant'
import * as api from '@/api/attestation'
export default {
name: 'submitStudent',
components: {
Card,
VForm,
[Toast.name]: Toast,
[Dialog.name]: Dialog
},
data() {
return {
auditStatus: 2,
ispay: false,
isLook: false,
formModel: { apply: '', passport: '', degree:''},
fields: [
{
fieldType: 'uploader',
name: 'apply',
label: '1,已签字确认的个人资料页',
placeholder: '请上传照片',
examples: 'https://zws-imgs-pub.ezijing.com/static/public/ec3457296e311c4c1917b5febc2c1a7e.png'
},
{
fieldType: 'uploader',
name: 'passport',
label: '2,个人护照信息页',
placeholder: '请上传照片',
examples: 'https://zws-imgs-pub.ezijing.com/static/public/d74236d102ec6be2aeb5ab49a57cd7e5.png'
},
{
fieldType: 'uploader',
name: 'degree',
label: '3,学位证书页',
placeholder: '请上传照片',
examples: 'https://zws-imgs-pub.ezijing.com/static/public/356814af81ac3ce50ab9501dfa05f481.png'
}
],
type: false
}
},
watch: {
$route: {
immediate: true,
deep: true,
handler(route) {
this.formModel = Object.assign(this.formModel, route.query)
}
}
},
computed: {
currentStu() {
const stu = parseInt(this.auditStatus)
let cont = ''
switch(stu) {
case -1:
cont = '待审核'
break
case 0:
cont = '审核驳回'
break
case 1:
cont = '审核通过'
break
}
return cont
}
},
mounted() {
this.$route.query.look && (this.isLook = true)
this.$route.query.edit && (this.isLook = true)
if (this.$route.query.edit) {
this.getCertificationDetail()
}
},
methods: {
goForm() {
this.$router.replace({
path: '/attestation/form',
query: {
id: this.$route.query.id,
edit: 1
}
})
},
getCertificationDetail() {
api.getAttestationDetail(this.$route.query.id).then(response => {
// formModel: { apply: '', passport: '', degree:''}
this.formModel.apply = response.apply
this.formModel.passport = response.passport
this.formModel.degree = response.degree
this.auditStatus = response.approve_status
this.ispay = response.pay
})
},
revoke() {
// 撤销
Dialog.confirm({
message: '你确定要撤回申请吗?撤回后,需要重新填写资料提交申请。'
}).then(() => {
const id = window.sessionStorage.dataId
if (id) {
api.revoke(this.$route.query.id, { status: -2 }).then(response => {
if (response.success) {
Toast('撤销成功')
window.sessionStorage.removeItem('dataId')
window.sessionStorage.removeItem('dataUrl')
setTimeout(() => {
this.$router.go(-1)
}, 1000)
}
})
} else {
// this.$router.go(0)
}
})
},
fileStatus(state) {
this.type = state
},
handleSubmit() {
this.$refs.form.submit()
},
onSubmit() {
const ruleForm = this.$refs.form.ruleForm
const param = {}
param.apply = ruleForm.apply
param.passport = ruleForm.passport
param.degree = ruleForm.degree
param.type = 2
console.log(ruleForm)
for (let i = 0; i < Object.values(ruleForm).length; i++) {
if (Object.values(ruleForm)[i] === '') {
Toast('请上传')
return
}
}
api.addSubmitStudent(this.$route.query.id, param).then(response => {
if (response.success) {
this.$dialog
.alert({
confirmButtonText: '确定',
message: '上传成功'
})
.then(() => {
// queding
this.isLook = true
this.getCertificationDetail()
})
} else {
this.$toast(response.message)
}
})
}
}
}
</script>
<style lang="scss" scope>
.status{
margin: 0 20px;
}
.upload-box{
padding-top: 20px;
}
.btn-box{
display: flex;
justify-content: space-around;
.submit-button{
width: 40%;
}
}
.look-form{
margin: 0px 20px;
.form-item{
.up-box{
display: flex;
padding-top: 10px;
margin-bottom: 10px;
img{
width: 50%;
display: block;
}
}
}
}
.btn-box{
margin-top: 30px;
}
</style>
...@@ -10,7 +10,7 @@ module.exports = { ...@@ -10,7 +10,7 @@ module.exports = {
}, },
proxy: { proxy: {
'/api': { '/api': {
target: 'https://alumni.ezijing.com' target: 'https://alumni2.ezijing.com'
} }
} }
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论