feat:增加日程计划模块
This commit is contained in:
@@ -78,7 +78,7 @@ const eventClickEvent = (eventClick: EventClickArg) => {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "@/styles/home.variable.module";
|
||||
@use "@/styles/home.variable.module" as variable;
|
||||
|
||||
$cell-height: 3.8vh;
|
||||
$time-slot-width: 70px;
|
||||
@@ -104,7 +104,7 @@ $month-cell-height: 120px;
|
||||
}
|
||||
|
||||
.fc-button-active {
|
||||
background-color: $theme-color;
|
||||
background-color: variable.$theme-color;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,7 @@ $month-cell-height: 120px;
|
||||
|
||||
// 表头区域
|
||||
.fc-col-header {
|
||||
color: $theme-color;
|
||||
color: variable.$theme-color;
|
||||
height: 50px;
|
||||
font-size: 1.4rem;
|
||||
background-color: var(--color-record-card-bg);
|
||||
|
||||
@@ -84,7 +84,7 @@ const props = defineProps({
|
||||
const editPlanClick = async () => {
|
||||
planStore.planApiType = 'UPDATE'
|
||||
planStore.currentPlan = props.plan as IPlanInfo
|
||||
await router.push({ name: 'MobileHomePlanDetailId', params: { id: planStore.currentPlan.id } })
|
||||
await router.push({ name: 'PlanDetailId', params: { id: planStore.currentPlan.id } })
|
||||
}
|
||||
|
||||
const changeCompleteEvent = (value: boolean) => {
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="dialogData.visible" :title="dialogData.title"
|
||||
center @open="openDialogEvent"
|
||||
class="plan-dialog">
|
||||
<el-form ref="formRef" :model="dialogData.data"
|
||||
:rules="rules" label-width="80px" class="plan-form">
|
||||
<el-form-item label="计划标题" prop="title">
|
||||
<el-input v-model="dialogData.data.title" autocomplete="off"
|
||||
placeholder="请输入标题" clearable
|
||||
show-word-limit maxlength="10">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="计划内容">
|
||||
<el-input v-model="dialogData.data.content" autocomplete="off"
|
||||
placeholder="请输入标题" :rows="2" type="textarea" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<div style="display: flex;justify-content: space-between;">
|
||||
<el-form-item label="开始日期">
|
||||
<el-date-picker v-model="dialogData.data.date"
|
||||
type="date" placeholder="请选择日期" :editable="false"
|
||||
value-format="YYYY-MM-DD" style="width: 150px;"
|
||||
:disabled-date="disabledDate" @change="changeDateEvent"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="开始时间">
|
||||
<el-time-picker v-model="dialogData.data.startTime"
|
||||
placeholder="请选择开始时间" :editable="false"
|
||||
format="HH:mm" value-format="HH:mm" style="width: 150px;"
|
||||
:disabled="dialogData.data.date === null"
|
||||
@change="changeStartTimeEvent"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="结束时间">
|
||||
<el-time-picker v-model="dialogData.data.endTime"
|
||||
placeholder="请选择结束时间" :editable="false"
|
||||
:disabled="dialogData.data.startTime === null"
|
||||
format="HH:mm" value-format="HH:mm" style="width: 150px;"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div style="display: flex;gap: 40px;">
|
||||
<el-form-item label="提醒时间">
|
||||
<el-date-picker v-model="dialogData.data.alterTime"
|
||||
type="datetime" placeholder="请选择提醒时间" :editable="false"
|
||||
format="YYYY-MM-DD HH:mm" value-format="YYYY-MM-DD HH:mm:ss"
|
||||
@change="changeAlterTimeEvent"
|
||||
:disabled-date="disabledDate" style="width: 200px;"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="邮箱地址" prop="email">
|
||||
<el-input v-model="dialogData.data.email"
|
||||
placeholder="请输入邮箱地址" clearable
|
||||
:disabled="dialogData.data.alterTime === null"
|
||||
style="width: 200px;">
|
||||
<template #prefix>
|
||||
<i class="fa-solid fa-envelope"></i>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div style="display: flex;justify-content: space-between;">
|
||||
<el-form-item label="类别">
|
||||
<el-input v-model="dialogData.data.tag" autocomplete="off"
|
||||
placeholder="请输入类别" clearable
|
||||
show-word-limit maxlength="10" style="width: 150px;">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="置顶">
|
||||
<el-switch v-model="dialogData.data.isTop"
|
||||
:active-value="1" :inactive-value="0"
|
||||
@change="changeTopEvent"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="优先级">
|
||||
<el-select v-model="dialogData.data.priority"
|
||||
placeholder="请选择优先级" style="width: 150px;"
|
||||
:disabled="!!dialogData.data.isTop">
|
||||
<el-option v-for="(item, index) in priorityOptionList"
|
||||
:key="index" :label="item.label" :value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelClick">取消</el-button>
|
||||
<el-button type="primary" @click="confirmClick">确认</el-button>
|
||||
<el-button v-if="planStore.planApiType === 'UPDATE'"
|
||||
type="danger" @click="deleteClick">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage, FormInstance, FormRules } from 'element-plus'
|
||||
import { planRules } from '@/utils/element/elRules.ts'
|
||||
import { computed, nextTick, reactive, ref } from 'vue'
|
||||
import { isBeforeTime } from '@/utils/home/planUtil.ts'
|
||||
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
|
||||
import { usePlanStore } from '@/store/plan.ts'
|
||||
import { useUserStore } from '@/store/user.ts'
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const rules = reactive<FormRules>(planRules)
|
||||
const planStore = usePlanStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const dialogData = computed(() => planStore.planDialog)
|
||||
|
||||
const priorityOptionList = [{
|
||||
value: 0,
|
||||
label: '高'
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '中'
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '低'
|
||||
}]
|
||||
|
||||
const disabledDate = (time: Date) => {
|
||||
return time.getTime() < Date.now() - 8.64e7
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开对话框事件
|
||||
*/
|
||||
const openDialogEvent = async () => {
|
||||
await nextTick(() => {
|
||||
formRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
const changeDateEvent = (value: string) => {
|
||||
if (!value) {
|
||||
dialogData.value.data.startTime = null
|
||||
dialogData.value.data.endTime = null
|
||||
}
|
||||
}
|
||||
|
||||
const changeStartTimeEvent = (value: string) => {
|
||||
if (!value) {
|
||||
dialogData.value.data.endTime = null
|
||||
}
|
||||
}
|
||||
|
||||
const changeAlterTimeEvent = (value: string) => {
|
||||
if (value) {
|
||||
dialogData.value.data.email = userStore.userInfo.email
|
||||
}
|
||||
}
|
||||
|
||||
const changeTopEvent = (value: number) => {
|
||||
if (value) {
|
||||
dialogData.value.data.priority = 0
|
||||
}
|
||||
}
|
||||
|
||||
const validatePlan = (): boolean => {
|
||||
const { startTime, endTime } = dialogData.value.data
|
||||
if (startTime && endTime) {
|
||||
if (!isBeforeTime(startTime, endTime)) {
|
||||
ElMessage.error('请确认结束时间大于开始时间')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击确认按钮
|
||||
*/
|
||||
const confirmClick = () => {
|
||||
formRef.value?.validate().then(async () => {
|
||||
if (validatePlan()) {
|
||||
await planStore.handlePlanApi(dialogData.value.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const deleteClick = () => {
|
||||
commonElMessageBox('是否确认删除该计划内容?').then(() => {
|
||||
planStore.planApiType = 'DELETE'
|
||||
planStore.handlePlanApi(dialogData.value.data)
|
||||
})
|
||||
}
|
||||
|
||||
const cancelClick = () => {
|
||||
planStore.planDialog.visible = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.plan-dialog {
|
||||
width:40%;
|
||||
min-width: 800px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,18 +0,0 @@
|
||||
<template>
|
||||
<div class="plan-list">
|
||||
<el-empty v-if="planStore.planList.length === 0" />
|
||||
|
||||
<el-scrollbar v-else>
|
||||
<plan-card v-for="(item, index) in planStore.planList"
|
||||
:key="index" :plan="item">
|
||||
</plan-card>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PlanCard from '@/components/Plan/PlanCard.vue'
|
||||
import { usePlanStore } from '@/store/plan.ts'
|
||||
|
||||
const planStore = usePlanStore()
|
||||
</script>
|
||||
@@ -1,18 +1,18 @@
|
||||
<template>
|
||||
<div class="common-query">
|
||||
<el-select v-model="planStore.queryInfo.planType"
|
||||
@change="planStore.refreshInfo()"
|
||||
style="width: 120px;align-self: center;">
|
||||
<el-option v-for="(item, index) in planTypeOptions" :key="index"
|
||||
:label="item.label" :value="item.value"/>
|
||||
</el-select>
|
||||
<div class="mobile-common-query card-item">
|
||||
<div class="query-item">
|
||||
<span>分类:</span>
|
||||
<el-segmented v-model="planStore.queryInfo.planType"
|
||||
:options="planTypeOptions"
|
||||
@change="planStore.refreshInfo()"/>
|
||||
</div>
|
||||
|
||||
<el-select v-model="planStore.queryInfo.orderType"
|
||||
@change="planStore.refreshInfo()"
|
||||
style="width: 120px;align-self: center;">
|
||||
<el-option v-for="(item, index) in orderTypeOptions" :key="index"
|
||||
:label="item.label" :value="item.value"/>
|
||||
</el-select>
|
||||
<div class="query-item">
|
||||
<span>排序:</span>
|
||||
<el-segmented v-model="planStore.queryInfo.orderType"
|
||||
:options="orderTypeOptions"
|
||||
@change="planStore.refreshInfo()"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -26,20 +26,20 @@ const planTypeOptions = [{
|
||||
value: 'all'
|
||||
},
|
||||
{
|
||||
label: '已完成计划',
|
||||
label: '已完成',
|
||||
value: 'completed'
|
||||
},
|
||||
{
|
||||
label: '未完成计划',
|
||||
label: '未完成',
|
||||
value: 'notCompleted'
|
||||
}]
|
||||
|
||||
const orderTypeOptions = [{
|
||||
label: '按时间排序',
|
||||
label: '时间',
|
||||
value: 'date'
|
||||
},
|
||||
{
|
||||
label: '按重要性排序',
|
||||
label: '重要性',
|
||||
value: 'priority'
|
||||
}]
|
||||
</script>
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<div class="common-statistics">
|
||||
<stats-card
|
||||
title="计划总数" color="#CA6C65" unit="个" icon="iconfont icon-richeng"
|
||||
:value="planStore.planStats.totalCount" />
|
||||
|
||||
<stats-card
|
||||
title="完成总数" color="#6FBB69" unit="个" icon="iconfont icon-wancheng"
|
||||
:value="planStore.planStats.completedCount" />
|
||||
|
||||
<stats-card
|
||||
title="当前计划" color="#E4BF62" unit="个" icon="iconfont icon-dangqianjihua"
|
||||
:value="planStore.planStats.currentCount" />
|
||||
|
||||
<stats-card
|
||||
title="过期计划" color="#5470C6" unit="个" icon="iconfont icon-yuqi"
|
||||
:value="planStore.planStats.remainCount" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import StatsCard from '@/components/StatsCard.vue'
|
||||
import { usePlanStore } from '@/store/plan.ts'
|
||||
|
||||
const planStore = usePlanStore()
|
||||
</script>
|
||||
@@ -135,11 +135,12 @@ export const useBillStore = defineStore('bill', {
|
||||
const bookName = this.billQueryForm.billBook === 'all' ? '' : this.billQueryForm.billBook
|
||||
this.getBillDateList()
|
||||
|
||||
await this.queryBillSummary(bookName)
|
||||
|
||||
if (isStats) {
|
||||
await this.queryBillStats(bookName)
|
||||
} else {
|
||||
await this.queryBillSummary(bookName)
|
||||
}
|
||||
|
||||
this.isRefresh = !this.isRefresh
|
||||
this.isLoading = false
|
||||
},
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
.mobile-plan-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
|
||||
#planCalendar {
|
||||
.fc-view {
|
||||
height: calc(100vh - 210px);
|
||||
|
||||
.fc-timegrid-body {
|
||||
// 单元格高度
|
||||
tr {
|
||||
height: 3.5vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.plan-list {
|
||||
.el-scrollbar {
|
||||
.el-scrollbar__view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
.plan-view {
|
||||
.plan-list {
|
||||
height: calc(100vh - 120px);
|
||||
|
||||
.el-scrollbar {
|
||||
.el-scrollbar__view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,12 +6,12 @@
|
||||
<el-date-picker v-if="billStore.billDateType === 'month'"
|
||||
v-model="billStore.billQueryForm.billMonth"
|
||||
type="month" :editable="false" style="width: 120px;"
|
||||
@change="billStore.refreshInfo()"/>
|
||||
@change="billStore.refreshInfo(true)"/>
|
||||
|
||||
<el-date-picker v-if="billStore.billDateType === 'year'"
|
||||
v-model="billStore.billQueryForm.billYear"
|
||||
type="year" :editable="false" style="width: 120px;"
|
||||
@change="billStore.refreshInfo()"/>
|
||||
@change="billStore.refreshInfo(true)"/>
|
||||
</div>
|
||||
|
||||
<bill-stats />
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
title="物品记录" sub-title="收纳生活琐碎"
|
||||
router="/product/list"/>
|
||||
|
||||
<module-card icon="iconfont icon-paiban" color="#9933FF"
|
||||
title="日程安排" sub-title="规划每日时光"
|
||||
router="/plan/calendar"/>
|
||||
|
||||
<module-card icon="iconfont icon-yundongjiankang" color="#FD644C"
|
||||
title="运动健康" sub-title="乐享健康生活"
|
||||
router="/health/calendar"/>
|
||||
|
||||
@@ -93,10 +93,28 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
||||
title: '统计',
|
||||
icon: ''
|
||||
},
|
||||
'/plan': {
|
||||
title: '时光日程',
|
||||
icon: '',
|
||||
order: 5,
|
||||
redirect: '/plan/calendar'
|
||||
},
|
||||
'/plan/calendar': {
|
||||
title: '日程安排',
|
||||
icon: ''
|
||||
},
|
||||
'/plan/list': {
|
||||
title: '日程清单',
|
||||
icon: ''
|
||||
},
|
||||
'/plan/detail/id': {
|
||||
title: '日程内容',
|
||||
icon: ''
|
||||
},
|
||||
'/anniversary': {
|
||||
title: '纪念日',
|
||||
icon: 'home-anniversary',
|
||||
order: 5,
|
||||
order: 6,
|
||||
redirect: '/anniversary/list'
|
||||
},
|
||||
'/anniversary/list': {
|
||||
@@ -114,7 +132,7 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
||||
'/period': {
|
||||
title: '月经记录',
|
||||
icon: 'home-period',
|
||||
order: 6,
|
||||
order: 7,
|
||||
redirect: '/period/calendar'
|
||||
},
|
||||
'/period/calendar': {
|
||||
@@ -132,7 +150,7 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
||||
'/product': {
|
||||
title: '物品记录',
|
||||
icon: 'home-product',
|
||||
order: 7,
|
||||
order: 8,
|
||||
redirect: '/product/list'
|
||||
},
|
||||
'/product/list': {
|
||||
@@ -146,7 +164,7 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
||||
'/journal': {
|
||||
title: '日记',
|
||||
icon: 'home-product',
|
||||
order: 8,
|
||||
order: 9,
|
||||
redirect: '/journal/record'
|
||||
},
|
||||
'/journal/record': {
|
||||
@@ -164,7 +182,7 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
||||
'/kpi': {
|
||||
title: '绩效',
|
||||
icon: 'home-kpi',
|
||||
order: 9,
|
||||
order: 10,
|
||||
redirect: '/kpi/record'
|
||||
},
|
||||
'/kpi/record': {
|
||||
@@ -178,7 +196,7 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
||||
'/asset': {
|
||||
title: '资产',
|
||||
icon: 'home-asset',
|
||||
order: 10,
|
||||
order: 11,
|
||||
redirect: '/asset/list'
|
||||
},
|
||||
'/asset/list': {
|
||||
@@ -192,7 +210,7 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
||||
'/ledger': {
|
||||
title: '账本',
|
||||
icon: 'home-ledger',
|
||||
order: 11,
|
||||
order: 12,
|
||||
redirect: '/ledger/list'
|
||||
},
|
||||
'/ledger/list': {
|
||||
@@ -210,7 +228,7 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
||||
'/password': {
|
||||
title: '密码',
|
||||
icon: 'home-password',
|
||||
order: 12,
|
||||
order: 13,
|
||||
redirect: '/password/list'
|
||||
},
|
||||
'/password/list': {
|
||||
@@ -220,7 +238,7 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
||||
'/award': {
|
||||
title: '奖状证书',
|
||||
icon: 'home-award',
|
||||
order: 13,
|
||||
order: 14,
|
||||
redirect: '/award/list'
|
||||
},
|
||||
'/award/list': {
|
||||
@@ -234,7 +252,7 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
||||
'/profile': {
|
||||
title: '个人信息',
|
||||
icon: '',
|
||||
order: 14,
|
||||
order: 15,
|
||||
hidden: true,
|
||||
redirect: '/profile/index'
|
||||
},
|
||||
|
||||
34
src/views/plan/calendar.vue
Normal file
34
src/views/plan/calendar.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div class="mobile-plan-view common-mobile-view">
|
||||
<plan-calendar />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import PlanCalendar from '@/components/Plan/PlanCalendar.vue'
|
||||
import { usePlanStore } from '@/store/plan.ts'
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
const planStore = usePlanStore()
|
||||
|
||||
onMounted(() => {
|
||||
planStore.refreshInfo()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.mobile-plan-view {
|
||||
#planCalendar {
|
||||
.fc-view {
|
||||
height: calc(100vh - 210px);
|
||||
|
||||
.fc-timegrid-body {
|
||||
// 单元格高度
|
||||
tr {
|
||||
height: 3.5vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
205
src/views/plan/detail[id].vue
Normal file
205
src/views/plan/detail[id].vue
Normal file
@@ -0,0 +1,205 @@
|
||||
<template>
|
||||
<div class="common-mobile-view">
|
||||
<el-form ref="formRef" :model="planStore.currentPlan"
|
||||
:rules="rules" label-width="80px" class="form-item">
|
||||
<el-form-item label="计划标题" prop="title">
|
||||
<el-input v-model="planStore.currentPlan.title" autocomplete="off"
|
||||
placeholder="请输入标题" clearable
|
||||
show-word-limit maxlength="10">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="计划内容">
|
||||
<el-input v-model="planStore.currentPlan.content" autocomplete="off"
|
||||
placeholder="请输入标题" :rows="2" type="textarea" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="开始日期">
|
||||
<el-date-picker v-model="planStore.currentPlan.date"
|
||||
type="date" placeholder="请选择日期" :editable="false"
|
||||
value-format="YYYY-MM-DD" style="width: 150px;"
|
||||
:disabled-date="disabledDate" @change="changeDateEvent"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="开始时间">
|
||||
<el-time-picker v-model="planStore.currentPlan.startTime"
|
||||
placeholder="请选择开始时间" :editable="false"
|
||||
format="HH:mm" value-format="HH:mm" style="width: 150px;"
|
||||
:disabled="planStore.currentPlan.date === null"
|
||||
@change="changeStartTimeEvent"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="结束时间">
|
||||
<el-time-picker v-model="planStore.currentPlan.endTime"
|
||||
placeholder="请选择结束时间" :editable="false"
|
||||
:disabled="planStore.currentPlan.startTime === null"
|
||||
format="HH:mm" value-format="HH:mm" style="width: 150px;"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="提醒时间">
|
||||
<el-date-picker v-model="planStore.currentPlan.alterTime"
|
||||
type="datetime" placeholder="请选择提醒时间" :editable="false"
|
||||
format="YYYY-MM-DD HH:mm" value-format="YYYY-MM-DD HH:mm:ss"
|
||||
@change="changeAlterTimeEvent"
|
||||
:disabled-date="disabledDate" style="width: 200px;"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="邮箱地址" prop="email">
|
||||
<el-input v-model="planStore.currentPlan.email"
|
||||
placeholder="请输入邮箱地址" clearable
|
||||
:disabled="planStore.currentPlan.alterTime === null"
|
||||
style="width: 200px;">
|
||||
<template #prefix>
|
||||
<i class="fa-solid fa-envelope"></i>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="类别">
|
||||
<el-input v-model="planStore.currentPlan.tag" autocomplete="off"
|
||||
placeholder="请输入类别" clearable
|
||||
show-word-limit maxlength="10" style="width: 150px;">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="置顶">
|
||||
<el-switch v-model="planStore.currentPlan.isTop"
|
||||
:active-value="1" :inactive-value="0"
|
||||
@change="changeTopEvent"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="优先级">
|
||||
<el-select v-model="planStore.currentPlan.priority"
|
||||
placeholder="请选择优先级" style="width: 150px;"
|
||||
:disabled="!!planStore.currentPlan.isTop">
|
||||
<el-option v-for="(item, index) in priorityOptionList"
|
||||
:key="index" :label="item.label" :value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="form-button">
|
||||
<el-button type="primary" @click="confirmClick">确认</el-button>
|
||||
<el-button v-if="planStore.planApiType === 'UPDATE'"
|
||||
type="danger" @click="deleteClick">删除</el-button>
|
||||
<el-button type="info" @click="cancelClick">取消</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage, FormInstance, FormRules } from 'element-plus'
|
||||
import { planRules } from '@/utils/element/elRules.ts'
|
||||
import { nextTick, onMounted, reactive, ref } from 'vue'
|
||||
import { isBeforeTime } from '@/utils/home/planUtil.ts'
|
||||
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
|
||||
import { usePlanStore } from '@/store/plan.ts'
|
||||
import { useUserStore } from '@/store/user.ts'
|
||||
import { useAppStore } from '@/store/app.ts'
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const rules = reactive<FormRules>(planRules)
|
||||
const planStore = usePlanStore()
|
||||
const userStore = useUserStore()
|
||||
const appStore = useAppStore()
|
||||
|
||||
const priorityOptionList = [{
|
||||
value: 0,
|
||||
label: '高'
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '中'
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '低'
|
||||
}]
|
||||
|
||||
const disabledDate = (time: Date) => {
|
||||
return time.getTime() < Date.now() - 8.64e7
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
appStore.isShowMobileBack = true
|
||||
|
||||
await nextTick(() => {
|
||||
formRef.value?.clearValidate()
|
||||
})
|
||||
})
|
||||
|
||||
const changeDateEvent = (value: string) => {
|
||||
if (!value) {
|
||||
planStore.currentPlan.startTime = null
|
||||
planStore.currentPlan.endTime = null
|
||||
}
|
||||
}
|
||||
|
||||
const changeStartTimeEvent = (value: string) => {
|
||||
if (!value) {
|
||||
planStore.currentPlan.endTime = null
|
||||
}
|
||||
}
|
||||
|
||||
const changeAlterTimeEvent = (value: string) => {
|
||||
if (value) {
|
||||
planStore.currentPlan.email = userStore.userInfo.email
|
||||
}
|
||||
}
|
||||
|
||||
const changeTopEvent = (value: number) => {
|
||||
if (value) {
|
||||
planStore.currentPlan.priority = 0
|
||||
}
|
||||
}
|
||||
|
||||
const validatePlan = (): boolean => {
|
||||
const { startTime, endTime, alterTime, email } = planStore.currentPlan
|
||||
if (startTime && endTime) {
|
||||
if (!isBeforeTime(startTime, endTime)) {
|
||||
ElMessage.error('请确认结束时间大于开始时间')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (alterTime) {
|
||||
if (!email) {
|
||||
ElMessage.error('请输入邮箱地址')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击确认按钮
|
||||
*/
|
||||
const confirmClick = () => {
|
||||
formRef.value?.validate().then(async () => {
|
||||
if (validatePlan()) {
|
||||
await planStore.handlePlanApi(planStore.currentPlan)
|
||||
history.back()
|
||||
appStore.isShowMobileBack = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const deleteClick = () => {
|
||||
commonElMessageBox('是否确认删除该计划内容?').then(async () => {
|
||||
planStore.planApiType = 'DELETE'
|
||||
await planStore.handlePlanApi(planStore.currentPlan)
|
||||
history.back()
|
||||
appStore.isShowMobileBack = false
|
||||
})
|
||||
}
|
||||
|
||||
const cancelClick = () => {
|
||||
history.back()
|
||||
appStore.isShowMobileBack = false
|
||||
}
|
||||
</script>
|
||||
31
src/views/plan/list.vue
Normal file
31
src/views/plan/list.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<div class="common-mobile-view">
|
||||
<plan-query />
|
||||
|
||||
<el-empty v-if="planStore.planList.length === 0" description="暂无日程安排"/>
|
||||
|
||||
<div v-else class="content-list">
|
||||
<plan-card v-for="item in planStore.planList"
|
||||
:key="item.id" :plan="item">
|
||||
</plan-card>
|
||||
</div>
|
||||
|
||||
<van-floating-bubble icon="plus" @click="addClick" style="top: -60px;"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import PlanQuery from '@/components/Plan/PlanQuery.vue'
|
||||
import { usePlanStore } from '@/store/plan.ts'
|
||||
import { useRouter } from 'vue-router'
|
||||
import PlanCard from '@/components/Plan/PlanCard.vue'
|
||||
|
||||
const planStore = usePlanStore()
|
||||
const router = useRouter()
|
||||
|
||||
const addClick = () => {
|
||||
planStore.planApiType = 'ADD'
|
||||
planStore.currentPlan = planStore.getEmptyPlan()
|
||||
router.push({ name: 'PlanDetailId', params: { id: 0 } })
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user