日历计划新增功能

This commit is contained in:
xiaozzzi 2023-11-20 16:45:47 +08:00
parent 856e3d15d1
commit 54d9842085
2 changed files with 293 additions and 99 deletions

View File

@ -0,0 +1,178 @@
<template>
<div class="day-info-root">
<div class="info-form">
<el-form ref="DayFormRef" :model="dayForm" :rules="dayFormRule" label-position="top" label-width="60px" size="small">
<el-form-item prop="title">
<el-input v-model="dayForm.title" placeholder="计划标题" style="width: calc(100% - 30px)">
<template #prefix>
<el-icon size="15">
<Document />
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-input type="textarea" :rows="5" v-model="dayForm.content" placeholder="计划内容" resize="none" />
</el-form-item>
<el-form-item label="计划日期" prop="planDate">
<el-date-picker
v-model="dayForm.planDate"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
:editable="false" />
</el-form-item>
<el-form-item label="开始时间 / 结束时间" required>
<el-form-item prop="planStartTime">
<el-time-select
v-model="dayForm.planStartTime"
:max-time="dayForm.planEndTime"
:editable="false"
placeholder="开始日期"
start="00:00"
step="00:15"
end="23:59"
style="width: 155px; margin-right: 18px" />
</el-form-item>
<el-form-item prop="planEndTime">
<el-time-select
v-model="dayForm.planEndTime"
:min-time="dayForm.planStartTime"
:editable="false"
placeholder="结束日期"
start="00:00"
step="00:15"
end="23:59"
style="width: 155px" />
</el-form-item>
</el-form-item>
<el-form-item>
<el-checkbox v-model="dayForm.allDay" label="全天" style="margin-right: 20px" @change="allDayChange" />
<el-checkbox v-model="dayForm.repeat" label="重复" style="margin-right: 20px" @change="repeatChange" />
<div style="margin-right: 10px">重复天数</div>
<el-input-number v-model="dayForm.repeatDay" :min="1" :disabled="!dayForm.repeat" />
</el-form-item>
<bl-col>
<bl-row style="font-size: 12px" :style="{ color: dayForm.color }">
颜色
<span class="iconbl bl-a-colorpalette-line" style="font-size: 13px; padding-left: 5px"></span>
</bl-row>
<bl-row class="color-container">
<div v-for="color in colors" :class="['color', color]" @click="clickColor(color)"></div>
</bl-row>
</bl-col>
</el-form>
</div>
<el-button color="#474747" @click="saveDay(DayFormRef)" style="width: 100%">
<span class="iconbl bl-a-templateadd-line" style="margin-right: 10px" />
</el-button>
</div>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { Document } from '@element-plus/icons-vue'
import type { FormInstance, FormRules } from 'element-plus'
import { planAddDayApi } from '@/api/plan'
const colors = ['purple', 'red', 'yellow', 'blue', 'green', 'gray']
interface DayForm {
title: string
content: string
planDate: string
planStartTime: string
planEndTime: string
allDay: boolean
repeat: false
repeatDay: number
color: string
}
const DayFormRef = ref<FormInstance>()
const dayForm = ref<DayForm>({
title: '',
content: '',
planDate: '',
planStartTime: '',
planEndTime: '',
allDay: false,
repeat: false,
repeatDay: 1,
color: 'purple'
})
const dayFormRule = reactive<FormRules<DayForm>>({
planDate: [{ required: true, message: '请填写日期', trigger: 'change' }],
planStartTime: [{ required: true, message: '请填写开始时间', trigger: 'change' }],
planEndTime: [{ required: true, message: '请填写结束时间', trigger: 'change' }],
title: [{ required: true, message: '请填写计划标题', trigger: 'change' }]
})
const allDayChange = (allDay: boolean) => {
if (allDay) {
dayForm.value.planStartTime = '00:00'
dayForm.value.planEndTime = '23:59'
} else {
dayForm.value.planStartTime = ''
dayForm.value.planEndTime = ''
}
}
const repeatChange = (repeat: boolean) => {
if (!repeat) {
dayForm.value.repeatDay = 1
}
}
const clickColor = (color: string) => {
dayForm.value.color = color
}
const saveDay = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid, _fields) => {
if (valid) {
planAddDayApi(dayForm.value).then((_resp) => {
emits('saved')
})
}
})
}
const emits = defineEmits(['saved'])
</script>
<style scoped lang="scss">
@import url('./PlanColor.scss');
.day-info-root {
padding-top: 20px;
.color-container {
align-content: flex-start;
flex-wrap: wrap;
overflow: scroll;
overflow-y: overlay;
padding: 10px 10px 8px 0;
.color {
@include box(20px, 20px);
@include font(11px, 300);
color: #fff;
margin: 0 5px;
border-radius: 4px;
transition: transform 0.1s;
cursor: pointer;
&:active {
transform: scale(1.2);
}
}
}
}
</style>

View File

@ -1,9 +1,5 @@
<template>
<div class="plan-index-root">
<div class="header">
<IndexHeader :bg="true"></IndexHeader>
</div>
<div class="plan-root">
<bl-row just="space-between" class="workbench" height="45px">
<div class="month">{{ calendarDate.getMonth() + 1 }}</div>
<el-button-group size="small">
@ -12,68 +8,70 @@
<el-button @click="selectDate('next-month')">下月</el-button>
</el-button-group>
</bl-row>
<el-calendar class="bl-calendar" v-model="calendarDate" ref="CalendarRef">
<el-calendar class="plan-calendar" v-model="calendarDate" ref="CalendarRef">
<template #header="{ date }"><div></div></template>
<template #date-cell="{ data }">
<div class="date-title">
<span>{{ data.day.split('-').slice(2).join('-') }}</span>
<span class="iconbl bl-a-addline-line" @click="handleShowPlanAddDialog(data.day)"></span>
</div>
<div class="plan-group">
<div v-for="(plan, index) in planDays[data.day + ' 00:00:00']" :key="plan.id">
<el-popover
placement="right"
popper-class="plan-popover"
:width="200"
trigger="click"
:hide-after="0"
:disabled="plan.id < 0"
:persistent="false">
<!-- 触发元素 -->
<template #reference>
<div :class="'plan-line ' + plan.color + ' ' + plan.position + ' ' + plan.hl" :style="{ top: index * 21 + 'px' }">
<div v-if="plan.position == 'head' || plan.position == 'all'" class="plan-title">
{{ plan.title }}
</div>
</div>
</template>
<!-- 弹出框内容 -->
<bl-col class="plan-popover-inner">
<div :class="['plan-popover-title', plan.color]">
{{ plan.title }}
</div>
<div class="plan-popover-time">
<div><span class="iconbl bl-date-line"></span> {{ data.day }}</div>
<span class="iconbl bl-a-clock3-line"></span> {{ plan.planStartTime }} - {{ plan.planEndTime }}
</div>
<div class="plan-popover-content">
{{ plan.content }}
</div>
</bl-col>
</el-popover>
<div v-for="(plan, index) in planDays[data.day + ' 00:00:00']" :key="plan.id" @click="showUpdForm(plan)">
<div :class="'plan-line ' + plan.color + ' ' + plan.position + ' ' + plan.hl" :style="{ top: index * 21 + 'px' }">
<div v-if="plan.position == 'head' || plan.position == 'all'" class="plan-title">
{{ plan.title }}
</div>
</div>
</div>
</div>
</template>
</el-calendar>
<!-- -->
<div class="plan-add" @click="showAddForm"><span class="iconbl bl-a-addline-line"></span></div>
</div>
<!-- 新增页面 -->
<el-drawer v-model="isShowAddForm" direction="btt" :with-header="true" :destroy-on-close="true" size="470px">
<PlanDayInfo ref="PlanDayInfoRef" @saved="savedCallback"></PlanDayInfo>
</el-drawer>
<!-- 修改页面 -->
<el-drawer v-model="isShowUpdForm" direction="btt" :with-header="true" :destroy-on-close="true" size="270px">
<div class="detail">
<el-input size="small" style="width: calc(100% - 30px); margin-bottom: 18px" v-model="curPlan.title" placeholder="计划 标题">
<template #prefix>
<el-icon size="15">
<Document />
</el-icon>
</template>
</el-input>
<el-input size="small" type="textarea" placeholder="Todo 内容" v-model="curPlan.content" resize="none" :rows="4"></el-input>
<div class="times">
<bl-row style="margin-bottom: 5px"> <span class="iconbl bl-date-line"></span> {{ curPlan.planDate.substring(0, 10) }} </bl-row>
<bl-row> <span class="iconbl bl-a-clock3-line"></span> {{ curPlan.planStartTime }} - {{ curPlan.planEndTime }} </bl-row>
</div>
<bl-row class="btns" just="center">
<el-button-group style="width: 100%">
<el-button color="#474747" @click="delPlan" style="width: 50%"><i class="iconbl bl-delete-line"></i> </el-button>
<el-button color="#474747" @click="updPlan" style="width: 50%"><i class="iconbl bl-a-texteditorsave-line"></i> </el-button>
</el-button-group>
</bl-row>
</div>
</el-drawer>
</template>
<script setup lang="ts">
import { nextTick, onMounted, ref, watch } from 'vue'
import type { CalendarDateType, CalendarInstance } from 'element-plus'
import { planListDayApi, planDelApi } from '@/api/plan'
import { getDateTimeFormat, getNextDay, timestampToDatetime } from '@/assets/utils/util'
import IndexHeader from '@/views/index/IndexHeader.vue'
import { onMounted, ref, watch } from 'vue'
import { Document } from '@element-plus/icons-vue'
import { ElMessageBox, type CalendarDateType, type CalendarInstance } from 'element-plus'
import { planListDayApi, planDelApi, planUpdDayApi } from '@/api/plan'
import { getDateTimeFormat, timestampToDatetime } from '@/assets/utils/util'
import PlanDayInfo from './PlanDayInfo.vue'
onMounted(() => {
getPlanAll(getDateTimeFormat().substring(0, 7))
})
const PlanDayInfoRef = ref()
//
const planDays = ref<any>({})
// ,
let lastMonth: string = ''
const calendarDate = ref<Date>(new Date())
@ -100,52 +98,62 @@ const getPlanAll = (month: string, force: boolean = false) => {
})
}
//#region ----------------------------------------< >-------------------------------------
const isShowPlanAddDialog = ref(false)
const handleShowPlanAddDialog = (ymd: string) => {
isShowPlanAddDialog.value = true
nextTick(() => {
PlanDayInfoRef.value.setPlanDate(ymd)
})
//#region ----------------------------------------< >-------------------------------------
const PlanDayInfoRef = ref()
const isShowAddForm = ref(false)
const showAddForm = () => {
isShowAddForm.value = true
}
const savedCallback = () => {
getPlanAll(lastMonth, true)
isShowPlanAddDialog.value = false
isShowAddForm.value = false
}
const delDay = (groupId: number) => {
planDelApi({ groupId: groupId }).then((_resp) => {
const isShowUpdForm = ref(false)
const curPlan = ref({ groupId: '', title: '', content: '', planDate: '', planStartTime: '', planEndTime: '' })
const showUpdForm = (plan: any) => {
isShowUpdForm.value = true
curPlan.value = plan
}
const updPlan = () => {
planUpdDayApi(curPlan.value).then((resp) => {
getPlanAll(lastMonth, true)
isShowUpdForm.value = false
})
}
const delPlan = () => {
ElMessageBox.confirm('是否确定删除该任务', '删除任务', {
confirmButtonText: '我要删除',
cancelButtonText: '取消'
}).then(() => {
planDelApi({ groupId: curPlan.value.groupId }).then((_resp) => {
getPlanAll(lastMonth, true)
isShowUpdForm.value = false
})
})
}
//#endregion
</script>
<style scoped lang="scss">
.plan-index-root {
.plan-root {
@include box(100%, 100%);
@include flex(column, flex-start, center);
overflow: hidden;
.header {
@include box(100%, 60px);
}
.workbench,
.bl-calendar {
max-width: 900px;
}
position: relative;
.workbench {
padding: 10px 10px;
padding: 0 10px 10px 10px;
:deep(.el-button, .el-radio-button__inner) {
padding: 8px 10px;
}
}
.bl-calendar {
.plan-calendar {
--el-calendar-border: 1px solid var(--el-border-color);
overflow: hidden;
flex: 1;
@ -215,7 +223,8 @@ const delDay = (groupId: number) => {
border-right: 0;
border-left: 0;
border-top: 0;
overflow: scroll;
overflow-y: scroll;
overflow-x: hidden;
padding: 0;
&:last-child {
@ -320,42 +329,49 @@ const delDay = (groupId: number) => {
}
}
}
}
</style>
<style lang="scss">
.plan-add {
@include flex(row, center, center);
@include box(40px, 40px);
border-radius: 50%;
background-color: #7b7b7b4c;
box-shadow: 3px 3px 5px #bababa;
position: absolute;
right: 10px;
bottom: 5%;
cursor: pointer;
transition: background-color 0.3s;
&:hover {
background-color: var(--el-color-primary-light-7);
}
.iconbl {
color: #7b7b7ba9;
font-size: 20px;
}
}
}
@import url('./PlanColor.scss');
.plan-popover {
--el-popover-padding: 0 !important;
border: 0 !important;
width: 170px !important;
.detail {
@include flex(column, flex-start, flex-start);
height: 100%;
padding-top: 20px;
padding-bottom: 30px;
.plan-popover-inner {
.times {
margin-top: 18px;
margin-bottom: 18px;
color: #949494;
.iconbl {
font-size: 13px;
margin-right: 10px;
}
}
.plan-popover-title {
@include font(15px, 500);
width: 100%;
padding: 10px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
color: #fff;
}
.plan-popover-time {
width: 100%;
padding: 5px 10px;
text-align: left;
}
.plan-popover-content {
width: 100%;
text-align: left;
padding: 0 10px 10px;
white-space: pre-wrap;
.btns {
.iconbl {
margin-right: 15px;
}
}
}