@ -0,0 +1,144 @@
@@ -0,0 +1,144 @@
|
||||
import { dateUtil, getCalendarConfig } from './utils/index' |
||||
|
||||
/** |
||||
* 计算当前月份前后两月应占的格子 |
||||
* @param {number} year 年份 |
||||
* @param {number} month 月份 |
||||
*/ |
||||
function calculateEmptyGrids(year, month, config) { |
||||
const prevMonthGrids = calculatePrevMonthGrids(year, month, config) |
||||
const nextMonthGrids = calculateNextMonthGrids(year, month, config) |
||||
return { |
||||
prevMonthGrids, |
||||
nextMonthGrids |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 计算上月应占的格子 |
||||
* @param {number} year 年份 |
||||
* @param {number} month 月份 |
||||
*/ |
||||
function calculatePrevMonthGrids(year, month, config) { |
||||
let emptyGrids = [] |
||||
const prevMonthDays = dateUtil.getDatesCountOfMonth(year, month - 1) |
||||
let firstDayOfWeek = dateUtil.firstDayOfWeek(year, month) |
||||
if (config.firstDayOfWeek === 'Mon') { |
||||
if (firstDayOfWeek === 0) { |
||||
firstDayOfWeek = 6 |
||||
} else { |
||||
firstDayOfWeek -= 1 |
||||
} |
||||
} |
||||
if (firstDayOfWeek > 0) { |
||||
const len = prevMonthDays - firstDayOfWeek |
||||
const { onlyShowCurrentMonth } = config |
||||
const YMInfo = dateUtil.getPrevMonthInfo({ year, month }) |
||||
for (let i = prevMonthDays; i > len; i--) { |
||||
if (onlyShowCurrentMonth) { |
||||
emptyGrids.push('') |
||||
} else { |
||||
const week = dateUtil.getDayOfWeek(+year, +month, i) |
||||
emptyGrids.push({ |
||||
...YMInfo, |
||||
date: i, |
||||
week |
||||
}) |
||||
} |
||||
} |
||||
emptyGrids.reverse() |
||||
} |
||||
return emptyGrids |
||||
} |
||||
/** |
||||
* 计算下一月日期是否需要多展示的日期 |
||||
* 某些月份日期为5排,某些月份6排,统一为6排 |
||||
* @param {number} year |
||||
* @param {number} month |
||||
* @param {object} config |
||||
*/ |
||||
function calculateExtraEmptyDate(year, month, config) { |
||||
let extDate = 0 |
||||
if (+month === 2) { |
||||
extDate += 7 |
||||
let firstDayofMonth = dateUtil.getDayOfWeek(year, month, 1) |
||||
if (config.firstDayOfWeek === 'Mon') { |
||||
if (+firstDayofMonth === 1) extDate += 7 |
||||
} else { |
||||
if (+firstDayofMonth === 0) extDate += 7 |
||||
} |
||||
} else { |
||||
let firstDayofMonth = dateUtil.getDayOfWeek(year, month, 1) |
||||
if (config.firstDayOfWeek === 'Mon') { |
||||
if (firstDayofMonth !== 0 && firstDayofMonth < 6) { |
||||
extDate += 7 |
||||
} |
||||
} else { |
||||
if (firstDayofMonth <= 5) { |
||||
extDate += 7 |
||||
} |
||||
} |
||||
} |
||||
return extDate |
||||
} |
||||
/** |
||||
* 计算下月应占的格子 |
||||
* @param {number} year 年份 |
||||
* @param {number} month 月份 |
||||
*/ |
||||
function calculateNextMonthGrids(year, month, config) { |
||||
let emptyGrids = [] |
||||
const datesCount = dateUtil.getDatesCountOfMonth(year, month) |
||||
let lastDayWeek = dateUtil.getDayOfWeek(year, month, datesCount) |
||||
if (config.firstDayOfWeek === 'Mon') { |
||||
if (lastDayWeek === 0) { |
||||
lastDayWeek = 6 |
||||
} else { |
||||
lastDayWeek -= 1 |
||||
} |
||||
} |
||||
let len = 7 - (lastDayWeek + 1) |
||||
const { onlyShowCurrentMonth } = config |
||||
if (!onlyShowCurrentMonth) { |
||||
len = len + calculateExtraEmptyDate(year, month, config) |
||||
} |
||||
const YMInfo = dateUtil.getNextMonthInfo({ year, month }) |
||||
for (let i = 1; i <= len; i++) { |
||||
const week = dateUtil.getDayOfWeek(+year, +month, i) |
||||
if (onlyShowCurrentMonth) { |
||||
emptyGrids.push('') |
||||
} else { |
||||
emptyGrids.push({ |
||||
id: i - 1, |
||||
...YMInfo, |
||||
date: i, |
||||
week: week || 7 |
||||
}) |
||||
} |
||||
} |
||||
return emptyGrids |
||||
} |
||||
/** |
||||
* 设置日历面板数据 |
||||
* @param {number} year 年份 |
||||
* @param {number} month 月份 |
||||
* @param {number} curDate 日期 |
||||
*/ |
||||
function calculateCurrentMonthDates(year, month) { |
||||
return dateUtil.calcDates(year, month) |
||||
} |
||||
|
||||
export function calcJumpData({ dateInfo, config, component }) { |
||||
dateInfo = dateInfo || dateUtil.todayFMD() |
||||
const { year, month, date } = dateInfo |
||||
const calendarConfig = config || getCalendarConfig(component) |
||||
const emptyGrids = calculateEmptyGrids(year, month, calendarConfig) |
||||
const calendar = { |
||||
curYear: year, |
||||
curMonth: month, |
||||
curDate: date, |
||||
dates: calculateCurrentMonthDates(year, month), |
||||
...emptyGrids |
||||
} |
||||
return calendar |
||||
} |
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
import { dateUtil } from './utils/index' |
||||
|
||||
export function calcTargetYMInfo() { |
||||
return { |
||||
right: dateUtil.getPrevMonthInfo, |
||||
left: dateUtil.getNextMonthInfo, |
||||
prev_month: dateUtil.getPrevMonthInfo, |
||||
next_month: dateUtil.getNextMonthInfo, |
||||
prev_year: dateUtil.getPrevYearInfo, |
||||
next_year: dateUtil.getNextYearInfo |
||||
} |
||||
} |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
export {}; |
@ -0,0 +1,258 @@
@@ -0,0 +1,258 @@
|
||||
import plugins from './plugins/index' |
||||
import { calcJumpData } from './core' |
||||
import { renderCalendar } from './render' |
||||
import { calcTargetYMInfo } from './helper' |
||||
import { dateUtil, calendarGesture, logger } from './utils/index' |
||||
|
||||
Component({ |
||||
options: { |
||||
styleIsolation: 'apply-shared', |
||||
multipleSlots: true // 在组件定义时的选项中启用多slot支持
|
||||
}, |
||||
properties: { |
||||
config: { |
||||
type: Object, |
||||
value: {} |
||||
} |
||||
}, |
||||
lifetimes: { |
||||
attached: function() { |
||||
this.initComp() |
||||
} |
||||
}, |
||||
methods: { |
||||
initComp() { |
||||
const calendarConfig = this.setDefaultDisableDate() |
||||
this.setConfig(calendarConfig) |
||||
}, |
||||
// 禁用某天日期配置默认为今天
|
||||
setDefaultDisableDate() { |
||||
const calendarConfig = this.properties.config || {} |
||||
if (calendarConfig.disableMode && !calendarConfig.disableMode.date) { |
||||
calendarConfig.disableMode.date = dateUtil.toTimeStr( |
||||
dateUtil.todayFMD() |
||||
) |
||||
} |
||||
return calendarConfig |
||||
}, |
||||
initCalendar(config) { |
||||
const { defaultDate } = config |
||||
let date = dateUtil.todayFMD() |
||||
if (defaultDate && typeof defaultDate === 'string') { |
||||
const dateInfo = defaultDate.split('-') |
||||
if (dateInfo.length < 3) { |
||||
return logger.warn('defaultDate配置格式应为: 2018-4-2 或 2018-04-02') |
||||
} else { |
||||
date = { |
||||
year: +dateInfo[0], |
||||
month: +dateInfo[1], |
||||
date: +dateInfo[2] |
||||
} |
||||
} |
||||
} |
||||
const waitRenderData = calcJumpData({ |
||||
dateInfo: date, |
||||
config |
||||
}) |
||||
const timestamp = dateUtil.todayTimestamp() |
||||
if (config.autoChoosedWhenJump) { |
||||
const target = waitRenderData.dates.filter( |
||||
item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(date) |
||||
) |
||||
if (target && target.length) { |
||||
if (!waitRenderData.selectedDates) { |
||||
waitRenderData.selectedDates = target |
||||
} else { |
||||
waitRenderData.selectedDates.push(target[0]) |
||||
} |
||||
} |
||||
} |
||||
return { |
||||
...waitRenderData, |
||||
todayTimestamp: timestamp, |
||||
weeksCh: dateUtil.getWeekHeader(config.firstDayOfWeek) |
||||
} |
||||
}, |
||||
setConfig(config) { |
||||
if (config.markToday && typeof config.markToday === 'string') { |
||||
config.highlightToday = true |
||||
} |
||||
config.theme = config.theme || 'default' |
||||
this.setData( |
||||
{ |
||||
config |
||||
}, |
||||
() => { |
||||
for (let plugin of plugins.installed) { |
||||
const [, p] = plugin |
||||
if (typeof p.install === 'function') { |
||||
p.install(this) |
||||
} |
||||
if (typeof p.methods === 'function') { |
||||
const methods = p.methods(this) |
||||
for (let fnName in methods) { |
||||
if (fnName.startsWith('__')) continue |
||||
const fn = methods[fnName] |
||||
if (typeof fn === 'function') { |
||||
if (!this.calendar) this.calendar = {} |
||||
this.calendar[fnName] = fn |
||||
} |
||||
} |
||||
} |
||||
} |
||||
const initData = this.initCalendar(config) |
||||
renderCalendar.call(this, initData, config) |
||||
} |
||||
) |
||||
}, |
||||
tapDate(e) { |
||||
const { info } = e.currentTarget.dataset |
||||
const { date, disable } = info || {} |
||||
if (disable || !date) return |
||||
const { calendar, config } = this.data |
||||
let calendarData = calendar |
||||
let calendarConfig = config |
||||
if (config.takeoverTap) { |
||||
return this.triggerEvent('takeoverTap', info) |
||||
} |
||||
for (let plugin of plugins.installed) { |
||||
const [, p] = plugin |
||||
if (typeof p.onTapDate === 'function') { |
||||
const { |
||||
calendarData: __calendarData, |
||||
calendarConfig: __calendarConfig |
||||
} = p.onTapDate(info, calendarData, calendarConfig) |
||||
calendarData = __calendarData |
||||
calendarConfig = __calendarConfig |
||||
} |
||||
} |
||||
renderCalendar.call(this, calendarData, calendarConfig).then(() => { |
||||
this.triggerEvent('afterTapDate', info) |
||||
}) |
||||
}, |
||||
/** |
||||
* 日历滑动开始 |
||||
* @param {object} e |
||||
*/ |
||||
calendarTouchstart(e) { |
||||
const t = e.touches[0] |
||||
const startX = t.clientX |
||||
const startY = t.clientY |
||||
this.swipeLock = true |
||||
this.setData({ |
||||
'gesture.startX': startX, |
||||
'gesture.startY': startY |
||||
}) |
||||
}, |
||||
/** |
||||
* 日历滑动中 |
||||
* @param {object} e |
||||
*/ |
||||
calendarTouchmove(e) { |
||||
const { gesture } = this.data |
||||
const { preventSwipe } = this.properties.config |
||||
if (!this.swipeLock || preventSwipe) return |
||||
if (calendarGesture.isLeft(gesture, e.touches[0])) { |
||||
this.handleSwipe('left') |
||||
this.swipeLock = false |
||||
} |
||||
if (calendarGesture.isRight(gesture, e.touches[0])) { |
||||
this.handleSwipe('right') |
||||
this.swipeLock = false |
||||
} |
||||
}, |
||||
calendarTouchend(e) { |
||||
this.setData({ |
||||
'calendar.leftSwipe': 0, |
||||
'calendar.rightSwipe': 0 |
||||
}) |
||||
}, |
||||
handleSwipe(direction) { |
||||
let swipeKey = 'calendar.leftSwipe' |
||||
if (direction === 'right') { |
||||
swipeKey = 'calendar.rightSwipe' |
||||
} |
||||
this.setData({ |
||||
[swipeKey]: 1 |
||||
}) |
||||
const { calendar } = this.data |
||||
let calendarData = calendar |
||||
const { curYear, curMonth } = calendarData |
||||
const getMonthInfo = calcTargetYMInfo()[direction] |
||||
const target = getMonthInfo({ |
||||
year: +curYear, |
||||
month: +curMonth |
||||
}) |
||||
target.direction = direction |
||||
this.renderCalendar(target) |
||||
}, |
||||
changeDate(e) { |
||||
const { type } = e.currentTarget.dataset |
||||
const { calendar: calendarData } = this.data |
||||
const { curYear, curMonth } = calendarData |
||||
const getMonthInfo = calcTargetYMInfo()[type] |
||||
const target = getMonthInfo({ |
||||
year: +curYear, |
||||
month: +curMonth |
||||
}) |
||||
target.direction = type |
||||
this.renderCalendar(target) |
||||
}, |
||||
renderCalendar(target) { |
||||
let { calendar: calendarData, config } = this.data |
||||
const { curYear, curMonth } = calendarData || {} |
||||
for (let plugin of plugins.installed) { |
||||
const [, p] = plugin |
||||
if (typeof p.onSwitchCalendar === 'function') { |
||||
calendarData = p.onSwitchCalendar(target, calendarData, this) |
||||
} |
||||
} |
||||
return renderCalendar.call(this, calendarData, config).then(() => { |
||||
let triggerEventName = 'whenChangeMonth' |
||||
if (config.weekMode) { |
||||
triggerEventName = 'whenChangeWeek' |
||||
} |
||||
this.triggerEvent(triggerEventName, { |
||||
current: { |
||||
year: +curYear, |
||||
month: +curMonth |
||||
}, |
||||
next: target |
||||
}) |
||||
this.triggerEvent('onSwipe', { |
||||
current: { |
||||
year: +curYear, |
||||
month: +curMonth |
||||
}, |
||||
next: target, |
||||
type: triggerEventName |
||||
}) |
||||
}) |
||||
}, |
||||
doubleClickJumpToToday() { |
||||
const { multi, weekMode } = this.calendar.getCalendarConfig() || {} |
||||
if (multi || weekMode) return |
||||
if (this.count === undefined) { |
||||
this.count = 1 |
||||
} else { |
||||
this.count += 1 |
||||
} |
||||
if (this.lastClick) { |
||||
const difference = new Date().getTime() - this.lastClick |
||||
if ( |
||||
difference < 500 && |
||||
this.count >= 2 && |
||||
typeof this.calendar.jump === 'function' |
||||
) { |
||||
const today = dateUtil.todayFMD() |
||||
this.calendar.jump(today) |
||||
} |
||||
this.count = undefined |
||||
this.lastClick = undefined |
||||
} else { |
||||
this.lastClick = new Date().getTime() |
||||
} |
||||
this.triggerEvent('jumpToToday') |
||||
} |
||||
} |
||||
}) |
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
{ |
||||
"component": true |
||||
} |
@ -0,0 +1,116 @@
@@ -0,0 +1,116 @@
|
||||
<view class="flex b tb ac" wx:if="{{calendar}}"> |
||||
<view class="calendar b tb"> |
||||
<!-- 头部操作栏 --> |
||||
<view |
||||
wx:if="{{!config.hideHeader}}" |
||||
class="handle {{config.theme}}_handle-color fs32 b lr ac pc" |
||||
> |
||||
<view class="prev fs36" wx:if="{{!config.weekMode}}"> |
||||
<text |
||||
wx:if="{{!config.hideSelectYear}}" |
||||
class="prev-handle iconfont icon-doubleleft" |
||||
bindtap="changeDate" |
||||
data-type="prev_year" |
||||
></text> |
||||
<text |
||||
class="prev-handle iconfont icon-left" |
||||
bindtap="changeDate" |
||||
data-type="prev_month" |
||||
></text> |
||||
</view> |
||||
<view class="flex date-in-handle b lr cc blod" bindtap="doubleClickJumpToToday" |
||||
>{{calendar.curYear || "--"}} 年 {{calendar.curMonth || "--"}} 月</view |
||||
> |
||||
<view class="next fs36" wx:if="{{!config.weekMode}}"> |
||||
<text |
||||
class="next-handle iconfont icon-right" |
||||
bindtap="changeDate" |
||||
data-type="next_month" |
||||
></text> |
||||
<text |
||||
wx:if="{{!config.hideSelectYear}}" |
||||
class="next-handle iconfont icon-doubleright" |
||||
bindtap="changeDate" |
||||
data-type="next_year" |
||||
></text> |
||||
</view> |
||||
</view> |
||||
<!-- 星期栏 --> |
||||
<view class="weeks b lr ac {{config.theme}}_week-color"> |
||||
<view class="week fs28" wx:for="{{calendar.weeksCh}}" wx:key="index" data-idx="{{index}}"> |
||||
{{item}} |
||||
</view> |
||||
</view> |
||||
<!-- 日历面板主体 --> |
||||
<view |
||||
class="b lr wrap" |
||||
bindtouchstart="calendarTouchstart" |
||||
catchtouchmove="calendarTouchmove" |
||||
catchtouchend="calendarTouchend" |
||||
> |
||||
<!-- 上月日期格子 --> |
||||
<view |
||||
class="grid b ac pc {{config.theme}}_prev-month-date" |
||||
wx:for="{{calendar.prevMonthGrids}}" |
||||
wx:key="index" |
||||
data-idx="{{index}}" |
||||
> |
||||
<view class="date-wrap b cc"> |
||||
<view class="date"> |
||||
{{item.date}} |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<!-- 本月日期格子 --> |
||||
<view |
||||
wx:for="{{calendar.dates}}" |
||||
wx:key="index" |
||||
data-idx="{{index}}" |
||||
data-info="{{item}}" |
||||
bindtap="tapDate" |
||||
class="grid {{item.class ? item.class : ''}} {{config.theme}}_normal-date b ac pc" |
||||
> |
||||
<view |
||||
class="date-wrap b cc {{config.emphasisWeek && (item.week === 0 || item.week === 6) ? config.theme + '_weekend-color' : ''}}" |
||||
> |
||||
<view |
||||
class="date b ac pc {{item.class ? item.class : ''}} {{item.isToday && config.highlightToday ? config.theme + '_today' : ''}} {{item.choosed ? config.theme + '_choosed' : ''}} {{item.disable ? config.theme + '_date-disable' : ''}} {{config.chooseAreaMode ? 'date-area-mode' : ''}} {{calendar.todoLabelCircle && item.showTodoLabel && !item.choosed ? config.theme + '_todo-circle todo-circle' : '' }}" |
||||
> |
||||
{{config.markToday && item.isToday ? config.markToday : item.date}} |
||||
<view |
||||
wx:if="{{(config.showLunar && item.lunar && !item.showTodoLabel) || (item.showTodoLabel && calendar.todoLabelPos !== 'bottom') || config.showHolidays}}" |
||||
class="date-desc {{config.theme}}_date-desc date-desc-bottom {{(item.choosed || item.isToday) ? 'date-desc-bottom-always' : ''}} {{item.disable ? config.theme + '_date-desc-disable' : ''}}" |
||||
> |
||||
<text |
||||
class="{{config.showHolidays && !item.showTodoLabel && item.label && !item.choosed ? config.theme + '_date-desc-lunar' : ''}} {{item.type === 'festival' ? config.theme + '_festival' : ''}}" |
||||
>{{item.label || item.lunar.Term || item.lunar.IDayCn}}</text |
||||
> |
||||
</view> |
||||
<block wx:for="{{item.color}}" wx:for-item="col" wx:for-index="colIndex" wx:key="*this"> |
||||
<view |
||||
wx:if="{{item.showTodoLabel && !calendar.todoLabelCircle}}" |
||||
class="{{item.todoText ? 'date-desc' : config.theme + '_todo-dot todo-dot'}} {{config.showLunar ? config.theme + '_date-desc-lunar' : ''}} {{calendar.todoLabelPos === 'bottom' ? 'date-desc-bottom todo-dot-bottom' : 'date-desc-top todo-dot-top'}} {{calendar.showLabelAlways && item.choosed && calendar.todoLabelPos === 'bottom' ? 'date-desc-bottom-always todo-dot-bottom-always' : ''}} {{calendar.showLabelAlways && item.choosed && calendar.todoLabelPos === 'top' ? 'date-desc-top-always todo-dot-top-always' : ''}}" |
||||
style="background-color: {{item.todoText ? '' : col || calendar.todoLabelColor}}; color: {{col}};left:{{(item.color.length>1 ? 35 : 50)*(colIndex+1)}}%" |
||||
> |
||||
{{item.todoText}} |
||||
</view> |
||||
</block> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<!-- 下月日期格子 --> |
||||
<view |
||||
class="grid b ac pc {{config.theme}}_next-month-date" |
||||
wx:for="{{calendar.nextMonthGrids}}" |
||||
wx:key="index" |
||||
data-idx="{{index}}" |
||||
> |
||||
<view class="date-wrap b cc"> |
||||
<view class="date"> |
||||
{{item.date}} |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
@ -0,0 +1,248 @@
@@ -0,0 +1,248 @@
|
||||
@import "./theme/iconfont.wxss"; |
||||
@import "./theme/theme-default.wxss"; |
||||
@import "./theme/theme-elegant.wxss"; |
||||
@import "./theme/theme-nuohe.wxss"; |
||||
@import "./theme/theme-geneB.wxss"; |
||||
|
||||
.blod { |
||||
font-weight: bold; |
||||
} |
||||
|
||||
.b { |
||||
display: flex; |
||||
} |
||||
|
||||
.lr { |
||||
flex-direction: row; |
||||
} |
||||
|
||||
.tb { |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.pc { |
||||
justify-content: center; |
||||
} |
||||
|
||||
.ac { |
||||
align-items: center; |
||||
} |
||||
|
||||
.cc { |
||||
align-items: center; |
||||
justify-content: center; |
||||
} |
||||
|
||||
.wrap { |
||||
flex-wrap: wrap; |
||||
} |
||||
|
||||
.flex { |
||||
flex-grow: 1; |
||||
} |
||||
|
||||
.bg { |
||||
background-image: linear-gradient(to bottom, #faefe7, #ffcbd7); |
||||
overflow: hidden; |
||||
} |
||||
|
||||
.white-color { |
||||
color: #fff; |
||||
} |
||||
|
||||
.fs24 { |
||||
font-size: 24rpx; |
||||
} |
||||
|
||||
.fs28 { |
||||
font-size: 28rpx; |
||||
} |
||||
|
||||
.fs32 { |
||||
font-size: 32rpx; |
||||
} |
||||
|
||||
.fs36 { |
||||
font-size: 36rpx; |
||||
} |
||||
|
||||
.calendar { |
||||
width: 100%; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
/* 日历操作栏 */ |
||||
|
||||
.handle { |
||||
height: 80rpx; |
||||
} |
||||
|
||||
.prev-handle, |
||||
.next-handle { |
||||
padding: 20rpx; |
||||
} |
||||
|
||||
.date-in-handle { |
||||
height: 80rpx; |
||||
} |
||||
|
||||
/* 星期栏 */ |
||||
|
||||
.weeks { |
||||
height: 50rpx; |
||||
line-height: 50rpx; |
||||
opacity: 0.5; |
||||
} |
||||
|
||||
.week { |
||||
text-align: center; |
||||
} |
||||
|
||||
.grid, |
||||
.week { |
||||
width: 14.286014285714286%; |
||||
} |
||||
|
||||
.date-wrap { |
||||
width: 100%; |
||||
height: 80rpx; |
||||
position: relative; |
||||
left: 0; |
||||
top: 0; |
||||
} |
||||
|
||||
.date { |
||||
position: relative; |
||||
left: 0; |
||||
top: 0; |
||||
width: 55rpx; |
||||
height: 55rpx; |
||||
text-align: center; |
||||
line-height: 55rpx; |
||||
font-size: 28rpx; |
||||
font-weight: 200; |
||||
border-radius: 50%; |
||||
transition: all 0.3s; |
||||
font-weight: bold; |
||||
|
||||
animation-name: choosed; |
||||
|
||||
animation-duration: 0.5s; |
||||
|
||||
animation-timing-function: linear; |
||||
|
||||
animation-iteration-count: 1; |
||||
} |
||||
|
||||
.date-area-mode { |
||||
width: 100%; |
||||
|
||||
border-radius: 0; |
||||
} |
||||
|
||||
.date-desc { |
||||
width: 150%; |
||||
|
||||
height: 32rpx; |
||||
|
||||
font-size: 20rpx; |
||||
|
||||
line-height: 32rpx; |
||||
|
||||
position: absolute; |
||||
|
||||
left: 50%; |
||||
|
||||
transform: translateX(-50%); |
||||
|
||||
overflow: hidden; |
||||
|
||||
word-break: break-all; |
||||
|
||||
text-overflow: ellipsis; |
||||
|
||||
white-space: nowrap; |
||||
|
||||
-webkit-line-clamp: 1; |
||||
|
||||
text-align: center; |
||||
} |
||||
|
||||
@keyframes choosed { |
||||
from { |
||||
transform: scale(1); |
||||
} |
||||
|
||||
50% { |
||||
transform: scale(0.9); |
||||
} |
||||
|
||||
to { |
||||
transform: scale(1); |
||||
} |
||||
} |
||||
|
||||
/* 日期圆圈标记 */ |
||||
|
||||
.todo-circle { |
||||
border-width: 1rpx; |
||||
|
||||
border-style: solid; |
||||
|
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
/* 待办点标记相关样式 */ |
||||
|
||||
.todo-dot { |
||||
width: 16rpx; |
||||
|
||||
height: 16rpx; |
||||
|
||||
border-radius: 50%; |
||||
|
||||
position: absolute; |
||||
|
||||
left: 50%; |
||||
bottom: -10rpx !important; |
||||
|
||||
transform: translateX(-50%); |
||||
} |
||||
|
||||
.todo-dot-top { |
||||
top: 3rpx; |
||||
} |
||||
|
||||
.todo-dot.todo-dot-top-always { |
||||
top: -8rpx; |
||||
} |
||||
|
||||
.todo-dot.todo-dot-bottom { |
||||
bottom: 0; |
||||
} |
||||
|
||||
.todo-dot.todo-dot-bottom-always { |
||||
bottom: -10rpx; |
||||
} |
||||
|
||||
/* 日期描述文字(待办文字/农历)相关样式 */ |
||||
|
||||
.date-desc.date-desc-top { |
||||
top: -6rpx; |
||||
} |
||||
|
||||
.date-desc.date-desc-top-always { |
||||
top: -20rpx; |
||||
} |
||||
|
||||
.date-desc.date-desc-bottom { |
||||
bottom: -14rpx; |
||||
} |
||||
|
||||
.todo-circle .date-desc.date-desc-bottom { |
||||
bottom: -30rpx; |
||||
} |
||||
|
||||
.date-desc.date-desc-bottom-always { |
||||
bottom: -28rpx; |
||||
} |
@ -0,0 +1,212 @@
@@ -0,0 +1,212 @@
|
||||
/* * |
||||
@Author: drfu* |
||||
@Description: 数据来源于国务院办公厅关于2020年部分节假日安排的通知(国办发明电〔2019〕16号)_政府信息公开专栏,http://www.gov.cn/zhengce/content/2019-11/21/content_5454164.htm
|
||||
@Date: 2020-10-12 14:29:45* |
||||
* @Last Modified by: drfu |
||||
* @Last Modified time: 2020-10-16 17:38:08 |
||||
*/ |
||||
|
||||
// 节日列表
|
||||
export const festival = { |
||||
// 农历固定日期节日
|
||||
lunar: { |
||||
1: { |
||||
1: { |
||||
type: 'festival', |
||||
name: '春节', |
||||
label: '春节' |
||||
}, |
||||
8: { |
||||
type: 'festival', |
||||
name: '腊八节', |
||||
label: '腊八' |
||||
}, |
||||
15: { |
||||
type: 'festival', |
||||
name: '元宵节', |
||||
label: '元宵' |
||||
} |
||||
}, |
||||
7: { |
||||
7: { |
||||
type: 'festival', |
||||
name: '七夕节', |
||||
label: '七夕' |
||||
}, |
||||
15: { |
||||
type: 'festival', |
||||
name: '中元节', |
||||
label: '中元节' |
||||
} |
||||
}, |
||||
9: { |
||||
9: { |
||||
type: 'festival', |
||||
name: '重阳节', |
||||
label: '重阳节' |
||||
} |
||||
} |
||||
}, |
||||
// 阳历固定日期节日
|
||||
solar: { |
||||
2: { |
||||
14: { |
||||
type: 'festival', |
||||
name: '情人节', |
||||
label: '情人节' |
||||
} |
||||
}, |
||||
3: { |
||||
12: { |
||||
type: 'festival', |
||||
name: '植树节', |
||||
label: '植树节' |
||||
} |
||||
}, |
||||
4: { |
||||
1: { |
||||
type: 'festival', |
||||
name: '愚人节', |
||||
label: '愚人节' |
||||
}, |
||||
5: { |
||||
type: 'festival', |
||||
name: '清明节', |
||||
label: '清明节' |
||||
} |
||||
}, |
||||
5: { |
||||
1: { |
||||
type: 'festival', |
||||
name: '劳动节', |
||||
label: '劳动节' |
||||
} |
||||
}, |
||||
6: { |
||||
1: { |
||||
type: 'festival', |
||||
name: '儿童节', |
||||
label: '儿童节' |
||||
} |
||||
}, |
||||
7: { |
||||
1: { |
||||
type: 'festival', |
||||
name: '建党节', |
||||
label: '建党节' |
||||
} |
||||
}, |
||||
8: { |
||||
1: { |
||||
type: 'festival', |
||||
name: '建军节', |
||||
label: '建军节' |
||||
} |
||||
}, |
||||
9: { |
||||
10: { |
||||
type: 'festival', |
||||
name: '教师节', |
||||
label: '教师节' |
||||
} |
||||
}, |
||||
10: { |
||||
1: { |
||||
type: 'festival', |
||||
name: '国庆节', |
||||
label: '国庆节' |
||||
} |
||||
}, |
||||
12: { |
||||
25: { |
||||
type: 'festival', |
||||
name: '圣诞节', |
||||
label: '圣诞节' |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
export const holidays = { |
||||
2020: { |
||||
1: { |
||||
1: { |
||||
type: 'holiday', |
||||
name: '元旦', |
||||
label: '休' |
||||
}, |
||||
19: { |
||||
type: 'work', |
||||
name: '调班', |
||||
label: '班' |
||||
}, |
||||
'24-30': { |
||||
type: 'holiday', |
||||
name: '春节', |
||||
label: '休' |
||||
} |
||||
}, |
||||
2: { |
||||
1: { |
||||
type: 'work', |
||||
name: '调班', |
||||
label: '班' |
||||
} |
||||
}, |
||||
4: { |
||||
'4-6': { |
||||
type: 'holiday', |
||||
name: '清明节', |
||||
label: '休' |
||||
}, |
||||
26: { |
||||
type: 'work', |
||||
name: '调班', |
||||
label: '班' |
||||
} |
||||
}, |
||||
5: { |
||||
'1-5': { |
||||
type: 'holiday', |
||||
name: '劳动节', |
||||
label: '休' |
||||
}, |
||||
9: { |
||||
type: 'work', |
||||
name: '调班', |
||||
label: '班' |
||||
} |
||||
}, |
||||
6: { |
||||
'25-27': { |
||||
type: 'holiday', |
||||
name: '端午节', |
||||
label: '休' |
||||
}, |
||||
28: { |
||||
type: 'work', |
||||
name: '调班', |
||||
label: '班' |
||||
} |
||||
}, |
||||
9: { |
||||
27: { |
||||
type: 'work', |
||||
name: '调班', |
||||
label: '班' |
||||
} |
||||
}, |
||||
10: { |
||||
'1-8': { |
||||
type: 'holiday', |
||||
name: '国庆节/中秋节', |
||||
label: '休' |
||||
}, |
||||
10: { |
||||
type: 'work', |
||||
name: '调班', |
||||
label: '班' |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
export {}; |
@ -0,0 +1,201 @@
@@ -0,0 +1,201 @@
|
||||
/* * |
||||
@Author: drfu* |
||||
@Description: 显示法定节假日班/休情况 |
||||
@Date: 2020-10-12 14:29:45* |
||||
* @Last Modified by: drfu |
||||
* @Last Modified time: 2020-10-16 17:34:13 |
||||
*/ |
||||
|
||||
import { holidays, festival } from './holidays-map' |
||||
import { dateUtil, getCalendarData, logger } from '../../utils/index' |
||||
|
||||
/** |
||||
* 当前是否在休假期内 |
||||
* @param {object} { year, month } |
||||
* @param {object} { start, end, current } |
||||
* @returns |
||||
*/ |
||||
function inHolidays({ year, month }, { start, end, current }) { |
||||
const getTimeStamp = dateUtil.getTimeStamp |
||||
const startTimestamp = getTimeStamp({ |
||||
year, |
||||
month, |
||||
date: start |
||||
}) |
||||
const endTimestamp = getTimeStamp({ |
||||
year, |
||||
month, |
||||
date: end |
||||
}) |
||||
const currentDateTimestamp = getTimeStamp({ |
||||
year, |
||||
month, |
||||
date: current |
||||
}) |
||||
if ( |
||||
currentDateTimestamp >= startTimestamp && |
||||
currentDateTimestamp <= endTimestamp |
||||
) { |
||||
return true |
||||
} |
||||
return false |
||||
} |
||||
|
||||
function addSpecialFestival(date, component) { |
||||
const { convertlLunar2Solar, convertSolarLunar } = component.calendar || {} |
||||
const lunarDateInfo = convertSolarLunar(date) |
||||
const { lYear, lMonth } = lunarDateInfo || {} |
||||
// 春节
|
||||
const info = { |
||||
type: 'festival', |
||||
name: '除夕', |
||||
label: '除夕' |
||||
} |
||||
if (lMonth === 12) { |
||||
if (!festival.lunar['12']) festival.lunar['12'] = {} |
||||
if (convertlLunar2Solar(`${lYear}-12-30`) === -1) { |
||||
festival.lunar['12']['29'] = info |
||||
} else { |
||||
festival.lunar['12']['30'] = info |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 是否匹配到节日 |
||||
* @param {object} [dateInfo={}] |
||||
* @param {object} [component={}] |
||||
* @returns {object|boolean} 匹配到的节日数据或者false |
||||
*/ |
||||
function hasFestivalDate(dateInfo = {}, component = {}) { |
||||
const { month, date } = dateInfo |
||||
let festivalDate = festival.solar[month] && festival.solar[month][date] |
||||
if (!festivalDate) { |
||||
const { convertSolarLunar } = component.calendar || {} |
||||
const lunarDateInfo = convertSolarLunar(dateInfo) |
||||
const { lMonth, lDay } = lunarDateInfo |
||||
festivalDate = festival.lunar[lMonth] && festival.lunar[lMonth][lDay] |
||||
if (!festivalDate) { |
||||
const festivalOfMonth = festival.lunar[lMonth] || {} |
||||
const festivalDateKey = Object.keys(festivalOfMonth).find(item => |
||||
item.match(new RegExp(`\\b${lDay}\\b`)) |
||||
) |
||||
if (!festivalDateKey) { |
||||
festivalDate = false |
||||
} else { |
||||
const festivalInfo = festival.lunar[lMonth][festivalDateKey] |
||||
if (!festivalInfo) { |
||||
festivalDate = false |
||||
} else { |
||||
const { condition } = festivalInfo |
||||
if (typeof condition === 'function') { |
||||
festivalDate = condition(lunarDateInfo) |
||||
} else { |
||||
festivalDate = false |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return festivalDate |
||||
} |
||||
|
||||
export default () => { |
||||
return { |
||||
name: 'holidays', |
||||
beforeRender(calendarData = {}, calendarConfig = {}, component) { |
||||
let { dates = [] } = calendarData |
||||
if (calendarConfig.showHolidays || calendarConfig.showFestival) { |
||||
dates = dates.map(d => { |
||||
let item = { ...d } |
||||
const { year, month, date } = item |
||||
const holidaysOfMonth = |
||||
(holidays[year] && holidays[year][month]) || {} |
||||
const holidayDate = holidaysOfMonth[date] |
||||
if (holidayDate) { |
||||
item = { |
||||
...item, |
||||
...holidayDate |
||||
} |
||||
} else { |
||||
const holidayKeys = Object.keys(holidaysOfMonth).filter(item => |
||||
item.includes('-') |
||||
) |
||||
let target = '' |
||||
for (let v of holidayKeys) { |
||||
const [start, end] = v.split('-') |
||||
if (+d.date >= +start && +d.date <= +end) { |
||||
target = v |
||||
break |
||||
} |
||||
} |
||||
const [start, end] = target.split('-') |
||||
const isInHolidays = inHolidays( |
||||
{ |
||||
year, |
||||
month |
||||
}, |
||||
{ |
||||
start, |
||||
end, |
||||
current: date |
||||
} |
||||
) |
||||
if (isInHolidays) { |
||||
item = { |
||||
...item, |
||||
...holidaysOfMonth[target] |
||||
} |
||||
} else if (calendarConfig.showFestival) { |
||||
const { convertSolarLunar, convertlLunar2Solar } = |
||||
component.calendar || {} |
||||
if ( |
||||
typeof convertSolarLunar !== 'function' || |
||||
typeof convertlLunar2Solar !== 'function' |
||||
) { |
||||
return logger.warn( |
||||
'农历节日显示需要引入农历插件(/component/v2/plugins/solarLunar)' |
||||
) |
||||
} |
||||
addSpecialFestival(item, component) |
||||
const festivalDate = hasFestivalDate(item, component) |
||||
if (festivalDate) { |
||||
item = { |
||||
...item, |
||||
...festivalDate |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return item |
||||
}) |
||||
} |
||||
return { |
||||
calendarData: { |
||||
...calendarData, |
||||
dates: dates |
||||
}, |
||||
calendarConfig |
||||
} |
||||
}, |
||||
methods(component) { |
||||
return { |
||||
getHolidaysOfCurrentYear() { |
||||
const calendar = getCalendarData('calendar', component) |
||||
const { curYear } = calendar |
||||
return this.methods(component).getHolidaysOfYear(curYear) |
||||
}, |
||||
getHolidaysOfYear(year) { |
||||
if (!year) return logger.warn('getHolidaysOfCurrentYear() 入参错误') |
||||
if (!holidays[year]) { |
||||
logger.warn('未匹配到当前年份节假日信息,请自行补充') |
||||
return { |
||||
err: 'not match' |
||||
} |
||||
} |
||||
return holidays[year] |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
export {}; |
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
import preset from './preset/index' |
||||
|
||||
export default { |
||||
installed: [...preset], |
||||
use(plugin) { |
||||
if (typeof plugin !== 'function') return |
||||
const info = plugin() || {} |
||||
const { name } = info |
||||
if ( |
||||
name && |
||||
name !== 'methods' && |
||||
!this.installed.some(p => p[0] === name) |
||||
) { |
||||
this.installed.unshift([name, info]) |
||||
} |
||||
return this |
||||
} |
||||
} |
@ -0,0 +1,277 @@
@@ -0,0 +1,277 @@
|
||||
/** |
||||
* @Author: drfu* |
||||
* @Description: 基础功能 |
||||
* @Date: 2020-10-08 21:22:09* |
||||
* @Last Modified by: drfu |
||||
* @Last Modified time: 2020-10-11 13:28:52 |
||||
* */ |
||||
|
||||
import { calcJumpData } from '../../core' |
||||
import { renderCalendar } from '../../render' |
||||
import { |
||||
dateUtil, |
||||
getCalendarData, |
||||
setCalendarData, |
||||
getCalendarConfig |
||||
} from '../../utils/index' |
||||
|
||||
export default () => { |
||||
return { |
||||
name: 'base', |
||||
beforeRender(calendarData = {}, calendarConfig) { |
||||
const calendar = calendarData |
||||
const { selectedDates = [], dates } = calendar |
||||
let _dates = [...dates] |
||||
if (selectedDates.length) { |
||||
const selectedDatesStr = selectedDates.map(date => |
||||
dateUtil.toTimeStr(date) |
||||
) |
||||
_dates.forEach(date => { |
||||
const dateStr = dateUtil.toTimeStr(date) |
||||
if (selectedDatesStr.includes(dateStr)) { |
||||
date.choosed = true |
||||
} |
||||
}) |
||||
} |
||||
return { |
||||
calendarData: { |
||||
...calendarData, |
||||
dates: _dates |
||||
}, |
||||
calendarConfig |
||||
} |
||||
}, |
||||
onTapDate(tapedDate, calendarData = {}, calendarConfig = {}) { |
||||
const calendar = { |
||||
...calendarData |
||||
} |
||||
const dateIndex = dateUtil.findDateIndexInArray( |
||||
tapedDate, |
||||
calendarData.dates |
||||
) |
||||
const { multi, inverse } = calendarConfig |
||||
let dates = [...calendar.dates] |
||||
const { selectedDates = [] } = calendar |
||||
if (!multi) { |
||||
let preSelectedDate = {} |
||||
if (selectedDates.length) { |
||||
preSelectedDate = [...selectedDates].pop() || {} |
||||
} |
||||
const timeStr = dateUtil.toTimeStr |
||||
if (!inverse && timeStr(preSelectedDate) === timeStr(tapedDate)) { |
||||
return calendar |
||||
} |
||||
let _tapedDate = { ...tapedDate, choosed: !tapedDate.choosed } |
||||
|
||||
dates[dateIndex] = _tapedDate |
||||
if (preSelectedDate.date) { |
||||
const idx = dateUtil.findDateIndexInArray(preSelectedDate, dates) |
||||
const date = dates[idx] |
||||
if (date) { |
||||
date.choosed = false |
||||
} |
||||
} |
||||
if (dates[dateIndex].choosed) { |
||||
calendar.selectedDates = [dates[dateIndex]] |
||||
} else { |
||||
calendar.selectedDates = [] |
||||
} |
||||
} else { |
||||
dates[dateIndex] = { |
||||
...dates[dateIndex], |
||||
choosed: !dates[dateIndex].choosed |
||||
} |
||||
if (!calendar.selectedDates) { |
||||
calendar.selectedDates = [] |
||||
} |
||||
if (dates[dateIndex].choosed) { |
||||
calendar.selectedDates.push(dates[dateIndex]) |
||||
} else { |
||||
calendar.selectedDates = calendar.selectedDates.filter( |
||||
date => |
||||
dateUtil.toTimeStr(date) !== dateUtil.toTimeStr(dates[dateIndex]) |
||||
) |
||||
} |
||||
} |
||||
return { |
||||
calendarData: { |
||||
...calendar, |
||||
dates |
||||
}, |
||||
calendarConfig |
||||
} |
||||
}, |
||||
onSwitchCalendar(date, calendarData = {}, component) { |
||||
const calendarConfig = getCalendarConfig(component) |
||||
if (calendarConfig.weekMode) { |
||||
return calendarData |
||||
} |
||||
const updatedRenderData = calcJumpData({ |
||||
dateInfo: date, |
||||
config: calendarConfig |
||||
}) |
||||
return { |
||||
...calendarData, |
||||
...updatedRenderData |
||||
} |
||||
}, |
||||
methods(component) { |
||||
return { |
||||
jump: dateInfo => { |
||||
if (Object.prototype.toString.call(dateInfo) !== '[object Object]') |
||||
return |
||||
const updatedRenderData = calcJumpData({ |
||||
dateInfo, |
||||
component |
||||
}) |
||||
const existCalendarData = getCalendarData('calendar', component) |
||||
const config = getCalendarConfig(component) |
||||
if (config.autoChoosedWhenJump) { |
||||
const target = updatedRenderData.dates[dateInfo.date - 1] |
||||
if (!updatedRenderData.selectedDates) { |
||||
updatedRenderData.selectedDates = [target] |
||||
} else { |
||||
updatedRenderData.selectedDates.push(target) |
||||
} |
||||
} |
||||
return renderCalendar.call(component, { |
||||
...existCalendarData, |
||||
...updatedRenderData |
||||
}) |
||||
}, |
||||
getCalendarConfig() { |
||||
return getCalendarConfig(component) |
||||
}, |
||||
setCalendarConfig(config) { |
||||
return new Promise((resolve, reject) => { |
||||
if (!component || !component.data.config) { |
||||
reject('异常:未找到组件配置信息') |
||||
return |
||||
} |
||||
let conf = { ...component.config, ...config } |
||||
component.config = conf |
||||
setCalendarData({ config: conf }, component) |
||||
.then(resolve) |
||||
.catch(reject) |
||||
}) |
||||
}, |
||||
cancelSelectedDates(cancelDates = []) { |
||||
const existCalendarData = getCalendarData('calendar', component) || {} |
||||
const { dates = [], selectedDates = [] } = existCalendarData |
||||
let updatedRenderData = {} |
||||
const config = getCalendarConfig(component) |
||||
let chooseAreaData = {} |
||||
if (config.chooseAreaMode) { |
||||
chooseAreaData = { |
||||
chooseAreaTimestamp: [], |
||||
tempChooseAreaTimestamp: [] |
||||
} |
||||
} |
||||
if (!cancelDates.length) { |
||||
dates.forEach(item => { |
||||
item.choosed = false |
||||
}) |
||||
updatedRenderData = { |
||||
dates, |
||||
selectedDates: [] |
||||
} |
||||
} else { |
||||
const cancelDatesStr = cancelDates.map(date => |
||||
dateUtil.toTimeStr(date) |
||||
) |
||||
const filterSelectedDates = selectedDates.filter( |
||||
date => !cancelDatesStr.includes(dateUtil.toTimeStr(date)) |
||||
) |
||||
dates.forEach(date => { |
||||
if (cancelDatesStr.includes(dateUtil.toTimeStr(date))) { |
||||
date.choosed = false |
||||
} |
||||
}) |
||||
updatedRenderData = { |
||||
dates, |
||||
selectedDates: filterSelectedDates |
||||
} |
||||
} |
||||
|
||||
return renderCalendar.call(component, { |
||||
...existCalendarData, |
||||
...updatedRenderData, |
||||
...chooseAreaData |
||||
}) |
||||
}, |
||||
setSelectedDates: targetDates => { |
||||
const existCalendarData = getCalendarData('calendar', component) |
||||
let { dates, selectedDates = [] } = existCalendarData || {} |
||||
let __selectedDates = [] |
||||
let __dates = dates |
||||
if (!targetDates) { |
||||
__dates = dates.map(item => { |
||||
const date = { ...item } |
||||
date.choosed = true |
||||
if (existCalendarData.showLabelAlways && date.showTodoLabel) { |
||||
date.showTodoLabel = true |
||||
} else { |
||||
date.showTodoLabel = false |
||||
} |
||||
return date |
||||
}) |
||||
__selectedDates = dates |
||||
} else if (targetDates && targetDates.length) { |
||||
const allSelected = dateUtil.uniqueArrayByDate( |
||||
selectedDates.concat(targetDates) |
||||
) |
||||
const allSelectedDateStr = allSelected.map(d => |
||||
dateUtil.toTimeStr(d) |
||||
) |
||||
__dates = dates.map(item => { |
||||
const date = { ...item } |
||||
if (allSelectedDateStr.includes(dateUtil.toTimeStr(date))) { |
||||
date.choosed = true |
||||
__selectedDates.push(date) |
||||
} |
||||
if (existCalendarData.showLabelAlways && date.showTodoLabel) { |
||||
date.showTodoLabel = true |
||||
} else { |
||||
date.showTodoLabel = false |
||||
} |
||||
return date |
||||
}) |
||||
} |
||||
return renderCalendar.call(component, { |
||||
...existCalendarData, |
||||
dates: __dates, |
||||
selectedDates: __selectedDates |
||||
}) |
||||
}, |
||||
setDateStyle: toSetDates => { |
||||
if (!Array.isArray(toSetDates)) return Promise.reject() |
||||
const existCalendarData = getCalendarData('calendar', component) |
||||
const { dates = [], specialStyleDates } = existCalendarData || {} |
||||
if (Array.isArray(specialStyleDates)) { |
||||
toSetDates = dateUtil.uniqueArrayByDate([ |
||||
...specialStyleDates, |
||||
...toSetDates |
||||
]) |
||||
} |
||||
const toSetDatesStr = toSetDates.map(item => dateUtil.toTimeStr(item)) |
||||
const _dates = dates.map(item => { |
||||
const idx = toSetDatesStr.indexOf(dateUtil.toTimeStr(item)) |
||||
if (idx > -1) { |
||||
return { |
||||
...item, |
||||
class: toSetDates[idx].class |
||||
} |
||||
} else { |
||||
return item |
||||
} |
||||
}) |
||||
return renderCalendar.call(component, { |
||||
...existCalendarData, |
||||
dates: _dates, |
||||
specialStyleDates: toSetDates |
||||
}) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
/** |
||||
* @Author: drfu* |
||||
* @Description: 获取日历数据 |
||||
* @Date: 2020-10-08 21:22:09* |
||||
* @Last Modified by: drfu |
||||
* @Last Modified time: 2020-10-11 13:42:37 |
||||
* */ |
||||
|
||||
import { getCalendarData, logger, getCalendarConfig } from '../../utils/index' |
||||
|
||||
function wrapDateWithLunar(dates = [], convertFn) { |
||||
const datesWithLunar = JSON.parse(JSON.stringify(dates)).map(date => ({ |
||||
...date, |
||||
lunar: convertFn(date) |
||||
})) |
||||
return datesWithLunar |
||||
} |
||||
|
||||
export default () => { |
||||
return { |
||||
name: 'getData', |
||||
methods(component) { |
||||
return { |
||||
getCurrentYM: () => { |
||||
const { curYear, curMonth } = getCalendarData('calendar', component) |
||||
return { |
||||
year: curYear, |
||||
month: curMonth |
||||
} |
||||
}, |
||||
getSelectedDates: (options = {}) => { |
||||
const dates = |
||||
getCalendarData('calendar.selectedDates', component) || [] |
||||
const config = getCalendarConfig(component) || {} |
||||
if (options.lunar && !config.showLunar) { |
||||
const injectedFns = component.calendar || {} |
||||
if (typeof injectedFns.convertSolarLunar === 'function') { |
||||
return wrapDateWithLunar(dates, injectedFns.convertSolarLunar) |
||||
} else { |
||||
logger.warn('获取农历信息需引入农历插件') |
||||
} |
||||
} else { |
||||
return dates |
||||
} |
||||
}, |
||||
getCalendarDates: (options = {}) => { |
||||
const config = getCalendarConfig(component) || {} |
||||
const dates = getCalendarData('calendar.dates', component) |
||||
if (options.lunar && !config.showLunar) { |
||||
const injectedFns = component.calendar || {} |
||||
if (typeof injectedFns.convertSolarLunar === 'function') { |
||||
return wrapDateWithLunar(dates, injectedFns.convertSolarLunar) |
||||
} else { |
||||
logger.warn('获取农历信息需引入农历插件') |
||||
} |
||||
} else { |
||||
return dates |
||||
} |
||||
}, |
||||
getCalendarAllData: () => { |
||||
return { |
||||
data: getCalendarData('calendar', component) || {}, |
||||
config: getCalendarConfig(component) || {} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
export {}; |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
import base from './base' |
||||
import getCalendarData from './get-calendar-data' |
||||
|
||||
const preset = [ |
||||
['base', base()], |
||||
['get-calendar-data', getCalendarData()] |
||||
] |
||||
|
||||
export default preset |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
export {}; |
@ -0,0 +1,221 @@
@@ -0,0 +1,221 @@
|
||||
/** |
||||
* @Author: drfu* |
||||
* @Description: 禁用、启用日期选择 |
||||
* @Date: 2020-10-08 21:22:09* |
||||
* @Last Modified by: drfu |
||||
* @Last Modified time: 2020-10-08 21:25:00 |
||||
* */ |
||||
|
||||
import { getCalendarData, dateUtil, logger } from '../utils/index' |
||||
import { renderCalendar } from '../render' |
||||
|
||||
function convertEnableAreaToTimestamp(timearea = []) { |
||||
const start = timearea[0].split('-') |
||||
const end = timearea[1].split('-') |
||||
if (start.length !== 3 || end.length !== 3) { |
||||
logger.warn('enableArea() 参数格式为: ["2018-2-1", "2018-3-1"]') |
||||
return {} |
||||
} |
||||
const startTimestamp = dateUtil |
||||
.newDate(start[0], start[1], start[2]) |
||||
.getTime() |
||||
const endTimestamp = dateUtil.newDate(end[0], end[1], end[2]).getTime() |
||||
return { |
||||
start, |
||||
end, |
||||
startTimestamp, |
||||
endTimestamp |
||||
} |
||||
} |
||||
|
||||
function isValiditeOfDateArea(dateArea) { |
||||
const { |
||||
start, |
||||
end, |
||||
startTimestamp, |
||||
endTimestamp |
||||
} = convertEnableAreaToTimestamp(dateArea) |
||||
if (!start || !end) return |
||||
const datesCountOfStart = dateUtil.getDatesCountOfMonth(start[0], start[1]) |
||||
const datesCountOfEnd = dateUtil.getDatesCountOfMonth(end[0], end[1]) |
||||
if (start[2] > datesCountOfStart || start[2] < 1) { |
||||
logger.warn('enableArea() 开始日期错误,指定日期不在指定月份天数范围内') |
||||
return false |
||||
} else if (start[1] > 12 || start[1] < 1) { |
||||
logger.warn('enableArea() 开始日期错误,月份超出1-12月份') |
||||
return false |
||||
} else if (end[2] > datesCountOfEnd || end[2] < 1) { |
||||
logger.warn('enableArea() 截止日期错误,指定日期不在指定月份天数范围内') |
||||
return false |
||||
} else if (end[1] > 12 || end[1] < 1) { |
||||
logger.warn('enableArea() 截止日期错误,月份超出1-12月份') |
||||
return false |
||||
} else if (startTimestamp > endTimestamp) { |
||||
logger.warn('enableArea()参数最小日期大于了最大日期') |
||||
return false |
||||
} else { |
||||
return true |
||||
} |
||||
} |
||||
|
||||
function handleDisableMode(calendarConfig) { |
||||
const { disableMode } = calendarConfig |
||||
if (!disableMode) return {} |
||||
const disableBound = |
||||
dateUtil.getTimeStamp(disableMode.date) || dateUtil.todayTimestamp() |
||||
return { |
||||
disableBound, |
||||
disableType: disableMode.type |
||||
} |
||||
} |
||||
|
||||
function disabledByConfig(dateInfo, currentDate, calendarConfig) { |
||||
const date = { ...dateInfo } |
||||
const { disableType, disableBound } = handleDisableMode(calendarConfig) |
||||
if ( |
||||
(disableType === 'before' && disableBound && currentDate < disableBound) || |
||||
(disableType === 'after' && disableBound && currentDate > disableBound) |
||||
) { |
||||
date.disable = true |
||||
} else { |
||||
date.disable = false |
||||
} |
||||
return date |
||||
} |
||||
|
||||
export default () => { |
||||
return { |
||||
name: 'enable', |
||||
beforeRender(calendarData = {}, calendarConfig = {}) { |
||||
const { |
||||
dates, |
||||
enableArea, |
||||
enableDates, |
||||
disableDates, |
||||
renderCausedBy |
||||
} = calendarData |
||||
const _dates = [...dates].map(date => { |
||||
let item = { ...date } |
||||
const timeStr = dateUtil.toTimeStr(date) |
||||
const timestamp = +dateUtil.getTimeStamp(item) |
||||
if (renderCausedBy === 'enableDates') { |
||||
if (enableDates && enableDates.length) { |
||||
if (enableDates.includes(timeStr)) { |
||||
item.disable = false |
||||
} else { |
||||
item.disable = true |
||||
} |
||||
return item |
||||
} |
||||
} else if (renderCausedBy === 'enableArea') { |
||||
if (enableArea && enableArea.length) { |
||||
const [startTimestamp, endTimestamp] = enableArea || [] |
||||
const ifOutofArea = |
||||
+startTimestamp > timestamp || timestamp > +endTimestamp |
||||
item.disable = ifOutofArea |
||||
return item |
||||
} |
||||
} else if (renderCausedBy === 'disableDates') { |
||||
if (disableDates && disableDates.length) { |
||||
if (disableDates && disableDates.includes(timeStr)) { |
||||
item.disable = true |
||||
} else { |
||||
item.disable = false |
||||
} |
||||
return item |
||||
} |
||||
} |
||||
return disabledByConfig(item, timestamp, calendarConfig) |
||||
}) |
||||
|
||||
return { |
||||
calendarData: { |
||||
...calendarData, |
||||
dates: _dates |
||||
}, |
||||
calendarConfig |
||||
} |
||||
}, |
||||
methods(component) { |
||||
return { |
||||
enableArea: (dateArea = []) => { |
||||
if (dateArea.length === 2) { |
||||
const validate = isValiditeOfDateArea(dateArea) |
||||
if (validate) { |
||||
const existCalendarData = getCalendarData('calendar', component) |
||||
const { |
||||
startTimestamp, |
||||
endTimestamp |
||||
} = convertEnableAreaToTimestamp(dateArea) |
||||
|
||||
return renderCalendar.call(component, { |
||||
...existCalendarData, |
||||
renderCausedBy: 'enableArea', |
||||
enableArea: [startTimestamp, endTimestamp] |
||||
}) |
||||
} |
||||
} else { |
||||
return Promise.inject( |
||||
'enableArea()参数需为时间范围数组,形如:["2018-8-4" , "2018-8-24"]' |
||||
) |
||||
} |
||||
}, |
||||
enableDates: (toSet = []) => { |
||||
if (!toSet.length) return |
||||
const existCalendarData = getCalendarData('calendar', component) |
||||
const { enableDates = [] } = existCalendarData || {} |
||||
let toSetDates = toSet.map(item => { |
||||
if (typeof item === 'string') { |
||||
return dateUtil.transformDateRow2Dict(item) |
||||
} |
||||
return item |
||||
}) |
||||
if (enableDates.length) { |
||||
toSetDates = dateUtil.uniqueArrayByDate([ |
||||
...toSetDates, |
||||
...enableDates.map(d => dateUtil.transformDateRow2Dict(d)) |
||||
]) |
||||
} |
||||
return renderCalendar.call(component, { |
||||
...existCalendarData, |
||||
renderCausedBy: 'enableDates', |
||||
enableDates: toSetDates.map(date => { |
||||
if (typeof date !== 'string') { |
||||
return dateUtil.toTimeStr(date) |
||||
} |
||||
return date |
||||
}) |
||||
}) |
||||
}, |
||||
disableDates: toSet => { |
||||
const existCalendarData = getCalendarData('calendar', component) |
||||
const { disableDates = [], dates = [] } = existCalendarData || {} |
||||
let toSetDates = toSet.map(item => { |
||||
let date = { ...item } |
||||
if (typeof date === 'string') { |
||||
return dateUtil.transformDateRow2Dict(item) |
||||
} |
||||
return item |
||||
}) |
||||
if (disableDates && disableDates.length) { |
||||
toSetDates = dateUtil.uniqueArrayByDate([ |
||||
...toSetDates, |
||||
...disableDates.map(d => dateUtil.transformDateRow2Dict(d)) |
||||
]) |
||||
} |
||||
return renderCalendar.call(component, { |
||||
...existCalendarData, |
||||
renderCausedBy: 'disableDates', |
||||
dates, |
||||
disableDates: toSetDates.map(date => { |
||||
if (typeof date !== 'string') { |
||||
return dateUtil.toTimeStr(date) |
||||
} |
||||
return date |
||||
}) |
||||
}) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
export {}; |
@ -0,0 +1,59 @@
@@ -0,0 +1,59 @@
|
||||
import { dateUtil } from '../../utils/index' |
||||
import convertSolarLunar from './convertSolarLunar' |
||||
|
||||
function getDateRow2Dict(dateInfo) { |
||||
if (!dateInfo) return dateInfo |
||||
if (typeof dateInfo === 'string' && dateInfo.includes('-')) { |
||||
dateInfo = dateUtil.transformDateRow2Dict(dateInfo) |
||||
} |
||||
return dateInfo |
||||
} |
||||
|
||||
export default () => { |
||||
return { |
||||
name: 'convertSolarLunar', |
||||
beforeRender(calendarData = {}, calendarConfig = {}) { |
||||
let { dates = [], selectedDates = [] } = calendarData |
||||
if (calendarConfig.showLunar) { |
||||
dates = dates.map(dataInfo => { |
||||
const { year, month, date } = dataInfo |
||||
return { |
||||
...dataInfo, |
||||
lunar: convertSolarLunar.solar2lunar(year, month, date) |
||||
} |
||||
}) |
||||
selectedDates = selectedDates.map(dataInfo => { |
||||
const { year, month, date } = dataInfo |
||||
return { |
||||
...dataInfo, |
||||
lunar: convertSolarLunar.solar2lunar(year, month, date) |
||||
} |
||||
}) |
||||
} |
||||
return { |
||||
calendarData: { |
||||
...calendarData, |
||||
dates: dates, |
||||
selectedDates: selectedDates |
||||
}, |
||||
calendarConfig |
||||
} |
||||
}, |
||||
methods() { |
||||
return { |
||||
convertSolarLunar: dateInfo => { |
||||
dateInfo = getDateRow2Dict(dateInfo) |
||||
if (!dateInfo) return dateInfo |
||||
const { year, month, date } = dateInfo |
||||
return convertSolarLunar.solar2lunar(year, month, date) |
||||
}, |
||||
convertlLunar2Solar: (dateInfo, isLeapMonth) => { |
||||
dateInfo = getDateRow2Dict(dateInfo) |
||||
if (!dateInfo) return dateInfo |
||||
const { year, month, date } = dateInfo |
||||
return convertSolarLunar.lunar2solar(year, month, date, isLeapMonth) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,305 @@
@@ -0,0 +1,305 @@
|
||||
/** |
||||
* @Author: drfu* |
||||
* @Description: 时间区域选择 |
||||
* @Date: 2020-10-08 21:22:09* |
||||
* @Last Modified by: drfu |
||||
* @Last Modified time: 2020-10-11 13:56:32 |
||||
* */ |
||||
|
||||
import { renderCalendar } from '../render' |
||||
import { |
||||
logger, |
||||
dateUtil, |
||||
getCalendarConfig, |
||||
getCalendarData |
||||
} from '../utils/index' |
||||
|
||||
function pusheNextMonthDateArea( |
||||
dateInfo = {}, |
||||
startTimestamp, |
||||
endTimestamp, |
||||
selectedDates = [] |
||||
) { |
||||
let tempOfSelectedDate = [...selectedDates] |
||||
const dates = dateUtil.calcDates(dateInfo.year, dateInfo.month) |
||||
let datesLen = dates.length |
||||
for (let i = 0; i < datesLen; i++) { |
||||
const date = dates[i] |
||||
const timeStamp = dateUtil.getTimeStamp(date) |
||||
if (timeStamp <= endTimestamp && timeStamp >= startTimestamp) { |
||||
tempOfSelectedDate.push({ |
||||
...date, |
||||
choosed: true |
||||
}) |
||||
} |
||||
if (i === datesLen - 1 && timeStamp < endTimestamp) { |
||||
pusheNextMonthDateArea( |
||||
dateUtil.getNextMonthInfo(date), |
||||
startTimestamp, |
||||
endTimestamp, |
||||
tempOfSelectedDate |
||||
) |
||||
} |
||||
} |
||||
return tempOfSelectedDate |
||||
} |
||||
function pushPrevMonthDateArea( |
||||
dateInfo = {}, |
||||
startTimestamp, |
||||
endTimestamp, |
||||
selectedDates = [] |
||||
) { |
||||
let tempOfSelectedDate = [...selectedDates] |
||||
const dates = dateUtil.sortDatesByTime( |
||||
dateUtil.calcDates(dateInfo.year, dateInfo.month), |
||||
'desc' |
||||
) |
||||
let datesLen = dates.length |
||||
let firstDate = dateUtil.getTimeStamp(dates[0]) |
||||
for (let i = 0; i < datesLen; i++) { |
||||
const date = dates[i] |
||||
const timeStamp = dateUtil.getTimeStamp(date) |
||||
if (timeStamp >= startTimestamp && timeStamp <= endTimestamp) { |
||||
tempOfSelectedDate.push({ |
||||
...date, |
||||
choosed: true |
||||
}) |
||||
} |
||||
if (i === datesLen - 1 && firstDate > startTimestamp) { |
||||
pushPrevMonthDateArea( |
||||
dateUtil.getPrevMonthInfo(date), |
||||
startTimestamp, |
||||
endTimestamp, |
||||
tempOfSelectedDate |
||||
) |
||||
} |
||||
} |
||||
return tempOfSelectedDate |
||||
} |
||||
/** |
||||
* 当设置日期区域非当前时保存其它月份的日期至已选日期数组 |
||||
* @param {object} info |
||||
*/ |
||||
function calcDateWhenNotInOneMonth(info) { |
||||
const { firstDate, lastDate, startTimestamp, endTimestamp } = info |
||||
let { selectedDate } = info |
||||
if (dateUtil.getTimeStamp(firstDate) > startTimestamp) { |
||||
selectedDate = pushPrevMonthDateArea( |
||||
dateUtil.getPrevMonthInfo(firstDate), |
||||
startTimestamp, |
||||
endTimestamp, |
||||
selectedDate |
||||
) |
||||
} |
||||
if (dateUtil.getTimeStamp(lastDate) < endTimestamp) { |
||||
selectedDate = pusheNextMonthDateArea( |
||||
dateUtil.getNextMonthInfo(lastDate), |
||||
startTimestamp, |
||||
endTimestamp, |
||||
selectedDate |
||||
) |
||||
} |
||||
return [...selectedDate] |
||||
} |
||||
|
||||
/** |
||||
* 指定日期区域转时间戳 |
||||
* @param {array} timearea 时间区域 |
||||
*/ |
||||
export function convertTimeRangeToTimestamp(timearea = []) { |
||||
const start = timearea[0].split('-') |
||||
const end = timearea[1].split('-') |
||||
if (start.length !== 3 || end.length !== 3) { |
||||
logger.warn('enableArea() 参数格式为: ["2018-2-1", "2018-3-1"]') |
||||
return {} |
||||
} |
||||
const startTimestamp = dateUtil |
||||
.newDate(start[0], start[1], start[2]) |
||||
.getTime() |
||||
const endTimestamp = dateUtil.newDate(end[0], end[1], end[2]).getTime() |
||||
return { |
||||
start, |
||||
end, |
||||
startTimestamp, |
||||
endTimestamp |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 校验时间区域是否合法 |
||||
* @param {array} dateArea 时间区域 |
||||
*/ |
||||
function validateTimeRange(dateArea) { |
||||
const { |
||||
start, |
||||
end, |
||||
startTimestamp, |
||||
endTimestamp |
||||
} = convertTimeRangeToTimestamp(dateArea) |
||||
if (!start || !end) return |
||||
const startMonthDays = dateUtil.getDatesCountOfMonth(start[0], start[1]) |
||||
const endMonthDays = dateUtil.getDatesCountOfMonth(end[0], end[1]) |
||||
if (start[2] > startMonthDays || start[2] < 1) { |
||||
logger.warn('enableArea() 开始日期错误,指定日期不在当前月份天数范围内') |
||||
return false |
||||
} else if (start[1] > 12 || start[1] < 1) { |
||||
logger.warn('enableArea() 开始日期错误,月份超出1-12月份') |
||||
return false |
||||
} else if (end[2] > endMonthDays || end[2] < 1) { |
||||
logger.warn('enableArea() 截止日期错误,指定日期不在当前月份天数范围内') |
||||
return false |
||||
} else if (end[1] > 12 || end[1] < 1) { |
||||
logger.warn('enableArea() 截止日期错误,月份超出1-12月份') |
||||
return false |
||||
} else if (startTimestamp > endTimestamp) { |
||||
logger.warn('enableArea()参数最小日期大于了最大日期') |
||||
return false |
||||
} else { |
||||
return true |
||||
} |
||||
} |
||||
|
||||
export default () => { |
||||
return { |
||||
name: 'timeRange', |
||||
beforeRender(calendarData = {}, calendarConfig = {}) { |
||||
const { |
||||
chooseAreaTimestamp = [], |
||||
dates = [], |
||||
selectedDates = [] |
||||
} = calendarData |
||||
let __dates = dates |
||||
let __selectedDates = selectedDates |
||||
const [startDateTimestamp, endDateTimestamp] = chooseAreaTimestamp |
||||
if (chooseAreaTimestamp.length === 2) { |
||||
__selectedDates = [] |
||||
__dates = dates.map(d => { |
||||
const date = { ...d } |
||||
const dateTimeStamp = dateUtil.getTimeStamp(date) |
||||
if ( |
||||
dateTimeStamp >= startDateTimestamp && |
||||
endDateTimestamp >= dateTimeStamp |
||||
) { |
||||
date.choosed = true |
||||
__selectedDates.push(date) |
||||
} else { |
||||
date.choosed = false |
||||
__selectedDates = __selectedDates.filter( |
||||
item => dateUtil.getTimeStamp(item) !== dateTimeStamp |
||||
) |
||||
} |
||||
return date |
||||
}) |
||||
const monthOfStartDate = new Date(startDateTimestamp).getMonth() |
||||
const monthOfEndDate = new Date(endDateTimestamp).getMonth() |
||||
if (monthOfStartDate !== monthOfEndDate) { |
||||
__selectedDates = calcDateWhenNotInOneMonth({ |
||||
firstDate: __dates[0], |
||||
lastDate: __dates[__dates.length - 1], |
||||
startTimestamp: startDateTimestamp, |
||||
endTimestamp: endDateTimestamp, |
||||
selectedDate: __selectedDates |
||||
}) |
||||
} |
||||
} |
||||
return { |
||||
calendarData: { |
||||
...calendarData, |
||||
dates: __dates, |
||||
selectedDates: dateUtil.sortDatesByTime( |
||||
dateUtil.uniqueArrayByDate(__selectedDates) |
||||
) |
||||
}, |
||||
calendarConfig |
||||
} |
||||
}, |
||||
onTapDate(tapedDate, calendarData = {}, calendarConfig = {}) { |
||||
if (!calendarConfig.chooseAreaMode) { |
||||
return { |
||||
calendarData, |
||||
calendarConfig |
||||
} |
||||
} |
||||
let { |
||||
tempChooseAreaTimestamp = [], |
||||
chooseAreaTimestamp: existChooseAreaTimestamp = [], |
||||
selectedDates = [], |
||||
dates = [] |
||||
} = calendarData |
||||
const timestamp = dateUtil.getTimeStamp(tapedDate) |
||||
let __dates = [...dates] |
||||
let __selectedDates = [...selectedDates] |
||||
if ( |
||||
tempChooseAreaTimestamp.length === 2 || |
||||
existChooseAreaTimestamp.length === 2 |
||||
) { |
||||
tempChooseAreaTimestamp = [tapedDate] |
||||
__selectedDates = [] |
||||
__dates.forEach(d => (d.choosed = false)) |
||||
} else if (tempChooseAreaTimestamp.length === 1) { |
||||
const preChoosedDate = tempChooseAreaTimestamp[0] |
||||
const preTimestamp = dateUtil.getTimeStamp(preChoosedDate) |
||||
if (preTimestamp <= timestamp) { |
||||
tempChooseAreaTimestamp.push(tapedDate) |
||||
} else if (preTimestamp > timestamp) { |
||||
tempChooseAreaTimestamp.unshift(tapedDate) |
||||
} |
||||
} else { |
||||
tempChooseAreaTimestamp = [tapedDate] |
||||
} |
||||
let chooseAreaTimestamp = [] |
||||
if (tempChooseAreaTimestamp.length === 2) { |
||||
const [startDate, endDate] = tempChooseAreaTimestamp |
||||
const startDateTimestamp = dateUtil.getTimeStamp(startDate) |
||||
const endDateTimestamp = dateUtil.getTimeStamp(endDate) |
||||
chooseAreaTimestamp = [startDateTimestamp, endDateTimestamp] |
||||
} |
||||
return { |
||||
calendarData: { |
||||
...calendarData, |
||||
chooseAreaTimestamp, |
||||
tempChooseAreaTimestamp, |
||||
dates: __dates, |
||||
selectedDates: __selectedDates |
||||
}, |
||||
calendarConfig: { |
||||
...calendarConfig, |
||||
multi: true |
||||
} |
||||
} |
||||
}, |
||||
methods(component) { |
||||
return { |
||||
/** |
||||
* 设置连续日期选择区域 |
||||
* @param {array} dateArea 区域开始结束日期数组 |
||||
*/ |
||||
chooseDateArea: (dateArea = []) => { |
||||
if (dateArea.length === 1) { |
||||
dateArea = dateArea.concat(dateArea) |
||||
} |
||||
if (dateArea.length !== 2) return |
||||
const isRight = validateTimeRange(dateArea) |
||||
if (!isRight) return |
||||
const config = getCalendarConfig(component) || {} |
||||
const { startTimestamp, endTimestamp } = convertTimeRangeToTimestamp( |
||||
dateArea |
||||
) |
||||
const existCalendarData = getCalendarData('calendar', component) |
||||
return renderCalendar.call( |
||||
component, |
||||
{ |
||||
...existCalendarData, |
||||
chooseAreaTimestamp: [startTimestamp, endTimestamp] |
||||
}, |
||||
{ |
||||
...config, |
||||
multi: true, |
||||
chooseAreaMode: true |
||||
} |
||||
) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
export {}; |
@ -0,0 +1,135 @@
@@ -0,0 +1,135 @@
|
||||
/** |
||||
* @Author: drfu* |
||||
* @Description: 代办事项 |
||||
* @Date: 2020-10-08 21:22:09* |
||||
* @Last Modified by: drfu |
||||
* @Last Modified time: 2020-10-11 14:23:02 |
||||
* */ |
||||
|
||||
import { getCalendarData, dateUtil } from '../utils/index' |
||||
import { renderCalendar } from '../render' |
||||
|
||||
function updateDatePropertyOfTodoLabel(todos, dates, showLabelAlways) { |
||||
const datesInfo = [...dates] |
||||
for (let todo of todos) { |
||||
let targetIdx = datesInfo.findIndex( |
||||
item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(todo) |
||||
) |
||||
let target = datesInfo[targetIdx] |
||||
if (!target) continue |
||||
if (showLabelAlways) { |
||||
target.showTodoLabel = true |
||||
} else { |
||||
target.showTodoLabel = !target.choosed |
||||
} |
||||
if (target.showTodoLabel) { |
||||
target.todoText = todo.todoText |
||||
} |
||||
target.color = todo.color |
||||
} |
||||
return datesInfo |
||||
} |
||||
|
||||
export default () => { |
||||
return { |
||||
name: 'todo', |
||||
beforeRender(calendarData = {}, calendarConfig = {}, component) { |
||||
const { todos = [], dates = [], showLabelAlways } = calendarData |
||||
const dateWithTodoInfo = updateDatePropertyOfTodoLabel( |
||||
todos, |
||||
dates, |
||||
showLabelAlways |
||||
) |
||||
return { |
||||
calendarData: { |
||||
...calendarData, |
||||
dates: dateWithTodoInfo |
||||
}, |
||||
calendarConfig |
||||
} |
||||
}, |
||||
methods(component) { |
||||
return { |
||||
setTodos: (options = {}) => { |
||||
const calendar = getCalendarData('calendar', component) |
||||
if (!calendar || !calendar.dates) { |
||||
return Promise.reject('请等待日历初始化完成后再调用该方法') |
||||
} |
||||
const { |
||||
circle, |
||||
dotColor = '', |
||||
pos = 'bottom', |
||||
showLabelAlways, |
||||
dates: todoDates = [] |
||||
} = options |
||||
const { todos = [] } = calendar |
||||
const tranformStr2NumOfTodo = todoDates.map(date => |
||||
dateUtil.tranformStr2NumOfDate(date) |
||||
) |
||||
const calendarData = { |
||||
dates: calendar.dates, |
||||
todos: dateUtil.uniqueArrayByDate( |
||||
todos.concat(tranformStr2NumOfTodo) |
||||
) |
||||
} |
||||
if (!circle) { |
||||
calendarData.todoLabelPos = pos |
||||
calendarData.todoLabelColor = dotColor |
||||
} |
||||
calendarData.todoLabelCircle = circle || false |
||||
calendarData.showLabelAlways = showLabelAlways || false |
||||
const existCalendarData = getCalendarData('calendar', component) |
||||
return renderCalendar.call(component, { |
||||
...existCalendarData, |
||||
...calendarData |
||||
}) |
||||
}, |
||||
deleteTodos(todos = []) { |
||||
if (!(todos instanceof Array) || !todos.length) |
||||
return Promise.reject('deleteTodos()应为入参为非空数组') |
||||
const existCalendarData = getCalendarData('calendar', component) |
||||
const allTodos = existCalendarData.todos || [] |
||||
const toDeleteTodos = todos.map(item => dateUtil.toTimeStr(item)) |
||||
const remainTodos = allTodos.filter( |
||||
item => !toDeleteTodos.includes(dateUtil.toTimeStr(item)) |
||||
) |
||||
const { dates, curYear, curMonth } = existCalendarData |
||||
const _dates = [...dates] |
||||
const currentMonthTodos = dateUtil.filterDatesByYM( |
||||
{ |
||||
year: curYear, |
||||
month: curMonth |
||||
}, |
||||
remainTodos |
||||
) |
||||
_dates.forEach(item => { |
||||
item.showTodoLabel = false |
||||
}) |
||||
currentMonthTodos.forEach(item => { |
||||
_dates[item.date - 1].showTodoLabel = !_dates[item.date - 1].choosed |
||||
}) |
||||
return renderCalendar.call(component, { |
||||
...existCalendarData, |
||||
dates: _dates, |
||||
todos: remainTodos |
||||
}) |
||||
}, |
||||
clearTodos() { |
||||
const existCalendarData = getCalendarData('calendar', component) |
||||
const _dates = [...existCalendarData.dates] |
||||
_dates.forEach(item => { |
||||
item.showTodoLabel = false |
||||
}) |
||||
return renderCalendar.call(component, { |
||||
...existCalendarData, |
||||
dates: _dates, |
||||
todos: [] |
||||
}) |
||||
}, |
||||
getTodos() { |
||||
return getCalendarData('calendar.todos', component) || [] |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,432 @@
@@ -0,0 +1,432 @@
|
||||
/** |
||||
* @Author: drfu* |
||||
* @Description: 周视图 |
||||
* @Date: 2020-10-08 21:22:09* |
||||
* @Last Modified by: drfu |
||||
* @Last Modified time: 2020-10-12 14:39:45 |
||||
* */ |
||||
|
||||
import { renderCalendar } from '../render' |
||||
import { |
||||
getCalendarConfig, |
||||
getCalendarData, |
||||
logger, |
||||
dateUtil |
||||
} from '../utils/index' |
||||
import { calcJumpData } from '../core' |
||||
|
||||
/** |
||||
* 当月第一周所有日期 |
||||
*/ |
||||
function firstWeekInMonth( |
||||
target = {}, |
||||
calendarDates = [], |
||||
calendarConfig = {} |
||||
) { |
||||
const { firstDayOfWeek } = calendarConfig |
||||
const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon' |
||||
const { year, month } = target |
||||
let firstDay = dateUtil.getDayOfWeek(year, month, 1) |
||||
if (firstDayOfWeekIsMon && firstDay === 0) { |
||||
firstDay = 7 |
||||
} |
||||
const [, end] = [0, 7 - firstDay] |
||||
return calendarDates.slice(0, firstDayOfWeekIsMon ? end + 1 : end) |
||||
} |
||||
|
||||
/** |
||||
* 当月最后一周所有日期 |
||||
*/ |
||||
function lastWeekInMonth(target = {}, calendarDates = [], calendarConfig = {}) { |
||||
const { firstDayOfWeek } = calendarConfig |
||||
const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon' |
||||
const { year, month } = target |
||||
const lastDay = dateUtil.getDatesCountOfMonth(year, month) |
||||
let lastDayWeek = dateUtil.getDayOfWeek(year, month, lastDay) |
||||
if (firstDayOfWeekIsMon && lastDayWeek === 0) { |
||||
lastDayWeek = 7 |
||||
} |
||||
const [start, end] = [lastDay - lastDayWeek, lastDay] |
||||
return calendarDates.slice(firstDayOfWeekIsMon ? start : start - 1, end) |
||||
} |
||||
|
||||
/** |
||||
* 判断目标日期是否在某些指定日历内 |
||||
*/ |
||||
function dateIsInDatesRange(target, dates) { |
||||
if (!target || !dates || !dates.length) return false |
||||
const targetDateStr = dateUtil.toTimeStr(target) |
||||
let rst = false |
||||
for (let date of dates) { |
||||
const dateStr = dateUtil.toTimeStr(date) |
||||
if (dateStr === targetDateStr) { |
||||
rst = true |
||||
return rst |
||||
} |
||||
rst = false |
||||
} |
||||
return rst |
||||
} |
||||
|
||||
function getDatesWhenTargetInFirstWeek(target, firstWeekDates) { |
||||
const { year, month } = target |
||||
const prevMonthInfo = dateUtil.getPrevMonthInfo({ year, month }) |
||||
let lastMonthDatesCount = dateUtil.getDatesCountOfMonth( |
||||
prevMonthInfo.year, |
||||
prevMonthInfo.month |
||||
) |
||||
let dates = firstWeekDates |
||||
let firstWeekCount = firstWeekDates.length |
||||
for (let i = 0; i < 7 - firstWeekCount; i++) { |
||||
const week = dateUtil.getDayOfWeek(+year, +month, lastMonthDatesCount) |
||||
dates.unshift({ |
||||
year: prevMonthInfo.year, |
||||
month: prevMonthInfo.month, |
||||
date: lastMonthDatesCount, |
||||
week |
||||
}) |
||||
lastMonthDatesCount -= 1 |
||||
} |
||||
return dates |
||||
} |
||||
|
||||
function getDatesWhenTargetInLastWeek(target, lastWeekDates) { |
||||
const { year, month } = target |
||||
const prevMonthInfo = dateUtil.getNextMonthInfo({ year, month }) |
||||
let dates = lastWeekDates |
||||
let lastWeekCount = lastWeekDates.length |
||||
for (let i = 0; i < 7 - lastWeekCount; i++) { |
||||
const week = dateUtil.getDayOfWeek(+year, +month, i + 1) |
||||
dates.push({ |
||||
year: prevMonthInfo.year, |
||||
month: prevMonthInfo.month, |
||||
date: i + 1, |
||||
week |
||||
}) |
||||
} |
||||
return dates |
||||
} |
||||
|
||||
function getDates(target, calendarDates = [], calendarConfig = {}) { |
||||
const { year, month, date } = target |
||||
const targetDay = dateUtil.getDayOfWeek(year, month, date) |
||||
const { firstDayOfWeek } = calendarConfig |
||||
const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon' |
||||
if (firstDayOfWeekIsMon) { |
||||
const startIdx = date - (targetDay || 7) |
||||
return calendarDates.splice(startIdx, 7) |
||||
} else { |
||||
const startIdx = date - targetDay - 1 |
||||
return calendarDates.splice(startIdx, 7) |
||||
} |
||||
} |
||||
|
||||
function getTargetWeekDates(target, calendarConfig) { |
||||
if (!target) return |
||||
const { year, month } = target |
||||
const calendarDates = dateUtil.calcDates(year, month) |
||||
const firstWeekDates = firstWeekInMonth(target, calendarDates, calendarConfig) |
||||
const lastWeekDates = lastWeekInMonth(target, calendarDates, calendarConfig) |
||||
if (dateIsInDatesRange(target, firstWeekDates)) { |
||||
return getDatesWhenTargetInFirstWeek(target, firstWeekDates) |
||||
} else if (dateIsInDatesRange(target, lastWeekDates)) { |
||||
return getDatesWhenTargetInLastWeek(target, lastWeekDates) |
||||
} else { |
||||
return getDates(target, calendarDates, calendarConfig) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 计算周视图下当前这一周最后一天 |
||||
*/ |
||||
function calculateLastDateOfCurrentWeek(calendarData = {}) { |
||||
const { dates = [] } = calendarData |
||||
return dates[dates.length - 1] |
||||
} |
||||
/** |
||||
* 计算周视图下当前这一周第一天 |
||||
*/ |
||||
function calculateFirstDateOfCurrentWeek(calendarData = {}) { |
||||
const { dates } = calendarData |
||||
return dates[0] |
||||
} |
||||
|
||||
/** |
||||
* 计算下一周的日期 |
||||
*/ |
||||
function calculateNextWeekDates(calendarData = {}) { |
||||
let { curYear, curMonth } = calendarData |
||||
let calendarDates = [] |
||||
let lastDateInThisWeek = calculateLastDateOfCurrentWeek(calendarData) |
||||
const { year: LYear, month: LMonth } = lastDateInThisWeek |
||||
if (curYear !== LYear || curMonth !== LMonth) { |
||||
calendarDates = dateUtil.calcDates(LYear, LMonth) |
||||
curYear = LYear |
||||
curMonth = LMonth |
||||
} else { |
||||
calendarDates = dateUtil.calcDates(curYear, curMonth) |
||||
} |
||||
const lastDateInThisMonth = dateUtil.getDatesCountOfMonth(curYear, curMonth) |
||||
const count = lastDateInThisMonth - lastDateInThisWeek.date |
||||
const lastDateIdx = calendarDates.findIndex( |
||||
date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(lastDateInThisWeek) |
||||
) |
||||
const startIdx = lastDateIdx + 1 |
||||
if (count >= 7) { |
||||
return { |
||||
dates: calendarDates.splice(startIdx, 7), |
||||
year: curYear, |
||||
month: curMonth |
||||
} |
||||
} else { |
||||
const nextMonth = dateUtil.getNextMonthInfo({ |
||||
year: curYear, |
||||
month: curMonth |
||||
}) |
||||
const { year, month } = nextMonth || {} |
||||
const calendarDatesOfNextMonth = dateUtil.calcDates(year, month) |
||||
const remainDatesOfThisMonth = calendarDates.splice(startIdx) |
||||
const patchDatesOfNextMonth = calendarDatesOfNextMonth.splice( |
||||
0, |
||||
7 - remainDatesOfThisMonth.length |
||||
) |
||||
return { |
||||
dates: [...remainDatesOfThisMonth, ...patchDatesOfNextMonth], |
||||
...nextMonth |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 计算上一周的日期 |
||||
*/ |
||||
function calculatePrevWeekDates(calendarData = {}) { |
||||
let { curYear, curMonth } = calendarData |
||||
let firstDateInThisWeek = calculateFirstDateOfCurrentWeek(calendarData) |
||||
let calendarDates = [] |
||||
const { year: FYear, month: FMonth } = firstDateInThisWeek |
||||
if (curYear !== FYear || curMonth !== FMonth) { |
||||
calendarDates = dateUtil.calcDates(FYear, FMonth) |
||||
curYear = FYear |
||||
curMonth = FMonth |
||||
} else { |
||||
calendarDates = dateUtil.calcDates(curYear, curMonth) |
||||
} |
||||
const firstDateIdx = calendarDates.findIndex( |
||||
date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(firstDateInThisWeek) |
||||
) |
||||
if (firstDateIdx - 7 >= 0) { |
||||
const startIdx = firstDateIdx - 7 |
||||
return { |
||||
dates: calendarDates.splice(startIdx, 7), |
||||
year: curYear, |
||||
month: curMonth |
||||
} |
||||
} else { |
||||
const prevMonth = dateUtil.getPrevMonthInfo({ |
||||
year: curYear, |
||||
month: curMonth |
||||
}) |
||||
const { year, month } = prevMonth || {} |
||||
const calendarDatesOfPrevMonth = dateUtil.calcDates(year, month) |
||||
const remainDatesOfThisMonth = calendarDates.splice( |
||||
0, |
||||
firstDateInThisWeek.date - 1 |
||||
) |
||||
const patchDatesOfPrevMonth = calendarDatesOfPrevMonth.splice( |
||||
-(7 - remainDatesOfThisMonth.length) |
||||
) |
||||
return { |
||||
dates: [...patchDatesOfPrevMonth, ...remainDatesOfThisMonth], |
||||
...prevMonth |
||||
} |
||||
} |
||||
} |
||||
|
||||
export default () => { |
||||
return { |
||||
name: 'week', |
||||
beforeRender(calendarData = {}, calendarConfig = {}, component) { |
||||
const { initializedWeekMode, selectedDates } = calendarData |
||||
if (calendarConfig.weekMode && !initializedWeekMode) { |
||||
const { defaultDate } = calendarConfig |
||||
const target = |
||||
(selectedDates && selectedDates[0]) || |
||||
(defaultDate && dateUtil.transformDateRow2Dict(defaultDate)) || |
||||
dateUtil.todayFMD() |
||||
const waitRenderData = this.methods( |
||||
component |
||||
).__calcDatesWhenSwitchView('week', target) |
||||
const { data, config } = waitRenderData || {} |
||||
const setSelectDates = this.methods( |
||||
component |
||||
).__selectTargetDateWhenJump(target, data.dates, config) |
||||
return { |
||||
calendarData: { |
||||
...data, |
||||
...setSelectDates, |
||||
weeksCh: dateUtil.getWeekHeader(calendarConfig.firstDayOfWeek), |
||||
initializedWeekMode: true |
||||
}, |
||||
calendarConfig |
||||
} |
||||
} |
||||
return { |
||||
calendarData, |
||||
calendarConfig |
||||
} |
||||
}, |
||||
onSwitchCalendar(target = {}, calendarData = {}, component) { |
||||
const { direction } = target |
||||
const { curYear, curMonth } = calendarData |
||||
const calendarConfig = getCalendarConfig(component) |
||||
let waitRenderData = {} |
||||
if (calendarConfig.weekMode) { |
||||
if (direction === 'left') { |
||||
waitRenderData = calculateNextWeekDates(calendarData) |
||||
} else { |
||||
waitRenderData = calculatePrevWeekDates(calendarData) |
||||
} |
||||
const { dates, year, month } = waitRenderData |
||||
return { |
||||
...calendarData, |
||||
dates, |
||||
curYear: year || curYear, |
||||
curMonth: month || curMonth |
||||
} |
||||
} |
||||
return calendarData |
||||
}, |
||||
methods(component) { |
||||
return { |
||||
__selectTargetDateWhenJump: (target = {}, dates = [], config = {}) => { |
||||
let selectedDate = target |
||||
const weekDates = dates.map((date, idx) => { |
||||
const tmp = { ...date } |
||||
tmp.id = idx |
||||
const isTarget = |
||||
dateUtil.toTimeStr(target) === dateUtil.toTimeStr(tmp) |
||||
if (isTarget && !target.choosed && config.autoChoosedWhenJump) { |
||||
tmp.choosed = true |
||||
selectedDate = tmp |
||||
} |
||||
return tmp |
||||
}) |
||||
return { |
||||
dates: weekDates, |
||||
selectedDates: [selectedDate] |
||||
} |
||||
}, |
||||
__calcDatesForWeekMode(target, config = {}, calendarData = {}) { |
||||
const { year, month } = target || {} |
||||
const weekDates = getTargetWeekDates(target, config) |
||||
weekDates.forEach((date, idx) => (date.id = idx)) |
||||
return { |
||||
data: { |
||||
...calendarData, |
||||
prevMonthGrids: null, |
||||
nextMonthGrids: null, |
||||
dates: weekDates, |
||||
curYear: year, |
||||
curMonth: month |
||||
}, |
||||
config: { |
||||
...config, |
||||
weekMode: true |
||||
} |
||||
} |
||||
}, |
||||
__calcDatesForMonthMode(target, config = {}, calendarData = {}) { |
||||
const { year, month } = target || {} |
||||
const waitRenderData = calcJumpData({ |
||||
dateInfo: target, |
||||
config |
||||
}) |
||||
return { |
||||
data: { |
||||
...calendarData, |
||||
...waitRenderData, |
||||
curYear: year, |
||||
curMonth: month |
||||
}, |
||||
config: { |
||||
...config, |
||||
weekMode: false |
||||
} |
||||
} |
||||
}, |
||||
/** |
||||
* 周、月视图切换 |
||||
* @param {string} view 视图 [week, month] |
||||
* @param {object} target |
||||
*/ |
||||
__calcDatesWhenSwitchView: (view, target) => { |
||||
const calendarConfig = getCalendarConfig(component) |
||||
if (calendarConfig.multi) |
||||
return logger.warn('多选模式不能切换周月视图') |
||||
const existCalendarData = getCalendarData('calendar', component) || {} |
||||
const { |
||||
selectedDates = [], |
||||
dates = [], |
||||
curYear, |
||||
curMonth |
||||
} = existCalendarData |
||||
const currentMonthSelected = selectedDates.filter( |
||||
item => curYear === +item.year || curMonth === +item.month |
||||
) |
||||
let jumpTarget = {} |
||||
if (target) { |
||||
jumpTarget = target |
||||
} else { |
||||
if (currentMonthSelected.length) { |
||||
jumpTarget = currentMonthSelected.pop() |
||||
} else { |
||||
jumpTarget = dates[0] |
||||
} |
||||
} |
||||
if (view === 'week') { |
||||
return this.methods(component).__calcDatesForWeekMode( |
||||
jumpTarget, |
||||
calendarConfig, |
||||
existCalendarData |
||||
) |
||||
} else { |
||||
return this.methods(component).__calcDatesForMonthMode( |
||||
jumpTarget, |
||||
calendarConfig, |
||||
existCalendarData |
||||
) |
||||
} |
||||
}, |
||||
weekModeJump: dateInfo => { |
||||
const target = dateInfo || dateUtil.todayFMD() |
||||
const existCalendarData = getCalendarData('calendar', component) || {} |
||||
const waitRenderData = this.methods( |
||||
component |
||||
).__calcDatesWhenSwitchView('week', target) |
||||
const { data, config } = waitRenderData || {} |
||||
const setSelectDates = this.methods( |
||||
component |
||||
).__selectTargetDateWhenJump(target, data.dates, config) |
||||
return renderCalendar.call( |
||||
component, |
||||
{ |
||||
...existCalendarData, |
||||
...data, |
||||
...setSelectDates |
||||
}, |
||||
config |
||||
) |
||||
}, |
||||
switchView: (view, target) => { |
||||
const waitRenderData = this.methods( |
||||
component |
||||
).__calcDatesWhenSwitchView(view, target) |
||||
const { data, config } = waitRenderData || {} |
||||
if (!data) return logger.warn('当前状态不能切换为周视图') |
||||
return renderCalendar.call(component, data, config) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
import plugins from "./plugins/index"; |
||||
import { getCalendarConfig } from "./utils/index"; |
||||
|
||||
/** |
||||
* 渲染日历 |
||||
*/ |
||||
export function renderCalendar(calendarData, calendarConfig) { |
||||
return new Promise((resolve) => { |
||||
const Component = this; |
||||
if (Component.firstRender === void 0) { |
||||
Component.firstRender = true; |
||||
} else { |
||||
Component.firstRender = false; |
||||
} |
||||
const exitData = Component.data.calendar || {}; |
||||
for (let plugin of plugins.installed) { |
||||
const [, p] = plugin; |
||||
if (typeof p.beforeRender === "function") { |
||||
const { calendarData: newData, calendarConfig: newConfig } = |
||||
p.beforeRender( |
||||
{ ...exitData, ...calendarData }, |
||||
calendarConfig || getCalendarConfig(Component), |
||||
Component |
||||
); |
||||
calendarData = newData; |
||||
calendarConfig = newConfig; |
||||
} |
||||
} |
||||
|
||||
Component.setData( |
||||
{ |
||||
config: calendarConfig, |
||||
calendar: calendarData, |
||||
}, |
||||
() => { |
||||
const rst = { |
||||
calendar: calendarData, |
||||
config: calendarConfig, |
||||
firstRender: Component.firstRender, |
||||
}; |
||||
resolve(rst); |
||||
if (Component.firstRender) { |
||||
Component.triggerEvent("afterCalendarRender", rst); |
||||
Component.firstRender = false; |
||||
} |
||||
} |
||||
); |
||||
}); |
||||
} |
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
@font-face { |
||||
font-family: 'iconfont'; |
||||
src: url(data:font/truetype;charset=utf-8;base64,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) format('truetype'); |
||||
font-weight: normal; |
||||
font-style: normal; |
||||
} |
||||
|
||||
.iconfont { |
||||
font-family: "iconfont" !important; |
||||
font-size: 16px; |
||||
font-style: normal; |
||||
-webkit-font-smoothing: antialiased; |
||||
} |
||||
|
||||
.icon-right::before { |
||||
content: "\e7eb"; |
||||
} |
||||
|
||||
.icon-left::before { |
||||
content: "\e7ec"; |
||||
} |
||||
|
||||
.icon-doubleleft::before { |
||||
content: "\e7ed"; |
||||
} |
||||
|
||||
.icon-doubleright::before { |
||||
content: "\e7ee"; |
||||
} |
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
|
||||
/* 日历主要颜色相关样式 */ |
||||
|
||||
.default_color, |
||||
.default_weekend-color, |
||||
.default_handle-color, |
||||
.default_week-color { |
||||
color: #ff629a; |
||||
} |
||||
|
||||
.default_today { |
||||
color: #fff; |
||||
background-color: #874fb4; |
||||
} |
||||
|
||||
.default_choosed { |
||||
color: #fff; |
||||
background-color: #ff629a; |
||||
} |
||||
|
||||
.default_date-disable { |
||||
color: #c7c7c7; |
||||
} |
||||
|
||||
.default_choosed.default_date-disable { |
||||
color: #e2e2e2; |
||||
background-color: #c2afb6; |
||||
} |
||||
|
||||
.default_prev-month-date, |
||||
.default_next-month-date { |
||||
color: #e2e2e2; |
||||
} |
||||
|
||||
.default_normal-date { |
||||
color: #88d2ac; |
||||
} |
||||
|
||||
.default_todo-circle { |
||||
border-color: #88d2ac; |
||||
} |
||||
|
||||
.default_todo-dot { |
||||
background-color: #e54d42; |
||||
} |
||||
|
||||
.default_date-desc { |
||||
color: #c2c2c2; |
||||
} |
||||
|
||||
.default_date-desc-lunar { |
||||
color: #e54d42; |
||||
} |
||||
|
||||
.default_date-desc-disable { |
||||
color: #e2e2e2; |
||||
} |
||||
|
||||
.default_festival { |
||||
color: #c2c2c2; |
||||
} |
@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
|
||||
.elegant_color, |
||||
.elegant_weekend-color, |
||||
.elegant_handle-color, |
||||
.elegant_week-color { |
||||
color: #333; |
||||
} |
||||
|
||||
.elegant_today { |
||||
color: #000; |
||||
background-color: #e1e7f5; |
||||
} |
||||
|
||||
.elegant_choosed { |
||||
color: #000; |
||||
background-color: #e2e2e2; |
||||
} |
||||
|
||||
.elegant_date-disable { |
||||
color: #c7c7c7; |
||||
} |
||||
|
||||
.elegant_choosed.elegant_date-disable { |
||||
color: #999; |
||||
background-color: #ebebeb; |
||||
} |
||||
|
||||
.elegant_prev-month-date, |
||||
.elegant_next-month-date { |
||||
color: #e2e2e2; |
||||
} |
||||
|
||||
.elegant_normal-date { |
||||
color: #777; |
||||
} |
||||
|
||||
.elegant_todo-circle { |
||||
border-color: #161035; |
||||
} |
||||
|
||||
.elegant_todo-dot { |
||||
background-color: #161035; |
||||
} |
||||
|
||||
.elegant_date-desc { |
||||
color: #c2c2c2; |
||||
} |
||||
|
||||
.elegant_date-desc-lunar { |
||||
color: #161035; |
||||
} |
||||
|
||||
.elegant_date-desc-disable { |
||||
color: #e2e2e2; |
||||
} |
||||
|
||||
.elegant_festival { |
||||
color: #c2c2c2; |
||||
} |
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
/* 日历主要颜色相关样式 */ |
||||
|
||||
.geneb_color, |
||||
.geneb_weekend-color, |
||||
.geneb_handle-color, |
||||
.geneb_week-color { |
||||
color: rgba(51, 51, 51, 1); |
||||
} |
||||
|
||||
.geneb_choosed { |
||||
color: rgba(51, 51, 51, 1); |
||||
background-color: rgba(189, 189, 189, 0.3); |
||||
} |
||||
|
||||
.geneb_today { |
||||
color: rgba(246, 74, 58, 1); |
||||
background-color: rgba(255, 237, 235, 1); |
||||
} |
||||
|
||||
.geneb_date-disable { |
||||
color: #c7c7c7; |
||||
} |
||||
|
||||
.geneb_choosed.geneb_date-disable { |
||||
color: #e2e2e2; |
||||
background-color: #c2afb6; |
||||
} |
||||
|
||||
.geneb_prev-month-date, |
||||
.geneb_next-month-date { |
||||
color: #e2e2e2; |
||||
} |
||||
|
||||
.geneb_normal-date { |
||||
color: rgba(1, 1, 5, 1); |
||||
} |
||||
|
||||
.geneb_todo-circle { |
||||
border-color: #88d2ac; |
||||
} |
||||
|
||||
.geneb_todo-dot { |
||||
background-color: #e54d42; |
||||
} |
||||
|
||||
.geneb_date-desc { |
||||
color: #c2c2c2; |
||||
} |
||||
|
||||
.geneb_date-desc-lunar { |
||||
color: #e54d42; |
||||
} |
||||
|
||||
.geneb_date-desc-disable { |
||||
color: #e2e2e2; |
||||
} |
||||
|
||||
.geneb_festival { |
||||
color: #c2c2c2; |
||||
} |
||||
|
||||
.date.doc { |
||||
position: relative; |
||||
background-color: #e5e5e5; |
||||
} |
||||
|
||||
.date.doc::after { |
||||
position: absolute; |
||||
z-index: 1; |
||||
top: -5rpx; |
||||
right: -5rpx; |
||||
content: ''; |
||||
width: 17rpx; |
||||
height: 24rpx; |
||||
background-repeat: no-repeat; |
||||
background-size: cover; |
||||
background-image: url('data:image/png;base64,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'); |
||||
} |
||||
|
||||
.date.error { |
||||
background-color: rgba(207, 83, 117, 1); |
||||
border-radius: 50%; |
||||
color: #fff; |
||||
} |
||||
|
||||
.date.primary { |
||||
background-color: rgba(37, 217, 200, 1); |
||||
color: #fff; |
||||
border-radius: 50%; |
||||
} |
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
/* 日历主要颜色相关样式 */ |
||||
|
||||
.nuohe_color, |
||||
.nuohe_weekend-color, |
||||
.nuohe_handle-color, |
||||
.nuohe_week-color { |
||||
color: rgba(51, 51, 51, 1); |
||||
} |
||||
|
||||
.nuohe_today { |
||||
color: #fff; |
||||
background-color: #874fb4; |
||||
} |
||||
|
||||
.nuohe_choosed { |
||||
color: rgba(51, 51, 51, 1); |
||||
background-color: rgba(189, 189, 189, 0.3); |
||||
} |
||||
|
||||
.nuohe_date-disable { |
||||
color: #c7c7c7; |
||||
} |
||||
|
||||
.nuohe_choosed.nuohe_date-disable { |
||||
color: #e2e2e2; |
||||
background-color: #c2afb6; |
||||
} |
||||
|
||||
.nuohe_prev-month-date, |
||||
.nuohe_next-month-date { |
||||
color: #e2e2e2; |
||||
} |
||||
|
||||
.nuohe_normal-date { |
||||
color: rgba(51, 51, 51, 1); |
||||
} |
||||
|
||||
.nuohe_todo-circle { |
||||
border-color: #88d2ac; |
||||
} |
||||
|
||||
.nuohe_todo-dot { |
||||
background-color: #e54d42; |
||||
} |
||||
|
||||
.nuohe_date-desc { |
||||
color: #c2c2c2; |
||||
} |
||||
|
||||
.nuohe_date-desc-lunar { |
||||
color: #e54d42; |
||||
} |
||||
|
||||
.nuohe_date-desc-disable { |
||||
color: #e2e2e2; |
||||
} |
||||
|
||||
.nuohe_festival { |
||||
color: #c2c2c2; |
||||
} |
||||
|
||||
.date.doc { |
||||
position: relative; |
||||
background-color: #e5e5e5; |
||||
} |
||||
|
||||
.date.doc::after { |
||||
position: absolute; |
||||
z-index: 1; |
||||
top: -5rpx; |
||||
right: -5rpx; |
||||
content: ""; |
||||
width: 17rpx; |
||||
height: 24rpx; |
||||
background-repeat: no-repeat; |
||||
background-size: cover; |
||||
background-image: url("data:image/png;base64,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"); |
||||
} |
||||
|
||||
.date.error { |
||||
background-color: rgba(207, 83, 117, 1); |
||||
border-radius: 50%; |
||||
color: #fff; |
||||
} |
||||
|
||||
.date.primary { |
||||
background-color: rgba(37, 217, 200, 1); |
||||
color: #fff; |
||||
border-radius: 50%; |
||||
} |
@ -0,0 +1,275 @@
@@ -0,0 +1,275 @@
|
||||
import Logger from "./logger"; |
||||
import WxData from "./wxData"; |
||||
|
||||
let systemInfo; |
||||
export function getSystemInfo() { |
||||
if (systemInfo) return systemInfo; |
||||
systemInfo = wx.getSystemInfoSync(); |
||||
return systemInfo; |
||||
} |
||||
|
||||
export function isIos() { |
||||
const sys = getSystemInfo(); |
||||
return /iphone|ios/i.test(sys.platform); |
||||
} |
||||
|
||||
class Gesture { |
||||
/** |
||||
* 左滑 |
||||
* @param {object} e 事件对象 |
||||
* @returns {boolean} 布尔值 |
||||
*/ |
||||
isLeft(gesture = {}, touche = {}) { |
||||
const { startX, startY } = gesture; |
||||
const deltaX = touche.clientX - startX; |
||||
const deltaY = touche.clientY - startY; |
||||
if (deltaX < -60 && deltaY < 20 && deltaY > -20) { |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
/** |
||||
* 右滑 |
||||
* @param {object} e 事件对象 |
||||
* @returns {boolean} 布尔值 |
||||
*/ |
||||
isRight(gesture = {}, touche = {}) { |
||||
const { startX, startY } = gesture; |
||||
const deltaX = touche.clientX - startX; |
||||
const deltaY = touche.clientY - startY; |
||||
|
||||
if (deltaX > 60 && deltaY < 20 && deltaY > -20) { |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
class DateUtil { |
||||
newDate(year, month, date) { |
||||
let cur = `${+year}-${+month}-${+date}`; |
||||
if (isIos()) { |
||||
cur = `${+year}/${+month}/${+date}`; |
||||
} |
||||
return new Date(cur); |
||||
} |
||||
/** |
||||
* 计算指定日期时间戳 |
||||
* @param {object} date |
||||
*/ |
||||
getTimeStamp(dateInfo) { |
||||
if (typeof dateInfo === "string") { |
||||
dateInfo = this.transformDateRow2Dict(dateInfo); |
||||
} |
||||
if (Object.prototype.toString.call(dateInfo) !== "[object Object]") return; |
||||
const dateUtil = new DateUtil(); |
||||
return dateUtil.newDate(dateInfo.year, dateInfo.month, dateInfo.date).getTime(); |
||||
} |
||||
/** |
||||
* 计算指定月份共多少天 |
||||
* @param {number} year 年份 |
||||
* @param {number} month 月份 |
||||
*/ |
||||
getDatesCountOfMonth(year, month) { |
||||
return new Date(Date.UTC(year, month, 0)).getUTCDate(); |
||||
} |
||||
/** |
||||
* 计算指定月份第一天星期几 |
||||
* @param {number} year 年份 |
||||
* @param {number} month 月份 |
||||
*/ |
||||
firstDayOfWeek(year, month) { |
||||
return new Date(Date.UTC(year, month - 1, 1)).getUTCDay(); |
||||
} |
||||
/** |
||||
* 计算指定日期星期几 |
||||
* @param {number} year 年份 |
||||
* @param {number} month 月份 |
||||
* @param {number} date 日期 |
||||
*/ |
||||
getDayOfWeek(year, month, date) { |
||||
return new Date(Date.UTC(year, month - 1, date)).getUTCDay(); |
||||
} |
||||
todayFMD() { |
||||
const _date = new Date(); |
||||
const year = _date.getFullYear(); |
||||
const month = _date.getMonth() + 1; |
||||
const date = _date.getDate(); |
||||
return { |
||||
year: +year, |
||||
month: +month, |
||||
date: +date, |
||||
}; |
||||
} |
||||
todayTimestamp() { |
||||
const { year, month, date } = this.todayFMD(); |
||||
const timestamp = this.newDate(year, month, date).getTime(); |
||||
return timestamp; |
||||
} |
||||
toTimeStr(dateInfo = {}) { |
||||
return `${+dateInfo.year}-${+dateInfo.month}-${+dateInfo.date}`; |
||||
} |
||||
transformDateRow2Dict(dateStr) { |
||||
if (typeof dateStr === "string" && dateStr.includes("-")) { |
||||
const [year, month, date] = dateStr.split("-"); |
||||
return this.tranformStr2NumOfDate({ |
||||
year, |
||||
month, |
||||
date, |
||||
}); |
||||
} |
||||
return {}; |
||||
} |
||||
tranformStr2NumOfDate(date = {}) { |
||||
const target = { ...date }; |
||||
// 可能传入字符串
|
||||
target.year = +target.year; |
||||
target.month = +target.month; |
||||
target.date = +target.date; |
||||
return target; |
||||
} |
||||
sortDatesByTime(dates = [], sortType) { |
||||
return dates.sort((a, b) => { |
||||
const at = this.getTimeStamp(a); |
||||
const bt = this.getTimeStamp(b); |
||||
if (at < bt && sortType !== "desc") { |
||||
return -1; |
||||
} else { |
||||
return 1; |
||||
} |
||||
}); |
||||
} |
||||
getPrevMonthInfo(date = {}) { |
||||
const prevMonthInfo = |
||||
Number(date.month) > 1 |
||||
? { |
||||
year: +date.year, |
||||
month: Number(date.month) - 1, |
||||
} |
||||
: { |
||||
year: Number(date.year) - 1, |
||||
month: 12, |
||||
}; |
||||
return prevMonthInfo; |
||||
} |
||||
getNextMonthInfo(date = {}) { |
||||
const nextMonthInfo = |
||||
Number(date.month) < 12 |
||||
? { |
||||
year: +date.year, |
||||
month: Number(date.month) + 1, |
||||
} |
||||
: { |
||||
year: Number(date.year) + 1, |
||||
month: 1, |
||||
}; |
||||
return nextMonthInfo; |
||||
} |
||||
getPrevYearInfo(date = {}) { |
||||
return { |
||||
year: Number(date.year) - 1, |
||||
month: +date.month, |
||||
}; |
||||
} |
||||
getNextYearInfo(date = {}) { |
||||
return { |
||||
year: Number(date.year) + 1, |
||||
month: +date.month, |
||||
}; |
||||
} |
||||
findDateIndexInArray(target, dates) { |
||||
return dates.findIndex((item) => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(target)); |
||||
} |
||||
calcDates(year, month) { |
||||
const datesCount = this.getDatesCountOfMonth(year, month); |
||||
const dates = []; |
||||
const today = dateUtil.todayFMD(); |
||||
for (let i = 1; i <= datesCount; i++) { |
||||
const week = dateUtil.getDayOfWeek(+year, +month, i); |
||||
const date = { |
||||
year: +year, |
||||
id: i - 1, |
||||
month: +month, |
||||
date: i, |
||||
week, |
||||
isToday: +today.year === +year && +today.month === +month && i === +today.date, |
||||
}; |
||||
dates.push(date); |
||||
} |
||||
return dates; |
||||
} |
||||
/** |
||||
* 日期数组根据日期去重 |
||||
* @param {array} array 数组 |
||||
*/ |
||||
uniqueArrayByDate(array = []) { |
||||
let uniqueObject = {}; |
||||
let uniqueArray = []; |
||||
array.forEach((item) => { |
||||
uniqueObject[dateUtil.toTimeStr(item)] = item; |
||||
}); |
||||
for (let i in uniqueObject) { |
||||
uniqueArray.push(uniqueObject[i]); |
||||
} |
||||
return uniqueArray; |
||||
} |
||||
/** |
||||
* 筛选指定年月日期 |
||||
* @param {object} target 指定年月 |
||||
* @param {array} dates 待筛选日期 |
||||
*/ |
||||
filterDatesByYM(target, dates) { |
||||
if (target) { |
||||
const { year, month } = target; |
||||
const _dates = dates.filter((item) => +item.year === +year && +item.month === +month); |
||||
return _dates; |
||||
} |
||||
return dates; |
||||
} |
||||
getWeekHeader(firstDayOfWeek) { |
||||
let weeksCh = ["日", "一", "二", "三", "四", "五", "六"]; |
||||
if (firstDayOfWeek === "Mon") { |
||||
weeksCh = ["一", "二", "三", "四", "五", "六", "日"]; |
||||
} |
||||
return weeksCh; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取当前页面实例 |
||||
*/ |
||||
export function getCurrentPage() { |
||||
const pages = getCurrentPages() || []; |
||||
const last = pages.length - 1; |
||||
return pages[last] || {}; |
||||
} |
||||
|
||||
export function getComponentById(componentId) { |
||||
const logger = new Logger(); |
||||
let page = getCurrentPage() || {}; |
||||
if (page.selectComponent && typeof page.selectComponent === "function") { |
||||
if (componentId) { |
||||
return page.selectComponent(componentId); |
||||
} else { |
||||
logger.warn("请传入组件ID"); |
||||
} |
||||
} else { |
||||
logger.warn("该基础库暂不支持多个小程序日历组件"); |
||||
} |
||||
} |
||||
|
||||
export const logger = new Logger(); |
||||
export const calendarGesture = new Gesture(); |
||||
export const dateUtil = new DateUtil(); |
||||
export const getCalendarData = (key, component) => new WxData(component).getData(key); |
||||
export const setCalendarData = (data, component) => new WxData(component).setData(data); |
||||
export const getCalendarConfig = (component) => getCalendarData("config", component); |
||||
export const setCalendarConfig = (config, component) => |
||||
setCalendarData( |
||||
{ |
||||
config, |
||||
}, |
||||
component, |
||||
); |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
export default class Logger { |
||||
info(msg) { |
||||
console.log( |
||||
'%cInfo: %c' + msg, |
||||
'color:#FF0080;font-weight:bold', |
||||
'color: #FF509B' |
||||
) |
||||
} |
||||
warn(msg) { |
||||
console.log( |
||||
'%cWarn: %c' + msg, |
||||
'color:#FF6600;font-weight:bold', |
||||
'color: #FF9933' |
||||
) |
||||
} |
||||
tips(msg) { |
||||
console.log( |
||||
'%cTips: %c' + msg, |
||||
'color:#00B200;font-weight:bold', |
||||
'color: #00CC33' |
||||
) |
||||
} |
||||
} |
@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
|
||||
class WxData { |
||||
constructor(component) { |
||||
this.Component = component |
||||
} |
||||
getData(key) { |
||||
const data = this.Component.data |
||||
if (!key) return data |
||||
if (key.includes('.')) { |
||||
let keys = key.split('.') |
||||
const tmp = keys.reduce((prev, next) => { |
||||
return prev[next] |
||||
}, data) |
||||
return tmp |
||||
} else { |
||||
return this.Component.data[key] |
||||
} |
||||
} |
||||
setData(data) { |
||||
return new Promise((resolve, reject) => { |
||||
if (!data) return reject('no data to set') |
||||
if (typeof data === 'object') { |
||||
this.Component.setData(data, () => { |
||||
resolve(data) |
||||
}) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
export default WxData |
@ -0,0 +1,269 @@
@@ -0,0 +1,269 @@
|
||||
import WxCanvas from './wx-canvas' |
||||
const echarts = require('./echarts.js') |
||||
|
||||
let ctx |
||||
|
||||
function compareVersion(v1, v2) { |
||||
v1 = v1.split('.') |
||||
v2 = v2.split('.') |
||||
const len = Math.max(v1.length, v2.length) |
||||
|
||||
while (v1.length < len) { |
||||
v1.push('0') |
||||
} |
||||
while (v2.length < len) { |
||||
v2.push('0') |
||||
} |
||||
|
||||
for (let i = 0; i < len; i++) { |
||||
const num1 = parseInt(v1[i]) |
||||
const num2 = parseInt(v2[i]) |
||||
|
||||
if (num1 > num2) { |
||||
return 1 |
||||
} else if (num1 < num2) { |
||||
return -1 |
||||
} |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
Component({ |
||||
properties: { |
||||
canvasId: { |
||||
type: String, |
||||
value: 'ec-canvas', |
||||
}, |
||||
|
||||
ec: { |
||||
type: Object, |
||||
}, |
||||
|
||||
forceUseOldCanvas: { |
||||
type: Boolean, |
||||
value: false, |
||||
}, |
||||
}, |
||||
|
||||
data: { |
||||
isUseNewCanvas: false, |
||||
}, |
||||
|
||||
ready: async function () { |
||||
// Disable prograssive because drawImage doesn't support DOM as parameter
|
||||
// See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.html
|
||||
echarts.registerPreprocessor((option) => { |
||||
if (option && option.series) { |
||||
if (option.series.length > 0) { |
||||
option.series.forEach((series) => { |
||||
series.progressive = 0 |
||||
}) |
||||
} else if (typeof option.series === 'object') { |
||||
option.series.progressive = 0 |
||||
} |
||||
} |
||||
}) |
||||
|
||||
if (!this.data.ec) { |
||||
console.warn( |
||||
'组件需绑定 ec 变量,例:<ec-canvas id="mychart-dom-bar" ' + |
||||
'canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>', |
||||
) |
||||
return |
||||
} |
||||
|
||||
if (!this.data.ec.lazyLoad) { |
||||
this.init() |
||||
} |
||||
}, |
||||
|
||||
methods: { |
||||
init: async function (callback) { |
||||
const version = wx.getSystemInfoSync().SDKVersion |
||||
|
||||
const canUseNewCanvas = compareVersion(version, '2.9.0') >= 0 |
||||
const forceUseOldCanvas = this.data.forceUseOldCanvas |
||||
const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas |
||||
this.setData({ isUseNewCanvas }) |
||||
|
||||
if (forceUseOldCanvas && canUseNewCanvas) { |
||||
console.warn('开发者强制使用旧canvas,建议关闭') |
||||
} |
||||
|
||||
if (isUseNewCanvas) { |
||||
// console.log('微信基础库版本大于2.9.0,开始使用<canvas type="2d"/>');
|
||||
// 2.9.0 可以使用 <canvas type="2d"></canvas>
|
||||
this.initByNewWay(callback) |
||||
} else { |
||||
const isValid = compareVersion(version, '1.9.91') >= 0 |
||||
if (!isValid) { |
||||
console.error( |
||||
'微信基础库版本过低,需大于等于 1.9.91。' + |
||||
'参见:https://github.com/ecomfe/echarts-for-weixin' + |
||||
'#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82', |
||||
) |
||||
return |
||||
} else { |
||||
console.warn('建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能') |
||||
this.initByOldWay(callback) |
||||
} |
||||
} |
||||
}, |
||||
|
||||
initByOldWay(callback) { |
||||
// 1.9.91 <= version < 2.9.0:原来的方式初始化
|
||||
ctx = wx.createCanvasContext(this.data.canvasId, this) |
||||
const canvas = new WxCanvas(ctx, this.data.canvasId, false) |
||||
|
||||
echarts.setCanvasCreator(() => { |
||||
return canvas |
||||
}) |
||||
// const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dpr
|
||||
const canvasDpr = 1 |
||||
var query = wx.createSelectorQuery().in(this) |
||||
query |
||||
.select('.ec-canvas') |
||||
.boundingClientRect((res) => { |
||||
if (typeof callback === 'function') { |
||||
this.chart = callback(canvas, res.width, res.height, canvasDpr) |
||||
} else if (this.data.ec && typeof this.data.ec.onInit === 'function') { |
||||
this.chart = this.data.ec.onInit(canvas, res.width, res.height, canvasDpr) |
||||
} else { |
||||
this.triggerEvent('init', { |
||||
canvas: canvas, |
||||
width: res.width, |
||||
height: res.height, |
||||
canvasDpr: canvasDpr, // 增加了dpr,可方便外面echarts.init
|
||||
}) |
||||
} |
||||
}) |
||||
.exec() |
||||
}, |
||||
|
||||
initByNewWay(callback) { |
||||
// version >= 2.9.0:使用新的方式初始化
|
||||
const query = wx.createSelectorQuery().in(this) |
||||
query |
||||
.select('.ec-canvas') |
||||
.fields({ node: true, size: true }) |
||||
.exec((res) => { |
||||
const canvasNode = res[0].node |
||||
this.canvasNode = canvasNode |
||||
|
||||
const canvasDpr = wx.getSystemInfoSync().pixelRatio |
||||
const canvasWidth = res[0].width |
||||
const canvasHeight = res[0].height |
||||
|
||||
const ctx = canvasNode.getContext('2d') |
||||
|
||||
const canvas = new WxCanvas(ctx, this.data.canvasId, true, canvasNode) |
||||
echarts.setCanvasCreator(() => { |
||||
return canvas |
||||
}) |
||||
|
||||
if (typeof callback === 'function') { |
||||
this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr) |
||||
} else if (this.data.ec && typeof this.data.ec.onInit === 'function') { |
||||
this.chart = this.data.ec.onInit(canvas, canvasWidth, canvasHeight, canvasDpr) |
||||
} else { |
||||
this.triggerEvent('init', { |
||||
canvas: canvas, |
||||
width: canvasWidth, |
||||
height: canvasHeight, |
||||
dpr: canvasDpr, |
||||
}) |
||||
} |
||||
}) |
||||
}, |
||||
canvasToTempFilePath(opt) { |
||||
if (this.data.isUseNewCanvas) { |
||||
// 新版
|
||||
const query = wx.createSelectorQuery().in(this) |
||||
query |
||||
.select('.ec-canvas') |
||||
.fields({ node: true, size: true }) |
||||
.exec((res) => { |
||||
const canvasNode = res[0].node |
||||
opt.canvas = canvasNode |
||||
wx.canvasToTempFilePath(opt) |
||||
}) |
||||
} else { |
||||
// 旧的
|
||||
if (!opt.canvasId) { |
||||
opt.canvasId = this.data.canvasId |
||||
} |
||||
ctx.draw(true, () => { |
||||
wx.canvasToTempFilePath(opt, this) |
||||
}) |
||||
} |
||||
}, |
||||
|
||||
touchStart(e) { |
||||
if (this.chart && e.touches.length > 0) { |
||||
var touch = e.touches[0] |
||||
var handler = this.chart.getZr().handler |
||||
handler.dispatch('mousedown', { |
||||
zrX: touch.x, |
||||
zrY: touch.y, |
||||
preventDefault: () => {}, |
||||
stopImmediatePropagation: () => {}, |
||||
stopPropagation: () => {}, |
||||
}) |
||||
handler.dispatch('mousemove', { |
||||
zrX: touch.x, |
||||
zrY: touch.y, |
||||
preventDefault: () => {}, |
||||
stopImmediatePropagation: () => {}, |
||||
stopPropagation: () => {}, |
||||
}) |
||||
handler.processGesture(wrapTouch(e), 'start') |
||||
} |
||||
}, |
||||
|
||||
touchMove(e) { |
||||
if (this.chart && e.touches.length > 0) { |
||||
var touch = e.touches[0] |
||||
var handler = this.chart.getZr().handler |
||||
handler.dispatch('mousemove', { |
||||
zrX: touch.x, |
||||
zrY: touch.y, |
||||
preventDefault: () => {}, |
||||
stopImmediatePropagation: () => {}, |
||||
stopPropagation: () => {}, |
||||
}) |
||||
handler.processGesture(wrapTouch(e), 'change') |
||||
} |
||||
}, |
||||
|
||||
touchEnd(e) { |
||||
if (this.chart) { |
||||
const touch = e.changedTouches ? e.changedTouches[0] : {} |
||||
var handler = this.chart.getZr().handler |
||||
handler.dispatch('mouseup', { |
||||
zrX: touch.x, |
||||
zrY: touch.y, |
||||
preventDefault: () => {}, |
||||
stopImmediatePropagation: () => {}, |
||||
stopPropagation: () => {}, |
||||
}) |
||||
handler.dispatch('click', { |
||||
zrX: touch.x, |
||||
zrY: touch.y, |
||||
preventDefault: () => {}, |
||||
stopImmediatePropagation: () => {}, |
||||
stopPropagation: () => {}, |
||||
}) |
||||
handler.processGesture(wrapTouch(e), 'end') |
||||
} |
||||
}, |
||||
}, |
||||
}) |
||||
|
||||
function wrapTouch(event) { |
||||
for (let i = 0; i < event.touches.length; ++i) { |
||||
const touch = event.touches[i] |
||||
touch.offsetX = touch.x |
||||
touch.offsetY = touch.y |
||||
} |
||||
return event |
||||
} |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
{ |
||||
"component": true, |
||||
"usingComponents": {} |
||||
} |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
<!-- 新的:接口对其了H5 --> |
||||
<canvas wx:if="{{isUseNewCanvas}}" type="2d" class="ec-canvas" canvas-id="{{ canvasId }}" bindinit="init" bindtouchstart="{{ ec.disableTouch ? '' : 'touchStart' }}" bindtouchmove="{{ ec.disableTouch ? '' : 'touchMove' }}" bindtouchend="{{ ec.disableTouch ? '' : 'touchEnd' }}"></canvas> |
||||
<!-- 旧的 --> |
||||
<canvas wx:else class="ec-canvas" canvas-id="{{ canvasId }}" bindinit="init" bindtouchstart="{{ ec.disableTouch ? '' : 'touchStart' }}" bindtouchmove="{{ ec.disableTouch ? '' : 'touchMove' }}" bindtouchend="{{ ec.disableTouch ? '' : 'touchEnd' }}"></canvas> |
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
.ec-canvas { |
||||
width: 100%; |
||||
height: 100%; |
||||
z-index: 1; |
||||
} |
@ -0,0 +1,111 @@
@@ -0,0 +1,111 @@
|
||||
export default class WxCanvas { |
||||
constructor(ctx, canvasId, isNew, canvasNode) { |
||||
this.ctx = ctx; |
||||
this.canvasId = canvasId; |
||||
this.chart = null; |
||||
this.isNew = isNew |
||||
if (isNew) { |
||||
this.canvasNode = canvasNode; |
||||
} |
||||
else { |
||||
this._initStyle(ctx); |
||||
} |
||||
|
||||
// this._initCanvas(zrender, ctx);
|
||||
|
||||
this._initEvent(); |
||||
} |
||||
|
||||
getContext(contextType) { |
||||
if (contextType === '2d') { |
||||
return this.ctx; |
||||
} |
||||
} |
||||
|
||||
// canvasToTempFilePath(opt) {
|
||||
// if (!opt.canvasId) {
|
||||
// opt.canvasId = this.canvasId;
|
||||
// }
|
||||
// return wx.canvasToTempFilePath(opt, this);
|
||||
// }
|
||||
|
||||
setChart(chart) { |
||||
this.chart = chart; |
||||
} |
||||
|
||||
addEventListener() { |
||||
// noop
|
||||
} |
||||
|
||||
attachEvent() { |
||||
// noop
|
||||
} |
||||
|
||||
detachEvent() { |
||||
// noop
|
||||
} |
||||
|
||||
_initCanvas(zrender, ctx) { |
||||
zrender.util.getContext = function () { |
||||
return ctx; |
||||
}; |
||||
|
||||
zrender.util.$override('measureText', function (text, font) { |
||||
ctx.font = font || '12px sans-serif'; |
||||
return ctx.measureText(text); |
||||
}); |
||||
} |
||||
|
||||
_initStyle(ctx) { |
||||
ctx.createRadialGradient = () => { |
||||
return ctx.createCircularGradient(arguments); |
||||
}; |
||||
} |
||||
|
||||
_initEvent() { |
||||
this.event = {}; |
||||
const eventNames = [{ |
||||
wxName: 'touchStart', |
||||
ecName: 'mousedown' |
||||
}, { |
||||
wxName: 'touchMove', |
||||
ecName: 'mousemove' |
||||
}, { |
||||
wxName: 'touchEnd', |
||||
ecName: 'mouseup' |
||||
}, { |
||||
wxName: 'touchEnd', |
||||
ecName: 'click' |
||||
}]; |
||||
eventNames.forEach(name => { |
||||
this.event[name.wxName] = e => { |
||||
const touch = e.touches[0]; |
||||
this.chart.getZr().handler.dispatch(name.ecName, { |
||||
zrX: name.wxName === 'tap' ? touch.clientX : touch.x, |
||||
zrY: name.wxName === 'tap' ? touch.clientY : touch.y, |
||||
preventDefault: () => {}, |
||||
stopImmediatePropagation: () => {}, |
||||
stopPropagation: () => {} |
||||
}); |
||||
}; |
||||
}); |
||||
} |
||||
|
||||
set width(w) { |
||||
if (this.canvasNode) this.canvasNode.width = w |
||||
} |
||||
set height(h) { |
||||
if (this.canvasNode) this.canvasNode.height = h |
||||
} |
||||
|
||||
get width() { |
||||
if (this.canvasNode) |
||||
return this.canvasNode.width |
||||
return 0 |
||||
} |
||||
get height() { |
||||
if (this.canvasNode) |
||||
return this.canvasNode.height |
||||
return 0 |
||||
} |
||||
} |
@ -0,0 +1,231 @@
@@ -0,0 +1,231 @@
|
||||
// components/uploadFile/index.js
|
||||
const app = getApp() |
||||
Component({ |
||||
/** |
||||
* 组件的属性列表 |
||||
*/ |
||||
properties: { |
||||
// 是否可以上传
|
||||
upload: { |
||||
type: Boolean, |
||||
value: true, |
||||
}, |
||||
// 附件data
|
||||
fileList: { |
||||
type: Array, |
||||
value: [], |
||||
}, |
||||
accept: { |
||||
type: String, |
||||
value: 'media', |
||||
}, |
||||
fileTypes: { |
||||
// 上传类型
|
||||
type: Array, |
||||
value: ['image', 'video'], |
||||
}, |
||||
// 拍照和相机
|
||||
sourceType: { |
||||
type: Array, |
||||
value: ['album', 'camera'], |
||||
}, |
||||
// 是否可以删除
|
||||
canDelete: { |
||||
type: Boolean, |
||||
value: true, |
||||
}, |
||||
// 是否可以下载
|
||||
// canDownLoad: {
|
||||
// type: Boolean,
|
||||
// value: true
|
||||
// },
|
||||
// 最大上传数量, -1为不限制
|
||||
maxNum: { |
||||
type: Number, |
||||
value: -1, |
||||
}, |
||||
isSlot: { |
||||
type: Boolean, |
||||
value: false, |
||||
}, |
||||
count: { |
||||
type: Number, |
||||
value: 0, |
||||
}, |
||||
}, |
||||
|
||||
/** |
||||
* 组件的初始数据 |
||||
*/ |
||||
data: { |
||||
Timestamp: app.globalData.Timestamp, |
||||
imageUrl: app.globalData.imageUrl, |
||||
}, |
||||
|
||||
/** |
||||
* 组件的方法列表 |
||||
*/ |
||||
methods: { |
||||
viewFile(e) { |
||||
const { index } = e.currentTarget.dataset |
||||
const { fileList } = this.properties |
||||
let sources = [] |
||||
|
||||
fileList.map((e) => { |
||||
const obj = { |
||||
url: e.fileUrl, |
||||
type: e.type, // image video
|
||||
poster: e.imgUrl, |
||||
} |
||||
sources.push(obj) |
||||
}) |
||||
wx.previewMedia({ |
||||
current: index, |
||||
sources: sources, |
||||
}) |
||||
}, |
||||
deleteFile(e) { |
||||
const { index, item } = e.currentTarget.dataset |
||||
this.triggerEvent('deleteFile', { |
||||
index, |
||||
item, |
||||
}) |
||||
}, |
||||
downFile(e) { |
||||
const { item } = e.currentTarget.dataset |
||||
wx.showToast({ |
||||
title: '正在下载,请稍后...', |
||||
icon: 'none', |
||||
}) |
||||
wx.downloadFile({ |
||||
url: item.fileUrl, |
||||
success(res) { |
||||
if (item.type === 'image') { |
||||
wx.saveImageToPhotosAlbum({ |
||||
filePath: res.tempFilePath, |
||||
success: () => { |
||||
wx.showToast({ |
||||
title: '下载成功', |
||||
}) |
||||
}, |
||||
}) |
||||
} else if (item.type === 'video') { |
||||
wx.saveVideoToPhotosAlbum({ |
||||
filePath: res.tempFilePath, |
||||
success: () => { |
||||
wx.showToast({ |
||||
title: '下载成功', |
||||
}) |
||||
}, |
||||
}) |
||||
} else { |
||||
wx.showToast({ |
||||
title: '附件请到pc端下载!', |
||||
icon: 'none', |
||||
}) |
||||
// wx.saveFile({
|
||||
// tempFilePath: res.tempFilePath,
|
||||
// success: () => {
|
||||
// wx.showToast({
|
||||
// title: '下载成功',
|
||||
// })
|
||||
// },
|
||||
// fail(err){
|
||||
// console.log(err)
|
||||
// },
|
||||
// })
|
||||
} |
||||
}, |
||||
}) |
||||
}, |
||||
uploadFile(item) { |
||||
return new Promise((resolve, resject) => { |
||||
let url = `${app.globalData.upFileUrl}?r=file-service/upload-` |
||||
if (item.fileType === 'image') { |
||||
url += 'img' |
||||
} |
||||
if (item.fileType === 'video') { |
||||
url += 'video' |
||||
} |
||||
let that = this |
||||
wx.uploadFile({ |
||||
filePath: item.tempFilePath, |
||||
name: 'file', |
||||
url: url, |
||||
success(res) { |
||||
let data = JSON.parse(res.data) |
||||
let expandJson = { |
||||
fileId: '', |
||||
name: data.data.Url, |
||||
size: (item.size / 1024).toFixed(2), |
||||
fileUrl: data.data.Url, |
||||
suffix: that.GetExtensionFileName(data.data.Url), |
||||
type: item.fileType, |
||||
} |
||||
if (item.fileType === 'image') { |
||||
expandJson.imgUrl = data.data.Url |
||||
} |
||||
if (item.fileType === 'video') { |
||||
expandJson.imgUrl = data.data.SnapshotUrl |
||||
} |
||||
resolve(expandJson) |
||||
}, |
||||
fail() { |
||||
resject() |
||||
}, |
||||
}) |
||||
}) |
||||
}, |
||||
GetExtensionFileName(pathfilename) { |
||||
var reg = /(\\+)/g |
||||
var pString = pathfilename.replace(reg, '#') //用正则表达式来将\或\\替换成#
|
||||
var arr = pString.split('#') // 以“#”为分隔符,将字符分解为数组 例如 D Program Files bg.png
|
||||
var lastString = arr[arr.length - 1] //取最后一个字符
|
||||
var arr2 = lastString.split('.') // 再以"."作为分隔符
|
||||
return arr2[arr2.length - 1] //将后缀名返回出来
|
||||
}, |
||||
upFile(data) { |
||||
wx.showLoading({ |
||||
title: '正在上传', |
||||
}) |
||||
let apiArr = [] |
||||
data.map((e) => { |
||||
apiArr.push(this.uploadFile(e)) |
||||
}) |
||||
Promise.all(apiArr) |
||||
.then((res) => { |
||||
wx.hideLoading({ |
||||
success: () => { |
||||
this.triggerEvent('setData', res) |
||||
}, |
||||
}) |
||||
}) |
||||
.catch(() => { |
||||
wx.showToast({ |
||||
title: '上传失败', |
||||
icon: 'error', |
||||
}) |
||||
}) |
||||
}, |
||||
selectFile() { |
||||
let { fileList, maxNum, sourceType, fileTypes, count = 0 } = this.properties |
||||
var that = this |
||||
if (maxNum >= 0 && count == 0) { |
||||
count = maxNum - fileList.length |
||||
} |
||||
this.triggerEvent('choose') |
||||
wx.chooseMedia({ |
||||
mediaType: fileTypes, |
||||
count: count, |
||||
sourceType: sourceType, |
||||
sizeType: ['original'], |
||||
success(res) { |
||||
res.tempFiles.map((e) => { |
||||
e.fileType = e.fileType || res.type |
||||
}) |
||||
that.upFile(res.tempFiles) |
||||
}, |
||||
}) |
||||
}, |
||||
}, |
||||
}) |
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
{ |
||||
"component": true, |
||||
"usingComponents": { |
||||
"van-icon": "@vant/weapp/icon/index", |
||||
"van-image": "@vant/weapp/image/index" |
||||
} |
||||
} |
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
/* components/uploadFile/index.wxss */ |
||||
.upload-list { |
||||
display: flex; |
||||
flex-wrap: wrap; |
||||
gap: 18rpx; |
||||
|
||||
.item { |
||||
width: 180rpx; |
||||
height: 180rpx; |
||||
position: relative; |
||||
line-height: 0; |
||||
.item_mask { |
||||
position: absolute; |
||||
width: 100%; |
||||
height: 100%; |
||||
left: 0; |
||||
top: 0; |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
.item_mask_icon { |
||||
border-radius: 100%; |
||||
overflow: hidden; |
||||
background: #fff; |
||||
font-size: 0; |
||||
} |
||||
} |
||||
.image { |
||||
width: 100%; |
||||
height: 100%; |
||||
border-radius: 12rpx; |
||||
} |
||||
.clear { |
||||
position: absolute; |
||||
right: -22rpx; |
||||
top: -28rpx; |
||||
padding: 10rpx; |
||||
z-index: 9; |
||||
} |
||||
} |
||||
|
||||
.btn { |
||||
width: 188rpx; |
||||
height: 188rpx; |
||||
border-radius: 20rpx; |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: center; |
||||
align-items: center; |
||||
background-color: rgba(247, 247, 250, 1); |
||||
.name { |
||||
margin-top: 12rpx; |
||||
font-size: 28rpx; |
||||
color: rgba(207, 209, 213, 1); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
<!-- components/uploadFile/index.wxml --> |
||||
<view class="upload-list"> |
||||
<view class="item" wx:for="{{fileList}}" wx:key="index" data-index="{{index}}" catchtap="viewFile"> |
||||
<image class="image" mode="aspectFill" src="{{item.imgUrl}}"></image> |
||||
<view wx:if="{{item.type === 'video'}}" class="item_mask"> |
||||
<van-icon size="48rpx" color="rgba(0,0,0,0.6)" name="play-circle" class="item_mask_icon" /> |
||||
</view> |
||||
<view wx:if="{{canDelete}}" class="clear" catchtap="deleteFile" data-item="{{item}}" data-index="{{index}}"> |
||||
<van-icon name="clear" /> |
||||
</view> |
||||
</view> |
||||
<view wx:if="{{upload && (maxNum === -1 || maxNum > fileList.length)}}" catchtap="selectFile"> |
||||
<slot wx:if="{{isSlot}}"></slot> |
||||
<view wx:else class="btn"> |
||||
<van-icon name="plus" color="rgba(207, 209, 213, 1)" size="50rpx" /> |
||||
<view class="name">请上传</view> |
||||
</view> |
||||
</view> |
||||
</view> |
After Width: | Height: | Size: 412 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 9.5 KiB |
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 799 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
{ |
||||
"navigationBarTitleText": "我的AAV检查", |
||||
"usingComponents": { |
||||
"uploadFile": "/components/uploadFile/index" |
||||
} |
||||
} |
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
page { |
||||
background-color: rgba(247, 247, 250, 1); |
||||
} |
||||
.page { |
||||
padding: 32rpx 40rpx; |
||||
.date-card { |
||||
padding: 0 32rpx; |
||||
background: #ffffff; |
||||
border-radius: 24rpx 24rpx 24rpx 24rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
.label { |
||||
font-size: 32rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
font-weight: bold; |
||||
} |
||||
.picker { |
||||
flex: 1; |
||||
.picker-content { |
||||
padding: 26rpx 0; |
||||
display: flex; |
||||
gap: 22rpx; |
||||
justify-content: flex-end; |
||||
color: rgba(207, 209, 213, 1); |
||||
.content { |
||||
&::after { |
||||
content: attr(data-place); |
||||
font-size: 32rpx; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
.card { |
||||
margin-top: 24rpx; |
||||
padding: 32rpx; |
||||
border-radius: 24rpx; |
||||
background-color: #fff; |
||||
.card-title { |
||||
font-size: 32rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
font-weight: bold; |
||||
} |
||||
.upload-list { |
||||
margin-top: 24rpx; |
||||
} |
||||
.card-content { |
||||
margin-top: 24rpx; |
||||
gap: 24rpx; |
||||
display: grid; |
||||
grid-template-columns: repeat(3, 1fr); |
||||
.content { |
||||
padding: 16rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
gap: 18rpx; |
||||
font-size: 28rpx; |
||||
color: rgba(137, 141, 151, 1); |
||||
border-radius: 20rpx; |
||||
background: #f7f7fa; |
||||
border: 2rpx solid #f7f7fa; |
||||
.icon { |
||||
width: 58rpx; |
||||
height: 58rpx; |
||||
} |
||||
.icon2 { |
||||
display: none; |
||||
} |
||||
&.active { |
||||
color: rgba(246, 74, 58, 1); |
||||
background: #ffe5e2; |
||||
border-radius: 20rpx 20rpx 20rpx 20rpx; |
||||
border: 2rpx solid #f64a3a; |
||||
.icon1 { |
||||
display: none; |
||||
} |
||||
.icon2 { |
||||
display: block; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
const _app = getApp<IAppOption>(); |
||||
|
||||
Page({ |
||||
data: {}, |
||||
onLoad() {}, |
||||
}); |
||||
|
||||
export {} |
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
<view class="page"> |
||||
<view class="date-card"> |
||||
<view class="label">检查日期</view> |
||||
<picker class="picker" mode="date"> |
||||
<view class="picker-content"> |
||||
<view class="content" data-place="请选择检查日期"></view> |
||||
<van-icon name="arrow-down" /> |
||||
</view> |
||||
</picker> |
||||
</view> |
||||
<view class="card"> |
||||
<view class="card-title">上传我的AAV报告</view> |
||||
<view class="upload-list"> |
||||
<uploadFile></uploadFile> |
||||
</view> |
||||
</view> |
||||
<view class="card"> |
||||
<view class="card-title">我的AAV检查红绿灯</view> |
||||
<view class="card-content"> |
||||
<view class="content active"> |
||||
<image class="icon icon1" src="/images/icon49.png"></image> |
||||
<image class="icon icon2" src="/images/icon44.png"></image> |
||||
阴性 |
||||
</view> |
||||
<view class="content"> |
||||
<image class="icon icon1" src="/images/icon50.png"></image> |
||||
<image class="icon icon2" src="/images/icon42.png"></image> |
||||
阳性 |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
{ |
||||
"navigationBarTitleText": "BBM-H901输注备注", |
||||
"usingComponents": {} |
||||
} |
@ -0,0 +1,99 @@
@@ -0,0 +1,99 @@
|
||||
page { |
||||
background-color: rgba(247, 247, 250, 1); |
||||
} |
||||
.page { |
||||
padding: 48rpx 40rpx; |
||||
.card1 { |
||||
padding: 22rpx 32rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
border-radius: 24rpx; |
||||
background-color: #fff; |
||||
.label { |
||||
font-size: 32rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
font-weight: bold; |
||||
} |
||||
.select { |
||||
flex: 1; |
||||
display: flex; |
||||
gap: 24rpx; |
||||
justify-content: flex-end; |
||||
.s-btn { |
||||
width: 128rpx; |
||||
height: 64rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
font-size: 32rpx; |
||||
color: rgba(137, 141, 151, 1); |
||||
background-color: rgba(247, 247, 250, 1); |
||||
border-radius: 12rpx 12rpx 12rpx 12rpx; |
||||
&.active { |
||||
color: #fff; |
||||
background: #f64a3a; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.card2 { |
||||
margin-top: 24rpx; |
||||
padding: 32rpx; |
||||
border-radius: 24rpx; |
||||
background-color: #fff; |
||||
.title { |
||||
font-size: 32rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
font-weight: bold; |
||||
} |
||||
.textarea { |
||||
margin-top: 24rpx; |
||||
padding: 24rpx 32rpx; |
||||
width: 100%; |
||||
box-sizing: border-box; |
||||
font-size: 32rpx; |
||||
border-radius: 12rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
background-color: rgba(247, 247, 250, 1); |
||||
} |
||||
.place-textarea { |
||||
color: rgba(207, 209, 213, 1); |
||||
} |
||||
} |
||||
|
||||
.footer { |
||||
position: fixed; |
||||
bottom: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
padding: 16rpx 40rpx calc(16rpx + env(safe-area-inset-bottom)); |
||||
background-color: rgba(255, 255, 255, 1); |
||||
display: flex; |
||||
gap: 26rpx; |
||||
box-sizing: border-box; |
||||
.cancel { |
||||
flex: 1; |
||||
padding: 22rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
font-size: 32rpx; |
||||
color: rgba(246, 74, 58, 1); |
||||
border-radius: 84rpx; |
||||
border: 1px solid #f64a3a; |
||||
} |
||||
.submit { |
||||
flex: 1; |
||||
padding: 22rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
font-size: 32rpx; |
||||
color: #fff; |
||||
background: linear-gradient(356deg, #f23a2f 0%, #fc684f 100%); |
||||
border-radius: 84rpx; |
||||
border: 1px solid #f64a3a; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
const _app = getApp<IAppOption>(); |
||||
|
||||
Page({ |
||||
data: {}, |
||||
onLoad() {}, |
||||
}); |
||||
|
||||
export {} |
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
<view class="page"> |
||||
<view class="card1"> |
||||
<view class="label">是否有不良反应</view> |
||||
<view class="select"> |
||||
<view class="s-btn active">有</view> |
||||
<view class="s-btn">无</view> |
||||
</view> |
||||
</view> |
||||
<view class="card2"> |
||||
<view class="title">整体治疗过程说明</view> |
||||
<textarea class="textarea" placeholder-class="place-textarea" disable-default-padding placeholder="请输入您的药品名称"></textarea> |
||||
</view> |
||||
<view class="footer"> |
||||
<view class="cancel">取消</view> |
||||
<view class="submit">提交</view> |
||||
</view> |
||||
</view> |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
{ |
||||
"navigationBarTitleText": "BBM-H901输注记录", |
||||
"usingComponents": {} |
||||
} |
@ -0,0 +1,103 @@
@@ -0,0 +1,103 @@
|
||||
page { |
||||
background-color: rgba(247, 247, 250, 1); |
||||
} |
||||
.page { |
||||
padding: 48rpx 40rpx; |
||||
.container { |
||||
border-radius: 24rpx; |
||||
background: linear-gradient(90deg, #e1242a 0%, #ff7440 100%); |
||||
.title { |
||||
padding: 20rpx 0 60rpx; |
||||
font-size: 32rpx; |
||||
color: rgba(255, 255, 255, 1); |
||||
text-align: center; |
||||
} |
||||
.card { |
||||
margin-top: -40rpx; |
||||
padding: 0 32rpx; |
||||
border-radius: 24rpx; |
||||
background-color: #fff; |
||||
.row { |
||||
display: flex; |
||||
align-items: center; |
||||
.label { |
||||
width: 5em; |
||||
font-size: 32rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
} |
||||
.r-container { |
||||
flex: 1; |
||||
.picker { |
||||
.picker-content { |
||||
padding: 32rpx 0; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
.content { |
||||
text-align: right; |
||||
font-size: 32rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
&:empty::after { |
||||
content: attr(data-place); |
||||
color: rgba(207, 209, 213, 1); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
.columns { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 20rpx; |
||||
.input { |
||||
padding: 32rpx 0; |
||||
font-size: 32rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
} |
||||
.input-place { |
||||
color: rgba(207, 209, 213, 1); |
||||
} |
||||
.sub { |
||||
flex-shrink: 0; |
||||
font-size: 32rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.footer { |
||||
position: fixed; |
||||
bottom: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
padding: 16rpx 40rpx calc(16rpx + env(safe-area-inset-bottom)); |
||||
background-color: rgba(255, 255, 255, 1); |
||||
display: flex; |
||||
gap: 26rpx; |
||||
box-sizing: border-box; |
||||
.cancel { |
||||
flex: 1; |
||||
padding: 22rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
font-size: 32rpx; |
||||
color: rgba(246, 74, 58, 1); |
||||
border-radius: 84rpx; |
||||
border: 1px solid #f64a3a; |
||||
} |
||||
.submit { |
||||
flex: 1; |
||||
padding: 22rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
font-size: 32rpx; |
||||
color: #fff; |
||||
background: linear-gradient(356deg, #f23a2f 0%, #fc684f 100%); |
||||
border-radius: 84rpx; |
||||
border: 1px solid #f64a3a; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
const _app = getApp<IAppOption>(); |
||||
|
||||
Page({ |
||||
data: {}, |
||||
onLoad() {}, |
||||
}); |
||||
|
||||
export {} |
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
<view class="page"> |
||||
<view class="container"> |
||||
<view class="title">BBM-H901输注信息</view> |
||||
<view class="card"> |
||||
<view class="row"> |
||||
<view class="label">输注时间</view> |
||||
<view class="r-container"> |
||||
<picker class="picker"> |
||||
<view class="picker-content"> |
||||
<view class="content" data-place="请选择"></view> |
||||
<van-icon name="arrow-down" /> |
||||
</view> |
||||
</picker> |
||||
</view> |
||||
</view> |
||||
<view class="row"> |
||||
<view class="label">使用剂量</view> |
||||
<view class="r-container"> |
||||
<view class="columns"> |
||||
<input class="input" placeholder-class="input-place" type="" placeholder="请输入" /> |
||||
<view class="sub">x10¹¹vg</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="footer"> |
||||
<view class="cancel">取消</view> |
||||
<view class="submit">提交</view> |
||||
</view> |
||||
</view> |
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
{ |
||||
"navigationStyle": "custom", |
||||
"usingComponents": { |
||||
"van-circle": "@vant/weapp/circle/index", |
||||
"ec-canvas": "/components/ec-canvas/ec-canvas" |
||||
} |
||||
} |
@ -0,0 +1,145 @@
@@ -0,0 +1,145 @@
|
||||
page { |
||||
background-color: rgba(246, 246, 246, 1); |
||||
} |
||||
|
||||
.page { |
||||
padding: 40rpx; |
||||
.module1 { |
||||
margin-top: 32rpx; |
||||
padding: 32rpx; |
||||
background: linear-gradient(3deg, #ffffff 0%, #fff4f3 100%); |
||||
box-shadow: 0rpx 4rpx 24rpx 0rpx rgba(0, 0, 0, 0.06); |
||||
border-radius: 24rpx 24rpx 24rpx 24rpx; |
||||
border: 2rpx solid #ffffff; |
||||
display: grid; |
||||
grid-template-columns: repeat(2, 1fr); |
||||
.item { |
||||
padding: 0 0 0 48rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 24rpx; |
||||
&:first-of-type { |
||||
border-right: 1px solid rgba(0, 0, 0, 0.09); |
||||
} |
||||
.icon { |
||||
width: 96rpx; |
||||
height: 96rpx; |
||||
background: linear-gradient(159deg, #ffba01 0%, #f64a3a 100%); |
||||
box-shadow: 0rpx 4rpx 24rpx 0rpx rgba(246, 74, 58, 0.24); |
||||
border-radius: 122rpx 122rpx 122rpx 122rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
.i-img { |
||||
width: 52rpx; |
||||
height: 52rpx; |
||||
} |
||||
} |
||||
.wrap { |
||||
.name { |
||||
font-size: 24rpx; |
||||
color: rgba(161, 164, 172, 1); |
||||
} |
||||
.num { |
||||
font-size: 40rpx; |
||||
font-weight: bold; |
||||
color: rgba(1, 1, 5, 1); |
||||
.sub { |
||||
font-size: 24rpx; |
||||
color: rgba(161, 164, 172, 1); |
||||
font-weight: normal; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
.module2 { |
||||
margin-top: 32rpx; |
||||
padding: 24rpx 32rpx 32rpx; |
||||
background: #ffffff; |
||||
box-shadow: 0rpx 4rpx 24rpx 0rpx rgba(0, 0, 0, 0.06); |
||||
border-radius: 24rpx 24rpx 24rpx 24rpx; |
||||
.title { |
||||
font-size: 32rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
font-weight: bold; |
||||
} |
||||
.container { |
||||
margin-top: 32rpx; |
||||
display: grid; |
||||
grid-template-columns: repeat(3, 1fr); |
||||
.item { |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
.name { |
||||
font-size: 28rpx; |
||||
color: rgba(161, 164, 172, 1); |
||||
text-align: center; |
||||
} |
||||
.circle { |
||||
margin-top: 8rpx; |
||||
.content { |
||||
font-size: 40rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
.sub { |
||||
margin-left: -10rpx; |
||||
font-size: 20rpx; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
.module3 { |
||||
margin-top: 32rpx; |
||||
padding: 24rpx 32rpx 32rpx; |
||||
background: #ffffff; |
||||
box-shadow: 0rpx 4rpx 24rpx 0rpx rgba(0, 0, 0, 0.06); |
||||
border-radius: 24rpx 24rpx 24rpx 24rpx; |
||||
.title { |
||||
font-size: 32rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
font-weight: bold; |
||||
} |
||||
.container { |
||||
margin-top: 32rpx; |
||||
height: 300rpx; |
||||
#mychart-dom-bar { |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
} |
||||
} |
||||
.list { |
||||
.list-item { |
||||
margin-top: 24rpx; |
||||
background-color: #fff; |
||||
border-radius: 24rpx; |
||||
padding: 24rpx 32rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
.date { |
||||
font-size: 32rpx; |
||||
color: rgba(1, 1, 5, 1); |
||||
} |
||||
.progress { |
||||
width: 118rpx; |
||||
height: 88rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
font-size: 40rpx; |
||||
color: rgba(255, 255, 255, 1); |
||||
background: #0586ff; |
||||
border-radius: 16rpx 16rpx 16rpx 16rpx; |
||||
&::after { |
||||
margin-top: 10rpx; |
||||
content: '%'; |
||||
font-size: 24rpx; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,156 @@
@@ -0,0 +1,156 @@
|
||||
const _app = getApp<IAppOption>() |
||||
const echarts = require('@/components/ec-canvas/echarts.js') |
||||
|
||||
Page({ |
||||
data: { |
||||
cirlcleColor1: { |
||||
'0%': 'rgba(174, 248, 225, 1)', |
||||
'100%': 'rgba(31, 219, 160, 1)', |
||||
}, |
||||
cirlcleColor2: { |
||||
'0%': 'rgba(188, 223, 255, 1)', |
||||
'100%': 'rgba(0, 132, 255, 1)', |
||||
}, |
||||
cirlcleColor3: { |
||||
'0%': 'rgba(246, 74, 58, 1)', |
||||
'100%': 'rgba(255, 185, 1, 1)', |
||||
}, |
||||
}, |
||||
ecDataTrendComponent: null as any, |
||||
onLoad() { |
||||
this.ecDataTrendComponent = this.selectComponent('#mychart-dom-bar') |
||||
this.initChart() |
||||
}, |
||||
|
||||
initChart(defaultList = []) { |
||||
this.ecDataTrendComponent.init((canvas, width, height, dpr) => { |
||||
let chart = echarts.init(canvas, null, { |
||||
width: width, |
||||
height: height, |
||||
devicePixelRatio: dpr, // new
|
||||
}) |
||||
canvas.setChart(chart) |
||||
|
||||
var option = { |
||||
dataZoom: [ |
||||
{ |
||||
type: 'inside', // 内置于坐标系中
|
||||
// start: 0,
|
||||
// end: 15,
|
||||
startValue: 0, |
||||
endValue: 15, |
||||
xAxisIndex: [0], |
||||
}, |
||||
], |
||||
tooltip: { |
||||
trigger: 'axis', |
||||
axisPointer: { |
||||
type: 'shadow', |
||||
}, |
||||
confine: true, |
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)', |
||||
textStyle: { |
||||
color: '#fff', |
||||
fontSize: 10, |
||||
}, |
||||
order: 'seriesDesc', |
||||
}, |
||||
legend: { |
||||
bottom: 0, |
||||
padding: 0, |
||||
itemGap: 5, |
||||
itemWidth: 8, |
||||
itemHeight: 8, |
||||
icon: 'circle', |
||||
}, |
||||
grid: { |
||||
top: '10', |
||||
left: '5', |
||||
right: '0', |
||||
bottom: '15', |
||||
containLabel: true, |
||||
}, |
||||
xAxis: { |
||||
type: 'category', |
||||
axisLabel: { |
||||
color: 'rgba(161, 164, 172, 1)', |
||||
}, |
||||
axisTick: { |
||||
show: false, |
||||
}, |
||||
axisLine: { |
||||
lineStyle: { |
||||
type: 'solid', |
||||
color: 'rgba(137, 141, 151, 0.23)', |
||||
}, |
||||
}, |
||||
splitLine: { |
||||
show: true, |
||||
showMinLine: false, |
||||
lineStyle: { |
||||
type: 'dotted', |
||||
color: 'rgba(137, 141, 151, 0.23)', |
||||
}, |
||||
}, |
||||
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月'], |
||||
}, |
||||
yAxis: { |
||||
type: 'value', |
||||
axisLabel: { |
||||
color: 'rgba(161, 164, 172, 1)', |
||||
}, |
||||
axisLine: { |
||||
show: false, |
||||
lineStyle: { |
||||
type: 'solid', |
||||
color: 'rgba(137, 141, 151, 0.23)', |
||||
}, |
||||
}, |
||||
splitLine: { |
||||
show: true, |
||||
showMinLine: false, |
||||
lineStyle: { |
||||
type: 'dotted', |
||||
color: 'rgba(137, 141, 151, 0.23)', |
||||
}, |
||||
}, |
||||
}, |
||||
series: [ |
||||
{ |
||||
data: [150, 230, 224, 218, 135, 147, 260], |
||||
type: 'line', |
||||
lineStyle: { width: 4 }, |
||||
symbolSize: 6, |
||||
color: { |
||||
type: 'linear', |
||||
colorStops: [ |
||||
{ |
||||
offset: 0, |
||||
color: 'rgba(246, 74, 58, 1)', // 0% 处的颜色
|
||||
}, |
||||
{ |
||||
offset: 1, |
||||
color: 'rgba(255, 187, 0, 1)', // 100% 处的颜色
|
||||
}, |
||||
], |
||||
global: false, // 缺省为 false
|
||||
}, |
||||
}, |
||||
], |
||||
// dataZoom: {
|
||||
// show: true, // 为true 滚动条出现
|
||||
// realtime: true,
|
||||
// type: "slider", // 有type这个属性,滚动条在最下面,也可以不行,写y:36,这表示距离顶端36px,一般就是在图上面。
|
||||
// height: 20, // 表示滚动条的高度,也就是粗细
|
||||
// start: 20, // 表示默认展示20%~80%这一段。
|
||||
// end: 80,
|
||||
// },
|
||||
} |
||||
|
||||
chart.setOption(option) |
||||
return chart |
||||
}) |
||||
}, |
||||
}) |
||||
|
||||
export {} |
@ -0,0 +1,99 @@
@@ -0,0 +1,99 @@
|
||||
<view |
||||
class="page" |
||||
style="padding-top:{{pageTop}}px;background:url('{{imageUrl}}bg11.png?t={{Timestamp}}') no-repeat top center/100% 693rpx" |
||||
> |
||||
<view class="module1"> |
||||
<view class="item"> |
||||
<view class="icon"> |
||||
<image class="i-img" src="/images/icon57.png"></image> |
||||
</view> |
||||
<view class="wrap"> |
||||
<view class="name">因子检查</view> |
||||
<view class="num"> |
||||
30 |
||||
<text class="sub">次</text> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="icon"> |
||||
<image class="i-img" src="/images/icon58.png"></image> |
||||
</view> |
||||
<view class="wrap"> |
||||
<view class="name">因子检查</view> |
||||
<view class="num"> |
||||
30 |
||||
<text class="sub">次</text> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="module2"> |
||||
<view class="title">凝血因子水平</view> |
||||
<view class="container"> |
||||
<view class="item"> |
||||
<view class="name">≥15%</view> |
||||
<van-circle |
||||
class="circle" |
||||
value="{{ 30 }}" |
||||
size="80" |
||||
stroke-width="10" |
||||
color="{{cirlcleColor1}}" |
||||
layer-color="rgba(246, 246, 246, 1)" |
||||
clockwise="{{false}}" |
||||
> |
||||
<view class="content"> |
||||
4 |
||||
<text class="sub">次</text> |
||||
</view> |
||||
</van-circle> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="name">5%~15%</view> |
||||
<van-circle |
||||
class="circle" |
||||
value="{{ 30 }}" |
||||
size="80" |
||||
stroke-width="10" |
||||
color="{{cirlcleColor2}}" |
||||
layer-color="rgba(246, 246, 246, 1)" |
||||
clockwise="{{false}}" |
||||
> |
||||
<view class="content"> |
||||
4 |
||||
<text class="sub">次</text> |
||||
</view> |
||||
</van-circle> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="name">5%~15%</view> |
||||
<van-circle |
||||
class="circle" |
||||
value="{{ 30 }}" |
||||
size="80" |
||||
stroke-width="10" |
||||
color="{{cirlcleColor3}}" |
||||
layer-color="rgba(246, 246, 246, 1)" |
||||
clockwise="{{false}}" |
||||
> |
||||
<view class="content"> |
||||
4 |
||||
<text class="sub">次</text> |
||||
</view> |
||||
</van-circle> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="module3"> |
||||
<view class="title">凝血因子水平数据</view> |
||||
<view class="container"> |
||||
<ec-canvas id="mychart-dom-bar" canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas> |
||||
</view> |
||||
</view> |
||||
<view class="list"> |
||||
<view class="list-item"> |
||||
<view class="date">2025.6.15</view> |
||||
<view class="progress">13</view> |
||||
</view> |
||||
</view> |
||||
</view> |