191 changed files with 14256 additions and 1789 deletions
@ -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 @@ |
|||||||
|
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,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,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,247 @@ |
|||||||
|
@import "./theme/iconfont.wxss"; |
||||||
|
@import "./theme/theme-default.wxss"; |
||||||
|
@import "./theme/theme-elegant.wxss"; |
||||||
|
@import "./theme/theme-nuohe.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 @@ |
|||||||
|
/* * |
||||||
|
@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 @@ |
|||||||
|
export {}; |
||||||
@ -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,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 @@ |
|||||||
|
/** |
||||||
|
* @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 @@ |
|||||||
|
/** |
||||||
|
* @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 @@ |
|||||||
|
export {}; |
||||||
@ -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 @@ |
|||||||
|
export {}; |
||||||
@ -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 |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1 @@ |
|||||||
|
export {}; |
||||||
@ -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 @@ |
|||||||
|
/** |
||||||
|
* @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,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 @@ |
|||||||
|
/** |
||||||
|
* @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 @@ |
|||||||
|
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 @@ |
|||||||
|
@font-face { |
||||||
|
font-family: 'iconfont'; |
||||||
|
src: url(data:font/truetype;charset=utf-8;base64,AAEAAAANAIAAAwBQRkZUTYda3jUAAAfEAAAAHEdERUYAKQANAAAHpAAAAB5PUy8yPllJ4AAAAVgAAABWY21hcAAP65kAAAHIAAABQmdhc3D//wADAAAHnAAAAAhnbHlmLotR3AAAAxwAAAGkaGVhZBTU+ykAAADcAAAANmhoZWEHKwOFAAABFAAAACRobXR4DasB4gAAAbAAAAAWbG9jYQC0AR4AAAMMAAAAEG1heHABEwAyAAABOAAAACBuYW1lKeYRVQAABMAAAAKIcG9zdEoLnOYAAAdIAAAAUgABAAAAAQAAiPM8al8PPPUACwQAAAAAANjbW5YAAAAA2NtblgCzAAQDTQL8AAAACAACAAAAAAAAAAEAAAOA/4AAXAQAAAAAAANNAAEAAAAAAAAAAAAAAAAAAAAEAAEAAAAHACYAAgAAAAAAAgAAAAoACgAAAP8AAAAAAAAAAQQAAZAABQAAAokCzAAAAI8CiQLMAAAB6wAyAQgAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZABA5+vn7gOA/4AAXAOAAIAAAAABAAAAAAAABAAAAAAAAAAEAAAABAABLgD4ALQAswAAAAAAAwAAAAMAAAAcAAEAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAA5+7//wAA5+v//xgYAAEAAAAAAAABBgAAAQAAAAAAAAABAgAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJgBMAI4A0gABAS4ABAMKAvwAEgAACQEmBh0BFBcJAQYdARQWNwE2NAL+/j0ECQYBaP6YBgkEAcMMAZkBYAMEBU0IBf7n/ucFCE0FBAMBYAoeAAAAAQD4AAQC1AL8ABIAAAE1NCYHAQYUFwEWNj0BNCcJATYC1AkE/j0MDAHDBAkG/pgBaAYCpk0FBAP+oAoeCv6gAwQFTQgFARkBGQUAAAIAtAAgA00C4AASACUAAAkBNiYrASIHAwYUFwEWOwEyNicTATYmKwEiBwMGFBcBFjsBMjYnAREBCQMEBU0IBf8HBwD/BQhNBQQDJwEJAwQFTQgF/wcHAP8FCE0FBAMBgAFTBAkG/roJFgn+ugYJBAFTAVMECQb+ugkWCf66BgkEAAAAAAIAswAgA0wC4AASACUAAAEDJisBIgYXCQEGFjsBMjcBNjQlAyYrASIGFwkBBhY7ATI3ATY0AhX/BQhNBQQDAQn+9wMEBU0IBQD/BwEp/wUITQUEAwEJ/vcDBAVNCAUA/wcBlAFGBgkE/q3+rQQJBgFGCRYJAUYGCQT+rf6tBAkGAUYJFgAAAAAAABIA3gABAAAAAAAAABUALAABAAAAAAABAAgAVAABAAAAAAACAAcAbQABAAAAAAADAAgAhwABAAAAAAAEAAgAogABAAAAAAAFAAsAwwABAAAAAAAGAAgA4QABAAAAAAAKACsBQgABAAAAAAALABMBlgADAAEECQAAACoAAAADAAEECQABABAAQgADAAEECQACAA4AXQADAAEECQADABAAdQADAAEECQAEABAAkAADAAEECQAFABYAqwADAAEECQAGABAAzwADAAEECQAKAFYA6gADAAEECQALACYBbgAKAEMAcgBlAGEAdABlAGQAIABiAHkAIABpAGMAbwBuAGYAbwBuAHQACgAACkNyZWF0ZWQgYnkgaWNvbmZvbnQKAABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABSAGUAZwB1AGwAYQByAABSZWd1bGFyAABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABWAGUAcgBzAGkAbwBuACAAMQAuADAAAFZlcnNpb24gMS4wAABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABHAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAHMAdgBnADIAdAB0AGYAIABmAHIAbwBtACAARgBvAG4AdABlAGwAbABvACAAcAByAG8AagBlAGMAdAAuAABHZW5lcmF0ZWQgYnkgc3ZnMnR0ZiBmcm9tIEZvbnRlbGxvIHByb2plY3QuAABoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAABodHRwOi8vZm9udGVsbG8uY29tAAACAAAAAAAAAAoAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAcAAAABAAIBAgEDAQQBBQVyaWdodARsZWZ0CmRvdWJsZWxlZnQLZG91YmxlcmlnaHQAAAAAAAH//wACAAEAAAAMAAAAFgAAAAIAAQADAAYAAQAEAAAAAgAAAAAAAAABAAAAANWkJwgAAAAA2NtblgAAAADY21uW) 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 @@ |
|||||||
|
|
||||||
|
/* 日历主要颜色相关样式 */ |
||||||
|
|
||||||
|
.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 @@ |
|||||||
|
.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 @@ |
|||||||
|
/* 日历主要颜色相关样式 */ |
||||||
|
|
||||||
|
.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,iVBORw0KGgoAAAANSUhEUgAAACwAAABACAYAAABhspUgAAAAAXNSR0IArs4c6QAACAVJREFUaEPtmltsHFcZx/9nZu92bMdJSMitzoWkoXVKUrVV8wKk4gHxgJTwgKA8lhfgCZBoUJEqUYGA0AhRQUSpFJQIHlyqogZFIipUoKiAKJAYQkp9qR1ir9fe6+zuXM4FfWf2MrOJY+/aS0zlkRxZzsw5v/nP/3znO+c7DItcl4vFTWVl/7wg5EctKSK2knCVBFcKcrGH7vL3MvfwVnYeGbsaustgAAODCSDCDLU1Hp/Ym+o7fnrvB9+9U3NssT5ezWe+k5X8qwvCQ0FwVKSEswJg6sfmHH+cm2l0SZ3Tj8F84ChjiDID+1I9ly4ceuTjbQFfyM2MpDk/meEu8oKjJIUG9khh1YHEtUeupgPAWl3AAENEwzLEmIGd8dToq8OPDbcF/OLCrZFZ7p5Mcxc5wVEUAmQLT8mOLFHvfCwzF7ZEC3CcGdiRSIxeHD7WHvDZhZsjM56ngbMELDlsWVO4c4ExOd8E9i1R969vhzhj2BFPjv76cJvApPCtkMK8YYkVOALLUXh7PNE+8M/Iw553MiN8S1ii6eGVAI+mZ0PfhzHoAWfWBlyMMWyPJ0dfG368PUu8nJ8bWRD8ZPYOUWIlwH+YmQ4Dg8FoAPu22J5Ijb7ywKPtAV8uZZ/LC36qIH11q7UIIZRCp8CW5+Ly7M3bgVkzUlC0ONC74VcvHTj6ybaiBN38RmVhV9YxTBs2nrl08VTRrjy1gvEGZRh+HGu5epOp808ceehMFFEkDYN/f++Df1+sn0UnjtYHjB9+63tQ6ssrAV70WcZOyy8+/ZXltL0o8Hfzk3u4jc94Bh7nSm0uOZWNruvFozBMkzEG+iF3KGm5XJTAZFVIxRXCjnGkNB0pIwXPTWYcu6/MeYLAgh1HozHeE48VE6Y5vyFiXknFoufO73/4nWVZ4kwmc9BG5QVLiONcKSYYEFU0z/vd1P3rQaEiBYiwnSvr2Jgo5mFxTz9Gcbj+AjTjmczPKbbF41fej9jnzz5w9J/B9kMKP58e/1xO4ayjZNKlwaUUkqYJJZsDjRKfBcH1dN3pRa3dKpUwX61oqRs5RS1amLWpOmWYzv5k7xfO3X/0p/W+GsBnMtNPLQjvx1UlDUcKQDEkDKanYRJR6W+tMM0dzPPOYYMvmauWkStXfOBA1kYxWecWMJAwDHV/T9+Xzh088kLDSmfmpx9b8Lw3qpDxqv7MCilmaFBJ/9aMmZYcY05VK78aFw2DrGXBdp2AymSLQDIEAynD9B4c3PKRnwwduqIV/ubc5N+Kgj9EnqQEhxIQ+iwyEHPJIm+WSxBMj7TV4NX+lVIiXyzURGCg/NjP3ijdNEAzH/FsjcX/dWn42CH2g+zMJ9Ju5bWyFDrnFQB6GMGSur4N6Bpzq5hwnVUBbW2kWq3CcXyV6QoMvgZwghk43Dtwgn17burlrHBPaGAlEQFDnN68Bku41NDvrQLsVVK2FZhzAcsqNYCpP/rCZA2tsGGAgIeSvRfZs3Pj0wUhdpZr028vo/cj4OaHJ+WvVIpdUbfeaKHg26KpMoU3P7cgaALeHIun2TPpcaskeE9ZSp0v9DPTjwoB4Cytx+xyV4FLxSKE9FeL9TDnZ3D+KoSA+yIRm52aGVOWEiBLVKXEoBHRdtDRoXbNcQ9XuwxMliBrhIBr8VgDGwxJZoI9TcCSo6wkHCmxUQOHV8Zz3MVVu9JVha2SBR6YjCjlrK/1tCUMwwf+WgDYrQGLlsC1VoDJFiHgoMLBSLsWgClSJOvAJdncd6hbYi0B08DzLVFTeB24g+F5t0G3rnAHgt72yLrC93LieO952ARHVDWXQQVuYbqaWQ2rLtrGVJmhEljR6pyRFqS1fIKS+LjB/JmuNQ7vlrMYUs1dxp3udRwrvdJV4GedJ3BDbl6yj1UFdgsJVNMbQp0mt5UQ67OXBLknwOO/OILi2KYQXN++Bez99F/XJvA75x+G9e7GEFzvfTnsf/Iv68CNKhFla50OujWtsD3fA2tyMPSpM3/eBSebCv0tPljBlkfCm9i9Q1kkNofXiF0fdJO/HEb++tYlvXmnGwYOpTF04lrov7oOPDFyGIUb7+sIuP9gBns+Fd6zXgdunen+7xT+z28OIPOn3R1ZYsujU9jxsbf/tx6m3pQMVxzGLhyFNdUycezOYd9n3wrBMeP23c+ue/hO0q7pOLwOfC/Sy1uvfwDZa9tC4g8Oz2L78X8vOTjviYeXpLrLDSsC3qqy2KZyjeYH3EnsKf92JTxLPvti9UOYkv233eefWKEqE52rWGSJFNx9pxbu9Wbge2/VvOYVru/Ar+UN7cb+8FosGTRrz35RpulhE+zrs1TjoKKMf5BuIzN1cTFYRcpwD6NOd2scxRIVZZqbN/q0la7sN6tIumTwjdlxXUWqCAIW6KeiTMtxxXnh4boTPoK4ZJxq84ZssQgvAEwl3HpVXyusK0kG2HNzk/mSEP0VJfS5NCosKjq7USuAU15lKYkbXa4i3czlwOkUQe0KAtfrzf2RqMVOZ6Z+VxD8w1RUJEtElV9JDx4Ipd8nXFtX+btxOULg7ay/d9eohDL/tFX9PCZB70qk3mQ/ys0M5T3nWlXKXqrYcyaRpFtrRw7qiPQyRa3Aso8JLevdqAg/mptHwW1uZ9XPYxIwiUc/GyLRyuH+LcO6d4KuCv5SRYojrpQDFIcjMLTp60dcdMJel6D1YM+y0MI3uUIg57n4RyGLoueGE/xar2SLHsO0NsXi13b1DDz5/H0Hxv8Lo3UyF0Y2DrcAAAAASUVORK5CYII="); |
||||||
|
} |
||||||
|
|
||||||
|
.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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
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,271 @@ |
|||||||
|
import WxCanvas from './wx-canvas'; |
||||||
|
|
||||||
|
let ctx; |
||||||
|
let echarts; |
||||||
|
|
||||||
|
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 () { |
||||||
|
echarts = await require.async('../../gift/compontnts/echart/echarts.js'); |
||||||
|
// 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) { |
||||||
|
echarts = await require.async('../../gift/compontnts/echart/echarts.js'); |
||||||
|
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 @@ |
|||||||
|
{ |
||||||
|
"component": true, |
||||||
|
"usingComponents": {} |
||||||
|
} |
||||||
@ -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 @@ |
|||||||
|
.ec-canvas { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
z-index: 1; |
||||||
|
} |
||||||
@ -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 |
||||||
|
} |
||||||
|
} |
||||||
@ -1,176 +1,176 @@ |
|||||||
const app = getApp(); |
const app = getApp(); |
||||||
import dayjs from "dayjs"; |
import dayjs from "dayjs"; |
||||||
Component({ |
Component({ |
||||||
behaviors: [], |
behaviors: [], |
||||||
properties: { |
properties: { |
||||||
audio: { |
audio: { |
||||||
type: Object, |
type: Object, |
||||||
observer(val) { |
observer(val) { |
||||||
if (this.audioContext) { |
if (this.audioContext) { |
||||||
const { play } = this.data; |
const { play } = this.data; |
||||||
if (play) { |
if (play) { |
||||||
this.audioContext.pause(); |
this.audioContext.pause(); |
||||||
this.setData({ |
this.setData({ |
||||||
play: false, |
play: false, |
||||||
progress: 0, |
progress: 0, |
||||||
time: "00", |
time: "00", |
||||||
}); |
}); |
||||||
} |
} |
||||||
this.audioContext.destroy(); |
this.audioContext.destroy(); |
||||||
} |
} |
||||||
if (val) { |
if (val) { |
||||||
this.audioAddEventListener(val); |
this.audioAddEventListener(val); |
||||||
} |
} |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
data: { |
data: { |
||||||
Timestamp: app.globalData.Timestamp, |
Timestamp: app.globalData.Timestamp, |
||||||
progress: 0, |
progress: 0, |
||||||
time: "00", |
time: "00", |
||||||
duration: "00", |
duration: "00", |
||||||
play: false, |
play: false, |
||||||
loading: true, |
loading: true, |
||||||
|
|
||||||
imageUrl: app.globalData.imageUrl, |
imageUrl: app.globalData.imageUrl, |
||||||
progressimg: true, |
progressimg: true, |
||||||
}, |
}, |
||||||
lifetimes: { |
lifetimes: { |
||||||
created() {}, |
created() {}, |
||||||
async attached() {}, |
async attached() {}, |
||||||
moved() {}, |
moved() {}, |
||||||
detached() { |
detached() { |
||||||
if (this.audioContext) { |
if (this.audioContext) { |
||||||
const { play } = this.data; |
const { play } = this.data; |
||||||
if (play) { |
if (play) { |
||||||
this.audioContext.pause(); |
this.audioContext.pause(); |
||||||
} |
} |
||||||
this.audioContext.destroy(); |
this.audioContext.destroy(); |
||||||
} |
} |
||||||
this.audioAddEventListener = null; |
this.audioAddEventListener = null; |
||||||
this.setData({ |
this.setData({ |
||||||
play: false, |
play: false, |
||||||
progress: 0, |
progress: 0, |
||||||
time: "00", |
time: "00", |
||||||
}); |
}); |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
pageLifetimes: { |
pageLifetimes: { |
||||||
// 组件所在页面的生命周期函数
|
// 组件所在页面的生命周期函数
|
||||||
show: function () {}, |
show: function () {}, |
||||||
hide: function () { |
hide: function () { |
||||||
const { play } = this.data; |
const { play } = this.data; |
||||||
if (play) { |
if (play) { |
||||||
this.audioContext.pause(); |
this.audioContext.pause(); |
||||||
} |
} |
||||||
}, |
}, |
||||||
resize: function () {}, |
resize: function () {}, |
||||||
}, |
}, |
||||||
methods: { |
methods: { |
||||||
togglePlay() { |
togglePlay() { |
||||||
const { play, loading } = this.data; |
const { play, loading } = this.data; |
||||||
if (loading) { |
if (loading) { |
||||||
wx.showToast({ |
wx.showToast({ |
||||||
title: "音频加载中", |
title: "音频加载中", |
||||||
icon: "none", |
icon: "none", |
||||||
}); |
}); |
||||||
return; |
return; |
||||||
} |
} |
||||||
if (play) { |
if (play) { |
||||||
this.audioContext.pause(); |
this.audioContext.pause(); |
||||||
} else { |
} else { |
||||||
this.audioContext.play(); |
this.audioContext.play(); |
||||||
} |
} |
||||||
}, |
}, |
||||||
formatTime(time) { |
formatTime(time) { |
||||||
let m = parseInt(time / 60); |
let m = parseInt(time / 60); |
||||||
let s = parseInt(time % 60); |
let s = parseInt(time % 60); |
||||||
return this.towNum(m) + ":" + this.towNum(s); |
return this.towNum(m) + ":" + this.towNum(s); |
||||||
}, |
}, |
||||||
towNum(num) { |
towNum(num) { |
||||||
if (num >= 10) { |
if (num >= 10) { |
||||||
return num; |
return num; |
||||||
} else { |
} else { |
||||||
return "0" + num; |
return "0" + num; |
||||||
} |
} |
||||||
}, |
}, |
||||||
audioAddEventListener(val) { |
audioAddEventListener(val) { |
||||||
const that = this; |
const that = this; |
||||||
this.setData({ |
this.setData({ |
||||||
duration: this.formatTime(val.size), |
duration: this.formatTime(val.size), |
||||||
}); |
}); |
||||||
that.audioContext = wx.createInnerAudioContext(); |
that.audioContext = wx.createInnerAudioContext(); |
||||||
that.audioContext.src = val.url; |
that.audioContext.src = val.url; |
||||||
that.setData({ |
that.setData({ |
||||||
loading: false, |
loading: false, |
||||||
}); |
}); |
||||||
that.audioContext.onError(({ errCode, ...reset }) => { |
that.audioContext.onError(({ errCode, ...reset }) => { |
||||||
console.log("reset: ", reset); |
console.log("reset: ", reset); |
||||||
console.log("errCode: ", errCode); |
console.log("errCode: ", errCode); |
||||||
if (errCode === 10004 || errCode == 10001 || errCode == -1) { |
if (errCode === 10004 || errCode == 10001 || errCode == -1) { |
||||||
that.audioContext.destroy(); |
that.audioContext.destroy(); |
||||||
that.setData({ |
that.setData({ |
||||||
loading: true, |
loading: true, |
||||||
}); |
}); |
||||||
setTimeout(() => { |
setTimeout(() => { |
||||||
that.audioAddEventListener(val); |
that.audioAddEventListener(val); |
||||||
}, 300); |
}, 300); |
||||||
} |
} |
||||||
}); |
}); |
||||||
that.audioContext.onPlay(() => { |
that.audioContext.onPlay(() => { |
||||||
that.setData({ |
that.setData({ |
||||||
play: true, |
play: true, |
||||||
}); |
}); |
||||||
}); |
}); |
||||||
that.audioContext.onPause(() => { |
that.audioContext.onPause(() => { |
||||||
console.log(1111111); |
console.log(1111111); |
||||||
that.setData({ |
that.setData({ |
||||||
play: false, |
play: false, |
||||||
}); |
}); |
||||||
}); |
}); |
||||||
that.audioContext.onEnded(() => { |
that.audioContext.onEnded(() => { |
||||||
that.audioContext.seek(0); |
that.audioContext.seek(0); |
||||||
that.setData({ |
that.setData({ |
||||||
play: false, |
play: false, |
||||||
progress: 0, |
progress: 0, |
||||||
time: "00", |
time: "00", |
||||||
}); |
}); |
||||||
}); |
}); |
||||||
that.audioContext.onTimeUpdate(() => { |
that.audioContext.onTimeUpdate(() => { |
||||||
const duration = that.audioContext.duration || 0; |
const duration = that.audioContext.duration || 0; |
||||||
const currentTime = that.audioContext.currentTime || 0; |
const currentTime = that.audioContext.currentTime || 0; |
||||||
const progress = (currentTime / duration) * 100; |
const progress = (currentTime / duration) * 100; |
||||||
if (duration == Infinity) { |
if (duration == Infinity) { |
||||||
return; |
return; |
||||||
} |
} |
||||||
that.setData({ |
that.setData({ |
||||||
play: true, |
play: true, |
||||||
duration: that.formatTime(duration), |
duration: that.formatTime(duration), |
||||||
time: that.formatTime(currentTime), |
time: that.formatTime(currentTime), |
||||||
}); |
}); |
||||||
if (that.data.progressimg) { |
if (that.data.progressimg) { |
||||||
this.setData({ |
this.setData({ |
||||||
progress: progress, |
progress: progress, |
||||||
}); |
}); |
||||||
} |
} |
||||||
}); |
}); |
||||||
}, |
}, |
||||||
handleAuthChangeimg() { |
handleAuthChangeimg() { |
||||||
console.log(11111); |
console.log(11111); |
||||||
this.setData({ |
this.setData({ |
||||||
progressimg: false, |
progressimg: false, |
||||||
}); |
}); |
||||||
}, |
}, |
||||||
handleAuthChange(e) { |
handleAuthChange(e) { |
||||||
console.log(22222222222); |
console.log(22222222222); |
||||||
let { duration } = this.data; |
let { duration } = this.data; |
||||||
const secods = this.audioContext.duration || duration.split(":")[0] * 60 + duration.split(":")[1] * 1; |
const secods = this.audioContext.duration || duration.split(":")[0] * 60 + duration.split(":")[1] * 1; |
||||||
const progress = e.detail.value; |
const progress = e.detail.value; |
||||||
let seek = ((secods / 100) * progress).toFixed(3) * 1; |
let seek = ((secods / 100) * progress).toFixed(3) * 1; |
||||||
this.audioContext.seek(seek); |
this.audioContext.seek(seek); |
||||||
this.setData({ |
this.setData({ |
||||||
progressimg: true, |
progressimg: true, |
||||||
}); |
}); |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
}); |
}); |
||||||
|
|||||||
@ -1,26 +1,28 @@ |
|||||||
<view class="audio"> |
<view class="audio"> |
||||||
<view class="card-auth"> |
<view class="card-auth"> |
||||||
<image |
<image |
||||||
class="icon extend-via-pseudo-elem" |
class="icon extend-via-pseudo-elem" |
||||||
src="{{imageUrl}}1/audio-{{play?'pause':'play'}}.png?t={{Timestamp}}" |
src="{{imageUrl}}za-images/1/audio-{{play?'pause':'play'}}.png?t={{Timestamp}}" |
||||||
catchtap="togglePlay" |
catchtap="togglePlay" |
||||||
></image> |
></image> |
||||||
<view |
<view class="center"> |
||||||
class="center" |
<image |
||||||
> |
class="progress-bg" |
||||||
<image class="progress-bg" mode="aspectFill" src="https://m.zd.hbraas.com/zd/1/firee-audio-bg.png?t=1689998782161"></image> |
mode="aspectFill" |
||||||
<slider |
src="https://m.zd.hbraas.com/zd/1/firee-audio-bg.png?t=1689998782161" |
||||||
active |
></image> |
||||||
activeColor="#E04775" |
<slider |
||||||
backgroundColor="#E04775" |
active |
||||||
bind:changing="handleAuthChangeimg" |
activeColor="#E04775" |
||||||
bindchange="handleAuthChange" |
backgroundColor="#E04775" |
||||||
block-color="#E04775" |
bind:changing="handleAuthChangeimg" |
||||||
block-size="12" |
bindchange="handleAuthChange" |
||||||
class="progress" |
block-color="#E04775" |
||||||
value="{{progress}}" |
block-size="12" |
||||||
/> |
class="progress" |
||||||
</view> |
value="{{progress}}" |
||||||
<text class="time" wx:if="{{duration}}">{{duration}}</text> |
/> |
||||||
</view> |
</view> |
||||||
</view> |
<text class="time" wx:if="{{duration}}">{{duration}}</text> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
|||||||
@ -1,7 +1,7 @@ |
|||||||
<van-nav-bar title="" custom-style="background:transparent;"> |
<van-nav-bar title="" custom-style="background:transparent;"> |
||||||
<view class="navbar" slot="left"> |
<view class="navbar" slot="left"> |
||||||
<van-icon wx:if="{{back}}" class="back-icon" name="arrow-left" color="#333333" size="22" bind:tap="handleBack" /> |
<van-icon wx:if="{{back}}" class="back-icon" name="arrow-left" color="#333333" size="22" bind:tap="handleBack" /> |
||||||
<image wx:if="{{drug}}" class="drug-nav-img" src="{{imageUrl}}1.5/page-title.png?t={{Timestamp}}"></image> |
<image wx:if="{{drug}}" class="drug-nav-img" src="{{imageUrl}}za-images/1.5/page-title.png?t={{Timestamp}}"></image> |
||||||
<image wx:else class="nav-img" src="{{imageUrl}}1/page-title.png?t={{Timestamp}}"></image> |
<image wx:else class="nav-img" src="{{imageUrl}}za-images/1/page-title.png?t={{Timestamp}}"></image> |
||||||
</view> |
</view> |
||||||
</van-nav-bar> |
</van-nav-bar> |
||||||
|
|||||||
@ -0,0 +1,7 @@ |
|||||||
|
{ |
||||||
|
"component": true, |
||||||
|
"usingComponents": { |
||||||
|
"van-tabbar": "@vant/weapp/tabbar/index", |
||||||
|
"van-tabbar-item": "@vant/weapp/tabbar-item/index" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,19 @@ |
|||||||
|
/* custom-tab-bar/index.wxss */ |
||||||
|
|
||||||
|
|
||||||
|
.tab-item { |
||||||
|
.icon { |
||||||
|
width: 50rpx; |
||||||
|
height: 50rpx; |
||||||
|
} |
||||||
|
.name { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #CCCCCC; |
||||||
|
&.active{ |
||||||
|
color: #CF5375; |
||||||
|
} |
||||||
|
&.drug-active{ |
||||||
|
color: #25D9C8; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,113 @@ |
|||||||
|
import { getCurrentPageUrl } from '@/utils/util'; |
||||||
|
const app = getApp(); |
||||||
|
|
||||||
|
Component({ |
||||||
|
properties: {}, |
||||||
|
data: { |
||||||
|
imageUrl: app.globalData.imageUrl, |
||||||
|
isChild: 0, |
||||||
|
active: 0, |
||||||
|
list: [ |
||||||
|
{ |
||||||
|
pagePath: '/patient/pages/index/index', |
||||||
|
text: '首页', |
||||||
|
icon: 'home', |
||||||
|
iconActive: 'home-active', |
||||||
|
}, |
||||||
|
{ |
||||||
|
pagePath: '/patient/pages/repository/index', |
||||||
|
text: 'MG全知道', |
||||||
|
icon: 'story', |
||||||
|
iconActive: 'story-active', |
||||||
|
}, |
||||||
|
{ |
||||||
|
pagePath: '/patient/pages/live/index', |
||||||
|
text: '周三大咖说', |
||||||
|
icon: 'gift', |
||||||
|
iconActive: 'gift-active', |
||||||
|
}, |
||||||
|
{ |
||||||
|
pagePath: '/patient/pages/story/index', |
||||||
|
text: '向往的生活', |
||||||
|
icon: 'class', |
||||||
|
iconActive: 'class-active', |
||||||
|
}, |
||||||
|
{ |
||||||
|
pagePath: '/patient/pages/my/index', |
||||||
|
text: '我的', |
||||||
|
icon: 'my', |
||||||
|
iconActive: 'my-active', |
||||||
|
}, |
||||||
|
], |
||||||
|
userInfo: {}, |
||||||
|
showRed: false, |
||||||
|
anyWhere: false, |
||||||
|
|
||||||
|
config: {} as any, |
||||||
|
}, |
||||||
|
observers: {}, |
||||||
|
lifetimes: { |
||||||
|
ready() { |
||||||
|
app.zdGetTheme().then((res) => { |
||||||
|
this.setData({ |
||||||
|
theme: res, |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
const pagePath = getCurrentPageUrl(); |
||||||
|
const active = this.data.list.findIndex((item) => item.pagePath === pagePath); |
||||||
|
this.setData({ |
||||||
|
active, |
||||||
|
anyWhere: app.globalData.anyWhere, |
||||||
|
}); |
||||||
|
this.setData({ |
||||||
|
showRed: app.globalData.showRed, |
||||||
|
}); |
||||||
|
// getApp().registerListener(() => {
|
||||||
|
// this.setData({
|
||||||
|
// anyWhere: app.globalData.anyWhere,
|
||||||
|
// });
|
||||||
|
// wx.ajax({
|
||||||
|
// method: 'GET',
|
||||||
|
// url: '?r=zd/common/get-config',
|
||||||
|
// }).then((res) => {
|
||||||
|
// this.setData({
|
||||||
|
// config: res,
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
}, |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
onChange() {}, |
||||||
|
handleNav(e) { |
||||||
|
const { index } = e.currentTarget.dataset; |
||||||
|
const { list, config } = this.data; |
||||||
|
const pagePath = list[index].pagePath; |
||||||
|
app.globalData.BeginnerCardId = ''; |
||||||
|
this.setData({ |
||||||
|
anyWhere: app.globalData.anyWhere, |
||||||
|
}); |
||||||
|
if (pagePath == '/patient/pages/my/index') { |
||||||
|
app.zdPermissionVerification(2, 0, `/patient/pages/index/index`).then(() => { |
||||||
|
wx.reLaunch({ |
||||||
|
url: pagePath, |
||||||
|
}); |
||||||
|
}); |
||||||
|
} else if (pagePath == '/patient/pages/repository/index' && config.picTextEbookStatus == 1) { |
||||||
|
app.zdPermissionVerification(2, 0, `/pages/repository/index`).then(() => { |
||||||
|
const webviewUrl = encodeURIComponent( |
||||||
|
`${app.globalData.url}/zdcare/#/cover?loginState=${app.globalData.loginState}`, |
||||||
|
); |
||||||
|
wx.navigateTo({ |
||||||
|
url: `/patient/pages/webview/index?url=${webviewUrl}`, |
||||||
|
}); |
||||||
|
}); |
||||||
|
} else { |
||||||
|
wx.reLaunch({ |
||||||
|
url: pagePath, |
||||||
|
}); |
||||||
|
} |
||||||
|
}, |
||||||
|
}, |
||||||
|
}); |
||||||
@ -0,0 +1,16 @@ |
|||||||
|
<van-tabbar active="{{ active }}" active-color="#CF5375" bind:change="onChange" inactive-color="#CCCCCC"> |
||||||
|
<block wx:for="{{list}}" wx:key="*this"> |
||||||
|
<van-tabbar-item |
||||||
|
class="tab-item" |
||||||
|
wx:if="{{ index != 3 || !anyWhere}}" |
||||||
|
bind:tap="handleNav" |
||||||
|
data-index="{{index}}" |
||||||
|
icon="{{imageUrl}}za-images/tabbar/{{active==index ? (theme === 'DRUG' ? 'drug-' :'' ) + item.iconActive: item.icon}}.png" |
||||||
|
> |
||||||
|
<!-- <image class="icon" mode="aspectFit" slot="icon" src="{{imageUrl}}/tabbar/{{item.icon}}.png" /> --> |
||||||
|
<!-- <image class="icon" mode="aspectFit" slot="icon-active" src="{{imageUrl}}/tabbar/{{item.iconActive}}.png" /> --> |
||||||
|
<view class="name {{index==active && (theme === 'DRUG' ? 'drug-active' :'active')}}">{{item.text}}</view> |
||||||
|
<view class="hot"></view> |
||||||
|
</van-tabbar-item> |
||||||
|
</block> |
||||||
|
</van-tabbar> |
||||||
@ -1,204 +1,204 @@ |
|||||||
const app = getApp(); |
const app = getApp(); |
||||||
/** |
/** |
||||||
* >=min && <=max |
* >=min && <=max |
||||||
* @param min |
* @param min |
||||||
* @param max |
* @param max |
||||||
*/ |
*/ |
||||||
function getRandom(min, max) { |
function getRandom(min, max) { |
||||||
return min + Math.floor(Math.random() * (max - min + 1)); |
return min + Math.floor(Math.random() * (max - min + 1)); |
||||||
} |
} |
||||||
Component({ |
Component({ |
||||||
options: {}, |
options: {}, |
||||||
lifetimes: { |
lifetimes: { |
||||||
attached() { |
attached() { |
||||||
const query = wx.createSelectorQuery().in(this); |
const query = wx.createSelectorQuery().in(this); |
||||||
query |
query |
||||||
.select("#thumsCanvas") |
.select("#thumsCanvas") |
||||||
.fields({ node: true, size: true }) |
.fields({ node: true, size: true }) |
||||||
.exec((res) => { |
.exec((res) => { |
||||||
const canvas = res[0].node; |
const canvas = res[0].node; |
||||||
const context = canvas.getContext("2d"); |
const context = canvas.getContext("2d"); |
||||||
this.setData({ |
this.setData({ |
||||||
context: context, |
context: context, |
||||||
}); |
}); |
||||||
|
|
||||||
const dpr = wx.getSystemInfoSync().pixelRatio; |
const dpr = wx.getSystemInfoSync().pixelRatio; |
||||||
canvas.width = res[0].width * dpr; |
canvas.width = res[0].width * dpr; |
||||||
canvas.height = res[0].height * dpr; |
canvas.height = res[0].height * dpr; |
||||||
this.data.width = res[0].width * dpr; |
this.data.width = res[0].width * dpr; |
||||||
this.data.height = res[0].height * dpr; |
this.data.height = res[0].height * dpr; |
||||||
// context.fillStyle = "rgba(255, 255, 255, 0)";
|
// context.fillStyle = "rgba(255, 255, 255, 0)";
|
||||||
const images = [ |
const images = [ |
||||||
"star/icon1.png", |
"za-images/star/icon1.png", |
||||||
"star/icon2.png", |
"za-images/star/icon2.png", |
||||||
"star/icon3.png", |
"za-images/star/icon3.png", |
||||||
"star/icon4.png", |
"za-images/star/icon4.png", |
||||||
"star/icon5.png", |
"za-images/star/icon5.png", |
||||||
"star/icon6.png", |
"za-images/star/icon6.png", |
||||||
"star/icon7.png", |
"za-images/star/icon7.png", |
||||||
"star/icon8.png", |
"za-images/star/icon8.png", |
||||||
]; |
]; |
||||||
const promiseAll = [] as Array<Promise<any>>; |
const promiseAll = [] as Array<Promise<any>>; |
||||||
images.forEach((src) => { |
images.forEach((src) => { |
||||||
const p = new Promise(function (resolve) { |
const p = new Promise(function (resolve) { |
||||||
const img = canvas.createImage(); |
const img = canvas.createImage(); |
||||||
img.onerror = img.onload = resolve.bind(null, img); |
img.onerror = img.onload = resolve.bind(null, img); |
||||||
img.src = app.globalData.imageUrl + src; |
img.src = app.globalData.imageUrl + src; |
||||||
}); |
}); |
||||||
promiseAll.push(p); |
promiseAll.push(p); |
||||||
}); |
}); |
||||||
Promise.all(promiseAll).then((imgsList) => { |
Promise.all(promiseAll).then((imgsList) => { |
||||||
const imgsLists = imgsList.filter((d) => { |
const imgsLists = imgsList.filter((d) => { |
||||||
if (d && d.width > 0) return true; |
if (d && d.width > 0) return true; |
||||||
return false; |
return false; |
||||||
}); |
}); |
||||||
this.setData({ |
this.setData({ |
||||||
imgsList: imgsLists, |
imgsList: imgsLists, |
||||||
}); |
}); |
||||||
if (this.data.imgsList.length == 0) { |
if (this.data.imgsList.length == 0) { |
||||||
// logger.error("imgsList load all error");
|
// logger.error("imgsList load all error");
|
||||||
wx.showToast({ |
wx.showToast({ |
||||||
icon: "none", |
icon: "none", |
||||||
title: "imgsList load all error", |
title: "imgsList load all error", |
||||||
}); |
}); |
||||||
return; |
return; |
||||||
} |
} |
||||||
}); |
}); |
||||||
}); |
}); |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
properties: {}, |
properties: {}, |
||||||
data: { |
data: { |
||||||
imgsList: [] as WechatMiniprogram.ImageData[], |
imgsList: [] as WechatMiniprogram.ImageData[], |
||||||
width: 0, |
width: 0, |
||||||
height: 0, |
height: 0, |
||||||
context: null as any, |
context: null as any, |
||||||
scanning: false, |
scanning: false, |
||||||
renderList: [], |
renderList: [], |
||||||
scaleTime: 0.1, // 百分比
|
scaleTime: 0.1, // 百分比
|
||||||
}, |
}, |
||||||
methods: { |
methods: { |
||||||
handleTap() { |
handleTap() { |
||||||
this.start(); |
this.start(); |
||||||
}, |
}, |
||||||
createRender() { |
createRender() { |
||||||
if (this.data.imgsList.length == 0) return null; |
if (this.data.imgsList.length == 0) return null; |
||||||
const basicScale = [0.6, 0.9, 1.2][getRandom(0, 2)]; |
const basicScale = [0.6, 0.9, 1.2][getRandom(0, 2)]; |
||||||
|
|
||||||
const getScale = (diffTime) => { |
const getScale = (diffTime) => { |
||||||
if (diffTime < this.data.scaleTime) { |
if (diffTime < this.data.scaleTime) { |
||||||
return +(diffTime / this.data.scaleTime).toFixed(2) * basicScale; |
return +(diffTime / this.data.scaleTime).toFixed(2) * basicScale; |
||||||
} else { |
} else { |
||||||
return basicScale; |
return basicScale; |
||||||
} |
} |
||||||
}; |
}; |
||||||
const context = this.data.context; |
const context = this.data.context; |
||||||
// 随机读取一个图片来渲染
|
// 随机读取一个图片来渲染
|
||||||
const image: any = this.data.imgsList[getRandom(0, this.data.imgsList.length - 1)]; |
const image: any = this.data.imgsList[getRandom(0, this.data.imgsList.length - 1)]; |
||||||
const offset = 20; |
const offset = 20; |
||||||
const basicX = this.data.width / 2 + getRandom(-offset, offset); |
const basicX = this.data.width / 2 + getRandom(-offset, offset); |
||||||
const angle = getRandom(2, 10); |
const angle = getRandom(2, 10); |
||||||
let ratio = getRandom(10, 30) * (getRandom(0, 1) ? 1 : -1); |
let ratio = getRandom(10, 30) * (getRandom(0, 1) ? 1 : -1); |
||||||
const getTranslateX = (diffTime) => { |
const getTranslateX = (diffTime) => { |
||||||
if (diffTime < this.data.scaleTime) { |
if (diffTime < this.data.scaleTime) { |
||||||
// 放大期间,不进行摇摆位移
|
// 放大期间,不进行摇摆位移
|
||||||
return basicX; |
return basicX; |
||||||
} else { |
} else { |
||||||
return basicX + ratio * Math.sin(angle * (diffTime - this.data.scaleTime)); |
return basicX + ratio * Math.sin(angle * (diffTime - this.data.scaleTime)); |
||||||
} |
} |
||||||
}; |
}; |
||||||
|
|
||||||
const getTranslateY = (diffTime) => { |
const getTranslateY = (diffTime) => { |
||||||
return image.height / 2 + (this.data.height - image.height / 2) * (1 - diffTime); |
return image.height / 2 + (this.data.height - image.height / 2) * (1 - diffTime); |
||||||
}; |
}; |
||||||
|
|
||||||
const fadeOutStage = getRandom(14, 18) / 100; |
const fadeOutStage = getRandom(14, 18) / 100; |
||||||
const getAlpha = (diffTime) => { |
const getAlpha = (diffTime) => { |
||||||
let left = 1 - +diffTime; |
let left = 1 - +diffTime; |
||||||
if (left > fadeOutStage) { |
if (left > fadeOutStage) { |
||||||
return 1; |
return 1; |
||||||
} else { |
} else { |
||||||
return 1 - +((fadeOutStage - left) / fadeOutStage).toFixed(2); |
return 1 - +((fadeOutStage - left) / fadeOutStage).toFixed(2); |
||||||
} |
} |
||||||
}; |
}; |
||||||
|
|
||||||
return (diffTime) => { |
return (diffTime) => { |
||||||
// 差值满了,即结束了 0 ---》 1
|
// 差值满了,即结束了 0 ---》 1
|
||||||
if (diffTime >= 1) return true; |
if (diffTime >= 1) return true; |
||||||
context.save(); |
context.save(); |
||||||
const scale = getScale(diffTime); |
const scale = getScale(diffTime); |
||||||
// const rotate = getRotate();
|
// const rotate = getRotate();
|
||||||
const translateX = getTranslateX(diffTime); |
const translateX = getTranslateX(diffTime); |
||||||
const translateY = getTranslateY(diffTime); |
const translateY = getTranslateY(diffTime); |
||||||
context.translate(translateX, translateY); |
context.translate(translateX, translateY); |
||||||
context.scale(scale, scale); |
context.scale(scale, scale); |
||||||
// context.rotate(rotate * Math.PI / 180);
|
// context.rotate(rotate * Math.PI / 180);
|
||||||
context.globalAlpha = getAlpha(diffTime); |
context.globalAlpha = getAlpha(diffTime); |
||||||
context.drawImage(image, -image.width / 2, -image.height / 2, image.width, image.height); |
context.drawImage(image, -image.width / 2, -image.height / 2, image.width, image.height); |
||||||
context.restore(); |
context.restore(); |
||||||
}; |
}; |
||||||
}, |
}, |
||||||
scan() { |
scan() { |
||||||
this.data.context.clearRect(0, 0, this.data.width, this.data.height); |
this.data.context.clearRect(0, 0, this.data.width, this.data.height); |
||||||
this.data.context.fillStyle = "rgba(255, 255, 255, 0)"; |
this.data.context.fillStyle = "rgba(255, 255, 255, 0)"; |
||||||
this.data.context.fillRect(0, 0, 200, 400); |
this.data.context.fillRect(0, 0, 200, 400); |
||||||
let index = 0; |
let index = 0; |
||||||
let length = this.data.renderList.length; |
let length = this.data.renderList.length; |
||||||
if (length > 0) { |
if (length > 0) { |
||||||
this.requestFrame(this.scan.bind(this)); |
this.requestFrame(this.scan.bind(this)); |
||||||
this.setData({ |
this.setData({ |
||||||
scanning: true, |
scanning: true, |
||||||
}); |
}); |
||||||
} else { |
} else { |
||||||
this.setData({ |
this.setData({ |
||||||
scanning: false, |
scanning: false, |
||||||
}); |
}); |
||||||
} |
} |
||||||
while (index < length) { |
while (index < length) { |
||||||
const child = this.data.renderList[index]; |
const child = this.data.renderList[index]; |
||||||
if (!child || !child.render || child.render.call(null, (Date.now() - child.timestamp) / child.duration)) { |
if (!child || !child.render || child.render.call(null, (Date.now() - child.timestamp) / child.duration)) { |
||||||
// 结束了,删除该动画
|
// 结束了,删除该动画
|
||||||
this.setData({ |
this.setData({ |
||||||
renderList: [...this.data.renderList].filter((_item, fIndex) => fIndex != index), |
renderList: [...this.data.renderList].filter((_item, fIndex) => fIndex != index), |
||||||
}); |
}); |
||||||
length--; |
length--; |
||||||
} else { |
} else { |
||||||
// continue
|
// continue
|
||||||
index++; |
index++; |
||||||
} |
} |
||||||
} |
} |
||||||
}, |
}, |
||||||
start() { |
start() { |
||||||
const render = this.createRender(); |
const render = this.createRender(); |
||||||
const duration = getRandom(1500, 3000); |
const duration = getRandom(1500, 3000); |
||||||
this.setData({ |
this.setData({ |
||||||
renderList: [ |
renderList: [ |
||||||
...this.data.renderList, |
...this.data.renderList, |
||||||
{ |
{ |
||||||
render, |
render, |
||||||
duration, |
duration, |
||||||
timestamp: Date.now(), |
timestamp: Date.now(), |
||||||
}, |
}, |
||||||
], |
], |
||||||
}); |
}); |
||||||
|
|
||||||
if (!this.data.scanning) { |
if (!this.data.scanning) { |
||||||
this.setData({ |
this.setData({ |
||||||
scanning: true, |
scanning: true, |
||||||
}); |
}); |
||||||
|
|
||||||
this.requestFrame(this.scan.bind(this)); |
this.requestFrame(this.scan.bind(this)); |
||||||
// this.scan.bind(this)();
|
// this.scan.bind(this)();
|
||||||
} |
} |
||||||
return this; |
return this; |
||||||
}, |
}, |
||||||
requestFrame(cb) { |
requestFrame(cb) { |
||||||
return ( |
return ( |
||||||
this.data.context.requestAnimationFrame || |
this.data.context.requestAnimationFrame || |
||||||
(function (callback) { |
(function (callback) { |
||||||
setTimeout(callback, 1000 / 60); |
setTimeout(callback, 1000 / 60); |
||||||
})(cb) |
})(cb) |
||||||
); |
); |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
}); |
}); |
||||||
|
|||||||
@ -1,139 +1,139 @@ |
|||||||
const app = getApp() |
const app = getApp(); |
||||||
Component({ |
Component({ |
||||||
properties: { |
properties: { |
||||||
show: { |
show: { |
||||||
type: Boolean, |
type: Boolean, |
||||||
value: false, |
value: false, |
||||||
}, |
}, |
||||||
type: String, |
type: String, |
||||||
params: { |
params: { |
||||||
type: Object, |
type: Object, |
||||||
value() { |
value() { |
||||||
return {} |
return {}; |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
observers: { |
observers: { |
||||||
show(val) { |
show(val) { |
||||||
if (val) { |
if (val) { |
||||||
app.getTheme().then((res) => { |
app.zdGetTheme().then((res) => { |
||||||
this.setData({ |
this.setData({ |
||||||
theme: res, |
theme: res, |
||||||
}) |
}); |
||||||
}) |
}); |
||||||
if (this.data.params.timeOut) { |
if (this.data.params.timeOut) { |
||||||
let time = this.data.params.timeOut |
let time = this.data.params.timeOut; |
||||||
const timerFunc = () => { |
const timerFunc = () => { |
||||||
if (time <= 0) { |
if (time <= 0) { |
||||||
this.setData({ |
this.setData({ |
||||||
timeOut: '', |
timeOut: '', |
||||||
}) |
}); |
||||||
clearInterval(this.timer) |
clearInterval(this.timer); |
||||||
return |
return; |
||||||
} |
} |
||||||
this.setData({ |
this.setData({ |
||||||
timeOut: `${time}s`, |
timeOut: `${time}s`, |
||||||
}) |
}); |
||||||
--time |
--time; |
||||||
} |
}; |
||||||
timerFunc() |
timerFunc(); |
||||||
this.timer = setInterval(timerFunc, 1000) |
this.timer = setInterval(timerFunc, 1000); |
||||||
} |
} |
||||||
if (['storyLead', 'storyStar', 'storyShare'].includes(this.data.type)) { |
if (['storyLead', 'storyStar', 'storyShare'].includes(this.data.type)) { |
||||||
this.getSettingInfo() |
this.getSettingInfo(); |
||||||
} |
} |
||||||
} |
} |
||||||
this.setData({ |
this.setData({ |
||||||
userInfo: app.globalData.userInfo, |
zdUserInfo: app.globalData.zdUserInfo, |
||||||
}) |
}); |
||||||
}, |
}, |
||||||
type(val) { |
type(val) { |
||||||
if (val === 'healthCare') { |
if (val === 'healthCare') { |
||||||
this.getOpenPatientList() |
this.getOpenPatientList(); |
||||||
} |
} |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
data: { |
data: { |
||||||
imageUrl: '', |
imageUrl: '', |
||||||
protocol: true, |
protocol: true, |
||||||
timeOut: '', |
timeOut: '', |
||||||
settingsInfo: {}, |
settingsInfo: {}, |
||||||
userInfo: {}, |
zdUserInfo: {}, |
||||||
openPatientList: {}, |
openPatientList: {}, |
||||||
}, |
}, |
||||||
lifetimes: { |
lifetimes: { |
||||||
attached() { |
attached() { |
||||||
this.setData({ |
this.setData({ |
||||||
imageUrl: app.globalData.imageUrl, |
imageUrl: app.globalData.imageUrl, |
||||||
Timestamp: app.globalData.Timestamp, |
Timestamp: app.globalData.Timestamp, |
||||||
}) |
}); |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
methods: { |
methods: { |
||||||
timer: null as any, |
timer: null as any, |
||||||
handleOk() { |
handleOk() { |
||||||
if (this.data.timeOut) { |
if (this.data.timeOut) { |
||||||
return |
return; |
||||||
} |
} |
||||||
this.triggerEvent('ok', { protocol: this.data.protocol }) |
this.triggerEvent('ok', { protocol: this.data.protocol }); |
||||||
}, |
}, |
||||||
handleCancel(e = { currentTarget: { dataset: { key: '' } } }) { |
handleCancel(e = { currentTarget: { dataset: { key: '' } } }) { |
||||||
const { key } = e.currentTarget.dataset |
const { key } = e.currentTarget.dataset; |
||||||
if (this.timer) { |
if (this.timer) { |
||||||
clearInterval(this.timer) |
clearInterval(this.timer); |
||||||
this.setData({ |
this.setData({ |
||||||
timeOut: '', |
timeOut: '', |
||||||
}) |
}); |
||||||
} |
} |
||||||
this.triggerEvent('cancel', { key }) |
this.triggerEvent('cancel', { key }); |
||||||
}, |
}, |
||||||
handleTaskCancel() { |
handleTaskCancel() { |
||||||
this.triggerEvent('taskCancel') |
this.triggerEvent('taskCancel'); |
||||||
}, |
}, |
||||||
handleJump() { |
handleJump() { |
||||||
this.triggerEvent('jump') |
this.triggerEvent('jump'); |
||||||
}, |
}, |
||||||
handleDel() { |
handleDel() { |
||||||
this.triggerEvent('del') |
this.triggerEvent('del'); |
||||||
}, |
}, |
||||||
routerTo(e) { |
routerTo(e) { |
||||||
const { path } = e.currentTarget.dataset |
const { path } = e.currentTarget.dataset; |
||||||
wx.navigateTo({ |
wx.navigateTo({ |
||||||
url: path, |
url: path, |
||||||
}) |
}); |
||||||
this.handleCancel() |
this.handleCancel(); |
||||||
}, |
}, |
||||||
getSettingInfo() { |
getSettingInfo() { |
||||||
wx.ajax({ |
wx.ajax({ |
||||||
method: 'GET', |
method: 'GET', |
||||||
url: '?r=xd/drugs/setting-info', |
url: '?r=xd/drugs/setting-info', |
||||||
data: {}, |
data: {}, |
||||||
}).then((res) => { |
}).then((res) => { |
||||||
this.setData({ |
this.setData({ |
||||||
settingsInfo: res, |
settingsInfo: res, |
||||||
}) |
}); |
||||||
}) |
}); |
||||||
}, |
}, |
||||||
getOpenPatientList() { |
getOpenPatientList() { |
||||||
wx.ajax({ |
wx.ajax({ |
||||||
method: 'GET', |
method: 'GET', |
||||||
url: '?r=xd/nrdl/open-patient-list', |
url: '?r=xd/nrdl/open-patient-list', |
||||||
data: {}, |
data: {}, |
||||||
}).then((res) => { |
}).then((res) => { |
||||||
this.setData({ |
this.setData({ |
||||||
openPatientList: res, |
openPatientList: res, |
||||||
}) |
}); |
||||||
}) |
}); |
||||||
}, |
}, |
||||||
handleProtocolChange() { |
handleProtocolChange() { |
||||||
this.setData({ |
this.setData({ |
||||||
protocol: !this.data.protocol, |
protocol: !this.data.protocol, |
||||||
}) |
}); |
||||||
}, |
}, |
||||||
handleAdlQuestion() { |
handleAdlQuestion() { |
||||||
wx.navigateTo({ |
wx.navigateTo({ |
||||||
url: '/pages/repositoryDetail/index?id=9', |
url: '/pages/repositoryDetail/index?id=9', |
||||||
}) |
}); |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
}) |
}); |
||||||
|
|||||||
@ -0,0 +1,61 @@ |
|||||||
|
// components/viewFile/index.js
|
||||||
|
const app = getApp(); |
||||||
|
Component({ |
||||||
|
/** |
||||||
|
* 组件的属性列表 |
||||||
|
*/ |
||||||
|
properties: { |
||||||
|
fileList: { |
||||||
|
type: Array, |
||||||
|
value: [], |
||||||
|
}, |
||||||
|
// 是否可以删除
|
||||||
|
canDelete: { |
||||||
|
type: Boolean, |
||||||
|
value: false, |
||||||
|
}, |
||||||
|
// 是否可以下载
|
||||||
|
canDownLoad: { |
||||||
|
type: Boolean, |
||||||
|
value: false, |
||||||
|
}, |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* 组件的初始数据 |
||||||
|
*/ |
||||||
|
data: { |
||||||
|
Timestamp: app.globalData.Timestamp, |
||||||
|
imageUrl: app.globalData.imageUrl, |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* 组件的方法列表 |
||||||
|
*/ |
||||||
|
methods: { |
||||||
|
deleteFile(e) { |
||||||
|
const { index, item } = e.currentTarget.dataset; |
||||||
|
this.triggerEvent("deleteFile", { |
||||||
|
index, |
||||||
|
item, |
||||||
|
}); |
||||||
|
}, |
||||||
|
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, |
||||||
|
}); |
||||||
|
}, |
||||||
|
}, |
||||||
|
}); |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
{ |
||||||
|
"component": true, |
||||||
|
"usingComponents": { |
||||||
|
"van-icon": "@vant/weapp/icon/index" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
<!-- components/viewFile/index.wxml --> |
||||||
|
<view class="page"> |
||||||
|
<view class="item mar" 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" color="rgba(0,0,0,0.6)" size="32rpx" /> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
@ -0,0 +1,48 @@ |
|||||||
|
/* components/viewFile/index.wxss */ |
||||||
|
.page{ |
||||||
|
display: flex; |
||||||
|
flex-wrap: wrap; |
||||||
|
} |
||||||
|
.item{ |
||||||
|
width: 144rpx; |
||||||
|
height: 144rpx; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
.item .image{ |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
border-radius: 12rpx; |
||||||
|
} |
||||||
|
.clear{ |
||||||
|
width: 32rpx; |
||||||
|
height: 32rpx; |
||||||
|
background: #fff; |
||||||
|
position: absolute; |
||||||
|
right: -16rpx; |
||||||
|
top: -16rpx; |
||||||
|
border-radius: 100%; |
||||||
|
overflow: hidden; |
||||||
|
font-size: 0; |
||||||
|
} |
||||||
|
.mar{ |
||||||
|
margin-right: 16rpx; |
||||||
|
margin-bottom: 16rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.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; |
||||||
|
} |
||||||
@ -0,0 +1,66 @@ |
|||||||
|
/* eslint-disable */ |
||||||
|
const app = getApp(); |
||||||
|
Component({ |
||||||
|
behaviors: ["wx://form-field"], |
||||||
|
externalClasses: ["my-class"], |
||||||
|
properties: { |
||||||
|
src: { |
||||||
|
type: String, |
||||||
|
value: "", |
||||||
|
}, |
||||||
|
poster: { |
||||||
|
type: String, |
||||||
|
value: "", |
||||||
|
}, |
||||||
|
ViewNum: { |
||||||
|
type: Number, |
||||||
|
value: "", |
||||||
|
}, |
||||||
|
autoplay: { |
||||||
|
type: Boolean, |
||||||
|
value: false, |
||||||
|
}, |
||||||
|
}, |
||||||
|
observers: { |
||||||
|
autoplay(val) { |
||||||
|
if (val) { |
||||||
|
this.setData({ |
||||||
|
play: true, |
||||||
|
}); |
||||||
|
} |
||||||
|
}, |
||||||
|
}, |
||||||
|
relations: {}, |
||||||
|
data: { |
||||||
|
Timestamp: app.globalData.Timestamp, |
||||||
|
play: false, |
||||||
|
imageUrl: app.globalData.imageUrl, |
||||||
|
}, |
||||||
|
lifetimes: { |
||||||
|
created() {}, |
||||||
|
attached() {}, |
||||||
|
detached() {}, |
||||||
|
error() {}, |
||||||
|
}, |
||||||
|
pageLifetimes: { |
||||||
|
show() {}, |
||||||
|
hide() {}, |
||||||
|
resize() {}, |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
hanldePlay() { |
||||||
|
console.log(1111111111); |
||||||
|
const videoContext = wx.createVideoContext("video", this); |
||||||
|
videoContext.play(); |
||||||
|
this.setData({ |
||||||
|
play: true, |
||||||
|
}); |
||||||
|
}, |
||||||
|
handlePause() { |
||||||
|
console.log(11111111); |
||||||
|
this.setData({ |
||||||
|
play: false, |
||||||
|
}); |
||||||
|
}, |
||||||
|
}, |
||||||
|
}); |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
{ |
||||||
|
"component": true, |
||||||
|
"usingComponents": {} |
||||||
|
} |
||||||
@ -0,0 +1,46 @@ |
|||||||
|
.video { |
||||||
|
height: 388rpx; |
||||||
|
position: relative; |
||||||
|
overflow: hidden; |
||||||
|
.video-context { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
} |
||||||
|
.play { |
||||||
|
position: absolute; |
||||||
|
left: 50%; |
||||||
|
top: 50%; |
||||||
|
z-index: 10; |
||||||
|
transform: translate(-50%, -50%); |
||||||
|
width: 96rpx; |
||||||
|
height: 96rpx; |
||||||
|
} |
||||||
|
.status-bar { |
||||||
|
position: absolute; |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
width: 100%; |
||||||
|
padding: 0 48rpx; |
||||||
|
box-sizing: border-box; |
||||||
|
height: 78rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
flex-direction: row-reverse; |
||||||
|
background: linear-gradient(180deg, rgba(0, 0, 0, 0.02) 0%, #000000 100%); |
||||||
|
>view,>image{ |
||||||
|
margin-right: 32rpx; |
||||||
|
}; |
||||||
|
transition: all 0.8s; |
||||||
|
.time { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
.start { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
} |
||||||
|
.hide { |
||||||
|
transform: translateY(100%); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
<view class="video"> |
||||||
|
<video |
||||||
|
class="video-context" |
||||||
|
id="video" |
||||||
|
controls="{{play}}" |
||||||
|
autoplay="{{autoplay}}" |
||||||
|
catch:pause="handlePause" |
||||||
|
show-center-play-btn="{{false}}" |
||||||
|
poster="{{poster}}" |
||||||
|
object-fit="cover" |
||||||
|
src="{{src}}" |
||||||
|
></video> |
||||||
|
<image |
||||||
|
wx:if="{{!play}}" |
||||||
|
class="play" |
||||||
|
bind:tap="hanldePlay" |
||||||
|
src="{{imageUrl}}za-images/video-play.png?t={{Timestamp}}" |
||||||
|
></image> |
||||||
|
<view class="status-bar {{play && 'hide'}}"> |
||||||
|
</view> |
||||||
|
</view> |
||||||
@ -0,0 +1,46 @@ |
|||||||
|
.video { |
||||||
|
height: 388rpx; |
||||||
|
position: relative; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
.video .video-context { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
} |
||||||
|
.video .play { |
||||||
|
position: absolute; |
||||||
|
left: 50%; |
||||||
|
top: 50%; |
||||||
|
z-index: 10; |
||||||
|
transform: translate(-50%, -50%); |
||||||
|
width: 96rpx; |
||||||
|
height: 96rpx; |
||||||
|
} |
||||||
|
.video .status-bar { |
||||||
|
position: absolute; |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
width: 100%; |
||||||
|
padding: 0 48rpx; |
||||||
|
box-sizing: border-box; |
||||||
|
height: 78rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
flex-direction: row-reverse; |
||||||
|
background: linear-gradient(180deg, rgba(0, 0, 0, 0.02) 0%, #000000 100%); |
||||||
|
>view,>image{ |
||||||
|
margin-right: 32rpx; |
||||||
|
}; |
||||||
|
transition: all 0.8s; |
||||||
|
} |
||||||
|
.video .status-bar .time { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
.video .status-bar .start { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
.video .hide { |
||||||
|
transform: translateY(100%); |
||||||
|
} |
||||||
@ -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,8 @@ |
|||||||
|
{ |
||||||
|
"component": true, |
||||||
|
"usingComponents": { |
||||||
|
"van-icon": "@vant/weapp/icon/index", |
||||||
|
"van-image": "@vant/weapp/image/index", |
||||||
|
"viewFile": "/components/viewFile/index" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,20 @@ |
|||||||
|
<!-- components/uploadFile/index.wxml --> |
||||||
|
<view class="page"> |
||||||
|
<view class="item mar" 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="clearBox" catchtap="deleteFile" data-item="{{item}}" data-index="{{index}}"> |
||||||
|
<view class="clear"> |
||||||
|
<van-icon name="{{imageUrl}}za-images/1/upload-del.png" color="#A09D9D" size="46rpx" /> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view wx:if="{{upload && (maxNum === -1 || maxNum > fileList.length)}}" catchtap="selectFile"> |
||||||
|
<slot wx:if="{{isSlot}}"></slot> |
||||||
|
<view wx:else class="btn mar"> |
||||||
|
<van-icon name="{{imageUrl}}za-images/1/upload-icon.png" color="#A09D9D" size="60rpx" /> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
@ -0,0 +1,77 @@ |
|||||||
|
/* components/uploadFile/index.wxss */ |
||||||
|
.page { |
||||||
|
display: flex; |
||||||
|
flex-wrap: wrap; |
||||||
|
} |
||||||
|
|
||||||
|
.btn { |
||||||
|
width: 180rpx; |
||||||
|
height: 180rpx; |
||||||
|
background: #fff; |
||||||
|
border-radius: 12rpx; |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
background-color: #F8F8F8; |
||||||
|
} |
||||||
|
|
||||||
|
.btn .text { |
||||||
|
color: #9E9999; |
||||||
|
font-size: 24rpx; |
||||||
|
line-height: 34prx; |
||||||
|
margin-top: 16rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.item { |
||||||
|
width: 180rpx; |
||||||
|
height: 180rpx; |
||||||
|
position: relative; |
||||||
|
line-height: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.item .image { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
border-radius: 12rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.clearBox { |
||||||
|
position: absolute; |
||||||
|
right: -22rpx; |
||||||
|
top: -28rpx; |
||||||
|
padding: 10rpx; |
||||||
|
z-index: 9; |
||||||
|
} |
||||||
|
|
||||||
|
.clear { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
background: #fff; |
||||||
|
border-radius: 100%; |
||||||
|
overflow: hidden; |
||||||
|
font-size: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.mar { |
||||||
|
margin-right: 18rpx; |
||||||
|
margin-bottom: 26rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.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; |
||||||
|
} |
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,6 @@ |
|||||||
|
{ |
||||||
|
"navigationBarTitleText": "确认订单", |
||||||
|
"usingComponents": { |
||||||
|
"van-icon": "@vant/weapp/icon/index" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,184 @@ |
|||||||
|
.page { |
||||||
|
padding: 34rpx 40rpx; |
||||||
|
.site { |
||||||
|
padding: 40rpx 32rpx; |
||||||
|
background: #ffffff; |
||||||
|
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05); |
||||||
|
border-radius: 24rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
.wrap { |
||||||
|
.title { |
||||||
|
.label { |
||||||
|
width: 72rpx; |
||||||
|
height: 36rpx; |
||||||
|
border: 1rpx solid #e04775; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #e04775; |
||||||
|
text-align: center; |
||||||
|
border-radius: 10rpx; |
||||||
|
box-sizing: border-box; |
||||||
|
} |
||||||
|
.name { |
||||||
|
margin-top: -42rpx; |
||||||
|
text-indent: 80rpx; |
||||||
|
font-size: 36rpx; |
||||||
|
line-height: 46rpx; |
||||||
|
color: #3f3f3f; |
||||||
|
font-weight: bold; |
||||||
|
min-width: 0; |
||||||
|
overflow: hidden; |
||||||
|
text-overflow: ellipsis; |
||||||
|
display: -webkit-box; |
||||||
|
-webkit-line-clamp: 2; |
||||||
|
-webkit-box-orient: vertical; |
||||||
|
&.no-indent { |
||||||
|
margin-top: 0; |
||||||
|
text-indent: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.content { |
||||||
|
margin-top: 0; |
||||||
|
margin-top: 12rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #b6b7ba; |
||||||
|
} |
||||||
|
} |
||||||
|
.more { |
||||||
|
flex-shrink: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
.shop { |
||||||
|
margin-top: 16px; |
||||||
|
padding: 40rpx 32rpx; |
||||||
|
background: #ffffff; |
||||||
|
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05); |
||||||
|
border-radius: 24rpx; |
||||||
|
.shop-header { |
||||||
|
padding-bottom: 10px; |
||||||
|
display: flex; |
||||||
|
.shop-img { |
||||||
|
flex-shrink: 0; |
||||||
|
width: 204rpx; |
||||||
|
height: 204rpx; |
||||||
|
border-radius: 24rpx; |
||||||
|
} |
||||||
|
.wrap { |
||||||
|
padding-top: 8rpx; |
||||||
|
flex: 1; |
||||||
|
padding-left: 24rpx; |
||||||
|
.name { |
||||||
|
font-size: 32rpx; |
||||||
|
font-weight: bold; |
||||||
|
color: #3f3f3f; |
||||||
|
line-height: 44rpx; |
||||||
|
min-width: 0; |
||||||
|
overflow: hidden; |
||||||
|
text-overflow: ellipsis; |
||||||
|
display: -webkit-box; |
||||||
|
-webkit-line-clamp: 2; |
||||||
|
-webkit-box-orient: vertical; |
||||||
|
} |
||||||
|
.specification { |
||||||
|
margin-top: 8rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #b6b7ba; |
||||||
|
} |
||||||
|
.price { |
||||||
|
margin-top: 14rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
.num { |
||||||
|
font-size: 32rpx; |
||||||
|
color: #3f3f3f; |
||||||
|
} |
||||||
|
.sub { |
||||||
|
font-size: 22rpx; |
||||||
|
} |
||||||
|
.val { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #b6b7ba; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.row { |
||||||
|
margin-top: 32rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
.label { |
||||||
|
font-size: 32rpx; |
||||||
|
color: #3f3f3f; |
||||||
|
} |
||||||
|
.content { |
||||||
|
font-size: 32rpx; |
||||||
|
color: #3f3f3f; |
||||||
|
&.yellow { |
||||||
|
color: #e04775; |
||||||
|
} |
||||||
|
.sub { |
||||||
|
font-size: 22rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.remark { |
||||||
|
margin-top: 16px; |
||||||
|
padding: 40rpx 32rpx; |
||||||
|
background: #ffffff; |
||||||
|
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05); |
||||||
|
border-radius: 24rpx; |
||||||
|
.title { |
||||||
|
font-size: 32rpx; |
||||||
|
color: #3f3f3f; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
.textarea { |
||||||
|
margin-top: 10rpx; |
||||||
|
padding: 24rpx 32rpx; |
||||||
|
background-color: #fafafa; |
||||||
|
min-height: 196rpx; |
||||||
|
border-radius: 16rpx; |
||||||
|
box-sizing: border-box; |
||||||
|
} |
||||||
|
} |
||||||
|
.footer { |
||||||
|
padding: 24rpx 48rpx 48rpx; |
||||||
|
position: fixed; |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
width: 100vw; |
||||||
|
box-sizing: border-box; |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
height: 168rpx; |
||||||
|
background: #ffffff; |
||||||
|
box-shadow: 0rpx 8rpx 20rpx 0rpx rgba(0, 0, 0, 0.26); |
||||||
|
.price { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #b6b7ba; |
||||||
|
.num { |
||||||
|
font-size: 40rpx; |
||||||
|
color: #e04775; |
||||||
|
} |
||||||
|
.sub { |
||||||
|
font-size: 24rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.submit { |
||||||
|
width: 260rpx; |
||||||
|
height: 96rpx; |
||||||
|
background: #e04775; |
||||||
|
border-radius: 48rpx; |
||||||
|
text-align: center; |
||||||
|
line-height: 96rpx; |
||||||
|
color: #fff; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,86 @@ |
|||||||
|
const app = getApp<IAppOption>(); |
||||||
|
|
||||||
|
Page({ |
||||||
|
data: { |
||||||
|
id: "", |
||||||
|
detail: {}, |
||||||
|
select: false, |
||||||
|
addressDetail: {} as any, |
||||||
|
remark: "", |
||||||
|
}, |
||||||
|
onLoad(options) { |
||||||
|
this.setData({ |
||||||
|
id: options.id, |
||||||
|
}); |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
app.waitLogin().then(() => { |
||||||
|
this.getDetail(); |
||||||
|
if (!this.data.select) { |
||||||
|
this.getDefaultAddress(); |
||||||
|
} else { |
||||||
|
this.setData({ |
||||||
|
select: false, |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
}, |
||||||
|
getDefaultAddress() { |
||||||
|
wx.ajax({ |
||||||
|
method: "GET", |
||||||
|
url: "?r=zd/patient-address/get-default-address", |
||||||
|
data: {}, |
||||||
|
}).then((res) => { |
||||||
|
this.setData({ |
||||||
|
addressDetail: res, |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
getDetail() { |
||||||
|
wx.ajax({ |
||||||
|
method: "GET", |
||||||
|
url: "?r=zd/gift-order/get-order-detail", |
||||||
|
data: { |
||||||
|
orderId: this.data.id, |
||||||
|
}, |
||||||
|
}).then((res) => { |
||||||
|
this.setData({ |
||||||
|
detail: res, |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleSite() { |
||||||
|
if (this.data.addressDetail) { |
||||||
|
wx.navigateTo({ |
||||||
|
url: "/gift/pages/siteList/index", |
||||||
|
}); |
||||||
|
} else { |
||||||
|
wx.navigateTo({ |
||||||
|
url: "/gift/pages/siteEdit/index", |
||||||
|
}); |
||||||
|
} |
||||||
|
}, |
||||||
|
handleSubmit() { |
||||||
|
if (!this.data.addressDetail?.addressId) { |
||||||
|
wx.showToast({ |
||||||
|
icon: "none", |
||||||
|
title: "请选择地址", |
||||||
|
}); |
||||||
|
return; |
||||||
|
} |
||||||
|
wx.ajax({ |
||||||
|
method: "POST", |
||||||
|
url: "?r=zd/gift-order/confirm-order", |
||||||
|
data: { |
||||||
|
orderId: this.data.id, |
||||||
|
addressId: this.data.addressDetail.addressId, |
||||||
|
remark: this.data.remark, |
||||||
|
}, |
||||||
|
loading: true, |
||||||
|
}).then(() => { |
||||||
|
wx.reLaunch({ |
||||||
|
url: `/gift/pages/orderEnd/index?id=${this.data.id}`, |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
}); |
||||||
@ -0,0 +1,56 @@ |
|||||||
|
<view class="page"> |
||||||
|
<view class="site" bind:tap="handleSite"> |
||||||
|
<view class="wrap"> |
||||||
|
<block wx:if="{{addressDetail}}"> |
||||||
|
<view class="title"> |
||||||
|
<view class="label" wx:if="{{addressDetail.isDefault==1}}">默认</view> |
||||||
|
<view class="name {{addressDetail.isDefault!=1 && 'no-indent'}}"> |
||||||
|
{{addressDetail.provinceName}}{{addressDetail.cityName}}{{addressDetail.countyName}}{{addressDetail.address}} |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="content">{{addressDetail.receiveUserName}} {{addressDetail.receiveTelephone}}</view> |
||||||
|
</block> |
||||||
|
<view class="title" wx:else>请添加收货地址</view> |
||||||
|
</view> |
||||||
|
<van-icon class="more" name="arrow" /> |
||||||
|
</view> |
||||||
|
<view class="shop"> |
||||||
|
<view class="shop-header"> |
||||||
|
<image class="shop-img" src="{{detail.giftBigImg}}"></image> |
||||||
|
<view class="wrap"> |
||||||
|
<view class="name">{{detail.giftName}}</view> |
||||||
|
<view class="specification" wx:if="{{detail.specName}}">规格:{{detail.specName}}</view> |
||||||
|
<view class="price"> |
||||||
|
<view class="num">{{detail.giftScore}}<text class="sub">能量</text></view> |
||||||
|
<view class="val">x{{detail.orderCount}}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="row"> |
||||||
|
<view class="label">礼品总价</view> |
||||||
|
<view class="content yellow">{{detail.orderScore}}<text class="sub">能量</text></view> |
||||||
|
</view> |
||||||
|
<view class="row" > |
||||||
|
<view class="label">配送方式</view> |
||||||
|
<view class="content" style="font-weight:normal">快递配送</view> |
||||||
|
</view> |
||||||
|
<view class="row" > |
||||||
|
<view class="label">商家电话</view> |
||||||
|
<view class="content" style="font-weight:normal">{{detail.serviceTel}}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="remark"> |
||||||
|
<view class="title">留言</view> |
||||||
|
<textarea class="textarea" model:value="{{remark}}" placeholder="请输入留言" auto-height></textarea> |
||||||
|
</view> |
||||||
|
<view class="footer"> |
||||||
|
<view class="price"> |
||||||
|
共{{detail.orderCount}}件 |
||||||
|
<view> |
||||||
|
合计消耗 |
||||||
|
<text class="num">{{detail.orderScore}}<text class="sub">能量</text></text> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="submit" bind:tap="handleSubmit">提交订单</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
{ |
||||||
|
"navigationBarTitleText": "皮下剂型", |
||||||
|
"usingComponents": {} |
||||||
|
} |
||||||
@ -0,0 +1,63 @@ |
|||||||
|
page { |
||||||
|
background-color: #f7f6f7; |
||||||
|
} |
||||||
|
.page { |
||||||
|
.page1 { |
||||||
|
height: 869rpx; |
||||||
|
} |
||||||
|
.page2 { |
||||||
|
position: relative; |
||||||
|
height: 630rpx; |
||||||
|
.mg-video { |
||||||
|
position: absolute; |
||||||
|
top: 290rpx; |
||||||
|
right: 60rpx; |
||||||
|
width: 600rpx; |
||||||
|
height: 288rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.page3 { |
||||||
|
position: relative; |
||||||
|
height: 782rpx; |
||||||
|
.cidp-mask { |
||||||
|
position: absolute; |
||||||
|
top: 174rpx; |
||||||
|
right: 30rpx; |
||||||
|
z-index: 1; |
||||||
|
width: 74rpx; |
||||||
|
height: 304rpx; |
||||||
|
} |
||||||
|
.cidp-list { |
||||||
|
position: absolute; |
||||||
|
top: 184rpx; |
||||||
|
right: 30rpx; |
||||||
|
width: 632rpx; |
||||||
|
height: 288rpx; |
||||||
|
overflow-x: auto; |
||||||
|
overflow-y: hidden; |
||||||
|
display: flex; |
||||||
|
gap: 16rpx; |
||||||
|
.cidp-item { |
||||||
|
flex-shrink: 0; |
||||||
|
width: 216rpx; |
||||||
|
height: 288rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.page4 { |
||||||
|
height: 302rpx; |
||||||
|
} |
||||||
|
.page5 { |
||||||
|
height: 306rpx; |
||||||
|
} |
||||||
|
.page6 { |
||||||
|
display: block; |
||||||
|
width: 100%; |
||||||
|
height: 574rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#video { |
||||||
|
width: 0; |
||||||
|
height: 0; |
||||||
|
} |
||||||
@ -0,0 +1,65 @@ |
|||||||
|
const _app = getApp<IAppOption>() |
||||||
|
|
||||||
|
Page({ |
||||||
|
data: { |
||||||
|
mg: [ |
||||||
|
{ |
||||||
|
url: 'https://circlehbsaas.oss-cn-beijing.aliyuncs.com/video/20241129469_MG%E4%B8%93%E5%8C%BA%E8%A7%86%E9%A2%9101.mp4', |
||||||
|
}, |
||||||
|
], |
||||||
|
cidp: [ |
||||||
|
{ |
||||||
|
url: 'https://circlehbsaas.oss-cn-beijing.aliyuncs.com/video/20241129233_CIDP%E4%B8%93%E5%8C%BA%E8%A7%86%E9%A2%9101.mp4', |
||||||
|
}, |
||||||
|
{ |
||||||
|
url: 'https://circlehbsaas.oss-cn-beijing.aliyuncs.com/video/20241129667_CIDP%E4%B8%93%E5%8C%BA%E8%A7%86%E9%A2%9103.mp4', |
||||||
|
}, |
||||||
|
{ |
||||||
|
url: 'https://circlehbsaas.oss-cn-beijing.aliyuncs.com/video/20241129630_CIDP%E8%A7%86%E9%A2%91%E4%B8%93%E5%8C%BA02.mp4', |
||||||
|
}, |
||||||
|
{ |
||||||
|
url: 'https://circlehbsaas.oss-cn-beijing.aliyuncs.com/video/20241129281_CIDP%E4%B8%93%E5%8C%BA%E8%A7%86%E9%A2%9104.mp4', |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
videoContext: null as WechatMiniprogram.VideoContext | null, |
||||||
|
onLoad() { |
||||||
|
this.videoContext = wx.createVideoContext('video') |
||||||
|
}, |
||||||
|
onUnload() { |
||||||
|
if (this.videoContext) { |
||||||
|
this.videoContext.stop() |
||||||
|
} |
||||||
|
}, |
||||||
|
handleVideo(e: any) { |
||||||
|
const { key, index } = e.currentTarget.dataset |
||||||
|
const url = this.data[key][index].url |
||||||
|
if (this.videoContext) { |
||||||
|
this.setData({ |
||||||
|
videoUrl: url, |
||||||
|
}) |
||||||
|
this.videoContext.play() |
||||||
|
this.videoContext.requestFullScreen({ |
||||||
|
direction: 0, |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
handleFullScreen(e) { |
||||||
|
if (!e.detail.fullScreen && this.videoContext) { |
||||||
|
this.videoContext.stop() |
||||||
|
} |
||||||
|
}, |
||||||
|
handleDetail(e: any) { |
||||||
|
const { id } = e.currentTarget.dataset |
||||||
|
wx.navigateTo({ |
||||||
|
url: `/gift/pages/cutaneousDetail/index?id=${id}`, |
||||||
|
}) |
||||||
|
}, |
||||||
|
handleVideoDetail() { |
||||||
|
wx.navigateTo({ |
||||||
|
url: `/gift/pages/cutaneousVideo/index`, |
||||||
|
}) |
||||||
|
}, |
||||||
|
}) |
||||||
|
|
||||||
|
export {} |
||||||
@ -0,0 +1,82 @@ |
|||||||
|
<view class="page"> |
||||||
|
<view |
||||||
|
class="page1" |
||||||
|
style="background: url({{imageUrl}}/cutaneous/home1.png?t={{Timestamp}}) no-repeat top center/100%;" |
||||||
|
></view> |
||||||
|
|
||||||
|
<view |
||||||
|
class="page2" |
||||||
|
style="background: url({{imageUrl}}/cutaneous/home2.png?t={{Timestamp}}) no-repeat top center/100%;" |
||||||
|
bind:tap="handleDetail" |
||||||
|
data-id="2" |
||||||
|
> |
||||||
|
<image |
||||||
|
class="mg-video" |
||||||
|
src="{{imageUrl}}/cutaneous/video1-1.png?t={{Timestamp}}" |
||||||
|
data-key="mg" |
||||||
|
data-index="0" |
||||||
|
catch:tap="handleVideo" |
||||||
|
></image> |
||||||
|
</view> |
||||||
|
<view |
||||||
|
class="page3" |
||||||
|
style="background: url({{imageUrl}}/cutaneous/home3.png?t={{Timestamp}}) no-repeat top center/100%;" |
||||||
|
bind:tap="handleDetail" |
||||||
|
data-id="3" |
||||||
|
> |
||||||
|
<image class="cidp-mask" src="{{imageUrl}}/cutaneous/cidp-mask.png?t={{Timestamp}}"></image> |
||||||
|
<view class="cidp-list"> |
||||||
|
<image |
||||||
|
class="cidp-item" |
||||||
|
src="{{imageUrl}}/cutaneous/video2-1.png?t={{Timestamp}}" |
||||||
|
data-key="cidp" |
||||||
|
data-index="0" |
||||||
|
catch:tap="handleVideo" |
||||||
|
></image> |
||||||
|
<image |
||||||
|
class="cidp-item" |
||||||
|
src="{{imageUrl}}/cutaneous/video2-2.png?t={{Timestamp}}" |
||||||
|
data-key="cidp" |
||||||
|
data-index="1" |
||||||
|
catch:tap="handleVideo" |
||||||
|
></image> |
||||||
|
<image |
||||||
|
class="cidp-item" |
||||||
|
src="{{imageUrl}}/cutaneous/video2-3.png?t={{Timestamp}}" |
||||||
|
data-key="cidp" |
||||||
|
data-index="2" |
||||||
|
catch:tap="handleVideo" |
||||||
|
></image> |
||||||
|
<image |
||||||
|
class="cidp-item" |
||||||
|
src="{{imageUrl}}/cutaneous/video2-4.png?t={{Timestamp}}" |
||||||
|
data-key="cidp" |
||||||
|
data-index="3" |
||||||
|
catch:tap="handleVideo" |
||||||
|
></image> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view |
||||||
|
class="page4" |
||||||
|
style="background: url({{imageUrl}}/cutaneous/home4.png?t={{Timestamp}}) no-repeat top center/100%;" |
||||||
|
bind:tap="handleDetail" |
||||||
|
data-id="4" |
||||||
|
></view> |
||||||
|
<view |
||||||
|
class="page5" |
||||||
|
style="background: url({{imageUrl}}/cutaneous/home5.png?t={{Timestamp}}) no-repeat top center/100%;" |
||||||
|
bind:tap="handleDetail" |
||||||
|
data-id="5" |
||||||
|
></view> |
||||||
|
<image class="page6" bind:tap="handleVideoDetail" src="{{imageUrl}}/cutaneous/home6.png?t={{Timestamp}}"></image> |
||||||
|
</view> |
||||||
|
|
||||||
|
<video |
||||||
|
id="video" |
||||||
|
src="{{videoUrl}}" |
||||||
|
loop |
||||||
|
show-play-btn |
||||||
|
play-btn-position="center" |
||||||
|
enable-play-gesture |
||||||
|
bindfullscreenchange="handleFullScreen" |
||||||
|
></video> |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
{ |
||||||
|
"navigationBarTitleText": "皮下剂型", |
||||||
|
"usingComponents": {} |
||||||
|
} |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
.page { |
||||||
|
.card { |
||||||
|
width: 100%; |
||||||
|
display: block; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#video { |
||||||
|
width: 0; |
||||||
|
height: 0; |
||||||
|
} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
const _app = getApp<IAppOption>() |
||||||
|
|
||||||
|
Page({ |
||||||
|
data: { |
||||||
|
list: { |
||||||
|
2: ['2-1', '2-2', '2-3', '2-4'], |
||||||
|
3: ['3-1', '3-2', '3-3', '3-4', '3-5'], |
||||||
|
4: ['4-1', '4-2'], |
||||||
|
5: ['5-1', '5-2', '5-3', '5-4', '5-5'], |
||||||
|
}, |
||||||
|
curentList: [] as any, |
||||||
|
}, |
||||||
|
onLoad(e) { |
||||||
|
if (e.id) { |
||||||
|
this.setData({ |
||||||
|
curentList: this.data.list[e.id], |
||||||
|
}) |
||||||
|
} else { |
||||||
|
this.setData({ |
||||||
|
curentList: this.data.list[2], |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
}) |
||||||
|
|
||||||
|
export {} |
||||||
@ -0,0 +1,9 @@ |
|||||||
|
<view class="page"> |
||||||
|
<image |
||||||
|
class="card" |
||||||
|
mode="widthFix" |
||||||
|
wx:for="{{curentList}}" |
||||||
|
wx:key="index" |
||||||
|
src="{{imageUrl}}/cutaneous/{{item}}.png?t={{Timestamp}}" |
||||||
|
></image> |
||||||
|
</view> |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
{ |
||||||
|
"navigationBarTitleText": "皮下剂型", |
||||||
|
"usingComponents": {} |
||||||
|
} |
||||||
@ -0,0 +1,36 @@ |
|||||||
|
page { |
||||||
|
background: linear-gradient(218deg, #e8bbe7 0%, #ffedf6 26%, #ffedf6 100%); |
||||||
|
} |
||||||
|
.page { |
||||||
|
padding: 408rpx 40rpx 0; |
||||||
|
.container { |
||||||
|
padding: 40rpx 32rpx 42rpx; |
||||||
|
background-color: #fff; |
||||||
|
border-radius: 32rpx; |
||||||
|
.content { |
||||||
|
font-size: 32rpx; |
||||||
|
line-height: 2; |
||||||
|
color: #002b48; |
||||||
|
} |
||||||
|
.tip { |
||||||
|
margin-top: 28rpx; |
||||||
|
font-size: 32rpx; |
||||||
|
color: rgba(87,87,87,0.5); |
||||||
|
} |
||||||
|
} |
||||||
|
.btn { |
||||||
|
margin-top: 42rpx; |
||||||
|
height: 92rpx; |
||||||
|
font-size: 32rpx; |
||||||
|
color: #FFFFFF; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
background: linear-gradient(90deg, #dd406a 0%, #9039b0 100%); |
||||||
|
border-radius: 112rpx 112rpx 112rpx 112rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
#video { |
||||||
|
width: 0; |
||||||
|
height: 0; |
||||||
|
} |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
Page({ |
||||||
|
data: { |
||||||
|
videoUrl: 'https://circlehbsaas.oss-cn-beijing.aliyuncs.com/video/20241214185_1.mp4', |
||||||
|
}, |
||||||
|
videoContext: null as WechatMiniprogram.VideoContext | null, |
||||||
|
onLoad() { |
||||||
|
this.videoContext = wx.createVideoContext('video') |
||||||
|
}, |
||||||
|
onUnload() { |
||||||
|
if (this.videoContext) { |
||||||
|
this.videoContext.stop() |
||||||
|
} |
||||||
|
}, |
||||||
|
handleVideo() { |
||||||
|
if (this.videoContext) { |
||||||
|
this.videoContext.play() |
||||||
|
this.videoContext.requestFullScreen({ |
||||||
|
direction: 0, |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
handleFullScreen(e) { |
||||||
|
if (!e.detail.fullScreen && this.videoContext) { |
||||||
|
this.videoContext.stop() |
||||||
|
} |
||||||
|
}, |
||||||
|
}) |
||||||
|
|
||||||
|
export {} |
||||||
@ -0,0 +1,16 @@ |
|||||||
|
<view |
||||||
|
class="page" |
||||||
|
style="background: url({{imageUrl}}cutaneous/video-bg.png?t={{Timestamp}}) no-repeat 0 60rpx/100% 648rpx;" |
||||||
|
> |
||||||
|
<view class="container"> |
||||||
|
<view class="content"> |
||||||
|
本视频仅用于专业医护人员或艾加莫德a注射液(皮下注射)已处方患者(或其护理者)在接受充分的皮下注射技术培训后自行注射艾加莫德a注射液(皮下注射); |
||||||
|
本指导视频并不构成专业医疗建议、诊断或治疗的依据,请按照说明书并遵医嘱使用,切勿仅依赖本视频内容。 |
||||||
|
</view> |
||||||
|
<view class="tip">*在观看视频前请阅读声明并确认您的身份</view> |
||||||
|
</view> |
||||||
|
<view class="btn btn1" bind:tap="handleVideo">我是专业医护人员</view> |
||||||
|
<view class="btn btn2" bind:tap="handleVideo">我是卫力迦已处方患者(或其护理者)</view> |
||||||
|
</view> |
||||||
|
|
||||||
|
<video id="video" src="{{videoUrl}}" loop show-play-btn play-btn-position="center" enable-play-gesture bindfullscreenchange="handleFullScreen"></video> |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
{ |
||||||
|
"navigationBarTitleText": "双通道药房", |
||||||
|
"usingComponents": {} |
||||||
|
} |
||||||
@ -0,0 +1,128 @@ |
|||||||
|
.page { |
||||||
|
position: relative; |
||||||
|
.banner { |
||||||
|
width: 100%; |
||||||
|
min-height: 344rpx; |
||||||
|
} |
||||||
|
.container { |
||||||
|
padding: 48rpx 40rpx; |
||||||
|
position: absolute; |
||||||
|
top: 316rpx; |
||||||
|
left: 0; |
||||||
|
width: 100%; |
||||||
|
min-height: 100vh; |
||||||
|
border-radius: 24rpx 24rpx 0 0; |
||||||
|
background-color: #fafafa; |
||||||
|
box-sizing: border-box; |
||||||
|
.title { |
||||||
|
font-size: 36rpx; |
||||||
|
color: #484848; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
.tags { |
||||||
|
margin-top: 16rpx; |
||||||
|
display: flex; |
||||||
|
.tag { |
||||||
|
margin-right: 16rpx; |
||||||
|
padding-right: 8rpx; |
||||||
|
font-size: 22rpx; |
||||||
|
color: #e04775; |
||||||
|
line-height: 1; |
||||||
|
border-radius: 8rpx; |
||||||
|
background-color: #f5dfe6; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
.icon { |
||||||
|
margin-right: 8rpx; |
||||||
|
padding: 4rpx; |
||||||
|
width: 24rpx; |
||||||
|
max-height: 24rpx; |
||||||
|
background-color: #e04775; |
||||||
|
border-radius: 8rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.content { |
||||||
|
margin-top: 32rpx; |
||||||
|
margin-bottom: 20rpx; |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
.inner { |
||||||
|
.site { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #9e9e9e; |
||||||
|
} |
||||||
|
.tel { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #9b9ea6; |
||||||
|
} |
||||||
|
} |
||||||
|
.options { |
||||||
|
flex-shrink: 0; |
||||||
|
display: flex; |
||||||
|
.option { |
||||||
|
margin-left: 30rpx; |
||||||
|
.phone { |
||||||
|
width: 48rpx; |
||||||
|
height: 48rpx; |
||||||
|
border-radius: 50%; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
background-color: #fff; |
||||||
|
box-shadow: 0 4rpx 20rpx 0 rgba(0, 0, 0, 0.1); |
||||||
|
&-img { |
||||||
|
width: 24rpx; |
||||||
|
height: 24rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.name { |
||||||
|
margin-top: 8rpx; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #484848; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.card { |
||||||
|
margin-bottom: 16rpx; |
||||||
|
padding: 32rpx 30rpx; |
||||||
|
border-radius: 24rpx; |
||||||
|
background-color: #fff; |
||||||
|
.c-title { |
||||||
|
font-size: 32rpx; |
||||||
|
font-weight: bold; |
||||||
|
color: #484848; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
.c-icon { |
||||||
|
margin-right: 16rpx; |
||||||
|
width: 36rpx; |
||||||
|
height: 36rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.c-content{ |
||||||
|
margin-top: 24rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #9E9E9E; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.remark{ |
||||||
|
padding: 32rpx; |
||||||
|
border-radius: 24rpx; |
||||||
|
background-color: #fff; |
||||||
|
.r-title{ |
||||||
|
font-size: 32rpx; |
||||||
|
color: #484848; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
.r-content{ |
||||||
|
margin-top: 20rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #9E9E9E; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,52 @@ |
|||||||
|
const app = getApp<IAppOption>(); |
||||||
|
|
||||||
|
Page({ |
||||||
|
data: { |
||||||
|
id: "", |
||||||
|
detail: {} as any, |
||||||
|
}, |
||||||
|
onLoad(options) { |
||||||
|
this.setData({ |
||||||
|
id: options.id, |
||||||
|
}); |
||||||
|
app.waitLogin().then(() => { |
||||||
|
this.getDetail(); |
||||||
|
}); |
||||||
|
}, |
||||||
|
|
||||||
|
getDetail() { |
||||||
|
wx.ajax({ |
||||||
|
method: "GET", |
||||||
|
url: "?r=zd/dtp-pharmacy/detail", |
||||||
|
data: { |
||||||
|
Id: this.data.id, |
||||||
|
}, |
||||||
|
}).then((res) => { |
||||||
|
this.setData({ |
||||||
|
detail: res, |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleSite() { |
||||||
|
const { LNG, LAT, ProvinceName, CityName, CountyName, Address, Name } = this.data.detail; |
||||||
|
wx.openLocation({ |
||||||
|
latitude: LAT, |
||||||
|
longitude: LNG, |
||||||
|
name: Name, |
||||||
|
address: `${ProvinceName}${CityName}${CountyName}${Address}`, |
||||||
|
}); |
||||||
|
}, |
||||||
|
handlePhone() { |
||||||
|
const tel = this.data.detail.Telephone; |
||||||
|
if (!tel) { |
||||||
|
wx.showToast({ |
||||||
|
icon: "none", |
||||||
|
title: "电话暂未开通", |
||||||
|
}); |
||||||
|
return; |
||||||
|
} |
||||||
|
wx.makePhoneCall({ |
||||||
|
phoneNumber: tel, |
||||||
|
}); |
||||||
|
}, |
||||||
|
}); |
||||||
@ -0,0 +1,61 @@ |
|||||||
|
<view class="page"> |
||||||
|
<image wx:if="{{detail.ImgUrl}}" class="banner" mode="widthFix" src="{{detail.ImgUrl}}"></image> |
||||||
|
<image wx:else class="banner" mode="widthFix" src="{{imageUrl}}/nrdl/dtp-durg.png"></image> |
||||||
|
<view class="container"> |
||||||
|
<view class="title">{{detail.Name}}</view> |
||||||
|
<view class="tags"> |
||||||
|
<view class="tag" wx:if="{{detail.IsOwnInfusionCenter==1}}"> |
||||||
|
<image class="icon" mode="widthFix" src="{{imageUrl}}/nrdl/inject.png"></image> |
||||||
|
<!-- {{detail.OwnInfusionCenterName}} --> |
||||||
|
自有输注中心 |
||||||
|
</view> |
||||||
|
<view class="tag" wx:if="{{detail.IsCooperationInfusionCenter==1}}"> |
||||||
|
<image class="icon" mode="widthFix" src="{{imageUrl}}/nrdl/cooperate.png"></image> |
||||||
|
<!-- {{detail.CooperationInfusionCenterName}} --> |
||||||
|
合作输注中心 |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="content"> |
||||||
|
<view class="inner"> |
||||||
|
<view class="site">{{detail.ProvinceName}}{{detail.CityName}}{{detail.CountyName}}{{detail.Address}}</view> |
||||||
|
<view class="tel">{{detail.Telephone}}</view> |
||||||
|
</view> |
||||||
|
<view class="options"> |
||||||
|
<view class="option" bind:tap="handleSite" wx:if="{{detail.Address}}"> |
||||||
|
<view class="phone"> |
||||||
|
<image class="phone-img" src="{{imageUrl}}/nrdl/site.png"></image> |
||||||
|
</view> |
||||||
|
<view class="name">地址</view> |
||||||
|
</view> |
||||||
|
<view class="option" bind:tap="handlePhone"> |
||||||
|
<view class="phone"> |
||||||
|
<image class="phone-img" src="{{imageUrl}}/nrdl/phone.png"></image> |
||||||
|
</view> |
||||||
|
<view class="name">电话</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="card" wx:if="{{detail.IsOwnInfusionCenter==1}}"> |
||||||
|
<view class="c-title"> |
||||||
|
<image |
||||||
|
class="c-icon" |
||||||
|
src="{{imageUrl}}/nrdl/cooperate-1.png" |
||||||
|
style="width: 32rpx; height: 30rpx; margin-right: 18rpx" |
||||||
|
></image> |
||||||
|
自有输注中心 |
||||||
|
</view> |
||||||
|
<view class="c-content">{{detail.OwnInfusionCenterName}}</view> |
||||||
|
</view> |
||||||
|
<view class="card" wx:if="{{detail.IsCooperationInfusionCenter==1}}"> |
||||||
|
<view class="c-title"> |
||||||
|
<image class="c-icon" src="{{imageUrl}}/nrdl/inject-1.png" style="width: 36rpx; height: 36rpx"></image> |
||||||
|
合作输注中心 |
||||||
|
</view> |
||||||
|
<view class="c-content">{{detail.CooperationInfusionCenterName}}</view> |
||||||
|
</view> |
||||||
|
<view class="remark" wx:if="{{detail.Remark}}"> |
||||||
|
<view class="r-title">备注</view> |
||||||
|
<view class="r-content">{{detail.Remark}}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
@ -0,0 +1,7 @@ |
|||||||
|
{ |
||||||
|
"navigationBarTitleText": "礼品详情", |
||||||
|
"usingComponents": { |
||||||
|
"van-stepper": "@vant/weapp/stepper/index", |
||||||
|
"toast": "/components/toast/index" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,185 @@ |
|||||||
|
.page { |
||||||
|
background-color: #f9f9f9; |
||||||
|
padding-bottom: 400rpx; |
||||||
|
.banner { |
||||||
|
width: 100%; |
||||||
|
.banner-img { |
||||||
|
display: block; |
||||||
|
width: 100%; |
||||||
|
height: 562rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.container { |
||||||
|
padding: 30rpx 40rpx; |
||||||
|
.price { |
||||||
|
display: flex; |
||||||
|
align-items: baseline; |
||||||
|
.num { |
||||||
|
font-size: 56rpx; |
||||||
|
color: #e04775; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
.sub { |
||||||
|
font-size: 32rpx; |
||||||
|
color: #e04775; |
||||||
|
} |
||||||
|
} |
||||||
|
.title { |
||||||
|
margin-top: 22rpx; |
||||||
|
font-size: 36rpx; |
||||||
|
color: #3f3f3f; |
||||||
|
line-height: 48rpx; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
.list { |
||||||
|
margin-top: 24rpx; |
||||||
|
padding: 32rpx; |
||||||
|
background: #ffffff; |
||||||
|
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05); |
||||||
|
border-radius: 24rpx; |
||||||
|
.list-title { |
||||||
|
padding-bottom: 16rpx; |
||||||
|
position: relative; |
||||||
|
font-size: 36rpx; |
||||||
|
color: #3f3f3f; |
||||||
|
font-weight: bold; |
||||||
|
&::before { |
||||||
|
content: ""; |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: -32rpx; |
||||||
|
width: 12rpx; |
||||||
|
height: 44rpx; |
||||||
|
background: #e04775; |
||||||
|
border-radius: 0rpx 8rpx 8rpx 0rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.list-img { |
||||||
|
display: block; |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.footer { |
||||||
|
padding: 30rpx 40rpx 40rpx; |
||||||
|
position: fixed; |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
width: 100vw; |
||||||
|
box-sizing: border-box; |
||||||
|
background: #ffffff; |
||||||
|
box-shadow: 0rpx 8rpx 20rpx 0rpx rgba(0, 0, 0, 0.26); |
||||||
|
.options { |
||||||
|
padding-bottom: 25rpx; |
||||||
|
.row { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
.label { |
||||||
|
margin-right: 24rpx; |
||||||
|
flex-shrink: 0; |
||||||
|
font-size: 32rpx; |
||||||
|
color: #b6b7ba; |
||||||
|
} |
||||||
|
.radios { |
||||||
|
display: flex; |
||||||
|
overflow: auto; |
||||||
|
&::-webkit-scrollbar { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
.radio { |
||||||
|
margin-right: 16rpx; |
||||||
|
border-radius: 8rpx; |
||||||
|
border: 1px solid #d0d0d0; |
||||||
|
line-height: 40rpx; |
||||||
|
padding: 0 20rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #aaaaaa; |
||||||
|
white-space: nowrap; |
||||||
|
&.active { |
||||||
|
background-color: #e04775; |
||||||
|
border-color: #e04775; |
||||||
|
color: #fff; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.stepper { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
.custom-class { |
||||||
|
border: 1px solid #e5e5e5; |
||||||
|
border-radius: 8rpx; |
||||||
|
} |
||||||
|
.input-class { |
||||||
|
color: #3f3f3f; |
||||||
|
font-weight: bold; |
||||||
|
background-color: #ffffff; |
||||||
|
margin: 0; |
||||||
|
} |
||||||
|
.plus-class, |
||||||
|
.minus-class { |
||||||
|
margin: 0; |
||||||
|
background-color: #f8f8f8; |
||||||
|
} |
||||||
|
.minus-class { |
||||||
|
border-right: 1px solid #d7d7d7; |
||||||
|
} |
||||||
|
.plus-class { |
||||||
|
border-left: 1px solid #d7d7d7; |
||||||
|
} |
||||||
|
.status { |
||||||
|
margin-left: 8rpx; |
||||||
|
font-size: 32rpx; |
||||||
|
color: #e1e1e1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.row:not(:first-of-type) { |
||||||
|
margin-top: 24rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.module { |
||||||
|
border-top: 1px solid #f2f2f2; |
||||||
|
padding-top: 25rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
.wrap { |
||||||
|
.price { |
||||||
|
display: flex; |
||||||
|
align-items: baseline; |
||||||
|
.sub { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #e04775; |
||||||
|
} |
||||||
|
.num { |
||||||
|
font-size: 40rpx; |
||||||
|
color: #e04775; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
} |
||||||
|
.doc { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #999999; |
||||||
|
.checkbox { |
||||||
|
transform: scale(0.7); |
||||||
|
} |
||||||
|
.a { |
||||||
|
color: #e04775; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.submit { |
||||||
|
width: 298rpx; |
||||||
|
height: 96rpx; |
||||||
|
background: #e04775; |
||||||
|
border-radius: 48rpx; |
||||||
|
font-size: 36rpx; |
||||||
|
color: #ffffff; |
||||||
|
line-height: 96rpx; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,150 @@ |
|||||||
|
const app = getApp<IAppOption>(); |
||||||
|
|
||||||
|
Page({ |
||||||
|
data: { |
||||||
|
id: "", |
||||||
|
detail: {}, |
||||||
|
specVecItem: {} as any, |
||||||
|
num: 1, |
||||||
|
allPrice: "", |
||||||
|
|
||||||
|
toastShow: false, |
||||||
|
toastType: "giftEnter", |
||||||
|
|
||||||
|
toastParams: { |
||||||
|
doc: "", |
||||||
|
}, |
||||||
|
protocol: false, |
||||||
|
}, |
||||||
|
onLoad(options) { |
||||||
|
this.setData({ |
||||||
|
id: options.id, |
||||||
|
toastParams: { |
||||||
|
doc: `<p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">为让用户更好的享受再鼎gMG给力加油站的服务,gMG给力加油站平台向用户提供了能量兑换服务,并提供了丰富的礼品,平台注册用户可使用有效的能量兑换礼品。</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">gMG给力加油站的礼品库将提供:</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 微软雅黑;">1) </span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">查看用户在能量商城选择兑换的商品信息;</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 微软雅黑;">2) </span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">确认兑换商品的订单信息;</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 微软雅黑;">3) </span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">实施兑换商品的物流配送服务。</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">基于以上服务内容,我们在此特别声明:</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">gMG给力加油站非常重视用户个人信息保护,我们制定了详细的<a style="color:#00A4ED" href="/pages/privacyAgreement/index?page=/gift/pages/giftDetail/index&id=${options.id}">《知情同意书》</a></span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">,我们将按照公示的政策及相关法律法规的要求,对您的个人信息予以保护。为了完整的向您提供能量的商品兑换服务,gMG给力加油站将需要您提供用户真实姓名、手机号、地址信息,以便完成您所兑换商品的物流配送。其中,当用户准备对兑换商品进行结算时,平台会生成兑换该商品的订单,同时该订单中会载明订单号、所兑换的商品或服务信息、应支付的能量值。以上所有信息构成用户的“订单信息”,平台将使用订单信息来进行用户的身份核验、确定交易、支付结算、完成配送。</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">用户点击本协议的"同意"按钮即视为完全接受以上声明条款,在点击之前请用户再次确认已知悉并完全理解声明的全部内容。</span></p>`, |
||||||
|
// doc:` <p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">为让用户更好的享受再鼎gMG给力加油站的服务,gMG给力加油站平台向用户提供了能量兑换服务,并提供了丰富的礼品,平台注册用户可使用有效的能量兑换礼品。</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">gMG给力加油站的礼品库将提供:</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 微软雅黑;">1) </span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">查看用户在能量商城选择兑换的商品信息;</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 微软雅黑;">2) </span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">确认兑换商品的订单信息;</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 微软雅黑;">3) </span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">实施兑换商品的物流配送服务。</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">基于以上服务内容,我们在此特别声明:</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">gMG给力加油站非常重视用户个人信息保护,我们制定了详细的<a style="color:#00A4ED" href="/pages/privacyAgreement/index?page=/gift/pages/giftDetail/index&id=${options.id}">《知情同意书》</a></span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">,我们将按照公示的政策及相关法律法规的要求,对您的个人信息予以保护。为了完整的向您提供能量的商品兑换服务,gMG给力加油站将需要您提供用户真实姓名、手机号、地址信息,以便完成您所兑换商品的物流配送。其中,当用户准备对兑换商品进行结算时,平台会生成兑换该商品的订单,同时该订单中会载明订单号、所兑换的商品或服务信息、应支付的能量值。以上所有信息构成用户的“订单信息”,平台将使用订单信息来进行用户的身份核验、确定交易、支付结算、完成配送。</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">用户点击本协议的"同意"按钮即视为完全接受以上声明条款,在点击之前请用户再次确认已知悉并完全理解声明的全部内容。</span></p>`
|
||||||
|
}, |
||||||
|
}); |
||||||
|
app.waitLogin().then(() => { |
||||||
|
this.setView(); |
||||||
|
this.getDetail(); |
||||||
|
this.getProtocol(); |
||||||
|
}); |
||||||
|
}, |
||||||
|
setView() { |
||||||
|
wx.ajax({ |
||||||
|
method: "POST", |
||||||
|
url: "?r=zd/gift-spu/set-visit-num", |
||||||
|
data: { spuId: this.data.id }, |
||||||
|
showMsg: false, |
||||||
|
}); |
||||||
|
}, |
||||||
|
getDetail() { |
||||||
|
wx.ajax({ |
||||||
|
method: "GET", |
||||||
|
url: "?r=zd/gift-spu/get-detail", |
||||||
|
data: { |
||||||
|
spuId: this.data.id, |
||||||
|
}, |
||||||
|
}).then((res) => { |
||||||
|
this.setData({ |
||||||
|
detail: { |
||||||
|
...res, |
||||||
|
detailList: JSON.parse(res.detail), |
||||||
|
}, |
||||||
|
specVecItem: res.specVec[0], |
||||||
|
allPrice: res.specVec[0].score, |
||||||
|
num: res.specVec[0].stock >= 1 ? 1 : 0, |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
getProtocol() { |
||||||
|
wx.ajax({ |
||||||
|
method: "GET", |
||||||
|
url: "?r=zd/agreement/get-user-agreement", |
||||||
|
data: {}, |
||||||
|
}).then((res) => { |
||||||
|
this.setData({ |
||||||
|
protocol: res, |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
setProtocol() { |
||||||
|
wx.ajax({ |
||||||
|
method: "POST", |
||||||
|
url: "?r=zd/agreement/set-user-agreement", |
||||||
|
data: {}, |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleSpec(e: any) { |
||||||
|
const { index } = e.currentTarget.dataset; |
||||||
|
const specVecItem: any = this.data.detail.specVec[index]; |
||||||
|
console.log(specVecItem.stock>=1) |
||||||
|
this.setData({ |
||||||
|
specVecItem: specVecItem, |
||||||
|
allPrice: specVecItem.score, |
||||||
|
num: specVecItem.stock >= 1 ? 1 : 0, |
||||||
|
}); |
||||||
|
}, |
||||||
|
onChangeNumber(e: any) { |
||||||
|
this.setData({ |
||||||
|
num: e.detail, |
||||||
|
allPrice: this.data.specVecItem.score * e.detail, |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleDoc() { |
||||||
|
this.setData({ |
||||||
|
toastShow: true, |
||||||
|
toastType: "giftEnter", |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleToastOk(e) { |
||||||
|
if (!e.detail.protocol) { |
||||||
|
wx.showToast({ |
||||||
|
title: "请先勾选《用户须知》", |
||||||
|
icon: "none", |
||||||
|
}); |
||||||
|
return; |
||||||
|
} |
||||||
|
this.setProtocol(); |
||||||
|
this.setData({ |
||||||
|
protocol: e.detail.protocol, |
||||||
|
}); |
||||||
|
this.handleToastCancel(); |
||||||
|
}, |
||||||
|
handleToastCancel() { |
||||||
|
this.setData({ |
||||||
|
toastShow: false, |
||||||
|
toastType: "", |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleProtocol() { |
||||||
|
if (!this.data.protocol) { |
||||||
|
this.setProtocol(); |
||||||
|
} |
||||||
|
this.setData({ |
||||||
|
protocol: !this.data.protocol, |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleSubmit() { |
||||||
|
if (!this.data.protocol) { |
||||||
|
wx.showToast({ |
||||||
|
icon: "none", |
||||||
|
title: "请先同意《用户须知》", |
||||||
|
}); |
||||||
|
return; |
||||||
|
} |
||||||
|
wx.ajax({ |
||||||
|
method: "POST", |
||||||
|
url: "?r=zd/gift-order/place-order", |
||||||
|
data: { |
||||||
|
giftId: this.data.specVecItem.giftId, |
||||||
|
count: this.data.num, |
||||||
|
}, |
||||||
|
loading: true, |
||||||
|
}).then((res) => { |
||||||
|
wx.navigateTo({ |
||||||
|
url: `/gift/pages/conformOrder/index?id=${res}`, |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
}); |
||||||
@ -0,0 +1,80 @@ |
|||||||
|
<view class="page"> |
||||||
|
<view class="banner"> |
||||||
|
<image class="banner-img" mode="aspectFill" src="{{detail.bigImg}}"></image> |
||||||
|
</view> |
||||||
|
<view class="container"> |
||||||
|
<view class="price"> |
||||||
|
<view class="num">{{specVecItem.score}}</view> |
||||||
|
<view class="sub">能量</view> |
||||||
|
</view> |
||||||
|
<view class="title">{{detail.giftName}}</view> |
||||||
|
<view class="list"> |
||||||
|
<view class="list-title">礼品详情</view> |
||||||
|
<image class="list-img" mode="widthFix" wx:for="{{detail.detailList}}" wx:key="index" src="{{item.url}}"></image> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
|
||||||
|
<view class="footer"> |
||||||
|
<view class="options"> |
||||||
|
<view class="row" wx:if="{{detail.specVec.length > 0 && detail.specVec[0].specName}}"> |
||||||
|
<view class="label">规格</view> |
||||||
|
<view class="radios"> |
||||||
|
<view |
||||||
|
class="radio {{specVecItem.giftId==item.giftId && 'active'}}" |
||||||
|
wx:for="{{detail.specVec}}" |
||||||
|
wx:key="index" |
||||||
|
data-index="{{index}}" |
||||||
|
bind:tap="handleSpec" |
||||||
|
> |
||||||
|
{{item.specName }} |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="row"> |
||||||
|
<view class="label">数量</view> |
||||||
|
<view class="stepper"> |
||||||
|
<van-stepper |
||||||
|
custom-class="custom-class" |
||||||
|
value="{{ num }}" |
||||||
|
min="{{0}}" |
||||||
|
input-width="{{48}}" |
||||||
|
input-class="input-class" |
||||||
|
plus-class="plus-class" |
||||||
|
minus-class="minus-class" |
||||||
|
integer |
||||||
|
disable-input |
||||||
|
bind:change="onChangeNumber" |
||||||
|
disable-plus="{{num>=specVecItem.stock}}" |
||||||
|
/> |
||||||
|
<view class="status" wx:if="{{num<=specVecItem.stock && specVecItem.stock>0 }}">有库存</view> |
||||||
|
<view class="status" wx:else>无库存</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="module"> |
||||||
|
<view class="wrap"> |
||||||
|
<view class="price"> |
||||||
|
<view class="sub"> |
||||||
|
合计 |
||||||
|
<text decode="true"> </text> |
||||||
|
</view> |
||||||
|
<view class="num">{{allPrice}}</view> |
||||||
|
</view> |
||||||
|
<view class="doc"> |
||||||
|
<checkbox class="checkbox" checked="{{protocol}}" color="#DB3E6A" bind:tap="handleProtocol"></checkbox> |
||||||
|
已阅读 |
||||||
|
<view class="a" bind:tap="handleDoc">《用户须知》</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="submit" bind:tap="handleSubmit">立即兑换</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
|
||||||
|
<toast |
||||||
|
show="{{toastShow}}" |
||||||
|
type="{{toastType}}" |
||||||
|
params="{{toastParams}}" |
||||||
|
bind:ok="handleToastOk" |
||||||
|
bind:cancel="handleToastCancel" |
||||||
|
></toast> |
||||||
@ -0,0 +1,8 @@ |
|||||||
|
{ |
||||||
|
"navigationBarTitleText": "礼品中心", |
||||||
|
"navigationStyle": "custom", |
||||||
|
"usingComponents": { |
||||||
|
"van-icon": "@vant/weapp/icon/index", |
||||||
|
"navBar": "/components/zd-navBar/navBar" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,185 @@ |
|||||||
|
page { |
||||||
|
background-color: #f9f9f9; |
||||||
|
} |
||||||
|
.page { |
||||||
|
.bg { |
||||||
|
width: 100%; |
||||||
|
height: 902rpx; |
||||||
|
} |
||||||
|
.page-container { |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
top: 0; |
||||||
|
width: 100%; |
||||||
|
padding: 0 40rpx; |
||||||
|
box-sizing: border-box; |
||||||
|
padding-bottom: 200rpx; |
||||||
|
.notice { |
||||||
|
height: 44rpx; |
||||||
|
background: linear-gradient(90deg, rgba(241, 241, 241, 0) 0%, #f1f1f1 52%, rgba(241, 241, 241, 0) 100%); |
||||||
|
border-radius: 16rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #3f3f3f; |
||||||
|
.icon { |
||||||
|
margin-right: 5rpx; |
||||||
|
width: 30rpx; |
||||||
|
height: 24rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.banner { |
||||||
|
margin-top: 16rpx; |
||||||
|
background: #fafafa; |
||||||
|
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05); |
||||||
|
border-radius: 24rpx; |
||||||
|
border: 2rpx solid rgba(151, 151, 151, 0.14); |
||||||
|
.banner-header { |
||||||
|
padding: 32rpx 0 32rpx 32rpx; |
||||||
|
display: flex; |
||||||
|
background: #ffffff; |
||||||
|
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05); |
||||||
|
border-radius: 24rpx; |
||||||
|
border-bottom: 2rpx solid rgba(151, 151, 151, 0.14); |
||||||
|
display: flex; |
||||||
|
.user { |
||||||
|
width: 106rpx; |
||||||
|
height: 106rpx; |
||||||
|
border-radius: 50%; |
||||||
|
} |
||||||
|
.wrap { |
||||||
|
flex: 1; |
||||||
|
padding: 0 150rpx 0 22rpx; |
||||||
|
.title { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #3f3f3f; |
||||||
|
} |
||||||
|
.price { |
||||||
|
font-size: 48rpx; |
||||||
|
color: #3f3f3f; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
} |
||||||
|
.rule { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #ffffff; |
||||||
|
width: 136rpx; |
||||||
|
height: 44rpx; |
||||||
|
background: #f5ab1f; |
||||||
|
border-radius: 24rpx 0 0 24rpx; |
||||||
|
text-align: center; |
||||||
|
line-height: 44rpx; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
} |
||||||
|
.banner-footer { |
||||||
|
padding: 20rpx 0 28rpx; |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
.ver-line { |
||||||
|
width: 2rpx; |
||||||
|
height: 40rpx; |
||||||
|
background-color: rgba(221, 221, 221, 0.6); |
||||||
|
} |
||||||
|
.option { |
||||||
|
flex: 1; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #484848; |
||||||
|
font-weight: bold; |
||||||
|
.icon { |
||||||
|
margin-right: 22rpx; |
||||||
|
width: 50rpx; |
||||||
|
height: 50rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.list { |
||||||
|
margin-top: 48rpx; |
||||||
|
.list-title { |
||||||
|
margin-bottom: 20rpx; |
||||||
|
width: 180rpx; |
||||||
|
height: 40rpx; |
||||||
|
} |
||||||
|
.list-cate { |
||||||
|
padding: 20rpx 0; |
||||||
|
display: flex; |
||||||
|
flex-wrap: nowrap; |
||||||
|
max-width: 100vw; |
||||||
|
box-sizing: border-box; |
||||||
|
overflow-x: auto; |
||||||
|
&::-webkit-scrollbar { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
.cate { |
||||||
|
margin-right: 20rpx; |
||||||
|
padding: 10rpx 24rpx; |
||||||
|
white-space: nowrap; |
||||||
|
line-height: 1; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #484848; |
||||||
|
background-color: #f2f2f2; |
||||||
|
border-radius: 24rpx; |
||||||
|
&.active { |
||||||
|
color: #fff; |
||||||
|
background-color: #e04775; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.list-container { |
||||||
|
display: flex; |
||||||
|
flex-wrap: wrap; |
||||||
|
gap: 16rpx 22rpx; |
||||||
|
.list-item { |
||||||
|
margin-bottom: 16rpx; |
||||||
|
width: 324rpx; |
||||||
|
background: #ffffff; |
||||||
|
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05); |
||||||
|
border-radius: 24rpx; |
||||||
|
.photo { |
||||||
|
border-radius: 24rpx 24rpx 0 0; |
||||||
|
width: 100%; |
||||||
|
height: 324rpx; |
||||||
|
} |
||||||
|
.content { |
||||||
|
padding: 18rpx 20rpx 22rpx; |
||||||
|
.title { |
||||||
|
margin-top: 18rpx; |
||||||
|
font-size: 32rpx; |
||||||
|
color: #484848; |
||||||
|
font-weight: bold; |
||||||
|
overflow: hidden; |
||||||
|
white-space: nowrap; |
||||||
|
text-overflow: ellipsis; |
||||||
|
} |
||||||
|
.footer { |
||||||
|
margin-top: 6rpx; |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
.price { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #e04775; |
||||||
|
} |
||||||
|
.btn { |
||||||
|
width: 100rpx; |
||||||
|
height: 44rpx; |
||||||
|
text-align: center; |
||||||
|
line-height: 44rpx; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #ffffff; |
||||||
|
background: #e04775; |
||||||
|
border-radius: 24rpx; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,114 @@ |
|||||||
|
const app = getApp<IAppOption>(); |
||||||
|
|
||||||
|
Page({ |
||||||
|
data: { |
||||||
|
bottom: 0, |
||||||
|
selfScore: { |
||||||
|
expire: {}, |
||||||
|
}, |
||||||
|
cateList: [], |
||||||
|
|
||||||
|
cateId: "", |
||||||
|
list: [], |
||||||
|
pagination: { |
||||||
|
page: 1, |
||||||
|
pages: 1, |
||||||
|
count: 1, |
||||||
|
}, |
||||||
|
}, |
||||||
|
onLoad() { |
||||||
|
const SystemInfo = app.globalSystemInfo; |
||||||
|
if (SystemInfo) { |
||||||
|
const { bottom } = SystemInfo.capsulePosition; |
||||||
|
this.setData({ |
||||||
|
bottom: bottom, |
||||||
|
}); |
||||||
|
} |
||||||
|
app.waitLogin().then(() => { |
||||||
|
app.getZdUserInfo(this, true); |
||||||
|
this.getScore(); |
||||||
|
this.getList(); |
||||||
|
this.getCateList(); |
||||||
|
}); |
||||||
|
}, |
||||||
|
getScore() { |
||||||
|
wx.ajax({ |
||||||
|
method: "GET", |
||||||
|
url: "?r=zd/patient-score/get-self-score", |
||||||
|
data: {}, |
||||||
|
}).then((res) => { |
||||||
|
this.setData({ |
||||||
|
selfScore: res, |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
getCateList() { |
||||||
|
wx.ajax({ |
||||||
|
method: "GET", |
||||||
|
url: "?r=zd/gift-spu/get-cate-all-list", |
||||||
|
data: {}, |
||||||
|
}).then((res) => { |
||||||
|
this.setData({ |
||||||
|
cateList: res, |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleCate(e) { |
||||||
|
const { id } = e.currentTarget.dataset; |
||||||
|
this.setData({ |
||||||
|
cateId: id, |
||||||
|
}); |
||||||
|
this.getList(); |
||||||
|
}, |
||||||
|
getList(newPage = 1) { |
||||||
|
wx.ajax({ |
||||||
|
method: "POST", |
||||||
|
url: `?r=zd/gift-spu/get-list&page=${newPage}`, |
||||||
|
data: { |
||||||
|
cateId: this.data.cateId ? [this.data.cateId] : [], |
||||||
|
}, |
||||||
|
}).then((res) => { |
||||||
|
let list = res.page == 1 ? res.list : [...this.data.list, ...res.list]; |
||||||
|
this.setData({ |
||||||
|
list: list, |
||||||
|
pagination: { |
||||||
|
page: res.page, |
||||||
|
pages: res.pages, |
||||||
|
count: res.count, |
||||||
|
}, |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
handlePirceDetail() { |
||||||
|
wx.navigateTo({ |
||||||
|
url: "/gift/pages/priceDetail/index", |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleMyGift() { |
||||||
|
wx.navigateTo({ |
||||||
|
url: "/gift/pages/myGift/index", |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleDetail(e) { |
||||||
|
const { id } = e.currentTarget.dataset; |
||||||
|
wx.navigateTo({ |
||||||
|
url: `/gift/pages/giftDetail/index?id=${id}`, |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleRule() { |
||||||
|
wx.navigateTo({ |
||||||
|
url: `/gift/pages/scoreRule/index`, |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleBack() { |
||||||
|
wx.reLaunch({ |
||||||
|
url: "/pages/my/index", |
||||||
|
}); |
||||||
|
}, |
||||||
|
onReachBottom() { |
||||||
|
const { page, pages } = this.data.pagination; |
||||||
|
if (pages > page) { |
||||||
|
this.getList(page + 1); |
||||||
|
} |
||||||
|
}, |
||||||
|
}); |
||||||
@ -0,0 +1,51 @@ |
|||||||
|
<view class="page"> |
||||||
|
<navBar color="#222222" background="{{background}}" fixed title="礼品中心" back bind:back="handleBack"></navBar> |
||||||
|
<image class="bg" src="{{imageUrl}}1/my-bg.png?t={{Timestamp}}"></image> |
||||||
|
<view class="page-container" style="padding-top:{{bottom+26}}px"> |
||||||
|
<view class="notice" wx:if="{{selfScore.expire.expireStatus==1}}"> |
||||||
|
<image class="icon" src="{{imageUrl}}2/notice.png?t={{Timestamp}}"></image> |
||||||
|
你有{{selfScore.expire.expireScore}}能量将于7月1日过期 |
||||||
|
</view> |
||||||
|
<view class="banner"> |
||||||
|
<view class="banner-header"> |
||||||
|
<image class="user" src="{{zdUserInfo.UserImg}}"></image> |
||||||
|
<view class="wrap"> |
||||||
|
<view class="title">我的能量</view> |
||||||
|
<view class="price">{{selfScore.score}}</view> |
||||||
|
</view> |
||||||
|
<view class="rule" bind:tap="handleRule">能量规则</view> |
||||||
|
</view> |
||||||
|
<view class="banner-footer"> |
||||||
|
<view class="option" bind:tap="handlePirceDetail"> |
||||||
|
<image class="icon" style="width:52rpx;height: 50rpx;" src="{{imageUrl}}2/money.png?t={{Timestamp}}"></image> |
||||||
|
能量明细 |
||||||
|
</view> |
||||||
|
<view class="ver-line"></view> |
||||||
|
<view class="option" bind:tap="handleMyGift"> |
||||||
|
<image class="icon" style="width:48rpx;height: 54rpx;" src="{{imageUrl}}2/gift.png?t={{Timestamp}}"></image> |
||||||
|
我的礼品 |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="list"> |
||||||
|
<image class="list-title" src="{{imageUrl}}2/gift-list-title.png?t={{Timestamp}}"></image> |
||||||
|
<view class="list-cate"> |
||||||
|
<view class="cate {{!cateId && 'active'}}" data-id="" bind:tap="handleCate">全部</view> |
||||||
|
<view class="cate {{cateId == item.cateId && 'active'}}" wx:for="{{cateList}}" wx:key="cateId" data-id="{{item.cateId}}" bind:tap="handleCate">{{item.cateName}}</view> |
||||||
|
</view> |
||||||
|
<view class="list-container"> |
||||||
|
<view class="list-item" wx:for="{{list}}" wx:key="index" data-id="{{item.spuId}}" bind:tap="handleDetail"> |
||||||
|
<image class="photo" src="{{item.bigImg}}"></image> |
||||||
|
<view class="content"> |
||||||
|
<view class="title">{{item.giftName}}</view> |
||||||
|
<view class="footer"> |
||||||
|
<view class="price">{{item.lowestScore}}能量</view> |
||||||
|
<view class="btn">兑换</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<pagination pagination="{{pagination}}"></pagination> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
{ |
||||||
|
"navigationBarTitleText": "我的礼品", |
||||||
|
"usingComponents": {} |
||||||
|
} |
||||||
@ -0,0 +1,110 @@ |
|||||||
|
page { |
||||||
|
background-color: #f7f7f7; |
||||||
|
} |
||||||
|
.page { |
||||||
|
padding: 32rpx 40rpx; |
||||||
|
.card { |
||||||
|
margin-bottom: 16rpx; |
||||||
|
padding: 32rpx; |
||||||
|
background: #ffffff; |
||||||
|
border-radius: 24rpx; |
||||||
|
.header { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
padding-bottom: 32rpx; |
||||||
|
border-bottom: 1px solid #ebebeb; |
||||||
|
.on { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #bbbcbe; |
||||||
|
} |
||||||
|
.status { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #e04775; |
||||||
|
} |
||||||
|
.suc { |
||||||
|
color: #24d8c8; |
||||||
|
} |
||||||
|
} |
||||||
|
.shop { |
||||||
|
padding: 32rpx 0; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
.shop-img { |
||||||
|
flex-shrink: 0; |
||||||
|
width: 200rpx; |
||||||
|
height: 200rpx; |
||||||
|
border-radius: 24rpx; |
||||||
|
} |
||||||
|
.wrap { |
||||||
|
flex: 1; |
||||||
|
padding-left: 24rpx; |
||||||
|
.name { |
||||||
|
font-size: 32rpx; |
||||||
|
font-weight: bold; |
||||||
|
color: #3f3f3f; |
||||||
|
line-height: 44rpx; |
||||||
|
min-width: 0; |
||||||
|
overflow: hidden; |
||||||
|
text-overflow: ellipsis; |
||||||
|
display: -webkit-box; |
||||||
|
-webkit-line-clamp: 2; |
||||||
|
-webkit-box-orient: vertical; |
||||||
|
} |
||||||
|
.specification { |
||||||
|
display: inline-block; |
||||||
|
margin-top: 8rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #b6b7ba; |
||||||
|
border-radius: 10rpx; |
||||||
|
} |
||||||
|
.price { |
||||||
|
margin-top: 14rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
.num { |
||||||
|
font-size: 32rpx; |
||||||
|
color: #e04775; |
||||||
|
font-weight: bold; |
||||||
|
.sub { |
||||||
|
font-size: 22rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.val { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #b6b7ba; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.footer { |
||||||
|
border-top: 1px solid #ebebeb; |
||||||
|
padding-top: 32rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
.content { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #bbbcbe; |
||||||
|
display: flex; |
||||||
|
align-items: baseline; |
||||||
|
.num { |
||||||
|
font-size: 42rpx; |
||||||
|
color: #e04775; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
} |
||||||
|
.btn { |
||||||
|
width: 152rpx; |
||||||
|
height: 52rpx; |
||||||
|
border-radius: 8rpx; |
||||||
|
border: 1rpx solid rgba(158, 158, 158, 0.42); |
||||||
|
font-size: 28rpx; |
||||||
|
color: #3f3f3f; |
||||||
|
text-align: center; |
||||||
|
line-height: 52rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,48 @@ |
|||||||
|
const app = getApp<IAppOption>(); |
||||||
|
|
||||||
|
Page({ |
||||||
|
data: { |
||||||
|
list: [], |
||||||
|
pagination: { |
||||||
|
page: 1, |
||||||
|
pages: 1, |
||||||
|
count: 1, |
||||||
|
}, |
||||||
|
}, |
||||||
|
onLoad() { |
||||||
|
app.waitLogin().then(() => { |
||||||
|
this.getList(); |
||||||
|
}); |
||||||
|
}, |
||||||
|
getList(newPage = 1) { |
||||||
|
wx.ajax({ |
||||||
|
method: "POST", |
||||||
|
url: "?r=zd/gift-order/get-order-list", |
||||||
|
data: { |
||||||
|
page: newPage, |
||||||
|
}, |
||||||
|
}).then((res) => { |
||||||
|
let list = res.page == 1 ? res.list : [...this.data.list, ...res.list]; |
||||||
|
this.setData({ |
||||||
|
list: list, |
||||||
|
pagination: { |
||||||
|
page: res.page, |
||||||
|
pages: res.pages, |
||||||
|
count: res.count, |
||||||
|
}, |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
handleDetail(e: any) { |
||||||
|
const { id } = e.currentTarget.dataset; |
||||||
|
wx.navigateTo({ |
||||||
|
url: `/gift/pages/orderDetail/index?id=${id}`, |
||||||
|
}); |
||||||
|
}, |
||||||
|
onReachBottom() { |
||||||
|
const { page, pages } = this.data.pagination; |
||||||
|
if (pages > page) { |
||||||
|
this.getList(page + 1); |
||||||
|
} |
||||||
|
}, |
||||||
|
}); |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
<view class="page"> |
||||||
|
<view class="card" wx:for="{{list}}" wx:key="index" bind:tap="handleDetail" data-id="{{item.orderId}}"> |
||||||
|
<view class="header"> |
||||||
|
<view class="on">订单号:{{item.orderNo}}</view> |
||||||
|
<view class="status" wx:if="{{item.status==2}}">{{item.statusName}}</view> |
||||||
|
<view class="status suc" wx:else>{{item.statusName}}</view> |
||||||
|
</view> |
||||||
|
<view class="shop"> |
||||||
|
<image class="shop-img" src="{{item.giftBigImg}}"></image> |
||||||
|
<view class="wrap"> |
||||||
|
<view class="name">{{item.giftName}}</view> |
||||||
|
<view class="specification" wx:if="{{item.specName}}">规格:{{item.specName}}</view> |
||||||
|
<view class="price"> |
||||||
|
<view class="num">{{item.giftScore}}<text class="sub">能量</text></view> |
||||||
|
<view class="val">x{{item.orderCount}}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="footer"> |
||||||
|
<view class="content"> |
||||||
|
共{{item.orderCount}}件 消耗能量: |
||||||
|
<view class="num">{{item.orderScore}}</view> |
||||||
|
</view> |
||||||
|
<view class="btn" wx:if="{{item.status==3}}">查看物流</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<pagination pagination="{{pagination}}"></pagination> |
||||||
|
</view> |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
{ |
||||||
|
"navigationBarTitleText": "我的健康记录", |
||||||
|
"navigationStyle": "custom", |
||||||
|
"usingComponents": { |
||||||
|
"navBar": "/components/zd-navBar/navBar", |
||||||
|
"van-icon": "@vant/weapp/icon/index", |
||||||
|
"calendar": "/components/calendar/index", |
||||||
|
"toast": "/components/toast/index", |
||||||
|
"ec-canvas": "/components/ec-canvas/ec-canvas" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,741 @@ |
|||||||
|
page { |
||||||
|
background-color: rgba(250, 250, 250, 1); |
||||||
|
min-height: 100vh; |
||||||
|
padding-bottom: 200rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.page { |
||||||
|
padding: 0 40rpx 33rpx; |
||||||
|
|
||||||
|
.calendar-wrap { |
||||||
|
height: 80rpx; |
||||||
|
overflow: hidden; |
||||||
|
transition: all 0.5s; |
||||||
|
.calendar { |
||||||
|
margin: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.legend { |
||||||
|
margin-top: 30rpx; |
||||||
|
display: flex; |
||||||
|
> view:not(:last-of-type), |
||||||
|
> image { |
||||||
|
margin-right: 38rpx; |
||||||
|
} |
||||||
|
justify-content: flex-end; |
||||||
|
|
||||||
|
.item { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
> view:not(:last-of-type), |
||||||
|
> image { |
||||||
|
margin-right: 11rpx; |
||||||
|
} |
||||||
|
font-size: 24rpx; |
||||||
|
color: rgba(79, 79, 79, 1); |
||||||
|
|
||||||
|
&::before { |
||||||
|
margin-right: 10rpx; |
||||||
|
content: ""; |
||||||
|
width: 16rpx; |
||||||
|
height: 16rpx; |
||||||
|
border-radius: 50%; |
||||||
|
} |
||||||
|
} |
||||||
|
.drugs { |
||||||
|
.icon { |
||||||
|
width: 17rpx; |
||||||
|
height: 24rpx; |
||||||
|
} |
||||||
|
font-size: 24rpx; |
||||||
|
color: rgba(79, 79, 79, 1); |
||||||
|
} |
||||||
|
|
||||||
|
.item1 { |
||||||
|
&::before { |
||||||
|
background-color: rgba(207, 83, 117, 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.item2 { |
||||||
|
&::before { |
||||||
|
background-color: rgba(37, 217, 200, 1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
&.expend { |
||||||
|
height: 600rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.p-fold { |
||||||
|
padding: 20rpx; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
.chart { |
||||||
|
margin-top: 34rpx; |
||||||
|
.c-header { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
.title { |
||||||
|
font-size: 32rpx; |
||||||
|
color: rgba(71, 71, 71, 1); |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
.more { |
||||||
|
font-size: 24rpx; |
||||||
|
color: rgba(204, 204, 204, 1); |
||||||
|
} |
||||||
|
} |
||||||
|
.c-container { |
||||||
|
margin-top: 24rpx; |
||||||
|
background-color: #fff; |
||||||
|
border-radius: 24rpx; |
||||||
|
border: 1rpx solid rgba(0, 0, 0, 0.1); |
||||||
|
.c-header { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
border-bottom: 1rpx solid rgba(0, 0, 0, 0.1); |
||||||
|
.c-nav { |
||||||
|
overflow: hidden; |
||||||
|
flex: 1; |
||||||
|
display: flex; |
||||||
|
.nav-item { |
||||||
|
padding: 16rpx 0; |
||||||
|
width: 80rpx; |
||||||
|
text-align: center; |
||||||
|
line-height: 42rpx; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #666666; |
||||||
|
font-weight: bold; |
||||||
|
&.active { |
||||||
|
position: relative; |
||||||
|
color: #cf5375; |
||||||
|
&::after { |
||||||
|
position: absolute; |
||||||
|
bottom: 0; |
||||||
|
left: -5rpx; |
||||||
|
content: ""; |
||||||
|
width: 90rpx; |
||||||
|
height: 4rpx; |
||||||
|
background: #cf5375; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.fill { |
||||||
|
margin-right: 40rpx; |
||||||
|
width: 24rpx; |
||||||
|
height: 24rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.c-content { |
||||||
|
padding: 16rpx 0; |
||||||
|
.search-num { |
||||||
|
padding: 0 32rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
.col { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
.input { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #666666; |
||||||
|
border: 1px solid #ccc; |
||||||
|
padding-left: 1em; |
||||||
|
border-radius: 12rpx; |
||||||
|
} |
||||||
|
.btn { |
||||||
|
margin-left: 20rpx; |
||||||
|
padding: 4rpx 10rpx; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #fff; |
||||||
|
border-radius: 12rpx; |
||||||
|
background-color: #e04775; |
||||||
|
} |
||||||
|
} |
||||||
|
.all { |
||||||
|
font-size: 24rpx; |
||||||
|
color: rgba(79, 79, 79, 1); |
||||||
|
} |
||||||
|
} |
||||||
|
.search { |
||||||
|
padding: 0 36rpx 16rpx; |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
border-bottom: 1rpx solid rgba(0, 0, 0, 0.1); |
||||||
|
.date { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #666666; |
||||||
|
.line { |
||||||
|
margin: 0 10rpx; |
||||||
|
} |
||||||
|
.icon { |
||||||
|
transform: rotate(90deg); |
||||||
|
color: #666666; |
||||||
|
} |
||||||
|
} |
||||||
|
.result { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #666666; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
.icon { |
||||||
|
margin-right: 9rpx; |
||||||
|
width: 26rpx; |
||||||
|
height: 30rpx; |
||||||
|
} |
||||||
|
.question { |
||||||
|
width: 24rpx; |
||||||
|
height: 24rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.wrap { |
||||||
|
padding: 0 36rpx; |
||||||
|
.w-header { |
||||||
|
padding-top: 32rpx; |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
.title { |
||||||
|
font-size: 32rpx; |
||||||
|
color: #484848; |
||||||
|
} |
||||||
|
.legend { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
gap: 25rpx; |
||||||
|
.item { |
||||||
|
font-size: 20rpx; |
||||||
|
color: #4f4f4f; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
.logo { |
||||||
|
margin-right: 8rpx; |
||||||
|
width: 16rpx; |
||||||
|
height: 16rpx; |
||||||
|
border-radius: 50%; |
||||||
|
background-color: #cf5375; |
||||||
|
&.hormone { |
||||||
|
background-color: #3192A1; |
||||||
|
} |
||||||
|
} |
||||||
|
.icon { |
||||||
|
margin-right: 8rpx; |
||||||
|
width: 17rpx; |
||||||
|
height: 24rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.unit { |
||||||
|
font-size: 22rpx; |
||||||
|
color: #ccc; |
||||||
|
margin-bottom: -40rpx; |
||||||
|
} |
||||||
|
.w-chart { |
||||||
|
position: relative; |
||||||
|
padding-top: 20rpx; |
||||||
|
height: 500rpx; |
||||||
|
.touch { |
||||||
|
position: absolute; |
||||||
|
z-index: 100; |
||||||
|
width: 100%; |
||||||
|
height: 250rpx; |
||||||
|
} |
||||||
|
.left { |
||||||
|
position: absolute; |
||||||
|
top: 180rpx; |
||||||
|
left: -65rpx; |
||||||
|
width: 56rpx; |
||||||
|
height: 56rpx; |
||||||
|
background: #ffffff; |
||||||
|
box-shadow: 0rpx 6rpx 28rpx 0rpx rgba(0, 0, 0, 0.18); |
||||||
|
border: 1rpx solid #e8e8e8; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
border-radius: 50%; |
||||||
|
.icon { |
||||||
|
width: 18rpx; |
||||||
|
height: 28rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.right { |
||||||
|
position: absolute; |
||||||
|
top: 180rpx; |
||||||
|
right: -65rpx; |
||||||
|
width: 56rpx; |
||||||
|
height: 56rpx; |
||||||
|
background: #ffffff; |
||||||
|
box-shadow: 0rpx 6rpx 28rpx 0rpx rgba(0, 0, 0, 0.18); |
||||||
|
border: 1rpx solid #e8e8e8; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
border-radius: 50%; |
||||||
|
.icon { |
||||||
|
width: 18rpx; |
||||||
|
height: 28rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.share { |
||||||
|
padding: 40rpx 0 10rpx; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #e04775; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
.icon { |
||||||
|
margin-right: 8rpx; |
||||||
|
width: 22rpx; |
||||||
|
height: 22rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.banner { |
||||||
|
margin: 36rpx 0 0; |
||||||
|
padding: 20rpx; |
||||||
|
border-radius: 24rpx; |
||||||
|
background-color: #e04775; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
.inner { |
||||||
|
flex: 1; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #fafafa; |
||||||
|
} |
||||||
|
.btn { |
||||||
|
flex-shrink: 0; |
||||||
|
width: 152rpx; |
||||||
|
height: 64rpx; |
||||||
|
text-align: center; |
||||||
|
line-height: 64rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #e04775; |
||||||
|
background: #ffffff; |
||||||
|
border-radius: 12rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.tabs { |
||||||
|
margin-top: 36rpx; |
||||||
|
display: inline-flex; |
||||||
|
background-color: #fff; |
||||||
|
box-shadow: 0rpx 8rpx 32rpx 0rpx rgba(0, 0, 0, 0.13); |
||||||
|
border-radius: 12rpx; |
||||||
|
overflow: hidden; |
||||||
|
.tab { |
||||||
|
padding: 10rpx 20rpx; |
||||||
|
line-height: 40rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #666666; |
||||||
|
background-color: #fff; |
||||||
|
&.active { |
||||||
|
background-color: #e04775; |
||||||
|
color: #fff; |
||||||
|
} |
||||||
|
&:nth-of-type(2) { |
||||||
|
border: 1px solid #dddddd; |
||||||
|
border-top: none; |
||||||
|
border-bottom: none; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.detail { |
||||||
|
margin-top: 34rpx; |
||||||
|
.d-header { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
.title { |
||||||
|
font-size: 32rpx; |
||||||
|
color: rgba(71, 71, 71, 1); |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
.more { |
||||||
|
font-size: 24rpx; |
||||||
|
color: rgba(204, 204, 204, 1); |
||||||
|
} |
||||||
|
} |
||||||
|
.module { |
||||||
|
margin-top: 30rpx; |
||||||
|
.module-header { |
||||||
|
display: flex; |
||||||
|
.date { |
||||||
|
flex-shrink: 0; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #333333; |
||||||
|
} |
||||||
|
.tags { |
||||||
|
margin-left: 14rpx; |
||||||
|
flex: 1; |
||||||
|
display: flex; |
||||||
|
flex-wrap: nowrap; |
||||||
|
overflow-x: scroll; |
||||||
|
white-space: nowrap; |
||||||
|
&::-webkit-scrollbar { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
.tag1 { |
||||||
|
margin-left: 14rpx; |
||||||
|
padding: 0 12rpx; |
||||||
|
background: #d86687; |
||||||
|
border-radius: 6rpx; |
||||||
|
font-size: 24rpx; |
||||||
|
line-height: 36rpx; |
||||||
|
text-align: center; |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
.tag2 { |
||||||
|
margin-left: 14rpx; |
||||||
|
padding: 0 12rpx; |
||||||
|
background: #0b184f; |
||||||
|
border-radius: 6rpx; |
||||||
|
font-size: 24rpx; |
||||||
|
line-height: 36rpx; |
||||||
|
text-align: center; |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
.tag3 { |
||||||
|
margin-left: 14rpx; |
||||||
|
padding: 0 12rpx; |
||||||
|
background: #24d8c8; |
||||||
|
border-radius: 6rpx; |
||||||
|
font-size: 24rpx; |
||||||
|
line-height: 36rpx; |
||||||
|
text-align: center; |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.module-container { |
||||||
|
margin-top: 24rpx; |
||||||
|
display: flex; |
||||||
|
.aside { |
||||||
|
margin-right: 30rpx; |
||||||
|
padding-left: 14rpx; |
||||||
|
border-right: 1px dashed #dddddd; |
||||||
|
} |
||||||
|
.card { |
||||||
|
flex: 1; |
||||||
|
box-shadow: 0 4rpx 29rpx 0rpx rgba(207, 83, 116, 0.25); |
||||||
|
border-radius: 24rpx; |
||||||
|
.card-header { |
||||||
|
padding: 20rpx 18rpx 4rpx 48rpx; |
||||||
|
border-radius: 24rpx 24rpx 0 0; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
box-shadow: 8rpx 8rpx 16rpx 0rpx rgba(143, 217, 226, 0.1); |
||||||
|
&.grade1 { |
||||||
|
background: linear-gradient(90deg, #26dac9 7%, rgba(143, 217, 226, 0) 70%, rgba(143, 217, 226, 0) 100%); |
||||||
|
} |
||||||
|
&.grade2 { |
||||||
|
background: linear-gradient( |
||||||
|
90deg, |
||||||
|
rgba(235, 111, 87, 1) 7%, |
||||||
|
rgba(143, 217, 226, 0) 70%, |
||||||
|
rgba(143, 217, 226, 0) 100% |
||||||
|
); |
||||||
|
} |
||||||
|
&.grade3 { |
||||||
|
background: linear-gradient( |
||||||
|
90deg, |
||||||
|
rgba(207, 83, 117, 1) 7%, |
||||||
|
rgba(143, 217, 226, 0) 70%, |
||||||
|
rgba(143, 217, 226, 0) 100% |
||||||
|
); |
||||||
|
} |
||||||
|
.num { |
||||||
|
display: flex; |
||||||
|
align-items: baseline; |
||||||
|
font-size: 96rpx; |
||||||
|
line-height: 1; |
||||||
|
color: #ffffff; |
||||||
|
letter-spacing: 4rpx; |
||||||
|
.sub { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #fff; |
||||||
|
} |
||||||
|
} |
||||||
|
.num-detail { |
||||||
|
display: flex; |
||||||
|
.n-item { |
||||||
|
width: 73rpx; |
||||||
|
&.active { |
||||||
|
.box { |
||||||
|
background-color: #cf5375; |
||||||
|
} |
||||||
|
} |
||||||
|
.box { |
||||||
|
width: 45rpx; |
||||||
|
height: 45rpx; |
||||||
|
width: 45rpx; |
||||||
|
height: 45rpx; |
||||||
|
font-size: 32rpx; |
||||||
|
color: #fff; |
||||||
|
text-align: center; |
||||||
|
line-height: 45rpx; |
||||||
|
background: #333333; |
||||||
|
border-radius: 12rpx 12rpx 12rpx 12rpx; |
||||||
|
} |
||||||
|
.name { |
||||||
|
font-size: 24rpx; |
||||||
|
line-height: 48rpx; |
||||||
|
color: rgba(51, 51, 51, 0.5); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.status { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #989898; |
||||||
|
text-align: right; |
||||||
|
.s-num { |
||||||
|
font-size: 32rpx; |
||||||
|
} |
||||||
|
.s-core { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #989898; |
||||||
|
// background: #484848; |
||||||
|
border-radius: 6rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.card-container { |
||||||
|
padding: 8rpx 23rpx 20rpx; |
||||||
|
border-radius: 0 0 24rpx 24rpx; |
||||||
|
background-color: #fff; |
||||||
|
.cc-title { |
||||||
|
text-indent: 22rpx; |
||||||
|
font-size: 24rpx; |
||||||
|
color: rgba(79, 79, 79, 1); |
||||||
|
} |
||||||
|
.cc-content { |
||||||
|
margin-top: 12rpx; |
||||||
|
padding: 16rpx 20rpx; |
||||||
|
border-radius: 24rpx; |
||||||
|
background-color: rgba(249, 249, 249, 1); |
||||||
|
.line { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #666666; |
||||||
|
line-height: 36rpx; |
||||||
|
.dot { |
||||||
|
color: #666666; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
.red { |
||||||
|
color: #cf5375; |
||||||
|
} |
||||||
|
.green { |
||||||
|
color: #25d9c8; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.fold { |
||||||
|
margin-top: 16rpx; |
||||||
|
.fold-header { |
||||||
|
display: flex; |
||||||
|
justify-content: flex-end; |
||||||
|
font-size: 24rpx; |
||||||
|
color: rgba(204, 204, 204, 1); |
||||||
|
} |
||||||
|
.fold-container { |
||||||
|
padding-top: 10rpx; |
||||||
|
height: 500rpx; |
||||||
|
overflow: hidden; |
||||||
|
transition: all 0.5s; |
||||||
|
&.hide { |
||||||
|
padding: 0; |
||||||
|
height: 0; |
||||||
|
} |
||||||
|
.fold-img { |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
.scurt { |
||||||
|
width: 100%; |
||||||
|
border: 1px solid rgba(0, 0, 0, 0.1); |
||||||
|
box-sizing: border-box; |
||||||
|
.s-header { |
||||||
|
display: flex; |
||||||
|
height: 40rpx; |
||||||
|
margin-bottom: -1px; |
||||||
|
border-bottom: 1rpx solid rgba(0, 0, 0, 0.1); |
||||||
|
.none { |
||||||
|
flex-shrink: 0; |
||||||
|
width: 226rpx; |
||||||
|
background-color: rgba(228, 228, 228, 1); |
||||||
|
} |
||||||
|
.bar { |
||||||
|
flex: 1; |
||||||
|
display: flex; |
||||||
|
.num { |
||||||
|
flex: 1; |
||||||
|
text-align: center; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #fff; |
||||||
|
line-height: 40rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.s-body { |
||||||
|
display: flex; |
||||||
|
.s-aside { |
||||||
|
width: 28rpx; |
||||||
|
background-color: rgba(102, 102, 102, 0.15); |
||||||
|
flex-shrink: 0; |
||||||
|
.sa-item { |
||||||
|
display: flex; |
||||||
|
text-align: center; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
font-size: 18rpx; |
||||||
|
color: rgba(102, 102, 102, 1); |
||||||
|
line-height: 1; |
||||||
|
overflow: hidden; |
||||||
|
&:not(:last-of-type) { |
||||||
|
margin-bottom: -1px; |
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.1); |
||||||
|
} |
||||||
|
} |
||||||
|
.sa-item1 { |
||||||
|
height: 158rpx; |
||||||
|
} |
||||||
|
.sa-item2 { |
||||||
|
height: 54rpx; |
||||||
|
} |
||||||
|
.sa-item3 { |
||||||
|
height: 106rpx; |
||||||
|
} |
||||||
|
.sa-item4 { |
||||||
|
height: 108rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.s-container { |
||||||
|
flex: 1; |
||||||
|
.sc-row { |
||||||
|
display: flex; |
||||||
|
height: 54rpx; |
||||||
|
overflow: hidden; |
||||||
|
.sc-title { |
||||||
|
width: 198rpx; |
||||||
|
font-size: 18rpx; |
||||||
|
color: rgba(102, 102, 102, 1); |
||||||
|
text-align: center; |
||||||
|
line-height: 53rpx; |
||||||
|
} |
||||||
|
.sc-col { |
||||||
|
margin-left: -1px; |
||||||
|
border-left: 1px solid rgba(0, 0, 0, 0.1); |
||||||
|
flex: 1; |
||||||
|
text-align: center; |
||||||
|
.icon { |
||||||
|
margin-top: 11rpx; |
||||||
|
width: 32rpx; |
||||||
|
height: 32rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.sc-row:not(:last-of-type) { |
||||||
|
margin-bottom: -1px; |
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.1); |
||||||
|
} |
||||||
|
.sc-row:nth-of-type(2n-1) { |
||||||
|
background-color: rgba(217, 217, 217, 0.2); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.sub-card { |
||||||
|
flex: 1; |
||||||
|
padding: 14rpx 24rpx 14rpx 48rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
background: linear-gradient(110deg, #2280d5 0%, #ffffff 60%, #ffffff 100%); |
||||||
|
box-shadow: 0 4rpx 29rpx 0rpx rgba(207, 83, 116, 0.25); |
||||||
|
border-radius: 24rpx; |
||||||
|
.left { |
||||||
|
font-size: 96rpx; |
||||||
|
color: #fff; |
||||||
|
line-height: 1; |
||||||
|
.sub { |
||||||
|
font-size: 24rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.inner { |
||||||
|
text-align: right; |
||||||
|
.i-title { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #989898; |
||||||
|
.num { |
||||||
|
font-size: 32rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.sign { |
||||||
|
font-size: 32rpx; |
||||||
|
.num { |
||||||
|
font-size: 40rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.i-content { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #989898; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.drug-card { |
||||||
|
margin-top: 30rpx; |
||||||
|
flex: 1; |
||||||
|
box-shadow: 0 4rpx 29rpx 0rpx rgba(207, 83, 116, 0.25); |
||||||
|
border-radius: 24rpx; |
||||||
|
.d-header { |
||||||
|
border-radius: 24rpx 0 0 0; |
||||||
|
padding: 20rpx 50rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
background: linear-gradient(95deg, #26dac9 7%, rgba(143, 217, 226, 0) 100%); |
||||||
|
.name { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
.status { |
||||||
|
font-size: 22rpx; |
||||||
|
color: #5b6363; |
||||||
|
.num { |
||||||
|
font-size: 22rpx; |
||||||
|
color: #cf5375; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.content { |
||||||
|
padding: 20rpx 50rpx; |
||||||
|
font-size: 22rpx; |
||||||
|
color: #666666; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.add { |
||||||
|
position: fixed; |
||||||
|
left: 50%; |
||||||
|
bottom: 45rpx; |
||||||
|
transform: translateX(-50%); |
||||||
|
width: 152rpx; |
||||||
|
height: 152rpx; |
||||||
|
z-index: 10000; |
||||||
|
} |
||||||
|
} |
||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue