34 changed files with 1092 additions and 29 deletions
Split View
Diff Options
-
2app.js
-
29components/calendar/calendar.wxml
-
1components/calendar/components/header/index.d.ts
-
16components/calendar/components/header/index.js
-
3components/calendar/components/header/index.json
-
16components/calendar/components/header/index.wxml
-
1components/calendar/components/header/index.wxss
-
157components/calendar/components/month/index.js
-
3components/calendar/components/month/index.json
-
39components/calendar/components/month/index.wxml
-
67components/calendar/components/month/index.wxs
-
1components/calendar/components/month/index.wxss
-
290components/calendar/index.js
-
10components/calendar/index.json
-
25components/calendar/index.wxml
-
37components/calendar/index.wxs
-
1components/calendar/index.wxss
-
78components/calendar/utils.js
-
25components/calendar/utils.wxs
-
15components/common/utils.js
-
30components/common/validator.js
-
1components/toast/index.d.ts
-
29components/toast/index.js
-
9components/toast/index.json
-
33components/toast/index.wxml
-
1components/toast/index.wxss
-
68components/toast/toast.d.ts
-
70components/toast/toast.js
-
2pages/client/registe/index.js
-
40pages/process/index/index.js
-
2pages/process/index/index.json
-
7pages/process/index/index.wxml
-
2project.config.json
-
11utils/util.js
@ -0,0 +1,29 @@ |
|||
<view class="van-calendar"> |
|||
<header title="{{ title }}" showTitle="{{ showTitle }}" subtitle="{{ subtitle }}" showSubtitle="{{ showSubtitle }}"> |
|||
<slot name="title" slot="title"></slot> |
|||
</header> |
|||
|
|||
<scroll-view class="van-calendar__body" scroll-y scroll-into-view="{{ scrollIntoView }}"> |
|||
<month wx:for="{{ computed.getMonths(minDate, maxDate) }}" wx:key="index" id="month{{ index }}" class="month" |
|||
data-date="{{ item }}" date="{{ item }}" type="{{ type }}" color="{{ color }}" minDate="{{ minDate }}" |
|||
maxDate="{{ maxDate }}" showMark="{{ showMark }}" formatter="{{ formatter }}" rowHeight="{{ rowHeight }}" |
|||
currentDate="{{ currentDate }}" showSubtitle="{{ showSubtitle }}" allowSameDay="{{ allowSameDay }}" |
|||
showMonthTitle="{{ index !== 0 || !showSubtitle }}" bind:click="onClickDay" /> |
|||
</scroll-view> |
|||
|
|||
<view class="{{ utils.bem('calendar__footer', { safeAreaInsetBottom }) }}"> |
|||
<slot name="footer"></slot> |
|||
</view> |
|||
|
|||
<view class="{{ utils.bem('calendar__footer', { safeAreaInsetBottom }) }}"> |
|||
<van-button wx:if="{{ showConfirm }}" round block type="danger" color="{{ color }}" |
|||
custom-class="van-calendar__confirm" disabled="{{ computed.getButtonDisabled(type, currentDate) }}" |
|||
nativeType="text" bind:click="onConfirm"> |
|||
{{ |
|||
computed.getButtonDisabled(type, currentDate) |
|||
? confirmDisabledText |
|||
: confirmText |
|||
}} |
|||
</van-button> |
|||
</view> |
|||
</view> |
|||
@ -0,0 +1 @@ |
|||
export {}; |
|||
@ -0,0 +1,16 @@ |
|||
import { VantComponent } from '../../../common/component'; |
|||
VantComponent({ |
|||
props: { |
|||
title: { |
|||
type: String, |
|||
value: '日期选择', |
|||
}, |
|||
subtitle: String, |
|||
showTitle: Boolean, |
|||
showSubtitle: Boolean, |
|||
}, |
|||
data: { |
|||
weekdays: ['日', '一', '二', '三', '四', '五', '六'], |
|||
}, |
|||
methods: {}, |
|||
}); |
|||
@ -0,0 +1,3 @@ |
|||
{ |
|||
"component": true |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
<view class="van-calendar__header"> |
|||
<block wx:if="{{ showTitle }}"> |
|||
<view class="van-calendar__header-title"><slot name="title"></slot></view> |
|||
<view class="van-calendar__header-title">{{ title }}</view> |
|||
</block> |
|||
|
|||
<view wx:if="{{ showSubtitle }}" class="van-calendar__header-subtitle"> |
|||
{{ subtitle }} |
|||
</view> |
|||
|
|||
<view class="van-calendar__weekdays"> |
|||
<view wx:for="{{ weekdays }}" wx:key="index" class="van-calendar__weekday"> |
|||
{{ item }} |
|||
</view> |
|||
</view> |
|||
</view> |
|||
@ -0,0 +1 @@ |
|||
@import '../../../common/index.wxss';.van-calendar__header{-webkit-flex-shrink:0;flex-shrink:0;box-shadow:0 2px 10px rgba(125,126,128,.16);box-shadow:var(--calendar-header-box-shadow,0 2px 10px rgba(125,126,128,.16))}.van-calendar__header-subtitle,.van-calendar__header-title{text-align:center;height:44px;height:var(--calendar-header-title-height,44px);font-weight:500;font-weight:var(--font-weight-bold,500);line-height:44px;line-height:var(--calendar-header-title-height,44px)}.van-calendar__header-title+.van-calendar__header-title,.van-calendar__header-title:empty{display:none}.van-calendar__header-title:empty+.van-calendar__header-title{display:block!important}.van-calendar__weekdays{display:-webkit-flex;display:flex}.van-calendar__weekday{-webkit-flex:1;flex:1;text-align:center;font-size:12px;font-size:var(--calendar-weekdays-font-size,12px);line-height:30px;line-height:var(--calendar-weekdays-height,30px)} |
|||
@ -0,0 +1,157 @@ |
|||
import { VantComponent } from '../../../common/component'; |
|||
import { |
|||
getMonthEndDay, |
|||
compareDay, |
|||
getPrevDay, |
|||
getNextDay, |
|||
} from '../../utils'; |
|||
VantComponent({ |
|||
props: { |
|||
date: { |
|||
type: null, |
|||
observer: 'setDays', |
|||
}, |
|||
type: { |
|||
type: String, |
|||
observer: 'setDays', |
|||
}, |
|||
color: String, |
|||
minDate: { |
|||
type: null, |
|||
observer: 'setDays', |
|||
}, |
|||
maxDate: { |
|||
type: null, |
|||
observer: 'setDays', |
|||
}, |
|||
showMark: Boolean, |
|||
rowHeight: null, |
|||
formatter: { |
|||
type: null, |
|||
observer: 'setDays', |
|||
}, |
|||
currentDate: { |
|||
type: null, |
|||
observer: 'setDays', |
|||
}, |
|||
allowSameDay: Boolean, |
|||
showSubtitle: Boolean, |
|||
showMonthTitle: Boolean, |
|||
}, |
|||
data: { |
|||
visible: true, |
|||
days: [], |
|||
}, |
|||
methods: { |
|||
onClick(event) { |
|||
const { index } = event.currentTarget.dataset; |
|||
const item = this.data.days[index]; |
|||
if (item.type !== 'disabled') { |
|||
this.$emit('click', item); |
|||
} |
|||
}, |
|||
setDays() { |
|||
const days = []; |
|||
const startDate = new Date(this.data.date); |
|||
const year = startDate.getFullYear(); |
|||
const month = startDate.getMonth(); |
|||
const totalDay = getMonthEndDay( |
|||
startDate.getFullYear(), |
|||
startDate.getMonth() + 1 |
|||
); |
|||
for (let day = 1; day <= totalDay; day++) { |
|||
const date = new Date(year, month, day); |
|||
const type = this.getDayType(date); |
|||
let config = { |
|||
date, |
|||
type, |
|||
text: day, |
|||
bottomInfo: this.getBottomInfo(type), |
|||
}; |
|||
if (this.data.formatter) { |
|||
config = this.data.formatter(config); |
|||
} |
|||
days.push(config); |
|||
} |
|||
this.setData({ days }); |
|||
}, |
|||
getMultipleDayType(day) { |
|||
const { currentDate } = this.data; |
|||
if (!Array.isArray(currentDate)) { |
|||
return ''; |
|||
} |
|||
const isSelected = (date) => |
|||
currentDate.some((item) => compareDay(item, date) === 0); |
|||
if (isSelected(day)) { |
|||
const prevDay = getPrevDay(day); |
|||
const nextDay = getNextDay(day); |
|||
const prevSelected = isSelected(prevDay); |
|||
const nextSelected = isSelected(nextDay); |
|||
if (prevSelected && nextSelected) { |
|||
return 'multiple-middle'; |
|||
} |
|||
if (prevSelected) { |
|||
return 'end'; |
|||
} |
|||
return nextSelected ? 'start' : 'multiple-selected'; |
|||
} |
|||
return ''; |
|||
}, |
|||
getRangeDayType(day) { |
|||
const { currentDate, allowSameDay } = this.data; |
|||
if (!Array.isArray(currentDate)) { |
|||
return; |
|||
} |
|||
const [startDay, endDay] = currentDate; |
|||
if (!startDay) { |
|||
return; |
|||
} |
|||
const compareToStart = compareDay(day, startDay); |
|||
if (!endDay) { |
|||
return compareToStart === 0 ? 'start' : ''; |
|||
} |
|||
const compareToEnd = compareDay(day, endDay); |
|||
if (compareToStart === 0 && compareToEnd === 0 && allowSameDay) { |
|||
return 'start-end'; |
|||
} |
|||
if (compareToStart === 0) { |
|||
return 'start'; |
|||
} |
|||
if (compareToEnd === 0) { |
|||
return 'end'; |
|||
} |
|||
if (compareToStart > 0 && compareToEnd < 0) { |
|||
return 'middle'; |
|||
} |
|||
}, |
|||
getDayType(day) { |
|||
const { type, minDate, maxDate, currentDate } = this.data; |
|||
if (compareDay(day, minDate) < 0 || compareDay(day, maxDate) > 0) { |
|||
return 'disabled'; |
|||
} |
|||
if (type === 'single') { |
|||
return compareDay(day, currentDate) === 0 ? 'selected' : ''; |
|||
} |
|||
if (type === 'multiple') { |
|||
return this.getMultipleDayType(day); |
|||
} |
|||
/* istanbul ignore else */ |
|||
if (type === 'range') { |
|||
return this.getRangeDayType(day); |
|||
} |
|||
}, |
|||
getBottomInfo(type) { |
|||
if (this.data.type === 'range') { |
|||
if (type === 'start') { |
|||
return '开始'; |
|||
} |
|||
if (type === 'end') { |
|||
return '结束'; |
|||
} |
|||
if (type === 'start-end') { |
|||
return '开始/结束'; |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}); |
|||
@ -0,0 +1,3 @@ |
|||
{ |
|||
"component": true |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
<wxs src="./index.wxs" module="computed"></wxs> |
|||
<wxs src="../../../wxs/utils.wxs" module="utils" /> |
|||
|
|||
<view class="van-calendar__month" style="{{ computed.getMonthStyle(visible, date, rowHeight) }}"> |
|||
<view wx:if="{{ showMonthTitle }}" class="van-calendar__month-title"> |
|||
{{ computed.formatMonthTitle(date) }} |
|||
</view> |
|||
|
|||
<view wx:if="{{ visible }}" class="van-calendar__days"> |
|||
<view wx:if="{{ showMark }}" class="van-calendar__month-mark"> |
|||
{{ computed.getMark(date) }} |
|||
</view> |
|||
|
|||
<view |
|||
wx:for="{{ days }}" |
|||
wx:key="index" |
|||
style="{{ computed.getDayStyle(item.type, index, date, rowHeight, color) }}" |
|||
class="{{ utils.bem('calendar__day', [item.type]) }} {{ item.className }}" |
|||
data-index="{{ index }}" |
|||
bindtap="onClick" |
|||
> |
|||
<view wx:if="{{ item.type === 'selected' }}" class="van-calendar__selected-day" style="background: {{ color }}"> |
|||
<view wx:if="{{ item.topInfo }}" class="van-calendar__top-info">{{ item.topInfo }}</view> |
|||
{{ item.text }} |
|||
<view wx:if="{{ item.bottomInfo }}" class="van-calendar__bottom-info"> |
|||
{{ item.bottomInfo }} |
|||
</view> |
|||
</view> |
|||
|
|||
<view wx:else> |
|||
<view wx:if="{{ item.topInfo }}" class="van-calendar__top-info">{{ item.topInfo }}</view> |
|||
{{ item.text }} |
|||
<view wx:if="{{ item.bottomInfo }}" class="van-calendar__bottom-info"> |
|||
{{ item.bottomInfo }} |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
@ -0,0 +1,67 @@ |
|||
/* eslint-disable */ |
|||
var utils = require('../../utils.wxs'); |
|||
|
|||
function getMark(date) { |
|||
return getDate(date).getMonth() + 1; |
|||
} |
|||
|
|||
var ROW_HEIGHT = 64; |
|||
|
|||
function getDayStyle(type, index, date, rowHeight, color) { |
|||
var style = []; |
|||
var offset = getDate(date).getDay(); |
|||
|
|||
if (index === 0) { |
|||
style.push(['margin-left', (100 * offset) / 7 + '%']); |
|||
} |
|||
|
|||
if (rowHeight !== ROW_HEIGHT) { |
|||
style.push(['height', rowHeight + 'px']); |
|||
} |
|||
|
|||
if (color) { |
|||
if ( |
|||
type === 'start' || |
|||
type === 'end' || |
|||
type === 'multiple-selected' || |
|||
type === 'multiple-middle' |
|||
) { |
|||
style.push(['background', color]); |
|||
} else if (type === 'middle') { |
|||
style.push(['color', color]); |
|||
} |
|||
} |
|||
|
|||
return style |
|||
.map(function(item) { |
|||
return item.join(':'); |
|||
}) |
|||
.join(';'); |
|||
} |
|||
|
|||
function formatMonthTitle(date) { |
|||
date = getDate(date); |
|||
return date.getFullYear() + '年' + (date.getMonth() + 1) + '月'; |
|||
} |
|||
|
|||
function getMonthStyle(visible, date, rowHeight) { |
|||
if (!visible) { |
|||
date = getDate(date); |
|||
|
|||
var totalDay = utils.getMonthEndDay( |
|||
date.getFullYear(), |
|||
date.getMonth() + 1 |
|||
); |
|||
var offset = getDate(date).getDay(); |
|||
var padding = Math.ceil((totalDay + offset) / 7) * rowHeight; |
|||
|
|||
return 'padding-bottom:' + padding + 'px'; |
|||
} |
|||
} |
|||
|
|||
module.exports = { |
|||
getMark: getMark, |
|||
getDayStyle: getDayStyle, |
|||
formatMonthTitle: formatMonthTitle, |
|||
getMonthStyle: getMonthStyle |
|||
}; |
|||
@ -0,0 +1 @@ |
|||
@import '../../../common/index.wxss';.van-calendar{display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;height:100%;background-color:#fff;background-color:var(--calendar-background-color,#fff)}.van-calendar__month-title{text-align:center;height:44px;height:var(--calendar-header-title-height,44px);font-weight:500;font-weight:var(--font-weight-bold,500);font-size:14px;font-size:var(--calendar-month-title-font-size,14px);line-height:44px;line-height:var(--calendar-header-title-height,44px)}.van-calendar__days{position:relative;display:-webkit-flex;display:flex;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-user-select:none;user-select:none}.van-calendar__month-mark{position:absolute;top:50%;left:50%;z-index:0;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);pointer-events:none;color:rgba(242,243,245,.8);color:var(--calendar-month-mark-color,rgba(242,243,245,.8));font-size:160px;font-size:var(--calendar-month-mark-font-size,160px)}.van-calendar__day,.van-calendar__selected-day{display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;text-align:center}.van-calendar__day{position:relative;width:14.285%;height:64px;height:var(--calendar-day-height,64px);font-size:16px;font-size:var(--calendar-day-font-size,16px)}.van-calendar__day--end,.van-calendar__day--multiple-middle,.van-calendar__day--multiple-selected,.van-calendar__day--start,.van-calendar__day--start-end{color:#fff;color:var(--calendar-range-edge-color,#fff);background-color:#ee0a24;background-color:var(--calendar-range-edge-background-color,#ee0a24)}.van-calendar__day--start{border-radius:4px 0 0 4px;border-radius:var(--border-radius-md,4px) 0 0 var(--border-radius-md,4px)}.van-calendar__day--end{border-radius:0 4px 4px 0;border-radius:0 var(--border-radius-md,4px) var(--border-radius-md,4px) 0}.van-calendar__day--multiple-selected,.van-calendar__day--start-end{border-radius:4px;border-radius:var(--border-radius-md,4px)}.van-calendar__day--middle{color:#ee0a24;color:var(--calendar-range-middle-color,#ee0a24)}.van-calendar__day--middle:after{position:absolute;top:0;right:0;bottom:0;left:0;background-color:currentColor;content:"";opacity:.1;opacity:var(--calendar-range-middle-background-opacity,.1)}.van-calendar__day--disabled{cursor:default;color:#c8c9cc;color:var(--calendar-day-disabled-color,#c8c9cc)}.van-calendar__bottom-info,.van-calendar__top-info{position:absolute;right:0;left:0;font-size:10px;font-size:var(--calendar-info-font-size,10px);line-height:14px;line-height:var(--calendar-info-line-height,14px)}@media (max-width:350px){.van-calendar__bottom-info,.van-calendar__top-info{font-size:9px}}.van-calendar__top-info{top:6px}.van-calendar__bottom-info{bottom:4px}.van-calendar__selected-day{width:54px;width:var(--calendar-selected-day-size,54px);height:54px;height:var(--calendar-selected-day-size,54px);color:#fff;color:var(--calendar-selected-day-color,#fff);background-color:#ee0a24;background-color:var(--calendar-selected-day-background-color,#ee0a24);border-radius:4px;border-radius:var(--border-radius-md,4px)} |
|||
@ -0,0 +1,290 @@ |
|||
import { VantComponent } from '../common/component'; |
|||
import { |
|||
ROW_HEIGHT, |
|||
getNextDay, |
|||
compareDay, |
|||
copyDates, |
|||
calcDateNum, |
|||
formatMonthTitle, |
|||
compareMonth, |
|||
getMonths, |
|||
getDayByOffset, |
|||
} from './utils'; |
|||
import Toast from '../toast/toast'; |
|||
import { requestAnimationFrame } from '../common/utils'; |
|||
VantComponent({ |
|||
props: { |
|||
title: { |
|||
type: String, |
|||
value: '日期选择', |
|||
}, |
|||
color: String, |
|||
show: { |
|||
type: Boolean, |
|||
observer(val) { |
|||
if (val) { |
|||
this.initRect(); |
|||
this.scrollIntoView(); |
|||
} |
|||
}, |
|||
}, |
|||
formatter: null, |
|||
confirmText: { |
|||
type: String, |
|||
value: '确定', |
|||
}, |
|||
rangePrompt: String, |
|||
defaultDate: { |
|||
type: null, |
|||
observer(val) { |
|||
this.setData({ currentDate: val }); |
|||
this.scrollIntoView(); |
|||
}, |
|||
}, |
|||
allowSameDay: Boolean, |
|||
confirmDisabledText: String, |
|||
type: { |
|||
type: String, |
|||
value: 'single', |
|||
observer: 'reset', |
|||
}, |
|||
minDate: { |
|||
type: null, |
|||
value: Date.now(), |
|||
}, |
|||
maxDate: { |
|||
type: null, |
|||
value: new Date( |
|||
new Date().getFullYear(), |
|||
new Date().getMonth() + 6, |
|||
new Date().getDate() |
|||
).getTime(), |
|||
}, |
|||
position: { |
|||
type: String, |
|||
value: 'bottom', |
|||
}, |
|||
rowHeight: { |
|||
type: null, |
|||
value: ROW_HEIGHT, |
|||
}, |
|||
round: { |
|||
type: Boolean, |
|||
value: true, |
|||
}, |
|||
poppable: { |
|||
type: Boolean, |
|||
value: true, |
|||
}, |
|||
showMark: { |
|||
type: Boolean, |
|||
value: true, |
|||
}, |
|||
showTitle: { |
|||
type: Boolean, |
|||
value: true, |
|||
}, |
|||
showConfirm: { |
|||
type: Boolean, |
|||
value: true, |
|||
}, |
|||
showSubtitle: { |
|||
type: Boolean, |
|||
value: true, |
|||
}, |
|||
safeAreaInsetBottom: { |
|||
type: Boolean, |
|||
value: true, |
|||
}, |
|||
closeOnClickOverlay: { |
|||
type: Boolean, |
|||
value: true, |
|||
}, |
|||
maxRange: { |
|||
type: null, |
|||
value: null, |
|||
}, |
|||
}, |
|||
data: { |
|||
subtitle: '', |
|||
currentDate: null, |
|||
scrollIntoView: '', |
|||
}, |
|||
created() { |
|||
this.setData({ |
|||
currentDate: this.getInitialDate(), |
|||
}); |
|||
}, |
|||
mounted() { |
|||
if (this.data.show || !this.data.poppable) { |
|||
this.initRect(); |
|||
this.scrollIntoView(); |
|||
} |
|||
}, |
|||
methods: { |
|||
reset() { |
|||
this.setData({ currentDate: this.getInitialDate() }); |
|||
this.scrollIntoView(); |
|||
}, |
|||
initRect() { |
|||
if (this.contentObserver != null) { |
|||
this.contentObserver.disconnect(); |
|||
} |
|||
const contentObserver = this.createIntersectionObserver({ |
|||
thresholds: [0, 0.1, 0.9, 1], |
|||
observeAll: true, |
|||
}); |
|||
this.contentObserver = contentObserver; |
|||
contentObserver.relativeTo('.van-calendar__body'); |
|||
contentObserver.observe('.month', (res) => { |
|||
if (res.boundingClientRect.top <= res.relativeRect.top) { |
|||
// @ts-ignore
|
|||
this.setData({ subtitle: formatMonthTitle(res.dataset.date) }); |
|||
} |
|||
}); |
|||
}, |
|||
getInitialDate() { |
|||
const { type, defaultDate, minDate } = this.data; |
|||
if (type === 'range') { |
|||
const [startDay, endDay] = defaultDate || []; |
|||
return [ |
|||
startDay || minDate, |
|||
endDay || getNextDay(new Date(minDate)).getTime(), |
|||
]; |
|||
} |
|||
if (type === 'multiple') { |
|||
return defaultDate || [minDate]; |
|||
} |
|||
return defaultDate || minDate; |
|||
}, |
|||
scrollIntoView() { |
|||
requestAnimationFrame(() => { |
|||
const { currentDate, type, show, poppable, minDate, maxDate } = this.data |
|||
// @ts-ignore
|
|||
const targetDate = type === 'single' ? currentDate : currentDate[0]; |
|||
const displayed = show || !poppable; |
|||
if (!targetDate || !displayed) { |
|||
return; |
|||
} |
|||
const months = getMonths(minDate, maxDate); |
|||
months.some((month, index) => { |
|||
if (compareMonth(month, targetDate) === 0) { |
|||
this.setData({ scrollIntoView: `month${index}` }); |
|||
return true |
|||
} |
|||
return false |
|||
}) |
|||
}) |
|||
}, |
|||
onOpen() { |
|||
this.$emit('open'); |
|||
}, |
|||
onOpened() { |
|||
this.$emit('opened'); |
|||
}, |
|||
onClose() { |
|||
this.$emit('close'); |
|||
}, |
|||
onClosed() { |
|||
this.$emit('closed'); |
|||
}, |
|||
onClickDay(event) { |
|||
const { date } = event.detail; |
|||
const { type, currentDate, allowSameDay } = this.data; |
|||
if (type === 'range') { |
|||
// @ts-ignore
|
|||
const [startDay, endDay] = currentDate; |
|||
if (startDay && !endDay) { |
|||
const compareToStart = compareDay(date, startDay); |
|||
if (compareToStart === 1) { |
|||
this.select([startDay, date], true); |
|||
} else if (compareToStart === -1) { |
|||
this.select([date, null]); |
|||
} else if (allowSameDay) { |
|||
this.select([date, date]); |
|||
} |
|||
} else { |
|||
this.select([date, null]); |
|||
} |
|||
} else if (type === 'multiple') { |
|||
let selectedIndex; |
|||
// @ts-ignore
|
|||
const selected = currentDate.some((dateItem, index) => { |
|||
const equal = compareDay(dateItem, date) === 0; |
|||
if (equal) { |
|||
selectedIndex = index; |
|||
} |
|||
return equal; |
|||
}); |
|||
if (selected) { |
|||
// @ts-ignore
|
|||
const cancelDate = currentDate.splice(selectedIndex, 1); |
|||
this.setData({ currentDate }); |
|||
this.unselect(cancelDate); |
|||
} else { |
|||
// @ts-ignore
|
|||
this.select([...currentDate, date]); |
|||
} |
|||
} else { |
|||
this.select(date, true); |
|||
} |
|||
}, |
|||
unselect(dateArray) { |
|||
const date = dateArray[0]; |
|||
if (date) { |
|||
this.$emit('unselect', copyDates(date)); |
|||
} |
|||
}, |
|||
select(date, complete) { |
|||
if (complete && this.data.type === 'range') { |
|||
const valid = this.checkRange(date); |
|||
if (!valid) { |
|||
// auto selected to max range if showConfirm
|
|||
if (this.data.showConfirm) { |
|||
this.emit([ |
|||
date[0], |
|||
getDayByOffset(date[0], this.data.maxRange - 1), |
|||
]); |
|||
} else { |
|||
this.emit(date); |
|||
} |
|||
return; |
|||
} |
|||
} |
|||
this.emit(date); |
|||
if (complete && !this.data.showConfirm) { |
|||
this.onConfirm(); |
|||
} |
|||
}, |
|||
emit(date) { |
|||
const getTime = (date) => (date instanceof Date ? date.getTime() : date); |
|||
this.setData({ |
|||
currentDate: Array.isArray(date) ? date.map(getTime) : getTime(date), |
|||
}); |
|||
this.$emit('select', copyDates(date)); |
|||
}, |
|||
checkRange(date) { |
|||
const { maxRange, rangePrompt } = this.data; |
|||
if (maxRange && calcDateNum(date) > maxRange) { |
|||
Toast({ |
|||
context: this, |
|||
message: rangePrompt || `选择天数不能超过 ${maxRange} 天`, |
|||
}); |
|||
return false; |
|||
} |
|||
return true; |
|||
}, |
|||
onConfirm() { |
|||
if ( |
|||
this.data.type === 'range' && |
|||
!this.checkRange(this.data.currentDate) |
|||
) { |
|||
return; |
|||
} |
|||
wx.nextTick(() => { |
|||
// @ts-ignore
|
|||
this.$emit('confirm', copyDates(this.data.currentDate)); |
|||
}); |
|||
}, |
|||
}, |
|||
}); |
|||
@ -0,0 +1,10 @@ |
|||
{ |
|||
"component": true, |
|||
"usingComponents": { |
|||
"header": "./components/header/index", |
|||
"month": "./components/month/index", |
|||
"van-button": "../button/index", |
|||
"van-popup": "../popup/index", |
|||
"van-toast": "../toast/index" |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
<wxs src="./index.wxs" module="computed" /> |
|||
<wxs src="../wxs/utils.wxs" module="utils" /> |
|||
|
|||
<import src="./calendar.wxml" /> |
|||
|
|||
<van-popup |
|||
wx:if="{{ poppable }}" |
|||
custom-class="van-calendar__popup--{{ position }}" |
|||
close-icon-class="van-calendar__close-icon" |
|||
show="{{ show }}" |
|||
round="{{ round }}" |
|||
position="{{ position }}" |
|||
closeable="{{ showTitle || showSubtitle }}" |
|||
close-on-click-overlay="{{ closeOnClickOverlay }}" |
|||
bind:enter="onOpen" |
|||
bind:close="onClose" |
|||
bind:after-enter="onOpened" |
|||
bind:after-leave="onClosed" |
|||
> |
|||
<include src="calendar.wxml" /> |
|||
</van-popup> |
|||
|
|||
<include wx:else src="calendar.wxml" /> |
|||
|
|||
<van-toast id="van-toast" /> |
|||
@ -0,0 +1,37 @@ |
|||
/* eslint-disable */ |
|||
var utils = require('./utils.wxs'); |
|||
|
|||
function getMonths(minDate, maxDate) { |
|||
var months = []; |
|||
var cursor = getDate(minDate); |
|||
|
|||
cursor.setDate(1); |
|||
|
|||
do { |
|||
months.push(cursor.getTime()); |
|||
cursor.setMonth(cursor.getMonth() + 1); |
|||
} while (utils.compareMonth(cursor, getDate(maxDate)) !== 1); |
|||
|
|||
return months; |
|||
} |
|||
|
|||
function getButtonDisabled(type, currentDate) { |
|||
if (currentDate == null) { |
|||
return true; |
|||
} |
|||
|
|||
if (type === 'range') { |
|||
return !currentDate[0] || !currentDate[1]; |
|||
} |
|||
|
|||
if (type === 'multiple') { |
|||
return !currentDate.length; |
|||
} |
|||
|
|||
return !currentDate; |
|||
} |
|||
|
|||
module.exports = { |
|||
getMonths: getMonths, |
|||
getButtonDisabled: getButtonDisabled |
|||
}; |
|||
@ -0,0 +1 @@ |
|||
@import '../common/index.wxss';.van-calendar{display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;height:100%;height:var(--calendar-height,100%);background-color:#fff;background-color:var(--calendar-background-color,#fff)}.van-calendar__close-icon{top:11px}.van-calendar__popup--bottom,.van-calendar__popup--top{height:60%;height:var(--calendar-popup-height,60%)}.van-calendar__popup--left,.van-calendar__popup--right{height:100%}.van-calendar__body{-webkit-flex:1;flex:1;overflow:auto;-webkit-overflow-scrolling:touch}.van-calendar__footer{-webkit-flex-shrink:0;flex-shrink:0;padding:0 16px;padding:0 var(--padding-md,16px)}.van-calendar__footer--safe-area-inset-bottom{padding-bottom:env(safe-area-inset-bottom)}.van-calendar__footer+.van-calendar__footer,.van-calendar__footer:empty{display:none}.van-calendar__footer:empty+.van-calendar__footer{display:block!important}.van-calendar__confirm{height:36px!important;height:var(--calendar-confirm-button-height,36px)!important;margin:7px 0!important;margin:var(--calendar-confirm-button-margin,7px 0)!important;line-height:34px!important;line-height:var(--calendar-confirm-button-line-height,34px)!important} |
|||
@ -0,0 +1,78 @@ |
|||
export const ROW_HEIGHT = 64; |
|||
export function formatMonthTitle(date) { |
|||
if (!(date instanceof Date)) { |
|||
date = new Date(date); |
|||
} |
|||
return `${date.getFullYear()}年${date.getMonth() + 1}月`; |
|||
} |
|||
export function compareMonth(date1, date2) { |
|||
if (!(date1 instanceof Date)) { |
|||
date1 = new Date(date1); |
|||
} |
|||
if (!(date2 instanceof Date)) { |
|||
date2 = new Date(date2); |
|||
} |
|||
const year1 = date1.getFullYear(); |
|||
const year2 = date2.getFullYear(); |
|||
const month1 = date1.getMonth(); |
|||
const month2 = date2.getMonth(); |
|||
if (year1 === year2) { |
|||
return month1 === month2 ? 0 : month1 > month2 ? 1 : -1; |
|||
} |
|||
return year1 > year2 ? 1 : -1; |
|||
} |
|||
export function compareDay(day1, day2) { |
|||
if (!(day1 instanceof Date)) { |
|||
day1 = new Date(day1); |
|||
} |
|||
if (!(day2 instanceof Date)) { |
|||
day2 = new Date(day2); |
|||
} |
|||
const compareMonthResult = compareMonth(day1, day2); |
|||
if (compareMonthResult === 0) { |
|||
const date1 = day1.getDate(); |
|||
const date2 = day2.getDate(); |
|||
return date1 === date2 ? 0 : date1 > date2 ? 1 : -1; |
|||
} |
|||
return compareMonthResult; |
|||
} |
|||
export function getDayByOffset(date, offset) { |
|||
date = new Date(date); |
|||
date.setDate(date.getDate() + offset); |
|||
return date; |
|||
} |
|||
export function getPrevDay(date) { |
|||
return getDayByOffset(date, -1); |
|||
} |
|||
export function getNextDay(date) { |
|||
return getDayByOffset(date, 1); |
|||
} |
|||
export function calcDateNum(date) { |
|||
const day1 = new Date(date[0]).getTime(); |
|||
const day2 = new Date(date[1]).getTime(); |
|||
return (day2 - day1) / (1000 * 60 * 60 * 24) + 1; |
|||
} |
|||
export function copyDates(dates) { |
|||
if (Array.isArray(dates)) { |
|||
return dates.map((date) => { |
|||
if (date === null) { |
|||
return date; |
|||
} |
|||
return new Date(date); |
|||
}); |
|||
} |
|||
return new Date(dates); |
|||
} |
|||
export function getMonthEndDay(year, month) { |
|||
return 32 - new Date(year, month - 1, 32).getDate(); |
|||
} |
|||
export function getMonths(minDate, maxDate) { |
|||
const months = []; |
|||
const cursor = new Date(minDate); |
|||
cursor.setDate(1); |
|||
do { |
|||
months.push(cursor.getTime()); |
|||
cursor.setMonth(cursor.getMonth() + 1); |
|||
} while (compareMonth(cursor, maxDate) !== 1); |
|||
return months; |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
/* eslint-disable */ |
|||
function getMonthEndDay(year, month) { |
|||
return 32 - getDate(year, month - 1, 32).getDate(); |
|||
} |
|||
|
|||
function compareMonth(date1, date2) { |
|||
date1 = getDate(date1); |
|||
date2 = getDate(date2); |
|||
|
|||
var year1 = date1.getFullYear(); |
|||
var year2 = date2.getFullYear(); |
|||
var month1 = date1.getMonth(); |
|||
var month2 = date2.getMonth(); |
|||
|
|||
if (year1 === year2) { |
|||
return month1 === month2 ? 0 : month1 > month2 ? 1 : -1; |
|||
} |
|||
|
|||
return year1 > year2 ? 1 : -1; |
|||
} |
|||
|
|||
module.exports = { |
|||
getMonthEndDay: getMonthEndDay, |
|||
compareMonth: compareMonth |
|||
}; |
|||
@ -0,0 +1,30 @@ |
|||
export function isFunction(val) { |
|||
return typeof val === 'function'; |
|||
} |
|||
export function isPlainObject(val) { |
|||
return val !== null && typeof val === 'object' && !Array.isArray(val); |
|||
} |
|||
export function isPromise(val) { |
|||
return isPlainObject(val) && isFunction(val.then) && isFunction(val.catch); |
|||
} |
|||
export function isDef(value) { |
|||
return value !== undefined && value !== null; |
|||
} |
|||
export function isObj(x) { |
|||
const type = typeof x; |
|||
return x !== null && (type === 'object' || type === 'function'); |
|||
} |
|||
export function isNumber(value) { |
|||
return /^\d+(\.\d+)?$/.test(value); |
|||
} |
|||
export function isBoolean(value) { |
|||
return typeof value === 'boolean'; |
|||
} |
|||
const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)/i; |
|||
const VIDEO_REGEXP = /\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv)/i; |
|||
export function isImageUrl(url) { |
|||
return IMAGE_REGEXP.test(url); |
|||
} |
|||
export function isVideoUrl(url) { |
|||
return VIDEO_REGEXP.test(url); |
|||
} |
|||
@ -0,0 +1 @@ |
|||
export {}; |
|||
@ -0,0 +1,29 @@ |
|||
import { VantComponent } from '../common/component'; |
|||
VantComponent({ |
|||
props: { |
|||
show: Boolean, |
|||
mask: Boolean, |
|||
message: String, |
|||
forbidClick: Boolean, |
|||
zIndex: { |
|||
type: Number, |
|||
value: 1000, |
|||
}, |
|||
type: { |
|||
type: String, |
|||
value: 'text', |
|||
}, |
|||
loadingType: { |
|||
type: String, |
|||
value: 'circular', |
|||
}, |
|||
position: { |
|||
type: String, |
|||
value: 'middle', |
|||
}, |
|||
}, |
|||
methods: { |
|||
// for prevent touchmove
|
|||
noop() {}, |
|||
}, |
|||
}); |
|||
@ -0,0 +1,9 @@ |
|||
{ |
|||
"component": true, |
|||
"usingComponents": { |
|||
"van-icon": "../icon/index", |
|||
"van-loading": "../loading/index", |
|||
"van-overlay": "../overlay/index", |
|||
"van-transition": "../transition/index" |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
<van-overlay |
|||
wx:if="{{ mask || forbidClick }}" |
|||
show="{{ show }}" |
|||
z-index="{{ zIndex }}" |
|||
custom-style="{{ mask ? '' : 'background-color: transparent;' }}" |
|||
/> |
|||
<van-transition |
|||
show="{{ show }}" |
|||
custom-style="z-index: {{ zIndex }}" |
|||
custom-class="van-toast__container" |
|||
> |
|||
<view |
|||
class="van-toast van-toast--{{ type === 'text' ? 'text' : 'icon' }} van-toast--{{ position }}" |
|||
catch:touchmove="noop" |
|||
> |
|||
<!-- text only --> |
|||
<text wx:if="{{ type === 'text' }}">{{ message }}</text> |
|||
|
|||
<!-- with icon --> |
|||
<block wx:else> |
|||
<van-loading |
|||
wx:if="{{ type === 'loading' }}" |
|||
color="white" |
|||
type="{{ loadingType }}" |
|||
custom-class="van-toast__loading" |
|||
/> |
|||
<van-icon wx:else class="van-toast__icon" name="{{ type }}" /> |
|||
<text wx:if="{{ message }}" class="van-toast__text">{{ message }}</text> |
|||
</block> |
|||
|
|||
<slot /> |
|||
</view> |
|||
</van-transition> |
|||
@ -0,0 +1 @@ |
|||
@import '../common/index.wxss';.van-toast{display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;box-sizing:initial;color:#fff;color:var(--toast-text-color,#fff);font-size:14px;font-size:var(--toast-font-size,14px);line-height:20px;line-height:var(--toast-line-height,20px);white-space:pre-wrap;word-wrap:break-word;background-color:rgba(0,0,0,.7);background-color:var(--toast-background-color,rgba(0,0,0,.7));border-radius:8px;border-radius:var(--toast-border-radius,8px)}.van-toast__container{position:fixed;top:50%;left:50%;width:-webkit-fit-content;width:fit-content;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);max-width:70%;max-width:var(--toast-max-width,70%)}.van-toast--text{min-width:96px;min-width:var(--toast-text-min-width,96px);padding:8px 12px;padding:var(--toast-text-padding,8px 12px)}.van-toast--icon{width:88px;width:var(--toast-default-width,88px);min-height:88px;min-height:var(--toast-default-min-height,88px);padding:16px;padding:var(--toast-default-padding,16px)}.van-toast--icon .van-toast__icon{font-size:36px;font-size:var(--toast-icon-size,36px)}.van-toast--icon .van-toast__text{padding-top:8px}.van-toast__loading{margin:10px 0}.van-toast--top{-webkit-transform:translateY(-30vh);transform:translateY(-30vh)}.van-toast--bottom{-webkit-transform:translateY(30vh);transform:translateY(30vh)} |
|||
@ -0,0 +1,68 @@ |
|||
/// <reference types="miniprogram-api-typings" />
|
|||
declare type ToastMessage = string | number; |
|||
interface ToastOptions { |
|||
show?: boolean; |
|||
type?: string; |
|||
mask?: boolean; |
|||
zIndex?: number; |
|||
context?: |
|||
| WechatMiniprogram.Component.TrivialInstance |
|||
| WechatMiniprogram.Page.TrivialInstance; |
|||
position?: string; |
|||
duration?: number; |
|||
selector?: string; |
|||
forbidClick?: boolean; |
|||
loadingType?: string; |
|||
message?: ToastMessage; |
|||
onClose?: () => void; |
|||
} |
|||
declare function Toast( |
|||
toastOptions: ToastOptions | ToastMessage |
|||
): |
|||
| WechatMiniprogram.Component.Instance< |
|||
Record<string, any>, |
|||
Record<string, any>, |
|||
Record<string, any>, |
|||
Record<string, any>, |
|||
false |
|||
> |
|||
| undefined; |
|||
declare namespace Toast { |
|||
var loading: ( |
|||
options: string | number | ToastOptions |
|||
) => |
|||
| WechatMiniprogram.Component.Instance< |
|||
Record<string, any>, |
|||
Record<string, any>, |
|||
Record<string, any>, |
|||
Record<string, any>, |
|||
false |
|||
> |
|||
| undefined; |
|||
var success: ( |
|||
options: string | number | ToastOptions |
|||
) => |
|||
| WechatMiniprogram.Component.Instance< |
|||
Record<string, any>, |
|||
Record<string, any>, |
|||
Record<string, any>, |
|||
Record<string, any>, |
|||
false |
|||
> |
|||
| undefined; |
|||
var fail: ( |
|||
options: string | number | ToastOptions |
|||
) => |
|||
| WechatMiniprogram.Component.Instance< |
|||
Record<string, any>, |
|||
Record<string, any>, |
|||
Record<string, any>, |
|||
Record<string, any>, |
|||
false |
|||
> |
|||
| undefined; |
|||
var clear: () => void; |
|||
var setDefaultOptions: (options: ToastOptions) => void; |
|||
var resetDefaultOptions: () => void; |
|||
} |
|||
export default Toast; |
|||
@ -0,0 +1,70 @@ |
|||
import { isObj } from '../common/validator'; |
|||
const defaultOptions = { |
|||
type: 'text', |
|||
mask: false, |
|||
message: '', |
|||
show: true, |
|||
zIndex: 1000, |
|||
duration: 2000, |
|||
position: 'middle', |
|||
forbidClick: false, |
|||
loadingType: 'circular', |
|||
selector: '#van-toast', |
|||
}; |
|||
let queue = []; |
|||
let currentOptions = Object.assign({}, defaultOptions); |
|||
function parseOptions(message) { |
|||
return isObj(message) ? message : { message }; |
|||
} |
|||
function getContext() { |
|||
const pages = getCurrentPages(); |
|||
return pages[pages.length - 1]; |
|||
} |
|||
function Toast(toastOptions) { |
|||
const options = Object.assign( |
|||
Object.assign({}, currentOptions), |
|||
parseOptions(toastOptions) |
|||
); |
|||
const context = options.context || getContext(); |
|||
const toast = context.selectComponent(options.selector); |
|||
if (!toast) { |
|||
console.warn('未找到 van-toast 节点,请确认 selector 及 context 是否正确'); |
|||
return; |
|||
} |
|||
delete options.context; |
|||
delete options.selector; |
|||
toast.clear = () => { |
|||
toast.setData({ show: false }); |
|||
if (options.onClose) { |
|||
options.onClose(); |
|||
} |
|||
}; |
|||
queue.push(toast); |
|||
toast.setData(options); |
|||
clearTimeout(toast.timer); |
|||
if (options.duration != null && options.duration > 0) { |
|||
toast.timer = setTimeout(() => { |
|||
toast.clear(); |
|||
queue = queue.filter((item) => item !== toast); |
|||
}, options.duration); |
|||
} |
|||
return toast; |
|||
} |
|||
const createMethod = (type) => (options) => |
|||
Toast(Object.assign({ type }, parseOptions(options))); |
|||
Toast.loading = createMethod('loading'); |
|||
Toast.success = createMethod('success'); |
|||
Toast.fail = createMethod('fail'); |
|||
Toast.clear = () => { |
|||
queue.forEach((toast) => { |
|||
toast.clear(); |
|||
}); |
|||
queue = []; |
|||
}; |
|||
Toast.setDefaultOptions = (options) => { |
|||
Object.assign(currentOptions, options); |
|||
}; |
|||
Toast.resetDefaultOptions = () => { |
|||
currentOptions = Object.assign({}, defaultOptions); |
|||
}; |
|||
export default Toast; |
|||
Write
Preview
Loading…
Cancel
Save