mirror of
https://github.com/blossom-editor/blossom
synced 2024-11-17 22:48:03 +08:00
日历计划新增功能
This commit is contained in:
parent
856e3d15d1
commit
54d9842085
178
blossom-web/src/views/plan/PlanDayInfo.vue
Normal file
178
blossom-web/src/views/plan/PlanDayInfo.vue
Normal 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>
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user