shenwu 7 mesiacov pred
rodič
commit
9bd2674b08

+ 6 - 1
project.config.json

@@ -11,5 +11,10 @@
     "postcss": false,
     "minified": false
   },
-  "compileType": "miniprogram"
+  "compileType": "miniprogram",
+  "permission": {
+    "scope.userInfo": {
+      "desc": "你的信息将用于展示个人信息"
+    }
+  }
 }

+ 5 - 1
src/Hook/useApi.ts

@@ -1,4 +1,4 @@
-import { getParagraphList, getShortBookInfo, getShortBookInfoAppListOfPage } from '@src/server/book/short'
+import { getParagraphList, getShortBookInfo, getShortBookInfoAppListOfPage, readingShort, startReadShort } from '@src/server/book/short'
 import { getShortBanners, getShortHotCategory, getShortHotBooks } from '@src/server/index/index'
 /**用于长短篇小说区别,使用不同的接口*/
 function useApi(store) {
@@ -11,6 +11,10 @@ function useApi(store) {
         getBookContent: isLong ? getParagraphList : getParagraphList,
         /**获取小说详情用于分享进入*/
         getBookInfo: isLong ? getShortBookInfo : getShortBookInfo,
+        /**小说阅读上报*/ 
+        startReadBook: isLong ? startReadShort : startReadShort,
+        /**小说阅读心跳上报*/ 
+        readingBook: isLong ? readingShort : readingShort,
         /**首页组件接口*/
         indexComponents: {
             "banners": isLong ? getShortBanners : getShortBanners,

+ 6 - 6
src/app.config.ts

@@ -8,9 +8,9 @@ export default {
     'pages/book/bookDetails/index',//书籍详情
     // 'pages/task/index',//福利中心
     'pages/vipCore/index',//会员中心
-    // 'pages/contactus/index',//联系客服
     // 'pages/bookCatalog/index',//书籍目录
-    // 'pages/aboutWe/index',//关于我们
+    'pages/my/aboutUs/index',//关于我们
+    'pages/my/contactService/index',//联系客服
     'pages/book/bookArticle/index',//书籍内容 阅读页
     // 'pages/search/index',//搜索
     // 'pages/indexMore/index', // 更多
@@ -49,10 +49,10 @@ export default {
         selectedIconPath: './icon/fl_2.png',//选中的图片变化
       },
       {
-        text:'我的',//名称
-        pagePath:'pages/my/index',//路径
-        iconPath:'./icon/wd_1.png',//图片
-        selectedIconPath:'./icon/wd_2.png',//选中的图片变化
+        text: '我的',//名称
+        pagePath: 'pages/my/index',//路径
+        iconPath: './icon/wd_1.png',//图片
+        selectedIconPath: './icon/wd_2.png',//选中的图片变化
       },
     ]
   },

+ 3 - 3
src/app.tsx

@@ -3,7 +3,7 @@ import { Provider, ProviderProps } from 'mobx-react'
 import Taro from '@tarojs/taro'
 import './app.less'
 // ======store======
-import userInfo from './store/userInfo'
+import userInfoStore, { UserInfoStore } from './store/userInfo'
 import indexStore, { IndexStore } from './store/index'
 import Book, { BookStore } from './store/book'
 import appInfoStore, { AppInfoStore } from './store/appInfo'
@@ -18,13 +18,13 @@ import api from './server/index'
 
 export interface Store {
   appInfoStore: AppInfoStore
-  userInfo: any,
+  userInfoStore: UserInfoStore,
   indexStore: IndexStore,
   bookStore: BookStore,
   classifyStore: ClassifyStore,
 }
 const store: Store = {
-  userInfo,
+  userInfoStore,
   indexStore,
   appInfoStore,
   bookStore: Book,

+ 5 - 0
src/components/ScrollView/index.tsx

@@ -1,6 +1,7 @@
 import { ScrollView } from "@tarojs/components"
 import { Component } from "react"
 import { UpLoading } from "@src/components/PupPetry/Loading"
+import Taro from "@tarojs/taro"
 interface State {
     isShow: boolean  //是否开启刷新状态
     loadNum: number, //加载次数
@@ -12,6 +13,7 @@ interface Props {
     children: any,
     refresh?: () => Promise<any>,//刷新
     load?: () => Promise<any>,//加载
+    callback?:(num:any)=>void,//返回滚动距离
 }
 /**页面上下加载*/
 class ScrollViewHoc extends Component<Props> {
@@ -78,6 +80,9 @@ class ScrollViewHoc extends Component<Props> {
             // refresherEnabled={true}
             refresherTriggered={this.state.isShow}
             onScrollToLower={this.onScrollToLower}
+            onScroll={(evt)=>{
+                this.props.callback?.(evt.detail.scrollTop)
+            }}
             className='scrollview'
             scrollY={true}
             onRefresherRefresh={() => { this.onScrollToUpper() }}

+ 1 - 1
src/interceptor.ts

@@ -71,7 +71,7 @@ const responseInterceptor = (chain) => {
                     // appInfoStore.actionAppInfo(data.data.appInfo)
                     let res: any = await api.getAppComponent()
                     let user:any = await api.login()
-                    console.log(user)
+                    setApp({appName:data?.data?.appInfo?.appName})
                     appInfoStore.setData({ appInfo: data.data.appInfo, appComponent: res.data.data,token:user.token})
                 }
                 break;

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

@@ -1,15 +1,14 @@
 
 
 import React, { useState, useEffect, useRef } from 'react';
-import { View, Text, ScrollView, Button } from '@tarojs/components';
+import { View, Text, ScrollView } from '@tarojs/components';
 import { observer, inject } from 'mobx-react';
 import './index.less';
 import TopNavBar from '@src/components/TopNavBar/index';
-import Taro, { useDidHide } from '@tarojs/taro';
+import Taro from '@tarojs/taro';
 import BookConfigPuP from '@src/components/bookConfigPup';
 import { BookStore } from '@src/store/book';
 import useApi from '@src/Hook/useApi';
-import { UpLoading } from '@src/components/PupPetry/Loading';
 import { getReadLog, setReadLog } from '@src/utils/loginSto';
 
 interface Config {
@@ -35,9 +34,10 @@ const BookArticle: React.FC<BookArticleProps> = ({ store }) => {
     const { openBookData } = bookStore
     const [bookConfig, setBookConfig] = useState<Config>({ size: 'pre_21', off_on: true, bg: 'bg_b', lh: 'lh_72' });
     const [pup, setPup] = useState(false);
-    const { getBookContent } = useApi(appInfoStore)
+    const { getBookContent,readingBook } = useApi(appInfoStore)
     const [currentScrollId, setCurrentScrollId] = useState('');
     const newReadLogIdRef = useRef("");
+    const readLogInterval = useRef<NodeJS.Timeout>()
     // 页面显示的操作请求
     useEffect(() => {
         // ComponentDidMount
@@ -64,15 +64,25 @@ const BookArticle: React.FC<BookArticleProps> = ({ store }) => {
     }, []);
     // 页面卸载的操作
     useEffect(() => {
+        reportRead()
         return () => {
             console.log("卸载", newReadLogIdRef.current);
-            reportRead(); // 上报
+            openBookData && setReadLog({ [openBookData.bookId]: newReadLogIdRef.current })//离开时存放当前位置
+            clearInterval(readLogInterval.current)//清除上报心跳
         };
     }, [])
     // 这里可以填写上报逻辑
     const reportRead = () => {
         console.log("上报", newReadLogIdRef.current)
         openBookData && setReadLog({ [openBookData.bookId]: newReadLogIdRef.current })
+        if(readLogInterval.current){
+            clearInterval(readLogInterval.current)
+        }
+        // 定时上报心跳
+        readLogInterval.current = setInterval(() => {
+            readingBook(bookStore.readId)
+            console.log("上报阅读心跳",newReadLogIdRef.current,bookStore.readId)
+        }, 3000);
     };
     //设置配置
     const setConfig = (data: Config) => {
@@ -171,6 +181,7 @@ const BookArticle: React.FC<BookArticleProps> = ({ store }) => {
             }
         });
     };
+
     const { size, bg, off_on, lh } = bookConfig;
     return (
         <ScrollView

+ 14 - 6
src/pages/book/bookDetails/index.tsx

@@ -28,19 +28,27 @@ class BookDetails extends Component<Props> {
     componentDidShow(options) {
         Taro.showShareMenu({
             showShareItems: ["shareAppMessage"],
-            success: (res) => { console.log("成功") },
-            fail: (err) => { console.log("err") }
+            success: (res) => { log("成功") },
+            fail: (err) => { log("err") }
         });
         let params = Taro.getCurrentInstance()?.router?.params
         let { bookStore, appInfoStore } = this.props.store
         // 获取书籍详情
         if (params?.bookId && !bookStore.openBookData) {
             let { getBookInfo } = useApi(appInfoStore)
-            console.log("分享进入")
+            log("分享进入")
             getBookInfo(params.bookId)
-            console.log(params?.bookId)
+            log(params?.bookId)
         }
     }
+    // 上报阅读
+    onReport() {
+        let { indexStore, appInfoStore, bookStore } = this.props.store
+        let scene = indexStore.scene
+        let { startReadBook } = useApi(appInfoStore)
+        log("onReport", scene)
+        startReadBook({ bookId: bookStore.openBookData?.bookId, readCondition: scene })
+    }
     render() {
         let { bookStore } = this.props.store
         let { openBookData } = bookStore
@@ -76,10 +84,10 @@ class BookDetails extends Component<Props> {
 
                         <BookHead title="简介" ></BookHead>
                         <View className='center'>
-                            <Text>{openBookData?.bookDesc.replace(/\s/ig, '')}</Text>
+                            <Text>{openBookData?.bookDesc?.replace(/\s/ig, '')}</Text>
                         </View>
                     </View>
-                    <View className='btn'>
+                    <View className='btn' onClick={this.onReport.bind(this)}>
                         <Navigator url={`/pages/book/bookArticle/index?bookId=${openBookData?.bookId}`} hoverClass="none">
                             <Image src={require('../../../icon/btn.png')} className='img' />
                         </Navigator>

+ 13 - 4
src/pages/classify/index.tsx

@@ -20,9 +20,9 @@ interface Props {
 
 const Index = forwardRef((props: Props) => {
     const { bookStore, appInfoStore, classifyStore } = props.store
-    console.log("appInfoStore", appInfoStore.appInfo)
     const { getBookPageList } = useApi(appInfoStore)
     const [pageShow, setPageShow] = useState(false)//防止小程序切换页面组件不会被真实卸载,阻止不必要的操作
+    const [isFixed, setIsFixed] = useState(false)
     // 获取分类列表
     useEffect(() => {
         if (pageShow) {
@@ -80,14 +80,23 @@ const Index = forwardRef((props: Props) => {
         return getBookPageList(params)
     }
     return (
-        <ScrollViewHoc load={load} refresh={refresh}>
+        <ScrollViewHoc load={load} refresh={refresh} callback={(num) => {
+            // if(num > 100 && !isFixed){
+            //     setIsFixed(true)
+            // }
+            // if(num <100 && isFixed){
+            //     setIsFixed(false)
+            // }
+        }}>
             <View className='index'>
-                {bookStore?.classifyData?.length > 0 && <BookTypeTabs typeValue={bookStore?.classifyData} typeTabIndex={classifyStore.categoryId} workDirection={bookStore.workDirection}></BookTypeTabs>}
+                {bookStore?.classifyData?.length > 0 && <View style={isFixed ? { position: 'fixed', background: "#fff" } : {background: "#fff"}}>
+                    <BookTypeTabs typeValue={bookStore?.classifyData} typeTabIndex={classifyStore.categoryId} workDirection={bookStore.workDirection} ></BookTypeTabs>
+                </View>}
                 <View className='w  row for_top1 pd_btm'>
                     {
                         bookStore?.bookList?.records?.length > 0 ? bookStore?.bookList?.records?.map((item, index) => {
                             return <>
-                                <View key={index} ><BookboxRowBig {...item} /></View>
+                                <View key={item.bookId} ><BookboxRowBig {...item} /></View>
                             </>
                         }) :
                             <Empty />

+ 3 - 0
src/pages/my/aboutUs/index.config.ts

@@ -0,0 +1,3 @@
+export default {
+    navigationBarTitleText: '关于我们'
+}

+ 39 - 0
src/pages/my/aboutUs/index.less

@@ -0,0 +1,39 @@
+@import '../../../globaStyle.less';
+page{
+    background: #F4F5F6;
+}
+
+.aboutWe{
+    width: 100%;
+    .content{
+        margin-top: 312px;
+        display: flex;
+        align-items: center;
+        flex-direction: column;
+    }
+
+    .logo{
+        width: 152px;
+        border-radius: 15px;
+    }
+
+    .logoName{
+        font-size: 52px;
+        font-family: PingFangSC-Regular, PingFang SC;
+        font-weight: 400;
+        color: @cl_333;
+        margin-top: 24px;
+        margin-bottom: 98px;
+    }
+
+    .explain{
+        font-size: 28px;
+        font-family: PingFangSC-Regular, PingFang SC;
+        font-weight: 400;
+        color: #333333;
+
+        &:last-child{
+            margin-top: 34px;
+        }
+    }
+}

+ 52 - 0
src/pages/my/aboutUs/index.tsx

@@ -0,0 +1,52 @@
+import { Component } from 'react'
+import { View, Text, Image } from '@tarojs/components'
+import { observer, inject } from 'mobx-react'
+import './index.less'
+import Taro from '@tarojs/taro'
+type PageStateProps = {
+    store: {
+        indexStore: {
+            navBarTop: number,
+            SET_NAVBARMARGINTOP: Function,
+            openType: number
+        }
+    }
+}
+interface AboutWe {
+    props: PageStateProps;
+}
+
+
+
+@inject('store')
+@observer
+class AboutWe extends Component {
+    
+    componentWillMount() { }
+    componentDidMount() { }
+    componentWillUnmount() { }
+    componentDidShow() { }
+    componentDidHide() { }
+
+    render() {
+        let { indexStore } = this.props.store
+        return (
+            <View className='aboutWe'>
+                <View className="content">
+                    <Image src={""}  mode="widthFix" className="logo" style={{width: Taro.pxTransform(152)}}/>
+                    <Text className="logoName">{app.appName}</Text>
+                    {
+                        indexStore.openType === 1 ? <Text className="explain">致力于为用户提供精品阅读内容,精彩呈现</Text> :
+                        <>
+                            <Text className="explain">{app.appName}是一个全正版的免费阅读平台</Text>
+                            <Text className="explain">致力于为用户提供更丰富更优质的免费阅读内</Text>
+                        </>
+                    }
+                    
+                </View>
+            </View>
+        )
+    }
+}
+
+export default AboutWe

+ 3 - 0
src/pages/my/contactService/index.config.ts

@@ -0,0 +1,3 @@
+export default {
+    navigationBarTitleText: '联系客服'
+}

+ 0 - 0
src/pages/my/contactService/index.less


+ 44 - 0
src/pages/my/contactService/index.tsx

@@ -0,0 +1,44 @@
+import { Component } from 'react'
+import { View, Text, Image } from '@tarojs/components'
+import { observer, inject } from 'mobx-react'
+import './index.less'
+import Taro from '@tarojs/taro'
+type PageStateProps = {
+    store: {
+        indexStore: {
+            navBarTop: number,
+            SET_NAVBARMARGINTOP: Function,
+            openType: number
+        }
+    }
+}
+interface AboutWe {
+    props: PageStateProps;
+}
+
+
+
+@inject('store')
+@observer
+class AboutWe extends Component {
+    
+    componentWillMount() { }
+    componentDidMount() { }
+    componentWillUnmount() { }
+    componentDidShow() { }
+    componentDidHide() { }
+
+    render() {
+        let { indexStore } = this.props.store
+        return (
+            <View className='aboutWe'>
+                <View className="content">
+                    <Image src={""}  mode="widthFix" className="logo" style={{width: Taro.pxTransform(152)}}/>
+                    此处为二维码或者跳转至客服聊天功能
+                </View>
+            </View>
+        )
+    }
+}
+
+export default AboutWe

+ 426 - 362
src/pages/my/index.less

@@ -1,365 +1,429 @@
-
 @import '../../globaStyle.less';
-page{
-	background-color: #f6f6f6;
+
+page {
+    background-color: #f6f6f6;
 }
-.my{
-	.userInfo{
-		position: relative;
-		// height: 240px;
-		.userInfo_box{
-			position: absolute;
-			top: 0;
-			left: 0;
-			right: 0;
-			height: 240px;
-			display: flex;
-			flex-direction: column;
-			justify-content: space-between;
-			padding: 0 30px;
-			box-sizing: border-box;
-			.top {
-				margin-top: 26px;
-				display: flex;
-				justify-content: space-between;
-				align-items: center;
-				.left{
-					display: flex;
-					justify-content: flex-start;
-					align-items: center;
-					flex: 1;
-					.avtai{
-						width: 130px;
-						height: 130px;
-						background: @bg_EC;
-						border-radius: 50%;
-						margin-right: 28px;
-						image{
-							width: 130px;
-							border-radius: 50%;
-						}
-					}
-					.name{
-						display: flex;
-						justify-content: flex-start;
-						align-items: center;
-						flex-wrap: wrap;
-						flex: 1;
-						.ID{
-							font-size: 32px;
-							font-family: PingFangSC-Medium, PingFang SC;
-							font-weight: 500;
-							color: @cl_666;
-							overflow: hidden;
-							text-overflow: ellipsis;
-							white-space: nowrap;
-							margin-right: 8px;
-						}
-	
-						.grade{
-							height: 36px;
-							width: 90px;
-							display: flex;
-							align-items: center;
-							justify-content: center;
-							background-color: #EAC26E;
-							border-radius: 18px;
-							&>image{
-								width: 26px;
-								height: 22px;
-							}
-							&>text{
-								font-size: 24px;
-								font-family: PingFangSC-Regular, PingFang SC;
-								font-weight: 400;
-								color: #FFFFFF;
-								margin-left: 6px;
-							}
-						}
-					}
-					
-				}
-				.right {
-					width: 318px;
-					.loginBt{
-						margin: 0;
-						padding: 0;
-						background-color: rgba(255, 255, 255, 0);
-						border-radius:0;
-						height: 72px;
-						
-						&::after{
-							border: 0;
-						}
-						image{
-							width: 318px;
-							height: 72px;
-						}
-					}
-				}
-			}
-			.bottom {
-				width: 100%;
-				height: 156px;
-				margin-top: 20px;
-				position: relative;
-				&>view{
-					width: 100%;
-					height: 100%;
-					position: absolute;
-					top: 0;
-					left: 0;
-					right: 0;
-					bottom: 0;
-					display: flex;
-					justify-content: space-between;
-					padding: 0 28px;
-					box-sizing: border-box;
-					align-items: center;
-					.left{
-						display: flex;
-						align-items: center;
-						&>image{
-							width: 70px;
-							height: 60px;
-							margin-right: 20px;
-						}
-						&>.txt{
-							display: flex;
-							flex-direction: column;
-							text{
-								font-size: 32px;
-								font-family: PingFangSC-Regular, PingFang SC;
-								font-weight: 400;
-								color: #723700;
-							}
-							.tfv{
-								margin-top: 8px;
-								font-size: 24px;
-								color: #C3871A;
-							}
-						}
-						
-					}
-					.right{
-						width: 164px;
-						height: 58px;
-						text-align: center;
-						line-height: 58px;
-						font-size: 28px;
-						font-family: PingFangSC-Regular, PingFang SC;
-						font-weight: 400;
-						color: #C3871A;
-						background: #FFFAE8;
-						border-radius: 28px;
-					}
-				}
-				image{
-					width: 100%;
-					height: 132px;
-				}
-			}
-		}
-		&>image{
-			width: 100%;
-			max-height: 372px;
-		}
-	}
-	.list_bt{
-		background-color: #FFFFFF;
-		margin-top: 20px;
-		border-radius: 20px;
-		padding: 36px 30px;
-		box-sizing: border-box;
-		.line{
-			height: 2px;
-			background: #E9E9E9;
-		}
-		.item {
-			width: 100%;
-			
-			display: flex;
-			justify-content: space-between;
-			align-items: center;
-			&:last-child{
-				margin-top: 34px;
-			}
-			&:first-child{
-				margin-bottom: 34px;
-			}
-			&>view{
-				display: flex;
-				align-items: center;
-			}
-			.left{
-				image{
-					width: 36px;
-					margin-right: 16px;
-				}
-				text {
-					font-size: 32px;
-					font-family: PingFangSC-Regular, PingFang SC;
-					font-weight: 400;
-					color: @cl_333;
-				}
-			}
-			.right image{
-				width: 28px;
-				height: 28px;
-			}
-		}
-	}
-
-	.signIn{
-		height: 384px;
-		background-color: #FFFFFF;
-		border-radius: 20px;
-		margin: 100px 30px 0;
-		padding: 30px 28px;
-		box-sizing: border-box;
-		.header{
-			display: flex;
-			justify-content: space-between;
-			align-items: center;
-			margin-bottom: 20px;
-			.left{
-				font-weight: 600;
-				color: #333333;
-				font-size: 32px;
-			}
-			.right{
-				font-weight: 500;
-				color: #666666;
-				font-size: 24px;
-			}
-		}
-		.ins{
-			display: flex;
-			justify-content: space-between;
-			margin-bottom: 20px;
-			&>view{
-				&>.top{
-					border-radius: 10px;
-					width: 80px;
-					background-color: #f7f7f7;
-					height: 110px;
-					margin-bottom: 10px;
-					padding: 12px 10px;
-					box-sizing: border-box;
-					display: flex;
-					flex-direction: column;
-					justify-content: space-between;
-					align-items: center;
-					&>image{
-						width: 60px;
-						height: 60px;
-					}
-					&>text{
-						font-size: 24px;
-						font-weight: 500;
-						color: #999999;
-						text-align: center;
-					}
-				}
-				&>.bottom{
-					font-size: 24px;
-					font-weight: 400;
-					color: #999999;
-					text-align: center;
-				}
-
-				&.needSign{
-					&>.top{
-						background-color: #FFF3C9;
-						&>text{
-							color: #FF9A08;
-						}
-					}
-					&>.bottom{
-						color: #FFBF1C;
-					}
-				}
-			}
-		}
-		.signBt{
-			width: 428px;
-			height: 85px;
-			text-align: center;
-			line-height: 85px;
-			background-image: linear-gradient( #FF6178, #FF3154 );
-			border-radius: 50px;
-			color: #FFFFFF;
-			margin: 0 auto;
-			font-size: 32px;
-			font-weight: 600;
-			letter-spacing: 3px;
-		}
-		.signBtSucc{
-			background: #D2D2D2;
-		}
-	}
-	.crous{
-		height: 448px;
-		margin-top: 30px;
-		margin-bottom: 30px;
-		.header>.right{
-			display: flex;
-			align-items: center;
-			&>image{
-				width: 28px;
-				height: 28px;
-			}
-		}
-		.task{
-			margin: 24px 8px;
-			&>View{
-				height: 80px;
-				display: flex;
-				justify-content: space-between;
-				align-items: center;
-				margin-bottom: 36px;
-				.left{
-					display: flex;
-					justify-content: flex-start;
-					align-items: center;
-					.title{
-						color: #333333;
-						font-weight: 400;
-						font-size: 28px;
-						margin-left: 18px;
-						margin-right: 20px;
-					}
-					&>image{
-						width: 44px;
-						height: 52px;
-					}
-					.reward{
-						font-weight: 400;
-						color: #FF9302;
-						font-size: 28px;
-					}
-					.bean{
-						width: 40px;
-						height: 40px;
-					}
-				}
-				.right{
-					width: 160px;
-					height: 60px;
-					border-radius: 40px;
-					color: #FFFFFF;
-					text-align: center;
-					line-height: 60px;
-					background-color: #FF415B;
-					font-weight: 500;
-					font-size: 24px;
-				}
-				.rightSucc{
-					background-color: #FFFFFF;
-					border: 2px solid #FF415B;
-					color: #FF415B;
-				}
-			}
-		}
-	}
+
+.my {
+    .userInfo {
+        position: relative;
+        width: 100vw;
+        height: 100vh;
+        background: url("@src/icon/myBack.png");
+        background-size: 100%;
+        /* 设置背景图像为 100% 大小 */
+        background-repeat: no-repeat;
+        /* 禁止平铺 */
+        background-position: 0 -13%;
+        /* 设置背景图像的起始位置为 (0, 0) */
+
+        .userInfo_box {
+            position: absolute;
+            top: 0;
+            left: 0;
+            right: 0;
+            height: 240px;
+            display: flex;
+            flex-direction: column;
+            justify-content: space-between;
+            padding: 0 30px;
+            box-sizing: border-box;
+
+            .top {
+                margin-top: 26px;
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+
+                .left {
+                    display: flex;
+                    justify-content: flex-start;
+                    align-items: center;
+                    flex: 1;
+
+                    .avtai {
+                        width: 130px;
+                        height: 130px;
+                        background: @bg_EC;
+                        border-radius: 50%;
+                        margin-right: 28px;
+
+                        image {
+                            width: 130px;
+                            border-radius: 50%;
+                        }
+                    }
+
+                    .name {
+                        display: flex;
+                        justify-content: flex-start;
+                        align-items: center;
+                        flex-wrap: wrap;
+                        flex: 1;
+
+                        .ID {
+                            font-size: 32px;
+                            font-family: PingFangSC-Medium, PingFang SC;
+                            font-weight: 500;
+                            color: @cl_666;
+                            overflow: hidden;
+                            text-overflow: ellipsis;
+                            white-space: nowrap;
+                            margin-right: 8px;
+                        }
+
+                        .grade {
+                            height: 36px;
+                            width: 90px;
+                            display: flex;
+                            align-items: center;
+                            justify-content: center;
+                            background-color: #EAC26E;
+                            border-radius: 18px;
+
+                            &>image {
+                                width: 26px;
+                                height: 22px;
+                            }
+
+                            &>text {
+                                font-size: 24px;
+                                font-family: PingFangSC-Regular, PingFang SC;
+                                font-weight: 400;
+                                color: #FFFFFF;
+                                margin-left: 6px;
+                            }
+                        }
+                    }
+
+                }
+
+                .right {
+                    width: 318px;
+
+                    .loginBt {
+                        margin: 0;
+                        padding: 0;
+                        background-color: rgba(255, 255, 255, 0);
+                        border-radius: 0;
+                        height: 72px;
+
+                        &::after {
+                            border: 0;
+                        }
+
+                        image {
+                            width: 318px;
+                            height: 72px;
+                        }
+                    }
+                }
+            }
+
+            .bottom {
+                width: 100%;
+                height: 156px;
+                margin-top: 20px;
+                position: relative;
+
+                &>view {
+                    width: 100%;
+                    height: 100%;
+                    position: absolute;
+                    top: 0;
+                    left: 0;
+                    right: 0;
+                    bottom: 0;
+                    display: flex;
+                    justify-content: space-between;
+                    padding: 0 28px;
+                    box-sizing: border-box;
+                    align-items: center;
+
+                    .left {
+                        display: flex;
+                        align-items: center;
+
+                        &>image {
+                            width: 70px;
+                            height: 60px;
+                            margin-right: 20px;
+                        }
+
+                        &>.txt {
+                            display: flex;
+                            flex-direction: column;
+
+                            text {
+                                font-size: 32px;
+                                font-family: PingFangSC-Regular, PingFang SC;
+                                font-weight: 400;
+                                color: #723700;
+                            }
+
+                            .tfv {
+                                margin-top: 8px;
+                                font-size: 24px;
+                                color: #C3871A;
+                            }
+                        }
+
+                    }
+
+                    .right {
+                        width: 164px;
+                        height: 58px;
+                        text-align: center;
+                        line-height: 58px;
+                        font-size: 28px;
+                        font-family: PingFangSC-Regular, PingFang SC;
+                        font-weight: 400;
+                        color: #C3871A;
+                        background: #FFFAE8;
+                        border-radius: 28px;
+                    }
+                }
+
+                image {
+                    width: 100%;
+                    height: 132px;
+                }
+            }
+        }
+
+        &>image {
+            width: 100%;
+            max-height: 372px;
+        }
+    }
+
+    .list_bt {
+        background-color: #FFFFFF;
+        margin-top: 20px;
+        border-radius: 20px;
+        padding: 36px 30px;
+        box-sizing: border-box;
+
+        .line {
+            height: 2px;
+            background: #E9E9E9;
+        }
+
+        .item {
+            width: 100%;
+
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+
+            &:last-child {
+                margin-top: 34px;
+            }
+
+            &:first-child {
+                margin-bottom: 34px;
+            }
+
+            &>view {
+                display: flex;
+                align-items: center;
+            }
+
+            .left {
+                image {
+                    width: 36px;
+                    margin-right: 16px;
+                }
+
+                text {
+                    font-size: 32px;
+                    font-family: PingFangSC-Regular, PingFang SC;
+                    font-weight: 400;
+                    color: @cl_333;
+                }
+            }
+
+            .right image {
+                width: 28px;
+                height: 28px;
+            }
+        }
+    }
+
+    .signIn {
+        height: 384px;
+        background-color: #FFFFFF;
+        border-radius: 20px;
+        margin: 100px 30px 0;
+        padding: 30px 28px;
+        box-sizing: border-box;
+
+        .header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 20px;
+
+            .left {
+                font-weight: 600;
+                color: #333333;
+                font-size: 32px;
+            }
+
+            .right {
+                font-weight: 500;
+                color: #666666;
+                font-size: 24px;
+            }
+        }
+
+        .ins {
+            display: flex;
+            justify-content: space-between;
+            margin-bottom: 20px;
+
+            &>view {
+                &>.top {
+                    border-radius: 10px;
+                    width: 80px;
+                    background-color: #f7f7f7;
+                    height: 110px;
+                    margin-bottom: 10px;
+                    padding: 12px 10px;
+                    box-sizing: border-box;
+                    display: flex;
+                    flex-direction: column;
+                    justify-content: space-between;
+                    align-items: center;
+
+                    &>image {
+                        width: 60px;
+                        height: 60px;
+                    }
+
+                    &>text {
+                        font-size: 24px;
+                        font-weight: 500;
+                        color: #999999;
+                        text-align: center;
+                    }
+                }
+
+                &>.bottom {
+                    font-size: 24px;
+                    font-weight: 400;
+                    color: #999999;
+                    text-align: center;
+                }
+
+                &.needSign {
+                    &>.top {
+                        background-color: #FFF3C9;
+
+                        &>text {
+                            color: #FF9A08;
+                        }
+                    }
+
+                    &>.bottom {
+                        color: #FFBF1C;
+                    }
+                }
+            }
+        }
+
+        .signBt {
+            width: 428px;
+            height: 85px;
+            text-align: center;
+            line-height: 85px;
+            background-image: linear-gradient(#FF6178, #FF3154);
+            border-radius: 50px;
+            color: #FFFFFF;
+            margin: 0 auto;
+            font-size: 32px;
+            font-weight: 600;
+            letter-spacing: 3px;
+        }
+
+        .signBtSucc {
+            background: #D2D2D2;
+        }
+    }
+
+    .crous {
+        height: 448px;
+        margin-top: 30px;
+        margin-bottom: 30px;
+
+        .header>.right {
+            display: flex;
+            align-items: center;
+
+            &>image {
+                width: 28px;
+                height: 28px;
+            }
+        }
+
+        .task {
+            margin: 24px 8px;
+
+            &>View {
+                height: 80px;
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+                margin-bottom: 36px;
+
+                .left {
+                    display: flex;
+                    justify-content: flex-start;
+                    align-items: center;
+
+                    .title {
+                        color: #333333;
+                        font-weight: 400;
+                        font-size: 28px;
+                        margin-left: 18px;
+                        margin-right: 20px;
+                    }
+
+                    &>image {
+                        width: 44px;
+                        height: 52px;
+                    }
+
+                    .reward {
+                        font-weight: 400;
+                        color: #FF9302;
+                        font-size: 28px;
+                    }
+
+                    .bean {
+                        width: 40px;
+                        height: 40px;
+                    }
+                }
+
+                .right {
+                    width: 160px;
+                    height: 60px;
+                    border-radius: 40px;
+                    color: #FFFFFF;
+                    text-align: center;
+                    line-height: 60px;
+                    background-color: #FF415B;
+                    font-weight: 500;
+                    font-size: 24px;
+                }
+
+                .rightSucc {
+                    background-color: #FFFFFF;
+                    border: 2px solid #FF415B;
+                    color: #FF415B;
+                }
+            }
+        }
+    }
 }

+ 85 - 155
src/pages/my/index.tsx

@@ -1,90 +1,28 @@
 import { Component } from 'react'
 import Taro from '@tarojs/taro'
-import { View, Text, Image, Button, Navigator } from '@tarojs/components'
+import { View, Text, Image, Button, Navigator, Input } from '@tarojs/components'
 import { observer, inject } from 'mobx-react'
 import './index.less'
 // import { pushUserInfo, pushAdLog, getUserInfoSecond, setSign, getVideoNoin, setTaskCoin, addSubscribe } from '../../api'
 import { getLoginSto } from '@src/utils/loginSto'
+import { Store } from '@src/app'
 
 // import TipsUnlocking from '../../components/guidePage/tipsUnlocking'
 // import Toast from '../../components/guidePage/toast'
 // import SceneTips from '../../components/guidePage/sceneTips'
 // import Subscribe from '../../components/guidePage/subscribe'
 // import SignTips from '../../components/guidePage/signTips'
-
-type PageStateProps = {
-    store: {
-        indexStore: {
-            navBarTop: number,
-            SET_NAVBARMARGINTOP: Function,
-            openType: number,
-            userInfo: userInfo,
-            SET_USERINFO: Function
-        }
-    }
-}
-interface My {
-    props: PageStateProps;
-}
-
-type userInfo = {
-    user_name: string,
-    avatar_url: string,
-    is_auth: number,
-    is_vip: boolean,
-    member_end_date: string,
-}
-
-type state = {
-    canIUseGetUserProfile: boolean,
-    videoAd: Taro.RewardedVideoAd | undefined,
-    isPullVideo: boolean,
-    signInfo: {   // 签到信息
-        list: any[],
-        signInfo: any
-    },
-    account: number, // 我的免费豆
-    task: {          // 任务相关信息
-        daily: any,
-        important: any
-    },
-    toastInfo: {
-        title: string,
-        reward: number,
-        show: boolean
-    },
-    messageShow: boolean,
-    signShow: boolean,
-    signType: 'direct' | 'look' | 'lookTask'
+interface Props {
+    store: Store;
 }
 
 let _this: any = null
 
 @inject('store')
 @observer
-class My extends Component {
+class My extends Component<Props> {
 
-    state: state = {
-        canIUseGetUserProfile: false,
-        videoAd: undefined,
-        isPullVideo: false,
-        signInfo: {
-            list: [],
-            signInfo: {}
-        },
-        account: 0,
-        task: {
-            daily: {},
-            important: {}
-        },
-        toastInfo: {
-            title: '',
-            reward: 0,
-            show: false
-        },
-        messageShow: false,
-        signShow: false,
-        signType: 'direct'
+    state = {
     }
 
     componentDidShow() {
@@ -112,19 +50,8 @@ class My extends Component {
         // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
         // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
         /*   @ts-ignore */
-        wx.getUserProfile({
-            desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
-            success: res => {
-                _this.setState({
-                    userInfo: res.userInfo
-                })
-                // let { city, country, gender, nickName, province, avatarUrl } = res.userInfo
-                let { open_id } = getLoginSto()
-                // pushUserInfo({ openid: open_id, city, country, gender, nickname: nickName, province, avatarUrl }).then(() => {
-                //     _this.getData()
-                // })
-            }
-        })
+
+
     }
 
     getData = (type?: string) => {
@@ -166,93 +93,96 @@ class My extends Component {
         // })
     }
 
-
+    onChooseAvatar = (e) => {
+        const { avatarUrl } = e.detail
+        console.log(e.detail)
+    }
     render() {
-        let { indexStore } = this.props.store
+        let { userInfoStore } = this.props.store
+
+        return <View className='my'>
+            <View className="userInfo">
+                {/* <Image src={require('../../icon/myBack.png')} /> */}
+                <View className="userInfo_box">
+                    <View className="top" >
+                        <View className="left">
+                            <View className="avtai">
+                                <Image mode="widthFix" lazy-load src={userInfoStore.userInfo?.avatarUrl ? userInfoStore.userInfo?.avatarUrl : require('../../icon/avatar.jpg')} />
+                            </View>
+                            <View className="name" style={userInfoStore.isAuth ? { width: Taro.pxTransform(120) } : {}}>
+                                {
+                                    userInfoStore.userInfo?.nickName ? <View className="ID">{userInfoStore.userInfo?.nickName || ""}</View> :
+                                        <View className="ID">读友_sdajhsd</View>
+                                }
+                                {
+                                    userInfoStore.isVip && <View className="grade">
+                                        <Image lazy-load src={require('../../icon/grade.png')} />
+                                        <Text>V1</Text>
+                                    </View>
+                                }
+                            </View>
+                        </View>
+                        {
+                            userInfoStore.isAuth && <View className="right">
+                                {
+                                    userInfoStore.isAuth ?
+                                        <Button onClick={this.getUserProfile} className="loginBt"  >
+                                            <Image lazy-load src={require('../../icon/loaginBt.png')} />
+                                        </Button>
+                                        : <View>
+                                            <Button openType='chooseAvatar' onChooseAvatar={this.onChooseAvatar} className="loginBt">
+                                                <Image lazy-load src={require('../../icon/loaginBt.png')} />
+                                            </Button>
+                                            {/* <Input type="nickname" placeholder="请输入昵称" /> */}
+                                        </View>
 
-        return (
-            <View className='my'>
-                <View className="userInfo">
-                    <Image src={require('../../icon/myBack.png')} />
-                    <View className="userInfo_box">
-                        <View className="top" style={indexStore.openType === 1 ? { marginTop: Taro.pxTransform(130) } : {}}>
+                                }
+                            </View>
+                        }
+                    </View>
+                    {/* vip续费 */}
+                    <View className="bottom">
+                        <View>
                             <View className="left">
-                                <View className="avtai">
-                                    <Image mode="widthFix" lazy-load src={indexStore.userInfo?.avatar_url ? indexStore.userInfo?.avatar_url : require('../../icon/avatar.jpg')} />
-                                </View>
-                                <View className="name" style={indexStore.userInfo?.is_auth === 0 ? { width: Taro.pxTransform(120) } : {}}>
-                                    {
-                                        indexStore.openType === 1 ? <View className="ID">{indexStore.userInfo?.user_name || ""}</View> :
-                                            <View className="ID">读友_sdajhsd</View>
-                                    }
+                                <Image lazy-load src={require('../../icon/VIP.png')} />
+                                <View className="txt">
+                                    <Text>会员尊享免费解锁权益</Text>
                                     {
-                                        indexStore.userInfo?.is_vip && indexStore.openType !== 1 && <View className="grade">
-                                            <Image lazy-load src={require('../../icon/grade.png')} />
-                                            <Text>V1</Text>
-                                        </View>
+                                        userInfoStore.isVip && <Text className="tfv">有效期至:{1111}</Text>
                                     }
                                 </View>
                             </View>
-                            {
-                                indexStore.userInfo?.is_auth === 0 && <View className="right">
-                                    {
-                                        this.state.canIUseGetUserProfile ?
-                                            <Button onClick={this.getUserProfile} className="loginBt">
-                                                <Image lazy-load src={require('../../icon/loaginBt.png')} />
-                                            </Button>
-                                            :
-                                            <Button openType='getUserInfo' onGetUserInfo={this.handleWXGetUserInfo.bind(this)} className="loginBt">
-                                                <Image lazy-load src={require('../../icon/loaginBt.png')} />
-                                            </Button>
-                                    }
-                                </View>
-                            }
+                            <View className="right" onClick={() => { Taro.navigateTo({ url: '/pages/vipCore/index' }) }}>{userInfoStore.isVip ? '立即续费' : '立即开通'}</View>
                         </View>
-                        {/* vip续费 */}
-                        <View className="bottom">
-                            <View>
-                                <View className="left">
-                                    <Image lazy-load src={require('../../icon/VIP.png')} />
-                                    <View className="txt">
-                                        <Text>会员尊享免费解锁权益</Text>
-                                        {
-                                            indexStore.userInfo?.is_vip && <Text className="tfv">有效期至:{indexStore.userInfo?.member_end_date}</Text>
-                                        }
-                                    </View>
-                                </View>
-                                <View className="right" onClick={() => { Taro.navigateTo({ url: '/pages/vipCore/index' }) }}>{indexStore.userInfo?.is_vip ? '立即续费' : '立即开通'}</View>
+                        <Image lazy-load src={require('../../icon/vipBack.png')} />
+                    </View>
+                    {/* 底部功能入口 */}
+                    <View className="list_bt" >
+                        <Navigator className="item" url="/pages/my/contactService/index">
+                            <View className="left">
+                                <Image lazy-load src={require('../../icon/phone.png')} mode="widthFix" />
+                                <Text>联系客服</Text>
                             </View>
-                            <Image lazy-load src={require('../../icon/vipBack.png')} />
-                        </View>
-                        {/* 底部功能入口 */}
-                        <View className="list_bt" style={indexStore.openType === 1 ? { marginTop: Taro.pxTransform(100) } : {}}>
-                            <Navigator className="item" url="/pages/contactus/index">
-                                <View className="left">
-                                    <Image lazy-load src={require('../../icon/phone.png')} mode="widthFix" />
-                                    <Text>联系客服</Text>
-                                </View>
-                                <View className="right">
-                                    <Image lazy-load src={require('../../icon/jtRight.png')} mode="widthFix" />
-                                </View>
-                            </Navigator>
-                            <View className="line"></View>
-                            <Navigator className="item" url="/pages/aboutWe/index">
-                                <View className="left">
-                                    <Image lazy-load src={require('../../icon/we.png')} mode="widthFix" />
-                                    <Text>关于我们</Text>
-                                </View>
-                                <View className="right">
-                                    <Image lazy-load src={require('../../icon/jtRight.png')} mode="widthFix" />
-                                </View>
-                            </Navigator>
-                        </View>
+                            <View className="right">
+                                <Image lazy-load src={require('../../icon/jtRight.png')} mode="widthFix" />
+                            </View>
+                        </Navigator>
+                        <View className="line"></View>
+                        <Navigator className="item" url="/pages/my/aboutUs/index">
+                            <View className="left">
+                                <Image lazy-load src={require('../../icon/we.png')} mode="widthFix" />
+                                <Text>关于我们</Text>
+                            </View>
+                            <View className="right">
+                                <Image lazy-load src={require('../../icon/jtRight.png')} mode="widthFix" />
+                            </View>
+                        </Navigator>
                     </View>
                 </View>
+            </View>
 
 
-
-            </View>
-        )
+        </View>
     }
 }
 

+ 33 - 2
src/server/book/short/index.tsx

@@ -74,10 +74,41 @@ export function getShortBookInfo(bookId: any) {
 }
 
 /**
- * 开始阅读上报
+ * 开始阅读小说内容上报
+ * @param bookId 小说ID
+ * @param readCondition 场景
  * */
-
+export function startReadShort(data: { bookId: any, readCondition: any }) {
+    return new Promise(async (resolve, reject) => {
+        Taro.request({
+            url: `/app/shortBookInfo/startRead`,
+            method: 'GET',
+            data,
+            success: (res) => {
+                bookStore.setData({ readId: res.data.data })
+                resolve(res)
+            },
+            fail: (err) => {
+                reject(err);
+            }
+        })
+    })
+}
 
 /**
  * 阅读中心跳上报
  * */
+export function readingShort(readId: number) {
+    return new Promise(async (resolve, reject) => {
+        Taro.request({
+            url: `/app/shortBookInfo/reading/${readId}`,
+            method: 'PUT',
+            success: (res) => {
+                resolve(res)
+            },
+            fail: (err) => {
+                reject(err);
+            }
+        })
+    })
+}

+ 2 - 1
src/server/wx/login.ts

@@ -1,7 +1,7 @@
 import { setApp } from "@src/config";
 import { ResData } from "@src/interceptor"
 import Taro from "@tarojs/taro"
-
+import userInfoStore from '@src/store/userInfo'
 /**
  * 用户登录初始化(用来获取应用相关信息,并获取登录token)
  * */
@@ -40,6 +40,7 @@ export function wxlogin() {
             });
             if (response.code === 200) {
               setApp({token:response.data.token})//存放token
+              userInfoStore.setData({userInfo:response.data.userInfo})
               resolve(response.data)
             }
           } else {

+ 8 - 5
src/store/book.ts

@@ -1,10 +1,10 @@
 import { observable } from 'mobx'
 
 interface ContentData {
-    current:number,
-    total:number,
-    size:number,
-    records:any[]
+    current: number,
+    total: number,
+    size: number,
+    records: any[]
 }
 export interface OpenBookData {
     bookId: number,//书ID
@@ -15,7 +15,7 @@ export interface OpenBookData {
     bookStatus: number,//完本|连载状态
     wordCount: number,//字数
     labelInfoList: { name: string }[],//标签
-    contentData:ContentData|null //内容数据
+    contentData: ContentData | null //内容数据
 }
 
 interface ClassifyData {
@@ -28,6 +28,8 @@ interface ClassifyData {
 export interface BookStore {
     /**当前打开的的小说数据*/
     openBookData: OpenBookData | null,
+    /**心跳上报ID*/
+    readId: number,//
     bookList: any,
     /**1女频 0男频 默认男频*/
     workDirection: "男生" | "女生",
@@ -59,6 +61,7 @@ const Book: BookStore = observable({
     oldWorkDirection: "男生",
     classifyData: [],
     bookList: [],
+    readId: 0,
     bookConfig: { size: 'pre_21', off_on: false, bg: 'bg_b', lh: 'lh_72' },
     setData(data: { [key: string]: any }) {
         if (data) {

+ 19 - 9
src/store/userInfo.tsx

@@ -1,17 +1,27 @@
 import { observable } from 'mobx'
-export interface Data {
-  
+
+export interface UserInfoStore {
+    isAuth: boolean,//是否授权获取头像信息,
+    isVip: boolean,//是否是vip
+    userInfo: {
+        openId:string,
+        nickName:string,
+        avatarUrl:string
+    } | null,
+    setData: (data: { [key: string]: any }) => void,
 }
 /**
  * 用户信息
- * */ 
-const userInfoStore = observable({
-    data: null,
-    config: null,
-    channel:'m',
-    action(data: Data) {
+ * */
+const userInfoStore: UserInfoStore = observable({
+    isAuth: false,
+    isVip: false,
+    userInfo: null,
+    setData(data: { [key: string]: any }) {
         if (data) {
-            this.data = data
+            Object.keys(data).forEach(key => {
+                this[key] = data[key]
+            })
         }
     },
 })