2023.09.01

This commit is contained in:
@fawn-nine
2023-09-01 18:04:41 +08:00
parent ef6c52c0d4
commit 7b9044f4df
13 changed files with 1135 additions and 260 deletions

View File

@@ -1,126 +1,844 @@
<template>
<view>
<view class="top">
<z-nav-bar title="读书打卡"></z-nav-bar>
<uni-calendar
:insert="true"
:lunar="true"
:start-date="'2019-3-2'"
:end-date="'2019-5-20'"
@change="change"
/>
<view class="container">
<z-nav-bar title="读书打卡"></z-nav-bar>
<!-- 仿钉钉打卡日历组件 -->
<view class="calendar_container">
<!-- <zsy-calendar @change="change" /> -->
<!-- <clock-date></clock-date> -->
<view class="calendar_info">
<text class="title">读书打卡</text>
<view class="dakaBtn" @tap="kuickSign()" v-if="signList.indexOf(currentDay) == -1">
<u-icon name="checkbox-mark" color="#55aa7f" size="24" style="display: inline;"></u-icon>
<text>签到</text>
</view>
<view v-else class="haveSignText">
<text>今天已签到</text>
</view>
</view>
<scroll-view class="scroll-view_H flexbox" scroll-x="true" @scroll="scroll" :scroll-left="scrollLeft">
<view class="" style="padding: 0 6rpx; display: inline-block; width: 20%; box-sizing: border-box; " v-for="(item,index) in 365">
<view
:class="['item', signList.indexOf(index+1) != -1 ? 'havSign' : '',
currentDay == index+1 && signList.indexOf(index+1) == -1 ? 'current' : '',
linshiDay == index+1 ? 'linshiDay':'']" @click="getInfo(index+1)">
<span class="day"> <em>{{index+1}}</em> </span>
<u-icon v-if="signList.indexOf(index+1) != -1" name="checkbox-mark" color="#fff" size="28" style="margin: 0 auto; width: 28px; text-align: center;"></u-icon>
<span v-if="signList.indexOf(index+1) == -1 && currentDay > index+1" class="buka">未签</span>
<span v-if="currentDay < index+1" class="weidaka">未开始</span>
<span v-if="currentDay == index+1 && signList.indexOf(index+1) == -1" class="daka" @click="kuickSign()">签到</span>
</view>
</view>
</scroll-view>
</view>
<view class="container1">
<view class="task" v-if="taskInfo !== {}">
<view class="title" v-if="taskInfo.heading">
{{taskInfo.heading}}
</view>
<view class="video " v-if="taskInfo.video">
<!-- 视频形式的任务 -->
<view class="taskinfo">
<video id="myVideo" :poster="poster" v-show="!addTextShow"
:src="taskInfo.video"
@error="videoErrorCallback" controls></video>
</view>
</view>
<view class="image " v-if="taskInfo.images">
<!-- 图片形式的任务 -->
<image :src="taskInfo.images" style="width: 100%;" mode="aspectFit"></image>
</view>
<!-- <view class="voice ">
音频形式的任务
<audio style="text-align: center; width: 100%;" :src="currentAudio.src"
:poster="currentAudio.poster" :name="currentAudio.name" :author="currentAudio.author"
:action="audioAction" controls></audio>
</view> -->
<view class="txt" v-if="taskInfo.content" v-html="taskInfo.content"></view>
</view>
<view class="subContent">
<text class="clockTitle">-- 我的签到 --</text>
<!-- 未打卡 -->
<!-- 已打卡 -->
<view class="had" v-if="show">
<view class="item">
<h3>#第三课专业变现你的专业 = 超级杠杆 第一笔只是财富#</h3>
<view class="content">
借我一个暮年借我碎片
借我瞻前与顾后借我执拗如少年
借我后天长成的先天借我变如不曾改变
借我素淡的世故和明白的愚借我可预知的险
借我悲怆的磊落借我温软的鲁莽和玩笑的庄严
借我最初与最终的不敢借我不言而喻的不见
借我一场秋啊可你说这已是冬天
</view>
<view class="images flexbox">
<image @click="previewImage()"
src="https://picx.zhimg.com/70/v2-92392172531ba8e252e3f9afaa4232d2_1440w.awebp?source=172ae18b&biz_tag=Post"
mode="aspectFill"></image>
<image
src="https://picx.zhimg.com/70/v2-92392172531ba8e252e3f9afaa4232d2_1440w.awebp?source=172ae18b&biz_tag=Post"
mode="aspectFill"></image>
</view>
<view class="opBtns flexbox">
<span class="flexbox"><u-icon name="clock" color="#b3b3b3"></u-icon>2023-08-23 14:01</span>
</view>
</view>
</view>
</view>
<!-- 他人的打卡记录 -->
<view class="" v-if="commentsList && commentsList.length > 0">
<view class="pingjiaBox" v-for="(item, index) in commentsList" :key="index">
<view class="flexbox">
<view class="touxiang">
<image :src="item.avatar" mode="aspectFit"></image>
<text class="username nowrap ">{{item.name}}</text>
</view>
<view class="contentBox">
<div class="pjimgs flexbox">
<view class="item" v-for="(item1,index) in item.images">
<image v-if="item1.length > 10" @click="previewImage(item1)" :src="item1" mode="aspectFill" style="width:100%; height: 50px;"></image>
</view>
</div>
<view class="content" v-html="item.phtml"></view>
<text class="time">{{item.createdate}}</text>
</view>
</view>
<!-- 显示追平 -->
<view class="zhuiping item" v-if="item.zphtml != ''" style="padding-left: 50px;">
<h5 style="color: #dbdbdb; margin:10px;">追评内容</h5>
<view class="flexbox">
<view class="contentBox">
<view class="content" v-html="item.zphtml"></view>
<text class="time">{{item.followUpdate}}</text>
</view>
</view>
</view>
</view>
</view>
<view class="quesheng" v-else>
<text>暂无评价~</text>
</view>
</view>
<u-popup mode="bottom" :show="addTextShow" :round="10" @close="addTextShow=false">
<view class="tanchu">
<view class="dp_title">今日签到随想</view>
<view style="max-height: 1000rpx;overflow-y: scroll;">
<!-- 提交 -->
<view class="padding-bottom-sm flex padding-lr-sm" style="border-bottom: 1px solid #EEEEEE;">
<view class="mb30">
<!-- <uni-file-picker :auto-upload="false" ref="files" @delete="deleteImg" limit="5" @success="upSuccess" @select="select" v-model="Pform.img" fileMediatype="image" :image-styles="imageStyles"/> -->
<u-upload :fileList="formData.images" @afterRead="afterRead" @delete="deletePic" multiple
:maxCount="4" width="80" height="80" :previewFullImage="true">
</u-upload>
</view>
<view class="flex-sub flexbox mb30">
<i @click="showEmj()" :class="emojiIcon"></i>
<!-- <input type="text" @focus="InputFocus" @blur="InputBlur" v-model="message" @input="textareaBInput" placeholder-style="font-size:24rpx;color:#aaaaaa;" placeholder="请输入您要发送的内容"></input> -->
<textarea style="border: 1px solid #EEEEEE;" class="textarea" v-model="formData.content"
@focus="InputFocus" @blur="InputBlur" @input="textareaBInput"
placeholder-style="font-size:24rpx;color:#aaaaaa;" placeholder="请输入内容"></textarea>
</view>
<view>
<u-button type="success" @click="goToSign">提交</u-button>
</view>
</view>
<view style="position: relative;">
<emotion @emotion="handleEmj" :height="220" v-if="isShowEmj" :windowWidth="windowWidth">
</emotion>
</view>
</view>
</view>
</u-popup>
<view class="leaveBtn" v-if="!addTextShow">
<button type="primary" plain="true" @click="addTextShow = true">说点什么</button>
</view>
<music-play :playData="playData"></music-play>
<z-navigation></z-navigation>
<!-- <z-navigation></z-navigation> -->
</view>
</template>
<script>
import $http from '@/config/requestConfig.js';
import emotion from '@/bkhumor-emojiplus/components/bkhumor-emojiplus/bkhumor-emojiplus.vue';
import zsyCalendar from '@/components/zsy-calendar/zsy-calendar'
import clockDate from '@/components/clockDate.vue'
import musicPlay from '@/components/music.vue'
function getDate(date, AddDayCount = 0) {
if (!date) {
date = new Date()
}
if (typeof date !== 'object') {
date = date.replace(/-/g, '/')
}
const dd = new Date(date)
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
const y = dd.getFullYear()
const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期不足10补0
const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号不足10补0
return {
fullDate: y + '-' + m + '-' + d,
year: y,
month: m,
date: d,
day: dd.getDay()
}
}
import {
mapState
} from 'vuex';
export default {
data() {
return {
playData:{},
showCalendar: false,
info: {
lunar: true,
range: true,
insert: false,
selected: []
}
commentsList:[], // 他人的打卡列表
addTextShow: false, // 说点什么弹出层
show: false,
scrollLeft: 0, // 距离左侧的距离
currentDay:1, // 当前打卡位置
currentTid:null, // 今天的任务id
emojiIcon: 'cuIcon-emoji',
windowWidth: 0,
taskInfo:{
heading:''
},
emoji: [],
signList:[], // 已打卡天
linshiDay:null,
page: 1,
bookid: null,
windowHeight: 500,
isShowEmj: false,
playData: {},
videoContext: null,
innerAudioContext: null, // 音频对象
poster: '',
formData: {
// 打卡表单
content: '',
images: []
},
currentAudio: {
poster: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/music-a.png',
name: '致爱丽丝',
author: '暂无',
src: 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-hello-uniapp/2cc220e0-c27a-11ea-9dfb-6da8e309e0d8.mp3',
},
audioAction: {
method: 'pause'
},
// 校验规则
rules: {
content: {
rules: [{
required: true,
errorMessage: '内容不能为空'
}]
},
},
}
},
onLoad(e) {
this.bookid = e.bookid
this.windowWidth = uni.getSystemInfoSync().windowWidth;
this.getmySign()
},
onReady() {
this.$nextTick(() => {
this.showCalendar = true
})
// TODO 模拟请求异步同步数据
setTimeout(() => {
this.info.date = getDate(new Date(),-30).fullDate
this.info.startDate = getDate(new Date(),-60).fullDate
this.info.endDate = getDate(new Date(),30).fullDate
this.info.selected = [{
date: getDate(new Date(),-3).fullDate,
info: '打卡'
},
{
date: getDate(new Date(),-2).fullDate,
info: '签到',
data: {
custom: '自定义信息',
name: '自定义消息头'
}
},
{
date: getDate(new Date(),-1).fullDate,
info: '已打卡'
}
]
}, 2000)
},
this.videoContext = uni.createVideoContext('myVideo')
this.innerAudioContext = uni.createInnerAudioContext();
this.innerAudioContext.autoplay = false;
},
computed: {
...mapState(['userInfo'])
},
methods: {
open() {
this.$refs.calendar.open()
},
close(){
console.log('弹窗关闭');
},
change(e) {
console.log('change 返回:', e)
// 模拟动态打卡
if (this.info.selected.length > 5) return
this.info.selected.push({
date: e.fulldate,
info: '打卡'
})
},
confirm(e) {
console.log('confirm 返回:', e)
},
monthSwitch(e) {
console.log('monthSwitchs 返回:', e)
// 放大图片
previewImage(url){
console.log(url)
uni.previewImage({
urls: [url]
});
},
// 获取打卡参数
getmySign(){
let data = {
'bookId': this.bookid,
'userId': this.userInfo.id
}
this.$http
.post('book/clockinPunch/clockindays', data)
.then(res => {
if (res.code == 0) {
this.currentDay = res.daysBetween
this.signList = res.dayslist
console.log(res, '打卡参数')
let zheng = Math.floor(this.currentDay / 5)
let yu = this.currentDay % 5
if(this.currentDay <=5){this.scrollLeft = 0}
if(zheng >= 1 && yu > 0){
// 不是前五个,并且不能整除
this.scrollLeft = (this.windowWidth - 30) * zheng
}
if(zheng > 1 && yu == 0){
this.scrollLeft = (this.windowWidth - 30) * (zheng - 1)
}
// console.log(zheng, yu, this.scrollLeft, this.windowWidth, 'this.scrollLeft')
this.getTask(this.currentDay)
this.getAllSign(this.currentDay)
}
});
},
// 获取签到详情
getInfo(index){
if(this.currentDay < index){
uni.showToast({
title:'未来日期不可签到',
icon: 'none'
})
}else{
this.linshiDay = index
this.getTask(index)
this.getAllSign(index)
}
},
// 获取某天的签到列表信息
getAllSign(index){
let data = {
'bookid': this.bookid,
'limit': 5,
'page': this.page,
'taskid': index
}
console.log(data)
this.$http
.post('book/clockin/applist', data)
.then(res => {
if (res.code == 0) {
console.log(res, '所有人打卡信息')
this.commentsList = res.page.list
}
});
},
// 获取对应签到内容
getTask(index){
let data = {
'bookid': this.bookid,
'days': index
}
console.log(data)
this.$http
.post('book/task/applist', data)
.then(res => {
if (res.code == 0) {
console.log(res, '任务信息')
this.taskInfo = res.page.list[0]
this.taskInfo.video != ''? this.poster = this.taskInfo.video + "?x-oss-process=video/snapshot,t_0,f_jpg" : ''
}
});
},
// 快捷签到
kuickSign(){
let data = {
"bookId": this.bookid,
"userId": this.userInfo.id,
"tid": this.taskInfo.id,
"days":this.currentDay
}
// console.log(data,'data')
$http.request({
url : 'book/clockinPunch/save',
method: "POST", // POST、GET、PUT、DELETE具体说明查看官方文档
data,
header: { //默认 无 说明:请求头
'Content-Type': 'application/json'
},
}).then(res => {
if (res.code == 0) {
//console.log(res, '快捷签到')
uni.showToast({
title:res.msg
})
this.addTextShow = false
this.formData.content = ''
this.formData.images = []
this.getmySign()
this.getAllSign(this.currentDay)
}
});
},
// 说点什么
goToSign() {
let data = {
'bookId': this.bookid,
"userId": this.userInfo.id,
"taskId": this.currentDay,
"content": this.formData.content,
"images": this.formData.images.join(),
}
// console.log(data,'data')
var surl = ''
if(this.signList.indexOf(this.currentDay) != -1){
surl='book/clockin/update'
}else{
surl = 'book/clockin/save'
}
$http.request({
url : surl,
method: "POST", // POST、GET、PUT、DELETE具体说明查看官方文档
data,
header: { //默认 无 说明:请求头
'Content-Type': 'application/json'
},
}).then(res => {
if (res.code == 0) {
//console.log(res, '快捷签到')
uni.showToast({
title:res.msg
})
this.addTextShow = false
this.formData.content = ''
this.formData.images = []
this.getmySign()
this.getAllSign(this.currentDay)
}
});
},
scroll(e) {
},
// 获得输入的表情数组
handleEmj(i) {
console.log(i, 'i---------');
// this.inputValue = i
// console.log(this.inputValue);
if (i.emotioni == '[em_98]') {
//匹配最后一个表情符号并删除11。
this.formData.content = this.formData.content.replace(/(\[[^\]]+\]|[\s\S])$/, '');
if (this.emoji.length > 0) {
this.emoji = this.emoji.slice(0, -1)
}
} else {
this.emoji.push({
'tag': i.emotion,
'name': i.emotioni
})
// console.log(this.emoji,'this.emoji')
this.formData.content += i.emotioni;
/// this.Pform.html += i.emotion
}
},
// 放大图片
previewImage(url) {
console.log(url)
uni.previewImage({
urls: [url]
});
},
showEmj() {
let bool = !this.isShowEmj;
if (bool) {
this.emojiIcon = 'cuIcon-keyboard';
} else {
this.emojiIcon = 'cuIcon-emoji';
}
this.isShowEmj = bool;
this.$emit('show')
},
textareaBInput(e) {
this.formData.comment = e.detail.value
},
InputBlur(e) {
},
InputFocus(e) {
this.isShowEmj = false;
this.emojiIcon = 'cuIcon-emoji';
this.$emit('foc')
},
// 处理格式
getHtmlComment(comment) {
// 格式化html
// 这里处理 链接 换行符
let replacedStr = comment.replace(/\[([^(\]|\[)]*)\]/g, (item, index) => {
// console.log(item, index)
var indexss = emojiList1.findIndex(item1 => item1.alt === item)
// console.log(indexss, 'indexss')
return '<img src="https://www.nuttyreading.com/emojis/emojis/qq/' + emojiList1[indexss].url +
'" width="18rpx">';
});
// console.log(replacedStr,'replacedStr')
return replacedStr.replace(/(\r\n)|(\n)/g, '<br>');
},
// 提交打卡
submit() {
this.$refs['formData'].validate().then(res => {
console.log('success', res);
uni.showToast({
title: `校验通过`
})
}).catch(err => {
console.log('err', err);
})
},
deletePic() {
let that = this
that.formData.images.splice(0, 1)
//console.log(that.Pform.img)
},
afterRead(e) {
//console.log(e)
let that = this
for (var i = 0; i < e.file.length; i++) {
//console.log(i,e.file[i].url)
uni.uploadFile({
url: this.$baseUrl + 'oss/fileoss',
filePath: e.file[i].url,
//files:e.file,
name: 'file',
formData: {},
success: (res) => {
that.formData.images.push({
url: JSON.parse(res.data).url
})
}
});
}
},
videoErrorCallback: function(e) {
uni.showModal({
content: e.target.errMsg,
showCancel: false
})
},
// 日历选中日期改变事件回调
change(e) {
console.log(e)
}
},
components: {
musicPlay
},
musicPlay,
zsyCalendar,
emotion,
clockDate
},
}
</script>
<style lang="scss">
.example-body {
/* #ifndef APP-NVUE */
<style lang="scss" scoped>
.quesheng{text-align: center; margin-top: 100rpx; color: #8b8a91;}
.haveSignText{color: #999 ;}
.calendar_info {
display: flex;
/* #endif */
flex-direction: row;
}
.calendar-button {
flex: 1;
font-weight: bold;
font-size: 32rpx;
}
</style>
align-items: center;
justify-content: space-between;
padding: 20rpx;
.dakaBtn {
color: #55aa7f;
display: flex;
padding: 3rpx 5rpx;
border: #55aa7f 1px solid;
border-radius: 10rpx;
}
}
.scroll-view_H {
white-space: nowrap;
margin: 20px 0;
width: 100%;
.item {
border: 1px dashed #999;
width: calc(100% - 6rpx);
// margin: 0 6rpx;
text-align: center;
display: inline-block;
background-color: #F0FDFF;
border-radius: 20rpx;
padding: 6rpx 3rpx;
.day {display: block;
font-size: 26rpx;
color: #999;
em {
font-size: 36rpx;
font-style: normal;
font-weight: bold;
padding-right: 2px;
}
}
.checkbox-mark {
display: none;
}
.buka {
display: inline-block; padding: 0 6rpx;
color: #888;
// border: 1px solid #888;
margin: 10px 0;
border-radius: 15rpx;
margin-bottom: 0; ;
}
.weidaka {
color: #A3B4B5;
margin: 10px 0; font-size: 24;
border-radius: 20rpx;
margin-bottom: 0;
display: block;
}
.daka{
display: inline-block; padding: 0 6rpx;
border: 1px solid #55aaff;
color: #55aaff;
margin: 10px 0;
border-radius: 20rpx;
margin-bottom: 0;
display: block;
}
}
.item.havSign {
border: 1px solid #55aa7f;
text-align: center;
display: inline-block;
background-color: #55aa7f;
border-radius: 20rpx;
padding: 6px 6px;
.day {
font-size: 26rpx;
color: #fff;
em {
font-size: 32rpx;
font-style: normal;
font-weight: bold;
padding-right: 2px;
}
}
.checkbox-mark {
display: block;
}
}
.item.current{
border: 1px solid #55aaff;
text-align: center;
display: inline-block;
background-color: #edf9ff;
border-radius: 20rpx;
padding: 6px 6px;
.day {
font-size: 26rpx;
color: #55aaff;
em {
font-size: 32rpx;
font-style: normal;
font-weight: bold;
padding-right: 2px;
}
}
}
.item.linshiDay{
border: 1px solid #55aaff;
text-align: center;
display: inline-block;
background-color: #55aaff;
border-radius: 20rpx;
padding: 6px 6px;
.day {
font-size: 26rpx;
color: #fff;
em {
font-size: 32rpx;
font-style: normal;
font-weight: bold;
padding-right: 2px;
}
}
.buka{color: #fff; }
}
}
.dp_title {
font-size: 32rpx;
margin-bottom: 50rpx;
color: #555;
text-align: center;
font-weight: bold;
}
.mb30 {
margin-bottom: 30rpx;
}
.tanchu {
padding: 40rpx 30rpx 40rpx 30rpx;
position: relative;
}
.cuIcon-emoji {
background: url(../../static/biaoqing.png) no-repeat;
background-size: contain;
display: block;
margin-right: 20rpx;
width: 30px;
}
.cuIcon-keyboard {
background: url(../../static/biaoqing.png) no-repeat;
background-size: contain;
display: block;
width: 30px;
}
.leaveBtn {
position: fixed;
width: calc(100% - 4px);
background: #fff;
bottom: 1rpx;
left: 1px;
z-index: 1;
}
.task {
margin-top: 40rpx 20rpx;
.taskinfo {
video {
width: 100%;
}
}
}
.subContent {
margin-top: 20rpx;
background-color: #fff;
overflow: hidden;
.clockTitle {
color: #55aa7f;
font-size: 38rpx;
text-align: center;
display: block;
margin-top: 30rpx;
}
}
.container1 {
.margin-top {
margin-top: 30rpx;
overflow: hidden;
}
}
.container {
padding: 30rpx;
}
.calendar_container {
//min-height: calc(60vh);
background-color: #fff;
//padding: 30rpx;
box-sizing: border-box;
padding-bottom: 20rpx;
border-radius: 20rpx;
margin-bottom: 20rpx;
}
.task {
padding: 30rpx 20rpx;
background-color: #f5f5f5;
background-color: #fff;
padding-bottom: 50rpx;
.title {
margin-top: 30rpx;
padding: 30rpx;
color: #002968;
background-color: #fff;
font-size: 46rpx;
padding: 20rpx;
}
.item {}
.video {
border-radius: 0 0 20rpx 20rpx;
}
.txt {
margin-top: 30rpx;
color: #666;
line-height: 50rpx;
}
}
.haveNo {
background: #fff;
.box {
height: 20vh;
display: flex;
align-items: center;
button {
width: 50%;
margin: 0 auto;
}
}
.subform {
padding: 0 20rpx;
margin-top: 30rpx;
.btns {
width: 400rpx;
margin: 0 auto;
margin-bottom: 40rpx;
justify-content: space-between;
}
}
}
.had {
padding: 60rpx;
margin-top: 30rpx;
background-color: #fff;
h3 {
color: #8c9a92;
font-size: 34rpx;
}
.content {
line-height: 60rpx;
margin-top: 30rpx;
font-size: 30rpx;
color: #0e0e15;
}
.images {
height: 150rpx;
overflow: hidden;
margin-top: 30rpx;
image {
width: 150rpx;
margin: 0 10rpx;
}
}
.opBtns {
margin-top: 30rpx;
span {
color: #b3b3b3;
padding-left: 20rpx;
font-size: 24rpx;
}
}
}
.flexbox {
display: flex;
}
</style>