shenwu há 7 meses atrás
pai
commit
d0e8a97cfe

+ 1 - 0
src/app.tsx

@@ -52,6 +52,7 @@ class App extends Component {
     })
   }
   async componentDidShow(options) {
+    console.log("appcomponentDidShow")
     let { scene, query ,path} = options//获取当前小程序进入的场景值
     let bookConfig = Taro.getStorageSync("bookConfig")
     if (bookConfig) {

+ 28 - 4
src/components/bottomModal/index.tsx

@@ -5,6 +5,7 @@ import './index.less'
 import Vip from './vip';
 import Shubi from './shubi';
 import { setApp } from '@src/config';
+import { templateBuy } from '@src/server/wx/pay';
 
 interface Props {
     type?: 'vip' | 'shubi',
@@ -12,11 +13,17 @@ interface Props {
     shubiData?: {
         payCoin: number,
         coinNum: number,
-    }
+    },
+    payBookInfo?: {
+        bookId: number,
+        bookParagraphId: null,
+        orderCondition: "阅读中"
+    },
+    callBackFn?: () => void//支付刷新小说内容
 }
 
 const GlobalModal: React.FC<Props> = (props) => {
-    let { type = "shubi", isBook = true, shubiData } = props
+    let { type = "shubi", isBook = true, shubiData, payBookInfo, callBackFn } = props
     return useObserver(() => {
         let { visible } = modalStore
         const hide = (e) => {
@@ -25,15 +32,32 @@ const GlobalModal: React.FC<Props> = (props) => {
             // 关闭弹窗清空支付数据
             setApp({ payData: null })
         }
+        //模板支付
+        const pay = async (payData: any) => {
+            let params: any = {}
+            if (payBookInfo) {
+                params = { ...payBookInfo, ...payData }
+            } else {
+                params = { orderCondition: "个人中心", ...payData }
+            }
+              
+            console.log("支付模板数据", params)
+            // let res = await templateBuy(params)
+            // if(res){
+            //     callBackFn?.()//刷新页面
+            //     modalStore.hideModal()
+            // }
+          
+        }
         return <>
             {visible && <View className="modal" onClick={hide}>
                 <View className="box" onClick={(e) => { e.stopPropagation() }}>
                     {/* 关闭 */}
                     <View className='clear' onClick={hide}></View>
                     {/* Vip */}
-                    {type === 'vip' && <Vip isBook={isBook} />}
+                    {type === 'vip' && <Vip isBook={isBook} pay={pay} />}
                     {/* 书币 */}
-                    {type === 'shubi' && <Shubi isBook={isBook} shubiData={shubiData} />}
+                    {type === 'shubi' && <Shubi isBook={isBook} shubiData={shubiData} pay={pay} />}
                 </View>
             </View>}
         </>

+ 3 - 2
src/components/bottomModal/shubi/index.tsx

@@ -5,7 +5,8 @@ function Shubi(props: {
     isBook: boolean, shubiData?: {
         payCoin: number,
         coinNum: number
-    }
+    },
+    pay: (payData: any) => void//支付
 }) {
     return <View className="shubi">
         {
@@ -14,7 +15,7 @@ function Shubi(props: {
                 <View className="shubi_info">余额:{props?.shubiData?.coinNum || 0}书币</View>
             </> : <View className="shubi_title">选择套餐</View>
         }
-        <ShubiBox mar0={!props?.isBook} />
+        <ShubiBox mar0={!props?.isBook} pay={props.pay} />
     </View>
 }
 export default Shubi

+ 5 - 2
src/components/bottomModal/vip/index.tsx

@@ -1,7 +1,10 @@
 import { View, Text } from "@tarojs/components";
 import './index.less'
 import VipBox from "@src/components/pay/vip";
-function Vip(props: { isBook: boolean }) {
+function Vip(props: {
+    isBook: boolean,
+    pay: (payData: any) => void//支付
+}) {
     return <View>
         {
             props?.isBook ? <>
@@ -9,7 +12,7 @@ function Vip(props: { isBook: boolean }) {
             </> : <View className="shubi_title">选择套餐</View>
         }
 
-        <VipBox  mar0={!props?.isBook} />
+        <VipBox mar0={!props?.isBook} pay={props?.pay} />
     </View>
 }
 export default Vip

+ 7 - 5
src/components/pay/shubi/index.tsx

@@ -4,13 +4,12 @@ import { useMemo, useState } from "react";
 import { Store } from "@src/app";
 import { inject, observer } from "mobx-react";
 import { setApp } from "@src/config";
-import usePay from "@src/Hook/usePay";
 interface Props {
     store?: Store;
     mar0?: boolean
+    pay: (payData: any) => void//支付刷新小说内容
 }
 function ShubiBox(props?: Props) {
-    let { pay } = usePay()
     let [eq, setEq] = useState(0)
     let [payData, setPayData] = useState<any>(null)
     let [ok, setOk] = useState(false)
@@ -47,15 +46,18 @@ function ShubiBox(props?: Props) {
                 })
             }
         </View>
-        <View className="shubi_box_btn" onClick={() => { setOk(true); pay() }}>确认协议并支付{payData?.price}元</View>
-        <View className={`shubi_box_gz ${props?.mar0 ? "mar_bom_0" : ""}`}>
+        <View className="shubi_box_btn" onClick={() => {
+            setOk(true);
+            props?.pay({templateIndex:eq, rechargeTemplateId: props?.store?.indexStore?.rechargeTemplate?.find(item => item.templateType === 1)?.id })
+        }}>支付{payData?.price}元</View>
+        {/* <View className={`shubi_box_gz ${props?.mar0 ? "mar_bom_0" : ""}`}>
             <RadioGroup onChange={(e: any) => {
                 setOk(true)
             }}>
                 <Radio checked={ok} value='选中' >已阅读并同意《充值规则》</Radio>
             </RadioGroup>
 
-        </View>
+        </View> */}
     </>
 }
 export default inject('store')(observer(ShubiBox))

+ 8 - 5
src/components/pay/vip/index.tsx

@@ -1,7 +1,6 @@
 import { Radio, RadioGroup, ScrollView, View } from "@tarojs/components";
 import './index.less'
 import { useMemo, useState } from "react";
-import usePay from "@src/Hook/usePay";
 import { setApp } from "@src/config";
 import { Store } from "@src/app";
 import { inject, observer } from "mobx-react";
@@ -9,9 +8,9 @@ import { getEnum } from "@src/utils";
 interface Props {
     store?: Store;
     mar0?: boolean
+    pay: (payData: any) => void//支付刷新小说内容
 }
 function VipBox(props?: Props) {
-    let { pay } = usePay()
     let [eq, setEq] = useState(0)
     let [payData, setPayData] = useState<any>(null)
     let vipList = getEnum("VIP_DAYS")
@@ -25,6 +24,7 @@ function VipBox(props?: Props) {
         }
         return datas
     }, [props?.store?.indexStore?.rechargeTemplate])
+
     return <>
         <ScrollView
             className='vip_box'
@@ -57,15 +57,18 @@ function VipBox(props?: Props) {
                 })
             }
         </ScrollView>
-        <View className="vip_box_btn" onClick={() => { setOk(true); pay() }}>确认协议并支付{payData?.price}元</View>
-        <View className={`vip_box_gz ${props?.mar0 ? "mar_bom_0" : ""}`}>
+        <View className="vip_box_btn" onClick={() => {
+            setOk(true);
+            props?.pay({ templateIndex: eq, rechargeTemplateId: props?.store?.indexStore?.rechargeTemplate?.find(item => item.templateType === 2)?.id })
+        }}>支付{payData?.price}元</View>
+        {/* <View className={`vip_box_gz ${props?.mar0 ? "mar_bom_0" : ""}`}>
             <RadioGroup onChange={(e: any) => {
                 setOk(true)
             }}>
                 <Radio checked={ok} value='选中' >已阅读并同意《会员服务协议》</Radio>
             </RadioGroup>
 
-        </View>
+        </View> */}
     </>
 }
 export default inject('store')(observer(VipBox)) 

+ 88 - 16
src/pages/book/BookArticle/index.tsx

@@ -13,6 +13,7 @@ import { getReadLog, setReadLog } from '@src/utils/loginSto';
 import GlobalModal from '@src/components/bottomModal';
 import IosShowPay from '@src/components/pay/IosShowPay';
 import { Store } from '@src/app';
+import { cashBuy, virtualBuy } from '@src/server/wx/pay';
 
 interface Config {
     size: 'pre_15' | 'pre_17' | 'pre_19' | 'pre_21' | 'pre_23' | 'pre_25' | 'pre_27' | 'pre_29' | any;
@@ -160,13 +161,14 @@ const BookArticle: React.FC<BookArticleProps> = ({ store }) => {
         });
     }, [bookConfig.off_on]);
     // 下拉加载
-    const onLoad = async () => {
+    const onLoad = async (reload?: boolean) => {
+        console.log("下拉加载")
         if (openBookData?.contentData) {
             let { size, current, total, records } = openBookData.contentData
-            if (records.length < total) {
+            if (records.length < total || reload) {
                 console.log("加载")
                 setIsLoad(true)
-                await getBookContent({ pageNum: 1, pageSize: size + 2 }).then(res => {
+                await getBookContent({ pageNum: 1, pageSize: reload ? size : size + 1 }).then(res => {
                     setIsLoad(false)
                 })
             } else {
@@ -203,12 +205,58 @@ const BookArticle: React.FC<BookArticleProps> = ({ store }) => {
         setPayType(type)
         modalStore.showModal()
     }
+    // 全本购买
+    const allBuy = async (e) => {
+        e.stopPropagation();
+        let { paragraphInfo } = payBook
+        if (payBook) {
+            let params = {
+                bookId: paragraphInfo.bookId,
+                bookParagraphId: paragraphInfo.paragraphNo,
+                orderCondition: "阅读中"
+            }
+            let res = await cashBuy(params, onLoad)
+            if (res) {
+                console.log("全本购买:", res)
+                setTimeout(()=>{
+                    setShowPay(false)
+                    setShowVip(false)
+                    setPayBook(null)
+                },100)
+            }
+        
+        }
+    }
+    // 书币购买
+    const shubiBuy = async (e) => {
+        e.stopPropagation()
+        let { paragraphInfo } = payBook
+        if (payBook) {
+            let params = {
+                bookId: paragraphInfo.bookId,
+                bookParagraphId: paragraphInfo.paragraphNo,
+                orderCondition: "阅读中"
+            }
+            let res = await virtualBuy(params, onLoad)
+            if (res) {
+                console.log("书币购买章节:", res)
+                setTimeout(()=>{
+                    setShowPay(false)
+                    setShowVip(false)
+                    setPayBook(null)
+                    modalStore.hideModal()
+                },100)
+            }
+           
+        }
+
+    }
     const { size, bg, off_on, lh } = bookConfig;
     return (
         <ScrollView
             lowerThreshold={indexStore.navHeight}
             // refresherTriggered={isLoad}//加载状态
-            onScrollToLower={onLoad}
+            onScrollToLower={() => { onLoad() }}
             style={{ height: `calc(100vh - ${indexStore.navHeight}px)` }}
             scrollY={true}
             refresherDefaultStyle='black'
@@ -241,16 +289,22 @@ const BookArticle: React.FC<BookArticleProps> = ({ store }) => {
                     {
                         openBookData?.contentData?.records?.map(item => {
                             let needPay = item.needPay //是否付费解锁
+                            let isPay = item.isPay //是否已付费
                             let showText = true //是否显示内容
                             let arr = item.paragraphInfo.content?.match(/[^\n]*\n?/g);
                             // 是否需要付费
-                            if (needPay) {
+                            if (!showPay && needPay && !isPay) {
+                                console.log("是否需要付费====>",item,)
                                 showText = false
-                                if (!showPay) {
-                                    setShowPay(true)
-                                    setShowVip(item.vipFree)
-                                    setPayBook(item)
-                                }
+                                setShowPay(true)
+                                setShowVip(item.vipFree)
+                                setPayBook(item)
+                            }else{
+                                // if (showPay) {
+                                //     setShowPay(false)
+                                //     setShowVip(false)
+                                //     setPayBook(null)
+                                // } 
                             }
                             return showText ? <View
                                 id={'paragraphNo-' + item.paragraphInfo.paragraphNo}
@@ -275,9 +329,18 @@ const BookArticle: React.FC<BookArticleProps> = ({ store }) => {
                             {/* 存在vip免费字段展示购买vip */}
                             {showVip && <View className='vip_btn' onClick={(e) => { payBtn(e, "vip") }}>开通会员,本书免费读</View>}
                             {/* 存在章节书币价格显示购买书币 */}
-                            {payBook?.payCoin && <View className='shubi_btn' onClick={(e) => { payBtn(e, "shubi") }}>购买本章</View>}
+                            {payBook?.payCoin && <View className='shubi_btn' onClick={(e) => {
+                                // 余额
+                                let coinNum = userInfoStore?.userInfo?.coinNum || 0
+                                // 余额大于等于所需书币
+                                if (coinNum >= payBook?.payCoin) {
+                                    shubiBuy(e)
+                                } else {
+                                    payBtn(e, "shubi")
+                                }
+                            }}>购买本章 {payBook?.payCoin}书币</View>}
                             {/* 存在全本购买价格展示全本购买按钮*/}
-                            {payBook?.payAmount && <View className='shubi_btn' onClick={(e) => { e.stopPropagation() }}>支付{payBook?.payAmount}元购买本书</View>}
+                            {payBook?.payAmount && <View className='shubi_btn' onClick={(e) => { allBuy(e) }}>支付{payBook?.payAmount}元购买本书</View>}
                         </IosShowPay>
                     </View>}
 
@@ -285,10 +348,19 @@ const BookArticle: React.FC<BookArticleProps> = ({ store }) => {
                 {/* 设置弹窗 */}
                 {pup && <BookConfigPuP {...bookConfig} off_on={off_on} setOff={setOff} setSize={setSize} setBg={setBg} setLh={setLh} />}
                 {/* 支付弹窗 */}
-                <GlobalModal type={payType} shubiData={{
-                    coinNum: userInfoStore?.userInfo?.coinNum || 0,
-                    payCoin: payBook?.payCoin || 0,
-                }} />
+                <GlobalModal
+                    type={payType}
+                    callBackFn={onLoad}
+                    shubiData={{
+                        coinNum: userInfoStore?.userInfo?.coinNum || 0,
+                        payCoin: payBook?.payCoin || 0,
+                    }}
+                    payBookInfo={{
+                        bookId: payBook?.paragraphInfo?.bookId,
+                        bookParagraphId: payBook?.paragraphInfo?.paragraphNo,
+                        orderCondition: "阅读中"
+                    }}
+                />
             </View>
             {/* 底部下来加载 */}
             {/* {

+ 1 - 1
src/pages/my/index.tsx

@@ -25,7 +25,7 @@ function My(props: Props) {
     useDidHide(() => {
         ModalStore.hideModal()
     });
-    console.log(userInfoStore)
+    console.log("个人信息:",userInfoStore)
     return <View className='my'>
         <View className="userInfo">
             {/* <Image src={require('../../icon/myBack.png')} /> */}

+ 18 - 0
src/server/wx/login.ts

@@ -56,4 +56,22 @@ export function wxlogin() {
     log("已登录")
     return Promise.resolve({token:app.token,userInfo:app?.userInfo})
   }
+}
+
+/***
+ * 获取个人信息
+ * */
+export function getUserInfo(){
+  new Promise((res,rej)=>{
+    Taro.request({
+      url:"",
+      method:"GET",
+      success:(res)=>{
+        
+      },
+      fail:(err)=>{
+
+      }
+    })
+  })
 }

+ 125 - 0
src/server/wx/pay.ts

@@ -0,0 +1,125 @@
+import Taro from "@tarojs/taro";
+type PublicData = {
+    bookId: number,//小说ID
+    bookParagraphId: number,//章节ID
+    orderCondition: string,//支付场景
+}
+/**现金购买-预下单*/
+export function cashBuy(data: PublicData, callbackFn?: (b:boolean) => void) {
+    return new Promise(async (resolve, reject) => {
+        try {
+            // 初始化
+            Taro.request({
+                url: '/app/pay/buyout',
+                method: 'POST',
+                data,
+                success: async (res) => {
+                    let r = await whcatPay(res.data?.data?.wechatMchPayInfo)
+                    console.log("支付操作完成!!", r)
+                    callbackFn?.(true)
+                    resolve(r)
+                },
+                fail: (err) => {
+                    reject(err);
+                }
+            })
+        } catch (error) {
+            reject(error);
+        }
+    })
+}
+/**书币购买*/
+export function virtualBuy(data: PublicData, callbackFn?: (b:boolean) => void) {
+    return new Promise(async (resolve, reject) => {
+        try {
+            // 初始化
+            Taro.request({
+                url: '/app/pay/buyOfCoin',
+                method: 'POST',
+                data,
+                success: async (res) => {
+                    callbackFn?.(true)
+                    resolve(res)
+                },
+                fail: (err) => {
+                    reject(err);
+                }
+            })
+        } catch (error) {
+            reject(error);
+        }
+    })
+}
+interface Data extends PublicData {
+    rechargeTemplateId: number,//支付模板ID
+    templateIndex: number,//下标
+}
+/**模板购买-预下单*/
+export function templateBuy(data: Data, callbackFn?: (b:boolean) => void) {
+    return new Promise(async (resolve, reject) => {
+        try {
+            // 初始化
+            Taro.request({
+                url: '/app/pay/buyOfTemplate',
+                method: 'POST',
+                data,
+                success:async (res) => {
+                    let r = await whcatPay(res.data?.data?.wechatMchPayInfo)
+                    console.log("支付操作完成!!", r)
+                    callbackFn?.(true)
+                    resolve(r)
+                },
+                fail: (err) => {
+                    reject(err);
+                }
+            })
+        } catch (error) {
+            reject(error);
+        }
+    })
+}
+
+/**微信支付*/
+type WhcatPay = {
+    timeStamp: string,//时间戳,从 1970 年 1 月 1 日 00:00:00 至今的秒数,即当前的时间
+    nonceStr: string,//随机字符串,长度为32个字符以下
+    package: string,//统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=***
+    signType: any,//签名算法
+    paySign: string,//签名
+}
+export function whcatPay(params: WhcatPay) {
+    console.log("微信支付:", params)
+    return new Promise(async (resolve, reject) => {
+        try {
+            // 初始化
+            Taro.requestPayment({
+                ...params,
+                success: (res) => {
+                    console.log("支付成功:", res)
+                    Taro.showToast({
+                        title: '支付成功!',
+                        icon: 'success'
+                    });
+                    resolve(true)
+                },
+                fail: (err) => {
+                    console.log("支付失败:", err)
+                    if (err.errMsg === 'requestPayment:fail cancel') {
+                        Taro.showToast({
+                            title: '支付已取消!',
+                            icon: 'error'
+                        });
+                    } else {
+                        Taro.showToast({
+                            title: '支付失败,请重试!',
+                            icon: 'error'
+                        });
+                    }
+                    resolve(false)
+                }
+            })
+        } catch (error) {
+            reject(error);
+        }
+    })
+}

+ 0 - 1
src/utils/index.tsx

@@ -1,5 +1,4 @@
 export const getEnum = (enumName: string) => {
-    console.log("app?.enumDictList",app?.enumDictList,enumName)
     let arr = app?.enumDictList?.[enumName]?.values
     return arr?.map(({ value, description }: any) => ({ value, key: value, text: description }))
 }

+ 0 - 5
src/utils/pay.ts

@@ -1,5 +0,0 @@
-
-export function isPay(data:any):boolean{
-    //判断
-    return true
-}