This commit is contained in:
@fawn-nine
2024-05-29 15:34:50 +08:00
parent bb53af8bde
commit 4386f615f2
79 changed files with 6942 additions and 4121 deletions

View File

@@ -5,7 +5,7 @@
"configurations" : [
{
"app-plus" : {
"launchtype" : "remote"
"launchtype" : "local"
},
"default" : {
"launchtype" : "local"

84
App.vue
View File

@@ -37,90 +37,6 @@
}
})
// 取出初始播放信息
uni.getStorage({
key: 'playingInfo',
success: function(res) {
console.log(res, 'playingInfo本地初始化')
store.commit('setUserInfo', {
'playingInfo': res.data
})
store.commit('setUserInfo', {
'playTitle': res.data.chapter,
'fengImg': res.data.bookImage
})
console.log(store.state.userInfo, '初始化')
},
fail: function(e) {
console.log(e, 'playingInfo本地初始化失败')
store.commit('setUserInfo', {
'playingInfo': {
'images': '../../static/icon/fengziIcon.jpg',
'chapterName': '暂无播放信息',
}
})
store.commit('setUserInfo', {
'playTitle': '暂无播放信息',
'fengImg': '../../static/icon/fengziIcon.jpg'
})
},
})
// 取出播放列表
uni.getStorage({
key: 'playData',
success: function(res) { // 本地有播放数据就用本地的
console.log(res.data, '取出的本地数据');
if (res.data.myList.length <= 0) {
store.commit('setUserInfo', {
'playVisible': false
})
} else {
music.setList(res.data.myList, '', store.state.userInfo.playIndex)
// music.setCoverImg(res.data.fengImg)
store.commit('setUserInfo', res.data)
}
store.commit('setUserInfo', {
'playFlag': false
}); // 设置播放按钮状态为暂停
store.commit('setUserInfo', {
'currentTime': 0
});
},
fail: function(e) { // 如果没有,就查询一下线上的播放记录
console.log('本地无数据');
music.setList([])
//store.commit('setUserInfo',{'playingInfo': {'bookid':0,'chapterId':0}});
store.commit('setUserInfo', {
'playVisible': false
})
store.commit('setUserInfo', {
'myList': [],
'fengImg': '../../static/icon/fengziIcon.jpg'
})
store.commit('setUserInfo', {
'playFlag': false
});
store.commit('setUserInfo', {
'currentTime': 0
});
}
});
// end
// 取出播放弹窗显示或者隐藏
uni.getStorage({
key: 'playVisible',
success: function(res) {
store.commit('setUserInfo', {
'playVisible': res.data
}); // 设置是否显示按钮
},
fail: function(e) { // 如果本地没有playVisible数据默认为false
store.commit('setUserInfo', {
'playVisible': false
});
}
});
//取出缓存数据
store.commit('setCacheData');
// #ifdef MP-WEIXIN

View File

@@ -1,682 +0,0 @@
<template>
<!--音频组件-->
<view>
<view class="bgfff">
<view>
<view class="audo-video">
<!-- 播放封面 -->
<view :class="['fengmianBox','defaultBg', succes ? 'playAnimate' : '']" :style="{ backgroundImage: `url(${fengImg})` }"></view>
<!--音频播放按钮处-->
<view class="audo-top">
<!-- 顺序播放 -->
<image v-if="orderPlayBtn" style="width:50rpx;height:50rpx;" src="/static/orderPlaya.png" mode="aspectFill" @click="orderPlay(false)"></image>
<image v-else style="width:50rpx;height:50rpx;" src="/static/orderPlay.png" mode="aspectFill" @click="orderPlay(true)"></image>
<!--上一首切换按钮-->
<image v-if="jian" @click="sig" src="/static/xys.png" style="width:50rpx;height:50rpx;transform:rotate(180deg)"
mode="aspectFill"></image>
<image v-else style="width:50rpx;height:50rpx;" @click="nosig" src="/static/sys.png" mode="aspectFill"></image>
<!--上一首切换按钮-->
<!--快退按钮-->
<!-- <image src="/static/kt.png" style="width:45rpx;height:45rpx;" mode="aspectFill" @click="kt()"></image> -->
<!--快退按钮-->
<!--播放按钮-->
<image :src="succes?'/static/bofang2.png':'/static/zt.png'" mode="aspectFill"
style="width:180rpx;height:180rpx;" @click="plays()"></image>
<!--播放按钮-->
<!--快进按钮-->
<!-- <image src="/static/kj.png" style="width:45rpx;height:45rpx;" mode="aspectFill" @click="kj()"></image> -->
<!--快进按钮-->
<!--下一首切换按钮-->
<image v-if="jia" @click="noxig" style="width:50rpx;height:50rpx;transform:rotate(180deg)" src="/static/sys.png"
mode="aspectFill"> </image>
<image v-else style="width:50rpx;height:50rpx;" src="/static/xys.png" @click="xig" mode="aspectFill"></image>
<!-- 播放目录 -->
<image src="/static/libIcon.png" style="width:45rpx;height:45rpx;" mode="aspectFill" @click="showLib()"></image>
</view>
<!--音频播放按钮处-->
<!--音频api处[视频代替音频-实现倍数功能]-->
<video id="myVideo" ref="myVideo" :src="recorPath" class="hidden" @timeupdate="timeupdate"
:autoplay="autoplays" @loadedmetadata="loadedmetadata" @ended="next" controls
style="width: 10rpx;height:10rpx;">
</video>
<!--音频api处[视频代替音频-实现倍数功能]-->
<view class="audo-a" style="margin:0 auto;">
<!--进度条-->
<view class="slider-box">
<text class="mm">{{timer}}</text>
<slider style="width: 370rpx;" @change="sliderChange" @changing="sliderChanging"
class="audio-slider" block-size="16" :min="0" :max="duration" :value="currentTime"
activeColor="#2fc348" @touchstart="lock= true" @touchend="lock = false" />
<text class="ss" v-if="overTimer!='NaN:NaN'">{{overTimer}}</text>
<text class="ss" v-else>00.00</text>
</view>
<!--进度条-->
</view>
</view>
</view>
</view>
<view class="h-100"></view>
<!--占位-->
</view>
<!--音频组件 Author:chenxin-->
</template>
<script>
/*
list -- 音频文件传入 不传无法播放/数组形式
Faskms -- 快进秒数 number 默认15秒
Slowms -- 快退秒数 number 默认15秒
autoNext -- 是否自动播放下一首
autoplays -- 进入页面是否自动播放 - 默认false
slideYes -- 滑动进度条时是否开启播放 - 默认false
switAud -- 切换上下音频是否开启播放 - 默认false
BsNav -- 倍数数据传入/数组形式
按钮图片未自定义,如想改动请在组件内部修改,页面头部已注释 -- 逻辑根据自己需求改
目前只测试 微信小程序和H5和APP -- 其他平台未知
Author:chenxin 交流vx:cxalq8-24
*/
import {
mapState,mapMutations
} from 'vuex';
export default {
name: "cx-audio-play",
props: {
list: { //音频数据
Type: Array,
default:[]
},
fengImg:{
// 封面img
type:String,
default:''
},
Faskms: { //快进秒数
Type: Number,
default: 15,
},
jia:{
Type: Boolean,
default: false,
},
// orderPlayBtn:{
// // 按顺序播放
// Type: Boolean,
// default: false
// },
Slowms: { //快退秒数
Type: Number,
default: 15,
},
autoNext: {
Type: Boolean,
default: false,
},
autoplays: { //是否开启自动播放
Type: Boolean,
default: true,
},
slideYes: { //滑动进度条 - 是否开启播放
Type: Boolean,
default: false,
},
switAud: {
Type: Boolean, //切换上下音频 - 是否开启播放
default: false,
},
jian: { //减-切换图标
type:Boolean,
default:false
},
cctime:{ // 初始化播放位置(秒)
type:Object,
default:{}
},
BsNav: { //倍数-传入 0.5/0.8/1.0/1.25/1.5/2.0
Type: Array,
default: () => [{
id: 0.5,
bs: '0.5',
}, {
id: 0.8,
bs: '0.8'
}, {
id: 1.0,
bs: '1.0'
},{
id: 1.25,
bs: '1.25'
},{
id: 1.5,
bs: '1.5'
},{
id: 2.0,
bs: '2.0'
}
],
},
},
data() {
return {
orderPlayBtn:false,
shows: false, //倍数弹框
show: true, //倍数弹框动画默认开启
// jia: true, //加-切换图标
succes: true, //播放按钮
bsid: '', //倍数默认显示第一个
bsindex: 2, //倍数默认显示第一个
num: 0,
current: 0, //当前选中的索引
recorPath: '', //音频播放地址
lock: false, // 锁
currentTime: 0, //当前进度
duration: 1, // 总进度
videoContext: null,
loading: true, //锁 加载
audioMannager:null ,// 背景音乐
saveInterVal:null,
}
},
onReady() {},
onShow() {
},
onBackPress() {
},
mounted() {
// console.log(this.cctime,'cctime') // 默认播放的位置(秒),第一次加载
this.videoContext = uni.getBackgroundAudioManager()
// this.videoContext = uni.createVideoContext('myVideo', this)
//默认播放第一个 -- 按钮展示
if (this.list.length != 0) {
this.loading = true
this.videoContext.title = '暂无'
this.videoContext.singer = '暂无'
this.videoContext.coverImgUrl = this.fengImg
this.videoContext.src = this.list[0].recorPath
this.playloading()
// if (this.list.length > 1) { //音频文件大于1 -- 下一个切换默认显示
// // this.jia = false
// if (this.autoplays) {
// this.succes = true
// }
// }
}
this.videoContext.onEnded(() => {
this.next()
//this.setUserInfo({playFlag:false});
//console.log(this.userInfo.playFlag,'playFlag')
}) // 播放结束加载下一首
this.videoContext.onError((err) => {
console.log(err)
this.setUserInfo({playFlag:true});
this.next()
}) // 播放错误加载下一首
this.videoContext.onCanplay(() =>{
// this.setUserInfo({playFlag:true});
// console.log(this.userInfo.playFlag,'playFlag')
this.duration = this.videoContext.duration
// this.loading = false
uni.hideLoading()
this.succes = true
if(this.cctime.flag == 'init'){
// 页面初始化时
this.currentTime = this.cctime.time
// 跳转到指定的秒数上
this.videoContext.seek(this.currentTime)
console.log('获取到初始值,进行时间跳转')
}
})
this.videoContext.onPlay(() => {
this.playSeconds = Math.ceil(this.currentTime) // 秒数取整
})
this.videoContext.onTimeUpdate((res) => {
//console.log(this.videoContext.currentTime,'onTimeUpdate');
this.currentTime = Math.max(0, this.videoContext.currentTime)
// console.log(this.currentTime,'当前秒数');
// var ss = Math.floor(this.playSeconds / 60)
// console.log(ss, this.playSeconds)
// if(ss > this.playSeconds){
// this.playSeconds = ss
// console.log(ss)
// }
})
},
updated() {
},
onLoad() {
},
onHide() { //监听页面离开 - 销毁音频
// this.videoContext.stop();
console.log('onHide')
},
onUnload() { //监听页面卸载 - 销毁音频
// this.videoContext.stop();
console.log('onUnload')
},
destroyed() {
// if(this.videoContext){
// this.videoContext.stop();
// }
console.log('destroyed')
},
computed: {
...mapState(['userInfo']),
timer() {
return calcTimer(this.currentTime)
},
overTimer() {
return calcTimer(this.duration)
}
},
watch: {
},
methods: {
...mapMutations(['setUserInfo']),
// 存储听书进度
saveListenRate(){
console.log('存储听书进度')
this.$emit('saveRate',this.currentTime)
},
// 顺序播放
orderPlay(val){
// console.log(val)
if(val){
uni.showToast({
title:'开启顺序播放',
icon:'none'
})
this.orderPlayBtn = true
}else{
uni.showToast({
title:'关闭顺序播放',
icon:'none'
})
this.orderPlayBtn = false
}
},
// 显示播放列表
showLib(){
this.$emit('showLib',true)
},
plays() { //播放暂停
if (!this.list || this.list.length == 0) {
uni.showToast({
title: '暂无音频数据~',
icon: "none"
})
// console.log('暂无音频数据.~')
return;
}
// this.playloading()
this.succes = !this.succes
/// console.log('修改后',this.succes)
if (this.succes) {
console.log('去播放',this.succes)
// this.setUserInfo({playFlag:true});
this.videoContext.play()
} else {
// this.succes = false
console.log('去暂停',this.succes )
// this.setUserInfo({playFlag:false});
uni.hideLoading()
//#ifdef H5
this.videoContext.pause()
this.saveListenRate()
//#endif
//#ifndef H5
this.videoContext.pause()
this.saveListenRate()
//#endif
}
},
// beishu() { //倍速弹框
// this.shows = !this.shows
// },
// 倍速
// setRate(index, item) {
// this.bsid = item.id
// this.bsindex = index
// this.shows = false
// //#ifdef H5
// this.videoContext.playbackRate(2)
// //#endif
// //#ifndef H5
// this.videoContext.playbackRate(2)
// //#endif
// },
// 更新进度条
timeupdate(event) {
if (this.lock) return; // 锁
var currentTime, duration;
if (event.detail.detail) {
currentTime = event.detail.detail.currentTime
duration = event.detail.detail.duration
} else {
currentTime = event.detail.currentTime
duration = event.detail.duration
}
this.currentTime = currentTime
this.duration = duration
},
// 拖动进度条
sliderChange(data) {
//此处滑动进度条--开始播放
if (this.slideYes && !this.succes) {
//#ifdef H5
this.videoContext.play()
//#endif
//#ifndef H5
this.videoContext.play()
//#endif
this.succes = true
}
//#ifdef H5
this.videoContext.seek(data.detail.value) //获取秒数
//#endif
//#ifndef H5
this.videoContext.seek(data.detail.value) //获取秒数
//#endif
},
//拖动中
sliderChanging(data) {
if (data.detail.value == 0) {
this.succes = false
//#ifdef H5
this.videoContext.pause()
//#endif
//#ifndef H5
this.videoContext.pause()
//#endif
}
this.currentTime = data.detail.value
},
// 视频加载完成
loadedmetadata(data) {
this.duration = data.detail.duration
},
sig() { //上一首
this.$emit('playPrev',true)
// if (!this.list || this.list.length == 0) {
// console.log('暂无音频数据~')
// return;
// }
// this.num -= 1
// console.log(this.num,'this.num')
// if (this.num < this.list.length) {
// this.loading = true
// this.playloading() //加载框
// }
// if (this.num + 1 < this.list.length && this.num + 1 != 1) { //点击上一首小于音频数据总长度
// // this.jia = false // 下按钮-亮且可点击
// // this.jian = false // 上按钮-亮且可点击
// } else {
// // this.jian = true // 上按钮-灰且阻止
// // this.jia = false // 下按钮-亮且可点击
// }
// this.recorPath = this.list[this.num].recorPath
// if (this.switAud) { //切换时是否默认开启播放
// this.succes = true
// setTimeout(() => {
// //#ifdef H5
// this.$refs.myVideo.play()
// //#endif
// //#ifndef H5
// this.videoContext.play()
// //#endif
// }, 100)
// } else {
// this.succes = false
// }
},
xig() { //下一首
this.$emit("xiayishou");
// if (!this.list || this.list.length == 0) {
// console.log('暂无音频数据~')
// return;
// }
// this.num += 1
// if (this.num < this.list.length) {
// this.loading = true
// this.playloading() //加载框
// }
// if (this.num + 1 < this.list.length) { //点击下一首小于音频数据总长度
// this.jia = false // 下按钮-亮且可点击
// this.jian = false // 上按钮-亮且可点击
// } else { //大于总长度
// this.jia = true //下按钮 - 灰且阻止
// this.jian = false //上按钮 - 亮可点击
// }
// this.recorPath = this.list[this.num].recorPath
// if (this.switAud) { //切换时是否默认开启播放
// this.succes = true
// setTimeout(() => {
// //#ifdef H5
// this.$refs.myVideo.play()
// //#endif
// //#ifndef H5
// this.videoContext.play()
// //#endif
// }, 100)
// } else {
// this.succes = false
// }
},
nosig() {
uni.showToast({
title: '到头了~',
icon: "none"
})
},
noxig() {
uni.showToast({
title: '没有更多了~',
icon: "none"
})
},
next(data) { //监听音频结束
// console.log('开始播放下一首')
this.succes = false
/*音频结束--是否自动播放下一首*/
//if(this.orderPlayBtn){
setTimeout(()=>{
this.$emit("xiayishou");
},100)
// }else{
// console.log('音频结束-------')
// return
// }
// if (!this.autoNext) {
// return
// }
// if (this.num + 1 < this.list.length) {
// this.succes = true
// this.num += 1
// this.recorPath = this.list[this.num].recorPath
// setTimeout(() => {
// //#ifdef H5
// this.$refs.myVideo.play()
// //#endif
// //#ifndef H5
// this.videoContext.play()
// //#endif
// }, 100)
// } else {
// //this.jia = true //下按钮 - 灰且阻止
// //this.jian = false //上按钮 - 亮可点击
// }
},
playloading() { //加载框--封
if (this.loading) {
uni.showLoading({
title: "音频缓存中..."
})
this.loading = false
}
this.succes = false
// setTimeout(() => {
// uni.hideLoading()
// }, 1600)
},
},
watch: {}
}
//时间换算
function calcTimer(timer) {
if (timer === 0 || typeof timer !== 'number') {
return '00:00'
}
let mm = Math.floor(timer / 60)
let ss = Math.floor(timer % 60)
if (mm < 10) {
mm = '0' + mm
}
if (ss < 10) {
ss = '0' + ss
}
return mm + ':' + ss
}
</script>
<style lang="scss" scoped>
@-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
.playAnimate{
-webkit-transform: rotate(360deg);
animation: rotation 6s linear infinite;
-moz-animation: rotation 6s linear infinite;
-webkit-animation: rotation 6s linear infinite;
-o-animation: rotation 6s linear infinite;
}
.fengmianBox{text-align: center; width: 400rpx; height: 400rpx; position: relative; border-radius: 400rpx; margin: 0 auto; margin-bottom: 140rpx; background-size: contain;}
.fengmianBox:after{
content: ''; display: inline-block; left:0; top:0; z-index: 0;width: 400rpx; height: 400rpx; position: absolute; border-radius: 400rpx; box-shadow: rgba(177, 235, 202, 0.8) 0px 0px 29px 0px;
}
.fengmianBox.defaultBg{background-image: url('@/static/icon/home_icon_0.png');}
page {
background-color: #F6F6F8;
}
/* #video {
width: 100%;
} */
.audo-video {
padding-bottom: 20rpx;
color: #999;
}
.slider-box {
display: flex;
align-items: center;
justify-content: center;
font-size: 27rpx;
color: #999; margin: 0 auto;
}
button {
display: inline-block;
width: 100rpx;
background-color: #fff;
font-size: 24rpx;
color: #000;
padding: 0;
}
.hidden {
position: fixed;
top: 0;
left: -10rpx;
z-index: -1;
width: 1rpx;
height: 1rpx;
}
.audo-top {
padding: 20rpx 40rpx;
display: flex;
justify-content: space-around;
align-items: center;
image {
width: 45rpx;
height: 45rpx;
}
}
.audo-a {
display: flex;
justify-content: space-between;
align-items: center;
width: 750rpx;
position: relative;
z-index: 9; margin: 0 auto;
}
.beishu {
position: relative;
width: 100rpx;
padding-top: 5rpx;
padding-bottom: 5rpx;
text-align: center;
border-radius: 25rpx;
font-size: 28rpx;
}
.absolute {
position: absolute;
.beishu-a {
width: 200rpx;
border-radius: 20rpx;
text-align: center;
line-height: 90rpx;
background: #fff;
.title {
pdding-left: 30rpx;
}
}
}
</style>

View File

@@ -1,360 +0,0 @@
<template>
<!--音频组件-->
<view>
<view class="bgfff">
<view>
<view class="audo-video">
<!-- 播放封面 -->
<view :class="['fengmianBox','defaultBg', userInfo.playFlag ? 'playAnimate' : '']" :style="{ backgroundImage: `url(${fengImg})` }"></view>
<!-- <view v-else :class="['fengmianBox','defaultBg', userInfo.playFlag ? 'playAnimate' : '']" style="{ border:1px solid red;backgroundImage: url('@/static/icon/fengziIcon.jpg') }">显示我</view> -->
<!--音频播放按钮处-->
<view class="audo-top">
<!-- 顺序播放 -->
<!-- <image v-if="orderPlayBtn" style="width:50rpx;height:50rpx;" src="/static/orderPlaya.png" mode="aspectFill" @click="orderPlay(false)"></image>
<image v-else style="width:50rpx;height:50rpx;" src="/static/orderPlay.png" mode="aspectFill" @click="orderPlay(true)"></image>
<!--上一首切换按钮-->
<!-- <image v-if="jian" @click="sig" src="/static/xys.png" style="width:50rpx;height:50rpx;transform:rotate(180deg)"
mode="aspectFill"></image>
<image v-else style="width:50rpx;height:50rpx;" @click="nosig" src="/static/sys.png" mode="aspectFill"></image>-->
<image class="prevMusic" @click="prevMusic" src="/static/xys.png" style="width:90rpx;height:90rpx;transform:rotate(180deg)"
mode="aspectFill"></image>
<!--上一首切换按钮-->
<!--播放按钮-->
<image :src="userInfo.playFlag ?'/static/bofang2.png':'/static/zt.png'" mode="aspectFill"
style="width:180rpx;height:180rpx;" @click="plays()"></image>
<!--播放按钮-->
<!--下一首切换按钮-->
<!-- <image v-if="jia" @click="noxig" style="width:50rpx;height:50rpx;transform:rotate(180deg)" src="/static/sys.png"
mode="aspectFill"> </image>
<image v-else style="width:50rpx;height:50rpx;" src="/static/xys.png" @click="xig" mode="aspectFill"></image> -->
<image class="nextMusic" style="width:90rpx;height:90rpx;" src="/static/xys.png" @click="nextMusic" mode="aspectFill"></image>
<!-- 播放目录 -->
<image src="/static/libIcon.png" style="width:45rpx;height:45rpx;" mode="aspectFill" @click="showLib()"></image>
</view>
<!--音频播放按钮处-->
<view class="audo-a" style="margin:0 auto;">
<!--进度条-->
<view class="slider-box">
<text class="mm">{{timer}}</text>
<slider style="width: 370rpx;" @change="sliderChange" @changing="sliderChanging"
class="audio-slider" block-size="16" :min="0" :max="duration" :value="currentTime"
activeColor="#2fc348" @touchstart="lock= true" @touchend="lock = false" />
<text class="ss" v-if="overTimer!='NaN:NaN'">{{overTimer}}</text>
<text class="ss" v-else>00.00</text>
</view>
<!--进度条-->
</view>
</view>
</view>
<!-- 播放列表 -->
<u-popup mode="bottom" :show="LibVisible" :round="10" @close="LibVisible=false" >
<view class="libTitle">播放列表</view>
<view class="tanchu playList" style="height:400rpx;overflow-y: scroll;">
<scroll-view style="height:400rpx; overflow-y: scroll;" scroll-y="true"
<view class="item" v-for="(item,index) in libLIst" :key="index" >
<view @click="listenOne(item)" :class="userInfo.playIndex == index ? 'playNow' : ''">
<view>{{item.chapter}}</view>
</view>
</view>
</scroll-view>
</view>
</u-popup>
</view>
<view class="h-100"></view>
<!--占位-->
</view>
<!--音频组件 Author:chenxin-->
</template>
<script>
/*
list -- 音频文件传入 不传无法播放/数组形式
Faskms -- 快进秒数 number 默认15秒
Slowms -- 快退秒数 number 默认15秒
autoNext -- 是否自动播放下一首
autoplays -- 进入页面是否自动播放 - 默认false
slideYes -- 滑动进度条时是否开启播放 - 默认false
switAud -- 切换上下音频是否开启播放 - 默认false
BsNav -- 倍数数据传入/数组形式
按钮图片未自定义,如想改动请在组件内部修改,页面头部已注释 -- 逻辑根据自己需求改
目前只测试 微信小程序和H5和APP -- 其他平台未知
Author:chenxin 交流vx:cxalq8-24
*/
import {
mapState,mapMutations
} from 'vuex';
export default {
name: "cx-audio-play",
props: {
list: { //音频数据
Type: Array,
default:[]
},
},
data() {
return {
playIndex: 0,// 播放器index
LibVisible:false,
libLIst:[],
fengUrl:'',
orderPlayBtn:false,
shows: false, //倍数弹框
show: true, //倍数弹框动画默认开启
// jia: true, //加-切换图标
succes: true, //播放按钮
bsid: '', //倍数默认显示第一个
bsindex: 2, //倍数默认显示第一个
num: 0,
current: 0, //当前选中的索引
recorPath: '', //音频播放地址
lock: false, // 锁
currentTime: 0, //当前进度
duration: 1, // 总进度
videoContext: null,
loading: true, //锁 加载
audioMannager:null ,// 背景音乐
saveInterVal:null,
fengImg:'',
nofengImg:'../../static/icon/fengziIcon.jpg'
}
},
created() {
this.libLIst = this.$bgm.musicList
this.fengImg = this.userInfo.fengImg
console.log(this.userInfo.fengImg,'this.userInfo.fengImg++++++++++++++')
this.userInfo.playTimes ? this.setUserInfo({'currentTime': this.userInfo.playTimes}) : ''
},
computed: {
...mapState(['userInfo']),
timer() {
this.currentTime = this.userInfo.currentTime
return calcTimer(this.userInfo.currentTime)
},
overTimer() {
this.duration = this.userInfo.duration
return calcTimer(this.userInfo.duration)
},
},
watch: {
},
methods: {
...mapMutations(['setUserInfo']),
// 上一首
prevMusic(){
if(this.$bgm._options.src == ''){ // 如果直接点下一首,没点播放
this.$music.playBgm({mute:false})
this.$music.setPlayIndex('next')
}else{
this.$music.setPlayIndex('prev')
}
},
nextMusic(){ // 下一首
if(this.$bgm._options.src == ''){ // 如果直接点下一首,没点播放
this.$music.playBgm({mute:false})
this.$music.setPlayIndex('next')
}else{
this.$music.setPlayIndex('next')
}
},
//关闭或开启 音乐
plays() {
this.muteBgMusic = !this.muteBgMusic
console.log(this.muteBgMusic,this.muteBgMusic?'已关闭音乐####':'已开启音乐####');
if (this.userInfo.playFlag) {
// 暂停
// this.$music.playBgm({mute:true})
this.$bgm.pause()
} else {
// 播放
// this.$music.playBgm({mute:false})
if(this.$bgm._options.src == ''){
this.$music.playBgm({mute:false})
}else{
this.$bgm.play()
}
}
},
// 播放单个音频
listenOne(item){
if(this.$bgm._options.src == ''){
this.$music.playBgm({mute:false})
this.$music.setOneMusic(item)
}else{
this.$music.setOneMusic(item)
}
},
// 显示播放列表
showLib(){
this.LibVisible = true
},
// 拖动进度条
sliderChange(data) {
// console.log(data,'拖动进度条',data)
if(this.$bgm._options.src == ''){
this.$music.playBgm({mute:false})
// this.$bgm.pause()
}else{
this.$bgm.play()
}
console.log('拖动',data.detail.value)
uni.getBackgroundAudioManager().seek(data.detail.value)
// this.$bgm.seek(data.detail.value) //获取秒数
},
//拖动中
sliderChanging(data) {
this.$bgm.pause()
this.currentTime = data.detail.value
//console.log('拖动中',this.currentTime)
},
},
watch: {}
}
//时间换算
function calcTimer(timer) {
if (timer === 0 || typeof timer !== 'number') {
return '00:00'
}
let mm = Math.floor(timer / 60)
let ss = Math.floor(timer % 60)
if (mm < 10) {
mm = '0' + mm
}
if (ss < 10) {
ss = '0' + ss
}
return mm + ':' + ss
}
</script>
<style lang="scss" scoped>
.graytitle{color: #999;}
@-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
.playAnimate{
-webkit-transform: rotate(360deg);
animation: rotation 6s linear infinite;
-moz-animation: rotation 6s linear infinite;
-webkit-animation: rotation 6s linear infinite;
-o-animation: rotation 6s linear infinite;
}
.fengmianBox{text-align: center; width: 400rpx; height: 400rpx; position: relative; border-radius: 400rpx; margin: 0 auto; margin-bottom: 140rpx; background-size: contain;}
.fengmianBox:after{
content: ''; display: inline-block; left:0; top:0; z-index: 0;width: 400rpx; height: 400rpx; position: absolute; border-radius: 400rpx; box-shadow: rgba(177, 235, 202, 0.8) 0px 0px 29px 0px;
}
.fengmianBox.defaultBg{background-image: url('@/static/icon/home_icon_0.png'); background-size: cover;}
page {
background-color: #F6F6F8;
}
/* #video {
width: 100%;
} */
.audo-video {
padding-bottom: 20rpx;
color: #999;
}
.slider-box {
display: flex;
align-items: center;
justify-content: center;
font-size: 27rpx;
color: #999; margin: 0 auto;
}
button {
display: inline-block;
width: 100rpx;
background-color: #fff;
font-size: 24rpx;
color: #000;
padding: 0;
}
.hidden {
position: fixed;
top: 0;
left: -10rpx;
z-index: -1;
width: 1rpx;
height: 1rpx;
}
.audo-top {
padding: 20rpx 40rpx;
display: flex;
justify-content: space-around;
align-items: center;
image {
width: 45rpx;
height: 45rpx;
}
}
.audo-a {
display: flex;
justify-content: space-between;
align-items: center;
width: 750rpx;
position: relative;
z-index: 9; margin: 0 auto;
}
.beishu {
position: relative;
width: 100rpx;
padding-top: 5rpx;
padding-bottom: 5rpx;
text-align: center;
border-radius: 25rpx;
font-size: 28rpx;
}
.absolute {
position: absolute;
.beishu-a {
width: 200rpx;
border-radius: 20rpx;
text-align: center;
line-height: 90rpx;
background: #fff;
.title {
pdding-left: 30rpx;
}
}
}
</style>

View File

@@ -1,58 +0,0 @@
<template>
<view>
<view v-if="minishow" class="fuchuang" style="width: 750rpx;">
我是浮窗
<view class="libTitle">播放列表</view>
<view class="libTitle"v-for="(item,index) in libLIst">{{item.chapterName}}</view>
<view class="tanchu playList">
<!-- <u-button>显示目录</u-button> -->
</view>
</view>
</view>
</template>
<script>
export default {
name: "miniPlay",
props: {
LibVisible:{
Type: Boolean,
default: false,
},
},
data() {
return {
minishow:true,
playid:1,
libLIst:[
{
'chapterName':1,
'chapterId':1
},
{
'chapterName':2,
'chapterId':1
},
{
'chapterName':3,
'chapterId':1
},
]
}
},
methods: {
showLib(){
this.LibVisible = true
}
}
}
</script>
<style>
.fuchuang{font-size: 20px; position:fixed; right: 0; bottom: 70px; background: green; z-index: 55;}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 967 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 799 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1014 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -3,21 +3,21 @@
<swiper class="guide_pages_swiper" indicator-dots="true" indicator-color="#d1d1d1" indicator-active-color="#54a966">
<swiper-item>
<view class="guide_pages_bg1">
疯子读书
吴门医述
<br>
让阅读无处不在
</view>
</swiper-item>
<swiper-item>
<view class="guide_pages_bg2">
疯子读书
吴门医述
<br>
古今一统中西互参
</view>
</swiper-item>
<swiper-item>
<view class="guide_pages_bg3">
疯子读书
吴门医述
<br>
和光同尘普惠人间
</view>

View File

@@ -21,7 +21,7 @@
:src="'/' + item.selectedIconPath" mode="aspectFit"></image>
<image v-else class="footer_nav_item_image" :src="'/' + item.iconPath" mode="aspectFit"></image>
<text class="footer_nav_item_text"
:class="[item.pagePath == path ? 'footer_item_text_active' : '']">{{ item.text }}</text>
:class="[item.pagePath == path ? 'footer_item_text_active' : 'normal_text']">{{ item.text }}</text>
</view>
</view>
</view>
@@ -39,68 +39,57 @@
data() {
return {
path: '',
navigationList: [{
pagePath: 'pages/peanut/home',
iconPath: 'static/tab/icon1_n.png',
selectedIconPath: 'static/tab/icon1_y.png',
text: '首页'
},{
"pagePath": "pages/medicaldes/medicaldes",
"iconPath": "static/icon/five5_n.png",
"selectedIconPath": "static/icon/five5.png",
"text": "吴门医述"
navigationList: [
{
"pagePath": "pages/peanut/home",
"iconPath": "static/tab/icon1_n.png",
"selectedIconPath": "static/tab/icon1_y.png",
"text": "首页"
},
{
"pagePath": "pages/peanut/shopping",
"iconPath": "static/tab/tab_nor_02.png",
"selectedIconPath": "static/tab/tab_cur_02.png",
"text": "购物车"
},
{
"pagePath": "pages/library/library",
"iconPath": "static/tab/icon3_n.png",
"selectedIconPath": "static/tab/icon3_y.png",
"text": "我的图书"
"iconPath": "static/tab/tab_nor_03.png",
"selectedIconPath": "static/tab/tab_cur_03.png",
"text": "太湖公益"
},
// {
// pagePath: 'pages/peanut/bookshelf',
// iconPath: 'static/tab/icon3_n.png',
// selectedIconPath: 'static/tab/icon3_y.png',
// text: '我的书架'
// },
// {
// pagePath: 'pages/bookShop/orderList',
// iconPath: 'static/tab/icon2_n.png',
// selectedIconPath: 'static/tab/icon2_y.png',
// text: '我的订单'
// },
{
pagePath: 'pages/peanut/mine',
iconPath: 'static/tab/icon4_n.png',
selectedIconPath: 'static/tab/icon4_y.png',
text: '我的'
"pagePath": "pages/peanut/mine",
"iconPath": "static/tab/tab_nor_04.png",
"selectedIconPath": "static/tab/tab_cur_04.png",
"text": "我的"
}
],
navigationIos: [{
pagePath: 'pages/peanut/home',
iconPath: 'static/tab/icon1_n.png',
selectedIconPath: 'static/tab/icon1_y.png',
text: '首页'
},
// {
// pagePath: 'pages/bookShop/orderList',
// iconPath: 'static/tab/icon2_n.png',
// selectedIconPath: 'static/tab/icon2_y.png',
// text: '我的订单'
// },
navigationIos: [
{
"pagePath": "pages/medicaldes/medicaldes",
"iconPath": "static/icon/five5.png",
"selectedIconPath": "static/icon/five5.png",
"text": "吴门医述"
"pagePath": "pages/peanut/home",
"iconPath": "static/tab/icon1_n.png",
"selectedIconPath": "static/tab/icon1_y.png",
"text": "首页"
},
{
pagePath: 'pages/peanut/mine',
iconPath: 'static/tab/icon4_n.png',
selectedIconPath: 'static/tab/icon4_y.png',
text: '我的'
"pagePath": "pages/peanut/shopping",
"iconPath": "static/tab/tab_nor_02.png",
"selectedIconPath": "static/tab/tab_cur_02.png",
"text": "购物车"
},
{
"pagePath": "pages/library/library",
"iconPath": "static/tab/tab_nor_03.png",
"selectedIconPath": "static/tab/tab_cur_03.png",
"text": "太湖公益"
},
{
"pagePath": "pages/peanut/mine",
"iconPath": "static/tab/tab_nor_04.png",
"selectedIconPath": "static/tab/tab_cur_04.png",
"text": "我的"
}
],
};
@@ -126,7 +115,9 @@
</script>
<style lang="scss" scoped>
@import '@/style/mixin.scss';
.normal_text{
color: #FFF;
}
.footer_station {
height: 110rpx;
box-sizing: content-box;
@@ -151,7 +142,7 @@
}
.footer_bg {
background-color: #FFF;
background-color: #fff;
box-shadow: 0 0px 10px 1px #0000001a;
}
@@ -176,7 +167,7 @@
.footer_nav_item_text {
font-size: 26rpx;
color: #909090;
color: #7b7b7b;
margin-top: 6rpx;
}
@@ -207,7 +198,7 @@
.footer_item_text_active {
color: #079307;
color: #3983ff;
font-weight: bold;
}
</style>

View File

@@ -1,113 +0,0 @@
<template>
<!-- 日期显示 -->
<view class="date_box">
<view
v-for="(dateInfo, dateIndex) in dates"
:key="dateIndex"
class="calendar_date__box"
>
<view
class="calendar_date"
:class="{ isSelected: dateActiveIndex === dateIndex && dateInfo.type === 'cur' }"
:style="{
height: cellHeight + 'rpx',
width: cellHeight + 'rpx',
color: swiperMode === 'open' ? dateInfo.type === 'cur' ? '#2C2C2C' : '#959595' : '#2C2C2C',
backgroundColor: dateActiveIndex === dateIndex && dateInfo.type === 'cur' ? dateActiveColor : ''
}"
@tap="chooseDate(dateInfo)"
>
<view class="calendar_date__number">{{ dateInfo.date }}</view>
<view class="calendar_date__isToday" v-if="dateInfo.isToday" :style="{ backgroundColor: dateActiveColor }"></view>
<view class="calendar_date__cricle"></view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
dates: {
type: Array,
default: () => []
},
cellHeight: { // 一列的高度
type: Number,
default: 75
},
dateActiveColor: { // 日期选中颜色
type: String,
default: '#FE6601'
},
selectedDate: {
type: String,
default: ''
},
swiperMode: { // 日历显示模式
type: String,
default: 'open'
},
showActive: { // 是否显示选中高亮日期
type: Boolean,
default: false
}
},
computed: {
dateActiveIndex() {
return this.showActive ? this.dates.map(item => item.dateFormat).indexOf(this.selectedDate) : -1
}
},
methods: {
chooseDate(dateInfo) {
this.$emit('chooseDate', dateInfo)
}
}
}
</script>
<style>
/* 日历轮播 */
.date_box {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.date_box .calendar_date__box {
width: calc(100% / 7);
margin-top: 20rpx;
}
.calendar_date__box .calendar_date {
text-align: center;
margin: 0 auto;
font-weight: bold;
font-size: 28rpx;
border-radius: 50%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
}
.calendar_date__box .calendar_date.isSelected {
color: #FFFFFF !important;
}
.calendar_date .calendar_date__isToday {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
border-radius: 50%;
z-index: -1;
opacity: 0.4;
}
.calendar_date .calendar_date__cricle {
width: 9rpx;
height: 9rpx;
border-radius: 50%;
margin-top: 5rpx;
background-color: #FFFFFF;
}
/* 日历轮播 */
</style>

View File

@@ -1,68 +0,0 @@
/**
* 时间格式化
* @param {String} time
* @param {String} cFormat
*/
export function parseTime(time, cFormat) {
if (arguments.length === 0) {
return null
}
if (!time) return ''
/* 修复IOS系统上面的时间不兼容*/
if (time.toString().indexOf('-') > 0) {
time = time.replace(/-/g, '/')
}
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
time = parseInt(time)
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
const value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') {
return ['日', '一', '二', '三', '四', '五', '六'][value]
}
return value.toString().padStart(2, '0')
})
return time_str
}
/**
* This is just a simple version of deep copy
* Has a lot of edge cases bug
* If you want to use a perfect deep copy, use lodash's _.cloneDeep
* @param {Object} source
* @returns {Object}
*/
export function deepClone(source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'deepClone')
}
const targetObj = Object.prototype.toString.call(source) === "[object Array]" ? [] : {}
Object.keys(source).forEach(keys => {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepClone(source[keys])
} else {
targetObj[keys] = source[keys]
}
})
return targetObj
}

View File

@@ -1,641 +0,0 @@
<template>
<!-- 日历滚动插件 -->
<view class="zsy_calendar">
<!-- 日历顶部信息 -->
<view class="calendar_info">
<text class="title">每日记录</text>
<text class="desc">
({{ getAssignDateInfo(false, 0) === getAssignDateInfo(true, 0) ? '' : getAssignDateInfo(false, 0) + '年' }}{{ getAssignDateInfo(false, 1) }})
</text>
<text v-show="showBackToTodayBtn" class="backToToday" :style="{color: dateActiveColor}" @tap="goToDate()">回到今天</text>
</view>
<!-- 日历周数 -->
<view class="calendar_week">
<view v-for="(item, index) in week" :key="index" class="calendar_week__item">{{ item }}</view>
</view>
<!-- 日历轮播 -->
<view class="calendar_swiper">
<!-- 展开情况下的日历轮播 -->
<swiper
v-if="swiperMode === 'open'"
key="normalSwiper"
circular
:style="{height: swiperHeight('open')}"
:current="current"
:duration="duration"
:skip-hidden-item-layout="true"
@change="e => current = e.detail.current"
>
<swiper-item v-for="(swiper, swiperIndex) in 3" :key="swiperIndex" class="swiper-item">
<DateBox
:dates="calendarSwiperDates[swiperIndex]"
:cellHeight="cellHeight"
:dateActiveColor="dateActiveColor"
:swiperMode="swiperMode"
@chooseDate="chooseDate"
/>
</swiper-item>
</swiper>
<!-- 收缩情况下的日历轮播 -->
<swiper
v-else
key="shrinkSwiper"
circular
:style="{height: swiperHeight('close')}"
:current="shrinkCurrent"
:duration="duration"
:skip-hidden-item-layout="true"
@change="e => shrinkCurrent = e.detail.current"
>
<swiper-item v-for="(swiper, swiperIndex) in 3" :key="swiperIndex" class="swiper-item">
<DateBox
:dates="calendarSwiperShrinkDates[swiperIndex]"
:cellHeight="cellHeight"
:dateActiveColor="dateActiveColor"
:swiperMode="swiperMode"
@chooseDate="chooseShrinkDate"
/>
</swiper-item>
</swiper>
</view>
<!-- 日历切换模式 -->
<view class="calendar_toggle" @tap="swiperMode = swiperMode === 'open' ? 'close' : 'open'">
<view class="icon" :class="{down: swiperMode === 'close'}"></view>
</view>
</view>
</template>
<script>
import { parseTime, deepClone } from './js/utils.js'
import DateBox from './dateBox.vue'
export default {
name: 'ZsyCalendar',
components: {
DateBox
},
props: {
duration: { // 轮播图动画时长
type: Number,
default: 300
},
cellHeight: { // 一列的高度
type: Number,
default: 75
},
dateActiveColor: { // 日期选中颜色
type: String,
default: '#FE6601'
},
sundayIndex: { // 星期天所在索引0表示第一个、6表示最后一个
type: Number,
default: 6
},
mode: { // 日历模式
type: String,
default: 'open'
},
changeSetDefault: { // 月份切换时是否显示一号还是当前月份选中高亮
type: Boolean,
default: true
},
defaultSelectedDate: { // 默认选中日期
type: String | null,
default: null
},
showArrowBtn: { // 是否显示左右切换按钮
type: Boolean,
default: true
}
},
data() {
return {
today: parseTime(new Date(), '{y}-{m}-{d}'), // 今天日期
selectedDate: null, // 选中日期
week: [], // 日历周数
current: 1, // 当前日历轮播默认显示索引
shrinkCurrent: 1, // 缩放日历轮播默认显示索引
calendarSwiperDates: [], // 日历轮播日期信息
calendarSwiperShrinkDates: [], // 日历轮播收缩时的日期信息
dateActive: -1, // 日期选中索引
swiperByClick: false, // 是否通过点击上月份或下月份的日期进行轮播切换
shrinkSwiperByClick: false, // 是否通过点击上月份或下月份的日期进行收缩日历的轮播切换
swiperMode: this.mode, // 日历轮播显示模式 open展开 close收缩
dateCache: {}, // 日期缓存
emitTimer: null, // 日期改变向父级传递当前选中日期计时器
dateClick: false // 是否进行了日期的点击选择
}
},
computed: {
/* 获取指定日期信息
isCurDate: 是否获取当天的信息还是选中日期的信息
index: 0 表示年份 1 表示月份 2 表示日期 */
getAssignDateInfo() {
return (isCurDate, index) => {
return (isCurDate ? this.today : this.selectedDate).split('-')[index] * 1
}
},
// 是否显示回到今天按钮
showBackToTodayBtn() {
return this.getAssignDateInfo(false, 0) !== this.getAssignDateInfo(true, 0) || this.getAssignDateInfo(false, 1) !== this.getAssignDateInfo(true, 1)
},
// 返回轮播图高度
swiperHeight() {
return (swiperMode) => {
const normalHeight = (this.calendarSwiperDates[this.current] || []).length / 7 * (this.cellHeight + 20) + 'rpx'
const shrinkHeight = this.cellHeight + 20 + 'rpx'
return swiperMode === 'open' ? normalHeight : shrinkHeight
}
}
},
watch: {
// 展开日历轮播切换
current(newV, oldV) {
if (newV === 0 && oldV === 2) { // 右滑
this.swiperChange(1)
return
}
if (newV === 2 && oldV === 0) { // 左滑
this.swiperChange(-1)
return
}
if (newV > oldV) { // 右滑
this.swiperChange(1)
} else { // 左滑
this.swiperChange(-1)
}
},
// 收缩日历轮播切换
shrinkCurrent(newV, oldV) {
if (newV === 0 && oldV === 2) { // 右滑
this.shrinkSwiperChange(1)
return
}
if (newV === 2 && oldV === 0) { // 左滑
this.shrinkSwiperChange(-1)
return
}
if (newV > oldV) { // 右滑
this.shrinkSwiperChange(1)
} else { // 左滑
this.shrinkSwiperChange(-1)
}
},
// 日历显示方式切换
swiperMode(newV) {
// 当收缩时初始化收缩轮播图的日期数据
if (newV === 'close') {
this.initCalendarShrinkSwiperDates()
}
},
selectedDate: {
deep: true,
handler(newV, oldV) {
if (newV && (oldV === null || this.dateClick)) { // 初始化/日历点击选择时直接返回
this.emitDate()
this.dateClick = false
} else { // 其它情况做防抖处理
if (this.emitTimer !== null) {
clearTimeout(this.emitTimer)
}
this.emitTimer = setTimeout(() => {
this.emitDate()
}, this.duration + 200)
}
}
}
},
created() {
this.init() // 初始化数据
},
methods: {
// 初始化数据
init() {
if (this.selectedDate === null) { // 默认选中日期为当天
this.selectedDate = this.defaultSelectedDate || this.today
}
this.initWeek() // 初始化要显示的周数
this.initCalendarSwiperDates() // 初始化日历轮播日期信息
// 解决swiperMode初始化为收缩时没有初始化日历收缩轮播日期信息
if (this.swiperMode === 'close') {
this.initCalendarShrinkSwiperDates()
}
},
// 初始化周数
initWeek() {
const normalWeek = ['日', '一', '二', '三', '四', '五', '六'] // 正常周数
const sIndex = this.sundayIndex < 0 ? 0 : this.sundayIndex >= normalWeek.length ? normalWeek.length - 1 : this.sundayIndex
normalWeek.unshift(...normalWeek.slice(-sIndex))
normalWeek.length = 7
this.week = normalWeek
},
// 初始化展开时的日历轮播日期信息
initCalendarSwiperDates(cb) {
const year = this.getAssignDateInfo(false, 0)
const month = this.getAssignDateInfo(false, 1)
const cur = this.generateCalendar(year, month)
const prev = this.generateCalendar(month === 1 ? year - 1 : year, month === 1 ? 12 : month - 1)
const next = this.generateCalendar(month === 12 ? year + 1 : year, month === 12 ? 1 : month + 1)
// 根据current来判断相邻的轮播存放哪些日历数据
if (this.current === 0) {
this.calendarSwiperDates = [cur, next, prev]
} else if (this.current === 1) {
this.calendarSwiperDates = [prev, cur, next]
} else if (this.current === 2) {
this.calendarSwiperDates = [next, prev, cur]
}
this.swiperByClick = false
// 初始化日期信息完毕执行回调函数
cb && cb()
},
// 生成展开的日历数据
generateCalendar(year, month) {
let calendarDate = []
// 先获取缓存里面有没有该月的日期数据
if (this.dateCache[`${year}-${month}`]) {
calendarDate = deepClone(this.dateCache[`${year}-${month}`])
} else { // 进行月份日期的计算
const monthDates = new Date(year, month, 0).getDate() // 获取此月份总天数
const normalWeek = ['一', '二', '三', '四', '五', '六', '日'] // 正常周数
const monthFirstDay = normalWeek[new Date(year, month - 1, 0).getDay()] // 获取本月一号为星期几
const monthFirstDayIndex = this.week.indexOf(monthFirstDay) // 计算本月一号在日历周数中的索引,索引之前的填充上个月的后几天
// 本月一号在日历中不是第一个位置,需要进行填充
if (monthFirstDayIndex !== 0) {
const prevMonthDates = new Date(year, month - 1, 0).getDate() // 获取上一个月份的总天数
// 填充本月一号之前的数据
for (let i = 0; i < monthFirstDayIndex; i ++) {
const item = {
year: month === 1 ? year - 1 : year,
month: month === 1 ? 12 : month - 1,
date: prevMonthDates - i,
type: 'prev'
}
// 判断填充的日期是否包含今天日期
this.theDateIsToday(item)
calendarDate.unshift(item)
}
}
// 循环生成当月所有日期
for (let i = 1; i <= monthDates; i ++) {
const item = {
year,
month,
date: i,
isSelected: false,
isToday: false,
type: 'cur'
}
// 今天的日期在不在里面
this.theDateIsToday(item)
calendarDate.push(item)
}
const residue = calendarDate.length % 7
// 判断是否需要填充下个月的前几天
if (residue !== 0) {
for (let i = 1; i <= 7 - residue; i ++) {
const item = {
year: month === 12 ? year + 1 : year,
month: month === 12 ? 1 : month + 1,
date: i,
type: 'next'
}
// 下个月的前几天包含今天
this.theDateIsToday(item)
calendarDate.push(item)
}
}
this.dateCache[`${year}-${month}`] = deepClone(calendarDate)
}
// 进行日期的默认选中
if (year === this.getAssignDateInfo(false, 0) && month === this.getAssignDateInfo(false, 1)) {
for (let i = 0, len = calendarDate.length; i < len; i++) {
if (calendarDate[i].type === 'cur' && calendarDate[i].date === this.getAssignDateInfo(false, 2)) {
calendarDate[i].isSelected = true
this.dateActive = i
break
}
}
}
return calendarDate
},
// 判断日期是否为今天
theDateIsToday(item) {
if (item.year + '-' + item.month + '-' + item.date === this.getAssignDateInfo(true, 0) + '-' + this.getAssignDateInfo(true, 1) + '-' + this.getAssignDateInfo(true, 2)) {
item.isToday = true
}
},
// 初始化收缩时的日历轮播日期信息
initCalendarShrinkSwiperDates(swiperChangeType) {
let line = null
/**
* 日历收缩事件/当前滑动不涉及到到上个/下个月的日期数据
* 日历滑动到上一周并且本周不属于第一行并且上一周选中的日期必须是本月份里面的日期
* 日历滑动到下一周且本周不属于最后一行
*/
const curDateLine = Math.floor(this.dateActive / 7)
if (!swiperChangeType ||
(swiperChangeType === -1 && curDateLine !== 0 && this.calendarSwiperDates[this.current][(curDateLine - 1) * 7].type === 'cur') ||
(swiperChangeType === 1 && curDateLine + 1 !== this.calendarSwiperDates[this.current].length / 7)
) {
// 计算当前周选中日期处于日历中的哪一行位置
const curCalendarSwiperDates = this.calendarSwiperDates[this.current]
line = Math.floor(curCalendarSwiperDates.map(item => item.type === 'cur' ? item.date : -1).indexOf(this.getAssignDateInfo(false, 2)) / 7)
// 收缩日历滑动事件需要进行日期的选中处理
if (swiperChangeType) {
// 将当前选中日期清除选中状态
this.calendarSwiperDates[this.current][this.dateActive].isSelected = false
// 重新计算日期选中高亮并把下一个日期进行选中
this.dateActive = line * 7
this.calendarSwiperDates[this.current][this.dateActive].isSelected = true
}
} else { // 收缩日历滑动事件
// 将当前选中日期清除选中状态
this.calendarSwiperDates[this.current][this.dateActive].isSelected = false
// 涉及了上个月/下个月的日期数据,需要重新计算展开日历轮播的日期数据
let currentNum = this.current + swiperChangeType
currentNum = currentNum > 2 ? 0 : currentNum < 0 ? 2 : currentNum
this.current = currentNum
// 计算上一周/下一周选中日期处于日历中的哪一行位置
const curCalendarSwiperDates = this.calendarSwiperDates[this.current]
line = Math.floor(curCalendarSwiperDates.map(item => item.type === 'cur' ? item.date : -1).indexOf(this.getAssignDateInfo(false, 2)) / 7)
// 重新计算日期选中高亮并把下一个日期进行选中
this.dateActive = line * 7
this.calendarSwiperDates[this.current][this.dateActive].isSelected = true
}
const cur = this.generateShrinkCalendar(0, line)
const prev = this.generateShrinkCalendar(-1, line)
const next = this.generateShrinkCalendar(1, line)
// 根据shrinkCurrent来判断相邻的轮播存放哪些日历数据
if (this.shrinkCurrent === 0) {
this.calendarSwiperShrinkDates = [cur, next, prev]
} else if (this.shrinkCurrent === 1) {
this.calendarSwiperShrinkDates = [prev, cur, next]
} else if (this.shrinkCurrent === 2) {
this.calendarSwiperShrinkDates = [next, prev, cur]
}
},
// 生成收缩的日历数据
generateShrinkCalendar(type, line) {
// 返回当前这一周的日期数据
if (type === 0) {
return this.calendarSwiperDates[this.current].slice(line * 7, (line + 1) * 7)
}
// 返回上一周的日期数据
if (type === -1) {
// 当前选中的日期是否位于第一行
if (line === 0) {
/**
* 当前日历的第一行是否包含有上个月的日期
* 如果有包含,则返回上个月的倒数第二行日期
* 如果没有包含,则返回上个月的倒数第一行日期
*/
// 计算上个月的索引值
const prevIndex = this.current === 0 ? 2 : this.current - 1
// 获取上个月的日期数据
const prevCalendarSwiperDates = this.calendarSwiperDates[prevIndex]
// 获取上个月的日历行数
const prevCalendarSwiperDatesLine = prevCalendarSwiperDates.length / 7
if (this.calendarSwiperDates[this.current][0].type === 'prev') { // 倒数第二行
return prevCalendarSwiperDates.slice((prevCalendarSwiperDatesLine - 2) * 7, (prevCalendarSwiperDatesLine - 1) * 7)
} else { // 倒数第一行
return prevCalendarSwiperDates.slice((prevCalendarSwiperDatesLine - 1) * 7)
}
} else {
return this.calendarSwiperDates[this.current].slice((line - 1) * 7, line * 7)
}
}
// 返回下一周的日期数据
if (type === 1) {
// 计算当前日历月份总共有多少行
const curMonthMaxLine = this.calendarSwiperDates[this.current].length / 7
// 当前选中的日期是否位于最后一行
if (line === curMonthMaxLine - 1) {
/**
* 当前日历的最后一行是否包含有下个月的日期
* 如果有包含,则返回下个月的第二行日期
* 如果没有包含,则返回上个月的第一行日期
*/
// 计算下个月的索引值
const nextIndex = this.current === 2 ? 0 : this.current + 1
// 获取下个月的日期数据
const nextCalendarSwiperDates = this.calendarSwiperDates[nextIndex]
// 获取下个月的日历行数
const nextCalendarSwiperDatesLine = nextCalendarSwiperDates.length / 7
if (this.calendarSwiperDates[this.current][this.calendarSwiperDates[this.current].length - 1].type === 'next') { // 第二行
return nextCalendarSwiperDates.slice(7, 14)
} else { // 第一行
return nextCalendarSwiperDates.slice(0, 7)
}
} else {
return this.calendarSwiperDates[this.current].slice((line + 1) * 7, (line + 2) * 7)
}
}
},
// 展开日历轮播切换事件
swiperChange(type) {
// 通过点击上个月/下个月日期进行切换,不需要默认选中下个月的一号,直接选中点击的那个日期
if (!this.swiperByClick && this.swiperMode === 'open') {
this.getPrevOrNextDate(type)
}
setTimeout(() => { // 设置定时器是为了防止轮播切换时生成数据造成页面卡顿
this.initCalendarSwiperDates(() => {
this.swiperMode === 'close' && this.initCalendarShrinkSwiperDates()
}) // 初始化日历轮播日期信息
}, this.swiperMode === 'open' ? this.duration : 0)
},
// 收缩日历轮播切换事件
shrinkSwiperChange(type) {
// 默认选中下个星期的开始日期
this.getPrevOrNextStartDate(type)
setTimeout(() => { // 设置定时器是为了防止轮播切换时生成数据造成页面卡顿
this.initCalendarShrinkSwiperDates(type) // 初始化日历轮播日期信息
}, this.duration)
},
// 手动切换日历
switchCalendar(type) {
const currentKey = this.swiperMode === 'close' ? 'shrinkCurrent' : 'current'
const v = this[currentKey] + (type === 'prev' ? -1 : 1)
this[currentKey] = v === -1 ? 2 : v === 3 ? 0 : v
},
// 获取上一个月/下一个月的一号日期
getPrevOrNextDate(type) {
const year = this.getAssignDateInfo(false, 0)
let month = this.getAssignDateInfo(false, 1)
month = month + type
// 判断切换月份时选中当前日期高亮还是一号,若选中当前日期高亮需进行大小判断
const curActiveDate = this.getAssignDateInfo(false, 2)
const maxDate = new Date(year, month, 0).getDate()
const date = this.changeSetDefault ? 1 : curActiveDate > maxDate ? maxDate : curActiveDate
this.selectedDate = parseTime(new Date(year, month - 1, date), '{y}-{m}-{d}')
},
// 获取上个星期/下一星期的开始日期
getPrevOrNextStartDate(type) {
const date = this.calendarSwiperShrinkDates[this.shrinkCurrent][0]
this.selectedDate = parseTime(new Date(date.year, date.month - 1, date.date), '{y}-{m}-{d}')
},
// 前往某一天 格式 YYYY-MM | YYYY-MM-DD
goToDate(date = this.today) {
try {
if (date.split('-').length < 2 || date.split('-').length > 3) throw '参数有误'
if (date.split('-').length === 2) {
date += '-01'
}
} catch (err) {
throw Error('请检查参数是否符合规范')
}
this.selectedDate = date
this.initCalendarSwiperDates(() => {
this.initCalendarShrinkSwiperDates()
})
},
// 日历轮播展开的情况下选择日期
chooseDate(dateInfo, dateIndex) {
// 重复点击后续不做处理
if (dateInfo.isSelected) return false
// 是否点击了上个月份的后几天或者点击了下个月份的前几天
if (dateInfo.type !== 'cur') {
if (dateInfo.type === 'prev') { // 点击了上个月份的后几天,滑到上个月
this.current = this.current === 0 ? 2 : this.current - 1
} else { // 点击了下个月份的前几天,滑到下个月
this.current = this.current === 2 ? 0 : this.current + 1
}
// 将选中日期赋值为当前点击的那个日期
this.selectedDate = parseTime(new Date(dateInfo.year, dateInfo.month - 1, dateInfo.date), '{y}-{m}-{d}')
this.swiperByClick = true
return false
}
// 将当前选中的日期清空并选中最新的日期
this.calendarSwiperDates[this.current][this.dateActive].isSelected = false
this.dateActive = dateIndex
const date = this.calendarSwiperDates[this.current][this.dateActive]
date.isSelected = true
this.selectedDate = parseTime(new Date(date.year, date.month - 1, date.date), '{y}-{m}-{d}')
this.dateClick = true
},
// 日历轮播收缩的情况下选择日期
chooseShrinkDate(dateInfo, dateIndex) {
// 重复点击后续不做处理
if (dateInfo.isSelected) return false
this.dateClick = true
// 是否点击了上个月份的后几天或者点击了下个月份的前几天
if (dateInfo.type !== 'cur') {
if (dateInfo.type === 'prev') { // 点击了上个月份的后几天,切换到上个月
this.current = this.current === 0 ? 2 : this.current - 1
} else { // 点击了下个月份的前几天,切换到下个月
this.current = this.current === 2 ? 0 : this.current + 1
}
this.dateActive = dateIndex
// 将选中日期赋值为当前点击的那个日期
this.selectedDate = parseTime(new Date(dateInfo.year, dateInfo.month - 1, dateInfo.date), '{y}-{m}-{d}')
return false
}
// 计算当前选中日期之前有多少个日期
const dateActiveLine = Math.floor(this.dateActive / 7) * 7
// 将当前选中的日期清空并选中最新的日期
this.calendarSwiperDates[this.current][this.dateActive].isSelected = false
this.dateActive = dateIndex + dateActiveLine
const date = this.calendarSwiperDates[this.current][this.dateActive]
date.isSelected = true
this.selectedDate = parseTime(new Date(date.year, date.month - 1, date.date), '{y}-{m}-{d}')
},
// 向父组件传递当前选中数据
emitDate() {
const { year, month, date } = this.calendarSwiperDates[this.current][this.dateActive]
const e = {
selectedDate: this.selectedDate,
year,
month,
date
}
this.$emit('change', e)
}
}
}
</script>
<style>
.zsy_calendar {
width: 100%;
padding: 20rpx 0;
box-sizing: border-box;
background-color: #fff;
border-radius: 20rpx;
}
/* 日历顶部信息 */
.calendar_info {
display: flex;
align-items: center;
padding: 0 20rpx;
}
.calendar_info .title {
font-size: 34rpx;
font-weight: bold;
color: #2C2C2C;
}
.calendar_info .desc {
margin-left: 29rpx;
font-size: 28rpx;
color: #959595;
}
.calendar_info .backToToday {
margin-left: auto;
font-size: 24rpx;
}
/* 日历顶部信息 */
/* 日历周数 */
.calendar_week {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 26rpx;
color: #959595;
margin: 20rpx 0rpx;
}
.calendar_week .calendar_week__item {
width: calc(100% / 7);
text-align: center;
}
/* 日历周数 */
/* 日历切换模式 */
.calendar_toggle {
position: relative;
padding: 10rpx 0;
margin: 10rpx 20rpx 0;
display: flex;
justify-content: center;
}
.calendar_toggle .icon {
width: 30rpx;
height: 30rpx;
background-image: url('../../static/zsy-calendar/arrow.png');
background-size: contain;
background-repeat: no-repeat;
margin: 0 auto;
transition: all .3s;
}
.icon.down {
transform: rotate(180deg);
}
.calendar_toggle::before, .calendar_toggle::after {
width: calc(50% - 30rpx);
border-top: solid 2rpx #EAEAEA;
content: '';
display: block;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.calendar_toggle::before {
left: 0;
}
.calendar_toggle::after {
right: 0;
}
/* 日历切换模式 */
</style>

View File

@@ -1,536 +0,0 @@
<template>
<!-- 日历滚动插件 -->
<view class="zsy_calendar">
<!-- 日历顶部信息 -->
<view class="calendar_info" >
<view class="">
<text class="title">读书打卡</text>
<text class="desc">
({{ getAssignDateInfo(false, 0) === getAssignDateInfo(true, 0) ? '' : getAssignDateInfo(false, 0) + '年' }}{{ getAssignDateInfo(false, 1) }})
</text>
</view>
<view class="dakaBtn" @tap="goToDate()">
<u-icon name="checkbox-mark" color="#55aa7f" size="24" style="display: inline;"></u-icon>
<text>打卡</text>
</view>
<!-- <text v-show="showBackToTodayBtn" class="backToToday" :style="{color: dateActiveColor}" @tap="goToDate()">回到今天</text> -->
</view>
<!-- 日历周数 -->
<view class="calendar_week">
<view v-for="(item, index) in week" :key="index" class="calendar_week__item">{{ item }}</view>
</view>
<!-- 日历轮播 -->
<view class="calendar_swiper">
<swiper
key="normalSwiper"
circular
:style="{height: swiperHeight}"
:current="current"
:duration="duration"
:skip-hidden-item-layout="true"
@change="e => current = e.detail.current"
>
<swiper-item v-for="(swiper, swiperIndex) in 3" :key="swiperIndex" class="swiper-item">
<DateBox
:dates="getcurCalendarDates[swiperIndex]"
:cellHeight="cellHeight"
:selectedDate="selectedDate"
:dateActiveColor="dateActiveColor"
:swiperMode="swiperMode"
:showActive="emitTimer === null"
@chooseDate="chooseDate"
/>
</swiper-item>
</swiper>
</view>
<!-- 日历切换模式 -->
<view class="calendar_toggle" @tap="swiperMode = swiperMode === 'open' ? 'close' : 'open'">
<view class="icon" :class="{down: swiperMode === 'close'}"></view>
</view>
</view>
</template>
<script>
import { parseTime, deepClone } from './js/utils.js'
import DateBox from './dateBox.vue'
export default {
name: 'ZsyCalendar',
components: {
DateBox
},
props: {
duration: { // 轮播图动画时长
type: Number,
default: 300
},
cellHeight: { // 一列的高度
type: Number,
default: 75
},
dateActiveColor: { // 日期选中颜色
type: String,
default: '#FE6601'
},
sundayIndex: { // 星期天所在索引0表示第一个、6表示最后一个
type: Number,
default: 6
},
mode: { // 日历模式
type: String,
default: 'close'
},
changeSetDefault: { // 月份切换时是否显示一号还是当前月份选中高亮
type: Boolean,
default: true
},
defaultSelectedDate: { // 默认选中日期
type: String | null,
default: null
},
showArrowBtn: { // 是否显示左右切换按钮
type: Boolean,
default: true
}
},
data() {
return {
today: parseTime(new Date(), '{y}-{m}-{d}'), // 今天日期
selectedDate: null, // 选中日期
week: [], // 日历周数
current: 1, // 当前日历轮播默认显示索引
calendarSwiperDates: [], // 日历轮播日期信息
swiperChangeByClick: false, // 是否通过点击上月份或下月份的日期进行轮播切换
swiperMode: this.mode, // 日历轮播显示模式 open展开 close收缩
monthDateCache: {}, // 月份日期缓存数据
emitTimer: null, // 日期改变向父级传递当前选中日期计时器
dateClick: false // 是否进行了日期的点击选择
}
},
computed: {
// 返回当前日期信息(展开状态下为每月,收缩状态下为每周)
getcurCalendarDates() {
if (this.swiperMode === 'open') { // 展开
return this.calendarSwiperDates
} else {
return this.getCalendarShrinkSwiperDates()
}
},
// 计算选中日期的上月、本月、下月的年月信息
getAdjacentYMD() {
const year = this.getAssignDateInfo(false, 0)
const month = this.getAssignDateInfo(false, 1)
const prev = `${month === 1 ? year - 1 : year}-${month === 1 ? 12 : month - 1}`
const cur = `${year}-${month}`
const next = `${month === 12 ? year + 1 : year}-${month === 12 ? 1 : month + 1}`
return [prev, cur, next]
},
/* 获取指定日期信息
isToday: 是否获取当天的信息还是选中日期的信息
index: 0 表示年份 1 表示月份 2 表示日期 */
getAssignDateInfo() {
return (isToday, index) => {
return (isToday ? this.today : this.selectedDate).split('-')[index] * 1
}
},
// 是否显示回到今天按钮
showBackToTodayBtn() {
return this.getAssignDateInfo(false, 0) !== this.getAssignDateInfo(true, 0) || this.getAssignDateInfo(false, 1) !== this.getAssignDateInfo(true, 1)
},
// 返回轮播图高度
swiperHeight() {
const normalHeight = (this.calendarSwiperDates[this.current] || []).length / 7 * (this.cellHeight + 20) + 'rpx'
const shrinkHeight = this.cellHeight + 20 + 'rpx'
return this.swiperMode === 'open' ? normalHeight : shrinkHeight
}
},
watch: {
// 展开日历轮播切换
current(newV, oldV) {
if (newV === 0 && oldV === 2) { // 右滑
this.swiperChange(1)
return
}
if (newV === 2 && oldV === 0) { // 左滑
this.swiperChange(-1)
return
}
if (newV > oldV) { // 右滑
this.swiperChange(1)
} else { // 左滑
this.swiperChange(-1)
}
},
selectedDate: {
deep: true,
handler(newV, oldV) {
var selectD = new Date(newV).getTime();
var curTime = new Date().getTime();
//console.log(newV)
console.log(curTime,selectD)
if(selectD > curTime){
uni.showToast({
title:'未来日期不可打卡',
icon:'none'
})
return false
}else{
// 判断月历日期数据需不需要改变
if (this.swiperMode === 'close') {
setTimeout(() => {
this.generateAdjacentMonthDate() // 生成临近月份日期缓存数据
}, this.duration);
}
if (newV && (oldV === null || this.dateClick)) { // 初始化/日历点击选择时直接返回
this.emitDate()
this.dateClick = false
} else { // 其它情况做防抖处理
if (this.emitTimer !== null) {
clearTimeout(this.emitTimer)
this.emitTimer = null
}
this.emitTimer = setTimeout(() => {
this.emitDate()
this.emitTimer = null
}, this.duration + 200)
}
}}
}
},
created() {
this.init() // 初始化数据
},
methods: {
// 初始化数据
init() {
if (this.selectedDate === null) { // 默认选中日期为当天
this.selectedDate = this.defaultSelectedDate || this.today
}
this.initWeek() // 初始化要显示的周数
this.generateAdjacentMonthDate() // 生成临近月份日期缓存数据
},
// 初始化周数
initWeek() {
const normalWeek = ['日', '一', '二', '三', '四', '五', '六'] // 正常周数
const sIndex = this.sundayIndex < 0 ? 0 : this.sundayIndex >= normalWeek.length ? normalWeek.length - 1 : this.sundayIndex
normalWeek.unshift(...normalWeek.slice(-sIndex))
normalWeek.length = 7
this.week = normalWeek
},
// 根据current自动对轮播数据进行衔接排序
adjacentSortByCurrent(prev, cur, next) {
let arr
if (this.current === 0) {
arr = [cur, next, prev]
} else if (this.current === 1) {
arr = [prev, cur, next]
} else if (this.current === 2) {
arr = [next, prev, cur]
}
console.log(arr,'arr')
return arr
},
// 生成本月、上个月、下个月日期信息
generateAdjacentMonthDate() {
const arr = []
this.getAdjacentYMD.map(YM => {
const [year, month] = YM.split('-')
arr.push(this.generateMonthDateCache(year, month))
})
console.log(arr,'arr')
const [prev, cur, next] = arr
this.calendarSwiperDates = this.adjacentSortByCurrent(prev, cur, next)
if (this.swiperChangeByClick) {
this.swiperChangeByClick = false
}
},
// 生成月份日期缓存数据并返回
generateMonthDateCache(year, month) {
year = Number(year)
month = Number(month)
// 缓存中已存在
if (this.monthDateCache[`${year}-${month}`]) return this.monthDateCache[`${year}-${month}`]
let calendarDate = []
const monthDates = new Date(year, month, 0).getDate() // 获取此月份总天数
const normalWeek = ['一', '二', '三', '四', '五', '六', '日'] // 正常周数
const monthFirstDay = normalWeek[new Date(year, month - 1, 0).getDay()] // 获取本月一号为星期几
const monthFirstDayIndex = this.week.indexOf(monthFirstDay) // 计算本月一号在日历周数中的索引,索引之前的填充上个月的后几天
// 本月一号在日历中不是第一个位置,需要进行填充
if (monthFirstDayIndex !== 0) {
const prevMonthDates = new Date(year, month - 1, 0).getDate() // 获取上一个月份的总天数
// 填充本月一号之前的数据
for (let i = 0; i < monthFirstDayIndex; i ++) {
const item = {
year: month === 1 ? year - 1 : year,
month: month === 1 ? 12 : month - 1,
date: prevMonthDates - i,
dateFormat: `${month === 1 ? year - 1 : year}-${String(month === 1 ? 12 : month - 1).padStart(2, '0')}-${String(prevMonthDates - i).padStart(2, '0')}`,
type: 'prev'
}
// 判断填充的日期是否包含今天日期
this.theDateIsToday(item)
calendarDate.unshift(item)
}
}
// 循环生成当月所有日期
for (let i = 1; i <= monthDates; i ++) {
const item = {
year,
month,
date: i,
isSelected: false,
dateFormat: `${year}-${String(month).padStart(2, '0')}-${String(i).padStart(2, '0')}`,
type: 'cur'
}
// 今天的日期在不在里面
this.theDateIsToday(item)
calendarDate.push(item)
}
const residue = calendarDate.length % 7
// 判断是否需要填充下个月的前几天
if (residue !== 0) {
for (let i = 1; i <= 7 - residue; i ++) {
const item = {
year: month === 12 ? year + 1 : year,
month: month === 12 ? 1 : month + 1,
date: i,
dateFormat: `${month === 12 ? year + 1 : year}-${String(month === 12 ? 1 : month + 1).padStart(2, '0')}-${String(i).padStart(2, '0')}`,
type: 'next'
}
// 下个月的前几天包含今天
this.theDateIsToday(item)
calendarDate.push(item)
}
}
this.monthDateCache[`${year}-${month}`] = deepClone(calendarDate)
return this.monthDateCache[`${year}-${month}`]
},
// 轮播图切换结束
swiperChange(e) {
// 切换上个月/下个月,默认选中一号 / 切换上一周/下一周,默认选中第一天
if (!this.swiperChangeByClick) {
this.getPrevOrNextDate(e)
}
if (this.swiperMode === 'open') { // 展开
// 通过点击上个月/下个月日期进行切换,不需要默认选中下个月的一号,直接选中点击的那个日期
setTimeout(() => {
this.generateAdjacentMonthDate() // // 重新生成临近月份日期缓存数据
}, this.duration)
}
},
// 判断日期是否为今天
theDateIsToday(item) {
if (`${item.year}${item.month}${item.date}` === `${this.getAssignDateInfo(true, 0)}${this.getAssignDateInfo(true, 1)}${this.getAssignDateInfo(true, 2)}`) {
item.isToday = true
}
},
// 计算收缩时的日历轮播日期信息
getCalendarShrinkSwiperDates() {
const [prevYM, curYM, nextYM] = this.getAdjacentYMD
// 本月日期数据
const curDates = this.monthDateCache[curYM]
// 计算当前日期所在行
const line = Math.floor(curDates.map(item => item.dateFormat).indexOf(this.selectedDate) / 7)
// 当前周日期信息
const cur = curDates.slice(line * 7, (line + 1) * 7)
let prev, next
/**
* 获取上一周日期信息
* 注意:当选中日期为第一周要额外判断,如果刚好为日历的第一天,则上一周数据应为上一个月的最后一周,否则为上一个月的倒数第二周
*/
if (line === 0) {
// 获取上个月日历数据
const prevDates = this.monthDateCache[prevYM]
// 获取上个月的日历行数
const prevDatesLine = prevDates.length / 7
if (curDates[0].dateFormat === this.selectedDate) { // 选中日期刚好为日历第一天
prev = prevDates.slice((prevDatesLine - 1) * 7) // 上个月倒数第一周数据
} else {
prev = prevDates.slice((prevDatesLine - 2) * 7, (prevDatesLine - 1) * 7) // 上个月倒数第二周数据
}
} else {
prev = curDates.slice((line - 1) * 7, line * 7)
}
/**
* 获取下一周日期信息
* 注意:当选中日期为最后一周要额外判断,如果刚好为日历的最后一天,则下一周数据应为下一个月的第一周,否则为下一个月的第二周
*/
if (line + 1 === curDates.length / 7) {
// 获取下个月的日期数据
const nextDates = this.monthDateCache[nextYM]
if (curDates[curDates.length - 1].dateFormat === this.selectedDate) { // 选中日期刚好为日历最后一天
next = nextDates.slice(0, 7) // 下个月第一周数据
} else {
next = nextDates.slice(7, 14) // 下个月第二周数据
}
} else {
next = curDates.slice((line + 1) * 7, (line + 2) * 7)
}
return this.adjacentSortByCurrent(prev, cur, next)
},
// 手动切换日历
switchCalendar(type) {
const currentKey = this.swiperMode === 'close' ? 'shrinkCurrent' : 'current'
const v = this[currentKey] + (type === 'prev' ? -1 : 1)
this[currentKey] = v === -1 ? 2 : v === 3 ? 0 : v
},
// 获取月的一号日期/周的第一天
getPrevOrNextDate(type) {
if (this.swiperMode === 'open') {
const year = this.getAssignDateInfo(false, 0)
let month = this.getAssignDateInfo(false, 1)
month = month + type
// 判断切换月份时选中当前日期高亮还是一号,若选中当前日期高亮需进行大小判断
const curActiveDate = this.getAssignDateInfo(false, 2)
const maxDate = new Date(year, month, 0).getDate()
const date = this.changeSetDefault ? 1 : curActiveDate > maxDate ? maxDate : curActiveDate
this.selectedDate = parseTime(new Date(year, month - 1, date), '{y}-{m}-{d}')
} else {
let current = this.current + type < 0 ? 2 : this.current + type > 2 ? 0 : this.current + type
this.selectedDate = this.getcurCalendarDates[current][0].dateFormat
}
},
// 前往某一天 格式 YYYY-MM | YYYY-MM-DD
goToDate(date = this.today) {
try {
if (date.split('-').length < 2 || date.split('-').length > 3) throw '参数有误'
if (date.split('-').length === 2) {
date += '-01'
}
} catch (err) {
throw Error('请检查参数是否符合规范')
}
this.selectedDate = date
this.generateAdjacentMonthDate()
},
// 日历轮播展开的情况下选择日期
chooseDate(dateInfo) {
// 重复点击后续不做处理
if (dateInfo.dateFormat === this.selectedDate) return false
if (this.swiperMode === 'open') { // 展开
// 是否点击了上个月份的后几天或者点击了下个月份的前几天
if (dateInfo.type !== 'cur') {
if (dateInfo.type === 'prev') { // 点击了上个月份的后几天,滑到上个月
this.current = this.current === 0 ? 2 : this.current - 1
} else { // 点击了下个月份的前几天,滑到下个月
this.current = this.current === 2 ? 0 : this.current + 1
}
// 将选中日期赋值为当前点击的那个日期
this.swiperChangeByClick = true
} else {
this.dateClick = true
}
} else { // 收缩
// 是否点击了上个月份的后几天或者点击了下个月份的前几天
if (dateInfo.type !== 'cur') {
// 将选中日期赋值为当前点击的那个日期
this.swiperChangeByClick = true
}
this.dateClick = true
}
// 将当前选中的日期清空并选中最新的日期
this.selectedDate = dateInfo.dateFormat
},
// 向父组件传递当前选中数据
emitDate() {
const e = {
selectedDate: this.selectedDate
}
this.$emit('change', e)
}
}
}
</script>
<style>
.zsy_calendar {
width: 100%;
padding: 20rpx 0;
box-sizing: border-box;
background-color: #fff;
border-radius: 20rpx 20rpx 0 0;
}
.dakaBtn{
color: #55aa7f; display: flex; padding: 3rpx 5rpx; border: #55aa7f 1px solid; border-radius: 10rpx;
}
/* 日历顶部信息 */
.calendar_info {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20rpx;
}
.calendar_info .title {
font-size: 34rpx;
font-weight: bold;
color: #2C2C2C;
}
.calendar_info .desc {
margin-left: 29rpx;
font-size: 28rpx;
color: #959595;
}
.calendar_info .backToToday {
margin-left: auto;
font-size: 24rpx;
}
/* 日历顶部信息 */
/* 日历周数 */
.calendar_week {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 26rpx;
color: #959595;
margin: 20rpx 0rpx;
}
.calendar_week .calendar_week__item {
width: calc(100% / 7);
text-align: center;
}
/* 日历周数 */
/* 日历切换模式 */
.calendar_toggle {
position: relative;
padding: 10rpx 0;
margin: 10rpx 20rpx 0;
display: flex;
justify-content: center;
}
.calendar_toggle .icon {
width: 30rpx;
height: 30rpx;
background-image: url('../../static/zsy-calendar/arrow.png');
background-size: contain;
background-repeat: no-repeat;
margin: 0 auto;
transform: rotate(0deg);
transition: all .3s;
}
.icon.down {
transform: rotate(180deg);
}
.calendar_toggle::before, .calendar_toggle::after {
width: calc(50% - 30rpx);
border-top: solid 2rpx #EAEAEA;
content: '';
display: block;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.calendar_toggle::before {
left: 0;
}
.calendar_toggle::after {
right: 0;
}
/* 日历切换模式 */
</style>

View File

@@ -1,7 +1,7 @@
{
"name" : "疯子读书",
"appid" : "__UNI__9788EB5",
"description" : "疯子读书",
"name" : "吴门医述",
"appid" : "__UNI__C7475A8",
"description" : "吴门医述",
"networkTimeout" : {
"request" : 3000
},
@@ -12,8 +12,8 @@
"src" : "图片路径"
}
],
"versionName" : "1.2.44",
"versionCode" : 1244,
"versionName" : "1.0.0",
"versionCode" : 100,
"app-plus" : {
"compatible" : {
"ignoreVersion" : true
@@ -134,15 +134,15 @@
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
"app" : "",
"app@2x" : "",
"notification" : "",
"notification@2x" : "",
"proapp@2x" : "",
"settings" : "",
"settings@2x" : "",
"spotlight" : "",
"spotlight@2x" : ""
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",

View File

@@ -37,82 +37,6 @@
"enablePullDownRefresh": false
}
},
{
"path": "pages/eBook/1/bookComent",
"style": {
"navigationBarTitleText": "小说1"
}
},
{
"path": "pages/eBook/1/battery",
"style": {
"navigationBarTitleText": "小说1-1"
}
},
// {
// "path": "pages/eBook/1/bookComent",
// "style": {
// "navigationBarTitleText": "小说1-2"
// }
// },
{
"path": "pages/eBook/2/book",
"style": {
"navigationBarTitleText": "小说2"
}
},
{
"path": "pages/yRead/angbook",
"style": {
"navigationBarTitleText": "小说3",
"enablePullDownRefresh": false
}
},
{
"path": "pages/yRead/cus-audio-play",
"style": {
"navigationBarTitleText": "小说3-1",
"enablePullDownRefresh": false
}
},
{
"path": "pages/eBook/bookType",
"style": {
"navigationBarTitleText": "小说列表"
}
},
{
"path": "pages/eBook/bookList",
"style": {
"navigationBarTitleText": "小说列表"
}
},
{
"path": "pages/eBook/bookContent",
"style": {
"navigationBarTitleText": "小说详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/eBook/bookMessage",
"style": {
"navigationBarTitleText": "小说简介",
"enablePullDownRefresh": false
}
},
{
"path": "pages/eBook/bookRecord",
"style": {
"navigationBarTitleText": "阅读记录"
}
},
{
"path": "pages/eBook/bookBuy",
"style": {
"navigationBarTitleText": "购买记录"
}
},
{
"path": "pages/peanut/opeVip",
"style": {
@@ -266,104 +190,6 @@
"enablePullDownRefresh": false
}
},
{
"path": "pages/listen/listen",
"style": {
"navigationBarTitleText": "悦耳列表",
"enablePullDownRefresh": false
}
},
{
"path": "pages/listen/home",
"style": {
"navigationBarTitleText": "悦耳听书",
"enablePullDownRefresh": true
}
},
{
"path": "pages/listen/search",
"style": {
"navigationBarTitleText": "搜索听书",
"enablePullDownRefresh": false
}
},
{
"path": "pages/listen/bgMusix",
"style": {
"navigationBarTitleText": "背景音乐模式",
"enablePullDownRefresh": false
}
},
{
"path": "pages/listen/bgMusic",
"style": {
"navigationBarTitleText": "背景音乐启用",
"enablePullDownRefresh": false
}
},
{
"path": "pages/listen/bgMusic",
"style": {
"navigationBarTitleText": "背景音乐启用",
"enablePullDownRefresh": false
}
},
{
"path": "pages/listen/musicbg",
"style": {
"navigationBarTitleText": "音乐1",
"enablePullDownRefresh": false
}
},
{
"path": "pages/peanut/myComments",
"style": {
"navigationBarTitleText": "我的评价",
"enablePullDownRefresh": false
}
},
{
"path": "pages/listen/setListen",
"style": {
"navigationBarTitleText": "听书设置11",
"enablePullDownRefresh": false
}
},
{
"path": "pages/listen/bigListen",
"style": {
"navigationBarTitleText": "听书页面",
"enablePullDownRefresh": false
}
},
{
"path": "pages/listen/listenNotBuy",
"style": {
"navigationBarTitleText": "未购买的详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/comments/comments",
"style": {
"navigationBarTitleText": "书评1",
"enablePullDownRefresh": true
}
},
{
"path": "pages/comments/commentsDetail",
"style": {
"navigationBarTitleText": "书评详情1",
"enablePullDownRefresh": false
}
},
{
"path": "pages/comments/commentsList",
"style": {
"navigationBarTitleText": "书评",
"enablePullDownRefresh": true
}
},
{
"path": "pages/bookShop/settlementBook",
"style": {
@@ -371,76 +197,6 @@
"enablePullDownRefresh": false
}
},
{
"path": "pages/library/library",
"style": {
"navigationBarTitleText": "我的图书",
"enablePullDownRefresh": true
}
},
{
"path": "pages/clock/clock",
"style": {
"navigationBarTitleText": "读书打卡",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clock/index",
"style": {
"navigationBarTitleText": "读书打卡列表",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clock/clockList",
"style": {
"navigationBarTitleText": "打卡记录1",
"enablePullDownRefresh": false
}
},
{
"path": "pages/talkBook/talkBook",
"style": {
"navigationBarTitleText": "讲书",
"enablePullDownRefresh": true
}
},
{
"path": "pages/talkBook/talkBookML",
"style": {
"navigationBarTitleText": "讲书书籍页面",
"enablePullDownRefresh": true
}
},
{
"path": "pages/talkBook/talkBookDetail",
"style": {
"navigationBarTitleText": "讲书详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/yian/yian",
"style": {
"navigationBarTitleText": "医案",
"enablePullDownRefresh": true
}
},
{
"path": "pages/yian/yianList",
"style": {
"navigationBarTitleText": "医案列表",
"enablePullDownRefresh": true
}
},
{
"path": "pages/yian/yianDetail",
"style": {
"navigationBarTitleText": "医案详情",
"enablePullDownRefresh": false
}
},
{ // 更新版本
"path": "uni_modules/uni-upgrade-center-app/pages/upgrade-popup",
"style": {
@@ -471,159 +227,28 @@
}
},
{
"path": "pages/acupoint/acupoint",
"style": {
"navigationBarTitleText": "穴位检索",
"enablePullDownRefresh": false
}
},
{
"path": "pages/acupoint/acupointDetail",
"style": {
"navigationBarTitleText": "脉穴详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/acupoint/givenDegree",
"style": {
"navigationBarTitleText": "特定穴位",
"enablePullDownRefresh": false
}
},
{
"path": "pages/timeAcupoint/timeAcupoint",
"style": {
"navigationBarTitleText": "时辰取穴",
"enablePullDownRefresh": false
}
},
{
"path": "pages/timeAcupoint/totalTable",
"style": {
"navigationBarTitleText": "全部穴位一览表",
"enablePullDownRefresh": false
}
},
{
"path": "pages/prescript/prescript",
"style": {
"navigationBarTitleText": "方药检索",
"enablePullDownRefresh": false
}
},
{
"path": "pages/prescript/prescriptDetail",
"style": {
"navigationBarTitleText": "方剂详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/prescript/medicineSearchDetail",
"style": {
"navigationBarTitleText": "药物详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/prescript/CNMedicineSearch",
"style": {
"navigationBarTitleText": "中药检索",
"enablePullDownRefresh": false
}
},
{
"path": "pages/prescript/CNMedicineSearchDetail",
"style": {
"navigationBarTitleText": "中药详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/prescript/CNMedicineText",
"style": {
"navigationBarTitleText": "中药搜索",
"enablePullDownRefresh": false
}
},
{
"path": "pages/medicaldes/medicaldes",
"style": {
"navigationBarTitleText": "吴门医述",
"enablePullDownRefresh": false
}
},
{
"path": "pages/medicaldes/zhuanzhuchuban",
"style": {
"navigationBarTitleText": "专著出版",
"enablePullDownRefresh": false
}
},
{
"path": "pages/medicaldes/xueshugongxianDetail",
"style": {
"navigationBarTitleText": "学术贡献详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/medicaldes/medicaldesDetail",
"style": {
"navigationBarTitleText": "医述详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/medicaldes/recordDetail",
"style": {
"navigationBarTitleText": "纪实详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/medicaldes/video",
"style": {
"navigationBarTitleText": "医述详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/luck/luck",
"style": {
"navigationBarTitleText": "五运六气",
"enablePullDownRefresh": false
}
},
{
"path": "pages/classic/classic",
"style": {
"navigationBarTitleText": "国学经典",
"path" : "pages/news/news",
"style" :
{
"navigationBarTitleText" : "news",
"enablePullDownRefresh": false
}
}
// {
// "path": "pages/agreement/yszcPage",
// "style": {
// "navigationBarTitleText": "隐私政策"
// }
// }
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
// "navigationBarTitleText": "启动页",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarBackgroundColor": "#343434",
"backgroundColor": "#FFFFFF",
"navigationStyle": "custom",
"enablePullDownRefresh": true
},
"tabBar": {
"color": "#444444",
"color": "#fff",
"selectedColor": "#079307",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"backgroundColor": "#343434",
"list": [
{
"pagePath": "pages/peanut/home",
@@ -631,41 +256,23 @@
"selectedIconPath": "static/tab/icon1_y.png",
"text": "首页"
},
// {
// "pagePath": "pages/peanut/shopping",
// "iconPath": "static/tab/icon2_n.png",
// "selectedIconPath": "static/tab/icon2_y.png",
// "text": "购物车"
// },
{
"pagePath": "pages/medicaldes/medicaldes",
"iconPath": "static/icon/five5_n.png",
"selectedIconPath": "static/icon/five5.png",
"text": "吴门医述"
"pagePath": "pages/peanut/shopping",
"iconPath": "static/tab/tab_nor_02.png",
"selectedIconPath": "static/tab/tab_cur_02.png",
"text": "购物车"
},
{
"pagePath": "pages/library/library",
"iconPath": "static/tab/icon3_n.png",
"selectedIconPath": "static/tab/icon3_y.png",
"text": "我的图书"
"iconPath": "static/tab/tab_nor_03.png",
"selectedIconPath": "static/tab/tab_cur_03.png",
"text": "太湖公益"
},
// {
// "pagePath": "pages/peanut/bookshelf",
// "iconPath": "static/tab/icon3_n.png",
// "selectedIconPath": "static/tab/icon3_y.png",
// "text": "我的书架"
// },
// {
// "pagePath": "pages/bookShop/orderList",
// "iconPath": "static/tab/icon2_n.png",
// "selectedIconPath": "static/tab/icon2_y.png",
// "text": "我的订单"
// },
{
"pagePath": "pages/peanut/mine",
"iconPath": "static/tab/icon4_n.png",
"selectedIconPath": "static/tab/icon4_y.png",
"text": "我"
"iconPath": "static/tab/tab_nor_04.png",
"selectedIconPath": "static/tab/tab_cur_04.png",
"text": "我"
}
]
},

View File

@@ -1,65 +1,65 @@
<template>
<view>
<view class="dp_title">疯子读书软件许可及服务协议</view>
<view class="dp_title">吴门医述软件许可及服务协议</view>
<view class="dp_content">
<view>导言</view>
<view>欢迎你使用疯子读书软件及服务 </view>
<view>为使用疯子读书软件及服务以下简称本软件疯子读书服务本服务你应当阅读并遵守疯子读书软件许可及服务协议以下简称本协议以及会员订阅服务条款疯子读书服务的各项制度规范
<view>欢迎你使用吴门医述软件及服务 </view>
<view>为使用吴门医述软件及服务以下简称本软件吴门医述服务本服务你应当阅读并遵守吴门医述软件许可及服务协议以下简称本协议以及会员订阅服务条款吴门医述服务的各项制度规范
</view>
<view>请你务必审慎阅读充分理解各条款内容特别是免除或限制疯子读书责任的相应条款以及开通或使用某项服务如无限卡会员订阅服务的单独协议并选择接受或不接受限制免责条款可能以加粗形式提示你注意
<view>请你务必审慎阅读充分理解各条款内容特别是免除或限制吴门医述责任的相应条款以及开通或使用某项服务如无限卡会员订阅服务的单独协议并选择接受或不接受限制免责条款可能以加粗形式提示你注意
</view>
<view>除非你已阅读并接受本协议所有条款否则你无权下载安装或使用本软件及相关服务你的下载安装使用登录等行为即视为你已阅读并同意上述协议的约束 </view>
<view>你有违反本协议的任何行为时疯子读书有权依照违反情况随时单方限制中止或终止向你提供本服务并有权追究你的相关责任
<view>你有违反本协议的任何行为时吴门医述有权依照违反情况随时单方限制中止或终止向你提供本服务并有权追究你的相关责任
如果你未满18周岁请在监护人的陪同下阅读本协议及其他上述协议并特别注意未成年人使用条款 </view>
<view class="dp_con1">协议的范围 </view>
<view class="dp_con2">1. 本协议是你与疯子读书之间关于你下载安装使用复制本软件以及使用疯子读书相关服务所订立的协议</view>
<view class="dp_con2">1. 本协议是你与吴门医述之间关于你下载安装使用复制本软件以及使用吴门医述相关服务所订立的协议</view>
<view class="dp_con2">2.
本协议被视为疯子读书服务协议疯子读书微信软件许可及服务协议的补充协议是其不可分割的组成部分与其构成统一整体本协议与上述内容存在冲突的以本协议为准
本协议被视为吴门医述服务协议吴门医述微信软件许可及服务协议的补充协议是其不可分割的组成部分与其构成统一整体本协议与上述内容存在冲突的以本协议为准
</view>
<view class="dp_con2">3. 本协议内容同时包括疯子读书可能不断发布的关于本服务的相关协议服务声明业务规则及公告指引等内容以下统称为专项规则上述内容一经正式发布即为本协议不可分割的组成部分你同样应当遵守
<view class="dp_con2">3. 本协议内容同时包括吴门医述可能不断发布的关于本服务的相关协议服务声明业务规则及公告指引等内容以下统称为专项规则上述内容一经正式发布即为本协议不可分割的组成部分你同样应当遵守
</view>
<view class="dp_con1">术语定义 </view>
<view class="dp_con2">1.
疯子读书软件是指疯子读书向用户提供的购买阅读赠送分享电子读物发布读书想法等服务的客户端软件你启用本软件后可以阅读赠送分享评论你通过本服务购买的电子读物你也可以在你的微信好友允许的情况下浏览微信好友通过本服务阅读分享的读物及其读书想法等
吴门医述软件是指吴门医述向用户提供的购买阅读赠送分享电子读物发布读书想法等服务的客户端软件你启用本软件后可以阅读赠送分享评论你通过本服务购买的电子读物你也可以在你的微信好友允许的情况下浏览微信好友通过本服务阅读分享的读物及其读书想法等
</view>
<view class="dp_con2">2. 疯子读书是指天津众妙之门科技有限公司及其相关服务可能存在的运营关联单位 </view>
<view class="dp_con2">3. 用户是指启用浏览或上传数据至疯子读书服务的用户在本协议中也称为 </view>
<view class="dp_con2">4. 其他用户是指除用户本人外与疯子读书服务相关的其他微信用户 </view>
<view class="dp_con2">2. 吴门医述是指天津众妙之门科技有限公司及其相关服务可能存在的运营关联单位 </view>
<view class="dp_con2">3. 用户是指启用浏览或上传数据至吴门医述服务的用户在本协议中也称为 </view>
<view class="dp_con2">4. 其他用户是指除用户本人外与吴门医述服务相关的其他微信用户 </view>
<view class="dp_con1">关于本软件 </view>
<view class="dp_con2">1.服务许可 </view>
<view>本软件可能提供多个应用版本用户必须选择与所安装设备相匹配的软件版本各应用版本之间的功能可能不一致具体以相应版本中展示的为准用户可根据本协议获得以下许可 </view>
<view>1.1 疯子读书给予你一项个人的不可转让及非排他性的许可以使用本软件你可以为非商业目的在单一台终端设备上安装使用显示运行本软件 </view>
<view>1.1 吴门医述给予你一项个人的不可转让及非排他性的许可以使用本软件你可以为非商业目的在单一台终端设备上安装使用显示运行本软件 </view>
<view>1.2 你可以为使用本软件的目的复制本软件的一个副本仅用作备份备份副本必须包含原软件中含有的所有著作权信息 </view>
<view>1.3 本条及本协议其他条款未明示授权的其他一切权利仍由疯子读书保留你在行使这些权利时须另外取得疯子读书的书面许可疯子读书如果未行使前述任何权利并不构成对该权利的放弃 </view>
<view>1.3 本条及本协议其他条款未明示授权的其他一切权利仍由吴门医述保留你在行使这些权利时须另外取得吴门医述的书面许可吴门医述如果未行使前述任何权利并不构成对该权利的放弃 </view>
<view class="dp_con2">2.安装与卸载 </view>
<view>2.1
你可以直接从疯子读书的网站上获取本软件也可以从得到疯子读书授权的第三方获取如果你从未经疯子读书授权的第三方获取本软件或与本软件名称相同的安装程序疯子读书无法保证本软件能够正常使用并对因此给你造成的损失不予负责
你可以直接从吴门医述的网站上获取本软件也可以从得到吴门医述授权的第三方获取如果你从未经吴门医述授权的第三方获取本软件或与本软件名称相同的安装程序吴门医述无法保证本软件能够正常使用并对因此给你造成的损失不予负责
</view>
<view>2.2
疯子读书可能为不同的终端设备开发了不同的软件版本你应当根据实际情况选择下载合适的版本进行安装下载安装程序后你需要按照该程序提示的步骤正确安装为提供更加优质安全的服务在本软件安装时疯子读书可能推荐你安装其他软件你可以选择安装或不安装
吴门医述可能为不同的终端设备开发了不同的软件版本你应当根据实际情况选择下载合适的版本进行安装下载安装程序后你需要按照该程序提示的步骤正确安装为提供更加优质安全的服务在本软件安装时吴门医述可能推荐你安装其他软件你可以选择安装或不安装
</view>
<view>2.3 如果你不再需要使用本软件或者需要安装新版软件可以自行卸载如果你愿意帮助疯子读书改进产品服务请告知卸载的原因 </view>
<view>2.3 如果你不再需要使用本软件或者需要安装新版软件可以自行卸载如果你愿意帮助吴门医述改进产品服务请告知卸载的原因 </view>
<view>2.4
为了改善用户体验完善服务内容疯子读书将不断努力开发新的服务并为你不时提供软件更新这些更新可能会采取软件替换修改功能强化版本升级等形式为了保证本软件安全性和功能的一致性疯子读书有权不经向你特别通知而对软件进行更新或者对软件的部分功能效果进行改变或限制本软件新版本发布后旧版本的软件可能无法使用疯子读书不保证旧版本软件继续可用及相应的客户服务请你随时核对并下载最新版本
为了改善用户体验完善服务内容吴门医述将不断努力开发新的服务并为你不时提供软件更新这些更新可能会采取软件替换修改功能强化版本升级等形式为了保证本软件安全性和功能的一致性吴门医述有权不经向你特别通知而对软件进行更新或者对软件的部分功能效果进行改变或限制本软件新版本发布后旧版本的软件可能无法使用吴门医述不保证旧版本软件继续可用及相应的客户服务请你随时核对并下载最新版本
</view>
<view class="dp_con1">用户个人信息保护 </view>
<view class="dp_con2">1.
保护用户个人信息是疯子读书的一项基本原则疯子读书将会采取合理的措施保护用户的个人信息除法律法规规定或本协议另有约定的情形外未经用户许可疯子读书不会向第三方公开透露用户个人信息疯子读书对相关信息采用专业加密存储与传输方式保障用户个人信息的安全
保护用户个人信息是吴门医述的一项基本原则吴门医述将会采取合理的措施保护用户的个人信息除法律法规规定或本协议另有约定的情形外未经用户许可吴门医述不会向第三方公开透露用户个人信息吴门医述对相关信息采用专业加密存储与传输方式保障用户个人信息的安全
</view>
<view class="dp_con2">2.
你使用本服务的部分功能前需要有一个成功注册的微信帐号并通过该微信帐号进行授权授权内容包括但不限于获得该微信帐号的公开信息昵称头像等寻找与你共同使用该应用的微信好友帮助你分享信息到朋友圈等对于你的微信帐号信息疯子读书将采用专业加密存储与传输方式保障信息安全不会擅自收集利用透露或公开用户有责任妥善保管你的微信帐号信息及帐号密码的安全因你自身的原因导致微信帐号及密码泄漏而造成的本服务下相关信息的泄露篡改删除等后果疯子读书不承担任何责任
你使用本服务的部分功能前需要有一个成功注册的微信帐号并通过该微信帐号进行授权授权内容包括但不限于获得该微信帐号的公开信息昵称头像等寻找与你共同使用该应用的微信好友帮助你分享信息到朋友圈等对于你的微信帐号信息吴门医述将采用专业加密存储与传输方式保障信息安全不会擅自收集利用透露或公开用户有责任妥善保管你的微信帐号信息及帐号密码的安全因你自身的原因导致微信帐号及密码泄漏而造成的本服务下相关信息的泄露篡改删除等后果吴门医述不承担任何责任
</view>
<view class="dp_con2">3. 疯子读书将运用各种安全技术和程序建立完善的管理制度来保护你的个人信息以免遭受未经授权的访问使用或披露 </view>
<view class="dp_con2">4. 未经你的同意疯子读书不会向疯子读书以外的任何公司组织和个人披露你的个人信息但法律法规另有规定或本协议另有约定的除外 </view>
<view class="dp_con2">3. 吴门医述将运用各种安全技术和程序建立完善的管理制度来保护你的个人信息以免遭受未经授权的访问使用或披露 </view>
<view class="dp_con2">4. 未经你的同意吴门医述不会向吴门医述以外的任何公司组织和个人披露你的个人信息但法律法规另有规定或本协议另有约定的除外 </view>
<view class="dp_con1">用户注意事项 </view>
<view class="dp_con2">1. 你理解并同意为了向你提供有效的服务本软件会利用你设备终端的处理器和带宽等资源本软件使用过程中可能产生数据流量的费用用户需自行向运营商了解相关资费信息并自行承担相关费用 </view>
<view class="dp_con2">2. 你在使用本软件某一特定服务时该服务可能会另有单独的协议专项规则等你在使用该项服务前请阅读并同意相关的单独协议专项规则包括但不限于适用于无限卡会员订阅服务的会员订阅服务条款
</view>
<view class="dp_con2">3. 你理解并同意疯子读书将会尽其商业上的合理努力保障你在本软件中的数据存储安全但是疯子读书并不能就此提供完全保证包括但不限于以下情形 </view>
<view>3.1 疯子读书不对你在本软件中相关数据的删除或储存失败负责 </view>
<view>3.2 疯子读书有权根据实际情况自行决定单个用户在本软件中数据的最长储存期限并在服务器上为其分配数据最大存储空间等 </view>
<view>3.3 如果你停止使用本软件或服务被终止或取消疯子读书可以从服务器上永久地删除你的数据服务停止终止或取消后疯子读书没有义务向你返还任何数据 </view>
<view class="dp_con2">4. 用户在使用本软件时须自行承担如下来自疯子读书不可掌控的风险内容包括但不限于</view>
<view class="dp_con2">3. 你理解并同意吴门医述将会尽其商业上的合理努力保障你在本软件中的数据存储安全但是吴门医述并不能就此提供完全保证包括但不限于以下情形 </view>
<view>3.1 吴门医述不对你在本软件中相关数据的删除或储存失败负责 </view>
<view>3.2 吴门医述有权根据实际情况自行决定单个用户在本软件中数据的最长储存期限并在服务器上为其分配数据最大存储空间等 </view>
<view>3.3 如果你停止使用本软件或服务被终止或取消吴门医述可以从服务器上永久地删除你的数据服务停止终止或取消后吴门医述没有义务向你返还任何数据 </view>
<view class="dp_con2">4. 用户在使用本软件时须自行承担如下来自吴门医述不可掌控的风险内容包括但不限于</view>
<view>4.1 由于信息网络设备维护连接故障系统故障电力故障罢工暴乱火灾洪水风暴爆炸战争政府行为司法行政机关的命令或因第三方因素可能引起的个人信息丢失泄漏及其他损害等风险
</view>
<view>4.2 如使用本客户端软件用户必须选择与所安装设备相匹配的软件版本否则由于软件与设备型号不相匹配所导致的任何问题或损害均由用户自行承担 </view>
@@ -72,11 +72,11 @@
<view class="dp_con1">用户行为规范 </view>
<view class="dp_con2">1. 服务使用规范 </view>
<view>1.1
你应遵守本协议使用本服务你理解并同意本服务是你与其他用户之间就读物阅读进行信息交流的平台疯子读书不鼓励你在未经其他用户允许的前提下将其他用户使用本服务所产生的软件使用信息对外转发分享传播或用作其他违法或不合理用途
你应遵守本协议使用本服务你理解并同意本服务是你与其他用户之间就读物阅读进行信息交流的平台吴门医述不鼓励你在未经其他用户允许的前提下将其他用户使用本服务所产生的软件使用信息对外转发分享传播或用作其他违法或不合理用途
</view>
<view class="dp_con2">2. 信息内容规范 </view>
<view>2.1 本条所述信息内容是指用户使用本服务过程中所制作复制发布传播的任何内容包括但不限于图片文字相关链接页面等使用本服务所产生的内容 </view>
<view>2.2 你理解并同意疯子读书一直致力于为用户提供文明健康规范有序的网络环境你不得利用本服务制作复制发布传播如下干扰本服务正常运营以及侵犯其他用户或第三方合法权益的内容包括但不限于
<view>2.2 你理解并同意吴门医述一直致力于为用户提供文明健康规范有序的网络环境你不得利用本服务制作复制发布传播如下干扰本服务正常运营以及侵犯其他用户或第三方合法权益的内容包括但不限于
</view>
<view>2.2.1 发布传送传播储存违反国家法律法规禁止的内容 </view>
<view>1违反宪法确定的基本原则的 </view>
@@ -100,49 +100,49 @@
<view>3.2 诱导其他用户点击链接页面或分享信息的 </view>
<view>3.3 虚构事实隐瞒真相以误导欺骗他人的 </view>
<view>3.4 侵害他人名誉权肖像权知识产权商业秘密等合法权利的 </view>
<view>3.5 未经疯子读书书面许可利用微信帐号和任何服务以及第三方运营平台进行推广或互相推广的 </view>
<view>3.5 未经吴门医述书面许可利用微信帐号和任何服务以及第三方运营平台进行推广或互相推广的 </view>
<view>3.6 利用本软件及服务从事任何违法犯罪活动的 </view>
<view>3.7 制作发布与以上行为相关的方法工具或对此类方法工具进行运营或传播无论这些行为是否为商业目的 </view>
<view>3.8 其他违反法律法规规定侵犯其他用户合法权益干扰产品正常运营或疯子读书未明示授权的行为 </view>
<view>3.8 其他违反法律法规规定侵犯其他用户合法权益干扰产品正常运营或吴门医述未明示授权的行为 </view>
<view class="dp_con2">4.对自己行为负责 </view>
<view>
你充分了解并同意你必须为自己注册帐号下的一切行为负责包括你所发表的任何内容以及由此产生的任何后果你应对本服务中的内容自行加以判断并承担因使用内容而引起的所有风险包括因对内容的正确性完整性或实用性的依赖而产生的风险同时你应在本协议约定的范围内使用本服务因你利用本服务进行违反法律法规本协议专项规则的行为所产生的风险亦由你自行承担疯子读书无法且不会对因前述风险而导致的任何损失或损害承担责任
你充分了解并同意你必须为自己注册帐号下的一切行为负责包括你所发表的任何内容以及由此产生的任何后果你应对本服务中的内容自行加以判断并承担因使用内容而引起的所有风险包括因对内容的正确性完整性或实用性的依赖而产生的风险同时你应在本协议约定的范围内使用本服务因你利用本服务进行违反法律法规本协议专项规则的行为所产生的风险亦由你自行承担吴门医述无法且不会对因前述风险而导致的任何损失或损害承担责任
</view>
<view class="dp_con1">管理规范 </view>
<view class="dp_con2">
1.
疯子读书有权根据国家相关法规政策按照本协议的规定对你发布传送传播储存的内容进行审查以保证用户使用本服务的行为不违反法律法规及社会公共道德准则不侵犯疯子读书或第三方的合法权益不带有诋毁疯子读书及其产品形象的要素但并不因为疯子读书的审核而减轻你自身使用本服务时应承担的责任由此产生的一切责任和后果仍由你单独承担
吴门医述有权根据国家相关法规政策按照本协议的规定对你发布传送传播储存的内容进行审查以保证用户使用本服务的行为不违反法律法规及社会公共道德准则不侵犯吴门医述或第三方的合法权益不带有诋毁吴门医述及其产品形象的要素但并不因为吴门医述的审核而减轻你自身使用本服务时应承担的责任由此产生的一切责任和后果仍由你单独承担
</view>
<view class="dp_con2">
2.
如果疯子读书发现或收到他人举报或投诉用户违反本协议约定的疯子读书有权不经通知随时对相关内容进行删除屏蔽并视行为情节对违规帐号处以包括但不限于警告限制或禁止使用部分或全部服务帐号封禁直至注销的处罚并公告处理结果
如果吴门医述发现或收到他人举报或投诉用户违反本协议约定的吴门医述有权不经通知随时对相关内容进行删除屏蔽并视行为情节对违规帐号处以包括但不限于警告限制或禁止使用部分或全部服务帐号封禁直至注销的处罚并公告处理结果
</view>
<view class="dp_con2">
3.
你理解并同意疯子读书有权依合理判断对违反有关法律法规或本协议规定的行为进行处罚对违法违规的任何用户采取适当的法律行动并依据法律法规保存有关信息向有关部门报告等用户应独自承担由此而产生的一切法律责任
你理解并同意吴门医述有权依合理判断对违反有关法律法规或本协议规定的行为进行处罚对违法违规的任何用户采取适当的法律行动并依据法律法规保存有关信息向有关部门报告等用户应独自承担由此而产生的一切法律责任
</view>
<view class="dp_con2">4. 你理解并同意因你违反本协议或相关服务条款的规定导致或产生第三方主张的任何索赔要求或损失你应当独立承担责任疯子读书因此遭受损失的你也应当一并赔偿 </view>
<view class="dp_con2">4. 你理解并同意因你违反本协议或相关服务条款的规定导致或产生第三方主张的任何索赔要求或损失你应当独立承担责任吴门医述因此遭受损失的你也应当一并赔偿 </view>
<view class="dp_con1">知识产权声明 </view>
<view class="dp_con2">1.
疯子读书是本软件的知识产权权利人本软件的一切著作权商标权专利权商业秘密等知识产权以及与本软件相关的所有信息内容包括但不限于文字图片音频视频图表界面设计版面框架有关数据或电子文档等均受中华人民共和国法律法规和相应的国际条约保护疯子读书享有上述知识产权但相关权利人依照法律规定应享有的权利除外
吴门医述是本软件的知识产权权利人本软件的一切著作权商标权专利权商业秘密等知识产权以及与本软件相关的所有信息内容包括但不限于文字图片音频视频图表界面设计版面框架有关数据或电子文档等均受中华人民共和国法律法规和相应的国际条约保护吴门医述享有上述知识产权但相关权利人依照法律规定应享有的权利除外
</view>
<view class="dp_con2">2. 未经疯子读书或相关权利人书面同意你不得为任何商业或非商业目的自行或许可任何第三方实施利用转让上述知识产权 </view>
<view class="dp_con2">2. 未经吴门医述或相关权利人书面同意你不得为任何商业或非商业目的自行或许可任何第三方实施利用转让上述知识产权 </view>
<view class="dp_con1">终端安全责任 </view>
<view class="dp_con2">1.
你理解并同意本软件同大多数互联网软件一样可能会受多种因素影响包括但不限于用户原因网络服务质量社会环境等也可能会受各种安全问题的侵扰包括但不限于他人非法利用用户资料进行现实中的骚扰用户下载安装的其他软件或访问的其他网站中可能含有病毒木马程序或其他恶意程序威胁你的终端设备信息和数据安全继而影响本软件的正常使用等因此你应加强信息安全及个人信息的保护意识注意密码保护以免遭受损失
</view>
<view class="dp_con2">2. 你不得制作发布使用传播用于窃取微信帐号及他人个人信息财产的恶意程序 </view>
<view class="dp_con2">3. 维护软件安全与正常使用是疯子读书和你的共同责任疯子读书将按照行业标准合理审慎地采取必要技术措施保护你的终端设备信息和数据安全但是你承认和同意疯子读书并不能就此提供完全保证 </view>
<view class="dp_con2">4. 在任何情况下你不应轻信借款索要密码或其他涉及财产的网络信息涉及财产操作的请一定先核实对方身份并请经常留意疯子读书有关防范诈骗犯罪的提示 </view>
<view class="dp_con2">3. 维护软件安全与正常使用是吴门医述和你的共同责任吴门医述将按照行业标准合理审慎地采取必要技术措施保护你的终端设备信息和数据安全但是你承认和同意吴门医述并不能就此提供完全保证 </view>
<view class="dp_con2">4. 在任何情况下你不应轻信借款索要密码或其他涉及财产的网络信息涉及财产操作的请一定先核实对方身份并请经常留意吴门医述有关防范诈骗犯罪的提示 </view>
<view class="dp_con1">未成年人保护 </view>
<view class="dp_con2">疯子读书非常重视对未成年人个人信息的保护若你是18周岁以下的未成年人在使用疯子读书的服务前应事先取得你监护人的书面同意</view>
<view class="dp_con2">吴门医述非常重视对未成年人个人信息的保护若你是18周岁以下的未成年人在使用吴门医述的服务前应事先取得你监护人的书面同意</view>
<view class="dp_con1">十一其他 </view>
<view class="dp_con2">1.
你使用本软件即视为你已阅读并同意受本协议的约束疯子读书有权在必要时修改本协议条款你可以在本软件的最新版本中查阅相关协议条款本协议条款变更后如果你继续使用本软件即视为你已接受修改后的协议如果你不接受修改后的协议应当停止使用本软件
你使用本软件即视为你已阅读并同意受本协议的约束吴门医述有权在必要时修改本协议条款你可以在本软件的最新版本中查阅相关协议条款本协议条款变更后如果你继续使用本软件即视为你已接受修改后的协议如果你不接受修改后的协议应当停止使用本软件
</view>
<view class="dp_con2">2. 本协议签订地为中华人民共和国天津市南开区 </view>
<view class="dp_con2">3. 本协议的成立生效履行解释及纠纷解决适用中华人民共和国大陆地区法律不包括冲突法 </view>
<view class="dp_con2">4. 若你和疯子读书之间发生任何纠纷或争议首先应友好协商解决协商不成的你同意将纠纷或争议提交本协议签订地有管辖权的人民法院管辖 </view>
<view class="dp_con2">4. 若你和吴门医述之间发生任何纠纷或争议首先应友好协商解决协商不成的你同意将纠纷或争议提交本协议签订地有管辖权的人民法院管辖 </view>
<view class="dp_con2">5. 本协议所有条款的标题仅为阅读方便本身并无实际涵义不能作为本协议涵义解释的依据</view>
<view class="dp_con2">6. 本协议条款无论因何种原因部分无效或不可执行其余条款仍有效对双方具有约束力正文完 </view>
<view>天津众妙之门科技有限公司 </view>

View File

@@ -12,13 +12,13 @@
</view>
<view class="dp_con2">
2.
保护用户(特别是未成年人)的隐私是疯子读书的一项基本政策疯子读书将对用户所提供的资料进行严格的管理及保护并使用相应的技术防止用户的个人资料丢失被盗用或遭篡改保证不对外公开或向第三方提供单个用户的注册资料及用户在使用网络服务时存储在疯子读书的非公开内容但下列情况除外
保护用户(特别是未成年人)的隐私是吴门医述的一项基本政策吴门医述将对用户所提供的资料进行严格的管理及保护并使用相应的技术防止用户的个人资料丢失被盗用或遭篡改保证不对外公开或向第三方提供单个用户的注册资料及用户在使用网络服务时存储在吴门医述的非公开内容但下列情况除外
</view>
<view>2.1 事先获得用户的明确授权</view>
<view>2.2 根据有关的法律法规要求</view>
<view>2.3 按照相关政府主管部门的要求</view>
<view>2.4 为维护社会公众的利益</view>
<view>2.5 为维护疯子读书的合法权益</view>
<view>2.5 为维护吴门医述的合法权益</view>
<view class="dp_con2">
3. 任何时候如果您对我们的隐私策略有疑问请利用电子邮件huashengxiangyue@163.com联系我们我们会尽一切努力请合理适当的范围内立即改善这个问题
</view>
@@ -42,7 +42,7 @@
<view class="dp_con2">
3. 设备信息包括
</view>
<view>3.1 在使用疯子读书时可能获取并上传您的的设备信息Android_ID网络设备硬件地址MAC地址获取手机状态获取其中的设备序列号用于验证手机型号及安卓版本</view>
<view>3.1 在使用吴门医述时可能获取并上传您的的设备信息Android_ID网络设备硬件地址MAC地址获取手机状态获取其中的设备序列号用于验证手机型号及安卓版本</view>
<view>3.2 获取OAID用以标记设备唯一性</view>
<view>3.3 获取定位信息用于应用获取您的位置信息提供应用服务</view>
<view>3.4 获取软件安装列表用以第三方应用服务或链接</view>
@@ -89,13 +89,13 @@
我们会制定应急处理预案并在发生用户信息安全事件时立即启动应急预案努力阻止这些安全事件的影响和后果扩大一旦发生用户信息安全事件泄露丢失我们将按照法律法规的要求及时向您告知安全事件的基本情况和可能的影响我们已经采取或将要采取的处置措施您可自主防范和降低风险的建议对您的补救措施我们将及时将事件相关情况以推送通知短信及相关形式告知您难以逐一告知时我们会采取合理有效的方式发布公告同时我们还将按照相关监管部门要求上报用户信息安全事件的处置情况
</view>
<view class="dp_con1">知识产权</view>
<view class="dp_con2">1. 天津众妙之门科技有限公司系疯子读书的著作权人未经疯子读书许可用户不得对该软件进行反向工程reverse
<view class="dp_con2">1. 天津众妙之门科技有限公司系吴门医述的著作权人未经吴门医述许可用户不得对该软件进行反向工程reverse
engineer反向编译decompile或反汇编disassemble</view>
<view class="dp_con2">
2.
疯子读书提供的网络服务中包含的任何文本图片图形音频和/或视频资料均受版权商标和/或其它财产所有权法律的保护未经相关权利人同意上述资料均不得在任何媒体直接或间接发布播放出于播放或发布目的而改写或再发行或者被用于其他任何商业目的所有这些资料或资料的任何部分仅可作为私人和非商业用途而保存在用户终端内疯子读书不就由上述资料产生或在传送或递交全部或部分上述资料过程中产生的延误不准确错误和遗漏或从中产生或由此产生的任何损害赔偿以任何形式向用户或任何第三方负责
吴门医述提供的网络服务中包含的任何文本图片图形音频和/或视频资料均受版权商标和/或其它财产所有权法律的保护未经相关权利人同意上述资料均不得在任何媒体直接或间接发布播放出于播放或发布目的而改写或再发行或者被用于其他任何商业目的所有这些资料或资料的任何部分仅可作为私人和非商业用途而保存在用户终端内吴门医述不就由上述资料产生或在传送或递交全部或部分上述资料过程中产生的延误不准确错误和遗漏或从中产生或由此产生的任何损害赔偿以任何形式向用户或任何第三方负责
</view>
<view class="dp_con2">3. 疯子读书所有作品内容仅代表作者自己的立场和观点疯子读书无关由作者本人承担一切法律责任</view>
<view class="dp_con2">3. 吴门医述所有作品内容仅代表作者自己的立场和观点吴门医述无关由作者本人承担一切法律责任</view>
</view> -->
</view>

90
pages/news/news.vue Normal file
View File

@@ -0,0 +1,90 @@
<template>
<view>
<!-- 公共组件-每个页面必须引入 -->
<public-module></public-module>
<z-nav-bar title="消息详情"></z-nav-bar>
<view class="box">
<view class="title">
{{news.title}}
</view>
<view class="content" v-html="news.content"></view>
</view>
<music-play :playData="playData"></music-play>
</view>
</template>
<script>
import musicPlay from '@/components/music.vue'
import $http from '@/config/requestConfig.js';
var clear;
import {
mapState
} from 'vuex';
// 密码验证的正则
//1、密码为八位及以上并且字母数字特殊字符三项都包括
var strongRegex = new RegExp("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$", "g");
//2、密码为八位及以上并且字母、数字、特殊字符三项中有两项强度是中等
var mediumRegex = new RegExp(
"^(?=.{8,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[a-z])(?=.*\\W))|((?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*\\W))).*$",
"g");
var enoughRegex = new RegExp("(?=.{8,}).*", "g");
export default {
data() {
return {
playData: {},
newsId: null,
news: {
content: '',
title: ''
}
};
},
//第一次加载
onLoad(e) {
// 隐藏原生的tabbar
uni.hideTabBar();
this.newsId = e.newsid
console.log(e, '------')
},
computed: {
...mapState(['userInfo'])
},
//页面显示
onShow() {
// 隐藏原生的tabbar
uni.hideTabBar();
this.getData();
},
components: {
musicPlay
},
//方法
methods: {
getData() {
this.$http
.post('common/message/getMessageById?id=' + this.newsId)
.then(res => {
if (res.code == 0) {
this.news.content = res.result.content
this.news.title = res.result.title
}
}).catch(e => {
console.log(e, '获取新闻详情报错')
});
}
},
};
</script>
<style lang="scss" scoped>
@import '@/style/mixin.scss';
.box {
background-color: #fff;
@include pleft_right(10px);
min-height: calc(100vh - 70rpx);
}
.title{font-size: 32rpx; font-weight: bold; display: block; text-align: center;}
.content { font-size: 26rpx; line-height: 48rpx; margin-top: 10rpx;}
</style>

View File

@@ -4,7 +4,7 @@
<z-nav-bar title="关于我们"></z-nav-bar>
<view class="APPinfo">
<image src="../../static/icon/fengziIcon.jpg" mode="" style="height: 150rpx; width: 150rpx; margin: 0 auto;"></image><br/>
<image src="../../static/logo.png" mode="" style="height: 150rpx; width: 150rpx; margin: 0 auto;"></image><br/>
<p>版本信息{{versionName}},{{versionCode}}</p>
</view>
@@ -21,10 +21,7 @@
<p>一款线上电子书APP包含医学类国学类文学类中医古籍等各种类型3D仿真翻页护眼模式等阅读技术打造舒适阅读体验图文混排AI人声读书听书部分电子书也有对应的纸质书给予用户更多的阅读选择</p>
</view>
<view class="" style="text-align: center;">
<!-- https://main.nuttyreading.com/privacy.html -->
<!-- <text @click="seeDetail('')" style="color: #007aff; font-size: 26rpx;">隐私政策</text> -->
<uni-link href="https://main.nuttyreading.com/privacy.html" text="隐私政策"></uni-link>
<!-- <uni-link href="https://uniapp.dcloud.io/" text="https://uniapp.dcloud.io/"></uni-link> -->
</view>
<music-play :playData="playData"></music-play>
</view>
@@ -60,15 +57,6 @@
uni.showModal({
title: '提示',
content: '微信号yilujiankangkefu',
// success: function (res) {
// if (res.confirm) {
// uni.makePhoneCall({
// phoneNumber: '022-24142321' //仅为示例
// });
// } else if (res.cancel) {
// }
// }
})
}

File diff suppressed because it is too large Load Diff

View File

@@ -206,8 +206,8 @@ export default {
scene: "WXSceneSession",
type: 0,
href: this.$apkUrl,
title: "疯子读书",
summary: "我正在使用疯子读书提升自己,赶紧跟我一起来体验吧!",
title: "吴门医述",
summary: "我正在使用吴门医述提升自己,赶紧跟我一起来体验吧!",
imageUrl: "static/fengziIcon.jpg",
success: function (res) {
console.log("success:" + JSON.stringify(res));
@@ -223,8 +223,8 @@ export default {
scene: "WXSceneTimeline",
type: 0,
href: this.$apkUrl,
title: "疯子读书",
summary: "我正在使用疯子读书提升自己,赶紧跟我一起来体验吧!",
title: "吴门医述",
summary: "我正在使用吴门医述提升自己,赶紧跟我一起来体验吧!",
imageUrl: "static/fengziIcon.jpg",
success: function (res) {
console.log("success:" + JSON.stringify(res));

View File

@@ -8,7 +8,7 @@
<image src="../../static/icon/mine_card.png" alt=""></image>
<view class="text">
<image src="../../static/icon/mine_v.png" alt=""></image>
疯子读书会员
吴门医述会员
<br>
<i>VIPFENGZIDUSHU</i>
<br>

View File

@@ -182,12 +182,23 @@
});
},
showXieyi() {
this.$http
.get(`sys/agreement/list?key=pay`)
.then(res => {
this.xieyi = res.page.list[0]
$http.request({
url: "/sys/agreement/getAgreement",
method: "POST", // POST、GET、PUT、DELETE具体说明查看官方文档
data: {
"id": 106
},
header: { //默认 无 说明:请求头
'Content-Type': 'application/json'
},
}).then(res => {
if (res.code == 0) {
this.xieyi = res.agreement
this.xieyiShow = true
})
}
}).catch(e => {
console.log(e)
})
},
radioCheck(index) { // 勾选用户协议

500
pages/user/addAddress.vue Normal file
View File

@@ -0,0 +1,500 @@
<template>
<view>
<view class="addressHeader">
<!-- 顶部导航栏 -->
<z-nav-bar :title="navName"></z-nav-bar>
</view>
<view class="addContent">
<u-form :model="addressForm" ref='addForm' :rules="rules" label-width="180rpx">
<u-form-item label="收件人 :" prop="username">
<u-input type="string" v-model="addressForm.username" placeholder="姓名" clearable
border="surround" />
</u-form-item>
<u-form-item label="手机号码 :" prop="userphone">
<u-input type="number" v-model="addressForm.userphone" placeholder="手机号" clearable
border="surround" />
</u-form-item>
<u-form-item label="所在地区 :" prop="">
<view class="add_arrow" @click="addreShow=true">{{addressForm.areaidpathtext}}</view>
<u-picker @cancel="addcancel" :show="addreShow" ref="uPicker" :columns="columns" keyName="UName"
@confirm="addconfirm" @change="changeHandler" ></u-picker>
</u-form-item>
<u-form-item label="详细地址 :" prop="useraddress">
<u-input type="string" v-model="addressForm.useraddress" placeholder="小区楼栋/乡村名称" clearable
border="surround" />
</u-form-item>
<u-form-item label="默认地址 :">
<u-switch v-model="addressForm.isDafault" active-color="#ff9e02" @change="changeSwitch"></u-switch>
</u-form-item>
</u-form>
</view>
<view class="addFooter">
<view class="submit" @click="uploadSub">
保存
</view>
<view class="del" v-if="isShowDel" @click="deleteShow=true">
删除
</view>
</view>
<u-modal :show="deleteShow" content="你确定要删除地址吗?" :showCancelButton="true" @cancel="deleteShow=false"
@confirm="deleteSub">
</u-modal>
<music-play :playData="playData"></music-play>
<!-- 公共组件-每个页面必须引入 -->
<public-module></public-module>
</view>
</template>
<script>
import musicPlay from '@/components/music.vue'
import $http from '@/config/requestConfig.js';
import addressList1 from "@/static/json/address.json"
import {
mapState
} from 'vuex';
export default {
data() {
return {
// array: ['中国', '美国', '巴西', '日本'],
// indexp:0,
// indexq:0,
// indexc:0,
playData:{},
addreShow: false, //是否显示
columns: [], //省份数据显示,三级联动需要三维数组,展示初始数据
columnData: [], //市数据
columnDatas: [], //区地址
switchTrue: true,
switchFalse: false,
addressChanged:false, // 地址修改标记
navName: '', // 顶部导航栏标题
provId: '', // 存储省id
cityId: '', // 存储市id
countyId: '', // 存储区id
addressList: [],
// 地址
addressForm: {
addressid: '',
username: '',
userphone: '',
area: '',
useraddress: '',
isDafault: false,
areaidpathtext: ''
},
isShowDel: false,
editIndex: 0,
deleteShow: false,
rules: {
username: [{
required: true,
message: "请输入收件人姓名",
trigger: "blur"
}],
userphone: [{
required: true,
message: "请输入手机号",
},
{
// 自定义验证函数
validator: (rule, value, callback) => {
// 返回true表示校验通过返回false表示不通过
// 过滤第一层先判断输入为不为空因为required: false不是必填项所以为空应该返回true
if (value) {
return this.$u.test.mobile(value);
} else {
return true
}
},
message: '手机号码不正确',
// 触发器可以同时用blur和change
trigger: ['change', 'blur'],
}
],
useraddress: [{
required: true,
message: "请输入所在地区",
trigger: "blur"
}]
}
}
},
onLoad(e) {
this.addressList = addressList1
if (e.type == 0) {
this.navName = '添加地址'
this.isShowDel = false
} else {
this.navName = '编辑地址'
this.isShowDel = true
this.editIndex = e.index
this.getAddress()
}
this.initDataPicker() //初始化省份列表
},
onShow() {
},
computed: {
...mapState(['userInfo']),
},
onReady() {
this.$refs.addForm.setRules(this.rules)
},
components:{
musicPlay
},
methods: {
// 三级联动
initDataPicker() {
// console.log(this.addressList,'addressList')
// this.$http
// .post('api/province/getProvince')
// .then(res => {
// if (res.code == 0) {
// this.addressList = res.provinceEntity
//此处的province主要用作数据的初始化即刚打开就需要进行展示的数据这个跟第一条省份数据相关我的第一条是北京市所以需要columns中的三维数组第一维度是省份数据数组第二维度是市数据数组第三维度是区数据数组
let province = []; //初始数据需要展示的省份
let province1 = [{
"cityId": this.addressList[0].cityList[0].cityId,
"provId": this.addressList[0].cityList[0].provId,
"cityName": this.addressList[0].cityList[0].cityName,
"UName": this.addressList[0].cityList[0].cityName,
"createDate": this.addressList[0].cityList[0].createDate,
"regionCode": this.addressList[0].cityList[0].regionCode,
"countyList": this.addressList[0].cityList[0].countyList
}]; //因为第一个市北京市,所以就直接添加北京市下辖的直辖市了 也即初始数据需要展示的市,北京市只有一个市辖区
let province2 = []; //初始数据需要展示的区域数据,也即是 北京市市辖区内的区
for (let i = 0; i < this.addressList.length; i++) {
this.addressList[i].UName = this.addressList[i].provName
if (this.addressList[i].cityList == null) {
// 如果没有cityList数据就添加一项用省份的信息
// console.log('存在单一',this.addressList[i].provId)
this.addressList[i].cityList = [{
"cityId": this.addressList[i].provId,
"provId": this.addressList[i].provId,
"cityName": this.addressList[i].provName,
"UName": this.addressList[i].provName,
"createDate": this.addressList[i].createDate,
"regionCode": this.addressList[i].regionCode,
"countyList": [{
"countyId": this.addressList[i].provId,
"cityId": this.addressList[i].provId,
"countyName": this.addressList[i].provName,
"UName": this.addressList[i].provName,
"createDate": this.addressList[i].createDate,
"regionCode": this.addressList[i].regionCode
}]
}]
} else {
for (let j = 0; j < this.addressList[i].cityList.length; j++) {
this.addressList[i].cityList[j].UName = this.addressList[i].cityList[j]
.cityName
for (let k = 0; k < this.addressList[i].cityList[j].countyList.length; k++) {
this.addressList[i].cityList[j].countyList[k].UName = this.addressList[i]
.cityList[j].countyList[k].countyName
}
}
}
province.push(this.addressList[i]);
}
this.addressList[0].cityList[0].countyList.map(item => {
province2.push(item);
});
//省数据 因为要做数据初始化,所以是三维数组
// 数据格式 [ [所有的省份数据:{},{}] , [第一个省份下的所有的市:{},{},{}] , [第一个市下面所有的区:{},{},{}] ]
this.columns.push(province);
this.columns.push(province1);
this.columns.push(province2);
// console.log(6666666,this.columns)
// 市数据数组筛选address.json文件将全国所有省下面的市数据放入数组
// 格式[ [第一个省下面所有市,{},{},{}] , [第二个省下面所有市{},{},{}] , [第三个省下面所有市{},{},{}] ] 注意,以上的第一第二对应着 columns[0] 的数据
this.addressList.map(item => {
let city = [];
item.cityList.map(item1 => {
city.push(item1);
});
this.columnData.push(city);
});
//区数据数组
//数据格式: [ 所有省下面所有市的所有区 [ 第一个省下面所有市的区:[ [第一个省下面第一个市的所有区] , [第一个省下面第二个市的所有区] ,] , [ 第二个省下面所有市的区:[ [第二个省下面第一个市的所有区] , [第二个省下面第二个市的所有区] ,] ]
let area = [];
this.addressList.map((item, index) => {
let area1 = []; //省下面所有市的初始化
item.cityList.map(item1 => {
area = []; //市下面的区初始化
item1.countyList.map(item2 => {
area.push(item2);
});
area1.push(area); // 每循环一个市,添加该市下面的所有区
});
this.columnDatas.push(area1); // 每循环一个省,添加该省下面的所有市
});
// };
// }).catch(e => {
// console.log(e,'e')
// })
},
changeHandler(e) { //城市选择时触发
// console.log(e,'变化了',this.columnData, this.columnDatas)
this.addressChanged = true
const {
columnIndex, //当前选择的列,省 / 市 / 区
value, // 当前选择的数组内容
values, // values为当前变化列的数组内容
index, // 当前列的下标值
indexs, // 当前选择 省 市 区的下表值
picker = this.$refs.uPicker
} = e;
// 当第一列值发生变化时,变化第二列和第三列的值(省份变更,市和区跟着变更)
if (columnIndex === 0) { // 判断当前变更的是省还是市还是区
// picker为选择器this实例变化第二列对应的选项
picker.setColumnValues(1, this.columnData[
index]); //设置市为该省下面的所有市index是当前省在省份数组的下标对应市数组中的下表就是 该省下面的所有市 的数据
picker.setColumnValues(2, this.columnDatas[index][0]); // 设置区域为该省下面第一个市下面的所有区域
}
if (columnIndex === 1) {
// 当第二列发生变化 变化对应的第三列
picker.setColumnValues(2, this.columnDatas[indexs[0]][index]); //同上
}
},
addconfirm(e) { //点击确定按钮
// console.log(e,'选中的值')
this.addressChanged = true
this.addreShow = false;
this.addressForm.areaidpathtext = e.value[0].UName + '-' + e.value[1].UName + '-' + e.value[2].UName
this.provId = e.value[0].provId
this.cityId = e.value[1].cityId
this.countyId = e.value[2].regionCode
},
addcancel() { //点击取消按钮
this.addreShow = false;
},
// 保存地址
uploadSub() {
this.$refs.addForm.validate()
.then(res => {
let link_add = ''
if (!this.isShowDel) {
link_add = 'book/userAddress/save'
} else {
link_add = 'book/userAddress/update'
// this.addconfirm(e)
}
if (this.addressForm.areaidpath == '') {
uni.showToast({
title: '请补全所在地址信息',
icon: "none"
});
return
}
// this.addressForm.userId = this.userInfo.id
// this.addressForm.consigneePhone = this.addressForm.userphone
// this.addressForm.consigneeName = this.addressForm.username
// this.addressForm.regionCode = ''
// // this.addressForm.userid = this.userInfo.id
// if(this.addressChanged){ // 如果修改过地址区域,就重新赋值,否则保持不变
// this.addressForm.areaidpath = `${this.provId}_${this.cityId}_${this.countyId}`
// this.addressChanged = false
// }
// this.addressForm.areaid = this.countyId
// this.addressForm.isDefault = this.addressForm.isDafault ? 1 : 0
// let data = this.addressForm
let data = {
'id':this.addressForm.addressid,
'detailAddress' : this.addressForm.useraddress,
'regionCode':this.countyId,
'userId':this.userInfo.id,
'consigneePhone':this.addressForm.userphone,
'consigneeName': this.addressForm.username,
'isDefault':this.addressForm.isDafault ? 1 : 0
}
console.log(data,'保存参数')
$http.request({
url: link_add,
method: "POST", // POST、GET、PUT、DELETE具体说明查看官方文档
data,
header: { //默认 无 说明:请求头
'Content-Type': 'application/json'
},
}).then(res => {
if (res.code == 0) {
uni.showToast({
title: '操作成功',
duration: 1000,
});
setTimeout(function() {
uni.navigateBack()
}, 1000);
}
})
}).catch(errors => {
uni.showToast({
title: '请补全信息',
icon: "none"
});
})
},
changeSwitch(e) {
e ? this.addressForm.isdefault = 1 : this.addressForm.isdefault = 0
this.addressForm.isDafault = e
console.log(this.addressForm, e)
},
// 编辑地址获取信息
getAddress() {
this.$http
.post(`book/userAddress/getUserAddress?userId=${this.userInfo.id}`)
.then(res => {
if (res.code == 0) {
this.addressForm = {
'useraddress':res.list[this.editIndex].detailAddress,
'userphone':res.list[this.editIndex].consigneePhone,
'username':res.list[this.editIndex].consigneeName,
'isdefault':res.list[this.editIndex].isDefault,
'isDafault':res.list[this.editIndex].isDefault == 1 ? true : false,
'areaidpathtext':res.list[this.editIndex].province +'-'+ res.list[this.editIndex].city +'-'+ res.list[this.editIndex].county
,'addressid':res.list[this.editIndex].id
}
this.countyId = res.list[this.editIndex].regionCode
// this.addressForm = res.list[this.editIndex]
if (this.addressForm.isdefault == 1) {
this.addressForm.isDafault = true
}
}
})
},
// 删除地址
deleteSub() {
let addressArr = [];
addressArr.push(this.addressForm.addressid)
this.deleteShow = false
this.$http
.get(`book/userAddress/delete?id=${this.addressForm.addressid}`)
.then(res => {
if (res.code == 0) {
uni.showToast({
title: '地址删除成功',
duration: 1000,
});
uni.navigateBack()
}
})
},
},
}
</script>
<style lang="scss" scoped>
.flexbox{display: flex;}
.selectAdd{ justify-content: space-between;
.addItem{ display: block;width: 30%}
}
.add_arrow {
height: 28px;
line-height: 28px;
width: 100%;
position: relative;
&::after {
content: '';
position: absolute;
right: 20upx;
top: 50%;
transform: translateY(-50%);
width: 40upx;
height: 40upx;
background-image: url('../../static/icon/icon_right.png');
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
}
.addContent {
width: 90%;
margin: 20rpx auto 0 auto;
.addItem {
width: 100%;
height: 100%;
display: flex;
align-items: center;
padding: 25rpx 10rpx;
uni-picker {
flex: 1;
}
.pickerItem {
height: 100%;
padding: 20rpx;
background-color: #dfdfdf;
border-radius: 20rpx;
border-bottom: solid 1px #ccc;
color: #7d7d7d;
}
}
}
.addFooter {
width: 100%;
margin: 50rpx 0 0 0;
view {
font-size: 34rpx;
width: 80%;
padding: 25rpx 0;
text-align: center;
color: #fff;
border-radius: 20rpx;
margin: 30rpx auto 0 auto;
}
.submit {
background-image: linear-gradient(90deg, #eba00b 0%, #c96713 100%)
}
.del {
background-image: linear-gradient(90deg, #bf0c0c 0%, #95110c 100%)
}
}
</style>

152
pages/user/address.vue Normal file
View File

@@ -0,0 +1,152 @@
<template>
<view class="">
<view class="addressHeader">
<!-- 顶部导航栏 -->
<z-nav-bar title="地址管理"></z-nav-bar>
</view>
<view class="addressMain">
<view class="addressItem" v-for="(item,index) in addressList" :key="index">
<view class="addrContent">
<view class="addrContentTop">
<view class="userName">
{{item.consigneeName}}
</view>
<view class="userTel">
{{item.consigneePhone}}
</view>
<view class="userMoren" v-if="item.isDefault==1">
默认
</view>
</view>
<view class="addrContentBottom">
<view class="userAddress">
{{item.province}} {{item.city}} {{item.county}}
{{item.detailAddress}}
</view>
</view>
</view>
<view class="addrEdit" @click="toAddress(1,index)">
<u-icon name="edit-pen" color="#a7a5a5" size="24"></u-icon>
</view>
</view>
</view>
<view class="addressFooter">
<view class="addAddress" @click="toAddress(0,0)">
+ 添加收货地址
</view>
</view>
<music-play :playData="playData"></music-play>
</view>
</template>
<script>
import musicPlay from '@/components/music.vue'
import {
mapState
} from 'vuex';
export default {
data() {
return {
playData:{},
addressList: []
}
},
onShow() {
this.getUserAddress()
},
computed: {
...mapState(['userInfo']),
},
components:{
musicPlay
},
methods: {
getUserAddress() {
this.$http
.post(`book/userAddress/getUserAddress?userId=${this.userInfo.id}`)
// .post(`book/useraddress/getUserAddress?userId=${this.userInfo.id}`)
.then(res => {
if (res.code == 0) {
this.addressList = res.list
}
})
},
// 跳转页面
toAddress(type, index) {
uni.navigateTo({
url: `/pages/user/addAddress?type=${type}&index=${index}`
})
}
}
}
</script>
<style lang="scss" scoped>
.addressItem {
width: 100%;
display: flex;
padding: 20rpx 10rpx;
margin: 25rpx 0 0 0;
align-items: center;
background-color: #fff;
.addrContent {
margin-left: 40rpx;
flex: 1;
.addrContentTop {
display: flex;
align-items: flex-end;
margin: 0 0 15rpx 0;
.userName {
font-size: 35rpx;
font-weight: bold;
margin-right: 30rpx;
}
.userTel {
font-size: 25rpx;
color: #888;
}
.userMoren {
border: 1px solid #fd6004;
color: #fd6004;
padding: 3rpx 10rpx;
font-size: 22rpx;
border-radius: 10rpx;
margin: 0 0 0 20rpx;
}
}
.addrContentBottom {
font-size: 32rpx;
}
}
.addrEdit {
padding: 10rpx;
}
}
.addressFooter {
width: 100%;
height: auto;
display: flex;
justify-content: center;
position: fixed;
bottom: 30rpx;
.addAddress {
font-size: 34rpx;
width: 90%;
text-align: center;
color: #fff;
background-image: linear-gradient(90deg, #eba00b 0%, #c96713 100%);
border-radius: 20rpx;
padding: 25rpx 0;
}
}
</style>

288
pages/user/bindPhone.vue Normal file
View File

@@ -0,0 +1,288 @@
<template>
<view>
<z-nav-bar title="绑定手机号"></z-nav-bar>
<!-- 公共组件-每个页面必须引入 -->
<public-module></public-module>
<view class="bindAccountBox">
<image :src="logoUrl"></image>
<view><image src="../../static/icon/bindingIcon.png"></image></view>
<image src="../../static/icon/WeChatIcon.png"></image>
</view>
<view class="inputItem">
<view class="title">*手机号</view>
<view class="info"><input type="number" placeholder="请输入" v-model="phone" /></view>
</view>
<view class="inputItem">
<view class="title">*验证码</view>
<view class="info">
<input type="number" placeholder="请输入" v-model="code" />
<button @click="getCode">{{ codeText }}</button>
</view>
</view>
<view class="registeredBut bindAccountBut"><button @click="onSubmit">立即绑定</button></view>
<music-play :playData="playData"></music-play>
</view>
</template>
<script>
import musicPlay from '@/components/music.vue'
var clear;
import { mapState, mapMutations } from 'vuex';
import socket from '@/config/socket';
// #ifdef H5
import {publicShare} from '@/config/utils';
// #endif
export default {
data() {
return {
playData:{},
logoUrl: '',
readonly: false,
codeText: '获取验证码',
phone: '',
code: ''
};
},
//第一次加载
onLoad(e) {
this.logoUrl = this.$base.logoUrl;
},
computed: {
...mapState(['userInfo','chatScenesInfo'])
},
//页面显示
onShow() {},
components:{
musicPlay
},
//方法
methods: {
...mapMutations(['setUserInfo']),
//验证码按钮文字状态
getCodeState() {
const _this = this;
this.readonly = true;
this.codeText = '60S后重新获取';
var s = 60;
clear = setInterval(() => {
s--;
_this.codeText = s + 'S后重新获取';
if (s <= 0) {
clearInterval(clear);
_this.codeText = '获取验证码';
_this.readonly = false;
}
}, 1000);
},
//获取验证码
getCode() {
if (this.readonly) {
uni.showToast({
title: '验证码已发送',
icon: 'none'
});
return;
}
if (this.phone == '') {
uni.showToast({
title: '请输入手机号',
icon: 'none'
});
return;
}
if (!this.$base.phoneRegular.test(this.phone)) {
uni.showToast({
title: '手机号格式不正确',
icon: 'none'
});
return;
}
this.$http
.post('api/open/v1/send_sms', {
phone: this.phone,
type: 3104
})
.then(res => {
this.getCodeState();
});
},
//账号绑定
onSubmit() {
if (this.phone == '') {
uni.showToast({
title: '请输入手机号',
icon: 'none'
});
return;
}
if (!this.$base.phoneRegular.test(this.phone)) {
uni.showToast({
title: '手机号格式不正确',
icon: 'none'
});
return;
}
if (this.code == '') {
uni.showToast({
title: '请输入验证码',
icon: 'none'
});
return;
}
if (!/^[0-9]{6}$/.test(this.code)) {
uni.showToast({
title: '验证码必须是6位数',
icon: 'none'
});
return;
}
if (!(this.userInfo.wxSmallOpenId || this.userInfo.openId || this.userInfo.wxPublicOpenId)) {
uni.showToast({
title: '数据丢失',
icon: 'none'
});
return;
}
let httpData = {
openId: this.userInfo.openId || this.userInfo.wxSmallOpenId || this.userInfo.wxPublicOpenId,
phone: this.phone,
code: this.code,
// #ifdef MP-WEIXIN
type: 1201,
// #endif
// #ifdef H5
type: 1301,
// #endif
// #ifdef APP-PLUS
type: 1101
// #endif
};
if(this.userInfo.unionid || this.userInfo.wxUnionid){
httpData.unionid = this.userInfo.unionid || this.userInfo.wxUnionid;
}
// #ifdef H5
let recommendCode = uni.getStorageSync("recommendCode");
if(recommendCode){
httpData.recommendCode = recommendCode;
}
// #endif
// #ifndef H5
if(this.chatScenesInfo.recommendCode){
httpData.recommendCode = this.chatScenesInfo.recommendCode;
}
// #endif
this.$http
.post('api/open/v1/third_bind',httpData)
.then(res => {
this.setUserInfo(res);
// #ifdef H5
publicShare();
// #endif
socket.init();
uni.showModal({
title: '提示',
content: '账号绑定成功!',
showCancel: false,
success: res => {
uni.navigateBack();
}
});
});
}
},
//页面隐藏
onHide() {},
//页面卸载
onUnload() {},
//页面下来刷新
onPullDownRefresh() {},
//页面上拉触底
onReachBottom() {},
//用户点击分享
onShareAppMessage(e) {
return this.wxShare();
}
};
</script>
<style lang="scss" scoped>
@import '@/style/mixin.scss';
.bindAccountBox {
height: 283upx;
display: flex;
justify-content: center;
align-items: center;
}
.bindAccountBox > image {
width: 95upx;
height: 95upx;
border-radius: 15upx;
}
.bindAccountBox > view {
width: 95upx;
height: 95upx;
padding: 0upx 20upx;
display: flex;
align-items: center;
}
.bindAccountBox > view image {
width: 100%;
height: 40upx;
}
.bindAccountBut {
margin-top: 60upx;
}
.registeredBut {
margin-bottom: 30upx;
padding: 0upx 20upx;
}
.registeredBut button {
font-size: 36upx;
border-radius: 3upx;
text-align: center;
line-height: 90upx;
height: 90upx;
background-color: $themeColor;
color: #fff;
}
.inputItem {
background-color: #fff;
display: flex;
margin-top: 12upx;
padding: 0 25upx;
}
.inputItem .title {
min-width: 190upx;
height: 100upx;
line-height: 100upx;
flex-shrink: 0;
font-size: 30upx;
white-space: nowrap;
}
.inputItem .info {
flex: 1;
display: flex;
align-items: center;
color: #999;
}
.inputItem .info input {
height: 100upx;
line-height: 100upx;
font-size: 30upx;
width: 100%;
}
.inputItem .info button {
height: 80upx;
line-height: 80upx;
font-size: 28upx;
flex-shrink: 0;
padding: 0 15upx;
border: 1upx solid $themeColor;
background-color: #fff;
color: $themeColor;
}
</style>

312
pages/user/forget.vue Normal file
View File

@@ -0,0 +1,312 @@
<template>
<view class="page">
<z-nav-bar></z-nav-bar>
<!-- 公共组件-每个页面必须引入 -->
<public-module></public-module>
<view class="title">忘记密码</view>
<view class="input_box">
<text class="input_tit">手机号</text>
<input type="text" v-model="phone" placeholder="请输入手机号" />
</view>
<view class="input_box">
<text class="input_tit">验证码</text>
<input type="number" v-model="code" placeholder="请输入验证码" />
<button @click="getCode">{{codeText}}</button>
</view>
<view class="input_box">
<text class="input_tit">密码</text>
<input type="password" maxlength="8" v-model="password" placeholder="请输入密码" @input="inputMethod(password)" />
</view>
<view class="" style="font-size: 28rpx; color: #999;">
<p v-if="note != ''">{{note}}</p>
<p v-html="str2" style="margin-top: 10rpx;"></p>
</view>
<view class="input_box">
<text class="input_tit">确认密码</text>
<input type="password" maxlength="8" v-model="confirmPassword" placeholder="请确认密码" />
</view>
<view class="btn_box"><button @click="onSubmit"> </button></view>
<music-play :playData="playData"></music-play>
</view>
</template>
<script>
import musicPlay from '@/components/music.vue'
import md5 from '@/plugins/md5';
// 密码验证的正则
//1、密码为八位及以上并且字母数字特殊字符三项都包括
var strongRegex = new RegExp("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$", "g");
//2、密码为八位及以上并且字母、数字、特殊字符三项中有两项强度是中等
var mediumRegex = new RegExp(
"^(?=.{8,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[a-z])(?=.*\\W))|((?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*\\W))).*$",
"g");
var enoughRegex = new RegExp("(?=.{8,}).*", "g");
var clear;
export default {
data() {
return {
playData: {},
//手机号账号
phone: '',
// 密码
password: '',
//验证码
code: '',
//确认密码
confirmPassword: '',
//验证码
codeText: '获取验证码',
//验证码已发
readonly: false,
passwordOk:false,
note: '',
str2: '',
};
},
//第一次加载
onLoad(e) {},
//页面显示
onShow() {},
components: {
musicPlay
},
//方法
methods: {
// 密码验证
inputMethod(value) {
this.passwordOk = false
// console.log('输入的值为:', value)
if (strongRegex.test(value)) {
//console.log('强密码-----',value)
this.str2 = "<span style='color:#18bc37'>密码强度很不错哦!</span>"
// this.note = '请至少使用大小写字母、数字、符号两种类型组合的密码长度至少为8位。'
this.note = ''
this.passwordOk = true
} else if (mediumRegex.test(value)) {
// console.log('中等密码-----',value)
this.note = '请至少使用大小写字母、数字、符号两种类型组合的密码长度为8位。'
this.str2 = "<span style='color:#2979ff'>密码强度中等!</span>"
this.passwordOk = true
} else if (enoughRegex.test(value)) {
// console.log('弱密码-----',value)
// this.str2 = "<span style='color:#f3a73f'>密码强度太弱!</span>"
this.note = '请至少使用大小写字母、数字、符号两种类型组合的密码长度为8位。'
}
else {
this.passwordOk = false
this.note = '请至少使用大小写字母、数字、符号两种类型组合的密码长度为8位。'
this.str2 = ""
//console.log('密码-----',value)
}
},
//获取验证码
getCode() {
if (this.readonly) {
uni.showToast({
title: '验证码已发送',
icon: 'none'
});
return;
}
if (!this.phone) {
uni.showToast({
title: '请输入手机号',
icon: 'none'
});
return;
}
if (!this.$base.phoneRegular.test(this.phone)) {
uni.showToast({
title: '请输入正确的手机号',
icon: 'none'
});
return;
}
this.$http
// .post('api/common/v1/send_sms', {
.post('book/user/sms/sendcode', {
phone: this.phone,
type: 3000
})
.then(res => {
this.getCodeState();
});
},
//验证码按钮文字状态
getCodeState() {
const _this = this;
this.readonly = true;
this.codeText = '60S后重新获取';
var s = 60;
clear = setInterval(() => {
s--;
_this.codeText = s + 'S后重新获取';
if (s <= 0) {
clearInterval(clear);
_this.codeText = '获取验证码';
_this.readonly = false;
}
}, 1000);
},
onSubmit() {
if(!this.passwordOk){
console.log('不满足密码格式',this.note)
uni.showToast({
title:this.note,
icon: 'none'
})
return
}
if (!this.phone) {
uni.showToast({
title: '请输入手机号',
icon: 'none'
});
return;
}
if (!this.$base.phoneRegular.test(this.phone)) {
uni.showToast({
title: '请输入正确的手机号',
icon: 'none'
});
return;
}
if (!this.code) {
uni.showToast({
title: '请输入验证码',
icon: 'none'
});
return;
}
if (!this.password) {
uni.showToast({
title: '请输入密码',
icon: 'none'
});
return;
}
if (!this.confirmPassword) {
uni.showToast({
title: '请输入确认密码',
icon: 'none'
});
return;
}
if (this.confirmPassword != this.password) {
uni.showToast({
title: '两次密码不一致',
icon: 'none'
});
return;
}
if (!this.$base.passwordRegular.test(this.password)) {
uni.showToast({
title: '请输入不少于6位且包含数字和字母的密码',
icon: 'none'
});
return;
}
this.$http
// .post('api/common/v1/forget_password', {
.post('book/user/setPassword', {
phone: this.phone,
code: this.code,
// password: md5(this.password),
password: this.password
})
.then(res => {
uni.showModal({
title: "提示",
content: "密码修改成功!",
showCancel: false,
success: (res) => {
uni.navigateBack();
}
});
});
}
},
//页面隐藏
onHide() {},
//页面卸载
onUnload() {},
//页面下来刷新
onPullDownRefresh() {},
//页面上拉触底
onReachBottom() {},
//用户点击分享
onShareAppMessage(e) {
return this.wxShare();
}
};
</script>
<style lang="scss" scoped>
@import '@/style/mixin.scss';
.page {
background-color: #ffffff;
padding: 0 65rpx;
min-height: 100vh;
.title {
padding: 60rpx 0 40rpx 0;
font-size: 60rpx;
color: #333333;
}
.input_box {
display: flex;
justify-content: space-between;
height: 100rpx;
padding-top: 30rpx;
border-bottom: 1rpx solid #eeeeee;
align-items: center;
text {
font-size: 30rpx;
width: 180rpx;
}
input {
flex: 1;
height: 70rpx;
line-height: 70rpx;
font-size: 30rpx;
}
button {
height: 78rpx;
line-height: 78rpx;
font-size: 30rpx;
color: $themeColor;
&:active {
background-color: transparent;
}
}
}
.btn_box {
margin-top: 70rpx;
button {
font-size: 32rpx;
@include theme('btn_bg') color: #fff;
height: 80rpx;
line-height: 80rpx;
border-radius: 50rpx;
}
}
.protocol {
font-size: 24rpx;
color: #999999;
text-align: center;
margin-top: 20rpx;
text {
color: $themeColor;
}
}
}
</style>

297
pages/user/healthLog.vue Normal file
View File

@@ -0,0 +1,297 @@
<template>
<view class="page">
<z-nav-bar></z-nav-bar>
<!-- 公共组件-每个页面必须引入 -->
<public-module></public-module>
<view class="title">手机号验证</view>
<view class="input_box">
<text class="input_tit">手机号</text>
<input type="text" v-model="phone" placeholder="请输入手机号" />
</view>
<view class="input_box">
<text class="input_tit">验证码</text>
<input type="text" v-model="code" placeholder="请输入验证码" />
<button @click="getCode">{{codeText}}</button>
</view>
<view class="btn_box"><button @click="onSubmit"> </button></view>
<music-play :playData="playData"></music-play>
</view>
</template>
<script>
import musicPlay from '@/components/music.vue'
import md5 from '@/plugins/md5';
var clear;
import store from '@/store';
import socket from '@/config/socket';
import {
mapState,
mapMutations
} from 'vuex';
export default {
data() {
return {
playData:{},
//手机号账号
phone: '',
// 密码
password: '',
//验证码
code: '',
//验证码
codeText: '获取验证码',
//验证码已发
readonly: false
};
},
//第一次加载
onLoad(e) {
// 隐藏原生的tabbar
uni.hideTabBar();
this.showPhone();
},
computed: {
...mapState(["userInfo"])
},
//页面显示
onShow() {
// 隐藏原生的tabbar
uni.hideTabBar();
},
components:{
musicPlay
},
//方法
methods: {
// 显示手机号
showPhone() {
let HealthMes = store.state.HealthMes;
let IsPhoneHealth = this.$base.phoneRegular.test(HealthMes.cellPhone)
if (IsPhoneHealth) {
this.phone = HealthMes.cellPhone
}
},
//获取验证码
getCode() {
if (this.readonly) {
uni.showToast({
title: '验证码已发送',
icon: 'none'
});
return;
}
if (!this.phone) {
uni.showToast({
title: '请输入手机号',
icon: 'none'
});
return;
}
if (!this.$base.phoneRegular.test(this.phone)) {
uni.showToast({
title: '手机格式不正确',
icon: 'none'
});
return;
}
this.$http
.get('book/user/sms/sendcode', {
phone: this.phone,
type: 2000
})
.then(res => {
this.getCodeState();
});
},
//验证码按钮文字状态
getCodeState() {
const _this = this;
this.readonly = true;
this.codeText = '60S后重新获取';
var s = 60;
clear = setInterval(() => {
s--;
_this.codeText = s + 'S后重新获取';
if (s <= 0) {
clearInterval(clear);
_this.codeText = '获取验证码';
_this.readonly = false;
}
}, 1000);
},
onSubmit() {
if (!this.phone) {
uni.showToast({
title: '请输入手机号',
icon: 'none'
});
return;
}
if (!this.$base.phoneRegular.test(this.phone)) {
uni.showToast({
title: '请输入正确的手机号',
icon: 'none'
});
return;
}
if (!this.code) {
uni.showToast({
title: '请输入验证码',
icon: 'none'
});
return;
}
let HealthMes = store.state.HealthMes;
let httpData = {};
httpData.code = this.code;
httpData.phone = this.phone;
httpData.yljkOid = HealthMes.yljkOid;
httpData.userName = HealthMes.nameCN;
httpData.customerIcons = HealthMes.customerIcons;
this.$http
.get('book/user/registerHs', httpData)
.then(res => {
uni.showToast({
title: '手机验证成功',
duration: 1000,
});
console.log(res)
res.userInfo.token = res.token.token;
setTimeout(() => {
uni.navigateBack({
delta: 1
});
}, 1000);
this.setUserInfo(res.userInfo);
// socket.init();
// uni.showModal({
// title: '提示',
// content: '该手机号已经注册过花生,您是否要绑定登录?',
// success: function(res) {
// if (res.confirm) {
// console.log('用户点击确定');
// } else if (res.cancel) {
// console.log('用户点击取消');
// }
// }
// });
// uni.showModal({
// title: '提示',
// content: '验证成功,请问您要通过该账户登录花生吗?',
// success: function(res) {
// if (res.confirm) {
// this.setUserInfo(res.userInfo);
// // socket.init();
// uni.switchTab({
// url: "/pages/home/home"
// });
// } else if (res.cancel) {
// console.log('用户点击取消');
// }
// }
// });
});
// let bangDing = {};
// bangDing.phone = this.code;
// httpData.password = this.phone;
// httpData.hsuserId = HealthMes.yljkOid;
// this.$http
// .get('book/user/getEverhealthInfo', bangDing)
// .then(res => {
// console.log(res)
// uni.showToast({
// title: '验证成功',
// duration: 600,
// });
// });
}
},
};
</script>
<style lang="scss" scoped>
@import '@/style/mixin.scss';
.page {
background-color: #ffffff;
padding: 0 65rpx;
min-height: 100vh;
.title {
padding: 60rpx 0 40rpx 0;
font-size: 60rpx;
color: #333333;
}
.input_box {
display: flex;
justify-content: space-between;
height: 100rpx;
padding-top: 30rpx;
border-bottom: 1rpx solid #eeeeee;
align-items: center;
text {
font-size: 30rpx;
width: 180rpx;
}
input {
flex: 1;
height: 70rpx;
line-height: 70rpx;
font-size: 30rpx;
}
button {
height: 78rpx;
line-height: 78rpx;
font-size: 30rpx;
color: $themeColor;
&:active {
background-color: transparent;
}
}
}
.btn_box {
margin-top: 70rpx;
button {
font-size: 32rpx;
@include theme('btn_bg') color: #fff;
height: 80rpx;
line-height: 80rpx;
border-radius: 50rpx;
}
}
.protocol {
font-size: 24rpx;
color: #999999;
text-align: center;
margin-top: 20rpx;
text {
color: $themeColor;
}
}
}
</style>

1295
pages/user/login.vue Normal file

File diff suppressed because it is too large Load Diff

572
pages/user/persCount.vue Normal file
View File

@@ -0,0 +1,572 @@
<template>
<view>
<!-- 公共组件-每个页面必须引入 -->
<public-module></public-module>
<z-nav-bar title="我的账户"></z-nav-bar>
<view class="ACTable">
<u-tabs :list="tab_list" @click="tab_click" lineColor="#54a966 100% 100%"
:activeStyle="{color: '#303133',fontWeight: 'bold',transform: 'scale(1.1)'}" v-if="iosHide"></u-tabs>
<u-tabs :list="tab_list_ios" @click="tab_click" lineColor="#54a966 100% 100%"
:activeStyle="{color: '#303133',fontWeight: 'bold',transform: 'scale(1.1)'}" v-if="!iosHide"></u-tabs>
<view v-if="tab_muJian==0">
<view class="AC_mes">
<view style="font-size: 50rpx;font-weight: bold;">{{userMes.peanutCoin}}</view>
<view style="color: #888;font-size: 30rpx;margin-top: 10rpx;">天医币</view>
<text v-if="platform != 'ios'" class="AC_chong" @click="buPoint()">充值</text>
</view>
<view class="AC_con">
<view class="AC_jilu">充值记录</view>
<view v-for="(item,index) in MoneyRecord" class="AC_List">
<view class="AC_title">
{{item.orderType}}
<view>
<text v-if="item.changeAmount>0">+</text>
<text>{{item.changeAmount}}</text>
天医币
</view>
</view>
<view class="AC_mark">{{item.remark}}</view>
<view class="AC_time">{{item.createTime}}</view>
</view>
</view>
</view>
<view v-if="tab_muJian==1">
<view class="couponList">
<view v-for="(item,index) in couponTabs" @click="couponTabCLi(index)"
:class="couponListTab==index?'couStyle':''">{{item.name}}</view>
</view>
<view>
<view class="card" v-for="item in cardList">
<view>
<view class="content">
<view :class="couponListTab==0?'page-group':'page-group grey'">
<i class="fold-page"></i>
<span class="page">优惠券</span>
</view>
<i class="dot-left"></i>
<i class="dot-right"></i>
<view class="coupon-detail">
<view :class="couponListTab==0?'':'grey'">
<span></span>
<span>{{item.coupons.amount}}</span>
</view>
<view>
<view>{{item.coupons.couponName}}</view>
<view>{{item.coupons.useLevel}}元可用</view>
<view>
<span v-if="item.coupons.couponProType == 0">使用类型商品类</span>
<span v-if="item.coupons.couponProType == 1">使用类型电子书</span>
</view>
</view>
<view>
<view v-if="couponListTab==0" @click="onPageJump('../bookShop/bookShopIndex')">
立即使用</view>
</view>
</view>
</view>
<view class="footer">
<view style="margin: 0 0 8rpx 0;">使用时间{{item.coupons.takeEffectDate}} -
{{item.coupons.expirationDate}}
</view>
<view>{{item.coupons.note}}</view>
<view class="arrow"></view>
<view class="arrow-up"></view>
</view>
<view class="ribbon" v-if="couponListTab==0">未使用</view>
<view class="ribbon grey" v-if="couponListTab==1">已使用</view>
<view class="ribbon grey" v-if="couponListTab==2">已过期</view>
</view>
</view>
<view v-if="cardList.length==0" style="text-align: center;font-size: 30rpx;color: #666;">暂无代金券
</view>
</view>
</view>
<view>
<view v-if="status==0" style="text-align: center;">
<u-loading-icon style="display: inline-block;"></u-loading-icon>
<font style='vertical-align: super;margin-left: 10px;font-size: 26rpx;color: #909399;'>努力加载中</font>
</view>
<view v-if="status==1">
<u-divider text="全部加载完成"></u-divider>
</view>
</view>
<view style="padding-bottom: 20rpx;">
<u-back-top :scroll-top="scrollTop" bottom="60" :customStyle='bgiStyle' :iconStyle="iconStyle">
</u-back-top>
</view>
</view>
<music-play :playData="playData"></music-play>
</view>
</template>
<script>
import musicPlay from '@/components/music.vue'
import $http from '@/config/requestConfig.js';
import {
mapState
} from 'vuex';
export default {
data() {
return {
playData: {},
platform: null,
tab_list: [{
name: '天医币',
}, {
name: '优惠券',
}],
tab_list_ios: [{
name: '优惠券',
}],
couponTabs: [{
name: '未使用'
}, {
name: '已使用'
}, {
name: '已过期'
}],
cardList: [],
couponListTab: 0,
MoneyRecord: [],
userMes: {},
RecordScreen: {
userid: '',
page: 1,
limit: 5,
},
scrollTop: 0,
status: 3,
totalPage: 0,
totalCount: 0,
tab_muJian: 0,
bgiStyle: {
background: '#2ab58833'
},
iconStyle: {
fontSize: '40rpx',
fontWeight: 'bold',
color: '#54a966',
},
};
},
// 返回顶部
onPageScroll(e) {
this.scrollTop = e.scrollTop;
},
// 下拉刷新
onReachBottom() {
this.status = 0
if (this.RecordScreen.page < this.totalPage) {
this.RecordScreen.page = this.RecordScreen.page + 1
setTimeout(() => {
this.$http
.post('book/transactiondetails/list?userId=' + this.userInfo.id + '&page=' + this
.RecordScreen.page + '&limit=' + this.RecordScreen.limit)
.then(res => {
this.totalPage = res.page.totalPage
this.totalCount = res.page.totalCount
for (let i in res.page.list) {
this.MoneyRecord.push(res.page.list[i])
}
});
}, 1000)
} else {
this.status = 1
}
},
//第一次加载
onLoad(e) {
// 隐藏原生的tabbar
uni.hideTabBar();
// #ifdef APP-PLUS
this.platform = uni.getSystemInfoSync().platform
console.log('操纵系统', this.platform)
// #endif
},
computed: {
...mapState(['userInfo'])
},
//页面显示
onShow() {
// 隐藏原生的tabbar
uni.hideTabBar();
this.getData();
this.getCourpe();
},
components: {
musicPlay
},
//方法
methods: {
// 获取
getData() {
if(!this.iosHide){
this.tab_muJian=1
}
// 用户详情
if (this.userInfo.id != undefined) {
this.$http
.post('book/user/info/' + this.userInfo.id)
.then(res => {
this.userMes = res.user
});
}
// 充值记录
this.$http
.post('book/transactiondetails/list?userId=' + this.userInfo.id + '&page=' + this.RecordScreen
.page + '&limit=' + this.RecordScreen.limit)
.then(res => {
this.MoneyRecord = res.page.list
this.totalPage = res.page.totalPage
this.totalCount = res.page.totalCount
});
},
// 点击tab
tab_click(e) {
this.tab_muJian = e.index
},
// 优惠券
getCourpe() {
this.$http
.post('/book/couponhistory/appGetUserCenterCoupon?userId=' + this.userInfo.id + '&useStatus=' + this
.couponListTab)
.then(res => {
// this.cardList = res.couponVos
this.cardList = res.couponVos
});
},
// 切换优惠券
couponTabCLi(e) {
this.couponListTab = e
this.getCourpe()
},
// 充值天医币
buPoint() {
uni.navigateTo({
url: '../peanut/reCharge'
});
},
// 跳转
onPageJump(url) {
uni.navigateTo({
url: url
});
},
},
};
</script>
<style lang="scss" scoped>
@import '@/style/mixin.scss';
.ACTable {
padding: 20rpx 30rpx;
.AC_mes {
margin-top: 50rpx;
padding: 30rpx 30rpx;
box-shadow: 0 0px 10px 1px #d3d1d133;
background-color: #fff;
border-radius: 15rpx;
margin-bottom: 40rpx;
position: relative;
.AC_chong {
background-color: #54a966;
color: #fff;
border-radius: 80rpx;
padding: 15rpx 50rpx;
font-size: 35rpx;
position: absolute;
top: 50rpx;
right: 50rpx;
}
}
.AC_con {
margin-top: 50rpx;
padding: 30rpx 30rpx;
box-shadow: 0 0px 10px 1px #d3d1d133;
background-color: #fff;
border-radius: 15rpx;
margin-bottom: 40rpx;
font-size: 30rpx;
.AC_jilu {
font-size: 32rpx;
text-align: center;
margin-bottom: 30rpx;
}
.AC_List {
border-bottom: 1px solid #eee;
padding: 40rpx 10rpx;
.AC_title {
font-size: 32rpx;
margin-bottom: 20rpx;
view {
float: right;
font-size: 34rpx;
font-weight: bold;
}
}
.AC_mark {
font-size: 28rpx;
margin-bottom: 15rpx;
color: #888;
}
.AC_time {
color: #bababa;
font-size: 25rpx;
}
}
}
.couponList {
view {
display: inline-block;
padding: 0 0 25rpx 0;
margin: 40rpx 0 40rpx 0;
width: 33%;
text-align: center;
font-size: 30rpx;
}
.couStyle {
border-bottom: 5rpx solid #54a966;
color: #54a966;
font-weight: bold;
}
}
.card {
width: 100%;
overflow: hidden;
margin-bottom: 30rpx;
padding-left: 10rpx;
position: relative;
}
.card>view {
background: #fff;
border-radius: 5rpx;
}
.card .dot-left,
.card .dot-right {
display: block;
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background: #f5f5f5;
position: absolute;
z-index: 999;
}
.card .dot-left {
bottom: -6rpx;
left: -6rpx;
}
.card .dot-right {
bottom: -6rpx;
right: -6rpx;
}
.card .page-group {
position: absolute;
top: 10rpx;
left: -2rpx;
width: 100%;
max-width: 200rpx;
.fold-page {
display: block;
width: 10rpx;
height: 8rpx;
background: #54a966;
transform: skewY(-40deg);
position: absolute;
top: -5rpx;
left: -8rpx;
z-index: 0;
}
.page {
position: absolute;
z-index: 1;
display: block;
padding: 5rpx 20rpx 3rpx 20rpx;
height: 40rpx;
line-height: 40rpx;
background: linear-gradient(137deg, #54a966 0%, #0d5e1e 100%);
border-radius: 0 20rpx 20rpx 0;
color: #fff;
text-align: center;
font-size: 24rpx;
overflow: hidden;
left: -8rpx;
}
}
.card .page-group.grey {
.fold-page {
background: #c6c6c6;
}
.page {
background: linear-gradient(137deg, #c6c6c6 0%, #999595 100%);
}
}
.card .content {
width: 100%;
height: 180rpx;
border-bottom: 1rpx dotted #f5f5f5;
position: relative;
z-index: 2;
}
.card .content .coupon-detail {
display: flex;
padding: 0 15rpx 0 20rpx;
}
.card .content .coupon-detail>view {
height: 130rpx;
display: flex;
align-items: center;
}
.card .content .coupon-detail>view:first-child {
color: #54a966;
padding-top: 100rpx;
width: 30%;
}
.card .content .coupon-detail>view.grey {
color: #c6c6c6;
}
.card .content .coupon-detail>view:first-child>span:first-child {
font-size: 30rpx;
margin: 0 10rpx 0 0;
}
.card .content .coupon-detail>view:first-child>span:last-child {
font-size: 70rpx;
}
.card .content .coupon-detail>view:last-child>view {
color: #54a966;
border: 1rpx solid #54a966;
border-radius: 50rpx;
font-size: 12px;
line-height: 25px;
width: 150rpx;
height: 50rpx;
margin: 100rpx 0 0 5rpx;
text-align: center;
}
.card .coupon-detail>view:nth-child(2) {
flex-direction: column;
padding-top: 60rpx;
width: 40%;
}
.card .coupon-detail>view:nth-child(2)>view {
width: 100%;
}
.card .coupon-detail>view:nth-child(2)>view:first-child {
color: #333;
font-weight: bold;
font-size: 25rpx;
margin: 0 0 10rpx 0;
}
.card .coupon-detail>view:nth-child(2)>view:last-child {
font-size: 12px;
color: #adadad;
margin-top: 5rpx;
}
.card .coupon-detail>view:nth-child(2)>view:last-child>view {
transform: scale(0.8);
margin-left: -14rpx;
}
.card {
.footer {
color: #999;
font-size: 12px;
padding: 30rpx 15rpx 30rpx 30rpx;
}
.ribbon {
width: 160rpx;
height: 40rpx;
background: #54a966;
position: absolute;
right: -40rpx;
top: 25rpx;
transform: rotateZ(45deg);
text-align: center;
color: #fff;
font-size: 20rpx;
line-height: 44rpx;
}
.ribbon.grey {
background: #c6c6c6;
}
}
}
</style>

850
pages/user/persData.vue Normal file
View File

@@ -0,0 +1,850 @@
<template>
<view>
<!-- 公共组件-每个页面必须引入 -->
<public-module></public-module>
<z-nav-bar title="个人资料"></z-nav-bar>
<view class="tabulate">
<view class="per_list">
<text class="biaoti">手机号</text>
<text class="neirong">{{userMsage.tel}}</text>
<text class="marPer" v-if="!userMsage.tel" @click="phoneShow = true;OpenClear()"
style="background-color: #ed901d;">点击绑定</text>
</view>
<view class="per_list">
<text class="biaoti">邮箱</text>
<text class="neirong">{{userMsage.email}}</text>
<text class="marPer" v-if="!userMsage.email" @click="emailShow = true;OpenClear()"
style="background-color: #ed901d;">点击绑定</text>
</view>
<view class="per_list per_list_arrow" @click="avatarShow = true">
<text class="biaoti" style="margin-top: 40rpx;">头像</text>
<text class="neirong" style="margin-top: 0;">
<image :src="userMsage.avatar" class="per_mes_img"></image>
</text>
</view>
<view class="per_list per_list_arrow" @click="nicknameShow = true">
<text class="biaoti">昵称</text>
<text class="neirong">{{userMsage.nickname}}</text>
</view>
<view class="per_list per_list_arrow" @click="passwordShow = true">
<text class="biaoti">密码</text>
<text v-if="userMsage.YNpass!=''" class="neirong">点击修改</text>
<text class="marPer" v-if="userMsage.YNpass!=''"
style="background-color: #92c78c;margin-right: 40rpx;">已设定</text>
<text v-if="userMsage.YNpass==''" class="neirong">去设置</text>
<text class="marPer" v-if="userMsage.YNpass==''"
style="background-color: #9d9d9d;margin-right: 40rpx;">未设定</text>
</view>
<view class="per_list per_list_arrow" @click="ageShow = true">
<text class="biaoti">年龄</text>
<text class="neirong">{{userMsage.age}}</text>
</view>
<view class="per_list per_list_arrow" @click="sexShow = true">
<text class="biaoti">性别</text>
<text class="neirong" v-if="userMsage.sex==1"></text>
<text class="neirong" v-if="userMsage.sex==0"></text>
</view>
</view>
<!-- 手机 -->
<u-popup :show="phoneShow" :round="10" @close="phoneShow=false;">
<view class="tanchu">
<view class="dp_title">请输入手机号</view>
<view style="display: flex;">
<view class="quhao">
<uni-data-select class="quhaoSel" placeholder="请选择区号" v-model="userMes.quCode"
:localdata="quCodeList"></uni-data-select>
</view> <u--input v-model="userMes.phone" placeholder="请输入手机号" border="surround" clearable>
</u--input>
</view>
<view style="display: flex;">
<u--input v-model="userMes.phonecode" type="number" placeholder="请输入验证码" border="surround" clearable
style="margin-top: 20rpx;">
</u--input>
<button class="emPHCode" @click="onSetCode('phone')">{{ PhoneEmailNote }}</button>
</view>
<u-button color="linear-gradient(to right, #72d386, #317e42)" text="确定" @click="chosePhone()"
style="margin-top: 50rpx;"></u-button>
<view @click="phoneShow=false" class="dp_canBtn">
取消</view>
</view>
</u-popup>
<!-- 邮箱 -->
<u-popup :show="emailShow" :round="10" @close="emailShow=false;PhoneEmailNote = '获取验证码'">
<view class="tanchu">
<view class="dp_title">请输入邮箱</view>
<u--input v-model="userMes.email" placeholder="请输入邮箱" border="surround" clearable>
</u--input>
<view style="display: flex;">
<u--input v-model="userMes.emailcode" type="number" placeholder="请输入验证码" border="surround" clearable
style="margin-top: 20rpx;">
</u--input>
<button class="emPHCode" @click="onSetCode('email')">{{ PhoneEmailNote }}</button>
</view>
<u-button color="linear-gradient(to right, #72d386, #317e42)" text="确定" @click="choseEmail()"
style="margin-top: 50rpx;"></u-button>
<view @click="emailShow=false" class="dp_canBtn">
取消</view>
</view>
</u-popup>
<!-- 头像 -->
<u-popup :show="avatarShow" :round="10" @close="avatarShow=false">
<view class="tanchu">
<view class="dp_title">请更换头像</view>
<u-upload :fileList="fileAvatar" @afterRead="afterRead" @delete="deletePic" multiple :maxCount="1"
width="150" height="150" :previewFullImage="true">
</u-upload>
<u-button color="linear-gradient(to right, #72d386, #317e42)" text="确定" @click="choseAvatar()"
style="margin-top: 50rpx;"></u-button>
<view @click="avatarShow=false" class="dp_canBtn">取消</view>
</view>
</u-popup>
<!-- 昵称 -->
<u-popup :show="nicknameShow" :round="10" @close="nicknameShow=false">
<view class="tanchu">
<view class="dp_title">请输入昵称</view>
<u--input v-model="userMes.nickname" placeholder="请输入昵称" border="surround" clearable></u--input>
<u-button color="linear-gradient(to right, #72d386, #317e42)" text="确定"
@click="choseNickname(userMes.nickname)" style="margin-top: 50rpx;"></u-button>
<view @click="nicknameShow=false" class="dp_canBtn">取消</view>
</view>
</u-popup>
<!-- 年龄 -->
<u-popup :show="ageShow" :round="10" @close="ageShow=false">
<view class="tanchu">
<view class="dp_title">请输入年龄</view>
<u--input v-model="userMes.age" type="number" placeholder="请输入年龄" border="surround" clearable>
</u--input>
<u-button color="linear-gradient(to right, #72d386, #317e42)" text="确定" @click="choseAge()"
style="margin-top: 50rpx;"></u-button>
<view @click="ageShow=false" class="dp_canBtn">
取消</view>
</view>
</u-popup>
<!-- 性别 -->
<u-popup :show="sexShow" :round="10" @close="sexShow=false">
<view class="tanchu">
<view class="dp_title">请选择性别</view>
<u-radio-group v-model="userMes.sex">
<view style="width: 100%;">
<view v-for="(item, index) in sexList" @click="choseSex(item.id)" class="dp_sex">
{{item.title}}
<u-radio :key="index" activeColor="#54a966" :name='item.id'
style="float: right;margin-top: 5rpx;" @change="choseSex(item.id)"></u-radio>
</view>
</view>
</u-radio-group>
<view @click="sexShow=false" class="dp_canBtn">取消</view>
</view>
</u-popup>
<!-- 密码 -->
<u-popup :show="passwordShow" :round="10" @close="cancelPass">
<view class="tanchu">
<view class="dp_title">请修改密码</view>
<u--input maxlength="8" v-model="userMiMa.password" placeholder="请输入新密码" :password="true"
border="surround" clearable @input="inputMethod(userMiMa.password)">
</u--input>
<view class="" style="font-size: 28rpx; color: #999;">
<p v-if="passNote != ''">{{passNote}}</p>
<p v-html="passStr" style="margin-top: 10rpx;"></p>
</view>
<u--input maxlength="8" v-model="userMiMa.Repassword" placeholder="请再确认密码" :password="true"
border="surround" clearable style="margin-top: 20rpx;"></u--input>
<u-button color="linear-gradient(to right, #72d386, #317e42)" text="确定" @click="chosePassword()"
style="margin-top: 50rpx;"></u-button>
<view @click="cancelPass" class="dp_canBtn">取消</view>
</view>
</u-popup>
<!-- <view class="btn_box">
<button @click="chosePassword" class="active"> </button>
</view> -->
<music-play :playData="playData"></music-play>
</view>
</template>
<script>
import musicPlay from '@/components/music.vue'
import $http from '@/config/requestConfig.js';
var clear;
import {
mapState
} from 'vuex';
// 密码验证的正则
//1、密码为八位及以上并且字母数字特殊字符三项都包括
var strongRegex = new RegExp("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$", "g");
//2、密码为八位及以上并且字母、数字、特殊字符三项中有两项强度是中等
var mediumRegex = new RegExp(
"^(?=.{8,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[a-z])(?=.*\\W))|((?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*\\W))).*$",
"g");
var enoughRegex = new RegExp("(?=.{8,}).*", "g");
export default {
data() {
return {
playData: {},
userMes: {
quCode: '',
phone: '',
email: '',
id: '',
age: '',
sex: '',
nickname: '',
tel: '',
oldName: '', // 老的用户名
},
userMsage: {
quCode: '',
phonecode: '',
phone: '',
emailcode: '',
email: '',
id: '',
age: '',
sex: '',
nickname: '',
tel: '',
YNpass: '',
oldName: '', // 老的用户名
},
userMiMa: {
id: '',
password: '',
Repassword: '',
},
readonly: false,
phoneShow: false,
emailShow: false,
avatarShow: false,
nicknameShow: false,
ageShow: false,
sexShow: false,
passwordShow: false,
fileAvatar: [],
quCodeList: [], // 国家区域码
sexList: [{
title: '男',
id: 1,
},
{
title: '女',
id: 0,
}
],
PhoneEmailNote: '获取验证码',
passNote: '',
passStr: '',
passwordOk: false, // 密码是否满足规则
};
},
//第一次加载
onLoad(e) {
// 隐藏原生的tabbar
uni.hideTabBar();
},
computed: {
...mapState(['userInfo'])
},
//页面显示
onShow() {
// 隐藏原生的tabbar
uni.hideTabBar();
this.getData();
this.getCountyCode()
},
components: {
musicPlay
},
//方法
methods: {
// 获取
getCountyCode() {
let that = this
// 获取国家区域编码
$http.request({
url: "book/baseArea/getAllBaseArea",
method: "POST", // POST、GET、PUT、DELETE具体说明查看官方文档
data: {},
header: { //默认 无 说明:请求头
'Content-Type': 'application/json'
},
})
.then(res => {
// console.log(res,'区域码')
if (res.code == 0 && res.baseAreas.length > 0) {
that.quCodeList = res.baseAreas.map(item => {
let obj = {
'text': item.title + ' (+' + item.code + ')',
'value': item.code,
}
return obj
})
} else {
that.quCodeList = []
}
}).catch(e => {
console.log(e, 'e')
});
},
getData() {
let that = this
// 获取个人信息
if (this.userInfo.id != undefined) {
this.$http
.post('book/user/info/' + that.userInfo.id)
.then(res => {
that.userMes.id = res.user.id
that.userMes.age = res.user.age
that.userMes.sex = res.user.sex
that.userMes.nickname = res.user.nickname
that.userMes.tel = res.user.tel
that.userMes.avatar = res.user.avatar
that.userMes.oldName = that.userMes.nickname
that.userMes.id = res.user.id
that.userMsage.age = res.user.age
that.userMsage.email = res.user.email
that.userMsage.sex = res.user.sex
that.userMsage.nickname = res.user.nickname
that.userMsage.tel = res.user.tel
that.userMsage.avatar = res.user.avatar
that.userMsage.YNpass = res.user.password
that.userMiMa.id = res.user.id
});
}
},
cancelPass() {
this.passwordShow = false
this.userMiMa.password = ''
this.userMiMa.Repassword = ''
this.passNote = ''
this.passStr = ''
},
// 密码验证
inputMethod(value) {
this.passwordOk = false
// console.log('输入的值为:', value)
if (strongRegex.test(value)) {
//console.log('强密码-----',value)
this.passStr = "<span style='color:#18bc37'>密码强度很不错哦!</span>"
// this.passNote = '请至少使用大小写字母、数字、符号两种类型组合的密码长度为8位。'
this.passNote = ''
this.passwordOk = true
} else if (mediumRegex.test(value)) {
//console.log('中等密码-----',value)
this.passNote = '请至少使用大小写字母、数字、符号两种类型组合的密码长度为8位。'
this.passStr = "<span style='color:#2979ff'>密码强度中等!</span>"
this.passwordOk = true
} else if (enoughRegex.test(value)) {
//console.log('弱密码-----',value)
this.passStr = "<span style='color:#f3a73f'>密码强度太弱!</span>"
this.passNote = '请至少使用大小写字母、数字、符号两种类型组合的密码长度为8位。'
} else {
this.passwordOk = false
this.passNote = '请至少使用大小写字母、数字、符号两种类型组合的密码长度为8位。'
this.passStr = ""
//console.log('密码-----',value)
}
},
// 清除验证码
OpenClear() {
clearInterval(clear)
this.PhoneEmailNote = '获取验证码';
this.readonly = false;
},
// 获取验证码
emPHCode() {
clear && clearInterval(clear);
this.readonly = true
this.PhoneEmailNote = '60S';
var s = 60;
clear = setInterval(() => {
s--;
this.PhoneEmailNote = s + 'S';
if (s <= 0) {
clearInterval(clear);
this.PhoneEmailNote = '获取验证码';
this.readonly = false;
}
}, 1000);
},
// 发送验证码
onSetCode(e) {
if (this.readonly) {
return;
}
if (e == 'phone') {
if (this.userMes.phone == '') {
uni.showToast({
title: '请输入手机号',
icon: 'none'
});
return;
}
if (this.userMes.quCode == '' || this.userMes.quCode == 86) {
if (!this.$base.phoneRegular.test(this.userMes.phone)) {
uni.showToast({
title: '手机格式不正确',
icon: 'none'
});
return;
}
}
this.$http
.get('book/user/sms/sendcode', {
phone: this.userMes.phone,
areaCode: this.userMes.quCode,
type: 2000
})
.then(res => {
uni.showToast({
title: '验证码发送成功',
icon: 'none'
});
this.emPHCode();
});
}
if (e == 'email') {
if (!this.userMes.email) {
uni.showToast({
title: '请输入邮箱',
icon: 'none'
});
return;
}
if (!this.$base.mailRegular.test(this.userMes.email)) {
uni.showToast({
title: '邮箱格式不正确',
icon: 'none'
});
return;
}
this.$http
.get('book/user/getMailCaptcha', {
email: this.userMes.email
})
.then(res => {
uni.showToast({
title: '验证码发送成功',
icon: 'none'
});
this.emPHCode();
});
}
},
// 手机
chosePhone(e) {
this.userMes.code = this.userMes.phonecode
if (this.userMes.phone == '') {
uni.showToast({
title: '请输入手机号',
icon: 'none'
});
return;
}
if (this.userMes.code == '' || this.userMes.code == null) {
uni.showToast({
title: '请输入验证码',
icon: 'none'
});
return;
}
let that = this
$http.request({
url: "book/user/updateUserTel",
method: "POST",
data: this.userMes,
header: {
'Content-Type': 'application/json'
},
}).then(function(res) {
if (res.code == 0) {
that.getData();
that.phoneShow = false
uni.showToast({
title: "绑定手机号成功"
});
}
}).catch(function(error) {
console.log(error);
});
},
// 邮箱
choseEmail(e) {
this.userMes.code = this.userMes.emailcode
if (this.userMes.email == '') {
uni.showToast({
title: '请输入邮箱',
icon: 'none'
});
return;
}
if (this.userMes.code == '' || this.userMes.code == null) {
uni.showToast({
title: '请输入验证码',
icon: 'none'
});
return;
}
let that = this
$http.request({
url: "book/user/updateUserEmail",
method: "POST",
data: this.userMes,
header: {
'Content-Type': 'application/json'
},
}).then(function(res) {
if (res.code == 0) {
that.getData();
that.emailShow = false
uni.showToast({
title: "绑定邮箱成功"
});
}
}).catch(function(error) {
console.log(error);
});
},
// 头像
choseAvatar(e) {
let that = this
if (that.fileAvatar.length == 0) {
uni.showToast({
title: "请选择图片",
icon: 'none'
});
return
}
that.userMes.avatar = that.fileAvatar[0].url
that.choseData()
that.avatarShow = false
that.fileAvatar.splice(0, 1)
},
// 年龄
choseAge(e) {
let that = this
if (that.userMes.age <= 0) {
uni.showToast({
title: "年龄不能小于0",
icon: 'none'
});
return
}
that.choseData()
that.ageShow = false
},
// 昵称
choseNickname(e) {
let that = this
if (e && e != '') {
that.choseData()
that.nicknameShow = false
} else {
that.userMes.nickname = that.userMes.oldName
console.log(that.userMes.nickname)
uni.showToast({
title: '昵称不可为空',
icon: 'none'
})
}
},
// 性别
choseSex(e) {
let that = this
that.userMes.sex = e
that.choseData()
that.sexShow = false
},
// 修改密码
chosePassword() {
if (!this.passwordOk) {
console.log('不满足密码格式', this.passNote)
uni.showToast({
title: this.passNote,
icon: 'none'
})
return
}
let that = this
if (that.userMiMa.Repassword == '' || that.userMiMa.password == '') {
uni.showToast({
icon: "none",
title: "请输入密码!"
});
return
}
if (that.userMiMa.Repassword != that.userMiMa.password) {
uni.showToast({
icon: "none",
title: "两次密码输入不一致!"
});
return
}
$http.request({
url: "book/user/updateUserPassword",
method: "POST",
data: that.userMiMa,
header: {
'Content-Type': 'application/json'
},
}).then(function(res) {
if (res.code == 0) {
uni.showToast({
title: "修改成功"
});
that.passwordShow = false
}
}).catch(function(error) {
console.log(error);
});
},
// 修改个人资料
choseData() {
let that = this
$http.request({
url: "book/user/update",
method: "POST",
data: that.userMes,
header: {
'Content-Type': 'application/json'
},
}).then(function(res) {
if (res.code == 0) {
that.getData();
// that.$forceUpdate()
uni.showToast({
title: "修改成功"
});
}
}).catch(function(error) {
console.log(error);
});
},
// 头像上传
afterRead(e) {
let that = this
uni.uploadFile({
url: this.$baseUrl + 'oss/fileoss',
filePath: e.file[0].url,
name: 'file',
formData: {},
success: (res) => {
that.fileAvatar.push({
url: JSON.parse(res.data).url
})
}
});
},
// 删除图片
deletePic() {
let that = this
that.fileAvatar.splice(0, 1)
},
},
};
</script>
<style lang="scss" scoped>
@import '@/style/mixin.scss';
.btn_box {
margin-top: 40rpx;
padding: 10px;
button {
font-size: 32rpx;
background-color: #e5e5e5;
color: #fff;
height: 80rpx;
line-height: 80rpx;
border-radius: 50rpx;
&.active {
@include theme('btn_bg') color: #fff;
}
}
}
.tabulate {
.per_list {
font-size: 30rpx;
background-color: #fff;
padding: 0;
align-items: center;
position: relative;
border-top: 1px solid #e5e5e5;
width: 100%;
overflow: auto;
text.biaoti {
color: #333;
display: inline-block;
margin: 25rpx 0 25rpx 40rpx;
}
text.neirong {
color: #888;
font-weight: normal;
float: right;
margin: 25rpx 80rpx 0 0;
display: block;
}
text.marPer {
color: #fff;
font-weight: normal;
float: right;
margin: 25rpx 0 0 0;
display: block;
border-radius: 10rpx;
background-color: #eee;
padding: 2rpx 10rpx;
}
}
.per_list_arrow {
font-size: 30rpx;
background-color: #fff;
padding: 0;
align-items: center;
position: relative;
border-top: 1px solid #e5e5e5;
width: 100%;
overflow: auto;
&:active {
background-color: #f5f5f5;
}
&::after {
content: '';
position: absolute;
right: 20upx;
top: 50%;
transform: translateY(-50%);
width: 40upx;
height: 40upx;
background-image: url('../../static/icon/icon_right.png');
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
.per_mes_img {
width: 100rpx;
height: 100rpx;
background-color: #fff;
border-radius: 120rpx;
margin: 10rpx 0;
}
}
}
.tanchu {
padding: 60rpx 50rpx 80rpx 50rpx;
.dp_title {
font-size: 32rpx;
margin-bottom: 50rpx;
color: #555;
text-align: center;
font-weight: bold;
}
.dp_sex {
font-size: 30rpx;
padding-bottom: 20rpx;
margin-bottom: 20rpx;
border-bottom: 1px solid #ededed;
image {
width: 40rpx;
height: 40rpx;
display: inline-block;
margin-right: 20rpx;
vertical-align: bottom;
}
}
.dp_canBtn {
text-align: center;
font-size: 28rpx;
margin-top: 25rpx;
color: #888;
}
.emPHCode {
height: 80rpx;
width: 200rpx;
background-color: #f8f9fb;
font-size: 28rpx;
padding: 0 14rpx;
color: #54a966;
line-height: 80rpx;
margin: 20rpx 0 0 20rpx;
display: inline-block;
}
.quhao {
height: 60rpx;
width: 240rpx;
margin: 1rpx 15rpx 0 0;
.quhaoSel {
/deep/.uni-select {
font-size: 24rpx;
}
/deep/.uni-select__selector-item {
font-size: 24rpx;
}
/deep/.uni-stat__select {
height: 60rpx;
}
}
}
}
</style>

75
pages/user/protocol.vue Normal file
View File

@@ -0,0 +1,75 @@
<template>
<view class="protocol_page">
<z-nav-bar title="协议"></z-nav-bar>
<!-- 公共组件-每个页面必须引入 -->
<public-module></public-module>
<view class="title">{{title}}</view>
<jyf-parser ref="article"></jyf-parser>
</view>
</template>
<script>
export default {
data() {
return {
type:1000,
title:"用户协议"
};
},
//第一次加载
onLoad(e) {
console.log(e)
if(e.type){
this.type = parseInt(e.type);
let title;
switch (this.type) {
case 1000:
title = "登录注册用户协议";
break;
}
this.title = title;
}
this.pageData();
},
//页面显示
onShow() {},
//方法
methods: {
pageData() {
this.$http
.get('api/common/v1/protocol', {
type: this.type
})
.then(res => {
console.log(res)
this.$refs.article.setContent(res);
});
}
},
//页面隐藏
onHide() {},
//页面卸载
onUnload() {},
//页面下来刷新
onPullDownRefresh() {},
//页面上拉触底
onReachBottom() {},
//用户点击分享
onShareAppMessage(e) {
return this.wxShare();
}
};
</script>
<style lang="scss" scoped>
@import '@/style/mixin.scss';
.protocol_page {
background-color: #fff;
padding: 30upx;
font-size: 30upx;
line-height: 180%;
.title {
font-size: 50upx;
padding-bottom: 30upx;
}
}
</style>

300
pages/user/register.vue Normal file
View File

@@ -0,0 +1,300 @@
<template>
<view class="page">
<z-nav-bar></z-nav-bar>
<!-- 公共组件-每个页面必须引入 -->
<public-module></public-module>
<view class="title">注册</view>
<view class="input_box">
<text class="input_tit">手机号</text>
<input type="text" v-model="phone" placeholder="请输入手机号" />
</view>
<view class="input_box">
<text class="input_tit">验证码</text>
<input type="number" v-model="code" placeholder="请输入验证码" />
<button @click="getCode">{{codeText}}</button>
</view>
<view class="input_box">
<text class="input_tit">密码</text>
<input password v-model="password" placeholder="请输入密码" />
</view>
<view class="input_box">
<text class="input_tit">确认密码</text>
<input password v-model="confirmPassword" placeholder="请确认密码" />
</view>
<view class="input_box">
<text class="input_tit">推荐码</text>
<input type="text" v-model="recommendCode" placeholder="推荐码(非必填)" @confirm="onSubmit" />
</view>
<view class="protocol_box">
<view class="select" :class="{active: agree}" @click="agree = !agree"></view>
我已同意
<text @click="onPageJump('/pages/user/protocol')">用户协议</text>
<text @click="onPageJump('/pages/user/protocol')">隐私协议</text>
</view>
<view class="btn_box"><button @click="onSubmit"> </button></view>
</view>
</template>
<script>
import md5 from '@/plugins/md5';
var clear;
export default {
data() {
return {
//手机号
phone: '',
// 密码
password: '',
//验证码
code: '',
//确认密码
confirmPassword: '',
// 推荐码
recommendCode: "",
//验证码
codeText: '获取验证码',
//验证码已发
readonly: false,
agree: false,
};
},
//第一次加载
onLoad(e) {},
//页面显示
onShow() {},
//方法
methods: {
onJumpPage(url) {
uni.navigateTo({
url: url
});
},
//获取验证码
getCode() {
if (this.readonly) {
uni.showToast({
title: '验证码已发送',
icon: 'none'
});
return;
}
if (!this.phone) {
uni.showToast({
title: '请输入手机号',
icon: 'none'
});
return;
}
if (!this.$base.phoneRegular.test(this.phone)) {
uni.showToast({
title: '请输入正确的手机号',
icon: 'none'
});
return;
}
this.$http
// .post('api/common/v1/send_sms', {
.post('book/user/sms/sendcode', {
phone: this.phone,
type: 1000
})
.then(res => {
this.getCodeState();
});
},
//验证码按钮文字状态
getCodeState() {
const _this = this;
this.readonly = true;
this.codeText = '60S后重新获取';
var s = 60;
clear = setInterval(() => {
s--;
_this.codeText = s + 'S后重新获取';
if (s <= 0) {
clearInterval(clear);
_this.codeText = '获取验证码';
_this.readonly = false;
}
}, 1000);
},
onSubmit() {
if (!this.agree) {
uni.showToast({
title: '请先同意《用户协议》和《隐私协议》',
icon: 'none'
});
return;
}
if (!this.phone) {
uni.showToast({
title: '请输入手机号',
icon: 'none'
});
return;
}
if (!this.$base.phoneRegular.test(this.phone)) {
uni.showToast({
title: '请输入正确的手机号',
icon: 'none'
});
return;
}
if (!this.code) {
uni.showToast({
title: '请输入验证码',
icon: 'none'
});
return;
}
if (!this.password) {
uni.showToast({
title: '请输入密码',
icon: 'none'
});
return;
}
if (!this.confirmPassword) {
uni.showToast({
title: '请输入确认密码',
icon: 'none'
});
return;
}
if (this.confirmPassword != this.password) {
uni.showToast({
title: '两次密码不一致',
icon: 'none'
});
return;
}
if (!this.$base.passwordRegular.test(this.password)) {
uni.showToast({
title: '请输入不少于6位且包含数字和字母的密码',
icon: 'none'
});
return;
}
let httpData = {
tel: this.phone,
code: this.code,
// password: md5(this.password),1
password: this.password,
};
if (this.recommendCode) {
httpData.recommendCode = this.recommendCode;
}
this.$http
.post('book/user/register', httpData)
.then(res => {
uni.showModal({
title: "提示",
content: "注册成功!",
showCancel: false,
success: (res) => {
uni.navigateBack();
}
});
});
}
},
//页面隐藏
onHide() {},
//页面卸载
onUnload() {},
//页面下来刷新
onPullDownRefresh() {},
//页面上拉触底
onReachBottom() {},
//用户点击分享
onShareAppMessage(e) {
return this.wxShare();
}
};
</script>
<style lang="scss" scoped>
@import '@/style/mixin.scss';
.page {
background-color: #FFF;
padding: 0 65rpx;
min-height: 100vh;
.title {
padding: 60rpx 0 40rpx 0;
font-size: 60rpx;
color: #333333;
}
.input_box {
display: flex;
justify-content: space-between;
height: 100rpx;
padding-top: 30rpx;
border-bottom: 1rpx solid #eeeeee;
align-items: center;
text{
font-size: 30rpx;
width: 180rpx;
}
input {
flex: 1;
height: 70rpx;
line-height: 80rpx;
font-size: 30rpx;
}
button {
height: 78rpx;
line-height: 78rpx;
font-size: 30rpx;
color: $themeColor;
&:active {
background-color: transparent;
}
}
}
.btn_box {
margin-top: 40rpx;
button {
font-size: 32rpx;
@include theme('btn_bg') color: #fff;
height: 80rpx;
line-height: 80rpx;
border-radius: 50rpx;
}
}
.protocol_box {
margin-top: 40rpx;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
font-size: 28rpx;
color: #333333;
.select {
width: 36rpx;
height: 36rpx;
background-image: url("../../static/icon/ic_gender_unselected.png");
background-position: center center;
background-repeat: no-repeat;
background-size: 100% auto;
margin-right: 15rpx;
&.active {
background-image: url("../../static/icon/ic_agreed.png");
}
}
>text {
color: $themeColor;
}
}
}
</style>

1255
pages/user/visitor.vue Normal file

File diff suppressed because it is too large Load Diff

BIN
static/biaoqing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
static/icon/b1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 118 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
static/learing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 821 B

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,18 +1,38 @@
@charset "utf-8";
//主题色
$themeColor: #54a966;
$themeColor: #258feb;
// 页面背景色
$containerColor: #f4f7ff;
@mixin theme($type,$path:''){
@if $type == "btn_bg" {
background-image: linear-gradient(90deg, #54a966 0%, #117e4c 100%);
background-image: linear-gradient(90deg, #258feb 0%, #00e1ec 100%);
} @else if $type == "unselected_img" {
background-image: url($path + "static/icon/ic_gender_unselected.png");
} @else if $type == "check_img" {
background-image: url($path + "static/icon/ic_agreed.png");
} @else if $type == "radio_img" {
background-image: url($path + "static/icon/ic_gender_selected.png");
} @else if $type == "fourIcon" {
background-image: linear-gradient(180deg, #e4edff 0%, #fff 100%);
}
}
// 左右paddingpx
@mixin pleft_right($p) {
padding-left:$p ;
padding-right: $p;
// background-image: url($url);
}
// 上下paddingpx
@mixin ptop_bottm($p) {
padding-bottom:$p ;
padding-top: $p;
}
// 外围阴影
@mixin mshadow($size,$opacity) {
box-shadow: 0px 0px $size 0px rgba(167, 187, 228, $opacity);
}
// 背景图片地址和大小
@mixin bis($url, $size: cover) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 369 KiB

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB