Browse Source

完善微信支付和微信登录

shmily1213 1 tháng trước cách đây
mục cha
commit
514dac4b23

+ 37 - 13
src/hooks/usePay.ts

@@ -43,20 +43,44 @@ export const usePay = () => {
         totalFee: price.value,
         type: payType.value
       });
+      loading.value = false;
       uni.$ie.hideLoading();
-      console.log(data, 666)
-      // outTradeNo.value = data.outTradeNo;
-      // const no = outTradeNo.value.split('_')[1];
-      // if (no) {
-      //   payStore.setOrderId(Number(no));
-      // }
-      // h5url.value = data.h5url;
-      // if (outTradeNo && h5url) {
-      //   clearResultFrame()
-      //   webview = await createResultFrame(h5url.value);
-      // } else {
-      //   throw new Error('支付地址缺失');
-      // }
+      outTradeNo.value = data.outTradeNo;
+      const no = outTradeNo.value.split('_')[1];
+      if (no) {
+        payStore.setOrderId(Number(no));
+      }
+      if (isH5.value || isWap2App.value) {
+        h5url.value = data.h5url;
+        if (outTradeNo && h5url) {
+          clearResultFrame()
+          webview = await createResultFrame(h5url.value);
+        } else {
+          throw new Error('支付地址缺失');
+        }
+      } else if (isMP.value) {
+        if (data.wcPayData) {
+          const payJson = JSON.parse(data.wcPayData);
+          uni.requestPayment({
+            provider: "wxpay",
+            orderInfo: {},
+            nonceStr: payJson.nonceStr,
+            package: payJson.packageValue,
+            paySign: payJson.paySign,
+            timeStamp: payJson.timeStamp,
+            signType: payJson.signType,
+            success(res) {
+              checkOrderStatus();
+            },
+            fail(e) {
+              uni.$ie.showToast('支付失败');
+              payStore.setOrderId(null);
+            }
+          })
+        } else {
+          throw new Error('缺少支付参数');
+        }
+      }
     } catch (error) {
       loading.value = false;
       uni.$ie.showToast('下单失败,请稍后再试');

+ 1 - 1
src/pagesStudy/components/mp-html/components/mp-html/mp-html.vue

@@ -41,7 +41,7 @@
 import node from './node/node'
 // #endif
 import Parser from './parser'
-import latex from './latex/index.js'
+import latex from './latex/index.js'
 const plugins=[latex,]
 // #ifdef APP-PLUS-NVUE
 const dom = weex.requireModule('dom')

+ 68 - 5
src/pagesStudy/components/mp-html/components/mp-html/parser.js

@@ -1262,6 +1262,39 @@ Lexer.prototype.text = function () {
   }
   const c = this.content[this.i + 1]
   if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+    // 检查是否是有效的标签开头
+    // 查找下一个 > 符号来验证这是否真的是一个标签
+    let tagEndPos = this.content.indexOf('>', this.i + 1)
+    // 如果找不到 > 或者在 > 之前遇到另一个 <,说明这不是有效的标签
+    let nextLtPos = this.content.indexOf('<', this.i + 1)
+    if (tagEndPos === -1 || (nextLtPos !== -1 && nextLtPos < tagEndPos)) {
+      // 这不是有效的标签,将 < 作为普通文本处理
+      this.i++
+      return
+    }
+    
+    // 提取标签名,验证是否是已知的HTML标签
+    let tagNameEnd = this.i + 1
+    while (tagNameEnd < tagEndPos && this.content[tagNameEnd] !== ' ' && this.content[tagNameEnd] !== '/' && !blankChar[this.content[tagNameEnd]]) {
+      tagNameEnd++
+    }
+    const possibleTagName = this.content.substring(this.i + 1, tagNameEnd).toLowerCase()
+    
+    // 检查是否是已知的HTML标签或SVG标签
+    const isValidTag = config.trustTags[possibleTagName] || 
+                       config.blockTags[possibleTagName] || 
+                       config.ignoreTags[possibleTagName] || 
+                       config.voidTags[possibleTagName] ||
+                       config.svgDict[possibleTagName] ||
+                       possibleTagName === 'svg' ||
+                       possibleTagName === 'foreignobject'
+    
+    if (!isValidTag) {
+      // 不是已知标签,将 < 作为普通文本处理
+      this.i++
+      return
+    }
+    
     // 标签开头
     if (this.start !== this.i) {
       this.handler.onText(this.content.substring(this.start, this.i))
@@ -1269,18 +1302,48 @@ Lexer.prototype.text = function () {
     this.start = ++this.i
     this.state = this.tagName
   } else if (c === '/' || c === '!' || c === '?') {
-    if (this.start !== this.i) {
-      this.handler.onText(this.content.substring(this.start, this.i))
-    }
     const next = this.content[this.i + 2]
     if (c === '/' && ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
-      // 标签结尾
+      // 可能是结束标签,需要验证
+      let tagEndPos = this.content.indexOf('>', this.i + 2)
+      if (tagEndPos !== -1) {
+        // 提取结束标签名进行验证
+        let tagNameEnd = this.i + 2
+        while (tagNameEnd < tagEndPos && this.content[tagNameEnd] !== ' ' && this.content[tagNameEnd] !== '/' && !blankChar[this.content[tagNameEnd]]) {
+          tagNameEnd++
+        }
+        const possibleTagName = this.content.substring(this.i + 2, tagNameEnd).toLowerCase()
+        
+        // 检查是否是已知的HTML标签
+        const isValidTag = config.trustTags[possibleTagName] || 
+                           config.blockTags[possibleTagName] || 
+                           config.ignoreTags[possibleTagName] || 
+                           config.voidTags[possibleTagName] ||
+                           config.svgDict[possibleTagName] ||
+                           possibleTagName === 'svg' ||
+                           possibleTagName === 'foreignobject'
+        
+        if (!isValidTag) {
+          // 不是已知标签,将 </ 作为普通文本处理
+          this.i++
+          return
+        }
+      }
+      
+      // 是有效的结束标签
+      if (this.start !== this.i) {
+        this.handler.onText(this.content.substring(this.start, this.i))
+      }
       this.i += 2
       this.start = this.i
       this.state = this.endTag
       return
     }
-    // 处理注释
+    
+    // 处理注释和其他特殊标签
+    if (this.start !== this.i) {
+      this.handler.onText(this.content.substring(this.start, this.i))
+    }
     let end = '-->'
     if (c !== '!' || this.content[this.i + 2] !== '-' || this.content[this.i + 3] !== '-') {
       end = '>'

+ 29 - 5
src/pagesSystem/pages/bind-profile/bind-profile.vue

@@ -1,6 +1,6 @@
 <template>
   <ie-page bg-color="#F6F8FA" :safeAreaInsetBottom="false">
-    <ie-navbar title="完善信息"></ie-navbar>
+    <ie-navbar title="完善信息" custom-back @left-click="handleBack" />
     <uv-form labelPosition="left" :model="form" labelWidth="70px" ref="formRef">
       <content-card title="个人信息">
         <uv-form-item label="姓名" prop="name" borderBottom required>
@@ -12,8 +12,12 @@
           <ie-picker ref="pickerRef" v-model="examTypeForm.location" :list="provinceList"
             :placeholder="pickerPlaceholder" :custom-style="customStyle" key-label="areaName" key-value="shortName"
             :disabled="isProvinceDisabled">
-            <template v-if="isProvinceDisabled" #right>
-              <ie-image src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+            <template #right>
+              <ie-image v-if="isProvinceDisabled" src="/static/image/icon-lock.png" custom-class="w-24 h-30"
+                mode="aspectFill" />
+              <view v-else class="transition-all duration-300">
+                <uv-icon name="arrow-right" size="15" color="#B3B3B3" />
+              </view>
             </template>
           </ie-picker>
         </uv-form-item>
@@ -21,8 +25,12 @@
           <ie-picker ref="pickerRef" v-model="examTypeForm.examType" :list="examTypeList" :disabled="isExamTypeDisabled"
             :placeholder="pickerPlaceholder" :custom-style="customStyle" key-label="dictLabel" key-value="dictValue"
             @click="handlePreCheck('examType')" @change="handleExamTypeChange">
-            <template v-if="isExamTypeDisabled" #right>
-              <ie-image src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+            <template #right>
+              <ie-image v-if="isExamTypeDisabled" src="/static/image/icon-lock.png" custom-class="w-24 h-30"
+                mode="aspectFill" />
+              <view v-else class="transition-all duration-300">
+                <uv-icon name="arrow-right" size="15" color="#B3B3B3" />
+              </view>
             </template>
           </ie-picker>
         </uv-form-item>
@@ -116,6 +124,7 @@ import { BindCardInfo, CardInfo, ClassItem, LoginInfo, RegisterInfo, SchoolItem,
 
 import { getClassList } from '@/api/modules/user';
 import { EnumBindScene, EnumExamRecordType, EnumExamType, EnumUserType } from '@/common/enum';
+import { usePayStore } from '@/store/payStore';
 type PrevDataInfo = {
   cardInfo: CardInfo;
   userInfo: UserInfo;
@@ -407,7 +416,22 @@ const startRegister = async (params: BindCardInfo) => {
   }
 }
 
+const handleBack = () => {
+  const pages = getCurrentPages();
+  const page = pages[pages.length - 2];
+  // 如果是登录页,允许直接返回
+  if (page?.route && ['pagesMain/pages/index/index', 'pagesMain/pages/me/me', 'pagesSystem/pages/pay/pay'].includes(page.route)) {
+    uni.$ie.showToast('请先完善信息');
+  } else {
+    transferBack();
+  }
+};
+
 const goHome = () => {
+  // 清除订单信息,不管有没有
+  const payStore = usePayStore();
+  payStore.setOrderId(null);
+  console.log('清除订单信息:', payStore.orderId)
   setTimeout(() => {
     transferTo('/pagesMain/pages/index/index', {
       type: 'reLaunch'

+ 51 - 36
src/pagesSystem/pages/login/login.vue

@@ -42,14 +42,15 @@
         <ie-button @click="handleLogin">登录</ie-button>
         <!-- #ifdef MP-WEIXIN -->
         <view class="flex items-center justify-center">
-          <uv-button v-if="!isAgree" :custom-style="customBtnStyle" :hover-effect="false" type="primary" @click="handleCheckAgree">
+          <uv-button v-if="!isAgree" :custom-style="customBtnStyle" :hover-effect="false" type="primary"
+            @click="handleCheckAgree">
             <view class="mt-40 flex items-center justify-center gap-10">
               <uv-icon name="weixin-circle-fill" color="#66dc79" size="26" />
               <text class="text-28 text-primary">一键登录</text>
             </view>
           </uv-button>
-          <uv-button v-else :custom-style="customBtnStyle" :hover-effect="false" :disabled="!isAgree" type="primary" text="手机号快捷登录"
-            icon-color="white" open-type="getPhoneNumber|agreePrivacyAuthorization"
+          <uv-button v-else :custom-style="customBtnStyle" :hover-effect="false" :disabled="!isAgree" type="primary"
+            text="手机号快捷登录" icon-color="white" open-type="getPhoneNumber|agreePrivacyAuthorization"
             @getphonenumber="handleGetPhoneNumber" @agreeprivacyauthorization="handleAgreePrivacyAuthorization"
             @click="handleWxLogin">
             <view class="mt-40 flex items-center justify-center gap-10">
@@ -83,7 +84,8 @@ import { useAppConfig } from '@/hooks/useAppConfig';
 import { verifyCard } from '@/api/modules/user';
 import { EnumBindScene, EnumSmsApiType, EnumUserType } from '@/common/enum';
 import { login, wxLogin } from '@/api/modules/login';
-import { LoginRequestDTO, UserInfo } from '@/types/user';
+import { LoginRequestDTO, MobileLoginResponseDTO, UserInfo } from '@/types/user';
+import { ApiResponse } from '@/types';
 
 const { transferBack, transferTo, routes } = useTransferPage();
 const userStore = useUserStore();
@@ -227,6 +229,7 @@ const handleGetPhoneNumber = async (e: any) => {
         loginCode: code,
       }).then(res => {
         console.log('微信登录结果:', res)
+        handleLoginResponse('wx', res);
       }).finally(() => {
         loading.value = false;
         uni.$ie.hideLoading();
@@ -241,43 +244,55 @@ const handleMobileLogin = async (params: LoginRequestDTO) => {
   uni.$ie.showLoading();
   login(params).then((res) => {
     uni.$ie.hideLoading();
-    if (res.data) {
-      const { code, message } = res.data;
-      if (code === 101) {
-        console.log('registerInfo:', params)
-        // 账号不存在,需要注册
-        transferTo('/pagesSystem/pages/bind-profile/bind-profile', {
-          data: {
-            scene: EnumBindScene.REGISTER,
-            userInfo: {},
-            cardInfo: {},
-            registerInfo: {
-              ...params
-            }
-          }
-        });
+    handleLoginResponse('mobile', res, params);
+  }).finally(() => {
+    uni.$ie.hideLoading();
+  });
+}
+
+const handleLoginResponse = (type: 'wx' | 'mobile', res: ApiResponse<MobileLoginResponseDTO>, params: LoginRequestDTO & { openId?: string } = {}) => {
+  console.log('处理登录', res, params);
+  if (res.data) {
+    const { code, message, mobile, openId } = res.data;
+    if (code === 101) {
+      console.log('registerInfo:', params)
+      const pageOptions = {
+        scene: EnumBindScene.REGISTER,
+        userInfo: {},
+        cardInfo: {},
+        registerInfo: {
+          ...params
+        }
+      };
+      if (type === 'wx') {
+        pageOptions.registerInfo = {
+          ...pageOptions.registerInfo,
+          mobile,
+          openId
+        }
       }
-    } else {
-      if (res.token) {
-        userStore.login(res.token).then(({ success, userInfo }) => {
-          if (success) {
-            // transferBack(true);
+      // 账号不存在,需要注册
+      transferTo('/pagesSystem/pages/bind-profile/bind-profile', {
+        data: pageOptions
+      });
+    }
+  } else {
+    if (res.token) {
+      userStore.login(res.token).then(({ success, userInfo }) => {
+        if (success) {
+          // transferBack(true);
+          uni.$ie.showSuccess('登录成功');
+          setTimeout(() => {
             transferTo(routes.pageIndex, {
               type: 'reLaunch'
             });
-          } else {
-            uni.$ie.showToast('登录失败')
-          }
-        });
-      }
+          }, 800);
+        } else {
+          uni.$ie.showToast('登录失败')
+        }
+      });
     }
-  }).catch(err => {
-    console.log('登录失败', err)
-  })
-}
-
-const handleLoginResponse = () => {
-
+  }
 }
 
 const handleCardLogin = (params: LoginRequestDTO) => {

+ 2 - 0
src/types/pay.ts

@@ -9,8 +9,10 @@ export interface EcardPrice {
 }
 
 export interface CreateOrderResult {
+  orderId: string;
   h5url: string;
   outTradeNo: string;
+  wcPayData?: string; // 微信小程序支付特有
 }
 
 export interface OrderPayStatus {