Browse Source

feat: 解决冲突

refact
xuesinan 4 years ago
parent
commit
30c42d3cc3
  1. 3
      .editorconfig
  2. 56
      .eslintrc.js
  3. 4
      .hbuilderx/launch.json
  4. 4
      App.vue
  5. 1
      CHANGELOG.md
  6. 8924
      common/styles/tailwind.scss
  7. 447
      components/Calendar/Calendar.vue
  8. 136
      components/Calendar/generateDates.js
  9. 3
      components/PrettyExchange/PrettyExchange.vue
  10. 2
      components/Projects/Projects.vue
  11. 39
      components/Upload/Upload.vue
  12. 7
      pages.json
  13. 75
      pages/index/index - 副本.vue
  14. 71
      pages/index/index.vue
  15. 90
      store/index.js
  16. 6
      store/project/actions.js
  17. 22
      store/project/getters.js
  18. 24
      store/project/index.js
  19. 124
      store/project/mutations.js
  20. 16
      store/project/state.js
  21. 30
      store/user/actions.js
  22. 12
      uni_modules/uni-calendar/changelog.md
  23. 546
      uni_modules/uni-calendar/components/uni-calendar/calendar.js
  24. 12
      uni_modules/uni-calendar/components/uni-calendar/i18n/en.json
  25. 8
      uni_modules/uni-calendar/components/uni-calendar/i18n/index.js
  26. 12
      uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json
  27. 12
      uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json
  28. 181
      uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue
  29. 551
      uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue
  30. 354
      uni_modules/uni-calendar/components/uni-calendar/util.js
  31. 88
      uni_modules/uni-calendar/package.json
  32. 103
      uni_modules/uni-calendar/readme.md
  33. 761
      utils/time.js

3
.editorconfig

@ -1,3 +1,5 @@
root = true
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
@ -5,4 +7,3 @@ end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 140
root = true

56
.eslintrc.js

@ -1,21 +1,41 @@
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": [
"plugin:vue/essential",
"airbnb-base"
env: {
browser: true,
es2021: true,
},
extends: [
'plugin:vue/essential',
'airbnb-base',
],
parserOptions: {
ecmaVersion: 13,
parser: '@typescript-eslint/parser',
sourceType: 'module',
},
plugins: [
'vue',
'@typescript-eslint',
],
rules: {
'vue/html-self-closing': 'off',
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-param-reassign': 'off',
'max-len': ['error', { code: 140, tabWidth: 2 }],
'object-curly-newline': ['error', { multiline: true }],
'arrow-parens': ['error', 'as-needed'],
'linebreak-style': 'off',
'vue/attributes-order': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/max-attributes-per-line': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/html-indent': 'off',
'vue/html-closing-bracket-newline': [
'error',
{
singleline: 'never',
multiline: 'always',
},
],
"parserOptions": {
"ecmaVersion": 13,
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
"plugins": [
"vue",
"@typescript-eslint"
],
"rules": {
}
},
};

4
.hbuilderx/launch.json

@ -2,6 +2,10 @@
// launchtypelocalremote, localremote
"version": "0.0",
"configurations": [{
"app-plus" :
{
"launchtype" : "local"
},
"default" :
{
"launchtype" : "local"

4
App.vue

@ -99,4 +99,8 @@
@import '@/common/styles/iconfont.scss';
@import '@/common/styles/app.scss';
@import '@/common/styles/tailwind.scss';
page {
height: 100%;
}
</style>

1
CHANGELOG.md

@ -5,6 +5,7 @@
--|--|--
- | 日历页首页 | [561c8e6](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/561c8e6)
- | 使用uview完成api请求 | [1b3efd8](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/1b3efd8)
- | 项目列表 | [a52e6d5](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/a52e6d5)
- | app.vue | [970cf9a](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/970cf9a)
- | first commit | [8dc26de](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/8dc26de)
- | vue3 | [12ed2ad](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/12ed2ad)

8924
common/styles/tailwind.scss

File diff suppressed because it is too large

447
components/Calendar/Calendar.vue

@ -1,8 +1,451 @@
<template>
<view class="zzx-calendar">
<view class="calendar-header">{{ timeStr }}</view>
<!-- 星期几标题 -->
<view class="calendar-weeks">
<view
class="calendar-week"
:class="{ 'text-red-500': week === '六' || week === '日' }"
v-for="(week, index) in data.weeks"
:key="index"
>{{ week }}</view>
</view>
<view class="calendar-content">
<swiper
class="calendar-swiper"
:style="{
width: '100%',
height: calenderHeight,
}"
:indicator-dots="false"
:autoplay="false"
:duration="500"
:current="data.current"
@change="changeSwp"
:circular="true"
>
<swiper-item class="calendar-item" v-for="sItem in data.swiper" :key="sItem">
<view class="calendar-days">
<!-- 当前的 -->
<template v-if="sItem === data.current">
<view
class="calendar-day"
v-for="(item, index) in data.days"
:key="index"
:class="{ 'day-hidden': !item.show }"
@click="clickItem(item)"
>
<view
class="date"
:class="[item.isToday ? 'is-today' : '', item.fullDate === data.selectedDate ? 'is-checked' : '']"
>{{ item.time.getDate() }}</view>
<view class="dot-show" v-if="item.info === '0'" :style="dotStyle"></view>
</view>
</template>
<template v-else>
<!-- 下一个月/ -->
<template v-if="data.current - sItem === 1 || data.current - sItem === -2">
<view
class="calendar-day"
v-for="(item, index) in preDays"
:key="index"
:class="{
'day-hidden': !item.show,
}"
>
<view class="date" :class="[item.isToday ? 'is-today' : '']">{{ item.time.getDate() }}</view>
</view>
</template>
<!-- 上一个月/ -->
<template v-else>
<view
class="calendar-day"
v-for="(item, index) in nextDays"
:key="index"
:class="{
'day-hidden': !item.show,
}"
>
<view class="date" :class="[item.isToday ? 'is-today' : '']">{{ item.time.getDate() }}</view>
</view>
</template>
</template>
</view>
</swiper-item>
</swiper>
<!-- <view class="mode-change" @click="changeMode">
<view :class="weekMode ? 'mode-arrow-bottom' : 'mode-arrow-top'"> </view>
</view>-->
</view>
<view class="flex justify-center u-font-18" style="color: #3b82f6" @click="goToday">今日</view>
</view>
</template>
<script>
<script setup>
import { reactive, computed, watchEffect } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import { generateDates, formatDate } from './generateDates.js';
defineProps({
//
dotStyle: {
type: Object,
default: () => ({ background: '#4ade80' }),
},
});
const emit = defineEmits(['handleFindPoint', 'handleFindPoint', 'days-change', 'selected-change']);
const data = reactive({
weeks: ['日', '一', '二', '三', '四', '五', '六'], //
current: 1,
currentYear: '',
currentMonth: '',
currentDate: '',
days: [],
weekMode: false, // false -> true ->
swiper: [0, 1, 2],
selectedDate: formatDate(new Date(), 'yyyy-MM-dd'), //
start: dayjs().startOf('month').valueOf(),
end: dayjs().endOf('month').valueOf(),
});
const store = useStore();
const dotList = computed(() => store.state.project.dotList);
const calenderHeight = computed(() => {
//
//
let h = '35px';
if (!data.weekMode) {
const d = new Date(data.currentYear, data.currentMonth, 0);
const days = d.getDate(); //
const day = new Date(d.setDate(1)).getDay();
// if (day === 0) {
// day = 7;
// }
const pre = 8 - day;
const rows = Math.ceil((days - pre) / 7) + 1;
h = `${35 * rows}px`;
}
return h;
});
//
const timeStr = computed(() => {
let str = '';
const d = new Date(data.currentYear, data.currentMonth - 1, data.currentDate);
const y = d.getFullYear();
const m = d.getMonth() + 1 <= 9 ? `0${d.getMonth() + 1}` : d.getMonth() + 1;
str = `${y}${m}`;
return str;
});
// days
const preDays = computed(() => {
let pres = [];
if (data.weekMode) {
//
const d = new Date(data.currentYear, data.currentMonth - 1, data.currentDate);
d.setDate(d.getDate() - 7);
pres = generateDates(d, 'week');
} else {
//
const d = new Date(data.currentYear, data.currentMonth - 2, 1);
pres = generateDates(d, 'month');
}
return pres;
});
// days
const nextDays = computed(() => {
let next = [];
if (data.weekMode) {
//
const d = new Date(data.currentYear, data.currentMonth - 1, data.currentDate);
d.setDate(d.getDate() + 7);
next = generateDates(d, 'week');
} else {
//
const d = new Date(data.currentYear, data.currentMonth, 1);
next = generateDates(d, 'month');
}
return next;
});
watchEffect(() => {
const days = data.days.slice(0);
const index = days.findIndex(day => day.show);
days.forEach((day, i) => {
dotList.value.forEach((item, j) => {
if (i - index === j) {
day.info = item;
}
});
});
data.days = days;
});
//
const initDate = cur => {
let date = '';
if (cur) {
date = new Date(cur);
} else {
date = new Date();
}
data.currentDate = date.getDate(); //
data.currentYear = date.getFullYear(); //
data.currentMonth = date.getMonth() + 1; //
data.currentWeek = date.getDay() === 0 ? 7 : date.getDay(); // 1...6,0
// const nowY = new Date().getFullYear(); //
// const nowM = new Date().getMonth() + 1;
// const nowD = new Date().getDate(); //
// const nowW = new Date().getDay();
// this.selectedDate = formatDate(new Date(), 'yyyy-MM-dd')
data.days = [];
let days = [];
if (data.weekMode) {
days = generateDates(date, 'week');
// this.selectedDate = days[0].fullDate;
} else {
days = generateDates(date, 'month');
// const sel = new Date(this.selectedDate.replace('-', '/').replace('-', '/'));
// const isMonth = sel.getFullYear() === this.currentYear && (sel.getMonth() + 1) === this.currentMonth;
// if(!isMonth) {
// this.selectedDate = formatDate(new Date(this.currentYear, this.currentMonth-1,1), 'yyyy-MM-dd')
// }
}
//
days.forEach((day, i) => {
dotList.value.forEach((item, j) => {
if (i === j) {
day.info = item;
}
});
});
data.days = days;
// ,
const obj = {
start: '',
end: '',
};
if (data.weekMode) {
obj.start = data.days[0].time;
obj.end = data.days[6].time;
} else {
const start = new Date(data.currentYear, data.currentMonth - 1, 1);
const end = new Date(data.currentYear, data.currentMonth, 0);
obj.start = start;
obj.end = end;
}
emit('days-change', obj);
};
initDate();
//
const daysPre = () => {
if (data.weekMode) {
const d = new Date(data.currentYear, data.currentMonth - 1, data.currentDate);
d.setDate(d.getDate() - 7);
initDate(d);
} else {
const d = new Date(data.currentYear, data.currentMonth - 2, 1);
initDate(d);
}
};
//
const daysNext = () => {
if (data.weekMode) {
const d = new Date(data.currentYear, data.currentMonth - 1, data.currentDate);
d.setDate(d.getDate() + 7);
initDate(d);
} else {
const d = new Date(data.currentYear, data.currentMonth, 1);
initDate(d);
}
};
/**
* 滑动切换上下周期
* 根据前一个减去目前的值我们可以判断是下一个月/周还是上一个月/
* current - pre === 1, -2 下一个月/
* current - pre === -1, 2 上一个月或者上一周
*/
const changeSwp = e => {
const pre = data.current;
const { current } = e.detail;
data.current = current;
if (current - pre === 1 || current - pre === -2) {
//
daysNext();
const arr = data.days.filter(s => s.show);
const end = `${arr[arr.length - 1].fullDate} 23:59:59`;
data.start = dayjs(arr[0].fullDate).valueOf();
data.end = dayjs(end).valueOf();
emit('handleFindPoint', data.start, data.end);
} else {
//
daysPre();
const arr = data.days.filter(s => s.show);
const end = `${arr[arr.length - 1].fullDate} 23:59:59`;
data.start = dayjs(arr[0].fullDate).valueOf();
data.end = dayjs(end).valueOf();
emit('handleFindPoint', data.start, data.end);
}
};
//
// const changeMode = () => {
// const premode = this.weekMode;
// let isweek = false;
// if (premode) {
// isweek = !!this.days.find((item) => item.fullDate === this.selectedDate);
// }
// this.weekMode = !this.weekMode;
// let d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
// const sel = new Date(this.selectedDate.replace('-', '/').replace('-', '/'));
// const isMonth = sel.getFullYear() === this.currentYear && sel.getMonth() + 1 === this.currentMonth;
// if ((this.selectedDate && isMonth) || isweek) {
// d = new Date(this.selectedDate.replace('-', '/').replace('-', '/'));
// }
// this.initDate(d);
// };
//
const clickItem = e => {
data.selectedDate = e.fullDate;
emit('selected-change', e);
};
//
const goToday = () => {
const d = new Date();
initDate(d);
};
</script>
<style>
<style lang="scss" scoped>
.zzx-calendar {
width: 100%;
height: auto;
background-color: #fff;
padding-bottom: 10px;
.calendar-header {
text-align: center;
padding: 16px 0;
position: relative;
font-size: 15px;
}
.calendar-weeks {
width: 100%;
display: flex;
flex-flow: row nowrap;
margin-bottom: 10px;
justify-content: center;
align-items: center;
font-size: 12px;
color: #9ca3af;
font-weight: bold;
.calendar-week {
width: calc(100% / 7);
height: 100%;
text-align: center;
}
}
swiper {
width: 100%;
height: 60upx;
}
.calendar-content {
min-height: 30px;
}
.calendar-swiper {
min-height: 35px;
transition: height ease-out 0.3s;
}
.calendar-item {
margin: 0;
padding: 0;
height: 100%;
}
.calendar-days {
display: flex;
flex-flow: row wrap;
width: 100%;
height: 100%;
overflow: hidden;
font-size: 14px;
.calendar-day {
width: calc(100% / 7);
height: 35px;
text-align: center;
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
align-items: center;
position: relative;
}
}
.day-hidden {
visibility: hidden;
}
.mode-change {
display: flex;
justify-content: center;
margin-top: 5px;
.mode-arrow-top {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 5px solid #ff6633;
}
.mode-arrow-bottom {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 5px solid #ff6633;
}
}
.is-today {
background: #ffffff;
border: 1upx solid #ff6633;
border-radius: 50%;
color: #ff6633;
}
.is-checked {
background: #ff6633;
color: #ffffff;
}
.date {
width: 25px;
height: 25px;
line-height: 25px;
margin: 0 auto;
border-radius: 25px;
}
.dot-show {
width: 6px;
height: 6px;
// background: red;
border-radius: 5px;
position: absolute;
top: 2px;
right: 10px;
}
}
</style>

136
components/Calendar/generateDates.js

@ -0,0 +1,136 @@
/*
*此函数的作用是根据传入的一个日期返回这一周的日期或者这一个月的日期
* 如果是月的话注意还包含上个月和下个月的日期月的话总共数据有 6 * 7 = 42
*
*/
/*
* 时间格式化函数
* 重要提示微信小程序new Date('2020-04-16')在ios中无法获取时间对象
* 解决方式: 建议将时间都格式化成'2020/04/16 00:00:00'的格式
* 函数示例: formatDate(new Date(), 'YYYY/MM/dd hh:mm:ss')
*/
export const formatDate = (date, fmt) => {
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
}
let o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds(),
};
for (let k in o) {
if (new RegExp(`(${k})`).test(fmt)) {
let str = o[k] + '';
fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : padLeftZero(str));
}
}
return fmt;
};
const padLeftZero = str => {
return ('00' + str).substr(str.length);
};
// 判断是不是date对象
export const judgeType = s => {
// 函数返回数据的具体类型
return Object.prototype.toString.call(s).slice(8, -1);
};
export const equalDate = (d1, d2) => {
let result = false;
if (d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate()) {
result = true;
}
return result;
};
/* ,2020-04-04
*/
export const dateEqual = (before, after) => {
before = new Date(before.replace('-', '/').replace('-', '/'));
after = new Date(after.replace('-', '/').replace('-', '/'));
if (before.getTime() - after.getTime() === 0) {
return true;
} else {
return false;
}
};
export const generateDates = (date = new Date(), type = 'week') => {
const result = [];
if (judgeType(date) === 'Date') {
// 年,月,日
const y = date.getFullYear();
const m = date.getMonth();
const d = date.getDate();
const days = new Date(y, m + 1, 0).getDate();
// 获取日期是星期几
// let weekIndex = date.getDay() === 0 ? 7 : date.getDay();
let weekIndex = date.getDay();
if (type === 'month') {
const dobj = new Date(y, m, 1);
// weekIndex = dobj.getDay() === 0 ? 7 : dobj.getDay();
weekIndex = dobj.getDay();
}
if (type === 'week') {
for (let i = weekIndex; i > 0; i--) {
const dtemp = new Date(y, m, d);
dtemp.setDate(dtemp.getDate() - i);
result.push({
time: dtemp,
show: true,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp),
});
}
for (let i = 0; i <= 7 - weekIndex; i++) {
const dtemp = new Date(y, m, d);
dtemp.setDate(dtemp.getDate() + i);
result.push({
time: dtemp,
show: true,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp),
});
}
} else if (type === 'month') {
// 上个月
for (let i = weekIndex; i > 0; i--) {
const dtemp = new Date(y, m, 1);
dtemp.setDate(dtemp.getDate() - i);
result.push({
time: dtemp,
show: false,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp),
});
}
// 这个月的日期
for (let i = 0; i < days; i++) {
const dtemp = new Date(y, m, 1);
dtemp.setDate(dtemp.getDate() + i);
result.push({
time: dtemp,
show: true,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp),
});
}
const len = 42 - result.length;
// 下个月的日期
for (let i = 1; i <= len; i++) {
const dtemp = new Date(y, m + 1, 0);
dtemp.setDate(dtemp.getDate() + i);
result.push({
time: dtemp,
show: false,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp),
});
}
}
}
return result;
};

3
components/PrettyExchange/PrettyExchange.vue

@ -99,8 +99,9 @@
<script setup>
import { ref, onMounted, watch, computed } from 'vue';
import ProjectItem from '@/components/Projects/ProjectItem.vue';
import store from '@/store/index.js'
import { useStore } from 'vuex';
const store = useStore();
const projects = computed(() => store.state.project.projects);
const data = ref({
itemTop: 0,

2
components/Projects/Projects.vue

@ -5,8 +5,6 @@
</template>
<script setup>
import PrettyExchange from '@/components/PrettyExchange/PrettyExchange.vue';
function change(options) {
if (options instanceof Array) {
let projectIdList = [];

39
components/Upload/Upload.vue

@ -1,8 +1,43 @@
<template>
<view class="upload">
<u-icon name="plus" size="24px" class="flex justify-center w-12 h-12 bg-blue-100 rounded-full shadow-md" @click="handleUpload"></u-icon>
</view>
</template>
<script>
<script setup>
import { computed } from 'vue';
import { useStore } from 'vuex';
const emit = defineEmits(['success', 'error']);
const store = useStore();
const userId = computed(() => store.getters['user/userId']);
// wbs
const handleUpload = async cur => {
try {
const res = await uni.$u.api.import();
// WBS
//
emit('success');
res.url && (uni.$t.domain = res.url);
setTimeout(() => {
uni.navigateTo({ url: `/pages/project-webview/project-webview?u=${userId.value}&p=${res.id}&pname=${res.pname}&url=${res.url}` });
}, 2000);
} catch (error) {
console.error('error: ', error);
emit('error', error);
}
};
</script>
<style>
<style lang="scss" scoped>
.upload {
position: absolute;
right: 10px;
bottom: 0;
transform: translate3d(0, 50%, 0);
color: $uni-color-primary !important;
}
</style>

7
pages.json

@ -19,5 +19,12 @@
"navigationBarTitleText": "TALL",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"easycom": {
"autoscan": true,
"custom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue",
"^p-(.*)": "@/plugins/p-$1/p-$1.vue"
}
}
}

75
pages/index/index - 副本.vue

@ -1,75 +0,0 @@
<template>
<view class="flex flex-col h-full bg-gray-50" @click="openAuth">
<view class="relative" @touchmove="onMove">
<!-- 日历 -->
<Calendar @selected-change="onDateChange" :show-back="true" ref="calendar" @handleFindPoint="handleFindPoint" />
<!-- 上传 导入wbs -->
<Upload @success="onUploadSuccess" @error="onUploadError" />
</view>
<!-- 项目列表 -->
<Projects @getProjects="getProjects" class="flex-1 overflow-y-auto" />
<!-- 全局提示框 -->
<u-top-tips ref="uTips"></u-top-tips>
</view>
</template>
<script setup>
import { ref, computed, watch } from 'vue';
import store from '@/store/index.js';
import dayjs from 'dayjs';
import Calendar from '@/components/Calendar/Calendar.vue';
import Upload from '@/components/Upload/Upload.vue';
import Projects from '@/components/Projects/Projects.vue';
const token = computed(() => store.state.user.token);
watch(token, (value) => {
if (!value) return;
getProjects();
})
//
function getProjects(start = dayjs().startOf('day').valueOf(), end = dayjs().endOf('day').valueOf()) {
// const data = await this.$u.api.getProjects(start, end);
uni.$catchReq.getProjects(start, end, (err, data) => {
if (err) {
console.error('err: ', err);
} else {
data.forEach(item => {
item.show = false;
});
store.commit('project/setProjects', data);
}
});
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>

71
pages/index/index.vue

@ -2,7 +2,8 @@
<view class="flex flex-col h-full bg-gray-50" @click="openAuth">
<view class="relative" @touchmove="onMove">
<!-- 日历 -->
<Calendar @selected-change="onDateChange" :show-back="true" ref="calendar" @handleFindPoint="handleFindPoint" />
<Calendar @selected-change="onDateChange" :show-back="true" ref="calendar"
@handleFindPoint="handleFindPoint" />
<!-- 上传 导入wbs -->
<Upload @success="onUploadSuccess" @error="onUploadError" />
</view>
@ -16,20 +17,27 @@
</template>
<script setup>
import { ref, computed, watch } from 'vue';
import store from '@/store/index.js';
import { reactive, ref, computed, watchEffect } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import Calendar from '@/components/Calendar/Calendar.vue';
import Upload from '@/components/Upload/Upload.vue';
import Projects from '@/components/Projects/Projects.vue';
const store = useStore();
const token = computed(() => store.state.user.token);
watch(token, (value) => {
if (!value) return;
getProjects();
})
const data = reactive({
calendar: null,
days: [],
});
// token
watchEffect(() => {
if (!token.value) return;
if (token.value) {
getProjects();
handleFindPoint();
}
});
//
function getProjects(start = dayjs().startOf('day').valueOf(), end = dayjs().endOf('day').valueOf()) {
// const data = await this.$u.api.getProjects(start, end);
@ -43,7 +51,44 @@
store.commit('project/setProjects', data);
}
});
}
};
async function handleFindPoint(start, end) {
try {
const startTime = start || dayjs().startOf('month').valueOf();
const endTime = end || dayjs().endOf('month').valueOf();
const res = await uni.$u.api.findRedPoint(startTime, endTime);
store.commit('project/setDotList', res);
} catch (error) {
console.log('error: ', error);
}
};
//
const onDateChange = event => {
const day = dayjs(event.fullDate);
const start = day.startOf('date').valueOf();
const end = day.endOf('date').valueOf();
getProjects(start, end);
};
//
const onUploadSuccess = () => {
uni.$refs.uTips.show({
title: '导入成功,即将打开新项目',
type: 'success',
duration: '3000',
});
};
//
const onUploadError = error => {
uni.$refs.uTips.show({
title: error || '导入失败',
type: 'error',
duration: '6000',
});
};
</script>
<style>

90
store/index.js

@ -1,46 +1,46 @@
import { createStore } from 'vuex';
import user from './user/index.js';
import socket from './socket/index.js';
import project from './project/index.js';
// 不属于具体模块的 应用级的 store内容
const state = {
networkConnected: true, // 网络是否连接
forceUseStorage: true, // 强制启用storage
systemInfo: null, // 系统设备信息
};
const getters = {
// 是否启用本地存储
// 设置了强制启用本地存储 或者 没有网络连接的时候
useStorage({ networkConnected, forceUseStorage }) {
return forceUseStorage || !networkConnected;
},
};
const mutations = {
/**
* 设置网络是否连接的变量
* @param {*} state
* @param {boolean} networkConnected
*/
setNetworkConnected(state, networkConnected) {
state.networkConnected = networkConnected;
},
/**
* 设置系统信息的数据
* @param {object} state
* @param {object | null} data 获取到的数据
*/
setSystemInfo(state, data) {
state.systemInfo = data;
},
};
export default createStore({
state,
getters,
mutations,
modules: {user, socket, project}
import { createStore } from 'vuex';
import user from './user/index.js';
import socket from './socket/index.js';
import project from './project/index.js';
// 不属于具体模块的 应用级的 store内容
const state = {
networkConnected: true, // 网络是否连接
forceUseStorage: true, // 强制启用storage
systemInfo: null, // 系统设备信息
};
const getters = {
// 是否启用本地存储
// 设置了强制启用本地存储 或者 没有网络连接的时候
useStorage({ networkConnected, forceUseStorage }) {
return forceUseStorage || !networkConnected;
},
};
const mutations = {
/**
* 设置网络是否连接的变量
* @param {*} state
* @param {boolean} networkConnected
*/
setNetworkConnected(state, networkConnected) {
state.networkConnected = networkConnected;
},
/**
* 设置系统信息的数据
* @param {object} state
* @param {object | null} data 获取到的数据
*/
setSystemInfo(state, data) {
state.systemInfo = data;
},
};
export default createStore({
state,
getters,
mutations,
modules: {user, socket, project}
});

6
store/project/actions.js

@ -1,3 +1,3 @@
const actions = {};
export default actions;
const actions = {};
export default actions;

22
store/project/getters.js

@ -1,11 +1,11 @@
const getters = {
/**
* 当前项目的id
* @param {object} project
*/
projectId({ project }) {
return project.id;
},
};
export default getters;
const getters = {
/**
* 当前项目的id
* @param {object} project
*/
projectId({ project }) {
return project.id;
},
};
export default getters;

24
store/project/index.js

@ -1,12 +1,12 @@
import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
export default {
namespaced: true,
state,
getters,
mutations,
actions,
};
import actions from './actions';
import getters from './getters';
import mutations from './mutations';
import state from './state';
export default {
namespaced: true,
state,
getters,
mutations,
actions,
};

124
store/project/mutations.js

@ -1,62 +1,62 @@
const mutations = {
/**
* 设置state projects书籍
* @param {object} state
* @param {array} projects 项目列表
*/
setProjects(state, projects) {
if (!projects || !projects.length) {
state.projects = [];
} else {
state.projects = [...projects];
}
},
/**
* 设置子项目收缩展开
* @param { object } state
* @param { object } options options:{ index,show }
*/
setProjectItemShow(state, options) {
if (options.show) {
for (var i = 0; i < state.projects.length; i++) {
if (i === options.index) {
state.projects[i].show = true;
} else {
state.projects[i].show = false;
}
}
} else {
state.projects[options.index].show = false;
}
},
/**
* 设置当前项目信息
* @param { object } state
* @param { object } data
*/
setProject(state, data) {
state.project = data || { name: '加载中...' };
},
/**
* 设置当前项目名称
* @param { object } state
* @param { string } data
*/
setProjectName(state, data) {
state.project.name = data;
},
/**
* 设置小红点
* @param { object } state
* @param { string } data
*/
setDotList(state, data) {
state.dotList = data;
},
};
export default mutations;
const mutations = {
/**
* 设置state projects书籍
* @param {object} state
* @param {array} projects 项目列表
*/
setProjects(state, projects) {
if (!projects || !projects.length) {
state.projects = [];
} else {
state.projects = [...projects];
}
},
/**
* 设置子项目收缩展开
* @param { object } state
* @param { object } options options:{ index,show }
*/
setProjectItemShow(state, options) {
if (options.show) {
for (var i = 0; i < state.projects.length; i++) {
if (i === options.index) {
state.projects[i].show = true;
} else {
state.projects[i].show = false;
}
}
} else {
state.projects[options.index].show = false;
}
},
/**
* 设置当前项目信息
* @param { object } state
* @param { object } data
*/
setProject(state, data) {
state.project = data || { name: '加载中...' };
},
/**
* 设置当前项目名称
* @param { object } state
* @param { string } data
*/
setProjectName(state, data) {
state.project.name = data;
},
/**
* 设置小红点
* @param { object } state
* @param { string } data
*/
setDotList(state, data) {
state.dotList = data;
},
};
export default mutations;

16
store/project/state.js

@ -1,8 +1,8 @@
/* eslint-disable */
const state = {
project: { name: '加载中...' }, // 当前项目信息
projects: [], // 项目列表
dotList: [], // 小红点
};
export default state;
/* eslint-disable */
const state = {
project: { name: '加载中...' }, // 当前项目信息
projects: [], // 项目列表
dotList: [], // 小红点
};
export default state;

30
store/user/actions.js

@ -1,21 +1,21 @@
import ui from '@/utils/ui.js';
const actions = {
/**
* 通过userId获取token
* @param {any} commit
* @param {string} userId 用户id
*/
async getTokenByUserId({ commit }, userId) {
try {
const res = await uni.$u.api.getToken(userId);
commit('setToken', res.token);
commit('setUser', res);
return res;
} catch (error) {
ui.showToast(error.msg || '获取个人信息失败');
}
},
/**
* 通过userId获取token
* @param {any} commit
* @param {string} userId 用户id
*/
async getTokenByUserId({ commit }, userId) {
try {
const res = await uni.$u.api.getToken(userId);
commit('setToken', res.token);
commit('setUser', res);
return res;
} catch (error) {
ui.showToast(error.msg || '获取个人信息失败');
}
},
};
export default actions;

12
uni_modules/uni-calendar/changelog.md

@ -0,0 +1,12 @@
## 1.4.3(2021-09-22)
- 修复 startDate、 endDate 属性失效的 bug
## 1.4.2(2021-08-24)
- 新增 支持国际化
## 1.4.1(2021-08-05)
- 修复 弹出层被 tabbar 遮盖 bug
## 1.4.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.3.16(2021-05-12)
- 新增 组件示例地址
## 1.3.15(2021-02-04)
- 调整为uni_modules目录规范

546
uni_modules/uni-calendar/components/uni-calendar/calendar.js

@ -0,0 +1,546 @@
/**
* @1900-2100区间内的公历农历互转
* @charset UTF-8
* @github https://github.com/jjonline/calendar.js
* @Author Jea杨(JJonline@JJonline.Cn)
* @Time 2014-7-21
* @Time 2016-8-13 Fixed 2033hexAttribution Annals
* @Time 2016-9-25 Fixed lunar LeapMonth Param Bug
* @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
* @Version 1.0.3
* @公历转农历calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
* @农历转公历calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
*/
/* eslint-disable */
var calendar = {
/**
* 农历1900-2100的润大小信息表
* @Array Of Property
* @return Hex
*/
lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
/** Add By JJonline@JJonline.Cn**/
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
0x0d520], // 2100
/**
* 公历每个月份的天数普通表
* @Array Of Property
* @return Number
*/
solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
/**
* 天干地支之天干速查表
* @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
* @return Cn string
*/
Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
/**
* 天干地支之地支速查表
* @Array Of Property
* @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
* @return Cn string
*/
Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],
/**
* 天干地支之地支速查表<=>生肖
* @Array Of Property
* @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
* @return Cn string
*/
Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],
/**
* 24节气速查表
* @Array Of Property
* @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
* @return Cn string
*/
solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],
/**
* 1900-2100各年的24节气日期速查表
* @Array Of Property
* @return 0x string For splice
*/
sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
'97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
'97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
'97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
'97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
'97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
'9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
'97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
'97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
'7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
'9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
'97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
'9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
'9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
'977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
'977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
'977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
'7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
'7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
'665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],
/**
* 数字转中文速查表
* @Array Of Property
* @trans ['日','一','二','三','四','五','六','七','八','九','十']
* @return Cn string
*/
nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],
/**
* 日期转农历称呼速查表
* @Array Of Property
* @trans ['初','十','廿','卅']
* @return Cn string
*/
nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
/**
* 月份转农历称呼速查表
* @Array Of Property
* @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
* @return Cn string
*/
nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],
/**
* 返回农历y年一整年的总天数
* @param lunar Year
* @return Number
* @eg:var count = calendar.lYearDays(1987) ;//count=387
*/
lYearDays: function (y) {
var i; var sum = 348
for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
return (sum + this.leapDays(y))
},
/**
* 返回农历y年闰月是哪个月若y年没有闰月 则返回0
* @param lunar Year
* @return Number (0-12)
* @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
*/
leapMonth: function (y) { // 闰字编码 \u95f0
return (this.lunarInfo[y - 1900] & 0xf)
},
/**
* 返回农历y年闰月的天数 若该年没有闰月则返回0
* @param lunar Year
* @return Number (02930)
* @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
*/
leapDays: function (y) {
if (this.leapMonth(y)) {
return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
}
return (0)
},
/**
* 返回农历y年m月非闰月的总天数计算m为闰月时的天数请使用leapDays方法
* @param lunar Year
* @return Number (-12930)
* @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
*/
monthDays: function (y, m) {
if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1
return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
},
/**
* 返回公历(!)y年m月的天数
* @param solar Year
* @return Number (-128293031)
* @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
*/
solarDays: function (y, m) {
if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
var ms = m - 1
if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
} else {
return (this.solarMonth[ms])
}
},
/**
* 农历年份转换为干支纪年
* @param lYear 农历年的年份数
* @return Cn string
*/
toGanZhiYear: function (lYear) {
var ganKey = (lYear - 3) % 10
var zhiKey = (lYear - 3) % 12
if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
},
/**
* 公历月日判断所属星座
* @param cMonth [description]
* @param cDay [description]
* @return Cn string
*/
toAstro: function (cMonth, cDay) {
var s = '\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'
var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
},
/**
* 传入offset偏移量返回干支
* @param offset 相对甲子的偏移量
* @return Cn string
*/
toGanZhi: function (offset) {
return this.Gan[offset % 10] + this.Zhi[offset % 12]
},
/**
* 传入公历(!)y年获得该年第n个节气的公历日期
* @param y公历年(1900-2100)n二十四节气中的第几个节气(1~24)从n=1(小寒)算起
* @return day Number
* @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
*/
getTerm: function (y, n) {
if (y < 1900 || y > 2100) { return -1 }
if (n < 1 || n > 24) { return -1 }
var _table = this.sTermInfo[y - 1900]
var _info = [
parseInt('0x' + _table.substr(0, 5)).toString(),
parseInt('0x' + _table.substr(5, 5)).toString(),
parseInt('0x' + _table.substr(10, 5)).toString(),
parseInt('0x' + _table.substr(15, 5)).toString(),
parseInt('0x' + _table.substr(20, 5)).toString(),
parseInt('0x' + _table.substr(25, 5)).toString()
]
var _calday = [
_info[0].substr(0, 1),
_info[0].substr(1, 2),
_info[0].substr(3, 1),
_info[0].substr(4, 2),
_info[1].substr(0, 1),
_info[1].substr(1, 2),
_info[1].substr(3, 1),
_info[1].substr(4, 2),
_info[2].substr(0, 1),
_info[2].substr(1, 2),
_info[2].substr(3, 1),
_info[2].substr(4, 2),
_info[3].substr(0, 1),
_info[3].substr(1, 2),
_info[3].substr(3, 1),
_info[3].substr(4, 2),
_info[4].substr(0, 1),
_info[4].substr(1, 2),
_info[4].substr(3, 1),
_info[4].substr(4, 2),
_info[5].substr(0, 1),
_info[5].substr(1, 2),
_info[5].substr(3, 1),
_info[5].substr(4, 2)
]
return parseInt(_calday[n - 1])
},
/**
* 传入农历数字月份返回汉语通俗表示法
* @param lunar month
* @return Cn string
* @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
*/
toChinaMonth: function (m) { // 月 => \u6708
if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
var s = this.nStr3[m - 1]
s += '\u6708'// 加上月字
return s
},
/**
* 传入农历日期数字返回汉字表示法
* @param lunar day
* @return Cn string
* @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
*/
toChinaDay: function (d) { // 日 => \u65e5
var s
switch (d) {
case 10:
s = '\u521d\u5341'; break
case 20:
s = '\u4e8c\u5341'; break
break
case 30:
s = '\u4e09\u5341'; break
break
default :
s = this.nStr2[Math.floor(d / 10)]
s += this.nStr1[d % 10]
}
return (s)
},
/**
* 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是立春
* @param y year
* @return Cn string
* @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
*/
getAnimal: function (y) {
return this.Animals[(y - 4) % 12]
},
/**
* 传入阳历年月日获得详细的公历农历object信息 <=>JSON
* @param y solar year
* @param m solar month
* @param d solar day
* @return JSON object
* @eg:console.log(calendar.solar2lunar(1987,11,01));
*/
solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
// 年份限定、上限
if (y < 1900 || y > 2100) {
return -1// undefined转换为数字变为NaN
}
// 公历传参最下限
if (y == 1900 && m == 1 && d < 31) {
return -1
}
// 未传参 获得当天
if (!y) {
var objDate = new Date()
} else {
var objDate = new Date(y, parseInt(m) - 1, d)
}
var i; var leap = 0; var temp = 0
// 修正ymd参数
var y = objDate.getFullYear()
var m = objDate.getMonth() + 1
var d = objDate.getDate()
var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
for (i = 1900; i < 2101 && offset > 0; i++) {
temp = this.lYearDays(i)
offset -= temp
}
if (offset < 0) {
offset += temp; i--
}
// 是否今天
var isTodayObj = new Date()
var isToday = false
if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
isToday = true
}
// 星期几
var nWeek = objDate.getDay()
var cWeek = this.nStr1[nWeek]
// 数字表示周几顺应天朝周一开始的惯例
if (nWeek == 0) {
nWeek = 7
}
// 农历年
var year = i
var leap = this.leapMonth(i) // 闰哪个月
var isLeap = false
// 效验闰月
for (i = 1; i < 13 && offset > 0; i++) {
// 闰月
if (leap > 0 && i == (leap + 1) && isLeap == false) {
--i
isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
} else {
temp = this.monthDays(year, i)// 计算农历普通月天数
}
// 解除闰月
if (isLeap == true && i == (leap + 1)) { isLeap = false }
offset -= temp
}
// 闰月导致数组下标重叠取反
if (offset == 0 && leap > 0 && i == leap + 1) {
if (isLeap) {
isLeap = false
} else {
isLeap = true; --i
}
}
if (offset < 0) {
offset += temp; --i
}
// 农历月
var month = i
// 农历日
var day = offset + 1
// 天干地支处理
var sm = m - 1
var gzY = this.toGanZhiYear(year)
// 当月的两个节气
// bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始
// 依据12节气修正干支月
var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
if (d >= firstNode) {
gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
}
// 传入的日期的节气与否
var isTerm = false
var Term = null
if (firstNode == d) {
isTerm = true
Term = this.solarTerm[m * 2 - 2]
}
if (secondNode == d) {
isTerm = true
Term = this.solarTerm[m * 2 - 1]
}
// 日柱 当月一日与 1900/1/1 相差天数
var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
var gzD = this.toGanZhi(dayCyclical + d - 1)
// 该日期所属的星座
var astro = this.toAstro(m, d)
return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
},
/**
* 传入农历年月日以及传入的月份是否闰月获得详细的公历农历object信息 <=>JSON
* @param y lunar year
* @param m lunar month
* @param d lunar day
* @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
* @return JSON object
* @eg:console.log(calendar.lunar2solar(1987,9,10));
*/
lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
var isLeapMonth = !!isLeapMonth
var leapOffset = 0
var leapMonth = this.leapMonth(y)
var leapDay = this.leapDays(y)
if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
var day = this.monthDays(y, m)
var _day = day
// bugFix 2016-9-25
// if month is leap, _day use leapDays method
if (isLeapMonth) {
_day = this.leapDays(y, m)
}
if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验
// 计算农历的时间差
var offset = 0
for (var i = 1900; i < y; i++) {
offset += this.lYearDays(i)
}
var leap = 0; var isAdd = false
for (var i = 1; i < m; i++) {
leap = this.leapMonth(y)
if (!isAdd) { // 处理闰月
if (leap <= i && leap > 0) {
offset += this.leapDays(y); isAdd = true
}
}
offset += this.monthDays(y, i)
}
// 转换闰月农历 需补充该年闰月的前一个月的时差
if (isLeapMonth) { offset += day }
// 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
var calObj = new Date((offset + d - 31) * 86400000 + stmap)
var cY = calObj.getUTCFullYear()
var cM = calObj.getUTCMonth() + 1
var cD = calObj.getUTCDate()
return this.solar2lunar(cY, cM, cD)
}
}
export default calendar

12
uni_modules/uni-calendar/components/uni-calendar/i18n/en.json

@ -0,0 +1,12 @@
{
"uni-calender.ok": "ok",
"uni-calender.cancel": "cancel",
"uni-calender.today": "today",
"uni-calender.MON": "MON",
"uni-calender.TUE": "TUE",
"uni-calender.WED": "WED",
"uni-calender.THU": "THU",
"uni-calender.FRI": "FRI",
"uni-calender.SAT": "SAT",
"uni-calender.SUN": "SUN"
}

8
uni_modules/uni-calendar/components/uni-calendar/i18n/index.js

@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}

12
uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json

@ -0,0 +1,12 @@
{
"uni-calender.ok": "确定",
"uni-calender.cancel": "取消",
"uni-calender.today": "今日",
"uni-calender.SUN": "日",
"uni-calender.MON": "一",
"uni-calender.TUE": "二",
"uni-calender.WED": "三",
"uni-calender.THU": "四",
"uni-calender.FRI": "五",
"uni-calender.SAT": "六"
}

12
uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json

@ -0,0 +1,12 @@
{
"uni-calender.ok": "確定",
"uni-calender.cancel": "取消",
"uni-calender.today": "今日",
"uni-calender.SUN": "日",
"uni-calender.MON": "一",
"uni-calender.TUE": "二",
"uni-calender.WED": "三",
"uni-calender.THU": "四",
"uni-calender.FRI": "五",
"uni-calender.SAT": "六"
}

181
uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue

@ -0,0 +1,181 @@
<template>
<view class="uni-calendar-item__weeks-box" :class="{
'uni-calendar-item--disable':weeks.disable,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':(calendar.fullDate === weeks.fullDate && !weeks.isDay) ,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
}"
@click="choiceDate(weeks)">
<view class="uni-calendar-item__weeks-box-item">
<text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
<text class="uni-calendar-item__weeks-box-text" :class="{
'uni-calendar-item--isDay-text': weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable,
}">{{weeks.date}}</text>
<text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uni-calendar-item__weeks-lunar-text" :class="{
'uni-calendar-item--isDay-text':weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
}">{{todayText}}</text>
<text v-if="lunar&&!weeks.extraInfo" class="uni-calendar-item__weeks-lunar-text" :class="{
'uni-calendar-item--isDay-text':weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable,
}">{{weeks.isDay ? todayText : (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text>
<text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uni-calendar-item__weeks-lunar-text" :class="{
'uni-calendar-item--extra':weeks.extraInfo.info,
'uni-calendar-item--isDay-text':weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable,
}">{{weeks.extraInfo.info}}</text>
</view>
</view>
</template>
<script>
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from './i18n/index.js'
const { t } = initVueI18n(messages)
export default {
emits:['change'],
props: {
weeks: {
type: Object,
default () {
return {}
}
},
calendar: {
type: Object,
default: () => {
return {}
}
},
selected: {
type: Array,
default: () => {
return []
}
},
lunar: {
type: Boolean,
default: false
}
},
computed: {
todayText() {
return t("uni-calender.today")
},
},
methods: {
choiceDate(weeks) {
this.$emit('change', weeks)
}
}
}
</script>
<style lang="scss" scoped>
.uni-calendar-item__weeks-box {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
}
.uni-calendar-item__weeks-box-text {
font-size: $uni-font-size-base;
color: $uni-text-color;
}
.uni-calendar-item__weeks-lunar-text {
font-size: $uni-font-size-sm;
color: $uni-text-color;
}
.uni-calendar-item__weeks-box-item {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
width: 100rpx;
height: 100rpx;
}
.uni-calendar-item__weeks-box-circle {
position: absolute;
top: 5px;
right: 5px;
width: 8px;
height: 8px;
border-radius: 8px;
background-color: $uni-color-error;
}
.uni-calendar-item--disable {
background-color: rgba(249, 249, 249, $uni-opacity-disabled);
color: $uni-text-color-disable;
}
.uni-calendar-item--isDay-text {
color: $uni-color-primary;
}
.uni-calendar-item--isDay {
background-color: $uni-color-primary;
opacity: 0.8;
color: #fff;
}
.uni-calendar-item--extra {
color: $uni-color-error;
opacity: 0.8;
}
.uni-calendar-item--checked {
background-color: $uni-color-primary;
color: #fff;
opacity: 0.8;
}
.uni-calendar-item--multiple {
background-color: $uni-color-primary;
color: #fff;
opacity: 0.8;
}
.uni-calendar-item--before-checked {
background-color: #ff5a5f;
color: #fff;
}
.uni-calendar-item--after-checked {
background-color: #ff5a5f;
color: #fff;
}
</style>

551
uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue

@ -0,0 +1,551 @@
<template>
<view class="uni-calendar">
<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></view>
<view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}">
<view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top">
<view class="uni-calendar__header-btn-box" @click="close">
<text class="uni-calendar__header-text uni-calendar--fixed-width">{{cancelText}}</text>
</view>
<view class="uni-calendar__header-btn-box" @click="confirm">
<text class="uni-calendar__header-text uni-calendar--fixed-width">{{okText}}</text>
</view>
</view>
<view class="uni-calendar__header">
<view class="uni-calendar__header-btn-box" @click.stop="pre">
<view class="uni-calendar__header-btn uni-calendar--left"></view>
</view>
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
<text class="uni-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
</picker>
<view class="uni-calendar__header-btn-box" @click.stop="next">
<view class="uni-calendar__header-btn uni-calendar--right"></view>
</view>
<text class="uni-calendar__backtoday" @click="backtoday">{{todayText}}</text>
</view>
<view class="uni-calendar__box">
<view v-if="showMonth" class="uni-calendar__box-bg">
<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
</view>
<view class="uni-calendar__weeks">
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{monText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{THUText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
</view>
</view>
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" @change="choiceDate"></calendar-item>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import Calendar from './util.js';
import calendarItem from './uni-calendar-item.vue'
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from './i18n/index.js'
const { t } = initVueI18n(messages)
/**
* Calendar 日历
* @description 日历组件可以查看日期选择任意范围内的日期打点操作常用场景如酒店日期预订火车机票选择购买日期上下班打卡等
* @tutorial https://ext.dcloud.net.cn/plugin?id=56
* @property {String} date 自定义当前时间默认为今天
* @property {Boolean} lunar 显示农历
* @property {String} startDate 日期选择范围-开始日期
* @property {String} endDate 日期选择范围-结束日期
* @property {Boolean} range 范围选择
* @property {Boolean} insert = [true|false] 插入模式,默认为false
* @value true 弹窗模式
* @value false 插入模式
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
* @property {Array} selected 打点期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
* @property {Boolean} showMonth 是否选择月份为背景
* @event {Function} change 日期改变`insert :ture` 时生效
* @event {Function} confirm 确认选择`insert :false` 时生效
* @event {Function} monthSwitch 切换月份时触发
* @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
*/
export default {
components: {
calendarItem
},
emits:['close','confirm','change','monthSwitch'],
props: {
date: {
type: String,
default: ''
},
selected: {
type: Array,
default () {
return []
}
},
lunar: {
type: Boolean,
default: false
},
startDate: {
type: String,
default: ''
},
endDate: {
type: String,
default: ''
},
range: {
type: Boolean,
default: false
},
insert: {
type: Boolean,
default: true
},
showMonth: {
type: Boolean,
default: true
},
clearDate: {
type: Boolean,
default: true
}
},
data() {
return {
show: false,
weeks: [],
calendar: {},
nowDate: '',
aniMaskShow: false
}
},
computed:{
/**
* for i18n
*/
okText() {
return t("uni-calender.ok")
},
cancelText() {
return t("uni-calender.cancel")
},
todayText() {
return t("uni-calender.today")
},
monText() {
return t("uni-calender.MON")
},
TUEText() {
return t("uni-calender.TUE")
},
WEDText() {
return t("uni-calender.WED")
},
THUText() {
return t("uni-calender.THU")
},
FRIText() {
return t("uni-calender.FRI")
},
SATText() {
return t("uni-calender.SAT")
},
SUNText() {
return t("uni-calender.SUN")
},
},
watch: {
date(newVal) {
// this.cale.setDate(newVal)
this.init(newVal)
},
startDate(val){
this.cale.resetSatrtDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
endDate(val){
this.cale.resetEndDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
selected(newVal) {
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
this.weeks = this.cale.weeks
}
},
created() {
//
this.cale = new Calendar({
// date: new Date(),
selected: this.selected,
startDate: this.startDate,
endDate: this.endDate,
range: this.range,
})
//
// this.cale.setDate(this.date)
this.init(this.date)
// this.setDay
},
methods: {
// 穿
clean() {},
bindDateChange(e) {
const value = e.detail.value + '-1'
console.log(this.cale.getDate(value));
this.init(value)
},
/**
* 初始化日期显示
* @param {Object} date
*/
init(date) {
this.cale.setDate(date)
this.weeks = this.cale.weeks
this.nowDate = this.calendar = this.cale.getInfo(date)
},
/**
* 打开日历弹窗
*/
open() {
//
if (this.clearDate && !this.insert) {
this.cale.cleanMultipleStatus()
// this.cale.setDate(this.date)
this.init(this.date)
}
this.show = true
this.$nextTick(() => {
setTimeout(() => {
this.aniMaskShow = true
}, 50)
})
},
/**
* 关闭日历弹窗
*/
close() {
this.aniMaskShow = false
this.$nextTick(() => {
setTimeout(() => {
this.show = false
this.$emit('close')
}, 300)
})
},
/**
* 确认按钮
*/
confirm() {
this.setEmit('confirm')
this.close()
},
/**
* 变化触发
*/
change() {
if (!this.insert) return
this.setEmit('change')
},
/**
* 选择月份触发
*/
monthSwitch() {
let {
year,
month
} = this.nowDate
this.$emit('monthSwitch', {
year,
month: Number(month)
})
},
/**
* 派发事件
* @param {Object} name
*/
setEmit(name) {
let {
year,
month,
date,
fullDate,
lunar,
extraInfo
} = this.calendar
this.$emit(name, {
range: this.cale.multipleStatus,
year,
month,
date,
fulldate: fullDate,
lunar,
extraInfo: extraInfo || {}
})
},
/**
* 选择天触发
* @param {Object} weeks
*/
choiceDate(weeks) {
if (weeks.disable) return
this.calendar = weeks
//
this.cale.setMultiple(this.calendar.fullDate)
this.weeks = this.cale.weeks
this.change()
},
/**
* 回到今天
*/
backtoday() {
console.log(this.cale.getDate(new Date()).fullDate);
let date = this.cale.getDate(new Date()).fullDate
// this.cale.setDate(date)
this.init(date)
this.change()
},
/**
* 上个月
*/
pre() {
const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
this.setDate(preDate)
this.monthSwitch()
},
/**
* 下个月
*/
next() {
const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
this.setDate(nextDate)
this.monthSwitch()
},
/**
* 设置日期
* @param {Object} date
*/
setDate(date) {
this.cale.setDate(date)
this.weeks = this.cale.weeks
this.nowDate = this.cale.getInfo(date)
}
}
}
</script>
<style lang="scss" scoped>
.uni-calendar {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.uni-calendar__mask {
position: fixed;
bottom: 0;
top: 0;
left: 0;
right: 0;
background-color: $uni-bg-color-mask;
transition-property: opacity;
transition-duration: 0.3s;
opacity: 0;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-calendar--mask-show {
opacity: 1
}
.uni-calendar--fixed {
position: fixed;
bottom: calc(var(--window-bottom));
left: 0;
right: 0;
transition-property: transform;
transition-duration: 0.3s;
transform: translateY(460px);
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-calendar--ani-show {
transform: translateY(0);
}
.uni-calendar__content {
background-color: #fff;
}
.uni-calendar__header {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
height: 50px;
border-bottom-color: $uni-border-color;
border-bottom-style: solid;
border-bottom-width: 1px;
}
.uni-calendar--fixed-top {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
border-top-color: $uni-border-color;
border-top-style: solid;
border-top-width: 1px;
}
.uni-calendar--fixed-width {
width: 50px;
// padding: 0 15px;
}
.uni-calendar__backtoday {
position: absolute;
right: 0;
top: 25rpx;
padding: 0 5px;
padding-left: 10px;
height: 25px;
line-height: 25px;
font-size: 12px;
border-top-left-radius: 25px;
border-bottom-left-radius: 25px;
color: $uni-text-color;
background-color: $uni-bg-color-hover;
}
.uni-calendar__header-text {
text-align: center;
width: 100px;
font-size: $uni-font-size-base;
color: $uni-text-color;
}
.uni-calendar__header-btn-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
}
.uni-calendar__header-btn {
width: 10px;
height: 10px;
border-left-color: $uni-text-color-placeholder;
border-left-style: solid;
border-left-width: 2px;
border-top-color: $uni-color-subtitle;
border-top-style: solid;
border-top-width: 2px;
}
.uni-calendar--left {
transform: rotate(-45deg);
}
.uni-calendar--right {
transform: rotate(135deg);
}
.uni-calendar__weeks {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-calendar__weeks-item {
flex: 1;
}
.uni-calendar__weeks-day {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
height: 45px;
border-bottom-color: #F5F5F5;
border-bottom-style: solid;
border-bottom-width: 1px;
}
.uni-calendar__weeks-day-text {
font-size: 14px;
}
.uni-calendar__box {
position: relative;
}
.uni-calendar__box-bg {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.uni-calendar__box-bg-text {
font-size: 200px;
font-weight: bold;
color: $uni-text-color-grey;
opacity: 0.1;
text-align: center;
/* #ifndef APP-NVUE */
line-height: 1;
/* #endif */
}
</style>

354
uni_modules/uni-calendar/components/uni-calendar/util.js

@ -0,0 +1,354 @@
import CALENDAR from './calendar.js'
class Calendar {
constructor({
date,
selected,
startDate,
endDate,
range
} = {}) {
// 当前日期
this.date = this.getDate(new Date()) // 当前初入日期
// 打点信息
this.selected = selected || [];
// 范围开始
this.startDate = startDate
// 范围结束
this.endDate = endDate
this.range = range
// 多选状态
this.cleanMultipleStatus()
// 每周日期
this.weeks = {}
// this._getWeek(this.date.fullDate)
}
/**
* 设置日期
* @param {Object} date
*/
setDate(date) {
this.selectDate = this.getDate(date)
this._getWeek(this.selectDate.fullDate)
}
/**
* 清理多选状态
*/
cleanMultipleStatus() {
this.multipleStatus = {
before: '',
after: '',
data: []
}
}
/**
* 重置开始日期
*/
resetSatrtDate(startDate) {
// 范围开始
this.startDate = startDate
}
/**
* 重置结束日期
*/
resetEndDate(endDate) {
// 范围结束
this.endDate = endDate
}
/**
* 获取任意时间
*/
getDate(date, AddDayCount = 0, str = 'day') {
if (!date) {
date = new Date()
}
if (typeof date !== 'object') {
date = date.replace(/-/g, '/')
}
const dd = new Date(date)
switch (str) {
case 'day':
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
break
case 'month':
if (dd.getDate() === 31) {
dd.setDate(dd.getDate() + AddDayCount)
} else {
dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
}
break
case 'year':
dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
break
}
const y = dd.getFullYear()
const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
return {
fullDate: y + '-' + m + '-' + d,
year: y,
month: m,
date: d,
day: dd.getDay()
}
}
/**
* 获取上月剩余天数
*/
_getLastMonthDays(firstDay, full) {
let dateArr = []
for (let i = firstDay; i > 0; i--) {
const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
dateArr.push({
date: beforeDate,
month: full.month - 1,
lunar: this.getlunar(full.year, full.month - 1, beforeDate),
disable: true
})
}
return dateArr
}
/**
* 获取本月天数
*/
_currentMonthDys(dateData, full) {
let dateArr = []
let fullDate = this.date.fullDate
for (let i = 1; i <= dateData; i++) {
let isinfo = false
let nowDate = full.year + '-' + (full.month < 10 ?
full.month : full.month) + '-' + (i < 10 ?
'0' + i : i)
// 是否今天
let isDay = fullDate === nowDate
// 获取打点信息
let info = this.selected && this.selected.find((item) => {
if (this.dateEqual(nowDate, item.date)) {
return item
}
})
// 日期禁用
let disableBefore = true
let disableAfter = true
if (this.startDate) {
// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
disableBefore = this.dateCompare(this.startDate, nowDate)
}
if (this.endDate) {
// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
disableAfter = this.dateCompare(nowDate, this.endDate)
}
let multiples = this.multipleStatus.data
let checked = false
let multiplesStatus = -1
if (this.range) {
if (multiples) {
multiplesStatus = multiples.findIndex((item) => {
return this.dateEqual(item, nowDate)
})
}
if (multiplesStatus !== -1) {
checked = true
}
}
let data = {
fullDate: nowDate,
year: full.year,
date: i,
multiple: this.range ? checked : false,
beforeMultiple: this.dateEqual(this.multipleStatus.before, nowDate),
afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
month: full.month,
lunar: this.getlunar(full.year, full.month, i),
disable: !(disableBefore && disableAfter),
isDay
}
if (info) {
data.extraInfo = info
}
dateArr.push(data)
}
return dateArr
}
/**
* 获取下月天数
*/
_getNextMonthDays(surplus, full) {
let dateArr = []
for (let i = 1; i < surplus + 1; i++) {
dateArr.push({
date: i,
month: Number(full.month) + 1,
lunar: this.getlunar(full.year, Number(full.month) + 1, i),
disable: true
})
}
return dateArr
}
/**
* 获取当前日期详情
* @param {Object} date
*/
getInfo(date) {
if (!date) {
date = new Date()
}
const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
return dateInfo
}
/**
* 比较时间大小
*/
dateCompare(startDate, endDate) {
// 计算截止时间
startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
// 计算详细项的截止时间
endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
if (startDate <= endDate) {
return true
} else {
return false
}
}
/**
* 比较时间是否相等
*/
dateEqual(before, after) {
// 计算截止时间
before = new Date(before.replace('-', '/').replace('-', '/'))
// 计算详细项的截止时间
after = new Date(after.replace('-', '/').replace('-', '/'))
if (before.getTime() - after.getTime() === 0) {
return true
} else {
return false
}
}
/**
* 获取日期范围内所有日期
* @param {Object} begin
* @param {Object} end
*/
geDateAll(begin, end) {
var arr = []
var ab = begin.split('-')
var ae = end.split('-')
var db = new Date()
db.setFullYear(ab[0], ab[1] - 1, ab[2])
var de = new Date()
de.setFullYear(ae[0], ae[1] - 1, ae[2])
var unixDb = db.getTime() - 24 * 60 * 60 * 1000
var unixDe = de.getTime() - 24 * 60 * 60 * 1000
for (var k = unixDb; k <= unixDe;) {
k = k + 24 * 60 * 60 * 1000
arr.push(this.getDate(new Date(parseInt(k))).fullDate)
}
return arr
}
/**
* 计算阴历日期显示
*/
getlunar(year, month, date) {
return CALENDAR.solar2lunar(year, month, date)
}
/**
* 设置打点
*/
setSelectInfo(data, value) {
this.selected = value
this._getWeek(data)
}
/**
* 获取多选状态
*/
setMultiple(fullDate) {
let {
before,
after
} = this.multipleStatus
if (!this.range) return
if (before && after) {
this.multipleStatus.before = ''
this.multipleStatus.after = ''
this.multipleStatus.data = []
} else {
if (!before) {
this.multipleStatus.before = fullDate
} else {
this.multipleStatus.after = fullDate
if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
} else {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
}
}
}
this._getWeek(fullDate)
}
/**
* 获取每周数据
* @param {Object} dateData
*/
_getWeek(dateData) {
const {
fullDate,
year,
month,
date,
day
} = this.getDate(dateData)
let firstDay = new Date(year, month - 1, 1).getDay()
let currentDay = new Date(year, month, 0).getDate()
let dates = {
lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
nextMonthDays: [], // 下个月开始几天
weeks: []
}
let canlender = []
const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
let weeks = {}
// 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
for (let i = 0; i < canlender.length; i++) {
if (i % 7 === 0) {
weeks[parseInt(i / 7)] = new Array(7)
}
weeks[parseInt(i / 7)][i % 7] = canlender[i]
}
this.canlender = canlender
this.weeks = weeks
}
//静态方法
// static init(date) {
// if (!this.instance) {
// this.instance = new Calendar(date);
// }
// return this.instance;
// }
}
export default Calendar

88
uni_modules/uni-calendar/package.json

@ -0,0 +1,88 @@
{
"id": "uni-calendar",
"displayName": "uni-calendar 日历",
"version": "1.4.3",
"description": "日历组件",
"keywords": [
"uni-ui",
"uniui",
"日历",
"",
"打卡",
"日历选择"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

103
uni_modules/uni-calendar/readme.md

@ -0,0 +1,103 @@
## Calendar 日历
> **组件名:uni-calendar**
> 代码块: `uCalendar`
日历组件
> **注意事项**
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 本组件农历转换使用的js是 [@1900-2100区间内的公历、农历互转](https://github.com/jjonline/calendar.js)
> - 仅支持自定义组件模式
> - `date`属性传入的应该是一个 String ,如: 2019-06-27 ,而不是 new Date()
> - 通过 `insert` 属性来确定当前的事件是 @change 还是 @confirm 。理应合并为一个事件,但是为了区分模式,现使用两个事件,这里需要注意
> - 弹窗模式下无法阻止后面的元素滚动,如有需要阻止,请在弹窗弹出后,手动设置滚动元素为不可滚动
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
### 基本用法
在 ``template`` 中使用组件
```html
<view>
<uni-calendar
:insert="true"
:lunar="true"
:start-date="'2019-3-2'"
:end-date="'2019-5-20'"
@change="change"
/>
</view>
```
### 通过方法打开日历
需要设置 `insert``false`
```html
<view>
<uni-calendar
ref="calendar"
:insert="false"
@confirm="confirm"
/>
<button @click="open">打开日历</button>
</view>
```
```javascript
export default {
data() {
return {};
},
methods: {
open(){
this.$refs.calendar.open();
},
confirm(e) {
console.log(e);
}
}
};
```
## API
### Calendar Props
| 属性名 | 类型 | 默认值| 说明 |
| | |
| date | String |- | 自定义当前时间,默认为今天 |
| lunar | Boolean | false | 显示农历 |
| startDate | String |- | 日期选择范围-开始日期 |
| endDate | String |- | 日期选择范围-结束日期 |
| range | Boolean | false | 范围选择 |
| insert | Boolean | false | 插入模式,可选值,ture:插入模式;false:弹窗模式;默认为插入模式 |
|clearDate |Boolean |true |弹窗模式是否清空上次选择内容 |
| selected | Array |- | 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}] |
|showMonth | Boolean | true | 是否显示月份为背景 |
### Calendar Events
| 事件名 | 说明 |返回值|
| | | |
| open | 弹出日历组件,`insert :false` 时生效|- |
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar](https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar)

761
utils/time.js

@ -1,384 +1,379 @@
import dayjs from 'dayjs';
// const advancedFormat = require('dayjs/plugin/advancedFormat');
// const weekOfYear = require('dayjs/plugin/weekOfYear');
// const duration = require('dayjs/plugin/duration');
// dayjs.extend(advancedFormat);
// dayjs.extend(weekOfYear);
// dayjs.extend(duration);
/**
* 格式化数字
* @param {*} n
*/
const formatNumber = n => {
const str = n.toString();
return str[1] ? str : `0${str}`;
};
/**
* 格式化时间
* @param {number} beginTime
*/
const formatTime = beginTime => {
const date = new Date(beginTime);
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const minute = date.getMinutes();
const second = date.getSeconds();
return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}`;
};
/**
* 添加一定时间的时长
* @param {number | date} time
* @param {number} num
* @param {string} cycle
*/
const add = (time, num, cycle) => {
const str = dayjs(time).add(num, cycle);
return str;
};
/**
* 时间转换 08:00 转换成8小时0分钟
* @param {string} time
* @returns {{hours: number, minutes: number}}
*/
const convertTime = time => {
const arr = time.split(':');
return {
hours: parseInt(arr[0], 10),
minutes: parseInt(arr[1], 10),
};
};
/**
* 将秒 ->
* @param {number} seconds
*/
const secondToMinute = seconds => {
const minute = formatNumber(Math.floor(seconds / 60));
const second = formatNumber(parseInt(seconds % 60, 10));
return {
minute,
second,
};
};
/**
* 将时间戳 -> :
* @param {Number} timestamp 时间戳
* @return date:2018/10/09 time: 12:59
*/
const setTimestampToStr = timestamp => {
const timeObj = new Date(timestamp);
const year = timeObj.getFullYear();
const month = formatNumber(timeObj.getMonth() + 1);
const day = formatNumber(timeObj.getDate());
const hour = formatNumber(timeObj.getHours());
const minute = formatNumber(timeObj.getMinutes());
const date = `${year}-${month}-${day}`;
const time = `${hour}:${minute}`;
return {
date,
time,
};
};
/**
* 检测时间(ms)是不是今天
* @param {Number} time 时间戳
*/
const validateTimeIsToday = time => {
const timeDate = new Date(time);
const date = new Date();
return timeDate.getFullYear() === date.getFullYear() && timeDate.getMonth() === date.getMonth() && timeDate
.getDate() === date.getDate();
};
/**
* 检测两个日期是否相同
* @param {number | date} time
* @param {number | date} value
* @param {string} cycle 传入 day 将会比较 day month和 year
*/
const isSame = (time, value, cycle) => {
const str = dayjs(time).isSame(value, cycle);
return str;
};
/**
* 格式化开始时间
* @param {Number} timestamp 时间戳
* @return
* 如果是今天 -> :
* 如果不是今年 -> // :
* 否则 ** :
*/
const formatBeginTime = timestamp => {
const timeObj = new Date(timestamp);
const year = timeObj.getFullYear();
const month = formatNumber(timeObj.getMonth() + 1);
const day = formatNumber(timeObj.getDate());
const hour = formatNumber(timeObj.getHours());
const minute = formatNumber(timeObj.getMinutes());
const date = `${year}/${month}/${day}`;
const time = `${hour}:${minute}`;
const currentYear = new Date().getFullYear();
if (validateTimeIsToday(timestamp)) {
// 今天
return `今天 ${time}`;
} else if (currentYear !== year) {
// 不是今年
return `${date} ${time}`;
} else {
return `${month}${day}${time}`;
}
};
/**
* 格式化时长
* @param {Number} duration 时长
* 超过24小时 24 * 60 * 60 * 1000 ms 转换成天数 + 小时 + 分钟
* 小于1分钟 60 * 1000 ms 转换成秒钟
* 其余的显示分钟
* 超过2小时 2 * 60 * 60 * 1000 ms 转换成小时 + 分钟数
*/
const formatDuration = duration => {
const minuteTime = 60 * 1000;
const hourTime = 60 * minuteTime;
const dayTime = 24 * hourTime;
const days = Math.floor(duration / dayTime);
const hours = Math.floor((duration % dayTime) / hourTime);
const minutes = Math.floor((duration % hourTime) / minuteTime);
if (duration <= 60 * 1000) {
// 小于1分钟 返回几秒
return `${Math.floor(duration / 1000)}`;
} else if (duration > dayTime) {
// 大于1天
if (minutes === 0) {
if (hours === 0) {
// 分钟数是0 和 小时数是0 返回 几天
return `${days}`;
} else {
// 分钟是0 小时不是0 返回 几天几小时
return `${days}${hours}小时`;
}
} else {
// 分钟不是0 返回几天几时几分
return `${days}${hours}${minutes}`;
}
} else if (duration > 2 * hourTime) {
// 大于2h
if (minutes === 0) {
// 分钟是0 返回几小时
return `${hours}小时`;
} else {
// 分钟不是0 返回几小时几分钟
return `${hours}小时${minutes}分钟`;
}
} else {
// 其余情况 返回 几分钟
return `${parseInt(duration / minuteTime)}分钟`;
}
};
/**
* 格式化时长 转换成对象格式
* @param {Number} duration 时长
* 超过24小时 24 * 60 * 60 * 1000 ms 转换成{days, hours, minutes, seconds: 0}
* 小于1分钟 60 * 1000 ms 转换成秒钟 { days: 0, hours: 0, minutes: 0, seconds }
* 其余的显示分钟 { days: 0, hours: 0, minutes, seconds: 0 }
* 超过2小时 2 * 60 * 60 * 1000 ms 转换成{ days: 0, hours, minutes, seconds: 0 }
*/
const formatDurationToObject = duration => {
const minuteTime = 60 * 1000;
const hourTime = 60 * minuteTime;
const dayTime = 24 * hourTime;
const days = Math.floor(duration / dayTime);
const hours = Math.floor((duration % dayTime) / hourTime);
const minutes = Math.floor((duration % hourTime) / minuteTime);
const result = {
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
};
if (duration <= 60 * 1000) {
// 小于1分钟 返回几秒
result.seconds = Math.floor(duration / 1000);
} else if (duration > dayTime) {
// 大于1天
if (minutes === 0) {
if (hours === 0) {
// 分钟数是0 和 小时数是0 返回 几天
result.days = days;
} else {
// 分钟是0 小时不是0 返回 几天几小时
result.days = days;
result.hours = hours;
}
} else {
// 分钟不是0 返回几天几时几分
result.days = days;
result.hours = hours;
result.minutes = minutes;
}
} else if (duration > 2 * hourTime) {
// 大于2h
if (minutes === 0) {
// 分钟是0 返回几小时
result.hours = hours;
} else {
// 分钟不是0 返回几小时几分钟
result.hours = hours;
result.minutes = minutes;
}
} else {
// 其余情况 返回 几分钟
result.minutes = minutes;
}
return result;
};
/**
* 将对象格式的时间转换成时间戳
* @param {obj} 对象格式的时间 days, hours, minutes, seconds
* @return 时长的ms
*/
const formatObjectTimeToMs = (days = 0, hours = 0, minutes = 0, seconds = 0) => {
return days * 24 * 60 * 60 * 1000 + hours * 60 * 60 * 1000 + minutes * 60 * 1000 + seconds * 1000;
};
/**
* 计算过滤 周期
* @param {string} time 周期字符串
* @return {string} cycle 周期英文字符串
*/
const computeCycle = time => {
// 加载下一个周期的任务
let cycle = 'day';
switch (time) {
case '天':
cycle = 'day';
break;
case '周':
cycle = 'week';
break;
case '月':
cycle = 'month';
break;
default:
cycle = '日程';
break;
}
return cycle;
};
/**
* 将时间按周期语义化
* @param {string} cycle 周期
* @param {number|string} time 时间
*/
const formatStartTimeToCycleTime = (cycle, time) => {
let result = '';
const _time = dayjs(+time);
switch (cycle) {
case '天':
result = _time.format('YYYY年M月D日');
break;
case '周':
result = _time.format('YYYY年w周');
break;
case '月':
result = _time.format('YYYY年M月');
break;
case '日程':
result = _time.format('YYYY年M月D日 HH:mm');
break;
default:
result = _time.format('YYYY年M月D日');
break;
}
return result;
};
/**
* 计算进行中状态剩余时间 显示数字
* @param {number} leftTime 剩余时间ms
* @returns { num: 显示的数字, time: 演示器演示时长 }
*/
const computeDurationText = leftTime => {
try {
if (leftTime < 0) return {
num: 0,
time: null
};
const {
years,
months,
days,
hours,
minutes,
seconds,
milliseconds
} = dayjs.duration(leftTime).$d;
let num = 0;
let time = 1000;
if (years > 0) {
num = years;
time = 60 * 60 * 1000; // 按小时
} else if (months > 0) {
num = months;
time = 60 * 60 * 1000; // 按小时
} else if (days > 0) {
num = days;
time = 60 * 60 * 1000; // 按小时
} else if (hours > 0) {
num = hours;
} else if (minutes > 0) {
num = minutes;
} else if (seconds > 0) {
num = seconds;
} else if (milliseconds > 0) {
num = milliseconds;
time = 16;
} else {
time = null;
}
return {
num,
time
};
} catch (error) {
console.log('🚀 ~ file: time.js ~ line 335 ~ computeDurationText ~ error', error);
return {
num: 0,
time: null
};
}
};
export default {
formatNumber,
formatTime,
add,
convertTime,
secondToMinute,
setTimestampToStr,
isSame,
formatBeginTime,
formatDuration,
formatDurationToObject,
formatObjectTimeToMs,
computeCycle,
formatStartTimeToCycleTime,
computeDurationText,
import dayjs from 'dayjs';
// const advancedFormat = require('dayjs/plugin/advancedFormat');
// const weekOfYear = require('dayjs/plugin/weekOfYear');
// const duration = require('dayjs/plugin/duration');
// dayjs.extend(advancedFormat);
// dayjs.extend(weekOfYear);
// dayjs.extend(duration);
/**
* 格式化数字
* @param {*} n
*/
const formatNumber = (n) => {
const str = n.toString();
return str[1] ? str : `0${str}`;
};
/**
* 格式化时间
* @param {number} beginTime
*/
const formatTime = (beginTime) => {
const date = new Date(beginTime);
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const minute = date.getMinutes();
const second = date.getSeconds();
return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}`;
};
/**
* 添加一定时间的时长
* @param {number | date} time
* @param {number} num
* @param {string} cycle
*/
const add = (time, num, cycle) => {
const str = dayjs(time).add(num, cycle);
return str;
};
/**
* 时间转换 08:00 转换成8小时0分钟
* @param {string} time
* @returns {{hours: number, minutes: number}}
*/
const convertTime = (time) => {
const arr = time.split(':');
return {
hours: parseInt(arr[0], 10),
minutes: parseInt(arr[1], 10),
};
};
/**
* 将秒 ->
* @param {number} seconds
*/
const secondToMinute = (seconds) => {
const minute = formatNumber(Math.floor(seconds / 60));
const second = formatNumber(parseInt(seconds % 60, 10));
return {
minute,
second,
};
};
/**
* 将时间戳 -> :
* @param {Number} timestamp 时间戳
* @return date:2018/10/09 time: 12:59
*/
const setTimestampToStr = (timestamp) => {
const timeObj = new Date(timestamp);
const year = timeObj.getFullYear();
const month = formatNumber(timeObj.getMonth() + 1);
const day = formatNumber(timeObj.getDate());
const hour = formatNumber(timeObj.getHours());
const minute = formatNumber(timeObj.getMinutes());
const date = `${year}-${month}-${day}`;
const time = `${hour}:${minute}`;
return {
date,
time,
};
};
/**
* 检测时间(ms)是不是今天
* @param {Number} time 时间戳
*/
const validateTimeIsToday = (time) => {
const timeDate = new Date(time);
const date = new Date();
return timeDate.getFullYear() === date.getFullYear() && timeDate.getMonth() === date.getMonth() && timeDate
.getDate() === date.getDate();
};
/**
* 检测两个日期是否相同
* @param {number | date} time
* @param {number | date} value
* @param {string} cycle 传入 day 将会比较 day month和 year
*/
const isSame = (time, value, cycle) => {
const str = dayjs(time).isSame(value, cycle);
return str;
};
/**
* 格式化开始时间
* @param {Number} timestamp 时间戳
* @return
* 如果是今天 -> :
* 如果不是今年 -> // :
* 否则 ** :
*/
const formatBeginTime = (timestamp) => {
const timeObj = new Date(timestamp);
const year = timeObj.getFullYear();
const month = formatNumber(timeObj.getMonth() + 1);
const day = formatNumber(timeObj.getDate());
const hour = formatNumber(timeObj.getHours());
const minute = formatNumber(timeObj.getMinutes());
const date = `${year}/${month}/${day}`;
const time = `${hour}:${minute}`;
const currentYear = new Date().getFullYear();
if (validateTimeIsToday(timestamp)) {
// 今天
return `今天 ${time}`;
} if (currentYear !== year) {
// 不是今年
return `${date} ${time}`;
}
return `${month}${day}${time}`;
};
/**
* 格式化时长
* @param {Number} duration 时长
* 超过24小时 24 * 60 * 60 * 1000 ms 转换成天数 + 小时 + 分钟
* 小于1分钟 60 * 1000 ms 转换成秒钟
* 其余的显示分钟
* 超过2小时 2 * 60 * 60 * 1000 ms 转换成小时 + 分钟数
*/
const formatDuration = (duration) => {
const minuteTime = 60 * 1000;
const hourTime = 60 * minuteTime;
const dayTime = 24 * hourTime;
const days = Math.floor(duration / dayTime);
const hours = Math.floor((duration % dayTime) / hourTime);
const minutes = Math.floor((duration % hourTime) / minuteTime);
if (duration <= 60 * 1000) {
// 小于1分钟 返回几秒
return `${Math.floor(duration / 1000)}`;
} if (duration > dayTime) {
// 大于1天
if (minutes === 0) {
if (hours === 0) {
// 分钟数是0 和 小时数是0 返回 几天
return `${days}`;
}
// 分钟是0 小时不是0 返回 几天几小时
return `${days}${hours}小时`;
}
// 分钟不是0 返回几天几时几分
return `${days}${hours}${minutes}`;
} if (duration > 2 * hourTime) {
// 大于2h
if (minutes === 0) {
// 分钟是0 返回几小时
return `${hours}小时`;
}
// 分钟不是0 返回几小时几分钟
return `${hours}小时${minutes}分钟`;
}
// 其余情况 返回 几分钟
return `${parseInt(duration / minuteTime)}分钟`;
};
/**
* 格式化时长 转换成对象格式
* @param {Number} duration 时长
* 超过24小时 24 * 60 * 60 * 1000 ms 转换成{days, hours, minutes, seconds: 0}
* 小于1分钟 60 * 1000 ms 转换成秒钟 { days: 0, hours: 0, minutes: 0, seconds }
* 其余的显示分钟 { days: 0, hours: 0, minutes, seconds: 0 }
* 超过2小时 2 * 60 * 60 * 1000 ms 转换成{ days: 0, hours, minutes, seconds: 0 }
*/
const formatDurationToObject = (duration) => {
const minuteTime = 60 * 1000;
const hourTime = 60 * minuteTime;
const dayTime = 24 * hourTime;
const days = Math.floor(duration / dayTime);
const hours = Math.floor((duration % dayTime) / hourTime);
const minutes = Math.floor((duration % hourTime) / minuteTime);
const result = {
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
};
if (duration <= 60 * 1000) {
// 小于1分钟 返回几秒
result.seconds = Math.floor(duration / 1000);
} else if (duration > dayTime) {
// 大于1天
if (minutes === 0) {
if (hours === 0) {
// 分钟数是0 和 小时数是0 返回 几天
result.days = days;
} else {
// 分钟是0 小时不是0 返回 几天几小时
result.days = days;
result.hours = hours;
}
} else {
// 分钟不是0 返回几天几时几分
result.days = days;
result.hours = hours;
result.minutes = minutes;
}
} else if (duration > 2 * hourTime) {
// 大于2h
if (minutes === 0) {
// 分钟是0 返回几小时
result.hours = hours;
} else {
// 分钟不是0 返回几小时几分钟
result.hours = hours;
result.minutes = minutes;
}
} else {
// 其余情况 返回 几分钟
result.minutes = minutes;
}
return result;
};
/**
* 将对象格式的时间转换成时间戳
* @param {obj} 对象格式的时间 days, hours, minutes, seconds
* @return 时长的ms
*/
const formatObjectTimeToMs = (days = 0, hours = 0, minutes = 0, seconds = 0) => days * 24 * 60 * 60 * 1000 + hours * 60 * 60 * 1000 + minutes * 60 * 1000 + seconds * 1000;
/**
* 计算过滤 周期
* @param {string} time 周期字符串
* @return {string} cycle 周期英文字符串
*/
const computeCycle = (time) => {
// 加载下一个周期的任务
let cycle = 'day';
switch (time) {
case '天':
cycle = 'day';
break;
case '周':
cycle = 'week';
break;
case '月':
cycle = 'month';
break;
default:
cycle = '日程';
break;
}
return cycle;
};
/**
* 将时间按周期语义化
* @param {string} cycle 周期
* @param {number|string} time 时间
*/
const formatStartTimeToCycleTime = (cycle, time) => {
let result = '';
const _time = dayjs(+time);
switch (cycle) {
case '天':
result = _time.format('YYYY年M月D日');
break;
case '周':
result = _time.format('YYYY年w周');
break;
case '月':
result = _time.format('YYYY年M月');
break;
case '日程':
result = _time.format('YYYY年M月D日 HH:mm');
break;
default:
result = _time.format('YYYY年M月D日');
break;
}
return result;
};
/**
* 计算进行中状态剩余时间 显示数字
* @param {number} leftTime 剩余时间ms
* @returns { num: 显示的数字, time: 演示器演示时长 }
*/
const computeDurationText = (leftTime) => {
try {
if (leftTime < 0) {
return {
num: 0,
time: null,
};
}
const {
years,
months,
days,
hours,
minutes,
seconds,
milliseconds,
} = dayjs.duration(leftTime).$d;
let num = 0;
let time = 1000;
if (years > 0) {
num = years;
time = 60 * 60 * 1000; // 按小时
} else if (months > 0) {
num = months;
time = 60 * 60 * 1000; // 按小时
} else if (days > 0) {
num = days;
time = 60 * 60 * 1000; // 按小时
} else if (hours > 0) {
num = hours;
} else if (minutes > 0) {
num = minutes;
} else if (seconds > 0) {
num = seconds;
} else if (milliseconds > 0) {
num = milliseconds;
time = 16;
} else {
time = null;
}
return {
num,
time,
};
} catch (error) {
console.log('🚀 ~ file: time.js ~ line 335 ~ computeDurationText ~ error', error);
return {
num: 0,
time: null,
};
}
};
export default {
formatNumber,
formatTime,
add,
convertTime,
secondToMinute,
setTimestampToStr,
isSame,
formatBeginTime,
formatDuration,
formatDurationToObject,
formatObjectTimeToMs,
computeCycle,
formatStartTimeToCycleTime,
computeDurationText,
};

Loading…
Cancel
Save