You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

741 lines
23 KiB

<template>
<view class="xin-calendar-out">
<view class="xin-calendar">
<view class="calendar-control-custom flex">
<view class="month-picker">
<picker class="custom-picker" mode="date" fields="month" :value="currentYearMonth" @change="handleMonthChange">
<text>{{currentYearMonthStr}}</text>
<img :src="cssUrl+'date_open.png'" class="date-open-icon">
</picker>
</view>
<view class="appointment-stats">
<!-- 本月到诊{{appointments.visited_count}}预约{{appointments.visit_count}} -->
本月利润 {{ totalProfit }}
</view>
</view>
<view class="calendar-header">
<view
class="calendar-week"
v-for="(item, index) in weeks"
:key="index"
>{{ item }}</view>
</view>
<view class="calendar-body">
<swiper
class="swiper"
:current="current"
circular
adjust-height="highest"
:autoplay="false"
:indicator-dots="false"
:interval="3000"
:duration="500"
@change="swiperChange"
@animationfinish1="swiperChange"
>
<swiper-item
class="swiper-item"
v-for="(calendar, calendarIndex) in calendarList"
:key="calendarIndex"
>
<view
class="calendar-line"
v-for="(line, lineIndex) in calendar.dateList"
:key="lineIndex"
>
<!--⬇️这个的click 不需要操作天 @click="clickEvent(item, index)" -->
<view
class="calendar-day"
v-for="(item, index) in line"
:key="index"
>
<!--暂且不需要对当天有特殊样式 active: activeDay === item.date -->
<view
:class="['day-item', {
can: item.type === 'day',
pre: item.type === 'pre',
next: item.type === 'next',
today: today === item.date,
}]"
>
<view :class="['label flex',(!appointments || !appointments[item.date])?'gray':'']">{{item.day}}<view v-if="today === item.date" class="totay-desc">今</view></view>
<!-- <view class="desc blue rest" v-if="appointments && appointments[item.date] && (appointments[item.date].visited==0 && appointments[item.date].total==0) && appointments[item.date].plan=='0'">休息</view> -->
<view :class="'desc green blue'+(appointments && appointments[item.date] )" v-if="appointments && appointments[item.date]">{{appointments[item.date]}}</view>
<view v-if="(!appointments || !appointments[item.date])" :class="'desc blue rest'">
</view>
<view class="desc blue" v-if="festival && item.lunarInfo.festival && item.type === 'day'">{{item.lunarInfo.festival}}</view>
<view class="desc" v-else-if="lunar">{{item.lunarInfo.IDayCn === '初一' ? item.lunarInfo.IMonthCn : item.lunarInfo.IDayCn}}</view>
<text class="dot" v-if="dots.indexOf(item.date) > -1"></text>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
<view class="notification-bar flex" v-if="chooseItem && (chooseItem.visited>0 || chooseItem.total>0)">
<img :src="cssUrl+'notification.svg'">
<text>{{activeDay.replace('-','年').replace('-','月')+'日'}}就诊详情:{{chooseItem.visited>0?'到诊'+chooseItem.visited+'人':''}}{{chooseItem.total>0?' 预约'+chooseItem.total+'人':''}}</text>
</view>
</view>
</template>
<script>
import moment from 'moment'
import XinTagBtn from './xin-tag-btn.vue'
import lunar from './lunar'
export default {
components: {
XinTagBtn,
},
props: {
value: {
type: String,
default: moment().format('YYYY-MM-DD'),
},
background: {
type: String,
default: '#ffffff'
},
showHeader: {
type: Boolean,
default: false
},
dots: {
type: Array,
default: () => [],
},
lunar: {
type: Boolean,
default: true,
},
festival: {
type: Boolean,
default: true,
},
totalVisits: {
type: Number,
default: 100
},
appointments:{
type: Object,
default: {}
}
},
data() {
return {
cssUrl:this.cssUrl1,
weeks: [ '日', '一', '二', '三', '四', '五', '六', ],
dateList: [],
today: moment().format('YYYY-MM-DD'),
activeDay: moment().format('YYYY-MM-DD'),
current: 1,
calendarList: [
{
date: moment().add(-1, 'months').startOf('month').format('YYYY-MM'),
dateList: [],
},
{
date: moment().startOf('month').format('YYYY-MM'),
dateList: [],
},
{
date: moment().add(1, 'months').startOf('month').format('YYYY-MM'),
dateList: [],
},
],
currentYearMonth:'',
currentYearMonthStr:'',
chooseItem:false,
}
},
computed: {
totalProfit(){
const sum = Object.values(this.appointments).reduce((acc, val) => acc + parseFloat(Number(val)), 0);
console.log(this.appointments,sum,'this.appointments==');
return sum
}
},
filters: {},
watch: {
value (n, o) {
this.activeDay = n
},
activeDay (n, o) {
this.$emit('input', n)
this.$emit('change', n)
this.init()
},
},
mounted() {
if (this.value) this.activeDay = this.value
var dateList = this.activeDay.split('-')
var currentYearMonth = dateList[0]+'-'+dateList[1]
this.jumpMonth(currentYearMonth, false)
this.init()
},
methods: {
init () {
this.calendarList.forEach((item, index) => {
item.dateList = this.createMonthDays(item.date)
})
let dateList = this.activeDay.split('-')
this.currentYearMonth = dateList[0]+'-'+dateList[1]
this.currentYearMonthStr = dateList[0]+'年'+dateList[1]+'月'
var timer = setInterval(function(){
if(this.appointments.list && this.appointments.list[this.activeDay]) {
this.chooseItem = this.appointments.list[this.activeDay]
clearInterval(timer)
}
}.bind(this), 10)
let searchData = this.getMonthStartEnd(this.currentYearMonth)
this.$emit('changeDate',searchData)
console.log(this.activeDay,'activeDay==init');
// let data = this.calendarList.find(item => item.date == this.currentYearMonth)
// console.log(this.calendarList,this.currentYearMonth,data,'tcalendarList===');
},
pre () {
this.current = this.current - 1 < 0 ? 2 : this.current - 1
},
next () {
this.current = this.current + 1 > 2 ? 0 : this.current + 1
},
setActiveDay(date) {
this.activeDay = date;
},
changeHosipital() {
this.current = 1
this.init()
},
jumpMonth(chooseYearMonth, isRequestData = true) {
var choosePreMonth = moment(chooseYearMonth).add(-1, 'months').startOf('month').format('YYYY-MM')
var chooseNextMonth = moment(chooseYearMonth).add(1, 'months').startOf('month').format('YYYY-MM')
this.calendarList = [
{
date: choosePreMonth,
dateList: [],
},
{
date: chooseYearMonth,
dateList: [],
},
{
date: chooseNextMonth,
dateList: [],
},
]
this.current = 1
if(isRequestData) this.init()
},
clickEvent (item, index) {
this.chooseItem = this.appointments.list[item.date]
// if(this.appointments.list && this.appointments.list[item.date] && this.appointments.list[item.date].plan=='0'){
// return;
// }
if (item.type !== 'day') return
this.activeDay = item.date
},
getMonthStartEnd(date){
let m = moment(date)
let searchData= {
start_date: moment(m).startOf('month').format('YYYY-MM-DD'),
end_date: moment(m).startOf('month').add(m.daysInMonth() - 1, 'days').format('YYYY-MM-DD'),
}
return searchData
},
createMonthDays(date) {
let list = [];
let monthInfo = this.getMomentInfo(date + '-01')
for (let i = 0; i < monthInfo.daysInMonth; i++) {
let dd = moment(monthInfo.firstDayInMonth).add(i, 'days')
let dayInfo = this.getMomentInfo(dd)
let day = {
type: 'day',
...dayInfo,
};
list.push(day);
}
let pre = [];
for (let i = 0; i < monthInfo.weekday; i++) {
let dd = moment(monthInfo.firstDayInMonth).add(-(monthInfo.weekday - i), 'days')
let dayInfo = this.getMomentInfo(dd)
pre.push({
type: 'pre',
...dayInfo,
});
}
let next = [];
let length = 42 - monthInfo.weekday - monthInfo.daysInMonth;
for (let i = 0; i < length; i++) {
let dd = moment(monthInfo.lastDayInMonth).add(i + 1, 'days')
let dayInfo = this.getMomentInfo(dd)
next.push({
type: 'next',
...dayInfo,
});
}
list = [...pre, ...list, ...next];
let result = [];
for (let i = 0; i < list.length; i += 7) {
result.push(list.slice(i, i + 7));
}
return result;
},
swiperChange (e) {
let current = e.detail.current
let preIndex = current - 1 > -1 ? current - 1 : 2
let nextIndex = current + 1 > 2 ? 0 : current + 1
let preMoment = moment(this.calendarList[current].date + '-01').add(-1, 'months')
if (preMoment.format('YYYY-MM') != moment().format('YYYY-MM')) {
preMoment = preMoment.startOf('month')
} else {
preMoment = moment()
}
this.calendarList[preIndex].date = preMoment.format('YYYY-MM')
let nextMoment = moment(this.calendarList[current].date + '-01').add(1, 'months')
if (nextMoment.format('YYYY-MM') != moment().format('YYYY-MM')) {
nextMoment = nextMoment.startOf('month')
} else {
nextMoment = moment()
}
this.calendarList[nextIndex].date = nextMoment.format('YYYY-MM')
if (moment().format('YYYY-MM') === this.calendarList[current].date) {
this.activeDay = moment().format('YYYY-MM-DD')
} else {
this.activeDay = this.calendarList[current].date + '-01'
}
this.$nextTick(() => {
// this.$emit('monthChange', this.activeDay)
})
},
getMomentInfo (date) {
let m = moment(date)
return {
moment: m,
firstDayInMonth: moment(m).startOf('month').format('YYYY-MM-DD'),
lastDayInMonth: moment(m).startOf('month').add(m.daysInMonth() - 1, 'days').format('YYYY-MM-DD'),
date: m.format('YYYY-MM-DD'),
year: m.format('YYYY'),
month: m.format('MM'),
day: m.format('DD'),
weekday: m.weekday(),
daysInMonth: m.daysInMonth(),
stamp: Number(m.format('x')),
lunarInfo: lunar.solar2lunar(Number(m.format('YYYY')), Number(m.format('MM')), Number(m.format('DD')))
}
},
handleMonthChange(e) {
const date = e.detail.value
this.currentYearMonth = moment(date).format('YYYY-MM')
this.currentYearMonthStr = moment(date).format('YYYY年MM月')
this.setActiveDay(this.currentYearMonth+'-01')
this.jumpMonth(this.currentYearMonth)
console.log(this.activeDay,this.currentYearMonth,'currentYearMonth==')
this.$nextTick(() => {
// this.$emit('monthChange', this.activeDay)
})
}
}
}
</script>
<style>
.custom-picker{
/* font-size: 36rpx;
color: red; */
}
.xin-calendar .calendar-control {
display: flex;
margin-bottom: 18rpx;
}
.xin-calendar .calendar-control .calendar-control-left {
flex: 1;
}
.xin-calendar .calendar-control .calendar-control-center {
display: flex;
justify-content: center;
align-items: center;
}
.xin-calendar .calendar-control .calendar-control-right {
flex: 1;
text-align: right;
}
.xin-calendar .calendar-header {
display: flex;
}
.xin-calendar .calendar-header .calendar-week {
flex: 1;
text-align: center;
line-height: 60rpx;
}
.xin-calendar .calendar-body .swiper {
height: 750rpx;
min-height: 750rpx;
}
.xin-calendar .calendar-body .swiper .swiper-item {
height: 750rpx;
min-height: 750rpx;
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line {
display: flex;
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
max-width: 96rpx;
max-height: 128rpx;
flex-shrink: 0;
border-radius: 10rpx;
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item {
width: 96rpx;
height: 96rpx;
display: flex;
flex-direction: column;
transition: all 0.15s;
position: relative;
border-radius: 10rpx;
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item .label {
font-size: 32rpx;
line-height: 32rpx;
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item .desc {
line-height: 32rpx;
font-size: 24rpx;
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item .desc.blue {
color: #39D067;
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.can.today {
background: #ffffff;
color: #39D067;
/* font-weight: bold; */
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.can.today .dot {
display: none;
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.can.active {
background: #39D067;
color: #ffffff;
font-weight: bold;
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.can.active .dot {
display: none;
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.can.active .desc.blue {
color: #ffffff;
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.can .dot {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 8rpx;
height: 8rpx;
border-radius: 100%;
background: #39D067;
}
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.pre,
.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.next {
}
</style>
<style lang="less">
// 源码修改可以在这里
// 尺寸
@font-size: 26rpx;
@space-width: 18rpx;
@radius-width: 18rpx;
// 颜色
@color-gray: #222222;
@color-blue: #39D067;
@color-green: #15bf81;
@color-yellow: #f7ab42;
@color-red: #ff6666;
@color-background: white;
// 方法
.shadow (@color: @color-gray, @x: 5rpx, @y: 5rpx, @r: 15rpx, @o: 3) {
}
.xin-calendar {
background-color: #fff;
border-radius: 8px;
padding: 36rpx 0rpx 36rpx 24rpx;
margin-top: 20rpx;
.calendar-control {
display: flex;
margin-bottom: @space-width;
.calendar-control-left {
flex: 1;
}
.calendar-control-center {
display: flex;
justify-content: center;
align-items: center;
}
.calendar-control-right {
flex: 1;
text-align: right;
}
}
.calendar-control-custom{
align-items: center;
justify-content: space-between;
height: 50rpx;
::v-deep .date-open-icon{
width: 32rpx;
height: 20rpx;
margin-left: 12rpx;
position: relative;
top: -2rpx;
}
.month-picker{
font-size: 36rpx;
font-weight: 600;
line-height: 50rpx;
color: #000000;
letter-spacing: 2rpx;
}
@supports (-webkit-touch-callout: none) {
.month-picker{
font-weight: 500;
}
}
.appointment-stats{
font-size: 26rpx;
line-height: 26rpx;
letter-spacing: normal;
color: #9E9E9E;
padding-right: 24rpx;
box-sizing: border-box;
}
}
.calendar-header {
margin-top: 36rpx;
display: flex;
.calendar-week {
flex: 1;
text-align: center;
width: 96rpx;
height: 48rpx;
line-height: 48rpx;
box-sizing: border-box;
font-size: 24rpx;
color: #333333;
}
}
.calendar-body {
.swiper {
height: 750rpx;
min-height: 750rpx;
.swiper-item {
height: 750rpx;
min-height: 750rpx;
display: flex;
flex-direction: column;
gap: 36rpx;
.calendar-line {
display: flex;
.calendar-day {
flex: 1;
display: flex;
justify-content: center;
align-items: baseline;
.day-item {
width: 96rpx;
height: auto;
max-width: 96rpx;
max-height: 128rpx;
flex-shrink: 0;
box-sizing: border-box;
padding: 6rpx 10rpx;
background: @color-background;
display: flex;
flex-direction: column;
align-items: center;
transition: all 0.15s;
position: relative;
.gray{
color: #C1C1C1 !important;
}
.label {
font-size: 34rpx;
line-height: 34rpx;
color: #333333;
height: 48rpx;
display: flex;
align-items: center;
font-weight: 500;
&.rest{
color:#C1C1C1 !important;
}
&.expire{
color:#999999;
}
.totay-desc{
width: 30rpx;
height: 30rpx;
line-height: 30rpx;
text-align: center;
border-radius: 2rpx;
background: #FF7D17;
font-size: 20rpx;
font-weight: 600;
color: #FFFFFF;
margin-left: 4rpx;
}
@supports (-webkit-touch-callout: none) {
.totay-desc{
font-weight: 500;
}
}
}
@supports (-webkit-touch-callout: none) {
.label{
font-weight: 500;
}
}
.desc {
line-height: 32rpx;
font-size: 24rpx;
max-width: 100%;
word-break: break-all;
text-align: center;
&.green{
color: @color-blue;
}
&.blue {
color: @color-blue;
&.rest{
color: #C1C1C1;
}
&.expire{
color: #999999;
}
}
}
&.can {
&.today {
background: #ffffff;
color: @color-blue;
// 字重正常
// font-weight: bold;
.shadow(@color: @color-gray, @o: 8);
.dot {
display: none;
}
&.active {
.label {
color: white;
font-weight: 600;
&.rest{
color:white !important;
}
}
@supports (-webkit-touch-callout: none) {
.label {
font-weight: 500;
}
}
}
}
&.active {
background: @color-blue;
color: #ffffff;
font-weight: bold;
.label {
color: white;
font-weight: 700;
&.rest{
color:white !important;
}
&.exprie{
color:white !important;
}
}
@supports (-webkit-touch-callout: none) {
.label{
font-weight: 600;
}
}
.shadow(@color: @color-blue, @o: 50);
.dot {
display: none;
}
.desc {
font-weight: normal;
&.blue {
color: #ffffff;
font-size: 24rpx;
line-height: 32rpx;
color: #FFFFFF;
}
&.expire{
color:white;
}
}
}
.dot {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 8rpx;
height: 8rpx;
border-radius: 100%;
background: @color-blue;
}
}
&.pre, &.next {
opacity: 0;
}
}
}
}
}
}
}
}
.xin-calendar-out{
.notification-bar{
width: 714rpx;
height: 68rpx;
align-items: center;
padding: 12rpx 24rpx;
box-sizing: border-box;
border-radius: 6rpx;
background: #75DF95;
font-size: 26rpx;
line-height: 68rpx;
color: #FFFFFF;
margin-top: 20rpx;
img{
width: 34rpx;
height: 34rpx;
margin-right: 12rpx;
position: relative;
top: -2rpx;
}
}
}
</style>