|
|
@@ -0,0 +1,369 @@
|
|
|
+<template>
|
|
|
+ <div class="package-container">
|
|
|
+ <van-nav-bar
|
|
|
+ title="服务套餐"
|
|
|
+ left-text="返回"
|
|
|
+ left-arrow
|
|
|
+ @click-left="goBack()"
|
|
|
+ />
|
|
|
+
|
|
|
+ <van-cell
|
|
|
+ title="设备押金 1200(元)"
|
|
|
+ label="设备押金在服务到期后,若不再进行续费,设备完好情况下,联系工作人员退款。"
|
|
|
+ >
|
|
|
+ <!-- <van-stepper
|
|
|
+ slot="right-icon"
|
|
|
+ v-model="WxTencentForm.equipmentPledge"
|
|
|
+ button-size="24px"
|
|
|
+ input-width="58px"
|
|
|
+ class="absolute right14"
|
|
|
+ disabled
|
|
|
+ /> -->
|
|
|
+ </van-cell>
|
|
|
+
|
|
|
+ <van-loading
|
|
|
+ v-if="loading"
|
|
|
+ type="spinner"
|
|
|
+ color="#1989fa"
|
|
|
+ size="40px"
|
|
|
+ vertical
|
|
|
+ >
|
|
|
+ 加载中...
|
|
|
+ </van-loading>
|
|
|
+
|
|
|
+ <van-overlay v-if="loading" :show="loading" />
|
|
|
+
|
|
|
+ <!-- 修改为单列布局 -->
|
|
|
+ <div class="package-list">
|
|
|
+ <div
|
|
|
+ v-for="(packageItem, index) in packages"
|
|
|
+ :key="index"
|
|
|
+ class="package-card"
|
|
|
+ >
|
|
|
+ <div class="image-wrapper" @click="showDialog(packageItem)">
|
|
|
+ <van-image
|
|
|
+ :src="packageItem.icon"
|
|
|
+ fit="cover"
|
|
|
+ class="package-image"
|
|
|
+ />
|
|
|
+ <div class="overlay-text">
|
|
|
+ <h3 class="card-title">{{ packageItem.type }}</h3>
|
|
|
+ <p class="card-price">{{ formatPrice(packageItem.price) }}元</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+ <van-dialog v-model="payShow" title="支付确认" show-cancel-button :lazy-render="false" @confirm="handleWechatAuth">
|
|
|
+
|
|
|
+ </van-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import {tencentLearnPackage} from '@/api/comboMeal/index'
|
|
|
+import { symmetryDecryptWX } from '@/utils/secret.js'
|
|
|
+import {wXTencentSave} from '@/api/patient/index'
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ packages: [
|
|
|
+ ],
|
|
|
+ WxTencentForm: {},
|
|
|
+ payShow: false,
|
|
|
+ learningPackageId: "",
|
|
|
+ loading: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.getLearnPackage()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ getLearnPackage(){
|
|
|
+ tencentLearnPackage().then(resp=>{
|
|
|
+ this.packages = resp.data.map(item => {
|
|
|
+ const newItem = { ...item }; // 创建新对象
|
|
|
+ switch (newItem.timeType) {
|
|
|
+ case "B":
|
|
|
+ newItem.icon = require('@/assets/images/packages3.png');
|
|
|
+ newItem.type = "季卡"
|
|
|
+ break;
|
|
|
+ case "C":
|
|
|
+ newItem.icon = require('@/assets/images/packages2.png');
|
|
|
+ newItem.type = "半年卡"
|
|
|
+ break;
|
|
|
+ case "D":
|
|
|
+ newItem.icon = require('@/assets/images/packages1.png');
|
|
|
+ newItem.type = "年卡"
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return newItem;
|
|
|
+ });
|
|
|
+ if(Object.keys(this.$route.query).length > 0){
|
|
|
+ const query = this.$route.query;
|
|
|
+ this.WxTencentForm = JSON.parse(symmetryDecryptWX(decodeURIComponent(this.$route.query.userInfo)));
|
|
|
+ if(query.code && query.packagesId && query.state){
|
|
|
+ this.handleSubmit(query.code,query.packagesId,query.state);
|
|
|
+ }
|
|
|
+ this.WxTencentForm.equipmentPledge = 1
|
|
|
+ }else {
|
|
|
+ this.$router.push({
|
|
|
+ path: '/officialAccounts/patientData',
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ goBack(){
|
|
|
+ this.$router.push({
|
|
|
+ path: '/officialAccounts/patientData',
|
|
|
+ query: {
|
|
|
+ payUserInfo: symmetryDecryptWX(this.$route.query.userInfo)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ formatPrice(price) {
|
|
|
+ return (price / 100).toFixed(2)
|
|
|
+ },
|
|
|
+ showDialog(row) {
|
|
|
+ this.payShow = true
|
|
|
+ this.learningPackageId= row.id
|
|
|
+ },
|
|
|
+ // 加载微信JS-SDK
|
|
|
+ loadWechatSDK() {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ if (window.wx) {
|
|
|
+ resolve(window.wx);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const script = document.createElement('script');
|
|
|
+ script.src = 'https://res.wx.qq.com/open/js/jweixin-1.6.0.js';
|
|
|
+ script.onload = () => {
|
|
|
+ // SDK加载成功后初始化配置
|
|
|
+ this.initWxConfig().then(resolve).catch(reject);
|
|
|
+ };
|
|
|
+ script.onerror = () => {
|
|
|
+ reject(new Error('微信SDK加载失败'));
|
|
|
+ };
|
|
|
+ document.head.appendChild(script);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 初始化微信配置
|
|
|
+ initWxConfig() {
|
|
|
+ return this.$http.get('/api/wechat/config', {
|
|
|
+ params: {
|
|
|
+ url: window.location.href.split('#')[0]
|
|
|
+ }
|
|
|
+ }).then(response => {
|
|
|
+ const { appId, timestamp, nonceStr, signature } = response.data;
|
|
|
+
|
|
|
+ wx.config({
|
|
|
+ debug: process.env.NODE_ENV === 'development',
|
|
|
+ appId,
|
|
|
+ timestamp,
|
|
|
+ nonceStr,
|
|
|
+ signature,
|
|
|
+ jsApiList: ['chooseWXPay']
|
|
|
+ });
|
|
|
+
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ wx.ready(() => resolve());
|
|
|
+ wx.error((res) => reject(new Error(`SDK配置失败: ${JSON.stringify(res)}`)));
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ handleSubmit(code,id,state) {
|
|
|
+ this.loading = true;
|
|
|
+ console.log(this.WxTencentForm)
|
|
|
+ if(this.WxTencentForm){
|
|
|
+ const params = {
|
|
|
+ state: state,
|
|
|
+ code: code,
|
|
|
+ packageId: id,
|
|
|
+ equipmentPledge: '1',
|
|
|
+ name: this.WxTencentForm.name,
|
|
|
+ gender: this.WxTencentForm.gender,
|
|
|
+ age: this.WxTencentForm.age,
|
|
|
+ mobile: this.WxTencentForm.mobile,
|
|
|
+ idCard: this.WxTencentForm.idCard,
|
|
|
+ birthDate: this.WxTencentForm.birthDate,
|
|
|
+ education: this.WxTencentForm.education,
|
|
|
+ medicalCurrentTypes: this.WxTencentForm.medicalCurrentTypes.toString(),
|
|
|
+ medicalHisTypes: this.WxTencentForm.medicalHisTypes.toString(),
|
|
|
+ geneticDiseases: this.WxTencentForm.geneticDiseases.toString(),
|
|
|
+ diagnoseResult: this.WxTencentForm.diagnoseResult.toString(),
|
|
|
+ tags: this.WxTencentForm.tags.toString(),
|
|
|
+ doctorName: this.WxTencentForm.doctorName
|
|
|
+ }
|
|
|
+ wXTencentSave(params).then(resp => {
|
|
|
+ if(resp.code == 201) {
|
|
|
+ console.log("重复调用")
|
|
|
+ this.$router.push({
|
|
|
+ path: '/officialAccounts/patientData',
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 微信JSAPI调用参数
|
|
|
+ const payParams = {
|
|
|
+ appId: resp.data.wxAppId,
|
|
|
+ timeStamp: resp.data.wxTimeStamp.toString(),
|
|
|
+ nonceStr: resp.data.wxNonceStr,
|
|
|
+ package: resp.data.wxPackage,
|
|
|
+ signType: resp.data.wxSignType, // 统一转换标准类型
|
|
|
+ paySign: resp.data.wxPaySign
|
|
|
+ };
|
|
|
+ // // 调用微信支付接口
|
|
|
+ // wx.chooseWXPay({
|
|
|
+ // ...payParams,
|
|
|
+ // success: res => {
|
|
|
+ // this.$toast.success('支付成功');
|
|
|
+ // this.handlePaymentSuccess(res);
|
|
|
+ // },
|
|
|
+ // fail: err => {
|
|
|
+ // this.$toast.error(`支付失败: ${err.errMsg || '系统错误'}`);
|
|
|
+ // this.handlePaymentFailure(err);
|
|
|
+ // },
|
|
|
+ // complete: () => {
|
|
|
+ // this.loading = false;
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+ this.invokeWechatPay(payParams)
|
|
|
+
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ invokeWechatPay(payParams) {
|
|
|
+ WeixinJSBridge.invoke('getBrandWCPayRequest', {
|
|
|
+ ...payParams
|
|
|
+ }, (res) => {
|
|
|
+ this.loading = false;
|
|
|
+ if (res.err_msg === 'get_brand_wcpay_request:ok') {
|
|
|
+ this.handlePaymentSuccess();
|
|
|
+ } else {
|
|
|
+ this.handlePaymentFailure(res);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 支付成功处理
|
|
|
+ handlePaymentSuccess() {
|
|
|
+ console.log("成功")
|
|
|
+ this.$router.push({
|
|
|
+ path: '/officialAccounts/payStatus',
|
|
|
+ query: {
|
|
|
+ payStatus: '0'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 支付失败处理
|
|
|
+ handlePaymentFailure(error) {
|
|
|
+ console.log("失败")
|
|
|
+ this.$router.push({
|
|
|
+ path: '/officialAccounts/payStatus',
|
|
|
+ query: {
|
|
|
+ payStatus: '1'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ handleWechatAuth() {
|
|
|
+ const currentPath = window.location.pathname;
|
|
|
+ const currentQuery = { ...this.$route.query,
|
|
|
+ packagesId: this.learningPackageId,
|
|
|
+ };
|
|
|
+ let redirectPath = currentPath;
|
|
|
+ const queryString = Object.keys(currentQuery)
|
|
|
+ .map(key => `${key}=${currentQuery[key]}`)
|
|
|
+ .join('&');
|
|
|
+ if (queryString) {
|
|
|
+ redirectPath += `?${queryString}`;
|
|
|
+ }
|
|
|
+ const redirectUri = encodeURIComponent(
|
|
|
+ window.location.origin + redirectPath
|
|
|
+ );
|
|
|
+ const params = {
|
|
|
+ appId: 'wxe6dbe98e8c6d1a4b',
|
|
|
+ redirectUri: redirectUri,
|
|
|
+ scope: 'snsapi_base',
|
|
|
+ state: this.generateState()
|
|
|
+ }
|
|
|
+
|
|
|
+ const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${params.appId}&redirect_uri=${params.redirectUri}&response_type=code&scope=${params.scope}&state=${params.state}#wechat_redirect`;
|
|
|
+ window.location.href = authUrl
|
|
|
+ },
|
|
|
+ generateState() {
|
|
|
+ return Math.random().toString(36).substr(2) + Date.now().toString(36)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+/* 修改图片容器为流式布局 */
|
|
|
+.image-wrapper {
|
|
|
+ position: relative;
|
|
|
+ width: 80%;
|
|
|
+ display: flex;
|
|
|
+ background: #f0f2f5;
|
|
|
+ margin: 2rem auto;
|
|
|
+ border-radius: 12px;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .package-image {
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ min-height: 150px;
|
|
|
+ object-fit: cover;
|
|
|
+ transition: height 0.3s ease;
|
|
|
+ }
|
|
|
+
|
|
|
+ .overlay-text {
|
|
|
+ position: absolute;
|
|
|
+ top: 0; // 定位到顶部
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ padding: 12px 16px;
|
|
|
+ background: transparent !important; // 透明背景
|
|
|
+
|
|
|
+ .card-title {
|
|
|
+ font-size: clamp(16px, 4vw, 18px);
|
|
|
+ color: #fff;
|
|
|
+ margin-left: 7%;
|
|
|
+ margin-top: 5%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .card-price {
|
|
|
+ font-size: clamp(24px, 6vw, 32px);
|
|
|
+ color: #fff;
|
|
|
+ font-weight: 400;
|
|
|
+ margin-top: 2%;
|
|
|
+ margin-left: 7%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 响应式适配
|
|
|
+@media (max-width: 480px) {
|
|
|
+ .image-wrapper {
|
|
|
+ width: 85%;
|
|
|
+ margin: 1.5rem auto;
|
|
|
+ border-radius: 8px;
|
|
|
+
|
|
|
+ .overlay-text {
|
|
|
+ padding: 8px 12px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 极端小屏适配
|
|
|
+@media (max-width: 320px) {
|
|
|
+ .image-wrapper {
|
|
|
+ width: 90%;
|
|
|
+ margin: 1rem auto;
|
|
|
+
|
|
|
+ .overlay-text {
|
|
|
+ padding: 6px 8px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|