Browse Source

feat: 添加日历

test2
song 4 years ago
parent
commit
94e4a7d644
  1. 56
      .eslintrc.js
  2. 1
      CHANGELOG.md
  3. 473
      components/Calendar/Calendar - 副本.vue
  4. 524
      components/Calendar/Calendar.vue
  5. 8
      components/Projects/Projects.vue
  6. 13
      pages.json
  7. 161
      pages/index/index.vue
  8. 64
      pages/project/project.vue
  9. 89
      store/index.js
  10. 3
      store/project/actions.js
  11. 11
      store/project/getters.js
  12. 12
      store/project/index.js
  13. 62
      store/project/mutations.js
  14. 8
      store/project/state.js
  15. 761
      utils/time.js

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": {
}
},
};

1
CHANGELOG.md

@ -7,6 +7,7 @@
- | 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)
- | 使用uview完成api请求 | [1b3efd8](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/1b3efd8)
- | 更新代码 | [392c8cc](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/392c8cc)
范围|描述|commitId

473
components/Calendar/Calendar - 副本.vue

@ -0,0 +1,473 @@
<template>
<view class="zzx-calendar">
<view class="calendar-heander">
{{ timeStr }}
</view>
<!-- 星期几标题 -->
<view class="calendar-weeks">
<view class="calendar-week" :class="{ 'text-red-500': week === '六' || week === '日' }" v-for="(week, index) in weeks" :key="index">
{{ week }}
</view>
</view>
<view class="calendar-content">
<swiper
class="calendar-swiper"
:style="{
width: '100%',
height: sheight,
}"
:indicator-dots="false"
:autoplay="false"
:duration="duration"
:current="current"
@change="changeSwp"
:circular="true"
>
<swiper-item class="calendar-item" v-for="sitem in swiper" :key="sitem">
<view class="calendar-days">
<!-- 当前的 -->
<template v-if="sitem === current">
<view
class="calendar-day"
v-for="(item, index) in days"
:key="index"
:class="{ 'day-hidden': !item.show }"
@click="clickItem(item)"
>
<view class="date" :class="[item.isToday ? todayClass : '', item.fullDate === selectedDate ? checkedClass : '']">
{{ item.time.getDate() }}
</view>
<view class="dot-show" v-if="item.info === '0'" :style="dotStyle"> </view>
</view>
</template>
<template v-else>
<!-- 下一个月/ -->
<template v-if="current - sitem === 1 || 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 ? todayClass : '']">
{{ 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 ? todayClass : '']">
{{ 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>
import { mapState } from 'vuex';
import { gegerateDates, formatDate } from './generateDates.js';
export default {
props: {
duration: { type: Number, default: 500 },
//
showBack: { type: Boolean, default: false },
// class
todayClass: { type: String, default: 'is-today' },
// class
checkedClass: { type: String, default: 'is-checked' },
//
dotStyle: {
type: Object,
default: () => {
return { background: '#4ade80' };
},
},
},
watch: {
dotList: function (newvalue) {
const days = this.days.slice(0);
const index = days.findIndex(day => day.show);
days.forEach((day, i) => {
newvalue.forEach((item, j) => {
if (i - index === j) {
day.info = item;
}
});
});
this.days = days;
},
},
data() {
return {
weeks: ['日', '一', '二', '三', '四', '五', '六'], //
current: 1,
currentYear: '',
currentMonth: '',
currentDate: '',
days: [],
weekMode: false, // false -> true ->
swiper: [0, 1, 2],
selectedDate: formatDate(new Date(), 'yyyy-MM-dd'), //
start: '',
end: '',
};
},
computed: {
...mapState('project', ['dotList']),
sheight() {
//
//
let h = '35px';
if (!this.weekMode) {
const d = new Date(this.currentYear, this.currentMonth, 0);
const days = d.getDate(); //
let 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;
},
//
timeStr() {
let str = '';
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
const y = d.getFullYear();
const m = d.getMonth() + 1 <= 9 ? `0${d.getMonth() + 1}` : d.getMonth() + 1;
str = `${y}${m}`;
return str;
},
// days
predays() {
let pres = [];
if (this.weekMode) {
//
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() - 7);
pres = gegerateDates(d, 'week');
} else {
//
const d = new Date(this.currentYear, this.currentMonth - 2, 1);
pres = gegerateDates(d, 'month');
}
return pres;
},
// days
nextdays() {
let nexts = [];
if (this.weekMode) {
//
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() + 7);
nexts = gegerateDates(d, 'week');
} else {
//
const d = new Date(this.currentYear, this.currentMonth, 1);
nexts = gegerateDates(d, 'month');
}
return nexts;
},
},
created() {
this.initDate();
this.start = this.$moment().startOf('month').valueOf();
this.end = this.$moment().endOf('month').valueOf();
},
methods: {
//
/**
* 滑动切换上下周期
* 根据前一个减去目前的值我们可以判断是下一个月/周还是上一个月/
* current - pre === 1, -2 下一个月/
* current - pre === -1, 2 上一个月或者上一周
*/
changeSwp(e) {
const pre = this.current;
const current = e.target.current;
this.current = current;
if (current - pre === 1 || current - pre === -2) {
//
this.daysNext();
const arr = this.days.filter(s => s.show);
const end = `${arr[arr.length - 1].fullDate} 23:59:59`;
this.start = this.$moment(arr[0].fullDate).valueOf();
this.end = this.$moment(end).valueOf();
this.$emit('handleFindPoint', this.start, this.end);
} else {
//
this.daysPre();
const arr = this.days.filter(s => s.show);
const end = `${arr[arr.length - 1].fullDate} 23:59:59`;
this.start = this.$moment(arr[0].fullDate).valueOf();
this.end = this.$moment(end).valueOf();
this.$emit('handleFindPoint', this.start, this.end);
}
},
//
initDate(cur) {
let date = '';
if (cur) {
date = new Date(cur);
} else {
date = new Date();
}
this.currentDate = date.getDate(); //
this.currentYear = date.getFullYear(); //
this.currentMonth = date.getMonth() + 1; //
this.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')
this.days = [];
let days = [];
if (this.weekMode) {
days = gegerateDates(date, 'week');
// this.selectedDate = days[0].fullDate;
} else {
days = gegerateDates(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) => {
this.dotList.forEach((item, j) => {
if (i === j) {
day.info = item;
}
});
});
this.days = days;
// ,
let obj = {
start: '',
end: '',
};
if (this.weekMode) {
obj.start = this.days[0].time;
obj.end = this.days[6].time;
} else {
const start = new Date(this.currentYear, this.currentMonth - 1, 1);
const end = new Date(this.currentYear, this.currentMonth, 0);
obj.start = start;
obj.end = end;
}
this.$emit('days-change', obj);
},
//
daysPre() {
if (this.weekMode) {
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() - 7);
this.initDate(d);
} else {
const d = new Date(this.currentYear, this.currentMonth - 2, 1);
this.initDate(d);
}
},
//
daysNext() {
if (this.weekMode) {
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() + 7);
this.initDate(d);
} else {
const d = new Date(this.currentYear, this.currentMonth, 1);
this.initDate(d);
}
},
//
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);
},
//
clickItem(e) {
this.selectedDate = e.fullDate;
this.$emit('selected-change', e);
},
//
goToday() {
const d = new Date();
this.initDate(d);
},
},
};
</script>
<style lang="scss" scoped>
.zzx-calendar {
width: 100%;
height: auto;
background-color: #fff;
padding-bottom: 10px;
.calendar-heander {
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>

524
components/Calendar/Calendar.vue

@ -1,14 +1,10 @@
<template>
<view class="zzx-calendar">
<view class="calendar-heander">
{{ timeStr }}
</view>
<view class="calendar-heander">{{ timeStr }}</view>
<!-- 星期几标题 -->
<view class="calendar-weeks">
<view class="calendar-week" :class="{ 'text-red-500': week === '六' || week === '日' }" v-for="(week, index) in weeks" :key="index">
{{ week }}
</view>
<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">
@ -25,26 +21,18 @@
@change="changeSwp"
:circular="true"
>
<swiper-item class="calendar-item" v-for="sitem in swiper" :key="sitem">
<swiper-item class="calendar-item" v-for="sitem in data.swiper" :key="sitem">
<view class="calendar-days">
<!-- 当前的 -->
<template v-if="sitem === current">
<view
class="calendar-day"
v-for="(item, index) in days"
:key="index"
:class="{ 'day-hidden': !item.show }"
@click="clickItem(item)"
>
<view class="date" :class="[item.isToday ? todayClass : '', item.fullDate === selectedDate ? checkedClass : '']">
{{ item.time.getDate() }}
</view>
<view class="dot-show" v-if="item.info === '0'" :style="dotStyle"> </view>
<template v-if="sitem === data.current">
<view class="calendar-day" v-for="(item, index) in days" :key="index" :class="{ 'day-hidden': !item.show }" @click="clickItem(item)">
<view class="date" :class="[item.isToday ? todayClass : '', item.fullDate === selectedDate ? checkedClass : '']">{{ item.time.getDate() }}</view>
<view class="dot-show" v-if="item.info === '0'" :style="dotStyle"></view>
</view>
</template>
<template v-else>
<!-- 下一个月/ -->
<template v-if="current - sitem === 1 || current - sitem === -2">
<template v-if="data.current - sitem === 1 || data.current - sitem === -2">
<view
class="calendar-day"
v-for="(item, index) in predays"
@ -53,9 +41,7 @@
'day-hidden': !item.show,
}"
>
<view class="date" :class="[item.isToday ? todayClass : '']">
{{ item.time.getDate() }}
</view>
<view class="date" :class="[item.isToday ? todayClass : '']">{{ item.time.getDate() }}</view>
</view>
</template>
<!-- 上一个月/ -->
@ -68,9 +54,7 @@
'day-hidden': !item.show,
}"
>
<view class="date" :class="[item.isToday ? todayClass : '']">
{{ item.time.getDate() }}
</view>
<view class="date" :class="[item.isToday ? todayClass : '']">{{ item.time.getDate() }}</view>
</view>
</template>
</template>
@ -83,274 +67,262 @@
</view> -->
</view>
<view class="flex justify-center u-font-18" style="color: #3b82f6" @click="goToday"> 今日 </view>
<view class="flex justify-center u-font-18" style="color: #3b82f6" @click="goToday">今日</view>
</view>
</template>
<script>
import { mapState } from 'vuex';
<script setup>
import { reactive, computed, watch, defineProps, defineEmits } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import { gegerateDates, formatDate } from './generateDates.js';
export default {
props: {
duration: { type: Number, default: 500 },
//
showBack: { type: Boolean, default: false },
// class
todayClass: { type: String, default: 'is-today' },
// class
checkedClass: { type: String, default: 'is-checked' },
//
dotStyle: {
type: Object,
default: () => {
return { background: '#4ade80' };
},
},
defineProps({
duration: { type: Number, default: 500 },
//
showBack: { type: Boolean, default: false },
// class
todayClass: { type: String, default: 'is-today' },
// class
checkedClass: { type: String, default: 'is-checked' },
//
dotStyle: {
type: Object,
default: () => ({ background: '#4ade80' }),
},
});
watch: {
dotList: function (newvalue) {
const days = this.days.slice(0);
const index = days.findIndex(day => day.show);
days.forEach((day, i) => {
newvalue.forEach((item, j) => {
if (i - index === j) {
day.info = item;
}
});
});
this.days = days;
},
},
data() {
return {
weeks: ['日', '一', '二', '三', '四', '五', '六'], //
current: 1,
currentYear: '',
currentMonth: '',
currentDate: '',
days: [],
weekMode: false, // false -> true ->
swiper: [0, 1, 2],
selectedDate: formatDate(new Date(), 'yyyy-MM-dd'), //
start: '',
end: '',
};
},
const emit = defineEmits(['handleFindPoint', 'handleFindPoint']);
computed: {
...mapState('project', ['dotList']),
sheight() {
//
//
let h = '35px';
if (!this.weekMode) {
const d = new Date(this.currentYear, this.currentMonth, 0);
const days = d.getDate(); //
let 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;
},
//
timeStr() {
let str = '';
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
const y = d.getFullYear();
const m = d.getMonth() + 1 <= 9 ? `0${d.getMonth() + 1}` : d.getMonth() + 1;
str = `${y}${m}`;
return str;
},
// days
predays() {
let pres = [];
if (this.weekMode) {
//
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() - 7);
pres = gegerateDates(d, 'week');
} else {
//
const d = new Date(this.currentYear, this.currentMonth - 2, 1);
pres = gegerateDates(d, 'month');
}
return pres;
},
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 sheight = 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 = gegerateDates(d, 'week');
} else {
//
const d = new Date(data.currentYear, data.currentMonth - 2, 1);
pres = gegerateDates(d, 'month');
}
return pres;
});
// days
const nextdays = computed(() => {
let nexts = [];
if (data.weekMode) {
//
const d = new Date(data.currentYear, data.currentMonth - 1, data.currentDate);
d.setDate(d.getDate() + 7);
nexts = gegerateDates(d, 'week');
} else {
//
const d = new Date(data.currentYear, data.currentMonth, 1);
nexts = gegerateDates(d, 'month');
}
return nexts;
});
// days
nextdays() {
let nexts = [];
if (this.weekMode) {
//
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() + 7);
nexts = gegerateDates(d, 'week');
} else {
//
const d = new Date(this.currentYear, this.currentMonth, 1);
nexts = gegerateDates(d, 'month');
watch(dotList, newValue => {
//
const days = data.days.slice(0);
const index = days.findIndex(day => day.show);
days.forEach((day, i) => {
newValue.forEach((item, j) => {
if (i - index === j) {
day.info = item;
}
return nexts;
},
},
});
});
data.days = days;
});
created() {
this.initDate();
this.start = this.$moment().startOf('month').valueOf();
this.end = this.$moment().endOf('month').valueOf();
},
methods: {
//
/**
* 滑动切换上下周期
* 根据前一个减去目前的值我们可以判断是下一个月/周还是上一个月/
* current - pre === 1, -2 下一个月/
* current - pre === -1, 2 上一个月或者上一周
*/
changeSwp(e) {
const pre = this.current;
const current = e.target.current;
this.current = current;
if (current - pre === 1 || current - pre === -2) {
//
this.daysNext();
const arr = this.days.filter(s => s.show);
const end = `${arr[arr.length - 1].fullDate} 23:59:59`;
this.start = this.$moment(arr[0].fullDate).valueOf();
this.end = this.$moment(end).valueOf();
this.$emit('handleFindPoint', this.start, this.end);
} else {
//
this.daysPre();
const arr = this.days.filter(s => s.show);
const end = `${arr[arr.length - 1].fullDate} 23:59:59`;
this.start = this.$moment(arr[0].fullDate).valueOf();
this.end = this.$moment(end).valueOf();
this.$emit('handleFindPoint', this.start, this.end);
}
},
//
const daysPre = () => {
// if (this.weekMode) {
// const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
// d.setDate(d.getDate() - 7);
// this.initDate(d);
// } else {
// const d = new Date(this.currentYear, this.currentMonth - 2, 1);
// this.initDate(d);
// }
};
//
initDate(cur) {
let date = '';
if (cur) {
date = new Date(cur);
} else {
date = new Date();
}
this.currentDate = date.getDate(); //
this.currentYear = date.getFullYear(); //
this.currentMonth = date.getMonth() + 1; //
this.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')
this.days = [];
let days = [];
if (this.weekMode) {
days = gegerateDates(date, 'week');
// this.selectedDate = days[0].fullDate;
} else {
days = gegerateDates(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) => {
this.dotList.forEach((item, j) => {
if (i === j) {
day.info = item;
}
});
});
this.days = days;
// ,
let obj = {
start: '',
end: '',
};
if (this.weekMode) {
obj.start = this.days[0].time;
obj.end = this.days[6].time;
} else {
const start = new Date(this.currentYear, this.currentMonth - 1, 1);
const end = new Date(this.currentYear, this.currentMonth, 0);
obj.start = start;
obj.end = end;
}
this.$emit('days-change', obj);
},
//
const daysNext = () => {
// if (this.weekMode) {
// const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
// d.setDate(d.getDate() + 7);
// this.initDate(d);
// } else {
// const d = new Date(this.currentYear, this.currentMonth, 1);
// this.initDate(d);
// }
};
//
daysPre() {
if (this.weekMode) {
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() - 7);
this.initDate(d);
} else {
const d = new Date(this.currentYear, this.currentMonth - 2, 1);
this.initDate(d);
}
},
/**
* 滑动切换上下周期
* 根据前一个减去目前的值我们可以判断是下一个月/周还是上一个月/
* current - pre === 1, -2 下一个月/
* current - pre === -1, 2 上一个月或者上一周
*/
const changeSwp = e => {
const pre = data.current;
const { current } = e.target;
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', this.start, this.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', this.start, this.end);
}
};
//
daysNext() {
if (this.weekMode) {
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() + 7);
this.initDate(d);
} else {
const d = new Date(this.currentYear, this.currentMonth, 1);
this.initDate(d);
}
},
//
const initDate = cur => {
// let date = '';
// if (cur) {
// date = new Date(cur);
// } else {
// date = new Date();
// }
// this.currentDate = date.getDate(); //
// this.currentYear = date.getFullYear(); //
// this.currentMonth = date.getMonth() + 1; //
// this.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')
// this.days = [];
// let days = [];
// if (this.weekMode) {
// days = gegerateDates(date, 'week');
// // this.selectedDate = days[0].fullDate;
// } else {
// days = gegerateDates(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) => {
// this.dotList.forEach((item, j) => {
// if (i === j) {
// day.info = item;
// }
// });
// });
// this.days = days;
// // ,
// const obj = {
// start: '',
// end: '',
// };
// if (this.weekMode) {
// obj.start = this.days[0].time;
// obj.end = this.days[6].time;
// } else {
// const start = new Date(this.currentYear, this.currentMonth - 1, 1);
// const end = new Date(this.currentYear, this.currentMonth, 0);
// obj.start = start;
// obj.end = end;
// }
// this.$emit('days-change', obj);
};
//
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 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);
};
//
clickItem(e) {
this.selectedDate = e.fullDate;
this.$emit('selected-change', e);
},
//
const clickItem = e => {
// this.selectedDate = e.fullDate;
// this.$emit('selected-change', e);
};
//
goToday() {
const d = new Date();
this.initDate(d);
},
},
//
const goToday = () => {
// const d = new Date();
// this.initDate(d);
};
initDate();
</script>
<style lang="scss" scoped>

8
components/Projects/Projects.vue

@ -0,0 +1,8 @@
<template>
</template>
<script>
</script>
<style>
</style>

13
pages.json

@ -3,13 +3,20 @@
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "uni-app"
"navigationBarText": "TALL"
}
}
}
// {
// "path": "pages/project/project",
// "style": {
// "navigationStyle": "custom",
// "navigationBarTextStyle": "white"
// }
// }
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarTitleText": "TALL",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
}

161
pages/index/index.vue

@ -1,66 +1,97 @@
<template>
<view :style="{ height: height }" class="flex flex-col overflow-hidden u-font-14">
<!-- 标题栏 -->
<Title />
<view class="container flex flex-col flex-1 mx-auto overflow-hidden bg-gray-100">
<!-- 角色栏 -->
<Roles />
<!-- 日常任务面板 -->
<Globals />
<!-- 定期任务面板 -->
<TimeLine @getTasks="getTasks" class="flex-1 overflow-hidden" ref="timeLine" />
</view>
</view>
</template>
<script setup>
import {
ref, onMounted
} from 'vue';
import Navbar from '@/components/Title/Title.vue';
import Roles from '@/components/Roles/Roles.vue';
import Globals from '@/components/Globals/Globals.vue';
import TimeLine from '@/components/TimeLine/TimeLine.vue';
let height = ref(null);
onMounted(() => {
const system = uni.getSystemInfoSync();
height.value = system.windowHeight + 'px';
});
function getTasks() {
}
</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;
}
<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 { reactive, ref, onMounted, computed, watch } 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 data = reactive({
calendar: null,
days: [],
});
const height = ref(null);
const store = useStore();
const token = computed(() => store.state.user.token);
// token
watch(
() => token.value,
newValue => {
console.log('newValue', newValue);
if (!newValue) return;
if (newValue) {
handleFindPoint();
}
},
{ immediate: true },
);
onMounted(() => {
const system = uni.getSystemInfoSync();
height.value = `${system.windowHeight}px`;
});
const handleFindPoint = async (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);
}
};
</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>

64
pages/project/project.vue

@ -0,0 +1,64 @@
<template>
<view :style="{ height: height }" class="flex flex-col overflow-hidden u-font-14">
<!-- 标题栏 -->
<Title />
<view class="container flex flex-col flex-1 mx-auto overflow-hidden bg-gray-100">
<!-- 角色栏 -->
<Roles />
<!-- 日常任务面板 -->
<Globals />
<!-- 定期任务面板 -->
<TimeLine @getTasks="getTasks" class="flex-1 overflow-hidden" ref="timeLine" />
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import Navbar from '@/components/Title/Title.vue';
import Roles from '@/components/Roles/Roles.vue';
import Globals from '@/components/Globals/Globals.vue';
import TimeLine from '@/components/TimeLine/TimeLine.vue';
let height = ref(null);
onMounted(() => {
const system = uni.getSystemInfoSync();
height.value = system.windowHeight + 'px';
});
function getTasks() {
}
</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>

89
store/index.js

@ -1,45 +1,46 @@
import { createStore } from 'vuex';
import user from './user/index.js';
import socket from './socket/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}
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 },
});

3
store/project/actions.js

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

11
store/project/getters.js

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

12
store/project/index.js

@ -0,0 +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,
};

62
store/project/mutations.js

@ -0,0 +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;

8
store/project/state.js

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

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