Compare View

switch
from
...
to
 
Commits (5)
Showing 92 changed files   Show diff stats
app.js
... ... @@ -44,9 +44,10 @@ App({
44 44 view.onShareAppMessage = function () {
45 45 //你的分享配置
46 46 return {
47   - title: name + '推荐大家都在用的升学大数据宝典',
  47 + title: name + '推荐您 一起开始自主学习之旅',
48 48 path: '/pages/index/index',
49   - imageUrl: 'https://proxy.shunzhi.net:51315/mp_share2.jpg',
  49 + // imageUrl: 'https://proxy.shunzhi.net:51315/mp_share2.jpg',
  50 + imageUrl: 'https://szyundisk.oss-cn-hangzhou.aliyuncs.com/AdmissionsManageSys/37317060-9e67-41e1-9731-b722c83cff8a.jpg',
50 51 };
51 52 }
52 53 }
... ...
app.json
1 1 {
2 2 "pages": [
3   - "pages/index/index",
4   - "pages/index/rank/rank",
  3 + "pages/login/loginNew/loginNew",
  4 + "pages/login/codeLogin/codeLogin",
5 5 "pages/index/achievement/achievement",
6   - "pages/index/punchDetail/punchDetail",
  6 + "pages/index/rank/rank",
  7 + "pages/index/index",
7 8 "pages/index/newPunch/newPunch",
8   - "pages/login/codeLogin/codeLogin",
  9 + "pages/mine/record/record",
  10 + "pages/mine/index",
  11 + "pages/index/punchDetail/punchDetail",
9 12 "pages/login/protocol/protocol",
10 13 "pages/login/policy/policy",
11   - "pages/mine/index",
12   - "pages/mine/record/record",
13 14 "pages/webview/webview"
14 15 ],
15 16 "window": {
16 17 "backgroundTextStyle": "dark",
17 18 "navigationBarBackgroundColor": "#fff",
18   - "navigationBarTitleText": "计划管家",
  19 + "navigationBarTitleText": "打卡管理",
19 20 "navigationBarTextStyle": "black"
20 21 },
21 22 "tabBar": {
... ... @@ -24,7 +25,7 @@
24 25 "borderStyle": "white",
25 26 "list": [
26 27 {
27   - "pagePath": "pages/index/index",
  28 + "pagePath": "pages/index/rank/rank",
28 29 "text": "首页",
29 30 "iconPath": "./img/tab_home_normat.png",
30 31 "selectedIconPath": "./img/tab_home_selected.png"
... ...
app.wxss
1   -/* @import "/miniprogram_npm/@vant/weapp/common/index.wxss"; */
2   -page{
  1 +@import "/miniprogram_npm/@vant/weapp/common/index.wxss";
  2 +/* page{
3 3 background: #fff;
4   -}
  4 +} */
5 5 /* 二级页面顶部统一返回按钮,位置可能需要根据机型调整 */
6 6 .navigation_back{
7 7 width: 80rpx;
... ...
component/v2/core.js 0 → 100644
... ... @@ -0,0 +1,144 @@
  1 +import { dateUtil, getCalendarConfig } from './utils/index'
  2 +
  3 +/**
  4 + * 计算当前月份前后两月应占的格子
  5 + * @param {number} year 年份
  6 + * @param {number} month 月份
  7 + */
  8 +function calculateEmptyGrids(year, month, config) {
  9 + const prevMonthGrids = calculatePrevMonthGrids(year, month, config)
  10 + const nextMonthGrids = calculateNextMonthGrids(year, month, config)
  11 + return {
  12 + prevMonthGrids,
  13 + nextMonthGrids
  14 + }
  15 +}
  16 +
  17 +/**
  18 + * 计算上月应占的格子
  19 + * @param {number} year 年份
  20 + * @param {number} month 月份
  21 + */
  22 +function calculatePrevMonthGrids(year, month, config) {
  23 + let emptyGrids = []
  24 + const prevMonthDays = dateUtil.getDatesCountOfMonth(year, month - 1)
  25 + let firstDayOfWeek = dateUtil.firstDayOfWeek(year, month)
  26 + if (config.firstDayOfWeek === 'Mon') {
  27 + if (firstDayOfWeek === 0) {
  28 + firstDayOfWeek = 6
  29 + } else {
  30 + firstDayOfWeek -= 1
  31 + }
  32 + }
  33 + if (firstDayOfWeek > 0) {
  34 + const len = prevMonthDays - firstDayOfWeek
  35 + const { onlyShowCurrentMonth } = config
  36 + const YMInfo = dateUtil.getPrevMonthInfo({ year, month })
  37 + for (let i = prevMonthDays; i > len; i--) {
  38 + if (onlyShowCurrentMonth) {
  39 + emptyGrids.push('')
  40 + } else {
  41 + const week = dateUtil.getDayOfWeek(+year, +month, i)
  42 + emptyGrids.push({
  43 + ...YMInfo,
  44 + date: i,
  45 + week
  46 + })
  47 + }
  48 + }
  49 + emptyGrids.reverse()
  50 + }
  51 + return emptyGrids
  52 +}
  53 +/**
  54 + * 计算下一月日期是否需要多展示的日期
  55 + * 某些月份日期为5排,某些月份6排,统一为6排
  56 + * @param {number} year
  57 + * @param {number} month
  58 + * @param {object} config
  59 + */
  60 +function calculateExtraEmptyDate(year, month, config) {
  61 + let extDate = 0
  62 + if (+month === 2) {
  63 + extDate += 7
  64 + let firstDayofMonth = dateUtil.getDayOfWeek(year, month, 1)
  65 + if (config.firstDayOfWeek === 'Mon') {
  66 + if (+firstDayofMonth === 1) extDate += 7
  67 + } else {
  68 + if (+firstDayofMonth === 0) extDate += 7
  69 + }
  70 + } else {
  71 + let firstDayofMonth = dateUtil.getDayOfWeek(year, month, 1)
  72 + if (config.firstDayOfWeek === 'Mon') {
  73 + if (firstDayofMonth !== 0 && firstDayofMonth < 6) {
  74 + extDate += 7
  75 + }
  76 + } else {
  77 + if (firstDayofMonth <= 5) {
  78 + extDate += 7
  79 + }
  80 + }
  81 + }
  82 + return extDate
  83 +}
  84 +/**
  85 + * 计算下月应占的格子
  86 + * @param {number} year 年份
  87 + * @param {number} month 月份
  88 + */
  89 +function calculateNextMonthGrids(year, month, config) {
  90 + let emptyGrids = []
  91 + const datesCount = dateUtil.getDatesCountOfMonth(year, month)
  92 + let lastDayWeek = dateUtil.getDayOfWeek(year, month, datesCount)
  93 + if (config.firstDayOfWeek === 'Mon') {
  94 + if (lastDayWeek === 0) {
  95 + lastDayWeek = 6
  96 + } else {
  97 + lastDayWeek -= 1
  98 + }
  99 + }
  100 + let len = 7 - (lastDayWeek + 1)
  101 + const { onlyShowCurrentMonth } = config
  102 + if (!onlyShowCurrentMonth) {
  103 + len = len + calculateExtraEmptyDate(year, month, config)
  104 + }
  105 + const YMInfo = dateUtil.getNextMonthInfo({ year, month })
  106 + for (let i = 1; i <= len; i++) {
  107 + const week = dateUtil.getDayOfWeek(+year, +month, i)
  108 + if (onlyShowCurrentMonth) {
  109 + emptyGrids.push('')
  110 + } else {
  111 + emptyGrids.push({
  112 + id: i - 1,
  113 + ...YMInfo,
  114 + date: i,
  115 + week: week || 7
  116 + })
  117 + }
  118 + }
  119 + return emptyGrids
  120 +}
  121 +/**
  122 + * 设置日历面板数据
  123 + * @param {number} year 年份
  124 + * @param {number} month 月份
  125 + * @param {number} curDate 日期
  126 + */
  127 +function calculateCurrentMonthDates(year, month) {
  128 + return dateUtil.calcDates(year, month)
  129 +}
  130 +
  131 +export function calcJumpData({ dateInfo, config, component }) {
  132 + dateInfo = dateInfo || dateUtil.todayFMD()
  133 + const { year, month, date } = dateInfo
  134 + const calendarConfig = config || getCalendarConfig(component)
  135 + const emptyGrids = calculateEmptyGrids(year, month, calendarConfig)
  136 + const calendar = {
  137 + curYear: year,
  138 + curMonth: month,
  139 + curDate: date,
  140 + dates: calculateCurrentMonthDates(year, month),
  141 + ...emptyGrids
  142 + }
  143 + return calendar
  144 +}
... ...
component/v2/helper.js 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +import { dateUtil } from './utils/index'
  2 +
  3 +export function calcTargetYMInfo() {
  4 + return {
  5 + right: dateUtil.getPrevMonthInfo,
  6 + left: dateUtil.getNextMonthInfo,
  7 + prev_month: dateUtil.getPrevMonthInfo,
  8 + next_month: dateUtil.getNextMonthInfo,
  9 + prev_year: dateUtil.getPrevYearInfo,
  10 + next_year: dateUtil.getNextYearInfo
  11 + }
  12 +}
... ...
component/v2/index.js 0 → 100644
... ... @@ -0,0 +1,257 @@
  1 +import plugins from './plugins/index'
  2 +import { calcJumpData } from './core'
  3 +import { renderCalendar } from './render'
  4 +import { calcTargetYMInfo } from './helper'
  5 +import { dateUtil, calendarGesture, logger } from './utils/index'
  6 +
  7 +Component({
  8 + options: {
  9 + styleIsolation: 'apply-shared',
  10 + multipleSlots: true // 在组件定义时的选项中启用多slot支持
  11 + },
  12 + properties: {
  13 + config: {
  14 + type: Object,
  15 + value: {}
  16 + }
  17 + },
  18 + lifetimes: {
  19 + attached: function() {
  20 + this.initComp()
  21 + }
  22 + },
  23 + methods: {
  24 + initComp() {
  25 + const calendarConfig = this.setDefaultDisableDate()
  26 + this.setConfig(calendarConfig)
  27 + },
  28 + // 禁用某天日期配置默认为今天
  29 + setDefaultDisableDate() {
  30 + const calendarConfig = this.properties.config || {}
  31 + if (calendarConfig.disableMode && !calendarConfig.disableMode.date) {
  32 + calendarConfig.disableMode.date = dateUtil.toTimeStr(
  33 + dateUtil.todayFMD()
  34 + )
  35 + }
  36 + return calendarConfig
  37 + },
  38 + initCalendar(config) {
  39 + const { defaultDate } = config
  40 + let date = dateUtil.todayFMD()
  41 + if (defaultDate && typeof defaultDate === 'string') {
  42 + const dateInfo = defaultDate.split('-')
  43 + if (dateInfo.length < 3) {
  44 + return logger.warn('defaultDate配置格式应为: 2018-4-2 或 2018-04-02')
  45 + } else {
  46 + date = {
  47 + year: +dateInfo[0],
  48 + month: +dateInfo[1],
  49 + date: +dateInfo[2]
  50 + }
  51 + }
  52 + }
  53 + const waitRenderData = calcJumpData({
  54 + dateInfo: date,
  55 + config
  56 + })
  57 + const timestamp = dateUtil.todayTimestamp()
  58 + if (config.autoChoosedWhenJump) {
  59 + const target = waitRenderData.dates.filter(
  60 + item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(date)
  61 + )
  62 + if (target && target.length) {
  63 + if (!waitRenderData.selectedDates) {
  64 + waitRenderData.selectedDates = target
  65 + } else {
  66 + waitRenderData.selectedDates.push(target[0])
  67 + }
  68 + }
  69 + }
  70 + return {
  71 + ...waitRenderData,
  72 + todayTimestamp: timestamp,
  73 + weeksCh: dateUtil.getWeekHeader(config.firstDayOfWeek)
  74 + }
  75 + },
  76 + setConfig(config) {
  77 + if (config.markToday && typeof config.markToday === 'string') {
  78 + config.highlightToday = true
  79 + }
  80 + config.theme = config.theme || 'default'
  81 + this.setData(
  82 + {
  83 + config
  84 + },
  85 + () => {
  86 + for (let plugin of plugins.installed) {
  87 + const [, p] = plugin
  88 + if (typeof p.install === 'function') {
  89 + p.install(this)
  90 + }
  91 + if (typeof p.methods === 'function') {
  92 + const methods = p.methods(this)
  93 + for (let fnName in methods) {
  94 + if (fnName.startsWith('__')) continue
  95 + const fn = methods[fnName]
  96 + if (typeof fn === 'function') {
  97 + if (!this.calendar) this.calendar = {}
  98 + this.calendar[fnName] = fn
  99 + }
  100 + }
  101 + }
  102 + }
  103 + const initData = this.initCalendar(config)
  104 + renderCalendar.call(this, initData, config)
  105 + }
  106 + )
  107 + },
  108 + tapDate(e) {
  109 + const { info } = e.currentTarget.dataset
  110 + const { date, disable } = info || {}
  111 + if (disable || !date) return
  112 + const { calendar, config } = this.data
  113 + let calendarData = calendar
  114 + let calendarConfig = config
  115 + if (config.takeoverTap) {
  116 + return this.triggerEvent('takeoverTap', info)
  117 + }
  118 + for (let plugin of plugins.installed) {
  119 + const [, p] = plugin
  120 + if (typeof p.onTapDate === 'function') {
  121 + const {
  122 + calendarData: __calendarData,
  123 + calendarConfig: __calendarConfig
  124 + } = p.onTapDate(info, calendarData, calendarConfig)
  125 + calendarData = __calendarData
  126 + calendarConfig = __calendarConfig
  127 + }
  128 + }
  129 + renderCalendar.call(this, calendarData, calendarConfig).then(() => {
  130 + this.triggerEvent('afterTapDate', info)
  131 + })
  132 + },
  133 + /**
  134 + * 日历滑动开始
  135 + * @param {object} e
  136 + */
  137 + calendarTouchstart(e) {
  138 + const t = e.touches[0]
  139 + const startX = t.clientX
  140 + const startY = t.clientY
  141 + this.swipeLock = true
  142 + this.setData({
  143 + 'gesture.startX': startX,
  144 + 'gesture.startY': startY
  145 + })
  146 + },
  147 + /**
  148 + * 日历滑动中
  149 + * @param {object} e
  150 + */
  151 + calendarTouchmove(e) {
  152 + const { gesture } = this.data
  153 + const { preventSwipe } = this.properties.config
  154 + if (!this.swipeLock || preventSwipe) return
  155 + if (calendarGesture.isLeft(gesture, e.touches[0])) {
  156 + this.handleSwipe('left')
  157 + this.swipeLock = false
  158 + }
  159 + if (calendarGesture.isRight(gesture, e.touches[0])) {
  160 + this.handleSwipe('right')
  161 + this.swipeLock = false
  162 + }
  163 + },
  164 + calendarTouchend(e) {
  165 + this.setData({
  166 + 'calendar.leftSwipe': 0,
  167 + 'calendar.rightSwipe': 0
  168 + })
  169 + },
  170 + handleSwipe(direction) {
  171 + let swipeKey = 'calendar.leftSwipe'
  172 + if (direction === 'right') {
  173 + swipeKey = 'calendar.rightSwipe'
  174 + }
  175 + this.setData({
  176 + [swipeKey]: 1
  177 + })
  178 + const { calendar } = this.data
  179 + let calendarData = calendar
  180 + const { curYear, curMonth } = calendarData
  181 + const getMonthInfo = calcTargetYMInfo()[direction]
  182 + const target = getMonthInfo({
  183 + year: +curYear,
  184 + month: +curMonth
  185 + })
  186 + target.direction = direction
  187 + this.renderCalendar(target)
  188 + },
  189 + changeDate(e) {
  190 + const { type } = e.currentTarget.dataset
  191 + const { calendar: calendarData } = this.data
  192 + const { curYear, curMonth } = calendarData
  193 + const getMonthInfo = calcTargetYMInfo()[type]
  194 + const target = getMonthInfo({
  195 + year: +curYear,
  196 + month: +curMonth
  197 + })
  198 + target.direction = type
  199 + this.renderCalendar(target)
  200 + },
  201 + renderCalendar(target) {
  202 + let { calendar: calendarData, config } = this.data
  203 + const { curYear, curMonth } = calendarData || {}
  204 + for (let plugin of plugins.installed) {
  205 + const [, p] = plugin
  206 + if (typeof p.onSwitchCalendar === 'function') {
  207 + calendarData = p.onSwitchCalendar(target, calendarData, this)
  208 + }
  209 + }
  210 + return renderCalendar.call(this, calendarData, config).then(() => {
  211 + let triggerEventName = 'whenChangeMonth'
  212 + if (config.weekMode) {
  213 + triggerEventName = 'whenChangeWeek'
  214 + }
  215 + this.triggerEvent(triggerEventName, {
  216 + current: {
  217 + year: +curYear,
  218 + month: +curMonth
  219 + },
  220 + next: target
  221 + })
  222 + this.triggerEvent('onSwipe', {
  223 + current: {
  224 + year: +curYear,
  225 + month: +curMonth
  226 + },
  227 + next: target,
  228 + type: triggerEventName
  229 + })
  230 + })
  231 + },
  232 + doubleClickJumpToToday() {
  233 + const { multi, weekMode } = this.calendar.getCalendarConfig() || {}
  234 + if (multi || weekMode) return
  235 + if (this.count === undefined) {
  236 + this.count = 1
  237 + } else {
  238 + this.count += 1
  239 + }
  240 + if (this.lastClick) {
  241 + const difference = new Date().getTime() - this.lastClick
  242 + if (
  243 + difference < 500 &&
  244 + this.count >= 2 &&
  245 + typeof this.calendar.jump === 'function'
  246 + ) {
  247 + const today = dateUtil.todayFMD()
  248 + this.calendar.jump(today)
  249 + }
  250 + this.count = undefined
  251 + this.lastClick = undefined
  252 + } else {
  253 + this.lastClick = new Date().getTime()
  254 + }
  255 + }
  256 + }
  257 +})
... ...
component/v2/index.json 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +{
  2 + "component": true
  3 +}
0 4 \ No newline at end of file
... ...
component/v2/index.wxml 0 → 100644
... ... @@ -0,0 +1,60 @@
  1 +<view class="flex b tb ac" wx:if="{{calendar}}">
  2 + <view class="calendar b tb">
  3 + <!-- 头部操作栏 -->
  4 + <view
  5 + wx:if="{{!config.hideHeader}}"
  6 + class="handle {{config.theme}}_handle-color fs28 b lr ac pc">
  7 + <view class="prev fs36" wx:if="{{!config.weekMode}}">
  8 + <text class="prev-handle iconfont icon-doubleleft" bindtap="changeDate" data-type="prev_year"></text>
  9 + <text class="prev-handle iconfont icon-left" bindtap="changeDate" data-type="prev_month"></text>
  10 + </view>
  11 + <view class="flex date-in-handle b lr cc" bindtap="doubleClickJumpToToday">{{calendar.curYear || "--"}} 年 {{calendar.curMonth || "--"}} 月</view>
  12 + <view class="next fs36" wx:if="{{!config.weekMode}}">
  13 + <text class="next-handle iconfont icon-right" bindtap="changeDate" data-type="next_month"></text>
  14 + <text class="next-handle iconfont icon-doubleright" bindtap="changeDate" data-type="next_year"></text>
  15 + </view>
  16 + </view>
  17 + <!-- 星期栏 -->
  18 + <view class="weeks b lr ac {{config.theme}}_week-color">
  19 + <view class="week fs28" wx:for="{{calendar.weeksCh}}" wx:key="index" data-idx="{{index}}">{{item}}</view>
  20 + </view>
  21 + <!-- 日历面板主体 -->
  22 + <view class="b lr wrap" bindtouchstart="calendarTouchstart" catchtouchmove="calendarTouchmove" catchtouchend="calendarTouchend">
  23 + <!-- 上月日期格子 -->
  24 + <view class="grid b ac pc {{config.theme}}_prev-month-date" wx:for="{{calendar.prevMonthGrids}}" wx:key="index" data-idx="{{index}}">
  25 + <view class="date-wrap b cc">
  26 + <view class="date">
  27 + {{item.date}}
  28 + </view>
  29 + </view>
  30 + </view>
  31 + <!-- 本月日期格子 -->
  32 + <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">
  33 + <view class="date-wrap b cc {{config.emphasisWeek && (item.week === 0 || item.week === 6) ? config.theme + '_weekend-color' : ''}}">
  34 + <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' : '' }}">
  35 + {{config.markToday && item.isToday ? config.markToday : item.date}}
  36 + <view
  37 + wx:if="{{(config.showLunar && item.lunar && !item.showTodoLabel) || (item.showTodoLabel && calendar.todoLabelPos !== 'bottom') || config.showHolidays}}"
  38 + 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' : ''}}">
  39 + <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>
  40 + </view>
  41 + <view
  42 + wx:if="{{item.showTodoLabel && !calendar.todoLabelCircle}}"
  43 + 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' : ''}}"
  44 + style="background-color: {{item.todoText ? '' : item.color || calendar.todoLabelColor}}; color: {{item.color}}">
  45 + {{item.todoText}}
  46 + </view>
  47 + </view>
  48 + </view>
  49 + </view>
  50 + <!-- 下月日期格子 -->
  51 + <view class="grid b ac pc {{config.theme}}_next-month-date" wx:for="{{calendar.nextMonthGrids}}" wx:key="index" data-idx="{{index}}">
  52 + <view class="date-wrap b cc">
  53 + <view class="date">
  54 + {{item.date}}
  55 + </view>
  56 + </view>
  57 + </view>
  58 + </view>
  59 + </view>
  60 +</view>
... ...
component/v2/index.wxss 0 → 100644
... ... @@ -0,0 +1,214 @@
  1 +@import './theme/iconfont.wxss';
  2 +@import './theme/theme-default.wxss';
  3 +@import './theme/theme-elegant.wxss';
  4 +
  5 +.b {
  6 + display: flex;
  7 +}
  8 +
  9 +.lr {
  10 + flex-direction: row;
  11 +}
  12 +
  13 +.tb {
  14 + flex-direction: column;
  15 +}
  16 +
  17 +.pc {
  18 + justify-content: center;
  19 +}
  20 +
  21 +.ac {
  22 + align-items: center;
  23 +}
  24 +
  25 +.cc {
  26 + align-items: center;
  27 + justify-content: center;
  28 +}
  29 +
  30 +.wrap {
  31 + flex-wrap: wrap;
  32 +}
  33 +
  34 +.flex {
  35 + flex-grow: 1;
  36 +}
  37 +
  38 +.bg {
  39 + background-image: linear-gradient(to bottom, #faefe7, #ffcbd7);
  40 + overflow: hidden;
  41 +}
  42 +
  43 +.white-color {
  44 + color: #fff;
  45 +}
  46 +
  47 +.fs24 {
  48 + font-size: 24rpx;
  49 +}
  50 +
  51 +.fs28 {
  52 + font-size: 28rpx;
  53 +}
  54 +
  55 +.fs32 {
  56 + font-size: 32rpx;
  57 +}
  58 +
  59 +.fs36 {
  60 + font-size: 36rpx;
  61 +}
  62 +
  63 +.calendar {
  64 + width: 100%;
  65 + box-sizing: border-box;
  66 +}
  67 +
  68 +/* 日历操作栏 */
  69 +
  70 +.handle {
  71 + height: 80rpx;
  72 +}
  73 +
  74 +.prev-handle,
  75 +.next-handle {
  76 + padding: 20rpx;
  77 +}
  78 +
  79 +.date-in-handle {
  80 + height: 80rpx;
  81 +}
  82 +
  83 +/* 星期栏 */
  84 +
  85 +.weeks {
  86 + height: 50rpx;
  87 + line-height: 50rpx;
  88 + opacity: 0.5;
  89 +}
  90 +
  91 +.week {
  92 + text-align: center;
  93 +}
  94 +
  95 +.grid,
  96 +.week {
  97 + width: 14.286014285714286%;
  98 +}
  99 +
  100 +.date-wrap {
  101 + width: 100%;
  102 + height: 80rpx;
  103 + position: relative;
  104 + left: 0;
  105 + top: 0;
  106 +}
  107 +
  108 +.date {
  109 + position: relative;
  110 + left: 0;
  111 + top: 0;
  112 + width: 55rpx;
  113 + height: 55rpx;
  114 + text-align: center;
  115 + line-height: 55rpx;
  116 + font-size: 26rpx;
  117 + font-weight: 200;
  118 + border-radius: 50%;
  119 + transition: all 0.3s;
  120 + animation-name: choosed;
  121 + animation-duration: 0.5s;
  122 + animation-timing-function: linear;
  123 + animation-iteration-count: 1;
  124 +}
  125 +
  126 +.date-area-mode {
  127 + width: 100%;
  128 + border-radius: 0;
  129 +}
  130 +
  131 +.date-desc {
  132 + width: 150%;
  133 + height: 32rpx;
  134 + font-size: 20rpx;
  135 + line-height: 32rpx;
  136 + position: absolute;
  137 + left: 50%;
  138 + transform: translateX(-50%);
  139 + overflow: hidden;
  140 + word-break: break-all;
  141 + text-overflow: ellipsis;
  142 + white-space: nowrap;
  143 + -webkit-line-clamp: 1;
  144 + text-align: center;
  145 +}
  146 +
  147 +@keyframes choosed {
  148 + from {
  149 + transform: scale(1);
  150 + }
  151 +
  152 + 50% {
  153 + transform: scale(0.9);
  154 + }
  155 +
  156 + to {
  157 + transform: scale(1);
  158 + }
  159 +}
  160 +
  161 +/* 日期圆圈标记 */
  162 +.todo-circle {
  163 + border-width: 1rpx;
  164 + border-style: solid;
  165 + box-sizing: border-box;
  166 +}
  167 +
  168 +/* 待办点标记相关样式 */
  169 +.todo-dot {
  170 + width: 10rpx;
  171 + height: 10rpx;
  172 + border-radius: 50%;
  173 + position: absolute;
  174 + left: 50%;
  175 + transform: translateX(-50%);
  176 +}
  177 +
  178 +.todo-dot-top {
  179 + top: 3rpx;
  180 +}
  181 +
  182 +.todo-dot.todo-dot-top-always {
  183 + top: -8rpx;
  184 +}
  185 +
  186 +.todo-dot.todo-dot-bottom {
  187 + bottom: 0;
  188 +}
  189 +
  190 +.todo-dot.todo-dot-bottom-always {
  191 + bottom: -10rpx;
  192 +}
  193 +
  194 +/* 日期描述文字(待办文字/农历)相关样式 */
  195 +
  196 +.date-desc.date-desc-top {
  197 + top: -6rpx;
  198 +}
  199 +
  200 +.date-desc.date-desc-top-always {
  201 + top: -20rpx;
  202 +}
  203 +
  204 +.date-desc.date-desc-bottom {
  205 + bottom: -14rpx;
  206 +}
  207 +
  208 +.todo-circle .date-desc.date-desc-bottom {
  209 + bottom: -30rpx;
  210 +}
  211 +
  212 +.date-desc.date-desc-bottom-always {
  213 + bottom: -28rpx;
  214 +}
... ...
component/v2/plugins/holidays/holidays-map.js 0 → 100644
... ... @@ -0,0 +1,212 @@
  1 +/* *
  2 + @Author: drfu*
  3 + @Description: 数据来源于国务院办公厅关于2020年部分节假日安排的通知(国办发明电〔2019〕16号)_政府信息公开专栏,http://www.gov.cn/zhengce/content/2019-11/21/content_5454164.htm
  4 + @Date: 2020-10-12 14:29:45*
  5 + * @Last Modified by: drfu
  6 + * @Last Modified time: 2020-10-16 17:38:08
  7 +*/
  8 +
  9 +// 节日列表
  10 +export const festival = {
  11 + // 农历固定日期节日
  12 + lunar: {
  13 + 1: {
  14 + 1: {
  15 + type: 'festival',
  16 + name: '春节',
  17 + label: '春节'
  18 + },
  19 + 8: {
  20 + type: 'festival',
  21 + name: '腊八节',
  22 + label: '腊八'
  23 + },
  24 + 15: {
  25 + type: 'festival',
  26 + name: '元宵节',
  27 + label: '元宵'
  28 + }
  29 + },
  30 + 7: {
  31 + 7: {
  32 + type: 'festival',
  33 + name: '七夕节',
  34 + label: '七夕'
  35 + },
  36 + 15: {
  37 + type: 'festival',
  38 + name: '中元节',
  39 + label: '中元节'
  40 + }
  41 + },
  42 + 9: {
  43 + 9: {
  44 + type: 'festival',
  45 + name: '重阳节',
  46 + label: '重阳节'
  47 + }
  48 + }
  49 + },
  50 + // 阳历固定日期节日
  51 + solar: {
  52 + 2: {
  53 + 14: {
  54 + type: 'festival',
  55 + name: '情人节',
  56 + label: '情人节'
  57 + }
  58 + },
  59 + 3: {
  60 + 12: {
  61 + type: 'festival',
  62 + name: '植树节',
  63 + label: '植树节'
  64 + }
  65 + },
  66 + 4: {
  67 + 1: {
  68 + type: 'festival',
  69 + name: '愚人节',
  70 + label: '愚人节'
  71 + },
  72 + 5: {
  73 + type: 'festival',
  74 + name: '清明节',
  75 + label: '清明节'
  76 + }
  77 + },
  78 + 5: {
  79 + 1: {
  80 + type: 'festival',
  81 + name: '劳动节',
  82 + label: '劳动节'
  83 + }
  84 + },
  85 + 6: {
  86 + 1: {
  87 + type: 'festival',
  88 + name: '儿童节',
  89 + label: '儿童节'
  90 + }
  91 + },
  92 + 7: {
  93 + 1: {
  94 + type: 'festival',
  95 + name: '建党节',
  96 + label: '建党节'
  97 + }
  98 + },
  99 + 8: {
  100 + 1: {
  101 + type: 'festival',
  102 + name: '建军节',
  103 + label: '建军节'
  104 + }
  105 + },
  106 + 9: {
  107 + 10: {
  108 + type: 'festival',
  109 + name: '教师节',
  110 + label: '教师节'
  111 + }
  112 + },
  113 + 10: {
  114 + 1: {
  115 + type: 'festival',
  116 + name: '国庆节',
  117 + label: '国庆节'
  118 + }
  119 + },
  120 + 12: {
  121 + 25: {
  122 + type: 'festival',
  123 + name: '圣诞节',
  124 + label: '圣诞节'
  125 + }
  126 + }
  127 + }
  128 +}
  129 +
  130 +export const holidays = {
  131 + 2020: {
  132 + 1: {
  133 + 1: {
  134 + type: 'holiday',
  135 + name: '元旦',
  136 + label: '休'
  137 + },
  138 + 19: {
  139 + type: 'work',
  140 + name: '调班',
  141 + label: '班'
  142 + },
  143 + '24-30': {
  144 + type: 'holiday',
  145 + name: '春节',
  146 + label: '休'
  147 + }
  148 + },
  149 + 2: {
  150 + 1: {
  151 + type: 'work',
  152 + name: '调班',
  153 + label: '班'
  154 + }
  155 + },
  156 + 4: {
  157 + '4-6': {
  158 + type: 'holiday',
  159 + name: '清明节',
  160 + label: '休'
  161 + },
  162 + 26: {
  163 + type: 'work',
  164 + name: '调班',
  165 + label: '班'
  166 + }
  167 + },
  168 + 5: {
  169 + '1-5': {
  170 + type: 'holiday',
  171 + name: '劳动节',
  172 + label: '休'
  173 + },
  174 + 9: {
  175 + type: 'work',
  176 + name: '调班',
  177 + label: '班'
  178 + }
  179 + },
  180 + 6: {
  181 + '25-27': {
  182 + type: 'holiday',
  183 + name: '端午节',
  184 + label: '休'
  185 + },
  186 + 28: {
  187 + type: 'work',
  188 + name: '调班',
  189 + label: '班'
  190 + }
  191 + },
  192 + 9: {
  193 + 27: {
  194 + type: 'work',
  195 + name: '调班',
  196 + label: '班'
  197 + }
  198 + },
  199 + 10: {
  200 + '1-8': {
  201 + type: 'holiday',
  202 + name: '国庆节/中秋节',
  203 + label: '休'
  204 + },
  205 + 10: {
  206 + type: 'work',
  207 + name: '调班',
  208 + label: '班'
  209 + }
  210 + }
  211 + }
  212 +}
... ...
component/v2/plugins/holidays/index.js 0 → 100644
... ... @@ -0,0 +1,201 @@
  1 +/* *
  2 + @Author: drfu*
  3 + @Description: 显示法定节假日班/休情况
  4 + @Date: 2020-10-12 14:29:45*
  5 + * @Last Modified by: drfu
  6 + * @Last Modified time: 2020-10-16 17:34:13
  7 +*/
  8 +
  9 +import { holidays, festival } from './holidays-map'
  10 +import { dateUtil, getCalendarData, logger } from '../../utils/index'
  11 +
  12 +/**
  13 + * 当前是否在休假期内
  14 + * @param {object} { year, month }
  15 + * @param {object} { start, end, current }
  16 + * @returns
  17 + */
  18 +function inHolidays({ year, month }, { start, end, current }) {
  19 + const getTimeStamp = dateUtil.getTimeStamp
  20 + const startTimestamp = getTimeStamp({
  21 + year,
  22 + month,
  23 + date: start
  24 + })
  25 + const endTimestamp = getTimeStamp({
  26 + year,
  27 + month,
  28 + date: end
  29 + })
  30 + const currentDateTimestamp = getTimeStamp({
  31 + year,
  32 + month,
  33 + date: current
  34 + })
  35 + if (
  36 + currentDateTimestamp >= startTimestamp &&
  37 + currentDateTimestamp <= endTimestamp
  38 + ) {
  39 + return true
  40 + }
  41 + return false
  42 +}
  43 +
  44 +function addSpecialFestival(date, component) {
  45 + const { convertlLunar2Solar, convertSolarLunar } = component.calendar || {}
  46 + const lunarDateInfo = convertSolarLunar(date)
  47 + const { lYear, lMonth } = lunarDateInfo || {}
  48 + // 春节
  49 + const info = {
  50 + type: 'festival',
  51 + name: '除夕',
  52 + label: '除夕'
  53 + }
  54 + if (lMonth === 12) {
  55 + if (!festival.lunar['12']) festival.lunar['12'] = {}
  56 + if (convertlLunar2Solar(`${lYear}-12-30`) === -1) {
  57 + festival.lunar['12']['29'] = info
  58 + } else {
  59 + festival.lunar['12']['30'] = info
  60 + }
  61 + }
  62 +}
  63 +
  64 +/**
  65 + * 是否匹配到节日
  66 + * @param {object} [dateInfo={}]
  67 + * @param {object} [component={}]
  68 + * @returns {object|boolean} 匹配到的节日数据或者false
  69 + */
  70 +function hasFestivalDate(dateInfo = {}, component = {}) {
  71 + const { month, date } = dateInfo
  72 + let festivalDate = festival.solar[month] && festival.solar[month][date]
  73 + if (!festivalDate) {
  74 + const { convertSolarLunar } = component.calendar || {}
  75 + const lunarDateInfo = convertSolarLunar(dateInfo)
  76 + const { lMonth, lDay } = lunarDateInfo
  77 + festivalDate = festival.lunar[lMonth] && festival.lunar[lMonth][lDay]
  78 + if (!festivalDate) {
  79 + const festivalOfMonth = festival.lunar[lMonth] || {}
  80 + const festivalDateKey = Object.keys(festivalOfMonth).find(item =>
  81 + item.match(new RegExp(`\\b${lDay}\\b`))
  82 + )
  83 + if (!festivalDateKey) {
  84 + festivalDate = false
  85 + } else {
  86 + const festivalInfo = festival.lunar[lMonth][festivalDateKey]
  87 + if (!festivalInfo) {
  88 + festivalDate = false
  89 + } else {
  90 + const { condition } = festivalInfo
  91 + if (typeof condition === 'function') {
  92 + festivalDate = condition(lunarDateInfo)
  93 + } else {
  94 + festivalDate = false
  95 + }
  96 + }
  97 + }
  98 + }
  99 + }
  100 + return festivalDate
  101 +}
  102 +
  103 +export default () => {
  104 + return {
  105 + name: 'holidays',
  106 + beforeRender(calendarData = {}, calendarConfig = {}, component) {
  107 + let { dates = [] } = calendarData
  108 + if (calendarConfig.showHolidays || calendarConfig.showFestival) {
  109 + dates = dates.map(d => {
  110 + let item = { ...d }
  111 + const { year, month, date } = item
  112 + const holidaysOfMonth =
  113 + (holidays[year] && holidays[year][month]) || {}
  114 + const holidayDate = holidaysOfMonth[date]
  115 + if (holidayDate) {
  116 + item = {
  117 + ...item,
  118 + ...holidayDate
  119 + }
  120 + } else {
  121 + const holidayKeys = Object.keys(holidaysOfMonth).filter(item =>
  122 + item.includes('-')
  123 + )
  124 + let target = ''
  125 + for (let v of holidayKeys) {
  126 + const [start, end] = v.split('-')
  127 + if (+d.date >= +start && +d.date <= +end) {
  128 + target = v
  129 + break
  130 + }
  131 + }
  132 + const [start, end] = target.split('-')
  133 + const isInHolidays = inHolidays(
  134 + {
  135 + year,
  136 + month
  137 + },
  138 + {
  139 + start,
  140 + end,
  141 + current: date
  142 + }
  143 + )
  144 + if (isInHolidays) {
  145 + item = {
  146 + ...item,
  147 + ...holidaysOfMonth[target]
  148 + }
  149 + } else if (calendarConfig.showFestival) {
  150 + const { convertSolarLunar, convertlLunar2Solar } =
  151 + component.calendar || {}
  152 + if (
  153 + typeof convertSolarLunar !== 'function' ||
  154 + typeof convertlLunar2Solar !== 'function'
  155 + ) {
  156 + return logger.warn(
  157 + '农历节日显示需要引入农历插件(/component/v2/plugins/solarLunar)'
  158 + )
  159 + }
  160 + addSpecialFestival(item, component)
  161 + const festivalDate = hasFestivalDate(item, component)
  162 + if (festivalDate) {
  163 + item = {
  164 + ...item,
  165 + ...festivalDate
  166 + }
  167 + }
  168 + }
  169 + }
  170 + return item
  171 + })
  172 + }
  173 + return {
  174 + calendarData: {
  175 + ...calendarData,
  176 + dates: dates
  177 + },
  178 + calendarConfig
  179 + }
  180 + },
  181 + methods(component) {
  182 + return {
  183 + getHolidaysOfCurrentYear() {
  184 + const calendar = getCalendarData('calendar', component)
  185 + const { curYear } = calendar
  186 + return this.methods(component).getHolidaysOfYear(curYear)
  187 + },
  188 + getHolidaysOfYear(year) {
  189 + if (!year) return logger.warn('getHolidaysOfCurrentYear() 入参错误')
  190 + if (!holidays[year]) {
  191 + logger.warn('未匹配到当前年份节假日信息,请自行补充')
  192 + return {
  193 + err: 'not match'
  194 + }
  195 + }
  196 + return holidays[year]
  197 + }
  198 + }
  199 + }
  200 + }
  201 +}
... ...
component/v2/plugins/index.js 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +import preset from './preset/index'
  2 +
  3 +export default {
  4 + installed: [...preset],
  5 + use(plugin) {
  6 + if (typeof plugin !== 'function') return
  7 + const info = plugin() || {}
  8 + const { name } = info
  9 + if (
  10 + name &&
  11 + name !== 'methods' &&
  12 + !this.installed.some(p => p[0] === name)
  13 + ) {
  14 + this.installed.unshift([name, info])
  15 + }
  16 + return this
  17 + }
  18 +}
... ...
component/v2/plugins/preset/base.js 0 → 100644
... ... @@ -0,0 +1,277 @@
  1 +/**
  2 + * @Author: drfu*
  3 + * @Description: 基础功能
  4 + * @Date: 2020-10-08 21:22:09*
  5 + * @Last Modified by: drfu
  6 + * @Last Modified time: 2020-10-11 13:28:52
  7 + * */
  8 +
  9 +import { calcJumpData } from '../../core'
  10 +import { renderCalendar } from '../../render'
  11 +import {
  12 + dateUtil,
  13 + getCalendarData,
  14 + setCalendarData,
  15 + getCalendarConfig
  16 +} from '../../utils/index'
  17 +
  18 +export default () => {
  19 + return {
  20 + name: 'base',
  21 + beforeRender(calendarData = {}, calendarConfig) {
  22 + const calendar = calendarData
  23 + const { selectedDates = [], dates } = calendar
  24 + let _dates = [...dates]
  25 + if (selectedDates.length) {
  26 + const selectedDatesStr = selectedDates.map(date =>
  27 + dateUtil.toTimeStr(date)
  28 + )
  29 + _dates.forEach(date => {
  30 + const dateStr = dateUtil.toTimeStr(date)
  31 + if (selectedDatesStr.includes(dateStr)) {
  32 + date.choosed = true
  33 + }
  34 + })
  35 + }
  36 + return {
  37 + calendarData: {
  38 + ...calendarData,
  39 + dates: _dates
  40 + },
  41 + calendarConfig
  42 + }
  43 + },
  44 + onTapDate(tapedDate, calendarData = {}, calendarConfig = {}) {
  45 + const calendar = {
  46 + ...calendarData
  47 + }
  48 + const dateIndex = dateUtil.findDateIndexInArray(
  49 + tapedDate,
  50 + calendarData.dates
  51 + )
  52 + const { multi, inverse } = calendarConfig
  53 + let dates = [...calendar.dates]
  54 + const { selectedDates = [] } = calendar
  55 + if (!multi) {
  56 + let preSelectedDate = {}
  57 + if (selectedDates.length) {
  58 + preSelectedDate = [...selectedDates].pop() || {}
  59 + }
  60 + const timeStr = dateUtil.toTimeStr
  61 + if (!inverse && timeStr(preSelectedDate) === timeStr(tapedDate)) {
  62 + return calendar
  63 + }
  64 + let _tapedDate = { ...tapedDate, choosed: !tapedDate.choosed }
  65 +
  66 + dates[dateIndex] = _tapedDate
  67 + if (preSelectedDate.date) {
  68 + const idx = dateUtil.findDateIndexInArray(preSelectedDate, dates)
  69 + const date = dates[idx]
  70 + if (date) {
  71 + date.choosed = false
  72 + }
  73 + }
  74 + if (dates[dateIndex].choosed) {
  75 + calendar.selectedDates = [dates[dateIndex]]
  76 + } else {
  77 + calendar.selectedDates = []
  78 + }
  79 + } else {
  80 + dates[dateIndex] = {
  81 + ...dates[dateIndex],
  82 + choosed: !dates[dateIndex].choosed
  83 + }
  84 + if (!calendar.selectedDates) {
  85 + calendar.selectedDates = []
  86 + }
  87 + if (dates[dateIndex].choosed) {
  88 + calendar.selectedDates.push(dates[dateIndex])
  89 + } else {
  90 + calendar.selectedDates = calendar.selectedDates.filter(
  91 + date =>
  92 + dateUtil.toTimeStr(date) !== dateUtil.toTimeStr(dates[dateIndex])
  93 + )
  94 + }
  95 + }
  96 + return {
  97 + calendarData: {
  98 + ...calendar,
  99 + dates
  100 + },
  101 + calendarConfig
  102 + }
  103 + },
  104 + onSwitchCalendar(date, calendarData = {}, component) {
  105 + const calendarConfig = getCalendarConfig(component)
  106 + if (calendarConfig.weekMode) {
  107 + return calendarData
  108 + }
  109 + const updatedRenderData = calcJumpData({
  110 + dateInfo: date,
  111 + config: calendarConfig
  112 + })
  113 + return {
  114 + ...calendarData,
  115 + ...updatedRenderData
  116 + }
  117 + },
  118 + methods(component) {
  119 + return {
  120 + jump: dateInfo => {
  121 + if (Object.prototype.toString.call(dateInfo) !== '[object Object]')
  122 + return
  123 + const updatedRenderData = calcJumpData({
  124 + dateInfo,
  125 + component
  126 + })
  127 + const existCalendarData = getCalendarData('calendar', component)
  128 + const config = getCalendarConfig(component)
  129 + if (config.autoChoosedWhenJump) {
  130 + const target = updatedRenderData.dates[dateInfo.date - 1]
  131 + if (!updatedRenderData.selectedDates) {
  132 + updatedRenderData.selectedDates = [target]
  133 + } else {
  134 + updatedRenderData.selectedDates.push(target)
  135 + }
  136 + }
  137 + return renderCalendar.call(component, {
  138 + ...existCalendarData,
  139 + ...updatedRenderData
  140 + })
  141 + },
  142 + getCalendarConfig() {
  143 + return getCalendarConfig(component)
  144 + },
  145 + setCalendarConfig(config) {
  146 + return new Promise((resolve, reject) => {
  147 + if (!component || !component.data.config) {
  148 + reject('异常:未找到组件配置信息')
  149 + return
  150 + }
  151 + let conf = { ...component.data.config, ...config }
  152 + component.data.config = conf
  153 + setCalendarData({ config: conf }, component)
  154 + .then(resolve)
  155 + .catch(reject)
  156 + })
  157 + },
  158 + cancelSelectedDates(cancelDates = []) {
  159 + const existCalendarData = getCalendarData('calendar', component) || {}
  160 + const { dates = [], selectedDates = [] } = existCalendarData
  161 + let updatedRenderData = {}
  162 + const config = getCalendarConfig(component)
  163 + let chooseAreaData = {}
  164 + if (config.chooseAreaMode) {
  165 + chooseAreaData = {
  166 + chooseAreaTimestamp: [],
  167 + tempChooseAreaTimestamp: []
  168 + }
  169 + }
  170 + if (!cancelDates.length) {
  171 + dates.forEach(item => {
  172 + item.choosed = false
  173 + })
  174 + updatedRenderData = {
  175 + dates,
  176 + selectedDates: []
  177 + }
  178 + } else {
  179 + const cancelDatesStr = cancelDates.map(date =>
  180 + dateUtil.toTimeStr(date)
  181 + )
  182 + const filterSelectedDates = selectedDates.filter(
  183 + date => !cancelDatesStr.includes(dateUtil.toTimeStr(date))
  184 + )
  185 + dates.forEach(date => {
  186 + if (cancelDatesStr.includes(dateUtil.toTimeStr(date))) {
  187 + date.choosed = false
  188 + }
  189 + })
  190 + updatedRenderData = {
  191 + dates,
  192 + selectedDates: filterSelectedDates
  193 + }
  194 + }
  195 +
  196 + return renderCalendar.call(component, {
  197 + ...existCalendarData,
  198 + ...updatedRenderData,
  199 + ...chooseAreaData
  200 + })
  201 + },
  202 + setSelectedDates: targetDates => {
  203 + const existCalendarData = getCalendarData('calendar', component)
  204 + let { dates, selectedDates = [] } = existCalendarData || {}
  205 + let __selectedDates = []
  206 + let __dates = dates
  207 + if (!targetDates) {
  208 + __dates = dates.map(item => {
  209 + const date = { ...item }
  210 + date.choosed = true
  211 + if (existCalendarData.showLabelAlways && date.showTodoLabel) {
  212 + date.showTodoLabel = true
  213 + } else {
  214 + date.showTodoLabel = false
  215 + }
  216 + return date
  217 + })
  218 + __selectedDates = dates
  219 + } else if (targetDates && targetDates.length) {
  220 + const allSelected = dateUtil.uniqueArrayByDate(
  221 + selectedDates.concat(targetDates)
  222 + )
  223 + const allSelectedDateStr = allSelected.map(d =>
  224 + dateUtil.toTimeStr(d)
  225 + )
  226 + __dates = dates.map(item => {
  227 + const date = { ...item }
  228 + if (allSelectedDateStr.includes(dateUtil.toTimeStr(date))) {
  229 + date.choosed = true
  230 + __selectedDates.push(date)
  231 + }
  232 + if (existCalendarData.showLabelAlways && date.showTodoLabel) {
  233 + date.showTodoLabel = true
  234 + } else {
  235 + date.showTodoLabel = false
  236 + }
  237 + return date
  238 + })
  239 + }
  240 + return renderCalendar.call(component, {
  241 + ...existCalendarData,
  242 + dates: __dates,
  243 + selectedDates: __selectedDates
  244 + })
  245 + },
  246 + setDateStyle: toSetDates => {
  247 + if (!Array.isArray(toSetDates)) return Promise.reject()
  248 + const existCalendarData = getCalendarData('calendar', component)
  249 + const { dates = [], specialStyleDates } = existCalendarData || {}
  250 + if (Array.isArray(specialStyleDates)) {
  251 + toSetDates = dateUtil.uniqueArrayByDate([
  252 + ...specialStyleDates,
  253 + ...toSetDates
  254 + ])
  255 + }
  256 + const toSetDatesStr = toSetDates.map(item => dateUtil.toTimeStr(item))
  257 + const _dates = dates.map(item => {
  258 + const idx = toSetDatesStr.indexOf(dateUtil.toTimeStr(item))
  259 + if (idx > -1) {
  260 + return {
  261 + ...item,
  262 + class: toSetDates[idx].class
  263 + }
  264 + } else {
  265 + return item
  266 + }
  267 + })
  268 + return renderCalendar.call(component, {
  269 + ...existCalendarData,
  270 + dates: _dates,
  271 + specialStyleDates: toSetDates
  272 + })
  273 + }
  274 + }
  275 + }
  276 + }
  277 +}
... ...
component/v2/plugins/preset/get-calendar-data.js 0 → 100644
... ... @@ -0,0 +1,69 @@
  1 +/**
  2 + * @Author: drfu*
  3 + * @Description: 获取日历数据
  4 + * @Date: 2020-10-08 21:22:09*
  5 + * @Last Modified by: drfu
  6 + * @Last Modified time: 2020-10-11 13:42:37
  7 + * */
  8 +
  9 +import { getCalendarData, logger, getCalendarConfig } from '../../utils/index'
  10 +
  11 +function wrapDateWithLunar(dates = [], convertFn) {
  12 + const datesWithLunar = JSON.parse(JSON.stringify(dates)).map(date => ({
  13 + ...date,
  14 + lunar: convertFn(date)
  15 + }))
  16 + return datesWithLunar
  17 +}
  18 +
  19 +export default () => {
  20 + return {
  21 + name: 'getData',
  22 + methods(component) {
  23 + return {
  24 + getCurrentYM: () => {
  25 + const { curYear, curMonth } = getCalendarData('calendar', component)
  26 + return {
  27 + year: curYear,
  28 + month: curMonth
  29 + }
  30 + },
  31 + getSelectedDates: (options = {}) => {
  32 + const dates =
  33 + getCalendarData('calendar.selectedDates', component) || []
  34 + const config = getCalendarConfig(component) || {}
  35 + if (options.lunar && !config.showLunar) {
  36 + const injectedFns = component.calendar || {}
  37 + if (typeof injectedFns.convertSolarLunar === 'function') {
  38 + return wrapDateWithLunar(dates, injectedFns.convertSolarLunar)
  39 + } else {
  40 + logger.warn('获取农历信息需引入农历插件')
  41 + }
  42 + } else {
  43 + return dates
  44 + }
  45 + },
  46 + getCalendarDates: (options = {}) => {
  47 + const config = getCalendarConfig(component) || {}
  48 + const dates = getCalendarData('calendar.dates', component)
  49 + if (options.lunar && !config.showLunar) {
  50 + const injectedFns = component.calendar || {}
  51 + if (typeof injectedFns.convertSolarLunar === 'function') {
  52 + return wrapDateWithLunar(dates, injectedFns.convertSolarLunar)
  53 + } else {
  54 + logger.warn('获取农历信息需引入农历插件')
  55 + }
  56 + } else {
  57 + return dates
  58 + }
  59 + },
  60 + getCalendarAllData: () => {
  61 + return {
  62 + data: getCalendarData('calendar', component) || {},
  63 + config: getCalendarConfig(component) || {}
  64 + }
  65 + }
  66 + }
  67 + }
  68 + }
  69 +}
... ...
component/v2/plugins/preset/index.js 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +import base from './base'
  2 +import getCalendarData from './get-calendar-data'
  3 +
  4 +const preset = [
  5 + ['base', base()],
  6 + ['get-calendar-data', getCalendarData()]
  7 +]
  8 +
  9 +export default preset
... ...
component/v2/plugins/selectable.js 0 → 100644
... ... @@ -0,0 +1,219 @@
  1 +/**
  2 + * @Author: drfu*
  3 + * @Description: 禁用、启用日期选择
  4 + * @Date: 2020-10-08 21:22:09*
  5 + * @Last Modified by: drfu
  6 + * @Last Modified time: 2020-10-08 21:25:00
  7 + * */
  8 +
  9 +import { getCalendarData, dateUtil, logger } from '../utils/index'
  10 +import { renderCalendar } from '../render'
  11 +
  12 +function convertEnableAreaToTimestamp(timearea = []) {
  13 + const start = timearea[0].split('-')
  14 + const end = timearea[1].split('-')
  15 + if (start.length !== 3 || end.length !== 3) {
  16 + logger.warn('enableArea() 参数格式为: ["2018-2-1", "2018-3-1"]')
  17 + return {}
  18 + }
  19 + const startTimestamp = dateUtil
  20 + .newDate(start[0], start[1], start[2])
  21 + .getTime()
  22 + const endTimestamp = dateUtil.newDate(end[0], end[1], end[2]).getTime()
  23 + return {
  24 + start,
  25 + end,
  26 + startTimestamp,
  27 + endTimestamp
  28 + }
  29 +}
  30 +
  31 +function isValiditeOfDateArea(dateArea) {
  32 + const {
  33 + start,
  34 + end,
  35 + startTimestamp,
  36 + endTimestamp
  37 + } = convertEnableAreaToTimestamp(dateArea)
  38 + if (!start || !end) return
  39 + const datesCountOfStart = dateUtil.getDatesCountOfMonth(start[0], start[1])
  40 + const datesCountOfEnd = dateUtil.getDatesCountOfMonth(end[0], end[1])
  41 + if (start[2] > datesCountOfStart || start[2] < 1) {
  42 + logger.warn('enableArea() 开始日期错误,指定日期不在指定月份天数范围内')
  43 + return false
  44 + } else if (start[1] > 12 || start[1] < 1) {
  45 + logger.warn('enableArea() 开始日期错误,月份超出1-12月份')
  46 + return false
  47 + } else if (end[2] > datesCountOfEnd || end[2] < 1) {
  48 + logger.warn('enableArea() 截止日期错误,指定日期不在指定月份天数范围内')
  49 + return false
  50 + } else if (end[1] > 12 || end[1] < 1) {
  51 + logger.warn('enableArea() 截止日期错误,月份超出1-12月份')
  52 + return false
  53 + } else if (startTimestamp > endTimestamp) {
  54 + logger.warn('enableArea()参数最小日期大于了最大日期')
  55 + return false
  56 + } else {
  57 + return true
  58 + }
  59 +}
  60 +
  61 +function handleDisableMode(calendarConfig) {
  62 + const { disableMode } = calendarConfig
  63 + if (!disableMode) return {}
  64 + const disableBound =
  65 + dateUtil.getTimeStamp(disableMode.date) || dateUtil.todayTimestamp()
  66 + return {
  67 + disableBound,
  68 + disableType: disableMode.type
  69 + }
  70 +}
  71 +
  72 +function disabledByConfig(dateInfo, currentDate, calendarConfig) {
  73 + const date = { ...dateInfo }
  74 + const { disableType, disableBound } = handleDisableMode(calendarConfig)
  75 + if (
  76 + (disableType === 'before' && disableBound && currentDate < disableBound) ||
  77 + (disableType === 'after' && disableBound && currentDate > disableBound)
  78 + ) {
  79 + date.disable = true
  80 + } else {
  81 + date.disable = false
  82 + }
  83 + return date
  84 +}
  85 +
  86 +export default () => {
  87 + return {
  88 + name: 'enable',
  89 + beforeRender(calendarData = {}, calendarConfig = {}) {
  90 + const {
  91 + dates,
  92 + enableArea,
  93 + enableDates,
  94 + disableDates,
  95 + renderCausedBy
  96 + } = calendarData
  97 + const _dates = [...dates].map(date => {
  98 + let item = { ...date }
  99 + const timeStr = dateUtil.toTimeStr(date)
  100 + const timestamp = +dateUtil.getTimeStamp(item)
  101 + if (renderCausedBy === 'enableDates') {
  102 + if (enableDates && enableDates.length) {
  103 + if (enableDates.includes(timeStr)) {
  104 + item.disable = false
  105 + } else {
  106 + item.disable = true
  107 + }
  108 + return item
  109 + }
  110 + } else if (renderCausedBy === 'enableArea') {
  111 + if (enableArea && enableArea.length) {
  112 + const [startTimestamp, endTimestamp] = enableArea || []
  113 + const ifOutofArea =
  114 + +startTimestamp > timestamp || timestamp > +endTimestamp
  115 + item.disable = ifOutofArea
  116 + return item
  117 + }
  118 + } else if (renderCausedBy === 'disableDates') {
  119 + if (disableDates && disableDates.length) {
  120 + if (disableDates && disableDates.includes(timeStr)) {
  121 + item.disable = true
  122 + }
  123 + return item
  124 + }
  125 + }
  126 + return disabledByConfig(item, timestamp, calendarConfig)
  127 + })
  128 +
  129 + return {
  130 + calendarData: {
  131 + ...calendarData,
  132 + dates: _dates
  133 + },
  134 + calendarConfig
  135 + }
  136 + },
  137 + methods(component) {
  138 + return {
  139 + enableArea: (dateArea = []) => {
  140 + if (dateArea.length === 2) {
  141 + const validate = isValiditeOfDateArea(dateArea)
  142 + if (validate) {
  143 + const existCalendarData = getCalendarData('calendar', component)
  144 + const {
  145 + startTimestamp,
  146 + endTimestamp
  147 + } = convertEnableAreaToTimestamp(dateArea)
  148 +
  149 + return renderCalendar.call(component, {
  150 + ...existCalendarData,
  151 + renderCausedBy: 'enableArea',
  152 + enableArea: [startTimestamp, endTimestamp]
  153 + })
  154 + }
  155 + } else {
  156 + return Promise.inject(
  157 + 'enableArea()参数需为时间范围数组,形如:["2018-8-4" , "2018-8-24"]'
  158 + )
  159 + }
  160 + },
  161 + enableDates: (toSet = []) => {
  162 + if (!toSet.length) return
  163 + const existCalendarData = getCalendarData('calendar', component)
  164 + const { enableDates = [] } = existCalendarData || {}
  165 + let toSetDates = toSet.map(item => {
  166 + if (typeof item === 'string') {
  167 + return dateUtil.transformDateRow2Dict(item)
  168 + }
  169 + return item
  170 + })
  171 + if (enableDates.length) {
  172 + toSetDates = dateUtil.uniqueArrayByDate([
  173 + ...toSetDates,
  174 + ...enableDates.map(d => dateUtil.transformDateRow2Dict(d))
  175 + ])
  176 + }
  177 + return renderCalendar.call(component, {
  178 + ...existCalendarData,
  179 + renderCausedBy: 'enableDates',
  180 + enableDates: toSetDates.map(date => {
  181 + if (typeof date !== 'string') {
  182 + return dateUtil.toTimeStr(date)
  183 + }
  184 + return date
  185 + })
  186 + })
  187 + },
  188 + disableDates: toSet => {
  189 + const existCalendarData = getCalendarData('calendar', component)
  190 + const { disableDates = [], dates = [] } = existCalendarData || {}
  191 + let toSetDates = toSet.map(item => {
  192 + let date = { ...item }
  193 + if (typeof date === 'string') {
  194 + return dateUtil.transformDateRow2Dict(item)
  195 + }
  196 + return item
  197 + })
  198 + if (disableDates && disableDates.length) {
  199 + toSetDates = dateUtil.uniqueArrayByDate([
  200 + ...toSetDates,
  201 + ...disableDates.map(d => dateUtil.transformDateRow2Dict(d))
  202 + ])
  203 + }
  204 + return renderCalendar.call(component, {
  205 + ...existCalendarData,
  206 + renderCausedBy: 'disableDates',
  207 + dates,
  208 + disableDates: toSetDates.map(date => {
  209 + if (typeof date !== 'string') {
  210 + return dateUtil.toTimeStr(date)
  211 + }
  212 + return date
  213 + })
  214 + })
  215 + }
  216 + }
  217 + }
  218 + }
  219 +}
... ...
component/v2/plugins/solarLunar/convertSolarLunar.js 0 → 100644
... ... @@ -0,0 +1,1036 @@
  1 +/**
  2 + * @1900-2100区间内的公历、农历互转
  3 + * @Version 1.0.3
  4 + * @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
  5 + * @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
  6 + */
  7 +/* 公历年月日转农历数据 返回json */
  8 +// calendar.solar2lunar(1987,11,01);
  9 +/** 农历年月日转公历年月日 **/
  10 +// calendar.lunar2solar(1987,9,10);
  11 +// 调用以上方法后返回类似如下object(json)具体以上就不需要解释了吧!
  12 +// c开头的是公历各属性值 l开头的自然就是农历咯 gz开头的就是天干地支纪年的数据啦~
  13 +// {
  14 +// Animal: "兔",
  15 +// IDayCn: "初十",
  16 +// IMonthCn: "九月",
  17 +// Term: null,
  18 +// astro: "天蝎座",
  19 +// cDay: 1,
  20 +// cMonth: 11,
  21 +// cYear: 1987,
  22 +// gzDay: "甲寅",
  23 +// gzMonth: "庚戌",
  24 +// gzYear: "丁卯",
  25 +// isLeap: false,
  26 +// isTerm: false,
  27 +// isToday: false,
  28 +// lDay: 10,
  29 +// lMonth: 9,
  30 +// lYear: 1987,
  31 +// nWeek: 7,
  32 +// ncWeek: "星期日"
  33 +// }
  34 +// 该代码还有其他可以调用的方法,请自己查看代码中的详细注释
  35 +const calendar = {
  36 + /**
  37 + * 农历1900-2100的润大小信息表
  38 + * @Array Of Property
  39 + * @return Hex
  40 + */
  41 + lunarInfo: [
  42 + 0x04bd8,
  43 + 0x04ae0,
  44 + 0x0a570,
  45 + 0x054d5,
  46 + 0x0d260,
  47 + 0x0d950,
  48 + 0x16554,
  49 + 0x056a0,
  50 + 0x09ad0,
  51 + 0x055d2, // 1900-1909
  52 + 0x04ae0,
  53 + 0x0a5b6,
  54 + 0x0a4d0,
  55 + 0x0d250,
  56 + 0x1d255,
  57 + 0x0b540,
  58 + 0x0d6a0,
  59 + 0x0ada2,
  60 + 0x095b0,
  61 + 0x14977, // 1910-1919
  62 + 0x04970,
  63 + 0x0a4b0,
  64 + 0x0b4b5,
  65 + 0x06a50,
  66 + 0x06d40,
  67 + 0x1ab54,
  68 + 0x02b60,
  69 + 0x09570,
  70 + 0x052f2,
  71 + 0x04970, // 1920-1929
  72 + 0x06566,
  73 + 0x0d4a0,
  74 + 0x0ea50,
  75 + 0x06e95,
  76 + 0x05ad0,
  77 + 0x02b60,
  78 + 0x186e3,
  79 + 0x092e0,
  80 + 0x1c8d7,
  81 + 0x0c950, // 1930-1939
  82 + 0x0d4a0,
  83 + 0x1d8a6,
  84 + 0x0b550,
  85 + 0x056a0,
  86 + 0x1a5b4,
  87 + 0x025d0,
  88 + 0x092d0,
  89 + 0x0d2b2,
  90 + 0x0a950,
  91 + 0x0b557, // 1940-1949
  92 + 0x06ca0,
  93 + 0x0b550,
  94 + 0x15355,
  95 + 0x04da0,
  96 + 0x0a5b0,
  97 + 0x14573,
  98 + 0x052b0,
  99 + 0x0a9a8,
  100 + 0x0e950,
  101 + 0x06aa0, // 1950-1959
  102 + 0x0aea6,
  103 + 0x0ab50,
  104 + 0x04b60,
  105 + 0x0aae4,
  106 + 0x0a570,
  107 + 0x05260,
  108 + 0x0f263,
  109 + 0x0d950,
  110 + 0x05b57,
  111 + 0x056a0, // 1960-1969
  112 + 0x096d0,
  113 + 0x04dd5,
  114 + 0x04ad0,
  115 + 0x0a4d0,
  116 + 0x0d4d4,
  117 + 0x0d250,
  118 + 0x0d558,
  119 + 0x0b540,
  120 + 0x0b6a0,
  121 + 0x195a6, // 1970-1979
  122 + 0x095b0,
  123 + 0x049b0,
  124 + 0x0a974,
  125 + 0x0a4b0,
  126 + 0x0b27a,
  127 + 0x06a50,
  128 + 0x06d40,
  129 + 0x0af46,
  130 + 0x0ab60,
  131 + 0x09570, // 1980-1989
  132 + 0x04af5,
  133 + 0x04970,
  134 + 0x064b0,
  135 + 0x074a3,
  136 + 0x0ea50,
  137 + 0x06b58,
  138 + 0x055c0,
  139 + 0x0ab60,
  140 + 0x096d5,
  141 + 0x092e0, // 1990-1999
  142 + 0x0c960,
  143 + 0x0d954,
  144 + 0x0d4a0,
  145 + 0x0da50,
  146 + 0x07552,
  147 + 0x056a0,
  148 + 0x0abb7,
  149 + 0x025d0,
  150 + 0x092d0,
  151 + 0x0cab5, // 2000-2009
  152 + 0x0a950,
  153 + 0x0b4a0,
  154 + 0x0baa4,
  155 + 0x0ad50,
  156 + 0x055d9,
  157 + 0x04ba0,
  158 + 0x0a5b0,
  159 + 0x15176,
  160 + 0x052b0,
  161 + 0x0a930, // 2010-2019
  162 + 0x07954,
  163 + 0x06aa0,
  164 + 0x0ad50,
  165 + 0x05b52,
  166 + 0x04b60,
  167 + 0x0a6e6,
  168 + 0x0a4e0,
  169 + 0x0d260,
  170 + 0x0ea65,
  171 + 0x0d530, // 2020-2029
  172 + 0x05aa0,
  173 + 0x076a3,
  174 + 0x096d0,
  175 + 0x04afb,
  176 + 0x04ad0,
  177 + 0x0a4d0,
  178 + 0x1d0b6,
  179 + 0x0d250,
  180 + 0x0d520,
  181 + 0x0dd45, // 2030-2039
  182 + 0x0b5a0,
  183 + 0x056d0,
  184 + 0x055b2,
  185 + 0x049b0,
  186 + 0x0a577,
  187 + 0x0a4b0,
  188 + 0x0aa50,
  189 + 0x1b255,
  190 + 0x06d20,
  191 + 0x0ada0, // 2040-2049
  192 + /** Add By JJonline@JJonline.Cn **/
  193 + 0x14b63,
  194 + 0x09370,
  195 + 0x049f8,
  196 + 0x04970,
  197 + 0x064b0,
  198 + 0x168a6,
  199 + 0x0ea50,
  200 + 0x06b20,
  201 + 0x1a6c4,
  202 + 0x0aae0, // 2050-2059
  203 + 0x0a2e0,
  204 + 0x0d2e3,
  205 + 0x0c960,
  206 + 0x0d557,
  207 + 0x0d4a0,
  208 + 0x0da50,
  209 + 0x05d55,
  210 + 0x056a0,
  211 + 0x0a6d0,
  212 + 0x055d4, // 2060-2069
  213 + 0x052d0,
  214 + 0x0a9b8,
  215 + 0x0a950,
  216 + 0x0b4a0,
  217 + 0x0b6a6,
  218 + 0x0ad50,
  219 + 0x055a0,
  220 + 0x0aba4,
  221 + 0x0a5b0,
  222 + 0x052b0, // 2070-2079
  223 + 0x0b273,
  224 + 0x06930,
  225 + 0x07337,
  226 + 0x06aa0,
  227 + 0x0ad50,
  228 + 0x14b55,
  229 + 0x04b60,
  230 + 0x0a570,
  231 + 0x054e4,
  232 + 0x0d160, // 2080-2089
  233 + 0x0e968,
  234 + 0x0d520,
  235 + 0x0daa0,
  236 + 0x16aa6,
  237 + 0x056d0,
  238 + 0x04ae0,
  239 + 0x0a9d4,
  240 + 0x0a2d0,
  241 + 0x0d150,
  242 + 0x0f252, // 2090-2099
  243 + 0x0d520
  244 + ], // 2100
  245 +
  246 + /**
  247 + * 公历每个月份的天数普通表
  248 + * @Array Of Property
  249 + * @return Number
  250 + */
  251 + solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
  252 +
  253 + /**
  254 + * 天干地支之天干速查表
  255 + * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
  256 + * @return Cn string
  257 + */
  258 + Gan: [
  259 + '\u7532',
  260 + '\u4e59',
  261 + '\u4e19',
  262 + '\u4e01',
  263 + '\u620a',
  264 + '\u5df1',
  265 + '\u5e9a',
  266 + '\u8f9b',
  267 + '\u58ec',
  268 + '\u7678'
  269 + ],
  270 +
  271 + /**
  272 + * 天干地支之地支速查表
  273 + * @Array Of Property
  274 + * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
  275 + * @return Cn string
  276 + */
  277 + Zhi: [
  278 + '\u5b50',
  279 + '\u4e11',
  280 + '\u5bc5',
  281 + '\u536f',
  282 + '\u8fb0',
  283 + '\u5df3',
  284 + '\u5348',
  285 + '\u672a',
  286 + '\u7533',
  287 + '\u9149',
  288 + '\u620c',
  289 + '\u4ea5'
  290 + ],
  291 +
  292 + /**
  293 + * 天干地支之地支速查表<=>生肖
  294 + * @Array Of Property
  295 + * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
  296 + * @return Cn string
  297 + */
  298 + Animals: [
  299 + '\u9f20',
  300 + '\u725b',
  301 + '\u864e',
  302 + '\u5154',
  303 + '\u9f99',
  304 + '\u86c7',
  305 + '\u9a6c',
  306 + '\u7f8a',
  307 + '\u7334',
  308 + '\u9e21',
  309 + '\u72d7',
  310 + '\u732a'
  311 + ],
  312 +
  313 + /**
  314 + * 24节气速查表
  315 + * @Array Of Property
  316 + * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
  317 + * @return Cn string
  318 + */
  319 + solarTerm: [
  320 + '\u5c0f\u5bd2',
  321 + '\u5927\u5bd2',
  322 + '\u7acb\u6625',
  323 + '\u96e8\u6c34',
  324 + '\u60ca\u86f0',
  325 + '\u6625\u5206',
  326 + '\u6e05\u660e',
  327 + '\u8c37\u96e8',
  328 + '\u7acb\u590f',
  329 + '\u5c0f\u6ee1',
  330 + '\u8292\u79cd',
  331 + '\u590f\u81f3',
  332 + '\u5c0f\u6691',
  333 + '\u5927\u6691',
  334 + '\u7acb\u79cb',
  335 + '\u5904\u6691',
  336 + '\u767d\u9732',
  337 + '\u79cb\u5206',
  338 + '\u5bd2\u9732',
  339 + '\u971c\u964d',
  340 + '\u7acb\u51ac',
  341 + '\u5c0f\u96ea',
  342 + '\u5927\u96ea',
  343 + '\u51ac\u81f3'
  344 + ],
  345 +
  346 + /**
  347 + * 1900-2100各年的24节气日期速查表
  348 + * @Array Of Property
  349 + * @return 0x string For splice
  350 + */
  351 + sTermInfo: [
  352 + '9778397bd097c36b0b6fc9274c91aa',
  353 + '97b6b97bd19801ec9210c965cc920e',
  354 + '97bcf97c3598082c95f8c965cc920f',
  355 + '97bd0b06bdb0722c965ce1cfcc920f',
  356 + 'b027097bd097c36b0b6fc9274c91aa',
  357 + '97b6b97bd19801ec9210c965cc920e',
  358 + '97bcf97c359801ec95f8c965cc920f',
  359 + '97bd0b06bdb0722c965ce1cfcc920f',
  360 + 'b027097bd097c36b0b6fc9274c91aa',
  361 + '97b6b97bd19801ec9210c965cc920e',
  362 + '97bcf97c359801ec95f8c965cc920f',
  363 + '97bd0b06bdb0722c965ce1cfcc920f',
  364 + 'b027097bd097c36b0b6fc9274c91aa',
  365 + '9778397bd19801ec9210c965cc920e',
  366 + '97b6b97bd19801ec95f8c965cc920f',
  367 + '97bd09801d98082c95f8e1cfcc920f',
  368 + '97bd097bd097c36b0b6fc9210c8dc2',
  369 + '9778397bd197c36c9210c9274c91aa',
  370 + '97b6b97bd19801ec95f8c965cc920e',
  371 + '97bd09801d98082c95f8e1cfcc920f',
  372 + '97bd097bd097c36b0b6fc9210c8dc2',
  373 + '9778397bd097c36c9210c9274c91aa',
  374 + '97b6b97bd19801ec95f8c965cc920e',
  375 + '97bcf97c3598082c95f8e1cfcc920f',
  376 + '97bd097bd097c36b0b6fc9210c8dc2',
  377 + '9778397bd097c36c9210c9274c91aa',
  378 + '97b6b97bd19801ec9210c965cc920e',
  379 + '97bcf97c3598082c95f8c965cc920f',
  380 + '97bd097bd097c35b0b6fc920fb0722',
  381 + '9778397bd097c36b0b6fc9274c91aa',
  382 + '97b6b97bd19801ec9210c965cc920e',
  383 + '97bcf97c3598082c95f8c965cc920f',
  384 + '97bd097bd097c35b0b6fc920fb0722',
  385 + '9778397bd097c36b0b6fc9274c91aa',
  386 + '97b6b97bd19801ec9210c965cc920e',
  387 + '97bcf97c359801ec95f8c965cc920f',
  388 + '97bd097bd097c35b0b6fc920fb0722',
  389 + '9778397bd097c36b0b6fc9274c91aa',
  390 + '97b6b97bd19801ec9210c965cc920e',
  391 + '97bcf97c359801ec95f8c965cc920f',
  392 + '97bd097bd097c35b0b6fc920fb0722',
  393 + '9778397bd097c36b0b6fc9274c91aa',
  394 + '97b6b97bd19801ec9210c965cc920e',
  395 + '97bcf97c359801ec95f8c965cc920f',
  396 + '97bd097bd07f595b0b6fc920fb0722',
  397 + '9778397bd097c36b0b6fc9210c8dc2',
  398 + '9778397bd19801ec9210c9274c920e',
  399 + '97b6b97bd19801ec95f8c965cc920f',
  400 + '97bd07f5307f595b0b0bc920fb0722',
  401 + '7f0e397bd097c36b0b6fc9210c8dc2',
  402 + '9778397bd097c36c9210c9274c920e',
  403 + '97b6b97bd19801ec95f8c965cc920f',
  404 + '97bd07f5307f595b0b0bc920fb0722',
  405 + '7f0e397bd097c36b0b6fc9210c8dc2',
  406 + '9778397bd097c36c9210c9274c91aa',
  407 + '97b6b97bd19801ec9210c965cc920e',
  408 + '97bd07f1487f595b0b0bc920fb0722',
  409 + '7f0e397bd097c36b0b6fc9210c8dc2',
  410 + '9778397bd097c36b0b6fc9274c91aa',
  411 + '97b6b97bd19801ec9210c965cc920e',
  412 + '97bcf7f1487f595b0b0bb0b6fb0722',
  413 + '7f0e397bd097c35b0b6fc920fb0722',
  414 + '9778397bd097c36b0b6fc9274c91aa',
  415 + '97b6b97bd19801ec9210c965cc920e',
  416 + '97bcf7f1487f595b0b0bb0b6fb0722',
  417 + '7f0e397bd097c35b0b6fc920fb0722',
  418 + '9778397bd097c36b0b6fc9274c91aa',
  419 + '97b6b97bd19801ec9210c965cc920e',
  420 + '97bcf7f1487f531b0b0bb0b6fb0722',
  421 + '7f0e397bd097c35b0b6fc920fb0722',
  422 + '9778397bd097c36b0b6fc9274c91aa',
  423 + '97b6b97bd19801ec9210c965cc920e',
  424 + '97bcf7f1487f531b0b0bb0b6fb0722',
  425 + '7f0e397bd07f595b0b6fc920fb0722',
  426 + '9778397bd097c36b0b6fc9274c91aa',
  427 + '97b6b97bd19801ec9210c9274c920e',
  428 + '97bcf7f0e47f531b0b0bb0b6fb0722',
  429 + '7f0e397bd07f595b0b0bc920fb0722',
  430 + '9778397bd097c36b0b6fc9210c91aa',
  431 + '97b6b97bd197c36c9210c9274c920e',
  432 + '97bcf7f0e47f531b0b0bb0b6fb0722',
  433 + '7f0e397bd07f595b0b0bc920fb0722',
  434 + '9778397bd097c36b0b6fc9210c8dc2',
  435 + '9778397bd097c36c9210c9274c920e',
  436 + '97b6b7f0e47f531b0723b0b6fb0722',
  437 + '7f0e37f5307f595b0b0bc920fb0722',
  438 + '7f0e397bd097c36b0b6fc9210c8dc2',
  439 + '9778397bd097c36b0b70c9274c91aa',
  440 + '97b6b7f0e47f531b0723b0b6fb0721',
  441 + '7f0e37f1487f595b0b0bb0b6fb0722',
  442 + '7f0e397bd097c35b0b6fc9210c8dc2',
  443 + '9778397bd097c36b0b6fc9274c91aa',
  444 + '97b6b7f0e47f531b0723b0b6fb0721',
  445 + '7f0e27f1487f595b0b0bb0b6fb0722',
  446 + '7f0e397bd097c35b0b6fc920fb0722',
  447 + '9778397bd097c36b0b6fc9274c91aa',
  448 + '97b6b7f0e47f531b0723b0b6fb0721',
  449 + '7f0e27f1487f531b0b0bb0b6fb0722',
  450 + '7f0e397bd097c35b0b6fc920fb0722',
  451 + '9778397bd097c36b0b6fc9274c91aa',
  452 + '97b6b7f0e47f531b0723b0b6fb0721',
  453 + '7f0e27f1487f531b0b0bb0b6fb0722',
  454 + '7f0e397bd097c35b0b6fc920fb0722',
  455 + '9778397bd097c36b0b6fc9274c91aa',
  456 + '97b6b7f0e47f531b0723b0b6fb0721',
  457 + '7f0e27f1487f531b0b0bb0b6fb0722',
  458 + '7f0e397bd07f595b0b0bc920fb0722',
  459 + '9778397bd097c36b0b6fc9274c91aa',
  460 + '97b6b7f0e47f531b0723b0787b0721',
  461 + '7f0e27f0e47f531b0b0bb0b6fb0722',
  462 + '7f0e397bd07f595b0b0bc920fb0722',
  463 + '9778397bd097c36b0b6fc9210c91aa',
  464 + '97b6b7f0e47f149b0723b0787b0721',
  465 + '7f0e27f0e47f531b0723b0b6fb0722',
  466 + '7f0e397bd07f595b0b0bc920fb0722',
  467 + '9778397bd097c36b0b6fc9210c8dc2',
  468 + '977837f0e37f149b0723b0787b0721',
  469 + '7f07e7f0e47f531b0723b0b6fb0722',
  470 + '7f0e37f5307f595b0b0bc920fb0722',
  471 + '7f0e397bd097c35b0b6fc9210c8dc2',
  472 + '977837f0e37f14998082b0787b0721',
  473 + '7f07e7f0e47f531b0723b0b6fb0721',
  474 + '7f0e37f1487f595b0b0bb0b6fb0722',
  475 + '7f0e397bd097c35b0b6fc9210c8dc2',
  476 + '977837f0e37f14998082b0787b06bd',
  477 + '7f07e7f0e47f531b0723b0b6fb0721',
  478 + '7f0e27f1487f531b0b0bb0b6fb0722',
  479 + '7f0e397bd097c35b0b6fc920fb0722',
  480 + '977837f0e37f14998082b0787b06bd',
  481 + '7f07e7f0e47f531b0723b0b6fb0721',
  482 + '7f0e27f1487f531b0b0bb0b6fb0722',
  483 + '7f0e397bd097c35b0b6fc920fb0722',
  484 + '977837f0e37f14998082b0787b06bd',
  485 + '7f07e7f0e47f531b0723b0b6fb0721',
  486 + '7f0e27f1487f531b0b0bb0b6fb0722',
  487 + '7f0e397bd07f595b0b0bc920fb0722',
  488 + '977837f0e37f14998082b0787b06bd',
  489 + '7f07e7f0e47f531b0723b0b6fb0721',
  490 + '7f0e27f1487f531b0b0bb0b6fb0722',
  491 + '7f0e397bd07f595b0b0bc920fb0722',
  492 + '977837f0e37f14998082b0787b06bd',
  493 + '7f07e7f0e47f149b0723b0787b0721',
  494 + '7f0e27f0e47f531b0b0bb0b6fb0722',
  495 + '7f0e397bd07f595b0b0bc920fb0722',
  496 + '977837f0e37f14998082b0723b06bd',
  497 + '7f07e7f0e37f149b0723b0787b0721',
  498 + '7f0e27f0e47f531b0723b0b6fb0722',
  499 + '7f0e397bd07f595b0b0bc920fb0722',
  500 + '977837f0e37f14898082b0723b02d5',
  501 + '7ec967f0e37f14998082b0787b0721',
  502 + '7f07e7f0e47f531b0723b0b6fb0722',
  503 + '7f0e37f1487f595b0b0bb0b6fb0722',
  504 + '7f0e37f0e37f14898082b0723b02d5',
  505 + '7ec967f0e37f14998082b0787b0721',
  506 + '7f07e7f0e47f531b0723b0b6fb0722',
  507 + '7f0e37f1487f531b0b0bb0b6fb0722',
  508 + '7f0e37f0e37f14898082b0723b02d5',
  509 + '7ec967f0e37f14998082b0787b06bd',
  510 + '7f07e7f0e47f531b0723b0b6fb0721',
  511 + '7f0e37f1487f531b0b0bb0b6fb0722',
  512 + '7f0e37f0e37f14898082b072297c35',
  513 + '7ec967f0e37f14998082b0787b06bd',
  514 + '7f07e7f0e47f531b0723b0b6fb0721',
  515 + '7f0e27f1487f531b0b0bb0b6fb0722',
  516 + '7f0e37f0e37f14898082b072297c35',
  517 + '7ec967f0e37f14998082b0787b06bd',
  518 + '7f07e7f0e47f531b0723b0b6fb0721',
  519 + '7f0e27f1487f531b0b0bb0b6fb0722',
  520 + '7f0e37f0e366aa89801eb072297c35',
  521 + '7ec967f0e37f14998082b0787b06bd',
  522 + '7f07e7f0e47f149b0723b0787b0721',
  523 + '7f0e27f1487f531b0b0bb0b6fb0722',
  524 + '7f0e37f0e366aa89801eb072297c35',
  525 + '7ec967f0e37f14998082b0723b06bd',
  526 + '7f07e7f0e47f149b0723b0787b0721',
  527 + '7f0e27f0e47f531b0723b0b6fb0722',
  528 + '7f0e37f0e366aa89801eb072297c35',
  529 + '7ec967f0e37f14998082b0723b06bd',
  530 + '7f07e7f0e37f14998083b0787b0721',
  531 + '7f0e27f0e47f531b0723b0b6fb0722',
  532 + '7f0e37f0e366aa89801eb072297c35',
  533 + '7ec967f0e37f14898082b0723b02d5',
  534 + '7f07e7f0e37f14998082b0787b0721',
  535 + '7f07e7f0e47f531b0723b0b6fb0722',
  536 + '7f0e36665b66aa89801e9808297c35',
  537 + '665f67f0e37f14898082b0723b02d5',
  538 + '7ec967f0e37f14998082b0787b0721',
  539 + '7f07e7f0e47f531b0723b0b6fb0722',
  540 + '7f0e36665b66a449801e9808297c35',
  541 + '665f67f0e37f14898082b0723b02d5',
  542 + '7ec967f0e37f14998082b0787b06bd',
  543 + '7f07e7f0e47f531b0723b0b6fb0721',
  544 + '7f0e36665b66a449801e9808297c35',
  545 + '665f67f0e37f14898082b072297c35',
  546 + '7ec967f0e37f14998082b0787b06bd',
  547 + '7f07e7f0e47f531b0723b0b6fb0721',
  548 + '7f0e26665b66a449801e9808297c35',
  549 + '665f67f0e37f1489801eb072297c35',
  550 + '7ec967f0e37f14998082b0787b06bd',
  551 + '7f07e7f0e47f531b0723b0b6fb0721',
  552 + '7f0e27f1487f531b0b0bb0b6fb0722'
  553 + ],
  554 +
  555 + /**
  556 + * 数字转中文速查表
  557 + * @Array Of Property
  558 + * @trans ['日','一','二','三','四','五','六','七','八','九','十']
  559 + * @return Cn string
  560 + */
  561 + nStr1: [
  562 + '\u65e5',
  563 + '\u4e00',
  564 + '\u4e8c',
  565 + '\u4e09',
  566 + '\u56db',
  567 + '\u4e94',
  568 + '\u516d',
  569 + '\u4e03',
  570 + '\u516b',
  571 + '\u4e5d',
  572 + '\u5341'
  573 + ],
  574 +
  575 + /**
  576 + * 日期转农历称呼速查表
  577 + * @Array Of Property
  578 + * @trans ['初','十','廿','卅']
  579 + * @return Cn string
  580 + */
  581 + nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
  582 +
  583 + /**
  584 + * 月份转农历称呼速查表
  585 + * @Array Of Property
  586 + * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
  587 + * @return Cn string
  588 + */
  589 + nStr3: [
  590 + '\u6b63',
  591 + '\u4e8c',
  592 + '\u4e09',
  593 + '\u56db',
  594 + '\u4e94',
  595 + '\u516d',
  596 + '\u4e03',
  597 + '\u516b',
  598 + '\u4e5d',
  599 + '\u5341',
  600 + '\u51ac',
  601 + '\u814a'
  602 + ],
  603 +
  604 + /**
  605 + * 返回农历y年一整年的总天数
  606 + * @param lunar Year
  607 + * @return Number
  608 + * @eg:var count = calendar.lYearDays(1987) ;//count=387
  609 + */
  610 + lYearDays: function(y) {
  611 + let i
  612 + let sum = 348
  613 + for (i = 0x8000; i > 0x8; i >>= 1) {
  614 + sum += calendar.lunarInfo[y - 1900] & i ? 1 : 0
  615 + }
  616 + return sum + calendar.leapDays(y)
  617 + },
  618 +
  619 + /**
  620 + * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
  621 + * @param lunar Year
  622 + * @return Number (0-12)
  623 + * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
  624 + */
  625 + leapMonth: function(y) {
  626 + // 闰字编码 \u95f0
  627 + return calendar.lunarInfo[y - 1900] & 0xf
  628 + },
  629 +
  630 + /**
  631 + * 返回农历y年闰月的天数 若该年没有闰月则返回0
  632 + * @param lunar Year
  633 + * @return Number (0、29、30)
  634 + * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
  635 + */
  636 + leapDays: function(y) {
  637 + if (calendar.leapMonth(y)) {
  638 + return calendar.lunarInfo[y - 1900] & 0x10000 ? 30 : 29
  639 + }
  640 + return 0
  641 + },
  642 +
  643 + /**
  644 + * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
  645 + * @param lunar Year
  646 + * @return Number (-1、29、30)
  647 + * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
  648 + */
  649 + monthDays: function(y, m) {
  650 + if (m > 12 || m < 1) return -1 // 月份参数从1至12,参数错误返回-1
  651 + return calendar.lunarInfo[y - 1900] & (0x10000 >> m) ? 30 : 29
  652 + },
  653 +
  654 + /**
  655 + * 返回公历(!)y年m月的天数
  656 + * @param solar Year
  657 + * @return Number (-1、28、29、30、31)
  658 + * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
  659 + */
  660 + solarDays: function(y, m) {
  661 + if (m > 12 || m < 1) return -1 // 若参数错误 返回-1
  662 + const ms = m - 1
  663 + if (+ms === 1) {
  664 + // 2月份的闰平规律测算后确认返回28或29
  665 + return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 ? 29 : 28
  666 + } else {
  667 + return calendar.solarMonth[ms]
  668 + }
  669 + },
  670 +
  671 + /**
  672 + * 农历年份转换为干支纪年
  673 + * @param lYear 农历年的年份数
  674 + * @return Cn string
  675 + */
  676 + toGanZhiYear: function(lYear) {
  677 + let ganKey = (lYear - 3) % 10
  678 + let zhiKey = (lYear - 3) % 12
  679 + if (+ganKey === 0) ganKey = 10 // 如果余数为0则为最后一个天干
  680 + if (+zhiKey === 0) zhiKey = 12 // 如果余数为0则为最后一个地支
  681 + return calendar.Gan[ganKey - 1] + calendar.Zhi[zhiKey - 1]
  682 + },
  683 +
  684 + /**
  685 + * 公历月、日判断所属星座
  686 + * @param cMonth [description]
  687 + * @param cDay [description]
  688 + * @return Cn string
  689 + */
  690 + toAstro: function(cMonth, cDay) {
  691 + const s =
  692 + '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
  693 + const arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
  694 + return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7' // 座
  695 + },
  696 +
  697 + /**
  698 + * 传入offset偏移量返回干支
  699 + * @param offset 相对甲子的偏移量
  700 + * @return Cn string
  701 + */
  702 + toGanZhi: function(offset) {
  703 + return calendar.Gan[offset % 10] + calendar.Zhi[offset % 12]
  704 + },
  705 +
  706 + /**
  707 + * 传入公历(!)y年获得该年第n个节气的公历日期
  708 + * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
  709 + * @return day Number
  710 + * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
  711 + */
  712 + getTerm: function(y, n) {
  713 + if (y < 1900 || y > 2100) return -1
  714 + if (n < 1 || n > 24) return -1
  715 + const _table = calendar.sTermInfo[y - 1900]
  716 + const _info = [
  717 + parseInt('0x' + _table.substr(0, 5)).toString(),
  718 + parseInt('0x' + _table.substr(5, 5)).toString(),
  719 + parseInt('0x' + _table.substr(10, 5)).toString(),
  720 + parseInt('0x' + _table.substr(15, 5)).toString(),
  721 + parseInt('0x' + _table.substr(20, 5)).toString(),
  722 + parseInt('0x' + _table.substr(25, 5)).toString()
  723 + ]
  724 + const _calday = [
  725 + _info[0].substr(0, 1),
  726 + _info[0].substr(1, 2),
  727 + _info[0].substr(3, 1),
  728 + _info[0].substr(4, 2),
  729 +
  730 + _info[1].substr(0, 1),
  731 + _info[1].substr(1, 2),
  732 + _info[1].substr(3, 1),
  733 + _info[1].substr(4, 2),
  734 +
  735 + _info[2].substr(0, 1),
  736 + _info[2].substr(1, 2),
  737 + _info[2].substr(3, 1),
  738 + _info[2].substr(4, 2),
  739 +
  740 + _info[3].substr(0, 1),
  741 + _info[3].substr(1, 2),
  742 + _info[3].substr(3, 1),
  743 + _info[3].substr(4, 2),
  744 +
  745 + _info[4].substr(0, 1),
  746 + _info[4].substr(1, 2),
  747 + _info[4].substr(3, 1),
  748 + _info[4].substr(4, 2),
  749 +
  750 + _info[5].substr(0, 1),
  751 + _info[5].substr(1, 2),
  752 + _info[5].substr(3, 1),
  753 + _info[5].substr(4, 2)
  754 + ]
  755 + return parseInt(_calday[n - 1])
  756 + },
  757 +
  758 + /**
  759 + * 传入农历数字月份返回汉语通俗表示法
  760 + * @param lunar month
  761 + * @return Cn string
  762 + * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
  763 + */
  764 + toChinaMonth: function(m) {
  765 + // 月 => \u6708
  766 + if (m > 12 || m < 1) return -1 // 若参数错误 返回-1
  767 + let s = calendar.nStr3[m - 1]
  768 + s += '\u6708' // 加上月字
  769 + return s
  770 + },
  771 +
  772 + /**
  773 + * 传入农历日期数字返回汉字表示法
  774 + * @param lunar day
  775 + * @return Cn string
  776 + * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
  777 + */
  778 + toChinaDay: function(d) {
  779 + // 日 => \u65e5
  780 + let s
  781 + switch (d) {
  782 + case 10:
  783 + s = '\u521d\u5341'
  784 + break
  785 + case 20:
  786 + s = '\u4e8c\u5341'
  787 + break
  788 + case 30:
  789 + s = '\u4e09\u5341'
  790 + break
  791 + default:
  792 + s = calendar.nStr2[Math.floor(d / 10)]
  793 + s += calendar.nStr1[d % 10]
  794 + }
  795 + return s
  796 + },
  797 +
  798 + /**
  799 + * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
  800 + * @param y year
  801 + * @return Cn string
  802 + * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
  803 + */
  804 + getAnimal: function(y) {
  805 + return calendar.Animals[(y - 4) % 12]
  806 + },
  807 +
  808 + /**
  809 + * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
  810 + * @param y solar year
  811 + * @param m solar month
  812 + * @param d solar day
  813 + * @return JSON object
  814 + * @eg:console.log(calendar.solar2lunar(1987,11,01));
  815 + */
  816 + solar2lunar: function(y, m, d) {
  817 + // 参数区间1900.1.31~2100.12.31
  818 + // 年份限定、上限
  819 + if (y < 1900 || y > 2100) {
  820 + return -1 // undefined转换为数字变为NaN
  821 + }
  822 + // 公历传参最下限
  823 + if (+y === 1900 && +m === 1 && +d < 31) {
  824 + return -1
  825 + }
  826 + // 未传参 获得当天
  827 + let objDate
  828 + if (!y) {
  829 + objDate = new Date()
  830 + } else {
  831 + objDate = new Date(y, parseInt(m) - 1, d)
  832 + }
  833 + let i
  834 + let leap = 0
  835 + let temp = 0
  836 + // 修正ymd参数
  837 + y = objDate.getFullYear()
  838 + m = objDate.getMonth() + 1
  839 + d = objDate.getDate()
  840 + let offset =
  841 + (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) -
  842 + Date.UTC(1900, 0, 31)) /
  843 + 86400000
  844 + for (i = 1900; i < 2101 && offset > 0; i++) {
  845 + temp = calendar.lYearDays(i)
  846 + offset -= temp
  847 + }
  848 + if (offset < 0) {
  849 + offset += temp
  850 + i--
  851 + }
  852 +
  853 + // 是否今天
  854 + const isTodayObj = new Date()
  855 + let isToday = false
  856 + if (
  857 + isTodayObj.getFullYear() === +y &&
  858 + isTodayObj.getMonth() + 1 === +m &&
  859 + isTodayObj.getDate() === +d
  860 + ) {
  861 + isToday = true
  862 + }
  863 + // 星期几
  864 + let nWeek = objDate.getDay()
  865 + const cWeek = calendar.nStr1[nWeek]
  866 + // 数字表示周几顺应天朝周一开始的惯例
  867 + if (+nWeek === 0) {
  868 + nWeek = 7
  869 + }
  870 + // 农历年
  871 + const year = i
  872 + leap = calendar.leapMonth(i) // 闰哪个月
  873 + let isLeap = false
  874 +
  875 + // 效验闰月
  876 + for (i = 1; i < 13 && offset > 0; i++) {
  877 + // 闰月
  878 + if (leap > 0 && i === leap + 1 && isLeap === false) {
  879 + --i
  880 + isLeap = true
  881 + temp = calendar.leapDays(year) // 计算农历闰月天数
  882 + } else {
  883 + temp = calendar.monthDays(year, i) // 计算农历普通月天数
  884 + }
  885 + // 解除闰月
  886 + if (isLeap === true && i === leap + 1) isLeap = false
  887 + offset -= temp
  888 + }
  889 + // 闰月导致数组下标重叠取反
  890 + if (offset === 0 && leap > 0 && i === leap + 1) {
  891 + if (isLeap) {
  892 + isLeap = false
  893 + } else {
  894 + isLeap = true
  895 + --i
  896 + }
  897 + }
  898 + if (offset < 0) {
  899 + offset += temp
  900 + --i
  901 + }
  902 + // 农历月
  903 + const month = i
  904 + // 农历日
  905 + const day = offset + 1
  906 + // 天干地支处理
  907 + const sm = m - 1
  908 + const gzY = calendar.toGanZhiYear(year)
  909 +
  910 + // 当月的两个节气
  911 + // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
  912 + const firstNode = calendar.getTerm(y, m * 2 - 1) // 返回当月「节」为几日开始
  913 + const secondNode = calendar.getTerm(y, m * 2) // 返回当月「节」为几日开始
  914 +
  915 + // 依据12节气修正干支月
  916 + let gzM = calendar.toGanZhi((y - 1900) * 12 + m + 11)
  917 + if (d >= firstNode) {
  918 + gzM = calendar.toGanZhi((y - 1900) * 12 + m + 12)
  919 + }
  920 +
  921 + // 传入的日期的节气与否
  922 + let isTerm = false
  923 + let Term = null
  924 + if (+firstNode === d) {
  925 + isTerm = true
  926 + Term = calendar.solarTerm[m * 2 - 2]
  927 + }
  928 + if (+secondNode === d) {
  929 + isTerm = true
  930 + Term = calendar.solarTerm[m * 2 - 1]
  931 + }
  932 + // 日柱 当月一日与 1900/1/1 相差天数
  933 + const dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
  934 + const gzD = calendar.toGanZhi(dayCyclical + d - 1)
  935 + // 该日期所属的星座
  936 + const astro = calendar.toAstro(m, d)
  937 +
  938 + return {
  939 + lYear: year,
  940 + lMonth: month,
  941 + lDay: day,
  942 + Animal: calendar.getAnimal(year),
  943 + IMonthCn: (isLeap ? '\u95f0' : '') + calendar.toChinaMonth(month),
  944 + IDayCn: calendar.toChinaDay(day),
  945 + cYear: y,
  946 + cMonth: m,
  947 + cDay: d,
  948 + gzYear: gzY,
  949 + gzMonth: gzM,
  950 + gzDay: gzD,
  951 + isToday: isToday,
  952 + isLeap: isLeap,
  953 + nWeek: nWeek,
  954 + ncWeek: '\u661f\u671f' + cWeek,
  955 + isTerm: isTerm,
  956 + Term: Term,
  957 + astro: astro
  958 + }
  959 + },
  960 +
  961 + /**
  962 + * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
  963 + * @param y lunar year
  964 + * @param m lunar month
  965 + * @param d lunar day
  966 + * @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
  967 + * @return JSON object
  968 + * @eg:console.log(calendar.lunar2solar(1987,9,10));
  969 + */
  970 + lunar2solar: function(y, m, d, isLeapMonth) {
  971 + // 参数区间1900.1.31~2100.12.1
  972 + isLeapMonth = !!isLeapMonth
  973 + // let leapOffset = 0;
  974 + const leapMonth = calendar.leapMonth(y)
  975 + // let leapDay = calendar.leapDays(y);
  976 + if (isLeapMonth && leapMonth !== m) return -1 // 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
  977 + if (
  978 + (+y === 2100 && +m === 12 && +d > 1) ||
  979 + (+y === 1900 && +m === 1 && +d < 31)
  980 + )
  981 + return -1 // 超出了最大极限值
  982 + const day = calendar.monthDays(y, m)
  983 + let _day = day
  984 + // bugFix 2016-9-25
  985 + // if month is leap, _day use leapDays method
  986 + if (isLeapMonth) {
  987 + _day = calendar.leapDays(y, m)
  988 + }
  989 + if (y < 1900 || y > 2100 || d > _day) return -1 // 参数合法性效验
  990 +
  991 + // 计算农历的时间差
  992 + let offset = 0
  993 + for (let i = 1900; i < y; i++) {
  994 + offset += calendar.lYearDays(i)
  995 + }
  996 + let leap = 0
  997 + let isAdd = false
  998 + for (let i = 1; i < m; i++) {
  999 + leap = calendar.leapMonth(y)
  1000 + if (!isAdd) {
  1001 + // 处理闰月
  1002 + if (leap <= i && leap > 0) {
  1003 + offset += calendar.leapDays(y)
  1004 + isAdd = true
  1005 + }
  1006 + }
  1007 + offset += calendar.monthDays(y, i)
  1008 + }
  1009 + // 转换闰月农历 需补充该年闰月的前一个月的时差
  1010 + if (isLeapMonth) offset += day
  1011 + // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
  1012 + const stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
  1013 + const calObj = new Date((offset + d - 31) * 86400000 + stmap)
  1014 + const cY = calObj.getUTCFullYear()
  1015 + const cM = calObj.getUTCMonth() + 1
  1016 + const cD = calObj.getUTCDate()
  1017 +
  1018 + return calendar.solar2lunar(cY, cM, cD)
  1019 + }
  1020 +}
  1021 +
  1022 +const {
  1023 + Gan,
  1024 + Zhi,
  1025 + nStr1,
  1026 + nStr2,
  1027 + nStr3,
  1028 + Animals,
  1029 + solarTerm,
  1030 + lunarInfo,
  1031 + sTermInfo,
  1032 + solarMonth,
  1033 + ...rest
  1034 +} = calendar
  1035 +
  1036 +export default rest
... ...
component/v2/plugins/solarLunar/index.js 0 → 100644
... ... @@ -0,0 +1,59 @@
  1 +import { dateUtil } from '../../utils/index'
  2 +import convertSolarLunar from './convertSolarLunar'
  3 +
  4 +function getDateRow2Dict(dateInfo) {
  5 + if (!dateInfo) return dateInfo
  6 + if (typeof dateInfo === 'string' && dateInfo.includes('-')) {
  7 + dateInfo = dateUtil.transformDateRow2Dict(dateInfo)
  8 + }
  9 + return dateInfo
  10 +}
  11 +
  12 +export default () => {
  13 + return {
  14 + name: 'convertSolarLunar',
  15 + beforeRender(calendarData = {}, calendarConfig = {}) {
  16 + let { dates = [], selectedDates = [] } = calendarData
  17 + if (calendarConfig.showLunar) {
  18 + dates = dates.map(dataInfo => {
  19 + const { year, month, date } = dataInfo
  20 + return {
  21 + ...dataInfo,
  22 + lunar: convertSolarLunar.solar2lunar(year, month, date)
  23 + }
  24 + })
  25 + selectedDates = selectedDates.map(dataInfo => {
  26 + const { year, month, date } = dataInfo
  27 + return {
  28 + ...dataInfo,
  29 + lunar: convertSolarLunar.solar2lunar(year, month, date)
  30 + }
  31 + })
  32 + }
  33 + return {
  34 + calendarData: {
  35 + ...calendarData,
  36 + dates: dates,
  37 + selectedDates: selectedDates
  38 + },
  39 + calendarConfig
  40 + }
  41 + },
  42 + methods() {
  43 + return {
  44 + convertSolarLunar: dateInfo => {
  45 + dateInfo = getDateRow2Dict(dateInfo)
  46 + if (!dateInfo) return dateInfo
  47 + const { year, month, date } = dateInfo
  48 + return convertSolarLunar.solar2lunar(year, month, date)
  49 + },
  50 + convertlLunar2Solar: (dateInfo, isLeapMonth) => {
  51 + dateInfo = getDateRow2Dict(dateInfo)
  52 + if (!dateInfo) return dateInfo
  53 + const { year, month, date } = dateInfo
  54 + return convertSolarLunar.lunar2solar(year, month, date, isLeapMonth)
  55 + }
  56 + }
  57 + }
  58 + }
  59 +}
... ...
component/v2/plugins/time-range.js 0 → 100644
... ... @@ -0,0 +1,309 @@
  1 +/**
  2 + * @Author: drfu*
  3 + * @Description: 时间区域选择
  4 + * @Date: 2020-10-08 21:22:09*
  5 + * @Last Modified by: drfu
  6 + * @Last Modified time: 2020-10-11 13:56:32
  7 + * */
  8 +
  9 +import { renderCalendar } from '../render'
  10 +import {
  11 + logger,
  12 + dateUtil,
  13 + getCalendarConfig,
  14 + getCalendarData
  15 +} from '../utils/index'
  16 +
  17 +function pusheNextMonthDateArea(
  18 + dateInfo = {},
  19 + startTimestamp,
  20 + endTimestamp,
  21 + selectedDates = []
  22 +) {
  23 + let tempOfSelectedDate = [...selectedDates]
  24 + const dates = dateUtil.calcDates(dateInfo.year, dateInfo.month)
  25 + let datesLen = dates.length
  26 + for (let i = 0; i < datesLen; i++) {
  27 + const date = dates[i]
  28 + const timeStamp = dateUtil.getTimeStamp(date)
  29 + if (timeStamp <= endTimestamp && timeStamp >= startTimestamp) {
  30 + tempOfSelectedDate.push({
  31 + ...date,
  32 + choosed: true
  33 + })
  34 + }
  35 + if (i === datesLen - 1 && timeStamp < endTimestamp) {
  36 + tempOfSelectedDate = pusheNextMonthDateArea(
  37 + dateUtil.getNextMonthInfo(date),
  38 + startTimestamp,
  39 + endTimestamp,
  40 + tempOfSelectedDate
  41 + )
  42 + }
  43 + }
  44 + return tempOfSelectedDate
  45 +}
  46 +function pushPrevMonthDateArea(
  47 + dateInfo = {},
  48 + startTimestamp,
  49 + endTimestamp,
  50 + selectedDates = []
  51 +) {
  52 + let tempOfSelectedDate = [...selectedDates]
  53 + const dates = dateUtil.sortDatesByTime(
  54 + dateUtil.calcDates(dateInfo.year, dateInfo.month),
  55 + 'desc'
  56 + )
  57 + let datesLen = dates.length
  58 + let firstDate = dateUtil.getTimeStamp(dates[0])
  59 + for (let i = 0; i < datesLen; i++) {
  60 + const date = dates[i]
  61 + const timeStamp = dateUtil.getTimeStamp(date)
  62 + if (timeStamp >= startTimestamp && timeStamp <= endTimestamp) {
  63 + tempOfSelectedDate.push({
  64 + ...date,
  65 + choosed: true
  66 + })
  67 + }
  68 + if (i === datesLen - 1 && firstDate > startTimestamp) {
  69 + tempOfSelectedDate = pushPrevMonthDateArea(
  70 + dateUtil.getPrevMonthInfo(date),
  71 + startTimestamp,
  72 + endTimestamp,
  73 + tempOfSelectedDate
  74 + )
  75 + }
  76 + }
  77 + return tempOfSelectedDate
  78 +}
  79 +/**
  80 + * 当设置日期区域非当前时保存其他月份的日期至已选日期数组
  81 + * @param {object} info
  82 + */
  83 +function calcDateWhenNotInOneMonth(info) {
  84 + const { firstDate, lastDate, startTimestamp, endTimestamp } = info
  85 + let { selectedDate } = info
  86 + if (dateUtil.getTimeStamp(firstDate) > startTimestamp) {
  87 + selectedDate = pushPrevMonthDateArea(
  88 + dateUtil.getPrevMonthInfo(firstDate),
  89 + startTimestamp,
  90 + endTimestamp,
  91 + selectedDate
  92 + )
  93 + }
  94 + if (dateUtil.getTimeStamp(lastDate) < endTimestamp) {
  95 + selectedDate = pusheNextMonthDateArea(
  96 + dateUtil.getNextMonthInfo(lastDate),
  97 + startTimestamp,
  98 + endTimestamp,
  99 + selectedDate
  100 + )
  101 + }
  102 + return [...selectedDate]
  103 +}
  104 +
  105 +/**
  106 + * 指定日期区域转时间戳
  107 + * @param {array} timearea 时间区域
  108 + */
  109 +export function convertTimeRangeToTimestamp(timearea = []) {
  110 + const start = timearea[0].split('-')
  111 + const end = timearea[1].split('-')
  112 + if (start.length !== 3 || end.length !== 3) {
  113 + logger.warn('enableArea() 参数格式为: ["2018-2-1", "2018-3-1"]')
  114 + return {}
  115 + }
  116 + const startTimestamp = dateUtil
  117 + .newDate(start[0], start[1], start[2])
  118 + .getTime()
  119 + const endTimestamp = dateUtil.newDate(end[0], end[1], end[2]).getTime()
  120 + return {
  121 + start,
  122 + end,
  123 + startTimestamp,
  124 + endTimestamp
  125 + }
  126 +}
  127 +
  128 +/**
  129 + * 校验时间区域是否合法
  130 + * @param {array} dateArea 时间区域
  131 + */
  132 +function validateTimeRange(dateArea) {
  133 + const {
  134 + start,
  135 + end,
  136 + startTimestamp,
  137 + endTimestamp
  138 + } = convertTimeRangeToTimestamp(dateArea)
  139 + if (!start || !end) return
  140 + const startMonthDays = dateUtil.getDatesCountOfMonth(start[0], start[1])
  141 + const endMonthDays = dateUtil.getDatesCountOfMonth(end[0], end[1])
  142 + if (start[2] > startMonthDays || start[2] < 1) {
  143 + logger.warn('enableArea() 开始日期错误,指定日期不在当前月份天数范围内')
  144 + return false
  145 + } else if (start[1] > 12 || start[1] < 1) {
  146 + logger.warn('enableArea() 开始日期错误,月份超出1-12月份')
  147 + return false
  148 + } else if (end[2] > endMonthDays || end[2] < 1) {
  149 + logger.warn('enableArea() 截止日期错误,指定日期不在当前月份天数范围内')
  150 + return false
  151 + } else if (end[1] > 12 || end[1] < 1) {
  152 + logger.warn('enableArea() 截止日期错误,月份超出1-12月份')
  153 + return false
  154 + } else if (startTimestamp > endTimestamp) {
  155 + logger.warn('enableArea()参数最小日期大于了最大日期')
  156 + return false
  157 + } else {
  158 + return true
  159 + }
  160 +}
  161 +
  162 +export default () => {
  163 + return {
  164 + name: 'timeRange',
  165 + beforeRender(calendarData = {}, calendarConfig = {}) {
  166 + const {
  167 + chooseAreaTimestamp = [],
  168 + dates = [],
  169 + selectedDates = []
  170 + } = calendarData
  171 + let __dates = dates
  172 + let __selectedDates = selectedDates
  173 + const [startDateTimestamp, endDateTimestamp] = chooseAreaTimestamp
  174 + if (chooseAreaTimestamp.length === 2) {
  175 + __selectedDates = []
  176 + __dates = dates.map(d => {
  177 + const date = { ...d }
  178 + const dateTimeStamp = dateUtil.getTimeStamp(date)
  179 + if (
  180 + dateTimeStamp >= startDateTimestamp &&
  181 + endDateTimestamp >= dateTimeStamp
  182 + ) {
  183 + date.choosed = true
  184 + __selectedDates.push(date)
  185 + } else {
  186 + date.choosed = false
  187 + __selectedDates = __selectedDates.filter(
  188 + item => dateUtil.getTimeStamp(item) !== dateTimeStamp
  189 + )
  190 + }
  191 + return date
  192 + })
  193 + const { year: startYear, month: startMonth } = dateUtil.formatTimestamp(
  194 + startDateTimestamp
  195 + )
  196 + const { year: endYear, month: endMonth } = dateUtil.formatTimestamp(
  197 + endDateTimestamp
  198 + )
  199 + if (startMonth !== endMonth || startYear !== endYear) {
  200 + __selectedDates = calcDateWhenNotInOneMonth({
  201 + firstDate: __dates[0],
  202 + lastDate: __dates[__dates.length - 1],
  203 + startTimestamp: startDateTimestamp,
  204 + endTimestamp: endDateTimestamp,
  205 + selectedDate: __selectedDates
  206 + })
  207 + }
  208 + }
  209 + return {
  210 + calendarData: {
  211 + ...calendarData,
  212 + dates: __dates,
  213 + selectedDates: dateUtil.sortDatesByTime(
  214 + dateUtil.uniqueArrayByDate(__selectedDates)
  215 + )
  216 + },
  217 + calendarConfig
  218 + }
  219 + },
  220 + onTapDate(tapedDate, calendarData = {}, calendarConfig = {}) {
  221 + if (!calendarConfig.chooseAreaMode) {
  222 + return {
  223 + calendarData,
  224 + calendarConfig
  225 + }
  226 + }
  227 + let {
  228 + tempChooseAreaTimestamp = [],
  229 + chooseAreaTimestamp: existChooseAreaTimestamp = [],
  230 + selectedDates = [],
  231 + dates = []
  232 + } = calendarData
  233 + const timestamp = dateUtil.getTimeStamp(tapedDate)
  234 + let __dates = [...dates]
  235 + let __selectedDates = [...selectedDates]
  236 + if (
  237 + tempChooseAreaTimestamp.length === 2 ||
  238 + existChooseAreaTimestamp.length === 2
  239 + ) {
  240 + tempChooseAreaTimestamp = [tapedDate]
  241 + __selectedDates = []
  242 + __dates.forEach(d => (d.choosed = false))
  243 + } else if (tempChooseAreaTimestamp.length === 1) {
  244 + const preChoosedDate = tempChooseAreaTimestamp[0]
  245 + const preTimestamp = dateUtil.getTimeStamp(preChoosedDate)
  246 + if (preTimestamp <= timestamp) {
  247 + tempChooseAreaTimestamp.push(tapedDate)
  248 + } else if (preTimestamp > timestamp) {
  249 + tempChooseAreaTimestamp.unshift(tapedDate)
  250 + }
  251 + } else {
  252 + tempChooseAreaTimestamp = [tapedDate]
  253 + }
  254 + let chooseAreaTimestamp = []
  255 + if (tempChooseAreaTimestamp.length === 2) {
  256 + const [startDate, endDate] = tempChooseAreaTimestamp
  257 + const startDateTimestamp = dateUtil.getTimeStamp(startDate)
  258 + const endDateTimestamp = dateUtil.getTimeStamp(endDate)
  259 + chooseAreaTimestamp = [startDateTimestamp, endDateTimestamp]
  260 + }
  261 + return {
  262 + calendarData: {
  263 + ...calendarData,
  264 + chooseAreaTimestamp,
  265 + tempChooseAreaTimestamp,
  266 + dates: __dates,
  267 + selectedDates: __selectedDates
  268 + },
  269 + calendarConfig: {
  270 + ...calendarConfig,
  271 + multi: true
  272 + }
  273 + }
  274 + },
  275 + methods(component) {
  276 + return {
  277 + /**
  278 + * 设置连续日期选择区域
  279 + * @param {array} dateArea 区域开始结束日期数组
  280 + */
  281 + chooseDateArea: (dateArea = []) => {
  282 + if (dateArea.length === 1) {
  283 + dateArea = dateArea.concat(dateArea)
  284 + }
  285 + if (dateArea.length !== 2) return
  286 + const isRight = validateTimeRange(dateArea)
  287 + if (!isRight) return
  288 + const config = getCalendarConfig(component) || {}
  289 + const { startTimestamp, endTimestamp } = convertTimeRangeToTimestamp(
  290 + dateArea
  291 + )
  292 + const existCalendarData = getCalendarData('calendar', component)
  293 + return renderCalendar.call(
  294 + component,
  295 + {
  296 + ...existCalendarData,
  297 + chooseAreaTimestamp: [startTimestamp, endTimestamp]
  298 + },
  299 + {
  300 + ...config,
  301 + multi: true,
  302 + chooseAreaMode: true
  303 + }
  304 + )
  305 + }
  306 + }
  307 + }
  308 + }
  309 +}
... ...
component/v2/plugins/todo.js 0 → 100644
... ... @@ -0,0 +1,135 @@
  1 +/**
  2 + * @Author: drfu*
  3 + * @Description: 代办事项
  4 + * @Date: 2020-10-08 21:22:09*
  5 + * @Last Modified by: drfu
  6 + * @Last Modified time: 2020-10-11 14:23:02
  7 + * */
  8 +
  9 +import { getCalendarData, dateUtil } from '../utils/index'
  10 +import { renderCalendar } from '../render'
  11 +
  12 +function updateDatePropertyOfTodoLabel(todos, dates, showLabelAlways) {
  13 + const datesInfo = [...dates]
  14 + for (let todo of todos) {
  15 + let targetIdx = datesInfo.findIndex(
  16 + item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(todo)
  17 + )
  18 + let target = datesInfo[targetIdx]
  19 + if (!target) continue
  20 + if (showLabelAlways) {
  21 + target.showTodoLabel = true
  22 + } else {
  23 + target.showTodoLabel = !target.choosed
  24 + }
  25 + if (target.showTodoLabel) {
  26 + target.todoText = todo.todoText
  27 + }
  28 + target.color = todo.color
  29 + }
  30 + return datesInfo
  31 +}
  32 +
  33 +export default () => {
  34 + return {
  35 + name: 'todo',
  36 + beforeRender(calendarData = {}, calendarConfig = {}, component) {
  37 + const { todos = [], dates = [], showLabelAlways } = calendarData
  38 + const dateWithTodoInfo = updateDatePropertyOfTodoLabel(
  39 + todos,
  40 + dates,
  41 + showLabelAlways
  42 + )
  43 + return {
  44 + calendarData: {
  45 + ...calendarData,
  46 + dates: dateWithTodoInfo
  47 + },
  48 + calendarConfig
  49 + }
  50 + },
  51 + methods(component) {
  52 + return {
  53 + setTodos: (options = {}) => {
  54 + const calendar = getCalendarData('calendar', component)
  55 + if (!calendar || !calendar.dates) {
  56 + return Promise.reject('请等待日历初始化完成后再调用该方法')
  57 + }
  58 + const {
  59 + circle,
  60 + dotColor = '',
  61 + pos = 'bottom',
  62 + showLabelAlways,
  63 + dates: todoDates = []
  64 + } = options
  65 + const { todos = [] } = calendar
  66 + const tranformStr2NumOfTodo = todoDates.map(date =>
  67 + dateUtil.tranformStr2NumOfDate(date)
  68 + )
  69 + const calendarData = {
  70 + dates: calendar.dates,
  71 + todos: dateUtil.uniqueArrayByDate(
  72 + todos.concat(tranformStr2NumOfTodo)
  73 + )
  74 + }
  75 + if (!circle) {
  76 + calendarData.todoLabelPos = pos
  77 + calendarData.todoLabelColor = dotColor
  78 + }
  79 + calendarData.todoLabelCircle = circle || false
  80 + calendarData.showLabelAlways = showLabelAlways || false
  81 + const existCalendarData = getCalendarData('calendar', component)
  82 + return renderCalendar.call(component, {
  83 + ...existCalendarData,
  84 + ...calendarData
  85 + })
  86 + },
  87 + deleteTodos(todos = []) {
  88 + if (!(todos instanceof Array) || !todos.length)
  89 + return Promise.reject('deleteTodos()应为入参为非空数组')
  90 + const existCalendarData = getCalendarData('calendar', component)
  91 + const allTodos = existCalendarData.todos || []
  92 + const toDeleteTodos = todos.map(item => dateUtil.toTimeStr(item))
  93 + const remainTodos = allTodos.filter(
  94 + item => !toDeleteTodos.includes(dateUtil.toTimeStr(item))
  95 + )
  96 + const { dates, curYear, curMonth } = existCalendarData
  97 + const _dates = [...dates]
  98 + const currentMonthTodos = dateUtil.filterDatesByYM(
  99 + {
  100 + year: curYear,
  101 + month: curMonth
  102 + },
  103 + remainTodos
  104 + )
  105 + _dates.forEach(item => {
  106 + item.showTodoLabel = false
  107 + })
  108 + currentMonthTodos.forEach(item => {
  109 + _dates[item.date - 1].showTodoLabel = !_dates[item.date - 1].choosed
  110 + })
  111 + return renderCalendar.call(component, {
  112 + ...existCalendarData,
  113 + dates: _dates,
  114 + todos: remainTodos
  115 + })
  116 + },
  117 + clearTodos() {
  118 + const existCalendarData = getCalendarData('calendar', component)
  119 + const _dates = [...existCalendarData.dates]
  120 + _dates.forEach(item => {
  121 + item.showTodoLabel = false
  122 + })
  123 + return renderCalendar.call(component, {
  124 + ...existCalendarData,
  125 + dates: _dates,
  126 + todos: []
  127 + })
  128 + },
  129 + getTodos() {
  130 + return getCalendarData('calendar.todos', component) || []
  131 + }
  132 + }
  133 + }
  134 + }
  135 +}
... ...
component/v2/plugins/week.js 0 → 100644
... ... @@ -0,0 +1,432 @@
  1 +/**
  2 + * @Author: drfu*
  3 + * @Description: 周视图
  4 + * @Date: 2020-10-08 21:22:09*
  5 + * @Last Modified by: drfu
  6 + * @Last Modified time: 2020-10-12 14:39:45
  7 + * */
  8 +
  9 +import { renderCalendar } from '../render'
  10 +import {
  11 + getCalendarConfig,
  12 + getCalendarData,
  13 + logger,
  14 + dateUtil
  15 +} from '../utils/index'
  16 +import { calcJumpData } from '../core'
  17 +
  18 +/**
  19 + * 当月第一周所有日期
  20 + */
  21 +function firstWeekInMonth(
  22 + target = {},
  23 + calendarDates = [],
  24 + calendarConfig = {}
  25 +) {
  26 + const { firstDayOfWeek } = calendarConfig
  27 + const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon'
  28 + const { year, month } = target
  29 + let firstDay = dateUtil.getDayOfWeek(year, month, 1)
  30 + if (firstDayOfWeekIsMon && firstDay === 0) {
  31 + firstDay = 7
  32 + }
  33 + const [, end] = [0, 7 - firstDay]
  34 + return calendarDates.slice(0, firstDayOfWeekIsMon ? end + 1 : end)
  35 +}
  36 +
  37 +/**
  38 + * 当月最后一周所有日期
  39 + */
  40 +function lastWeekInMonth(target = {}, calendarDates = [], calendarConfig = {}) {
  41 + const { firstDayOfWeek } = calendarConfig
  42 + const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon'
  43 + const { year, month } = target
  44 + const lastDay = dateUtil.getDatesCountOfMonth(year, month)
  45 + let lastDayWeek = dateUtil.getDayOfWeek(year, month, lastDay)
  46 + if (firstDayOfWeekIsMon && lastDayWeek === 0) {
  47 + lastDayWeek = 7
  48 + }
  49 + const [start, end] = [lastDay - lastDayWeek, lastDay]
  50 + return calendarDates.slice(firstDayOfWeekIsMon ? start : start - 1, end)
  51 +}
  52 +
  53 +/**
  54 + * 判断目标日期是否在某些指定日历内
  55 + */
  56 +function dateIsInDatesRange(target, dates) {
  57 + if (!target || !dates || !dates.length) return false
  58 + const targetDateStr = dateUtil.toTimeStr(target)
  59 + let rst = false
  60 + for (let date of dates) {
  61 + const dateStr = dateUtil.toTimeStr(date)
  62 + if (dateStr === targetDateStr) {
  63 + rst = true
  64 + return rst
  65 + }
  66 + rst = false
  67 + }
  68 + return rst
  69 +}
  70 +
  71 +function getDatesWhenTargetInFirstWeek(target, firstWeekDates) {
  72 + const { year, month } = target
  73 + const prevMonthInfo = dateUtil.getPrevMonthInfo({ year, month })
  74 + let lastMonthDatesCount = dateUtil.getDatesCountOfMonth(
  75 + prevMonthInfo.year,
  76 + prevMonthInfo.month
  77 + )
  78 + let dates = firstWeekDates
  79 + let firstWeekCount = firstWeekDates.length
  80 + for (let i = 0; i < 7 - firstWeekCount; i++) {
  81 + const week = dateUtil.getDayOfWeek(+year, +month, lastMonthDatesCount)
  82 + dates.unshift({
  83 + year: prevMonthInfo.year,
  84 + month: prevMonthInfo.month,
  85 + date: lastMonthDatesCount,
  86 + week
  87 + })
  88 + lastMonthDatesCount -= 1
  89 + }
  90 + return dates
  91 +}
  92 +
  93 +function getDatesWhenTargetInLastWeek(target, lastWeekDates) {
  94 + const { year, month } = target
  95 + const prevMonthInfo = dateUtil.getNextMonthInfo({ year, month })
  96 + let dates = lastWeekDates
  97 + let lastWeekCount = lastWeekDates.length
  98 + for (let i = 0; i < 7 - lastWeekCount; i++) {
  99 + const week = dateUtil.getDayOfWeek(+year, +month, i + 1)
  100 + dates.push({
  101 + year: prevMonthInfo.year,
  102 + month: prevMonthInfo.month,
  103 + date: i + 1,
  104 + week
  105 + })
  106 + }
  107 + return dates
  108 +}
  109 +
  110 +function getDates(target, calendarDates = [], calendarConfig = {}) {
  111 + const { year, month, date } = target
  112 + const targetDay = dateUtil.getDayOfWeek(year, month, date)
  113 + const { firstDayOfWeek } = calendarConfig
  114 + const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon'
  115 + if (firstDayOfWeekIsMon) {
  116 + const startIdx = date - (targetDay || 7)
  117 + return calendarDates.splice(startIdx, 7)
  118 + } else {
  119 + const startIdx = date - targetDay - 1
  120 + return calendarDates.splice(startIdx, 7)
  121 + }
  122 +}
  123 +
  124 +function getTargetWeekDates(target, calendarConfig) {
  125 + if (!target) return
  126 + const { year, month } = target
  127 + const calendarDates = dateUtil.calcDates(year, month)
  128 + const firstWeekDates = firstWeekInMonth(target, calendarDates, calendarConfig)
  129 + const lastWeekDates = lastWeekInMonth(target, calendarDates, calendarConfig)
  130 + if (dateIsInDatesRange(target, firstWeekDates)) {
  131 + return getDatesWhenTargetInFirstWeek(target, firstWeekDates)
  132 + } else if (dateIsInDatesRange(target, lastWeekDates)) {
  133 + return getDatesWhenTargetInLastWeek(target, lastWeekDates)
  134 + } else {
  135 + return getDates(target, calendarDates, calendarConfig)
  136 + }
  137 +}
  138 +
  139 +/**
  140 + * 计算周视图下当前这一周最后一天
  141 + */
  142 +function calculateLastDateOfCurrentWeek(calendarData = {}) {
  143 + const { dates = [] } = calendarData
  144 + return dates[dates.length - 1]
  145 +}
  146 +/**
  147 + * 计算周视图下当前这一周第一天
  148 + */
  149 +function calculateFirstDateOfCurrentWeek(calendarData = {}) {
  150 + const { dates } = calendarData
  151 + return dates[0]
  152 +}
  153 +
  154 +/**
  155 + * 计算下一周的日期
  156 + */
  157 +function calculateNextWeekDates(calendarData = {}) {
  158 + let { curYear, curMonth } = calendarData
  159 + let calendarDates = []
  160 + let lastDateInThisWeek = calculateLastDateOfCurrentWeek(calendarData)
  161 + const { year: LYear, month: LMonth } = lastDateInThisWeek
  162 + if (curYear !== LYear || curMonth !== LMonth) {
  163 + calendarDates = dateUtil.calcDates(LYear, LMonth)
  164 + curYear = LYear
  165 + curMonth = LMonth
  166 + } else {
  167 + calendarDates = dateUtil.calcDates(curYear, curMonth)
  168 + }
  169 + const lastDateInThisMonth = dateUtil.getDatesCountOfMonth(curYear, curMonth)
  170 + const count = lastDateInThisMonth - lastDateInThisWeek.date
  171 + const lastDateIdx = calendarDates.findIndex(
  172 + date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(lastDateInThisWeek)
  173 + )
  174 + const startIdx = lastDateIdx + 1
  175 + if (count >= 7) {
  176 + return {
  177 + dates: calendarDates.splice(startIdx, 7),
  178 + year: curYear,
  179 + month: curMonth
  180 + }
  181 + } else {
  182 + const nextMonth = dateUtil.getNextMonthInfo({
  183 + year: curYear,
  184 + month: curMonth
  185 + })
  186 + const { year, month } = nextMonth || {}
  187 + const calendarDatesOfNextMonth = dateUtil.calcDates(year, month)
  188 + const remainDatesOfThisMonth = calendarDates.splice(startIdx)
  189 + const patchDatesOfNextMonth = calendarDatesOfNextMonth.splice(
  190 + 0,
  191 + 7 - remainDatesOfThisMonth.length
  192 + )
  193 + return {
  194 + dates: [...remainDatesOfThisMonth, ...patchDatesOfNextMonth],
  195 + ...nextMonth
  196 + }
  197 + }
  198 +}
  199 +
  200 +/**
  201 + * 计算上一周的日期
  202 + */
  203 +function calculatePrevWeekDates(calendarData = {}) {
  204 + let { curYear, curMonth } = calendarData
  205 + let firstDateInThisWeek = calculateFirstDateOfCurrentWeek(calendarData)
  206 + let calendarDates = []
  207 + const { year: FYear, month: FMonth } = firstDateInThisWeek
  208 + if (curYear !== FYear || curMonth !== FMonth) {
  209 + calendarDates = dateUtil.calcDates(FYear, FMonth)
  210 + curYear = FYear
  211 + curMonth = FMonth
  212 + } else {
  213 + calendarDates = dateUtil.calcDates(curYear, curMonth)
  214 + }
  215 + const firstDateIdx = calendarDates.findIndex(
  216 + date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(firstDateInThisWeek)
  217 + )
  218 + if (firstDateIdx - 7 >= 0) {
  219 + const startIdx = firstDateIdx - 7
  220 + return {
  221 + dates: calendarDates.splice(startIdx, 7),
  222 + year: curYear,
  223 + month: curMonth
  224 + }
  225 + } else {
  226 + const prevMonth = dateUtil.getPrevMonthInfo({
  227 + year: curYear,
  228 + month: curMonth
  229 + })
  230 + const { year, month } = prevMonth || {}
  231 + const calendarDatesOfPrevMonth = dateUtil.calcDates(year, month)
  232 + const remainDatesOfThisMonth = calendarDates.splice(
  233 + 0,
  234 + firstDateInThisWeek.date - 1
  235 + )
  236 + const patchDatesOfPrevMonth = calendarDatesOfPrevMonth.splice(
  237 + -(7 - remainDatesOfThisMonth.length)
  238 + )
  239 + return {
  240 + dates: [...patchDatesOfPrevMonth, ...remainDatesOfThisMonth],
  241 + ...prevMonth
  242 + }
  243 + }
  244 +}
  245 +
  246 +export default () => {
  247 + return {
  248 + name: 'week',
  249 + beforeRender(calendarData = {}, calendarConfig = {}, component) {
  250 + const { initializedWeekMode, selectedDates } = calendarData
  251 + if (calendarConfig.weekMode && !initializedWeekMode) {
  252 + const { defaultDate } = calendarConfig
  253 + const target =
  254 + (selectedDates && selectedDates[0]) ||
  255 + (defaultDate && dateUtil.transformDateRow2Dict(defaultDate)) ||
  256 + dateUtil.todayFMD()
  257 + const waitRenderData = this.methods(
  258 + component
  259 + ).__calcDatesWhenSwitchView('week', target)
  260 + const { data, config } = waitRenderData || {}
  261 + const setSelectDates = this.methods(
  262 + component
  263 + ).__selectTargetDateWhenJump(target, data.dates, config)
  264 + return {
  265 + calendarData: {
  266 + ...data,
  267 + ...setSelectDates,
  268 + weeksCh: dateUtil.getWeekHeader(calendarConfig.firstDayOfWeek),
  269 + initializedWeekMode: true
  270 + },
  271 + calendarConfig
  272 + }
  273 + }
  274 + return {
  275 + calendarData,
  276 + calendarConfig
  277 + }
  278 + },
  279 + onSwitchCalendar(target = {}, calendarData = {}, component) {
  280 + const { direction } = target
  281 + const { curYear, curMonth } = calendarData
  282 + const calendarConfig = getCalendarConfig(component)
  283 + let waitRenderData = {}
  284 + if (calendarConfig.weekMode) {
  285 + if (direction === 'left') {
  286 + waitRenderData = calculateNextWeekDates(calendarData)
  287 + } else {
  288 + waitRenderData = calculatePrevWeekDates(calendarData)
  289 + }
  290 + const { dates, year, month } = waitRenderData
  291 + return {
  292 + ...calendarData,
  293 + dates,
  294 + curYear: year || curYear,
  295 + curMonth: month || curMonth
  296 + }
  297 + }
  298 + return calendarData
  299 + },
  300 + methods(component) {
  301 + return {
  302 + __selectTargetDateWhenJump: (target = {}, dates = [], config = {}) => {
  303 + let selectedDate = target
  304 + const weekDates = dates.map((date, idx) => {
  305 + const tmp = { ...date }
  306 + tmp.id = idx
  307 + const isTarget =
  308 + dateUtil.toTimeStr(target) === dateUtil.toTimeStr(tmp)
  309 + if (isTarget && !target.choosed && config.autoChoosedWhenJump) {
  310 + tmp.choosed = true
  311 + selectedDate = tmp
  312 + }
  313 + return tmp
  314 + })
  315 + return {
  316 + dates: weekDates,
  317 + selectedDates: [selectedDate]
  318 + }
  319 + },
  320 + __calcDatesForWeekMode(target, config = {}, calendarData = {}) {
  321 + const { year, month } = target || {}
  322 + const weekDates = getTargetWeekDates(target, config)
  323 + weekDates.forEach((date, idx) => (date.id = idx))
  324 + return {
  325 + data: {
  326 + ...calendarData,
  327 + prevMonthGrids: null,
  328 + nextMonthGrids: null,
  329 + dates: weekDates,
  330 + curYear: year,
  331 + curMonth: month
  332 + },
  333 + config: {
  334 + ...config,
  335 + weekMode: true
  336 + }
  337 + }
  338 + },
  339 + __calcDatesForMonthMode(target, config = {}, calendarData = {}) {
  340 + const { year, month } = target || {}
  341 + const waitRenderData = calcJumpData({
  342 + dateInfo: target,
  343 + config
  344 + })
  345 + return {
  346 + data: {
  347 + ...calendarData,
  348 + ...waitRenderData,
  349 + curYear: year,
  350 + curMonth: month
  351 + },
  352 + config: {
  353 + ...config,
  354 + weekMode: false
  355 + }
  356 + }
  357 + },
  358 + /**
  359 + * 周、月视图切换
  360 + * @param {string} view 视图 [week, month]
  361 + * @param {object} target
  362 + */
  363 + __calcDatesWhenSwitchView: (view, target) => {
  364 + const calendarConfig = getCalendarConfig(component)
  365 + if (calendarConfig.multi)
  366 + return logger.warn('多选模式不能切换周月视图')
  367 + const existCalendarData = getCalendarData('calendar', component) || {}
  368 + const {
  369 + selectedDates = [],
  370 + dates = [],
  371 + curYear,
  372 + curMonth
  373 + } = existCalendarData
  374 + const currentMonthSelected = selectedDates.filter(
  375 + item => curYear === +item.year || curMonth === +item.month
  376 + )
  377 + let jumpTarget = {}
  378 + if (target) {
  379 + jumpTarget = target
  380 + } else {
  381 + if (currentMonthSelected.length) {
  382 + jumpTarget = currentMonthSelected.pop()
  383 + } else {
  384 + jumpTarget = dates[0]
  385 + }
  386 + }
  387 + if (view === 'week') {
  388 + return this.methods(component).__calcDatesForWeekMode(
  389 + jumpTarget,
  390 + calendarConfig,
  391 + existCalendarData
  392 + )
  393 + } else {
  394 + return this.methods(component).__calcDatesForMonthMode(
  395 + jumpTarget,
  396 + calendarConfig,
  397 + existCalendarData
  398 + )
  399 + }
  400 + },
  401 + weekModeJump: dateInfo => {
  402 + const target = dateInfo || dateUtil.todayFMD()
  403 + const existCalendarData = getCalendarData('calendar', component) || {}
  404 + const waitRenderData = this.methods(
  405 + component
  406 + ).__calcDatesWhenSwitchView('week', target)
  407 + const { data, config } = waitRenderData || {}
  408 + const setSelectDates = this.methods(
  409 + component
  410 + ).__selectTargetDateWhenJump(target, data.dates, config)
  411 + return renderCalendar.call(
  412 + component,
  413 + {
  414 + ...existCalendarData,
  415 + ...data,
  416 + ...setSelectDates
  417 + },
  418 + config
  419 + )
  420 + },
  421 + switchView: (view, target) => {
  422 + const waitRenderData = this.methods(
  423 + component
  424 + ).__calcDatesWhenSwitchView(view, target)
  425 + const { data, config } = waitRenderData || {}
  426 + if (!data) return logger.warn('当前状态不能切换为周视图')
  427 + return renderCalendar.call(component, data, config)
  428 + }
  429 + }
  430 + }
  431 + }
  432 +}
... ...
component/v2/render.js 0 → 100644
... ... @@ -0,0 +1,51 @@
  1 +import plugins from './plugins/index'
  2 +import { getCalendarConfig } from './utils/index'
  3 +
  4 +/**
  5 + * 渲染日历
  6 + */
  7 +export function renderCalendar(calendarData, calendarConfig) {
  8 + return new Promise(resolve => {
  9 + const Component = this
  10 + if (Component.firstRender === void 0) {
  11 + Component.firstRender = true
  12 + } else {
  13 + Component.firstRender = false
  14 + }
  15 + const exitData = Component.data.calendar || {}
  16 + for (let plugin of plugins.installed) {
  17 + const [, p] = plugin
  18 + if (typeof p.beforeRender === 'function') {
  19 + const {
  20 + calendarData: newData,
  21 + calendarConfig: newConfig
  22 + } = p.beforeRender(
  23 + { ...exitData, ...calendarData },
  24 + calendarConfig || getCalendarConfig(Component),
  25 + Component
  26 + )
  27 + calendarData = newData
  28 + calendarConfig = newConfig
  29 + }
  30 + }
  31 +
  32 + Component.setData(
  33 + {
  34 + config: calendarConfig,
  35 + calendar: calendarData
  36 + },
  37 + () => {
  38 + const rst = {
  39 + calendar: calendarData,
  40 + config: calendarConfig,
  41 + firstRender: Component.firstRender
  42 + }
  43 + resolve(rst)
  44 + if (Component.firstRender) {
  45 + Component.triggerEvent('afterCalendarRender', rst)
  46 + Component.firstRender = false
  47 + }
  48 + }
  49 + )
  50 + })
  51 +}
... ...
component/v2/theme/iconfont.wxss 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +@font-face {
  2 + font-family: 'iconfont';
  3 + 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');
  4 + font-weight: normal;
  5 + font-style: normal;
  6 +}
  7 +
  8 +.iconfont {
  9 + font-family: "iconfont" !important;
  10 + font-size: 16px;
  11 + font-style: normal;
  12 + -webkit-font-smoothing: antialiased;
  13 +}
  14 +
  15 +.icon-right::before {
  16 + content: "\e7eb";
  17 +}
  18 +
  19 +.icon-left::before {
  20 + content: "\e7ec";
  21 +}
  22 +
  23 +.icon-doubleleft::before {
  24 + content: "\e7ed";
  25 +}
  26 +
  27 +.icon-doubleright::before {
  28 + content: "\e7ee";
  29 +}
... ...
component/v2/theme/theme-default.wxss 0 → 100644
... ... @@ -0,0 +1,61 @@
  1 +
  2 +/* 日历主要颜色相关样式 */
  3 +
  4 +.default_color,
  5 +.default_weekend-color,
  6 +.default_handle-color,
  7 +.default_week-color {
  8 + color: #ff629a;
  9 +}
  10 +
  11 +.default_today {
  12 + color: #fff;
  13 + background-color: #874fb4;
  14 +}
  15 +
  16 +.default_choosed {
  17 + color: #fff;
  18 + background-color: #ff629a;
  19 +}
  20 +
  21 +.default_date-disable {
  22 + color: #c7c7c7;
  23 +}
  24 +
  25 +.default_choosed.default_date-disable {
  26 + color: #e2e2e2;
  27 + background-color: #c2afb6;
  28 +}
  29 +
  30 +.default_prev-month-date,
  31 +.default_next-month-date {
  32 + color: #e2e2e2;
  33 +}
  34 +
  35 +.default_normal-date {
  36 + color: #88d2ac;
  37 +}
  38 +
  39 +.default_todo-circle {
  40 + border-color: #88d2ac;
  41 +}
  42 +
  43 +.default_todo-dot {
  44 + background-color: #e54d42;
  45 +}
  46 +
  47 +.default_date-desc {
  48 + color: #c2c2c2;
  49 +}
  50 +
  51 +.default_date-desc-lunar {
  52 + color: #e54d42;
  53 +}
  54 +
  55 +.default_date-desc-disable {
  56 + color: #e2e2e2;
  57 +}
  58 +
  59 +.default_festival {
  60 + color: #c2c2c2;
  61 +}
... ...
component/v2/theme/theme-elegant.wxss 0 → 100644
... ... @@ -0,0 +1,58 @@
  1 +.elegant_color,
  2 +.elegant_weekend-color,
  3 +.elegant_handle-color,
  4 +.elegant_week-color {
  5 + color: #333;
  6 +}
  7 +
  8 +.elegant_today {
  9 + color: #000;
  10 + background-color: #e1e7f5;
  11 +}
  12 +
  13 +.elegant_choosed {
  14 + color: #000;
  15 + background-color: #e2e2e2;
  16 +}
  17 +
  18 +.elegant_date-disable {
  19 + color: #c7c7c7;
  20 +}
  21 +
  22 +.elegant_choosed.elegant_date-disable {
  23 + color: #999;
  24 + background-color: #ebebeb;
  25 +}
  26 +
  27 +.elegant_prev-month-date,
  28 +.elegant_next-month-date {
  29 + color: #e2e2e2;
  30 +}
  31 +
  32 +.elegant_normal-date {
  33 + color: #777;
  34 +}
  35 +
  36 +.elegant_todo-circle {
  37 + border-color: #161035;
  38 +}
  39 +
  40 +.elegant_todo-dot {
  41 + background-color: #161035;
  42 +}
  43 +
  44 +.elegant_date-desc {
  45 + color: #c2c2c2;
  46 +}
  47 +
  48 +.elegant_date-desc-lunar {
  49 + color: #161035;
  50 +}
  51 +
  52 +.elegant_date-desc-disable {
  53 + color: #e2e2e2;
  54 +}
  55 +
  56 +.elegant_festival {
  57 + color: #c2c2c2;
  58 +}
... ...
component/v2/utils/index.js 0 → 100644
... ... @@ -0,0 +1,284 @@
  1 +import Logger from './logger'
  2 +import WxData from './wxData'
  3 +
  4 +let systemInfo
  5 +export function getSystemInfo() {
  6 + if (systemInfo) return systemInfo
  7 + systemInfo = wx.getSystemInfoSync()
  8 + return systemInfo
  9 +}
  10 +
  11 +export function isIos() {
  12 + const sys = getSystemInfo()
  13 + return /iphone|ios/i.test(sys.platform)
  14 +}
  15 +
  16 +class Gesture {
  17 + /**
  18 + * 左滑
  19 + * @param {object} e 事件对象
  20 + * @returns {boolean} 布尔值
  21 + */
  22 + isLeft(gesture = {}, touche = {}) {
  23 + const { startX, startY } = gesture
  24 + const deltaX = touche.clientX - startX
  25 + const deltaY = touche.clientY - startY
  26 + if (deltaX < -60 && deltaY < 20 && deltaY > -20) {
  27 + return true
  28 + } else {
  29 + return false
  30 + }
  31 + }
  32 + /**
  33 + * 右滑
  34 + * @param {object} e 事件对象
  35 + * @returns {boolean} 布尔值
  36 + */
  37 + isRight(gesture = {}, touche = {}) {
  38 + const { startX, startY } = gesture
  39 + const deltaX = touche.clientX - startX
  40 + const deltaY = touche.clientY - startY
  41 +
  42 + if (deltaX > 60 && deltaY < 20 && deltaY > -20) {
  43 + return true
  44 + } else {
  45 + return false
  46 + }
  47 + }
  48 +}
  49 +
  50 +class DateUtil {
  51 + newDate(year, month, date) {
  52 + let cur = `${+year}-${+month}-${+date}`
  53 + if (isIos()) {
  54 + cur = `${+year}/${+month}/${+date}`
  55 + }
  56 + return new Date(cur)
  57 + }
  58 + /**
  59 + * 计算指定日期时间戳
  60 + * @param {object} date
  61 + */
  62 + getTimeStamp(dateInfo) {
  63 + if (typeof dateInfo === 'string') {
  64 + dateInfo = this.transformDateRow2Dict(dateInfo)
  65 + }
  66 + if (Object.prototype.toString.call(dateInfo) !== '[object Object]') return
  67 + const dateUtil = new DateUtil()
  68 + return dateUtil
  69 + .newDate(dateInfo.year, dateInfo.month, dateInfo.date)
  70 + .getTime()
  71 + }
  72 + /**
  73 + * 计算指定月份共多少天
  74 + * @param {number} year 年份
  75 + * @param {number} month 月份
  76 + */
  77 + getDatesCountOfMonth(year, month) {
  78 + return new Date(Date.UTC(year, month, 0)).getUTCDate()
  79 + }
  80 + /**
  81 + * 计算指定月份第一天星期几
  82 + * @param {number} year 年份
  83 + * @param {number} month 月份
  84 + */
  85 + firstDayOfWeek(year, month) {
  86 + return new Date(Date.UTC(year, month - 1, 1)).getUTCDay()
  87 + }
  88 + /**
  89 + * 计算指定日期星期几
  90 + * @param {number} year 年份
  91 + * @param {number} month 月份
  92 + * @param {number} date 日期
  93 + */
  94 + getDayOfWeek(year, month, date) {
  95 + return new Date(Date.UTC(year, month - 1, date)).getUTCDay()
  96 + }
  97 + formatTimestamp(timestamp) {
  98 + const date = new Date(timestamp)
  99 + return {
  100 + year: date.getFullYear(),
  101 + month: date.getMonth() + 1,
  102 + date: date.getDate()
  103 + }
  104 + }
  105 + todayTimestamp() {
  106 + return new Date().getTime()
  107 + }
  108 + todayFMD() {
  109 + const timestamp = this.todayTimestamp()
  110 + return this.formatTimestamp(timestamp)
  111 + }
  112 + toTimeStr(dateInfo = {}) {
  113 + return `${+dateInfo.year}-${+dateInfo.month}-${+dateInfo.date}`
  114 + }
  115 + transformDateRow2Dict(dateStr) {
  116 + if (typeof dateStr === 'string' && dateStr.includes('-')) {
  117 + const [year, month, date] = dateStr.split('-')
  118 + return this.tranformStr2NumOfDate({
  119 + year,
  120 + month,
  121 + date
  122 + })
  123 + }
  124 + return {}
  125 + }
  126 + tranformStr2NumOfDate(date = {}) {
  127 + const target = { ...date }
  128 + // 可能传入字符串
  129 + target.year = +target.year
  130 + target.month = +target.month
  131 + target.date = +target.date
  132 + return target
  133 + }
  134 + sortDatesByTime(dates = [], sortType) {
  135 + return dates.sort((a, b) => {
  136 + const at = this.getTimeStamp(a)
  137 + const bt = this.getTimeStamp(b)
  138 + if (at < bt && sortType !== 'desc') {
  139 + return -1
  140 + } else {
  141 + return 1
  142 + }
  143 + })
  144 + }
  145 + getPrevMonthInfo(date = {}) {
  146 + const prevMonthInfo =
  147 + Number(date.month) > 1
  148 + ? {
  149 + year: +date.year,
  150 + month: Number(date.month) - 1
  151 + }
  152 + : {
  153 + year: Number(date.year) - 1,
  154 + month: 12
  155 + }
  156 + return prevMonthInfo
  157 + }
  158 + getNextMonthInfo(date = {}) {
  159 + const nextMonthInfo =
  160 + Number(date.month) < 12
  161 + ? {
  162 + year: +date.year,
  163 + month: Number(date.month) + 1
  164 + }
  165 + : {
  166 + year: Number(date.year) + 1,
  167 + month: 1
  168 + }
  169 + return nextMonthInfo
  170 + }
  171 + getPrevYearInfo(date = {}) {
  172 + return {
  173 + year: Number(date.year) - 1,
  174 + month: +date.month
  175 + }
  176 + }
  177 + getNextYearInfo(date = {}) {
  178 + return {
  179 + year: Number(date.year) + 1,
  180 + month: +date.month
  181 + }
  182 + }
  183 + findDateIndexInArray(target, dates) {
  184 + return dates.findIndex(
  185 + item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(target)
  186 + )
  187 + }
  188 + calcDates(year, month) {
  189 + const datesCount = this.getDatesCountOfMonth(year, month)
  190 + const dates = []
  191 + const today = dateUtil.todayFMD()
  192 + for (let i = 1; i <= datesCount; i++) {
  193 + const week = dateUtil.getDayOfWeek(+year, +month, i)
  194 + const date = {
  195 + year: +year,
  196 + id: i - 1,
  197 + month: +month,
  198 + date: i,
  199 + week,
  200 + isToday:
  201 + +today.year === +year && +today.month === +month && i === +today.date
  202 + }
  203 + dates.push(date)
  204 + }
  205 + return dates
  206 + }
  207 + /**
  208 + * 日期数组根据日期去重
  209 + * @param {array} array 数组
  210 + */
  211 + uniqueArrayByDate(array = []) {
  212 + let uniqueObject = {}
  213 + let uniqueArray = []
  214 + array.forEach(item => {
  215 + uniqueObject[dateUtil.toTimeStr(item)] = item
  216 + })
  217 + for (let i in uniqueObject) {
  218 + uniqueArray.push(uniqueObject[i])
  219 + }
  220 + return uniqueArray
  221 + }
  222 + /**
  223 + * 筛选指定年月日期
  224 + * @param {object} target 指定年月
  225 + * @param {array} dates 待筛选日期
  226 + */
  227 + filterDatesByYM(target, dates) {
  228 + if (target) {
  229 + const { year, month } = target
  230 + const _dates = dates.filter(
  231 + item => +item.year === +year && +item.month === +month
  232 + )
  233 + return _dates
  234 + }
  235 + return dates
  236 + }
  237 + getWeekHeader(firstDayOfWeek) {
  238 + let weeksCh = ['日', '一', '二', '三', '四', '五', '六']
  239 + if (firstDayOfWeek === 'Mon') {
  240 + weeksCh = ['一', '二', '三', '四', '五', '六', '日']
  241 + }
  242 + return weeksCh
  243 + }
  244 +}
  245 +
  246 +/**
  247 + * 获取当前页面实例
  248 + */
  249 +export function getCurrentPage() {
  250 + const pages = getCurrentPages() || []
  251 + const last = pages.length - 1
  252 + return pages[last] || {}
  253 +}
  254 +
  255 +export function getComponentById(componentId) {
  256 + const logger = new Logger()
  257 + let page = getCurrentPage() || {}
  258 + if (page.selectComponent && typeof page.selectComponent === 'function') {
  259 + if (componentId) {
  260 + return page.selectComponent(componentId)
  261 + } else {
  262 + logger.warn('请传入组件ID')
  263 + }
  264 + } else {
  265 + logger.warn('该基础库暂不支持多个小程序日历组件')
  266 + }
  267 +}
  268 +
  269 +export const logger = new Logger()
  270 +export const calendarGesture = new Gesture()
  271 +export const dateUtil = new DateUtil()
  272 +export const getCalendarData = (key, component) =>
  273 + new WxData(component).getData(key)
  274 +export const setCalendarData = (data, component) =>
  275 + new WxData(component).setData(data)
  276 +export const getCalendarConfig = component =>
  277 + getCalendarData('config', component)
  278 +export const setCalendarConfig = (config, component) =>
  279 + setCalendarData(
  280 + {
  281 + config
  282 + },
  283 + component
  284 + )
... ...
component/v2/utils/logger.js 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +export default class Logger {
  2 + info(msg) {
  3 + console.log(
  4 + '%cInfo: %c' + msg,
  5 + 'color:#FF0080;font-weight:bold',
  6 + 'color: #FF509B'
  7 + )
  8 + }
  9 + warn(msg) {
  10 + console.log(
  11 + '%cWarn: %c' + msg,
  12 + 'color:#FF6600;font-weight:bold',
  13 + 'color: #FF9933'
  14 + )
  15 + }
  16 + tips(msg) {
  17 + console.log(
  18 + '%cTips: %c' + msg,
  19 + 'color:#00B200;font-weight:bold',
  20 + 'color: #00CC33'
  21 + )
  22 + }
  23 +}
... ...
component/v2/utils/wxData.js 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +class WxData {
  2 + constructor(component) {
  3 + this.Component = component
  4 + }
  5 + getData(key) {
  6 + const data = this.Component.data
  7 + if (!key) return data
  8 + if (key.includes('.')) {
  9 + let keys = key.split('.')
  10 + const tmp = keys.reduce((prev, next) => {
  11 + return prev[next]
  12 + }, data)
  13 + return tmp
  14 + } else {
  15 + return this.Component.data[key]
  16 + }
  17 + }
  18 + setData(data) {
  19 + return new Promise((resolve, reject) => {
  20 + if (!data) return reject('no data to set')
  21 + if (typeof data === 'object') {
  22 + this.Component.setData(data, () => {
  23 + resolve(data)
  24 + })
  25 + }
  26 + })
  27 + }
  28 +}
  29 +
  30 +export default WxData
... ...
config.js
1 1 //域名要在小程序的管理平台配置好,如果出现调用时报错,无效的域名,可在微信开发工具左边点项目-》配置信息-》看一下配置的域名【request合法域名】有没有刷新下来,没有的话就点下面的刷新
2 2  
3   -let host = 'https://proxy.shunzhi.net/'; //正式
  3 +// let host = 'https://proxy.shunzhi.net/'; //正式
  4 +let host = 'https://proxy.shunzhi.net/card'; //正式
4 5  
5 6 let file = 'https://wxsxh.myjxt.com:51314/file-center/'; //图片上传
6 7  
... ...
img/answer/1.png 0 → 100644

2.52 KB

img/answer/2.png 0 → 100644

2.9 KB

img/answer/3.png 0 → 100644

3.28 KB

img/answer/add.png 0 → 100644

12.7 KB

img/answer/back.png 0 → 100644

1.62 KB

img/answer/bj.png 0 → 100644

4.08 KB

img/answer/dkjl.png 0 → 100644

1.16 KB

img/answer/english.png 0 → 100644

5.09 KB

img/answer/math.png 0 → 100644

6.51 KB

img/answer/sp1.png 0 → 100644

4.32 KB

img/answer/succ.png 0 → 100644

62.6 KB

img/answer/tp1.png 0 → 100644

3.82 KB

img/answer/user.png 0 → 100644

2.99 KB

img/answer/yp1.png 0 → 100644

4.35 KB

img/answer/zdy.png 0 → 100644

2.95 KB

img/login_img.png 0 → 100644

84.5 KB

package-lock.json
1 1 {
2   - "name": "sxhClockIn",
3   - "version": "2.0.0",
4   - "lockfileVersion": 2,
  2 + "name": "sxh_clock_in",
  3 + "version": "1.0.0",
  4 + "lockfileVersion": 1,
5 5 "requires": true,
6   - "packages": {
7   - "": {
8   - "name": "sxhClockIn",
9   - "version": "2.0.0",
10   - "license": "ISC",
11   - "dependencies": {
12   - "@vant/weapp": "^1.10.5"
13   - }
14   - },
15   - "node_modules/@vant/weapp": {
16   - "version": "1.10.5",
17   - "resolved": "https://registry.npmmirror.com/@vant/weapp/-/weapp-1.10.5.tgz",
18   - "integrity": "sha512-bAHp9r0ZiRsOqPOLzQHI/ZvkAlXzol1/TFhM70MyghuxkzJTjcDUd8RIfLkCN3c1MCK/PfBGw2an8/afygftCg=="
19   - }
20   - },
21 6 "dependencies": {
22 7 "@vant/weapp": {
23 8 "version": "1.10.5",
24 9 "resolved": "https://registry.npmmirror.com/@vant/weapp/-/weapp-1.10.5.tgz",
25 10 "integrity": "sha512-bAHp9r0ZiRsOqPOLzQHI/ZvkAlXzol1/TFhM70MyghuxkzJTjcDUd8RIfLkCN3c1MCK/PfBGw2an8/afygftCg=="
  11 + },
  12 + "moment": {
  13 + "version": "2.29.4",
  14 + "resolved": "https://registry.npmmirror.com/moment/-/moment-2.29.4.tgz",
  15 + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
26 16 }
27 17 }
28 18 }
... ...
package.json
... ... @@ -4,7 +4,8 @@
4 4 "description": "计划管家",
5 5 "main": "app.js",
6 6 "dependencies": {
7   - "@vant/weapp": "^1.10.5"
  7 + "@vant/weapp": "^1.10.5",
  8 + "moment": "^2.29.4"
8 9 },
9 10 "scripts": {
10 11 "test": "echo \"Error: no test specified\" && exit 1"
... ...
pages/index/achievement/achievement.js
1 1 // pages/index/achievement/achievement.js
  2 +// 引入插件安装器
  3 +import plugin from '../../../component/v2/plugins/index'
  4 +import week from '../../../component/v2/plugins/week'
  5 +import todo from '../../../component/v2/plugins/todo'
  6 +import request from '../../../api/request.js'
  7 +import moment from 'moment';
  8 +plugin
  9 + .use(week)
  10 + .use(todo)
2 11 Page({
3 12  
4 13 /**
5 14 * 页面的初始数据
6 15 */
7 16 data: {
  17 + calendarConfig: {
  18 + theme: 'elegant',
  19 + weekMode: true, // 周视图模式
  20 + // highlightToday: true, // 是否高亮显示当天
  21 + hideHeader: true, // 隐藏日历头部操作栏
  22 + autoChoosedWhenJump: true, // 设置默认日期及跳转到指定日期后是否需要自动选中
  23 + defaultDate: moment(new Date().getTime()).format('YYYY-MM-DD'), // 默认选中指定某天,如需选中需配置 autoChoosedWhenJump: true
  24 + },
  25 + isDisplay: false,
  26 + calendar: {}, //日历
  27 + valueId: '', //任务ID
  28 + taskVo: {
  29 + allowRepairCard: 0,
  30 + hasData: 0,
  31 + statisticsUnit: "",
  32 + submitCondition: "",
  33 + id: 0,
  34 + releaseTime: "",
  35 + signTotal: 0,
  36 + taskCycle: 0,
  37 + taskDesc: "",
  38 + taskFrequency: "",
  39 + taskTitle: "",
  40 + weekDay: ""
  41 + },
  42 + resData: [], //成果数据
  43 + recordVo: {
  44 + commitTime: "",
  45 + files: [],
  46 + signDate: "",
  47 + taskRecordDesc: "",
  48 + taskStatisticsParam: ""
  49 + }, //成果数据当天
  50 + recordVoShow: false,
  51 + dayMoment: 0, //数据月份
  52 + },
  53 + /**
  54 + * 选择日期后执行的事件
  55 + */
  56 + afterTapDate(e) {
  57 + let date = e.detail.date
  58 + // let month = e.detail.month
  59 + // let year = e.detail.year
  60 + let recordVo = this.data.resData.eventDetails[date - 1].recordVo
  61 + if (recordVo != null) {
  62 + console.log('复制', recordVo)
  63 + this.setData({
  64 + recordVo: recordVo
  65 + })
  66 + this.setData({
  67 + recordVoShow: true
  68 + })
  69 + } else {
  70 + this.setData({
  71 + recordVoShow: false
  72 + })
  73 + }
  74 + },
  75 + //获取信息
  76 + getInfo(doday, isOne = 0) {
  77 + request({
  78 + url: `/wx/task/getSignRecord`,
  79 + method: 'get',
  80 + data: {
  81 + // wx.getStorageSync('userInfo_id'),
  82 + "taskId": this.data.valueId,
  83 + "signDate": doday
  84 + },
  85 + }).then(res => {
  86 + if (res.code == 0) {
  87 + this.setData({
  88 + resData: res.data
  89 + })
  90 + this.getV2(res.data)
  91 + if (isOne == 1) {
  92 + let e = {
  93 + detail: {
  94 + date: moment().date(),
  95 + month: moment().month() + 1,
  96 + year: moment().year()
  97 + }
  98 + }
  99 + this.afterTapDate(e)
  100 + }
  101 + } else {
  102 + wx.showToast({
  103 + title: res.msg,
  104 + icon: 'none'
  105 + })
  106 + }
  107 + })
  108 + },
  109 + //初始化日历
  110 + initialize() {
  111 + // 设置待办
  112 + this.setData({
  113 + 'calendar': this.selectComponent('#calendar').calendar
  114 + })
  115 + },
  116 + //显示日历
  117 + getV2(resData) {
  118 + this.setData({
  119 + taskVo: resData.taskVo
  120 + })
  121 + // const calendar = this.selectComponent('#calendar').calendar
  122 + this.data.calendar.setTodos({
  123 + // 待办点标记设置
  124 + pos: 'bottom', // 待办点标记位置 ['top', 'bottom']
  125 + dotColor: 'red', // 待办点标记颜色
  126 + circle: false, // 待办圆圈标记设置(如圆圈标记已签到日期),该设置与点标记设置互斥
  127 + showLabelAlways: true, // 点击时是否显示待办事项(圆点/文字),在 circle 为 true 及当日历配置 showLunar 为 true 时,此配置失效
  128 + dates: resData.eventDetails
  129 + })
8 130 },
9   -
10 131 /**
11 132 * 生命周期函数--监听页面加载
12 133 */
13 134 onLoad(options) {
14   -
  135 + this.setData({
  136 + valueId: options.valueId
  137 + })
15 138 },
16 139 // 统一返回
17 140 handleBack() {
18 141 wx.navigateBack()
19 142 },
20 143 /**
21   - * 用户点击右上角分享
  144 + * 生命周期函数--监听页面初次渲染完成
22 145 */
23   - onShareAppMessage() {
24   -
25   - }
  146 + onReady() {
  147 + this.initialize()
  148 + this.getInfo(moment(new Date().getTime()).format('YYYY-MM-DD'), 1)
  149 + },
26 150 })
27 151 \ No newline at end of file
... ...
pages/index/achievement/achievement.json
1 1 {
2 2 "usingComponents": {
3   - "van-icon": "@vant/weapp/icon/index"
  3 + "van-icon": "@vant/weapp/icon/index",
  4 + "calendar": "/component/v2/index",
  5 + "van-popup": "@vant/weapp/popup/index",
  6 + "van-field": "@vant/weapp/field/index",
  7 + "van-image": "@vant/weapp/image/index",
  8 + "van-button": "@vant/weapp/button/index"
4 9 },
5   - "navigationStyle": "custom"
  10 + "navigationBarTitleText": "我的成果"
6 11 }
7 12 \ No newline at end of file
... ...
pages/index/achievement/achievement.wxml
1 1 <!--pages/index/achievement/achievement.wxml-->
2 2 <view class="punch_detail">
3   - <!-- 顶部统一返回 -->
4   - <view class="navigation_back" bindtap="handleBack">
5   - <van-icon name="arrow-left" />
  3 + <calendar id="calendar" config="{{calendarConfig}}" bind:afterTapDate="afterTapDate"/>
  4 + <!-- <view class="btn" bindtap="getInfo">按钮</view> -->
  5 + <view class="line_grey"></view>
  6 + <view class="card">
  7 + <view class="card_title">{{taskVo.taskTitle}}</view>
  8 + <view class="card_flex">
  9 + <view class="flex_grey">已进行 {{taskVo.signTotal +' / ' +taskVo.taskCycle}} 天</view>
  10 + <view class="flex_grey">打卡频次 : {{taskVo.taskFrequency}}</view>
  11 + <view class="flex_grey">{{taskVo.allowRepairCard == 1 ?'允许补卡': '不允许补卡'}}</view>
  12 + </view>
  13 + <view class="card_context">{{taskVo.taskDesc}}</view>
  14 + <view class="grey_font">
  15 + <view>我发布与{{taskVo.weekDay}} {{taskVo.releaseTime}}</view>
  16 + <view class="grey_font_bottom"></view>
  17 + </view>
6 18 </view>
7   - <image class="temporary" src="/img/_check_in5.png" mode="widthFix" alt="" />
8 19  
  20 + <view class="grey_line"></view>
  21 + <view class="box" wx:if="{{recordVoShow}}">
  22 + <view class="box_title">打卡成果</view>
  23 + <view class="box_blue" wx:if="{{recordVo.hasData==1}}">本次打卡坚持了<span>{{recordVo.taskStatisticsParam}}{{taskVo.statisticsUnit}}</span></view>
  24 + <view class="box_grey">"{{recordVo.taskRecordDesc}}"</view>
  25 + <view class="box_pic">
  26 + <view class="box_img" wx:for="{{recordVo.files}}" wx:key="index" wx:for-item="value">
  27 + <van-image width="100%" height="26vw" fit="fill" src="{{value}}" />
  28 + </view>
  29 + </view>
  30 + </view>
9 31 </view>
10 32 \ No newline at end of file
... ...
pages/index/achievement/achievement.wxss
1 1 /* pages/index/achievement/achievement.wxss */
  2 +.btn {
  3 + width: 20vw;
  4 + height: 20vw;
  5 + background-color: aqua;
  6 + font-size: 5vw;
  7 +}
  8 +.line_grey {
  9 + width: 90vw;
  10 + height: 1px;
  11 + background-color: #999;
  12 + margin: 10px 5vw 20px;
  13 +}
  14 +.card {
  15 + width: 92vw;
  16 + margin-left: 4vw;
  17 +}
  18 +.card_title {
  19 + font-size: 18px;
  20 + color: #556191;
  21 + margin: 15px 0;
  22 +}
  23 +.card_flex {
  24 + display: flex;
  25 +}
  26 +.flex_grey {
  27 + padding: 7px 10px;
  28 + box-sizing: border-box;
  29 + margin: 0 5px 10px 0;
  30 + font-size: 13px;
  31 + background-color: #F4F4F4;
  32 + color: #666666;
  33 + border-radius: 3px;
  34 +}
  35 +.card_context {
  36 + font-size: 16px;
  37 + margin: 10px 0;
  38 +}
  39 +.grey_font {
  40 + font-size: 14px;
  41 + color: #999999;
  42 + margin: 20px 0;
  43 +}
  44 +.grey_font_bottom {
  45 + margin-top: 5px;
  46 +}
  47 +.btn_box {
  48 + display: flex;
  49 + justify-content: space-around;
  50 + position: fixed;
  51 + bottom: 50px;
  52 + width: 100vw;
  53 +}
  54 +.pop_title {
  55 + font-size: 18px;
  56 + font-weight: bold;
  57 + text-align: center;
  58 + margin: 20px 0;
  59 +}
  60 +.pop_flex {
  61 + display: flex;
  62 + justify-content: space-between;
  63 + align-items: center;
  64 + padding: 0 20px;
  65 + box-sizing: border-box;
  66 +}
  67 +.pop_cell {
  68 + width: 40vw;
  69 + display: flex;
  70 + align-items: center;
  71 +}
  72 +.pop_fz {
  73 + width: 70px;
  74 +}
  75 +.pop_btn {
  76 + position: absolute;
  77 + bottom: 30px;
  78 + width: 90vw;
  79 + margin: 0 5vw;
  80 +}
  81 +.pop_tip {
  82 + position: absolute;
  83 + bottom: 90px;
  84 + width: 90vw;
  85 + margin: 0 5vw;
  86 +}
  87 +.pop_pic {
  88 + width: 70px;
  89 + height: 30px;
  90 +}
  91 +.grey_line {
  92 + width: 90vw;
  93 + height: 1px;
  94 + margin: 20vw 5vw 10vw ;
  95 + background-color: #999;
  96 +}
  97 +.box {
  98 + padding: 0 5vw;
  99 + box-sizing: border-box;
  100 + margin-bottom: 20px;
  101 +}
  102 +.box_title {
  103 + font-size: 20px;
  104 + font-weight: bold;
  105 +}
  106 +.box_blue {
  107 + padding: 7px 10px;
  108 + box-sizing: border-box;
  109 + background-color: #EDF5FF;
  110 + color: #333333;
  111 + margin: 15px 0;
  112 + border-radius: 10px;
  113 +}
  114 +.box_blue span {
  115 + color: #3A86F5;
  116 +}
  117 +.box_grey {
  118 + padding: 18px 10px;
  119 + box-sizing: border-box;
  120 + background-color: #FBFBFB;
  121 + color: #666666 ;
  122 + margin: 15px 0;
  123 + border-radius: 10px;
  124 +}
  125 +.box_pic {
  126 + display: flex;
  127 + justify-content: space-between;
  128 + flex-wrap: wrap;
  129 +}
  130 +.box_img {
  131 + width: 26vw;
  132 + margin:0 0 10px;
  133 + border-radius: 10px;
  134 +}
2 135 \ No newline at end of file
... ...
pages/index/index.js
... ... @@ -4,63 +4,73 @@ import request from &#39;../../api/request.js&#39;
4 4  
5 5 Page({
6 6 data: {
7   - showAdd: false, //新建打卡
8   - tabindex: 1,
  7 + active: 1,
  8 + taskList: []
9 9 // bannerList: [], // 轮播图
10 10 },
11   - /**
12   - * 生命周期函数--监听页面加载
13   - */
14   - onLoad: function (options) {
15   - // this.getBannerList() //获取banner
16   - },
17   - onShow:function (options) {
18   - this.setData({
19   - showAdd:false
20   - })
21   - },
22   - // 排行榜
23   - handleRank(){
24   - wx.navigateTo({
25   - url: '/pages/index/rank/rank',
26   - })
27   - },
28   - handleTab1() {
29   - this.setData({
30   - tabindex: 1
31   - })
32   - },
33   - handleTab2() {
  11 + checkTabs(e) {
  12 + let index = e.currentTarget.dataset.index
34 13 this.setData({
35   - tabindex: 2
36   - })
  14 + active: index
  15 + }) //修改参数
37 16 },
38   - handleAdd() {
39   - this.setData({
40   - showAdd: true
  17 +
  18 + //打卡记录列表
  19 + getTaskList() {
  20 + request({
  21 + url: `/wx/task/cardTaskList`,
  22 + method: 'post',
  23 + data: {
  24 + "oneselfFlag": 1,
  25 + "page": 1,
  26 + "pageSize": 999,
  27 + "userId": wx.getStorageSync("userInfo_id")
  28 + },
  29 + }).then(res => {
  30 + if (res.code == 0) {
  31 + this.setData({
  32 + taskList: res.rows
  33 + })
  34 + } else {
  35 + wx.showToast({
  36 + title: res.msg,
  37 + icon: 'none',
  38 + duration: 1500
  39 + })
  40 + }
41 41 })
42 42 },
43   - closeAdd() {
44   - this.setData({
45   - showAdd: false
  43 +
  44 + //查看排行榜
  45 + toRank() {
  46 + wx.switchTab({
  47 + url: './rank/rank',
46 48 })
47 49 },
48   - // 打卡成果
49   - handleAchievement(){
  50 +
  51 + // 打卡成果
  52 + handleAchievement(e){
50 53 wx.navigateTo({
51   - url: '/pages/index/achievement/achievement',
  54 + url: '/pages/index/achievement/achievement?valueId='+e.currentTarget.dataset.valueid ,
52 55 })
53 56 },
54 57 // 去打卡
55   - handleDetail(){
  58 + handleDetail(e){
  59 + let eData = e.currentTarget.dataset
56 60 wx.navigateTo({
57   - url: '/pages/index/punchDetail/punchDetail',
  61 + url: '/pages/index/punchDetail/punchDetail?valueId='+eData.valueid ,
58 62 })
  63 + },
  64 + /**
  65 + * 生命周期函数--监听页面加载
  66 + */
  67 + onLoad: function (options) {
  68 + // this.getBannerList() //获取banner
59 69 },
60   - // 自定义模板
61   - handleNewPunch(){
62   - wx.navigateTo({
63   - url: '/pages/index/newPunch/newPunch',
  70 + onShow: function (options) {
  71 + this.getTaskList()
  72 + this.setData({
  73 + showAdd: false
64 74 })
65 75 },
66 76 // 获取banner图
... ...
pages/index/index.json
1 1 {
2 2 "usingComponents": {
3   - "van-popup": "@vant/weapp/popup/index"
  3 + "van-popup": "@vant/weapp/popup/index",
  4 + "van-tab": "@vant/weapp/tab/index",
  5 + "van-tabs": "@vant/weapp/tabs/index",
  6 + "van-progress": "@vant/weapp/progress/index"
4 7 },
5 8 "navigationBarTextStyle": "black",
6   - "navigationStyle": "custom"
  9 + "navigationBarTitleText": "打卡"
7 10 }
8 11 \ No newline at end of file
... ...
pages/index/index.wxml
1 1 <view class="main">
2   - <image class="temporary" hidden="{{tabindex==2}}" src="/img/_index1.png" mode="widthFix" alt="" />
3   - <image class="temporary" hidden="{{tabindex==1}}" src="/img/_index2.png" mode="widthFix" alt="" />
4   - <!-- 排行榜 -->
5   - <text class="temporary_box" style="width: 370rpx;height: 100rpx;position: absolute;top: 192rpx;left: 20rpx;" bindtap="handleRank"></text>
6   - <!-- 两个tab -->
7   - <text class="temporary_box" style="width: 160rpx;height: 80rpx;position: absolute;top: 300rpx;left: 32rpx;" bindtap="handleTab1"></text>
8   - <text class="temporary_box" style="width: 160rpx;height: 80rpx;position: absolute;top: 300rpx;left: 200rpx;" bindtap="handleTab2"></text>
9   - <!-- 打卡成果 -->
10   - <text class="temporary_box" style="width: 350rpx;height: 100rpx;position: absolute;top: 1000rpx;left: 20rpx;" bindtap="handleAchievement"></text>
11   - <!-- 去打卡 -->
12   - <text class="temporary_box" style="width: 350rpx;height: 100rpx;position: absolute;top: 1000rpx;right: 20rpx;" bindtap="handleDetail"></text>
13   - <!-- 新建打卡 -->
14   - <text class="temporary_box" style="width: 120rpx;height: 120rpx;position: absolute;top: 1200rpx;right: 20rpx;" bindtap="handleAdd"></text>
15   - <van-popup show="{{ showAdd }}" position="bottom" custom-style="height: 80%;" bind:close="closeAdd">
16   - <image class="temporary" src="/img/_index3.png" mode="widthFix" alt="" />
17   - <!-- 自定义模板 -->
18   - <text class="temporary_box" style="width: 180rpx;height: 220rpx;position: absolute;top: 364rpx;left: 20rpx;" bindtap="handleNewPunch"></text>
19   - </van-popup>
  2 + <!-- <view class="bck" style="background-image: url('https://szyundisk.oss-cn-hangzhou.aliyuncs.com/null/67c3d489-6635-4bef-90f2-03553f56fd0a.png')">
  3 + </view> -->
  4 + <!-- 打卡排行榜 -->
  5 + <!-- <view class="box">
  6 + <view class="title_name">
  7 + </view>
  8 + <vidw class="title_view" bindtap="toRank">立即查看</vidw>
  9 + <view class="tabs_css">
  10 + <view class="{{active == 1?'tabs_item check' :'tabs_item no_check'}}" bindtap="checkTabs" data-index='1'>我的打卡</view>
  11 + <view class="{{active == 2?'tabs_item check' :'tabs_item no_check'}} " bindtap='checkTabs' data-index='2'>我创建的</view>
  12 + </view>
  13 + <view class="tabs_div"></view>
  14 + </view> -->
  15 + <view class="white_box">
  16 + <view class="card" wx:for="{{taskList}}" wx:key="index" wx:for-item="value">
  17 + <view class="card_title">
  18 + <view class="title_L">
  19 + <image class="title_pic" src="/img/answer/bj.png" alt="" />
  20 + </view>
  21 + <view class="title_R">
  22 + <view>{{value.taskTitle}}</view>
  23 + <view class="grey_font">开始时间 {{value.startDate}}</view>
  24 + </view>
  25 + </view>
  26 + <view class="day_font">{{value.taskDesc}}</view>
  27 + <!-- <view class="day_font2">已坚持打卡
  28 + <text class="day_font2_large">1/50 </text>天
  29 + </view> -->
  30 + <view>
  31 + <van-progress percentage="50" color='#3F5EFF' stroke-width="13" pivot-text=' ' />
  32 + </view>
  33 + <view class="flex_font">
  34 + <text class="grey_flex">打卡频次:</text>
  35 + {{value.taskFrequency}}
  36 + </view>
  37 + <view class="flex_font" wx:if="{{value.submitCondition != null}}">
  38 + <text class="grey_flex">打卡要求:</text>
  39 + {{ value.submitCondition == '无限制' ? '无限制': '需要 '+value.submitCondition}}
  40 + </view>
  41 + <view class="flex_font">
  42 + <view class="grey_flex">其他:</view>
  43 + {{value.allowRepairCard == 1 ? '允许补卡': '不允许补卡'}}
  44 + </view>
  45 + <view class="grey_line"></view>
  46 + <view class="blue_font">
  47 + <view bindtap="handleAchievement" data-valueId="{{value.id}}">打卡成果</view>
  48 + <view class="blue_line"></view>
  49 + <view bindtap="handleDetail" data-valueId="{{value.id}}">去打卡</view>
  50 + </view>
  51 + </view>
  52 + </view>
20 53  
21 54 </view>
22 55 \ No newline at end of file
... ...
pages/index/index.wxss
... ... @@ -0,0 +1,196 @@
  1 +.bck {
  2 + position: absolute;
  3 + top: 0;
  4 + left: 0;
  5 + width: 100%;
  6 + height: 250px;
  7 + z-index: -1;
  8 + background-size: 100% 100%;
  9 +}
  10 +
  11 +.box {
  12 + padding: 100px 7vw 0;
  13 + box-sizing: border-box;
  14 +}
  15 +
  16 +.title_name {
  17 + font-size: 7vw;
  18 + font-weight: bold;
  19 + letter-spacing: 1.5vw;
  20 + color: #fff;
  21 + margin-bottom: 20px;
  22 +}
  23 +
  24 +.title_view {
  25 + height: 20px;
  26 + font-size: 4.8vw;
  27 + letter-spacing: 0.5vw;
  28 + color: #fff;
  29 + opacity: 0.7;
  30 +}
  31 +
  32 +.tabs_css {
  33 + margin: 30px 0;
  34 + display: flex;
  35 +}
  36 +.tabs_div {
  37 + margin: 30px 0;
  38 +}
  39 +
  40 +.tabs_item {
  41 + margin-right: 20px;
  42 + font-size: 4.3vw;
  43 + color: #fff;
  44 +}
  45 +
  46 +.check {}
  47 +
  48 +.no_check {
  49 + opacity: 0.6;
  50 +}
  51 +
  52 +/**/
  53 +.white_box {
  54 + width: 100vw;
  55 + min-height: 550px;
  56 + /* background-color: rebeccapurple; */
  57 + background-color: #F5F6FA;
  58 + border-top-left-radius: 8vw;
  59 + border-top-right-radius: 8vw;
  60 + padding: 10vw 5vw;
  61 + box-sizing: border-box;
  62 +}
  63 +
  64 +.card {
  65 + width: 90vw;
  66 + background-color: #fff;
  67 + border-radius: 8vw;
  68 + padding: 8vw 7vw;
  69 + margin-bottom: 30px;
  70 + box-sizing: border-box;
  71 + box-shadow: 1px 1px 1px 1px rgb(196, 196, 196);
  72 +}
  73 +
  74 +.card_title {
  75 + display: flex;
  76 +}
  77 +
  78 +.title_L {
  79 + flex-shrink: 0;
  80 + width: 50px;
  81 + height: 50px;
  82 + margin-right: 15px;
  83 +}
  84 +
  85 +.title_pic {
  86 + width: 100%;
  87 + height: 100%;
  88 +}
  89 +
  90 +.title_R {
  91 + height: 50px;
  92 + display: flex;
  93 + align-content: space-between;
  94 + flex-wrap: wrap;
  95 + font-size: 4.6vw;
  96 +}
  97 +
  98 +.grey_font {
  99 + width: 100%;
  100 + color: #999;
  101 + font-size: 3.8vw;
  102 +}
  103 +
  104 +.day_font {
  105 + margin: 20px 0 20px;
  106 + letter-spacing: 0.2vw;
  107 + font-size: 4vw;
  108 +}
  109 +
  110 +.day_font2 {
  111 + margin: 20px 0;
  112 + letter-spacing: 0.2vw;
  113 + font-size: 3.8vw;
  114 +}
  115 +
  116 +.day_font2_large {
  117 + font-size: 5.5vw;
  118 + font-weight: bold;
  119 +}
  120 +
  121 +.flex_font {
  122 + font-size: 3.5vw;
  123 + margin: 20px 0;
  124 + display: flex;
  125 +}
  126 +
  127 +.grey_flex {
  128 + width: 80px;
  129 + color: #999;
  130 +}
  131 +
  132 +.grey_line {
  133 + width: 100%;
  134 + height: 1px;
  135 + background-color: #E5E5E5;
  136 +}
  137 +
  138 +.blue_line {
  139 + width: 1px;
  140 + height: 20px;
  141 + background-color: #EAEAEA;
  142 +}
  143 +
  144 +.blue_font {
  145 + display: flex;
  146 + justify-content: space-around;
  147 + margin-top: 20px;
  148 + font-size: 4.1vw;
  149 + color: #4C92F9;
  150 +}
  151 +
  152 +.blue_tip {
  153 + position: fixed;
  154 + bottom: 40px;
  155 + right: 3vw;
  156 +}
  157 +
  158 +.img_tip {
  159 + width: 70px;
  160 + height: 70px;
  161 +}
  162 +
  163 +.pop_card {
  164 + padding: 5vw;
  165 + box-sizing: border-box;
  166 +}
  167 +
  168 +.pop_title {
  169 + font-size: 4.8vw;
  170 + font-weight: bold;
  171 + letter-spacing: 1px;
  172 + margin-bottom: 30px;
  173 +}
  174 +
  175 +.tem_box {
  176 + display: flex;
  177 + flex-wrap: wrap;
  178 +}
  179 +
  180 +.tem_item {
  181 + width: 23vw;
  182 + height: 170px;
  183 + text-align: center;
  184 + margin: 0 3vw 30px;
  185 +}
  186 +
  187 +.tem_pic {
  188 + width: 23vw;
  189 + height: 120px;
  190 + border-radius: 10px;
  191 +}
  192 +
  193 +.tem_font {
  194 + font-size: 3.9vw;
  195 + margin-top: 10px;
  196 +}
0 197 \ No newline at end of file
... ...
pages/index/newPunch/newPunch.js
1 1 // pages/index/rank/rank.js
  2 +import request from '../../../api/request.js'
  3 +import moment from 'moment';
2 4 Page({
3 5  
4 6 /**
5 7 * 页面的初始数据
6 8 */
7 9 data: {
  10 + tempId: 0,
  11 + form: {
  12 + taskTitle: '', //任务标题
  13 + taskDesc: '', //任务描述内容
  14 + allowRepairCard: 2, //是否允许补卡 1是 2否
  15 + hasData: 2, //是否需要提交数据 1是 2否
  16 + // id: '', // 任务ID
  17 + lackNum: '', // 缺卡次数
  18 + remindTime: '', // 打卡提醒时间点
  19 + startDate: '', // 打卡开始时间
  20 + statisticsUnit: '', // 统计单位 hasData=1 时,必传
  21 + submitCondition: '', //提交包含条件:图片、视频、音频
  22 + taskCycle: '', //打卡周期
  23 + taskFileUrl: [], //任务文件(含多个)
  24 + taskFrequency: '', //打卡频次
  25 + userId: '', //所属用户ID
  26 + },
  27 + fileList: [],
  28 + //弹出层
  29 + //统计单位
  30 + unitShow: false,
  31 + columnsUnit: ['分钟', '小时', '个', '篇', '本', '张', '页', '次'],
  32 + //开始时间
  33 + startTimeShow: false,
  34 + columnsStartTime: ['9', '10', '11', '12'],
  35 + minDate: new Date().getTime(),
  36 + currentDate: new Date().getTime(),
  37 + formatter(type, value) {
  38 + if (type === 'year') {
  39 + return `${value}年`;
  40 + }
  41 + if (type === 'month') {
  42 + return `${value}月`;
  43 + }
  44 + return value;
  45 + },
  46 + //打卡周期
  47 + clockCycleShow: false,
  48 + columnsClockCycle: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10','11', '12', '13', '14', '15', '16', '17', '18', '19', '20','21', '22', '23', '24', '25', '26', '27', '28', '29', '30','31',
  49 + '32', '33', '34', '35', '36', '37', '38', '39', '40','41',
  50 + '42', '43', '44', '45', '46', '47', '48', '49', '40','51',
  51 + '52', '53', '54', '55', '56', '57', '58', '59', '60','61',
  52 + '62', '63', '64', '65', '66', '67', '68', '69', '70','71',
  53 + '72', '73', '74', '75', '76', '77', '78', '79', '80','81',
  54 + '82', '83', '84', '85', '86', '87', '88', '89', '90'],
  55 + //打卡频次
  56 + clockRateShow: false,
  57 + columnsClockRate: ['每天', '7天', '一个月'],
  58 + //打卡提醒
  59 + clockRemindShow: false,
  60 + columnsClockRemind: [
  61 + {
  62 + values: ['每天','周一', '周二', '周三', '周四', '周五', '周六', '周日'],
  63 + defaultIndex: 2,
  64 + },
  65 + // 第二列
  66 + {
  67 + values: ['8:00', '9:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00', '21:00'],
  68 + defaultIndex: 1,
  69 + },
  70 + ],
  71 + //打卡缺卡提醒
  72 + clockLackShow: false,
  73 + columnsClockLack: [1,2,3],
  74 + //必须包含
  75 + containShow: false,
  76 + columnsContain: ['无限制','图片'],
  77 + },
  78 + //获取模板详情 / 空模板
  79 + getDetail() {
  80 + request({
  81 + url: `/wx/temp/getTempDetail`,
  82 + method: 'get',
  83 + data: {
  84 + "tempId": this.data.tempId,
  85 + },
  86 + }).then(res => {
  87 + if (res.code == 0) {
  88 + const data = res.data
  89 + this.setData({
  90 + 'form.taskTitle': data.taskTitle
  91 + })
  92 + this.setData({
  93 + 'form.taskDesc': data.taskDesc
  94 + })
  95 + this.setData({
  96 + 'form.allowRepairCard': data.allowRepairCard
  97 + })
  98 + this.setData({
  99 + 'form.hasData': data.hasData
  100 + })
  101 + this.setData({
  102 + 'form.lackNum': data.lackNum
  103 + })
  104 + this.setData({
  105 + 'form.remindTime': data.remindTime
  106 + })
  107 + this.setData({
  108 + 'form.startDate': moment(new Date().getTime()).format('YYYY-MM-DD')
  109 + })
  110 + this.setData({
  111 + 'form.statisticsUnit': data.statisticsUnit
  112 + })
  113 + this.setData({
  114 + 'form.submitCondition': data.submitCondition
  115 + })
  116 + this.setData({
  117 + 'form.taskCycle': data.taskCycle
  118 + })
  119 + this.setData({
  120 + 'form.taskFileUrl': []
  121 + })
  122 + this.setData({
  123 + 'form.taskFrequency': data.taskFrequency
  124 + })
  125 + } else {
  126 + wx.showToast({
  127 + title: res.msg,
  128 + icon: 'none',
  129 + duration: 1000
  130 + })
  131 + }
  132 + })
  133 + },
  134 + //输入
  135 + onfieldChange(e) {
  136 + this.setData({
  137 + 'form.taskTitle': e.detail
  138 + })
  139 + },
  140 + //输入
  141 + onfieldDescChange(e) {
  142 + this.setData({
  143 + 'form.taskDesc': e.detail
  144 + })
  145 + },
  146 + //开关
  147 + onSwitch(e) {
  148 + console.log(e)
  149 + this.setData({
  150 + 'form.hasData': e.detail
  151 + })
  152 + },
  153 + onChange(e) {
  154 + console.log(e)
  155 + this.setData({
  156 + 'form.allowRepairCard': e.detail
  157 + })
  158 + },
  159 + //文件上传
  160 + afterRead(event) {
  161 + const {
  162 + file
  163 + } = event.detail;
  164 + var that = this
  165 + // 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
  166 + wx.uploadFile({
  167 + url: 'https://market.myjxt.com:51311/file/fileUpload', // 仅为示例,非真实的接口地址
  168 + filePath: file.url,
  169 + name: 'file',
  170 + formData: {
  171 + user: 'test'
  172 + },
  173 + success(res) {
  174 + // 上传完成需要更新 fileList
  175 + const {
  176 + fileList = []
  177 + } = that.data;
  178 + fileList.push({
  179 + ...file,
  180 + url: res.data
  181 + });
  182 + console.log(res,fileList)
  183 + that.setData({
  184 + fileList
  185 + });
  186 + that.setData({
  187 + 'form.taskFileUrl': fileList.map(v => v.url)
  188 + })
  189 + },
  190 + });
  191 + },
  192 + //删除
  193 + delFile(event) {
  194 + let [list,index] = [this.data.fileList,event.detail.index]
  195 + list.splice(index,1)
  196 + this.setData({
  197 + fileList:list
  198 + })
  199 + this.setData({
  200 + 'form.taskFileUrl': this.data.fileList.map(v => v.url)
  201 + })
  202 + },
  203 + //开关
  204 + onswitchChange({
  205 + detail
  206 + }) {
  207 + this.setData({
  208 + 'form.checked': detail
  209 + });
  210 + },
  211 + //创建
  212 + createTask() {
  213 + console.log(this.data.form)
  214 + if(this.data.form.hasData == 1 && !this.data.form.statisticsUnit) {
  215 + return wx.showToast({title: '请选择统计单位',icon: 'none',})
  216 + }
  217 + request({
  218 + url: `/wx/task/addCardTask`,
  219 + method: 'post',
  220 + data: this.data.form,
  221 + }).then(res => {
  222 + if (res.code == 0) {
  223 + wx.navigateTo({
  224 +    url: '../../mine/record/record'
  225 + })
  226 + }else {
  227 + wx.showToast({
  228 + title: res.msg,
  229 + icon: 'none',
  230 + duration: 1000
  231 + })
  232 + }
  233 + })
8 234 },
9   -
10 235 /**
11 236 * 生命周期函数--监听页面加载
12 237 */
13 238 onLoad(options) {
14   -
  239 + this.setData({
  240 + 'form.userId': wx.getStorageSync('userInfo_id')
  241 + })
  242 + this.setData({
  243 + tempId: options.tempId
  244 + }, () => {
  245 + this.getDetail()
  246 + })
15 247 },
16 248 // 创建完成
17   - handleCreate(){
  249 + handleCreate() {
18 250 // console.log(111)
19 251 wx.switchTab({
20   - url: '/pages/index/index',
  252 + url: '/pages/index/index',
21 253 })
22 254 },
23 255 // 统一返回
... ... @@ -29,5 +261,154 @@ Page({
29 261 */
30 262 onShareAppMessage() {
31 263  
32   - }
  264 + },
  265 + /*
  266 + 弹出层 - 统计单位
  267 + */
  268 + openUnitShow() {
  269 + this.setData({
  270 + unitShow: true
  271 + })
  272 + },
  273 + closeUnitShow() {
  274 + this.setData({
  275 + unitShow: false
  276 + })
  277 + },
  278 + changeUnitShow(e) {
  279 + console.log(e)
  280 + this.setData({
  281 + 'form.statisticsUnit': e.detail.value
  282 + })
  283 + this.setData({
  284 + unitShow: false
  285 + })
  286 + },
  287 + /*
  288 + 弹出层 - 开始时间
  289 + */
  290 + openStartTimeShow() {
  291 + this.setData({
  292 + startTimeShow: true
  293 + })
  294 + },
  295 + closeStartTimeShow() {
  296 + this.setData({
  297 + startTimeShow: false
  298 + })
  299 + },
  300 + changeStartTimeShow(e) {
  301 + let time = moment(e.detail).format('YYYY-MM-DD')
  302 + this.setData({
  303 + 'form.startDate': time,
  304 + });
  305 + this.setData({
  306 + startTimeShow: false
  307 + })
  308 + },
  309 + /*
  310 + 弹出层 - 打卡周期
  311 + */
  312 + openClockCycleShow() {
  313 + this.setData({
  314 + clockCycleShow: true
  315 + })
  316 + },
  317 + closeClockCycleShow() {
  318 + this.setData({
  319 + clockCycleShow: false
  320 + })
  321 + },
  322 + changeClockCycleShow(e) {
  323 + this.setData({
  324 + 'form.taskCycle': e.detail.value
  325 + })
  326 + this.setData({
  327 + clockCycleShow: false
  328 + })
  329 + },
  330 + /*
  331 + 弹出层 - 打卡频次
  332 + */
  333 + openClockRateShow() {
  334 + this.setData({
  335 + clockRateShow: true
  336 + })
  337 + },
  338 + closeClockRateShow() {
  339 + this.setData({
  340 + clockRateShow: false
  341 + })
  342 + },
  343 + changeClockRateShow(e) {
  344 + this.setData({
  345 + 'form.taskFrequency': e.detail.value
  346 + })
  347 + this.setData({
  348 + clockRateShow: false
  349 + })
  350 + },
  351 + /*
  352 + 弹出层 - 打卡提醒
  353 + */
  354 + openClockRemindShow() {
  355 + this.setData({
  356 + clockRemindShow: true
  357 + })
  358 + },
  359 + closeClockRemindShow() {
  360 + this.setData({
  361 + clockRemindShow: false
  362 + })
  363 + },
  364 + changeClockRemindShow(e) {
  365 + this.setData({
  366 + 'form.remindTime': e.detail.value[0] + '::' + e.detail.value[1]
  367 + })
  368 + this.setData({
  369 + clockRemindShow: false
  370 + })
  371 + },
  372 + /*
  373 + 弹出层 - 打卡缺卡提醒
  374 + */
  375 + openClockLackShow() {
  376 + this.setData({
  377 + clockLackShow: true
  378 + })
  379 + },
  380 + closeClockLackShow() {
  381 + this.setData({
  382 + clockLackShow: false
  383 + })
  384 + },
  385 + changeClockLackShow(e) {
  386 + this.setData({
  387 + 'form.lackNum': e.detail.value
  388 + })
  389 + this.setData({
  390 + clockLackShow: false
  391 + })
  392 + },
  393 + /*
  394 + 弹出层 - 必须包含
  395 + */
  396 + openContainShow() {
  397 + this.setData({
  398 + containShow: true
  399 + })
  400 + },
  401 + closeContainShow() {
  402 + this.setData({
  403 + containShow: false
  404 + })
  405 + },
  406 + changeContainShow(e) {
  407 + this.setData({
  408 + 'form.submitCondition': e.detail.value
  409 + })
  410 + this.setData({
  411 + containShow: false
  412 + })
  413 + },
33 414 })
34 415 \ No newline at end of file
... ...
pages/index/newPunch/newPunch.json
1 1 {
2 2 "usingComponents": {
3   - "van-icon": "@vant/weapp/icon/index"
  3 + "van-icon": "@vant/weapp/icon/index",
  4 + "van-cell-group": "@vant/weapp/cell-group/index",
  5 + "van-field": "@vant/weapp/field/index",
  6 + "van-cell": "@vant/weapp/cell/index",
  7 + "van-switch": "@vant/weapp/switch/index",
  8 + "van-button": "@vant/weapp/button/index",
  9 + "van-popup": "@vant/weapp/popup/index",
  10 + "van-picker": "@vant/weapp/picker/index",
  11 + "van-uploader": "@vant/weapp/uploader/index",
  12 + "van-datetime-picker": "@vant/weapp/datetime-picker/index"
4 13 },
5   - "navigationStyle": "custom"
  14 + "navigationBarTitleText": "打卡模板"
6 15 }
7 16 \ No newline at end of file
... ...
pages/index/newPunch/newPunch.wxml
1 1 <!--pages/index/rank/rank.wxml-->
2 2 <view class="punch_detail">
3   - <!-- 顶部统一返回 -->
4   - <view class="navigation_back" bindtap="handleBack">
5   - <van-icon name="arrow-left" />
  3 + <view class="title_card">
  4 + <van-cell-group border="{{ false }}">
  5 + <van-field value="{{ form.taskTitle }}" placeholder="请输入标题" border="{{ false }}" bind:change="onfieldChange" />
  6 + </van-cell-group>
  7 + <view class="grey_line"></view>
  8 + <view class="box_card">
  9 + <van-cell-group border="{{ false }}">
  10 + <van-field value="{{ form.taskDesc }}" type="textarea" placeholder="请输入" autosize border="{{ false }}" bind:change="onfieldDescChange" />
  11 + </van-cell-group>
  12 + </view>
  13 + <view class="tip_card">
  14 + <van-uploader accept='image' file-list="{{ fileList }}" deletable="{{ true }}" bind:after-read="afterRead" bind:delete="delFile">
  15 + <view class="tip_item">
  16 + <image class="pic" src="/img/answer/tp1.png" alt="" />
  17 + </view>
  18 + </van-uploader>
  19 + <!-- <view class="tip_item">
  20 + <image class="pic" src="/img/answer/sp1.png" alt="" />
  21 + </view>
  22 + <view class="tip_item">
  23 + <image class="pic" src="/img/answer/yp1.png" alt="" />
  24 + </view> -->
  25 + </view>
6 26 </view>
7   - <image class="temporary" src="/img/_new_punch.png" mode="widthFix" alt="" />
8   - <!-- 创建完成返回首页 -->
9   - <text class="temporary_box" style="width: 700rpx;height: 100rpx;position: absolute;top: 2392rpx;right: 32rpx;" bindtap="handleCreate"></text>
  27 + <view class="white_card">
  28 + <view class="bold_font">需要提交数据</view>
  29 + <view>
  30 + <van-switch checked="{{ form.hasData }}" size='20' active-value='1' inactive-value='2' bind:change="onSwitch" />
  31 + </view>
  32 + </view>
  33 + <view class="grey_line"></view>
  34 + <view class="white_card_nopadding" wx:if="{{form.hasData == 1}}">
  35 + <van-cell-group border="{{ false }}">
  36 + <van-cell title="统计单位" value="{{ form.statisticsUnit }}" is-link label="请选择统计单位" border="{{ false }}" bindtap="openUnitShow" />
  37 + </van-cell-group>
  38 + </view>
  39 + <view class="white_card">
  40 + <view>允许补卡</view>
  41 + <view>
  42 + <van-switch checked="{{ form.allowRepairCard }}" size='20' bind:change="onChange" active-value='1' inactive-value='2' />
  43 + </view>
  44 + </view>
  45 + <view class="sm_grey_font">
  46 + 开启后,在打卡周期内,学生家长可对未打卡的任务进行补卡。
  47 + </view>
  48 + <view class="white_card_nopadding">
  49 + <van-cell-group border="{{ false }}">
  50 + <van-cell title="开始时间" value="{{ form.startDate }}" is-link border="{{ false }}" bindtap="openStartTimeShow" />
  51 + </van-cell-group>
  52 + </view>
  53 + <view class="white_card_nopadding">
  54 + <van-cell-group border="{{ false }}">
  55 + <van-cell title="打卡周期" value="{{ form.taskCycle + ' 天'}}" is-link border="{{ false }}" bindtap="openClockCycleShow" />
  56 + </van-cell-group>
  57 + </view>
  58 + <view class="white_card_nopadding">
  59 + <van-cell-group border="{{ false }}">
  60 + <van-cell title="打卡频次" value="{{ form.taskFrequency }}" is-link border="{{ false }}" bindtap="openClockRateShow" />
  61 + </van-cell-group>
  62 + </view>
  63 +
  64 + <view class="clearance"></view>
  65 + <view class="white_card_nopadding">
  66 + <van-cell-group border="{{ false }}">
  67 + <van-cell title="打卡提醒" value="{{ form.remindTime }}" is-link border="{{ false }}" bindtap="openClockRemindShow" />
  68 + </van-cell-group>
  69 + </view>
  70 + <view class="white_card_nopadding">
  71 + <van-cell-group border="{{ false }}">
  72 + <van-cell title="缺卡打卡提醒" value="{{ form.lackNum + ' 次' }}" is-link border="{{ false }}" bindtap="openClockLackShow" />
  73 + </van-cell-group>
  74 + </view>
  75 +
  76 + <view class="sm_grey_font">
  77 + 学生如缺卡达到一定条件,将会提醒家长
  78 + </view>
  79 + <view class="white_card_nopadding">
  80 + <van-cell-group border="{{ false }}" >
  81 + <van-cell title="提交时必须包含" value="{{ form.submitCondition }}" is-link border="{{ false }}" bindtap="openContainShow" />
  82 + </van-cell-group>
  83 + </view>
  84 +
  85 + <view class="clearance"></view>
  86 + <view class="btn">
  87 + <van-button type="info" round block bindtap="createTask">创建打卡</van-button>
  88 + </view>
  89 +
  90 + <!--统计单位-->
  91 + <van-popup show="{{ unitShow }}" position="bottom" custom-style="height: 40%;" round bind:close="closeUnitShow">
  92 + <van-picker columns="{{ columnsUnit }}" bind:confirm="changeUnitShow" bind:cancel="closeUnitShow" show-toolbar title="统计单位" />
  93 + </van-popup>
  94 +
  95 + <!--开始时间-->
  96 + <van-popup show="{{ startTimeShow }}" position="bottom" custom-style="height: 40%;" round bind:close="closeStartTimeShow">
  97 + <!-- <van-picker columns="{{ columnsStartTime }}" bind:confirm="changeStartTimeShow" bind:cancel="closeStartTimeShow" show-toolbar title="开始时间" /> -->
  98 + <van-datetime-picker title="开始时间" type="date" value="{{ form.startTimeShow }}" min-date="{{ minDate }}" bind:confirm="changeStartTimeShow" bind:cancel="closeStartTimeShow" formatter="{{ formatter }}" />
  99 + </van-popup>
  100 +
  101 + <!--打卡周期-->
  102 + <van-popup show="{{ clockCycleShow }}" position="bottom" custom-style="height: 40%;" round bind:close="closeClockCycleShow">
  103 + <van-picker columns="{{ columnsClockCycle }}" bind:confirm="changeClockCycleShow" bind:cancel="closeClockCycleShow" show-toolbar title="打卡周期" />
  104 + </van-popup>
  105 +
  106 + <!--打卡频次-->
  107 + <van-popup show="{{ clockRateShow }}" position="bottom" custom-style="height: 40%;" round bind:close="closeClockRateShow">
  108 + <van-picker columns="{{ columnsClockRate }}" bind:confirm="changeClockRateShow" bind:cancel="closeClockRateShow" show-toolbar title="打卡频次" />
  109 + </van-popup>
  110 +
  111 + <!--打卡提醒-->
  112 + <van-popup show="{{ clockRemindShow }}" position="bottom" custom-style="height: 40%;" round bind:close="closeClockRemindShow">
  113 + <van-picker columns="{{ columnsClockRemind }}" bind:confirm="changeClockRemindShow" bind:cancel="closeClockRemindShow" show-toolbar title="打卡提醒" />
  114 + </van-popup>
  115 +
  116 + <!--打卡缺卡提醒-->
  117 + <van-popup show="{{ clockLackShow }}" position="bottom" custom-style="height: 40%;" round bind:close="closeClockLackShow">
  118 + <van-picker columns="{{ columnsClockLack }}" bind:confirm="changeClockLackShow" bind:cancel="closeClockLackShow" show-toolbar title="缺卡打卡提醒" />
  119 + </van-popup>
10 120  
  121 + <!-- 必须包含 -->
  122 + <van-popup show="{{ containShow }}" position="bottom" custom-style="height: 40%;" round bind:close="closeContainShow">
  123 + <van-picker columns="{{ columnsContain }}" bind:confirm="changeContainShow" bind:cancel="closeContainShow" show-toolbar title="提交时必须包含" />
  124 + </van-popup>
11 125 </view>
12 126 \ No newline at end of file
... ...
pages/index/newPunch/newPunch.wxss
1 1 /* pages/index/newPunch/newPunch.wxss */
  2 +.punch_detail {
  3 + position: absolute;
  4 + width: 100vw;
  5 + min-height: 100vh;
  6 + background-color: #F5F6FA;
  7 +}
  8 +
  9 +.title_card {
  10 + margin: 15px 0;
  11 +}
  12 +
  13 +.grey_line {
  14 + width: 80vw;
  15 + height: 1px;
  16 +}
  17 +
  18 +.box_card {
  19 + width: 100vw;
  20 + min-height: 120px;
  21 + background-color: #fff;
  22 +}
  23 +
  24 +.tip_card {
  25 + padding: 20px;
  26 + box-sizing: border-box;
  27 + display: flex;
  28 + background-color: #fff;
  29 +}
  30 +
  31 +.tip_item {
  32 + width: 70px;
  33 + height: 30px;
  34 + margin-right: 5vw;
  35 +}
  36 +
  37 +.pic {
  38 + width: 100%;
  39 + height: 100%;
  40 +}
  41 +
  42 +.white_card {
  43 + width: 100vw;
  44 + background-color: #fff;
  45 + padding: 20px 15px;
  46 + box-sizing: border-box;
  47 + display: flex;
  48 + justify-content: space-between;
  49 +}
  50 +
  51 +.bold_font {
  52 + font-weight: bold;
  53 +}
  54 +
  55 +.white_card_nopadding {
  56 + width: 100vw;
  57 + background-color: #fff;
  58 + font-weight: bold;
  59 + height: 60px;
  60 + padding-top: 11px;
  61 + box-sizing: border-box;
  62 +}
  63 +
  64 +.sm_grey_font {
  65 + padding: 15px 0 15px 20px;
  66 + box-sizing: border-box;
  67 + font-size: 12px;
  68 + color: #999;
  69 +}
  70 +
  71 +.clearance {
  72 + width: 100vw;
  73 + height: 20px;
  74 +}
  75 +
  76 +.btn {
  77 + width: 100vw;
  78 + height: 80px;
  79 + background-color: #fff;
  80 + padding: 20px 30px 80px;
  81 + box-sizing: border-box;
  82 +}
2 83 \ No newline at end of file
... ...
pages/index/punchDetail/punchDetail.js
1   -// pages/index/punchDetail/punchDetail.js
  1 +// pages/index/achievement/achievement.js
  2 +// 引入插件安装器
  3 +import plugin from '../../../component/v2/plugins/index'
  4 +import week from '../../../component/v2/plugins/week'
  5 +import todo from '../../../component/v2/plugins/todo'
  6 +import request from '../../../api/request.js'
  7 +import moment from 'moment';
  8 +plugin
  9 + .use(week)
  10 + .use(todo)
2 11 Page({
3 12  
4 13 /**
5 14 * 页面的初始数据
6 15 */
7 16 data: {
8   - showEdit: false, //确认打卡
9   - Clocked: false, //已打卡状态,只是为了演示用
10   - showSuccess:false
  17 + calendarConfig: {
  18 + theme: 'elegant',
  19 + weekMode: true, // 周视图模式
  20 + highlightToday: true, // 是否高亮显示当天
  21 + hideHeader: true, // 隐藏日历头部操作栏
  22 + },
  23 + isDisplay: false,
  24 + clockShow: false,
  25 + form: {
  26 + id: '', //任务ID
  27 + isRepair: 1, //是否补卡1立即打卡2补卡
  28 + repairDate: '', //补卡日期,当isRepair=2时必传,格式:YYYY-MM-dd
  29 + statisticsUnit: '', //统计单位所含内容
  30 + taskDesc: '', //打卡描述内容
  31 + taskFileUrl: [], //任务文件(含多个)
  32 + userId: ''
  33 + },
  34 + fileList: [],
  35 + calendar: {}, //日历
  36 + valueId: '', //任务ID
  37 + taskVo: {
  38 + allowRepairCard: 0,
  39 + hasData: 0,
  40 + statisticsUnit: "",
  41 + submitCondition: "",
  42 + id: 0,
  43 + releaseTime: "",
  44 + signTotal: 0,
  45 + taskCycle: 0,
  46 + taskDesc: "",
  47 + taskFrequency: "",
  48 + taskTitle: "",
  49 + weekDay: ""
  50 + },
  51 + resData: [], //成果数据
  52 + recordVo: {
  53 + commitTime: "",
  54 + files: [],
  55 + signDate: "",
  56 + taskRecordDesc: "",
  57 + taskStatisticsParam: ""
  58 + }, //成果数据当天
  59 + recordVoShow: false,
  60 + isToday:true,//是否是今天
  61 + isLarge:false, //是否大于今天
  62 + repairText: ''
11 63 },
12   -
13   - /**
14   - * 生命周期函数--监听页面加载
  64 + /**
  65 + * 选择日期后执行的事件
15 66 */
16   - onLoad(options) {
  67 + afterTapDate(e) {
  68 + let date = e.detail.date
  69 + this.setData({
  70 + isToday:e.detail.isToday
  71 + })
  72 + //选择的年月日
  73 + let checkDay = e.detail.year +'-' + e.detail.month +'-' + e.detail.date
  74 + let checktimeDate= new Date(moment(checkDay).format('YYYY-MM-DD')).getTime()
  75 + //选择的日期是否大于今天
  76 + if(checktimeDate > new Date().getTime()) {
  77 + console.log('ff')
  78 + this.setData({
  79 + isLarge: true
  80 + })
  81 + }else {
  82 + this.setData({
  83 + isLarge: false
  84 + })
  85 + }
  86 + this.setData({
  87 + repairText: e.detail.todoText
  88 + })
  89 + let recordVo = this.data.resData.eventDetails[date - 1].recordVo
  90 + //匹配数据
  91 + if (recordVo != null) {
  92 + console.log('复制',recordVo)
  93 + this.setData({
  94 + recordVo: recordVo
  95 + })
  96 + this.setData({
  97 + recordVoShow: true
  98 + })
  99 + }else {
  100 + this.setData({
  101 + recordVoShow: false
  102 + })
  103 + }
  104 + },
  105 + //获取信息
  106 + getInfo(doday) {
  107 + request({
  108 + url: `/wx/task/getSignRecord`,
  109 + method: 'get',
  110 + data: {
  111 + // wx.getStorageSync('userInfo_id'),
  112 + "taskId": this.data.valueId,
  113 + "signDate": doday
  114 + },
  115 + }).then(res => {
  116 + if (res.code == 0) {
  117 + this.setData({
  118 + resData: res.data
  119 + })
  120 + this.getV2(res.data)
  121 + } else {
  122 + wx.showToast({
  123 + title: res.msg,
  124 + icon: 'none'
  125 + })
  126 + }
  127 + })
  128 + },
  129 + //初始化日历
  130 + initialize() {
  131 + // 设置待办
  132 + this.setData({
  133 + 'calendar': this.selectComponent('#calendar').calendar
  134 + })
17 135  
18 136 },
19   - // 打卡成果
20   - handleAchievement(){
  137 + //显示日历
  138 + getV2(resData) {
  139 + this.setData({
  140 + taskVo: resData.taskVo
  141 + })
  142 + // const calendar = this.selectComponent('#calendar').calendar
  143 + this.data.calendar.setTodos({
  144 + // 待办点标记设置
  145 + pos: 'bottom', // 待办点标记位置 ['top', 'bottom']
  146 + dotColor: 'purple', // 待办点标记颜色
  147 + circle: false, // 待办圆圈标记设置(如圆圈标记已签到日期),该设置与点标记设置互斥
  148 + showLabelAlways: true, // 点击时是否显示待办事项(圆点/文字),在 circle 为 true 及当日历配置 showLunar 为 true 时,此配置失效
  149 + dates: resData.eventDetails
  150 + })
  151 + },
  152 + //成果
  153 + toAchieve(e) {
21 154 wx.navigateTo({
22   - url: '/pages/index/achievement/achievement',
  155 + url: '../achievement/achievement?valueId='+this.data.valueId,
23 156 })
24 157 },
25   - // 打开打卡信息填写
26   - handleEdit() {
27   - console.log(111)
  158 + //唤起 打卡
  159 + toClock() {
28 160 this.setData({
29   - showEdit: true
  161 + clockShow: true
30 162 })
31 163 },
32   - // 关闭打卡信息填写
33   - closeEdit() {
  164 + //唤起补卡
  165 + toRepairClock() {
  166 + let selectData = this.data.calendar.getSelectedDates()
  167 + let doday = selectData[0].year + '-' + selectData[0].month + '-' + selectData[0].date
  168 + console.log(doday)
  169 + let repairDate= moment(doday).format('YYYY-MM-DD')
  170 + this.setData({
  171 + 'form.isRepair':2
  172 + })
  173 + this.setData({
  174 + 'form.repairDate':repairDate
  175 + })
34 176 this.setData({
35   - showEdit: false
  177 + clockShow: true
36 178 })
37 179 },
38   - // 提交打卡信息,跳转打卡成功页面
39   - handleSubmit() {
  180 + //确定-打卡
  181 + toCardTask() {
40 182 this.setData({
41   - Clocked: true,
42   - showEdit: false,
43   - showSuccess:true
  183 + 'form.id': this.data.valueId
  184 + })
  185 + this.setData({
  186 + 'form.userId': wx.getStorageSync('userInfo_id')
  187 + })
  188 + if(this.data.taskVo.submitCondition=='图片') {
  189 + if(this.data.form.taskFileUrl.length == 0) {
  190 + return wx.showToast({
  191 + title: '请上传图片',
  192 + icon: 'none'
  193 + })
  194 + }
  195 + }
  196 + request({
  197 + url: `/wx/task/commitCardTask`,
  198 + method: 'post',
  199 + data: this.data.form,
  200 + }).then(res => {
  201 + if (res.code == 0) {
  202 + wx.showToast({
  203 + title: '打卡成功',
  204 + icon: 'none'
  205 + })
  206 + this.closeClockShow()
  207 + this.getInfo(moment(new Date().getTime()).format('YYYY-MM-DD'))
  208 + } else {
  209 + wx.showToast({
  210 + title: res.msg,
  211 + icon: 'none'
  212 + })
  213 + }
44 214 })
45 215 },
46   - colseSuccess(){
  216 + /**
  217 + * 生命周期函数--监听页面加载
  218 + */
  219 + onLoad(options) {
47 220 this.setData({
48   - showSuccess:false
  221 + valueId: options.valueId
49 222 })
50 223 },
  224 + /**
  225 + * 生命周期函数--监听页面初次渲染完成
  226 + */
  227 + onReady() {
  228 + this.initialize()
  229 + this.getInfo(moment(new Date().getTime()).format('YYYY-MM-DD'))
  230 + },
  231 + // 统一返回
51 232 handleBack() {
52 233 wx.navigateBack()
53 234 },
... ... @@ -56,5 +237,79 @@ Page({
56 237 */
57 238 onShareAppMessage() {
58 239  
  240 + },
  241 + //统计单位所含内容
  242 + onStatisChange(e) {
  243 + this.setData({
  244 + 'form.statisticsUnit': e.detail
  245 + })
  246 + },
  247 + //内容
  248 + onTaskDescChange(e) {
  249 + this.setData({
  250 + 'form.taskDesc': e.detail
  251 + })
  252 + },
  253 + //文件上传
  254 + afterRead(event) {
  255 + const {
  256 + file
  257 + } = event.detail;
  258 + var that = this
  259 + // 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
  260 + wx.uploadFile({
  261 + url: 'https://market.myjxt.com:51311/file/fileUpload', // 仅为示例,非真实的接口地址
  262 + filePath: file.url,
  263 + name: 'file',
  264 + formData: {
  265 + user: 'test'
  266 + },
  267 + success(res) {
  268 + // 上传完成需要更新 fileList
  269 + const {
  270 + fileList = []
  271 + } = that.data;
  272 + fileList.push({
  273 + ...file,
  274 + url: res.data
  275 + });
  276 + console.log(res, fileList)
  277 + that.setData({
  278 + fileList
  279 + });
  280 + that.setData({
  281 + 'form.taskFileUrl': fileList.map(v => v.url)
  282 + })
  283 + },
  284 + });
  285 + },
  286 + //删除
  287 + delFile(event) {
  288 + let [list, index] = [this.data.fileList, event.detail.index]
  289 + list.splice(index, 1)
  290 + this.setData({
  291 + fileList: list
  292 + })
  293 + this.setData({
  294 + 'form.taskFileUrl': this.data.fileList.map(v => v.url)
  295 + })
  296 + },
  297 + //关闭
  298 + closeClockShow() {
  299 + this.setData({
  300 + clockShow: false
  301 + })
  302 + let form = {
  303 + id: '', //任务ID
  304 + isRepair: 1, //是否补卡1立即打卡2补卡
  305 + repairDate: '', //补卡日期,当isRepair=2时必传,格式:YYYY-MM-dd
  306 + statisticsUnit: '', //统计单位所含内容
  307 + taskDesc: '', //打卡描述内容
  308 + taskFileUrl: [], //任务文件(含多个)
  309 + userId: ''
  310 + }
  311 + this.setData({
  312 + form: form
  313 + })
59 314 }
60 315 })
61 316 \ No newline at end of file
... ...
pages/index/punchDetail/punchDetail.json
1 1 {
2 2 "usingComponents": {
3 3 "van-icon": "@vant/weapp/icon/index",
4   - "van-popup": "@vant/weapp/popup/index"
  4 + "calendar": "/component/v2/index",
  5 + "van-popup": "@vant/weapp/popup/index",
  6 + "van-field": "@vant/weapp/field/index",
  7 + "van-uploader": "@vant/weapp/uploader/index",
  8 + "van-button": "@vant/weapp/button/index"
5 9 },
6   - "navigationStyle": "custom"
  10 + "navigationBarTitleText": "立即打卡"
7 11 }
8 12 \ No newline at end of file
... ...
pages/index/punchDetail/punchDetail.wxml
1   -<!--pages/index/punchDetail/punchDetail.wxml-->
  1 +<!--pages/index/achievement/achievement.wxml-->
2 2 <view class="punch_detail">
3   - <!-- 顶部统一返回 -->
4   - <view class="navigation_back" bindtap="handleBack">
5   - <van-icon name="arrow-left" />
  3 + <calendar id="calendar" config="{{calendarConfig}}" bind:afterTapDate="afterTapDate"/>
  4 + <!-- <view class="btn" bindtap="getInfo">按钮</view> -->
  5 + <view class="line_grey"></view>
  6 + <view class="card">
  7 + <view class="card_title">{{taskVo.taskTitle}}</view>
  8 + <view class="card_flex">
  9 + <view class="flex_grey">已进行 {{taskVo.signTotal +' / ' +taskVo.taskCycle}} 天</view>
  10 + <view class="flex_grey">打卡频次 : {{taskVo.taskFrequency}}</view>
  11 + <view class="flex_grey">{{taskVo.allowRepairCard == 1 ?'允许补卡': '不允许补卡'}}</view>
  12 + </view>
  13 + <view class="card_context">{{taskVo.taskDesc}}</view>
  14 + <view class="grey_font">
  15 + <view>我发布与{{taskVo.weekDay}} {{taskVo.releaseTime}}</view>
  16 + <view class="grey_font_bottom"></view>
  17 + </view>
  18 + </view>
  19 + <view class="btn_box">
  20 + <van-button round color="#F4F4F4" bindtap='toAchieve' custom-style="color: #000;">我 的 成 果</van-button>
  21 + <van-button round type="info" bindtap='toClock' wx:if="{{isToday}}">立 即 打 卡</van-button>
  22 + <van-button round type="warning" bindtap='toRepairClock' wx:if="{{taskVo.allowRepairCard == 1&&repairText=='未打卡'&&!isToday&&!isLarge}}">补 卡</van-button>
6 23 </view>
7   - <!-- 已打卡 -->
8   - <image class="temporary" wx:if="{{Clocked}}" src="/img/_check_in3.png" mode="widthFix" alt="" />
9   - <!-- 未打卡 -->
10   - <image class="temporary" wx:else src="/img/_check_in1.png" mode="widthFix" alt="" />
11   - <!-- 我的成果 -->
12   - <text class="temporary_box" wx:if="{{!Clocked}}" style="width: 308rpx;height: 100rpx;position: absolute;top: 1412rpx;left: 32rpx;" bindtap="handleAchievement"></text>
13   - <!-- 立即打卡 -->
14   - <text class="temporary_box" wx:if="{{!Clocked}}" style="width: 308rpx;height: 100rpx;position: absolute;top: 1412rpx;right: 32rpx;" bindtap="handleEdit"></text>
15 24  
16   - <!-- 立即打卡 -->
17   - <van-popup show="{{ showEdit }}" position="bottom" custom-style="height: 80%;" bind:close="closeEdit">
18   - <image class="temporary" src="/img/_check_in2.png" mode="widthFix" alt="" />
19   - <text class="temporary_box" style="width: 700rpx;height: 100rpx;position: absolute;top: 1452rpx;right: 32rpx;" bindtap="handleSubmit"></text>
20   - </van-popup>
21   - <!-- 打卡成果 -->
22   - <van-popup show="{{ showSuccess }}" custom-style="width:80%;height: 80%;" bind:close="colseSuccess">
23   - <image class="temporary" src="/img/_check_in4.png" mode="widthFix" alt="" />
24   - <text class="temporary_box" style="width: 200rpx;height: 60rpx;position: absolute;top: 800rpx;left: 200rpx;" bindtap="colseSuccess"></text>
  25 + <!--打卡-->
  26 + <van-popup show="{{ clockShow }}" position="bottom" custom-style="height: 60%;" round bind:close="closeClockShow">
  27 + <view class="pop_title">{{form.isRepair == 2? '补交打卡成果' : '提交打卡成果'}}</view>
  28 + <view class="pop_flex" wx:if="{{taskVo.hasData==1}}">
  29 + <view>提交数据</view>
  30 + <view class="pop_cell">
  31 + <view>
  32 + <van-cell-group>
  33 + <van-field value="{{ form.statisticsUnit }}" placeholder="请输入" border="{{ false }}" bind:change="onStatisChange" />
  34 + </van-cell-group>
  35 + </view>
  36 + <view class="pop_fz">{{taskVo.statisticsUnit}}</view>
  37 + </view>
  38 + </view>
  39 + <van-field value="{{ form.taskDesc }}" label="" type="textarea" placeholder="填写内容(如:已完成)" autosize border="{{ false }}" bind:change="onTaskDescChange"/>
  40 + <view class="pop_tip">
  41 + <van-uploader accept='image' file-list="{{ fileList }}" deletable="{{ true }}" bind:after-read="afterRead" bind:delete="delFile">
  42 + <view class="tip_item">
  43 + <image class="pop_pic" src="/img/answer/tp1.png" alt="" />
  44 + </view>
  45 + </van-uploader>
  46 + <!-- <image class="pop_pic" src="/img/answer/tp1.png" alt="" /> -->
  47 + </view>
  48 + <view class="pop_btn">
  49 + <van-button type="{{form.isRepair == 2? 'warning':'info'}}" block round bindtap="toCardTask">提 交</van-button>
  50 + </view>
25 51 </van-popup>
26 52 </view>
27 53 \ No newline at end of file
... ...
pages/index/punchDetail/punchDetail.wxss
1 1 /* pages/index/punchDetail/punchDetail.wxss */
  2 +/* pages/index/achievement/achievement.wxss */
  3 +.btn {
  4 + width: 20vw;
  5 + height: 20vw;
  6 + background-color: aqua;
  7 + font-size: 5vw;
  8 +}
  9 +.line_grey {
  10 + width: 90vw;
  11 + height: 1px;
  12 + background-color: #999;
  13 + margin: 10px 5vw 20px;
  14 +}
  15 +.card {
  16 + width: 92vw;
  17 + margin-left: 4vw;
  18 +}
  19 +.card_title {
  20 + font-size: 18px;
  21 + color: #556191;
  22 + margin: 15px 0;
  23 +}
  24 +.card_flex {
  25 + display: flex;
  26 +}
  27 +.flex_grey {
  28 + padding: 7px 10px;
  29 + box-sizing: border-box;
  30 + margin: 0 5px 10px 0;
  31 + font-size: 13px;
  32 + background-color: #F4F4F4;
  33 + color: #666666;
  34 + border-radius: 3px;
  35 +}
  36 +.card_context {
  37 + font-size: 16px;
  38 + margin: 10px 0;
  39 +}
  40 +.grey_font {
  41 + font-size: 14px;
  42 + color: #999999;
  43 + margin: 20px 0;
  44 +}
  45 +.grey_font_bottom {
  46 + margin-top: 5px;
  47 +}
  48 +.btn_box {
  49 + display: flex;
  50 + justify-content: space-around;
  51 + position: fixed;
  52 + bottom: 50px;
  53 + width: 100vw;
  54 +}
  55 +.pop_title {
  56 + font-size: 18px;
  57 + font-weight: bold;
  58 + text-align: center;
  59 + margin: 20px 0;
  60 +}
  61 +.pop_flex {
  62 + display: flex;
  63 + justify-content: space-between;
  64 + align-items: center;
  65 + padding: 0 20px;
  66 + box-sizing: border-box;
  67 +}
  68 +.pop_cell {
  69 + width: 40vw;
  70 + display: flex;
  71 + align-items: center;
  72 +}
  73 +.pop_fz {
  74 + width: 70px;
  75 +}
  76 +.pop_btn {
  77 + position: absolute;
  78 + bottom: 30px;
  79 + width: 90vw;
  80 + margin: 0 5vw;
  81 +}
  82 +.pop_tip {
  83 + position: absolute;
  84 + bottom: 90px;
  85 + width: 90vw;
  86 + margin: 0 5vw;
  87 +}
  88 +.pop_pic {
  89 + width: 70px;
  90 + height: 30px;
  91 +}
2 92 \ No newline at end of file
... ...
pages/index/rank/rank.js
1 1 // pages/index/rank/rank.js
  2 +import request from '../../../api/request.js'
  3 +import moment from 'moment';
2 4 Page({
3 5  
4 6 /**
5 7 * 页面的初始数据
6 8 */
7 9 data: {
  10 + rankList: [],
  11 + dayTime: '',
  12 + user: {
  13 + id: '',
  14 + userName: '',
  15 + nickname: '',
  16 + phone: "",
  17 + token: "",
  18 + headImg: ''
  19 + },
  20 + selfData: {
  21 + id: 0,
  22 + isOneSelf: 0,
  23 + signDayNum: 0,
  24 + signPercentage: "",
  25 + signRecordNum: 0,
  26 + userId: 0
  27 + }
8 28 },
9 29  
  30 + //排行榜列表
  31 + getRankList() {
  32 + request({
  33 + url: `/wx/task/getSignRank`,
  34 + method: 'post',
  35 + data: {
  36 + "page": 1,
  37 + "pageSize": 999,
  38 + "userId": wx.getStorageSync("userInfo_id")
  39 + },
  40 + }).then(res => {
  41 + if (res.code == 0) {
  42 + this.setData({
  43 + rankList: res.rows
  44 + })
  45 + console.log(this.data.rankList)
  46 + } else {
  47 + wx.showToast({
  48 + title: res.msg,
  49 + icon: 'none',
  50 + duration: 1500
  51 + })
  52 + }
  53 + })
  54 + },
  55 + //去打卡
  56 + toOpen() {
  57 + wx.navigateTo({
  58 + url: '/pages/index/index',
  59 + })
  60 + },
  61 + //获取个人
  62 + getSelf() {
  63 + request({
  64 + url: `/wx/task/getOneSelf`,
  65 + method: 'get',
  66 + data: {
  67 + "userId": wx.getStorageSync("userInfo_id")
  68 + },
  69 + }).then(res => {
  70 + if (res.code == 0) {
  71 + this.setData({
  72 + selfData: res.data
  73 + })
  74 + } else {
  75 + wx.showToast({
  76 + title: res.msg,
  77 + icon: 'none',
  78 + })
  79 + }
  80 + })
  81 + },
10 82 /**
11 83 * 生命周期函数--监听页面加载
12 84 */
13 85 onLoad(options) {
14   -
  86 +
15 87 },
16 88 // 统一返回
17 89 handleBack() {
18 90 wx.navigateBack()
19 91 },
20   - /**
21   - * 用户点击右上角分享
22   - */
23   - onShareAppMessage() {
24   -
  92 + onShow() {
  93 + this.setData({
  94 + 'user': wx.getStorageSync('userInfo')
  95 + })
  96 + this.setData({
  97 + "dayTime": moment(new Date().getTime()).format('YYYY-MM-DD')
  98 + })
  99 + this.getSelf()
  100 + this.getRankList()
25 101 }
26 102 })
27 103 \ No newline at end of file
... ...
pages/index/rank/rank.json
1 1 {
2 2 "usingComponents": {
3   - "van-icon": "@vant/weapp/icon/index"
  3 + "van-icon": "@vant/weapp/icon/index",
  4 + "van-button": "@vant/weapp/button/index"
4 5 },
5 6 "navigationStyle": "custom"
6 7 }
7 8 \ No newline at end of file
... ...
pages/index/rank/rank.wxml
1 1 <!--pages/index/rank/rank.wxml-->
2   -<view class="punch_detail">
3   - <!-- 顶部统一返回 -->
4   - <view class="navigation_back" bindtap="handleBack">
5   - <van-icon name="arrow-left" />
6   - </view>
7   - <image class="temporary" src="/img/_rank.png" mode="widthFix" alt="" />
  2 +<!-- <view class="rank" style="background-image: url('https://szyundisk.oss-cn-hangzhou.aliyuncs.com/null/5f055580-1341-4c52-9154-c3b125c1107a.png')"> -->
  3 +<view class="rank" style="background-image: url('https://szyundisk.oss-cn-hangzhou.aliyuncs.com/AdmissionsManageSys/54ec1f3f-dbb4-4660-ba24-4a6731e88def.png')">
  4 + <view class="rank_time">更新时间:{{dayTime}}</view>
  5 + <view class="white_box">
  6 + <view class="title_box">
  7 + <view class="title_pic">
  8 + <image class="pic" src="{{user.headImg}}" alt="" />
  9 + {{user.userName != null ? user.userName : user.nickname}}
  10 + </view>
  11 + <view class="red_title">已坚持{{selfData.signDayNum}}天</view>
  12 + <view class="red_title">{{selfData.signRecordNum}}次</view>
  13 + </view>
  14 + <view class="grey_title">
  15 + <view class="table_L">
  16 + <view>排名</view>
  17 + <view>姓名</view>
  18 + </view>
  19 + <view>打卡数</view>
  20 + </view>
8 21  
  22 + <view class="table_item" wx:for="{{ rankList }}" wx:key="index" wx:for-item="value">
  23 + <view class="table_L">
  24 + <image wx:if="{{index == 0}}" class="tem_pic" src="/img/answer/1.png" alt="" />
  25 + <image wx:if="{{index == 1}}" class="tem_pic" src="/img/answer/2.png" alt="" />
  26 + <image wx:if="{{index == 2}}" class="tem_pic" src="/img/answer/3.png" alt="" />
  27 + <view class="tem_pic" wx:if="{{index != 0 && index != 1 && index != 2}}">{{index + 1}}</view>
  28 + <view>{{value.userName}}</view>
  29 + </view>
  30 + <view class="table_R">
  31 + <view class="grey_R">已坚持{{value.signDayNum}}天</view>
  32 + <view>{{value.signRecordNum}}</view>
  33 + </view>
  34 + </view>
  35 + </view>
  36 +
  37 + <view class="btn">
  38 + <van-button type="info" block round bindtap="toOpen">去打卡</van-button>
  39 + </view>
9 40 </view>
10 41 \ No newline at end of file
... ...
pages/index/rank/rank.wxss
1 1 /* pages/index/rank/rank.wxss */
  2 +.rank {
  3 + position: absolute;
  4 + width: 100vw;
  5 + min-height: 100vh;
  6 + background-size: 100% 100%;
  7 + padding: 0 5vw;
  8 + box-sizing: border-box;
  9 +}
  10 +.rank_time {
  11 + font-size: 4.4vw;
  12 + color: #fff;
  13 + opacity: 0.8;
  14 + margin-top: 125px;
  15 + margin-left: 2vw;
  16 +}
  17 +.white_box{
  18 + width: 90vw;
  19 + min-height: 72vh;
  20 + margin-top: 40px;
  21 + background-color: #fff;
  22 + border-radius: 4vw;
  23 + padding: 7vw 5vw;
  24 + box-sizing: border-box;
  25 +}
  26 +.title_box {
  27 + display: flex;
  28 + justify-content: space-between;
  29 + align-items: center;
  30 + font-size: 3.9vw;
  31 + font-weight: bold;
  32 + padding: 30px 5vw;
  33 + box-sizing: border-box;
  34 + border-radius: 5vw;
  35 + box-shadow: 1px 1px 1px 1px rgb(207, 206, 206);
  36 +}
  37 +.title_pic {
  38 + display: flex;
  39 + align-items: center;
  40 +}
  41 +.pic {
  42 + width: 25px;
  43 + height: 25px;
  44 + border-radius: 25px;
  45 + margin-right: 7px;
  46 +}
  47 +.red_title {
  48 + color: #FD676A;
  49 +}
  50 +.grey_title {
  51 + margin: 30px 0;
  52 + font-size: 4.5vw;
  53 + color: #999;
  54 + display: flex;
  55 + justify-content: space-between;
  56 +}
  57 +.table_L{
  58 + width: 28vw;
  59 + display: flex;
  60 + justify-content: space-between;
  61 + align-items: center;
  62 +}
  63 +.L_box {
  64 + width: 50px;
  65 +}
  66 +
  67 +.table_item {
  68 + margin: 20px 0;
  69 + font-size: 4vw;
  70 + color: #333;
  71 + display: flex;
  72 + justify-content: space-between;
  73 + align-items: center;
  74 +}
  75 +.table_R {
  76 + width: 45vw;
  77 + display: flex;
  78 + justify-content: space-between;
  79 + align-items: center;
  80 +}
  81 +.grey_R {
  82 + color:#999;
  83 + font-size: 3.9vw;
  84 +}
  85 +.tem_pic {
  86 + width: 22px;
  87 + height: 28px;
  88 + text-align: center;
  89 +}
  90 +.btn {
  91 + position: fixed;
  92 + bottom: 50px;
  93 + width: 82vw;
  94 + margin-left: 4vw;
  95 +}
2 96 \ No newline at end of file
... ...
pages/login/codeLogin/codeLogin.js
1 1 // pages/login/codeLogin/codeLogin.js
2   -var app = getApp();
  2 +// var app = getApp();
  3 +var api = 'https://proxy.shunzhi.net/';
  4 +var api_card = 'https://proxy.shunzhi.net/card/';
  5 +var appid = 'wx186236fdcd93edcc';
3 6 var util = require('../../../utils/md5.js')
4 7 import request from '../../../api/request.js'
5 8 Page({
... ... @@ -21,6 +24,7 @@ Page({
21 24 path: '', //登录后跳转页面
22 25 modelShow: false, //完善信息
23 26 phone: '', //getUserInfo获取到的手机号
  27 + openId: ''
24 28 },
25 29 onLoad: function (options) {
26 30 console.log('登录页options:', options)
... ... @@ -69,20 +73,25 @@ Page({
69 73 })
70 74 }
71 75 request({
72   - url: `h5/user/Oneclicklogin`,
73   - method: 'get',
  76 + url: `/wx/app/oneClickLogin/`+ appid,
  77 + method: 'post',
74 78 data: {
75 79 "encryptedData": this.data.encryptedData,
76   - "session_key": this.data.session_key,
  80 + "sessionKey": this.data.session_key,
77 81 "iv": this.data.iv,
  82 + "openId": this.data.openId
78 83 },
79 84 }).then(res => {
80   - if (res.success) {
  85 + if (res.code == 0) {
81 86 if (res.data) {
82 87 this.setData({
83 88 phone: res.data.phone
84 89 }, () => {
85   - this.getUserInfo()
  90 + wx.setStorageSync('userInfo', res.data)
  91 + wx.setStorageSync('userInfo_id', res.data.id)
  92 + wx.switchTab({
  93 + url: '/pages/mine/index',
  94 + })
86 95 })
87 96 } else {
88 97 wx.showToast({
... ... @@ -107,36 +116,39 @@ Page({
107 116 }
108 117 },
109 118 getUserInfo() {
110   - let that = this
111   - request({
112   - url: `h5/user/getuserInfoNew`,
113   - method: 'get',
114   - data: {
115   - // PhoneName: '13355752969'
116   - PhoneName: this.data.phone
117   - },
118   - }).then((res) => {
119   - if (res.success) {
120   - if (res.data) {
121   - wx.setStorageSync('userInfo', res.data)
122   - wx.setStorageSync('showModal', '')
  119 + // let that = this
  120 + // request({
  121 + // url: `h5/user/getuserInfoNew`,
  122 + // method: 'get',
  123 + // data: {
  124 + // // PhoneName: '13355752969'
  125 + // PhoneName: this.data.phone
  126 + // },
  127 + // }).then((res) => {
  128 + // if (res.success) {
  129 + // if (res.data) {
  130 + // wx.setStorageSync('userInfo', res.data)
  131 + // wx.setStorageSync('showModal', '')
123 132  
124   - }
125   - }
126   - })
  133 + // }
  134 + // }
  135 + // })
127 136 },
128   - getOpenId() {
  137 + getOpenId() {
129 138 return request({
130   - url: `h5/MyVoluntary/GetOpenId`,
  139 + url: `/wx/app/getOpenId/wx186236fdcd93edcc`,
131 140 method: 'get',
132 141 data: {
133 142 code: this.data.loginCode
134 143 },
135 144 }).then(res2 => {
136   - // console.log(res2.data);
137 145 this.setData({
138   - session_key: JSON.parse(res2.data).session_key
  146 + session_key: res2.data.sessionKey
139 147 })
  148 + this.setData({
  149 + openId: res2.data.openid
  150 + })
  151 + console.log(this.data);
140 152 })
141 153 },
142 154 bindUserName: function (e) {
... ... @@ -181,16 +193,17 @@ Page({
181 193 wx.showLoading({
182 194 title: '请求中',
183 195 })
184   - wx.request({
185   - url: api + 'h5/MyVoluntary/CheckCodeIsRight',
  196 + wx.request({
  197 + url: api_card + '/wx/app/loginCode',
186 198 data: {
187   - captcha: code,
188   - mobile: username
  199 + code: code,
  200 + phone: username
189 201 },
190   - method: 'get',
  202 + method: 'post',
191 203 success: (res) => {
192 204 wx.hideLoading();
193 205 if (res.data.success) {
  206 + console.log(res.data)
194 207 if (res.data.data) {
195 208 this.setData({
196 209 phone: res.data.data.phone
... ... @@ -306,7 +319,7 @@ Page({
306 319 }
307 320 },
308 321 getPhoneNumber(e) {
309   - // console.log(e.detail)
  322 + console.log(e.detail)
310 323 if (e.detail.errMsg == 'getPhoneNumber:ok') {
311 324 this.setData({
312 325 encryptedData: e.detail.encryptedData,
... ... @@ -315,7 +328,6 @@ Page({
315 328 this.login()
316 329 })
317 330 }
318   -
319 331 },
320 332 //去查看协议
321 333 toProtocol() {
... ... @@ -331,7 +343,7 @@ Page({
331 343 },
332 344 goIndex() {
333 345 wx.switchTab({
334   - url: '/pages/index/index',
  346 + url: '/pages/index/rank/rank',
335 347 })
336 348 },
337 349  
... ...
pages/login/codeLogin/codeLogin.wxss
... ... @@ -126,4 +126,8 @@
126 126  
127 127 .footer_tips navigator {
128 128 display: inline-flex;
  129 +}
  130 +
  131 +.van-cell {
  132 + border: none;
129 133 }
130 134 \ No newline at end of file
... ...
pages/login/loginNew/loginNew.js 0 → 100644
... ... @@ -0,0 +1,167 @@
  1 +// pages/login/loginNew/loginNew.js
  2 +import request from '../../../api/request.js'
  3 +var appid = 'wx186236fdcd93edcc';
  4 +Page({
  5 +
  6 + /**
  7 + * 页面的初始数据
  8 + */
  9 + data: {
  10 + checked: true,
  11 + session_key: '',
  12 + openId: '',
  13 + encryptedData: '',
  14 + iv: '',
  15 + phone: ''
  16 + },
  17 + //多选框
  18 + onChange(e) {
  19 + this.setData({
  20 + checked: e.detail
  21 + })
  22 + },
  23 + //获取session_key
  24 + getOpenId() {
  25 + return request({
  26 + url: `/wx/app/getOpenId/wx186236fdcd93edcc`,
  27 + method: 'get',
  28 + data: {
  29 + code: this.data.loginCode
  30 + },
  31 + }).then(res2 => {
  32 + this.setData({
  33 + session_key: res2.data.sessionKey
  34 + })
  35 + this.setData({
  36 + openId: res2.data.openid
  37 + })
  38 + console.log(this.data);
  39 + })
  40 + },
  41 + getPhoneNumber(e) {
  42 + console.log('?')
  43 + if(!this.data.checked) {
  44 + return wx.showToast({title: '请先阅读并同意用户协议和隐私协议',icon: 'none'})
  45 + }
  46 + console.log(e.detail)
  47 + if (e.detail.errMsg == 'getPhoneNumber:ok') {
  48 + this.setData({
  49 + encryptedData: e.detail.encryptedData,
  50 + iv: e.detail.iv,
  51 + }, () => {
  52 + this.login()
  53 + })
  54 + }
  55 + },
  56 + login() {
  57 + if (!this.data.encryptedData || !this.data.session_key || !this.data.iv) {
  58 + wx.showToast({
  59 + title: '一键登陆失败,请重试',
  60 + icon: 'none',
  61 + duration: 2000
  62 + })
  63 + }
  64 + request({
  65 + url: `/wx/app/oneClickLogin/`+ appid,
  66 + method: 'post',
  67 + data: {
  68 + "encryptedData": this.data.encryptedData,
  69 + "sessionKey": this.data.session_key,
  70 + "iv": this.data.iv,
  71 + "openId": this.data.openId
  72 + },
  73 + }).then(res => {
  74 + if (res.code == 0) {
  75 + if (res.data) {
  76 + this.setData({
  77 + phone: res.data.phone
  78 + }, () => {
  79 + wx.setStorageSync('userInfo', res.data)
  80 + wx.setStorageSync('userInfo_id', res.data.id)
  81 + if(res.data.hasRecord == 1) {
  82 + wx.switchTab({
  83 + url: '/pages/index/rank/rank',
  84 + })
  85 + }else {
  86 + wx.switchTab({
  87 + url: '/pages/mine/index',
  88 + })
  89 + }
  90 + })
  91 + } else {
  92 + wx.showToast({
  93 + title: '一键登陆失败,请重试',
  94 + icon: 'none',
  95 + duration: 2000
  96 + })
  97 + }
  98 + }
  99 + })
  100 + },
  101 + /**
  102 + * 生命周期函数--监听页面加载
  103 + */
  104 + onLoad() {
  105 + wx.login({
  106 + success: (res) => {
  107 + if (res.code) {
  108 + this.setData({
  109 + loginCode: res.code
  110 + })
  111 + this.getOpenId()
  112 + } else {
  113 + console.log('登录失败!' + res.errMsg)
  114 + }
  115 + }
  116 + })
  117 + },
  118 +
  119 + /**
  120 + * 生命周期函数--监听页面初次渲染完成
  121 + */
  122 + onReady() {
  123 +
  124 + },
  125 +
  126 + /**
  127 + * 生命周期函数--监听页面显示
  128 + */
  129 + onShow() {
  130 +
  131 + },
  132 +
  133 + /**
  134 + * 生命周期函数--监听页面隐藏
  135 + */
  136 + onHide() {
  137 +
  138 + },
  139 +
  140 + /**
  141 + * 生命周期函数--监听页面卸载
  142 + */
  143 + onUnload() {
  144 +
  145 + },
  146 +
  147 + /**
  148 + * 页面相关事件处理函数--监听用户下拉动作
  149 + */
  150 + onPullDownRefresh() {
  151 +
  152 + },
  153 +
  154 + /**
  155 + * 页面上拉触底事件的处理函数
  156 + */
  157 + onReachBottom() {
  158 +
  159 + },
  160 +
  161 + /**
  162 + * 用户点击右上角分享
  163 + */
  164 + onShareAppMessage() {
  165 +
  166 + }
  167 +})
0 168 \ No newline at end of file
... ...
pages/login/loginNew/loginNew.json 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +{
  2 + "usingComponents": {
  3 + "van-button": "@vant/weapp/button/index",
  4 + "van-checkbox": "@vant/weapp/checkbox/index",
  5 + "van-checkbox-group": "@vant/weapp/checkbox-group/index"
  6 + },
  7 + "navigationBarTitleText": "登录"
  8 +}
0 9 \ No newline at end of file
... ...
pages/login/loginNew/loginNew.wxml 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +<!--pages/login/loginNew/loginNew.wxml-->
  2 +<view>
  3 + <view class="box">
  4 + <view class="img_box">
  5 + <image class="pic" src="/img/login_img.png" alt="" />
  6 + </view>
  7 + <view class="box_title">Hey</view>
  8 + <view class="box_grey">欢迎使用自主学习之旅~</view>
  9 + </view>
  10 + <view class="fied_box">
  11 + <view>
  12 + <van-button type="info" block round open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">登 录</van-button>
  13 + </view>
  14 + <view class="small_font">
  15 + <van-checkbox value="{{ checked }}" shape="square" bind:change="onChange" icon-size='15'>
  16 + <view class="small_font_tip">
  17 + 已同意 <navigator url="../protocol/protocol"><text class="blue_font"> 用户协议 </text></navigator>和<navigator url="../policy/policy"><text class="blue_font"> 隐私协议 </text></navigator>
  18 + </view>
  19 + </van-checkbox>
  20 + </view>
  21 + <van-notify id="van-notify" />
  22 + </view>
  23 +</view>
0 24 \ No newline at end of file
... ...
pages/login/loginNew/loginNew.wxss 0 → 100644
... ... @@ -0,0 +1,46 @@
  1 +/* pages/login/loginNew/loginNew.wxss */
  2 +.box {
  3 + display: flex;
  4 + justify-content: center;
  5 + flex-wrap: wrap;
  6 +}
  7 +.img_box {
  8 + width: 60vw;
  9 + height: 60vw;
  10 + margin: 100px 0 30px;
  11 +}
  12 +.pic {
  13 + width: 100%;
  14 + height: 100%;
  15 +}
  16 +.box_title {
  17 + width: 100%;
  18 + text-align: center;
  19 + margin: 15px 0;
  20 + font-weight: bold;
  21 +}
  22 +.box_grey {
  23 + width: 100%;
  24 + text-align: center;
  25 + color: #999;
  26 +}
  27 +.fied_box {
  28 + position: fixed;
  29 + bottom: 40px;
  30 + width: 100%;
  31 + padding: 0 30px;
  32 + box-sizing: border-box;
  33 +}
  34 +.small_font {
  35 + display: flex;
  36 + justify-content: center;
  37 + font-size: 12px;
  38 + margin: 10px 0 0;
  39 +}
  40 +.small_font_tip {
  41 + display: flex;
  42 +}
  43 +.blue_font {
  44 + color: #3578F9;
  45 + text-decoration:underline;
  46 +}
0 47 \ No newline at end of file
... ...
pages/login/policy/policy.json
1 1 {
2   - "usingComponents": {}
  2 + "usingComponents": {},
  3 + "navigationBarTitleText": "隐私协议"
3 4 }
4 5 \ No newline at end of file
... ...
pages/login/protocol/protocol.json
1 1 {
2   - "usingComponents": {}
  2 + "usingComponents": {},
  3 + "navigationBarTitleText": "用户协议"
3 4 }
4 5 \ No newline at end of file
... ...
pages/mine/index.js
... ... @@ -6,7 +6,9 @@ Page({
6 6 * 页面的初始数据
7 7 */
8 8 data: {
9   -
  9 + user_name: '',
  10 + user_phone: '',
  11 + user_img: '',
10 12 },
11 13 // 打卡记录
12 14 handleRecord(){
... ... @@ -14,13 +16,26 @@ Page({
14 16 url: '/pages/mine/record/record',
15 17 })
16 18 },
17   -// 退出登录
  19 + // 退出登录
18 20 handleLoginOut(){
  21 + wx.clearStorage()
  22 + wx.clearStorageSync()
19 23 wx.navigateTo({
20   - url: '/pages/login/codeLogin/codeLogin',
  24 + url: '/pages/login/loginNew/loginNew',
21 25 })
22 26 },
23 27 /**
  28 + * 生命周期函数--监听页面加载
  29 + */
  30 + onLoad(options) {
  31 + let userInfo = wx.getStorageSync('userInfo')
  32 + this.setData({
  33 + "user_name": userInfo.userName || userInfo.nickname,
  34 + "user_phone": userInfo.phone,
  35 + 'user_img':userInfo.headImg,
  36 + })
  37 + },
  38 + /**
24 39 * 用户点击右上角分享
25 40 */
26 41 onShareAppMessage: function () {
... ...
pages/mine/index.wxml
1   -<view class="mine">
2   - <image class="temporary" src="../../img/_mine.png" mode="widthFix" alt="" />
3   - <!-- 打卡记录 -->
4   - <text class="temporary_box" style="width: 340rpx;height: 160rpx;position: absolute;top: 340rpx;left: 32rpx;" bindtap="handleRecord"></text>
5   - <!-- 退出登录 -->
6   - <text class="temporary_box" style="width: 340rpx;height: 160rpx;position: absolute;top: 340rpx;right: 32rpx;" bindtap="handleLoginOut"></text>
7   -
  1 +<view class="mine" style="background-image: url('https://szyundisk.oss-cn-hangzhou.aliyuncs.com/null/89741dbf-cc76-45a6-a3c9-a210eb7deeef.png')">
  2 + <view class="title">
  3 + <view>
  4 + <image class="pic" src="{{user_img}}" alt="" />
  5 + </view>
  6 + <view class="title_box">
  7 + <view class="title_name">{{user_name}}</view>
  8 + <view class="grey_title">{{user_phone}}</view>
  9 + </view>
  10 + </view>
  11 + <view class="flex_card">
  12 + <view class="card_item" bindtap="handleRecord">
  13 + <view><image class="card_pic" src="/img/answer/dkjl.png" alt="" /></view>
  14 + <view class="item_font">创建打卡</view>
  15 + </view>
  16 + <view class="grey_line"></view>
  17 + <view class="card_item" bindtap="handleLoginOut">
  18 + <view><image class="card_pic" src="/img/answer/back.png" alt="" /></view>
  19 + <view class="item_font">退出登录</view>
  20 + </view>
  21 + </view>
8 22 </view>
... ...
pages/mine/index.wxss
... ... @@ -0,0 +1,59 @@
  1 + .mine {
  2 + position: absolute;
  3 + width: 100vw;
  4 + min-height: 40vh;
  5 + background-size: 100% 100%;
  6 + padding: 140px 5vw 0;
  7 + box-sizing: border-box;
  8 + }
  9 + .title {
  10 + display: flex;
  11 + }
  12 + .pic {
  13 + width: 60px;
  14 + height: 60px;
  15 + border-radius: 60px;
  16 + }
  17 + .title_box {
  18 + margin-left: 20px;
  19 + display: flex;
  20 + align-content: space-between;
  21 + flex-wrap: wrap;
  22 + padding: 4px 0;
  23 + box-sizing: border-box;
  24 + }
  25 + .title_name {
  26 + font-size: 18px;
  27 + font-weight: bold;
  28 + }
  29 + .grey_title {
  30 + width: 100%;
  31 + font-size: 14px;
  32 + color: #999;
  33 + }
  34 + .flex_card {
  35 + display: flex;
  36 + justify-content: space-between;
  37 + padding: 20px 50px;
  38 + box-sizing: border-box;
  39 + box-shadow: 1px 1px 1px 1px rgb(224, 224, 224);
  40 + margin: 40px 0;
  41 + background-color: #fff;
  42 + border-radius: 20px;
  43 + }
  44 + .card_item {
  45 + text-align: center;
  46 + }
  47 + .card_pic {
  48 + width: 30px;
  49 + height: 30px;
  50 +}
  51 +.item_font {
  52 + margin-top: 10px;
  53 + color:#5A6694
  54 + }
  55 + .grey_line {
  56 + width: 1px ;
  57 + height: 60px;
  58 + background-color: #999;
  59 + }
0 60 \ No newline at end of file
... ...
pages/mine/record/record.js
1 1 // pages/index/record/record.js
  2 +import request from '../../../api/request.js'
2 3 Page({
3 4  
4 5 /**
5 6 * 页面的初始数据
6 7 */
7 8 data: {
8   - tabindex: 1
  9 + tabindex: 0,
  10 + showAdd: false,
  11 + taskList: [],
  12 +
  13 + tempList: [
  14 + // {name:'自定义模板',url: '/img/answer/zdy.png'},
  15 + // {name:'英语模板',url: '/img/answer/english.png'},
  16 + // {name:'数学模板',url: '/img/answer/math.png'},
  17 + ]
9 18 },
10 19  
11   - /**
12   - * 生命周期函数--监听页面加载
13   - */
14   - onLoad(options) {
  20 + //打卡记录列表
  21 + getTaskList() {
  22 + request({
  23 + url: `/wx/task/cardTaskList`,
  24 + method: 'post',
  25 + data: {
  26 + "oneselfFlag": this.data.tabindex + 1,
  27 + "page": 1,
  28 + "pageSize": 999,
  29 + "userId": wx.getStorageSync("userInfo_id")
  30 + },
  31 + }).then(res => {
  32 + if (res.code == 0) {
  33 + this.setData({
  34 + taskList: res.rows
  35 + })
  36 + } else {
  37 + wx.showToast({
  38 + title: res.msg,
  39 + icon: 'none',
  40 + duration: 1500
  41 + })
  42 + }
  43 + })
  44 + },
  45 +
  46 + //模板列表
  47 + getTempList() {
  48 + request({
  49 + url: `/wx/temp/tempList`,
  50 + method: 'post',
  51 + data: {},
  52 + }).then(res => {
  53 + if (res.code == 0) {
  54 + this.setData({
  55 + tempList: res.data
  56 + })
  57 + } else {
  58 + wx.showToast({
  59 + title: res.msg,
  60 + icon: 'none',
  61 + duration: 1500
  62 + })
  63 + }
  64 + })
  65 + },
15 66  
  67 + //打卡
  68 + toShow(e) {
  69 + this.getTempList()
  70 + this.setData({
  71 + showAdd: true
  72 + })
16 73 },
17   - handleTab1() {
  74 + //关闭
  75 + closeAdd() {
18 76 this.setData({
19   - tabindex: 1
  77 + showAdd: false
  78 + })
  79 + },
  80 + //选择模板
  81 + toPunch(e) {
  82 + let obj = e.currentTarget.dataset
  83 + let id = obj.value ? obj.value.id : 0
  84 + wx.navigateTo({
  85 + url: `../../index/newPunch/newPunch?tempId=${id}`
20 86 })
21 87 },
22   - handleTab2() {
  88 + /**
  89 + * 生命周期函数--监听页面加载
  90 + */
  91 + onLoad(options) {
  92 + this.getTaskList()
  93 + },
  94 + //切换
  95 + handleTab(e) {
23 96 this.setData({
24   - tabindex: 2
  97 + tabindex: e.detail.index
25 98 })
  99 + this.getTaskList()
26 100 },
27 101 // 打卡成果
28   - handleAchievement(){
  102 + handleAchievement(e) {
29 103 wx.navigateTo({
30   - url: '/pages/index/achievement/achievement',
  104 + url: '/pages/index/achievement/achievement?valueId=' + e.currentTarget.dataset.valueid,
31 105 })
32 106 },
33 107 // 去打卡
34   - handleDetail(){
  108 + handleDetail(e) {
  109 + let eData = e.currentTarget.dataset
35 110 wx.navigateTo({
36   - url: '/pages/index/punchDetail/punchDetail',
  111 + url: '/pages/index/punchDetail/punchDetail?valueId=' + eData.valueid,
37 112 })
38 113 },
39 114 // 统一返回
... ...
pages/mine/record/record.json
1 1 {
2 2 "usingComponents": {
3   - "van-icon": "@vant/weapp/icon/index"
  3 + "van-icon": "@vant/weapp/icon/index",
  4 + "van-tab": "@vant/weapp/tab/index",
  5 + "van-tabs": "@vant/weapp/tabs/index",
  6 + "van-popup": "@vant/weapp/popup/index"
4 7 },
5   - "navigationStyle": "custom"
  8 + "navigationBarTitleText":"打卡记录"
6 9 }
7 10 \ No newline at end of file
... ...
pages/mine/record/record.wxml
1 1 <!--pages/index/record/record.wxml-->
2 2 <view class="punch_detail">
3   - <!-- 顶部统一返回 -->
4   - <view class="navigation_back" bindtap="handleBack">
5   - <van-icon name="arrow-left" />
  3 + <view>
  4 + <van-tabs active="{{ tabindex }}" bind:change="handleTab" line-height='0' title-inactive-color='#999' title-active-color='#556191'>
  5 + <van-tab title="我发布的"></van-tab>
  6 + <van-tab title="我的打卡"></van-tab>
  7 + </van-tabs>
6 8 </view>
7   - <!-- 两个tab -->
8   - <text class="temporary_box" style="width: 320rpx;height: 80rpx;position: absolute;top: 160rpx;left: 32rpx;" bindtap="handleTab1"></text>
9   - <text class="temporary_box" style="width: 320rpx;height: 80rpx;position: absolute;top: 160rpx;right: 32rpx;" bindtap="handleTab2"></text>
10   - <!-- 打卡成果 -->
11   - <text class="temporary_box" wx:if="{{tabindex==1}}" style="width: 700rpx;height: 100rpx;position: absolute;top: 988rpx;left: 32rpx;" bindtap="handleAchievement"></text>
12   - <!-- 打卡成果 -->
13   - <text class="temporary_box" wx:if="{{tabindex==2}}" style="width: 350rpx;height: 100rpx;position: absolute;top: 920rpx;left: 20rpx;" bindtap="handleAchievement"></text>
14   - <!-- 去打卡 -->
15   - <text class="temporary_box" wx:if="{{tabindex==2}}" style="width: 350rpx;height: 100rpx;position: absolute;top: 920rpx;right: 20rpx;" bindtap="handleDetail"></text>
16   -
17   - <image class="temporary" hidden="{{tabindex==2}}" src="/img/_my_punch1.png" mode="widthFix" alt="" />
18   - <image class="temporary" hidden="{{tabindex==1}}" src="/img/_my_punch2.png" mode="widthFix" alt="" />
  9 + <view class="bck">
  10 + <view class="grey_font">进行中打卡</view>
  11 + <view class="card" wx:for="{{taskList}}" wx:key="index" wx:for-item="value">
  12 + <view class="card_title">
  13 + <view class="title_L">
  14 + <image class="title_pic" src="/img/answer/bj.png" alt="" />
  15 + </view>
  16 + <view class="title_R">
  17 + <view>{{value.taskTitle}}</view>
  18 + <view class="grey_font">开始时间 {{value.startDate}}</view>
  19 + </view>
  20 + </view>
  21 + <view class="day_font" >{{value.taskDesc}}</view>
  22 + <!-- <view class="day_font2">已坚持打卡
  23 + <text class="day_font2_large">1/50 </text>天
  24 + </view> -->
  25 + <view>
  26 + <van-progress percentage="50" color='#3F5EFF' stroke-width="13" pivot-text=' ' />
  27 + </view>
  28 + <view class="flex_font">
  29 + <text class="grey_flex">打卡频次:</text>
  30 + {{value.taskFrequency}}
  31 + </view>
  32 + <view class="flex_font" wx:if="{{value.submitCondition != null}}">
  33 + <text class="grey_flex">打卡要求:</text>
  34 + {{ value.submitCondition == '无限制' ? '无限制': '需要 '+value.submitCondition}}
  35 + </view>
  36 + <view class="flex_font">
  37 + <view class="grey_flex">其他:</view>
  38 + {{value.allowRepairCard == 1 ? '允许补卡': '不允许补卡'}}
  39 + </view>
  40 + <view class="grey_line"></view>
  41 + <view class="blue_font" wx:if="{{tabindex == 0}}">
  42 + <view bindtap="handleAchievement" data-valueId="{{value.id}}">我的成果</view>
  43 + <view class="blue_line"></view>
  44 + <view bindtap="handleDetail" data-valueId="{{value.id}}">去打卡</view>
  45 + </view>
  46 + <view class="blue_font" wx:else>
  47 + <view bindtap="handleAchievement" data-valueId="{{value.id}}">打卡成果</view>
  48 + </view>
  49 + </view>
19 50  
  51 + <view class="blue_tip" bindtap="toShow">
  52 + <image class="img_tip" src="/img/answer/add.png" alt="" />
  53 + </view>
  54 + </view>
  55 +
  56 + <!-- 弹窗 -->
  57 + <van-popup show="{{ showAdd }}" round position="bottom" custom-style="height: 60%;" bind:close="closeAdd">
  58 + <view class="pop_card">
  59 + <view class="pop_title">选择模板</view>
  60 + <view class="tem_box">
  61 + <view class="tem_item" bindtap="toPunch" >
  62 + <image class="tem_pic" src="/img/answer/zdy.png" alt="" />
  63 + <view class="tem_font">自定义模板</view>
  64 + </view>
  65 + <view class="tem_item" wx:for="{{tempList}}" wx:key="index" wx:for-item="value" bindtap="toPunch" data-value="{{value}}">
  66 + <image class="tem_pic" src="{{value.taskBackground}}" alt="" />
  67 + <view class="tem_font">{{value.taskTitle}}</view>
  68 + </view>
  69 + </view>
  70 + </view>
  71 + </van-popup>
20 72 </view>
21 73 \ No newline at end of file
... ...
pages/mine/record/record.wxss
1 1 /* pages/index/record/record.wxss */
  2 +.punch_detail {
  3 + position: absolute;
  4 + width: 100vw;
  5 + height: 100vh;
  6 + background-color: #F5F6FA;
  7 +}
  8 +
  9 +.bck {
  10 + padding: 20px 4vw;
  11 + box-sizing: border-box;
  12 +}
  13 +
  14 +.grey_font {
  15 + width: 100%;
  16 + color: #999;
  17 + font-size: 14px;
  18 + margin-bottom: 15px;
  19 +}
  20 +
  21 +/**/
  22 +
  23 +.card {
  24 + width: 92vw;
  25 + background-color: #fff;
  26 + border-radius: 8vw;
  27 + padding: 8vw;
  28 + margin-bottom: 30px;
  29 + box-sizing: border-box;
  30 + box-shadow: 1px 1px 1px 1px rgb(228, 228, 228);
  31 +}
  32 +
  33 +.card_title {
  34 + display: flex;
  35 +}
  36 +
  37 +.title_L {
  38 + flex-shrink: 0;
  39 + width: 50px;
  40 + height: 50px;
  41 + margin-right: 15px;
  42 +}
  43 +
  44 +.title_pic {
  45 + width: 100%;
  46 + height: 100%;
  47 +}
  48 +
  49 +.title_R {
  50 + height: 65px;
  51 + display: flex;
  52 + align-content: space-between;
  53 + flex-wrap: wrap;
  54 + font-size: 4.6vw;
  55 +}
  56 +
  57 +/* .grey_font {
  58 + width: 100%;
  59 + color: #999;
  60 + font-size: 3.8vw;
  61 +} */
  62 +
  63 +.day_font {
  64 + margin: 10px 0 20px;
  65 + letter-spacing: 0.2vw;
  66 + font-size: 4vw;
  67 +}
  68 +
  69 +.day_font2 {
  70 + margin: 20px 0;
  71 + letter-spacing: 0.2vw;
  72 + font-size: 3.8vw;
  73 +}
  74 +
  75 +.day_font2_large {
  76 + font-size: 5.5vw;
  77 + font-weight: bold;
  78 +}
  79 +
  80 +.flex_font {
  81 + font-size: 3.5vw;
  82 + margin: 20px 0;
  83 + display: flex;
  84 +}
  85 +
  86 +.grey_flex {
  87 + width: 80px;
  88 + color: #999;
  89 +}
  90 +
  91 +.grey_line {
  92 + width: 100%;
  93 + height: 1px;
  94 + background-color: #EAEAEA;
  95 +}
  96 +
  97 +.blue_font {
  98 + display: flex;
  99 + justify-content: space-around;
  100 + margin-top: 15px;
  101 + font-size: 4.1vw;
  102 + color: #458EF8;
  103 + font-weight: 540;
  104 +}
  105 +
  106 +.blue_line {
  107 + width: 1px;
  108 + height: 15px;
  109 + background-color: #EAEAEA;
  110 +}
  111 +
  112 +.blue_tip {
  113 + position: fixed;
  114 + bottom: 50px;
  115 + right: 3vw;
  116 +}
  117 +
  118 +.img_tip {
  119 + width: 70px;
  120 + height: 70px;
  121 +}
  122 +
  123 +.pop_card {
  124 + padding: 5vw;
  125 + box-sizing: border-box;
  126 + }
  127 +
  128 + .pop_title {
  129 + font-size: 4.8vw;
  130 + font-weight: bold;
  131 + letter-spacing: 1px;
  132 + margin-bottom: 30px;
  133 + }
  134 +
  135 + .tem_box {
  136 + display: flex;
  137 + flex-wrap: wrap;
  138 + }
  139 +
  140 + .tem_item {
  141 + width: 23vw;
  142 + height: 170px;
  143 + text-align: center;
  144 + margin: 0 3vw 30px;
  145 + }
  146 +
  147 + .tem_pic {
  148 + width: 23vw;
  149 + height: 120px;
  150 + border-radius: 10px;
  151 + }
  152 +
  153 + .tem_font {
  154 + font-size: 3.9vw;
  155 + margin-top: 10px;
  156 + }
2 157 \ No newline at end of file
... ...