前端首页的待办卡片中新增基于localStorage的待办添加与删除功能,并优化页面顶部的消息卡片

This commit is contained in:
zhoumingfa
2024-08-03 23:38:05 +08:00
parent 7d8879abcb
commit 694aa18452
13 changed files with 337 additions and 181 deletions

View File

@@ -1,158 +0,0 @@
<!--
* 已办/代办
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-12 22:34:00
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*
-->
<template>
<default-home-card icon="Star" title="已办待办">
<div style="height: 280px">
<div class="center column">
<a-space direction="vertical" style="width: 100%">
<div v-for="(item, index) in toDoList" :key="index" :class="['to-do', { done: item.doneFlag }]">
<a-checkbox v-model:checked="item.doneFlag">
<span class="task">{{ item.title }}</span>
</a-checkbox>
<div class="star-icon" @click="itemStar(item)">
<StarFilled v-if="item.starFlag" style="color: #ff8c00" />
<StarOutlined v-else style="color: #c0c0c0" />
</div>
</div>
<div v-for="(item, index) in doneList" :key="index" :class="['to-do', { done: item.doneFlag }]">
<a-checkbox v-model:checked="item.doneFlag">
<span class="task">{{ item.title }}</span>
</a-checkbox>
<div class="star-icon" @click="itemStar(item)">
<StarFilled v-if="item.starFlag" style="color: #ff8c00" />
<StarOutlined v-else style="color: #c0c0c0" />
</div>
</div>
</a-space>
</div>
</div>
</default-home-card>
</template>
<script setup>
import DefaultHomeCard from '/@/views/system/home/components/default-home-card.vue';
import { computed, ref } from 'vue';
import dayjs from 'dayjs';
import { message } from 'ant-design-vue';
let taskList = ref([
{
title: '周五下班前需要提交周报',
doneFlag: true,
starFlag: true,
starTime: 0,
},
{
title: '为SmartAdmin前端小组分配任务',
doneFlag: false,
starFlag: false,
starTime: 0,
},
{
title: '跟进团建内容事宜',
doneFlag: false,
starFlag: true,
starTime: 0,
},
{
title: '跟进客户定制一个软件平台',
doneFlag: false,
starFlag: false,
starTime: 0,
},
{
title: '下个版本的需求确认',
doneFlag: false,
starFlag: false,
starTime: 0,
},
{
title: '线上版本发布',
doneFlag: true,
starFlag: true,
starTime: dayjs().unix(),
},
{
title: '周一财务报销',
doneFlag: true,
starFlag: false,
starTime: 0,
},
]);
let toDoList = computed(() => {
return taskList.value.filter((e) => !e.doneFlag).sort((a, b) => b.starTime - a.starTime);
});
let doneList = computed(() => {
return taskList.value.filter((e) => e.doneFlag);
});
function itemStar(item) {
item.starFlag = !item.starFlag;
if (item.starFlag) {
item.starTime = dayjs().unix();
}
}
//-------------------------任务新建-----------------------
let taskTitle = ref('');
function addTask() {
if (!taskTitle.value) {
message.warn('请输入任务标题');
return;
}
let data = {
title: taskTitle.value,
doneFlag: false,
starFlag: false,
starTime: 0,
};
taskList.value.unshift(data);
taskTitle.value = '';
}
</script>
<style lang="less" scoped>
.center {
display: flex;
justify-content: center;
height: 100%;
&.column {
flex-direction: column;
width: 100%;
padding: 0 10px;
justify-content: flex-start;
}
}
.to-do {
width: 100%;
border: 1px solid #d3d3d3;
border-radius: 4px;
padding: 4px;
display: flex;
align-items: center;
.star-icon {
margin-left: auto;
cursor: pointer;
}
&.done {
text-decoration: line-through;
color: #8c8c8c;
.task {
color: #8c8c8c;
}
}
}
</style>

View File

@@ -0,0 +1,172 @@
<!--
* 已办/代办
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-12 22:34:00
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*
-->
<template>
<default-home-card extra="添加" icon="StarTwoTone" title="待办工作" @extraClick="showAddToBeDone">
<div style="height: 280px">
<div class="center column">
<a-space direction="vertical" style="width: 100%">
<a-empty v-if="$lodash.isEmpty(toBeDoneList)" description="暂无待办工作" />
<div v-for="(item, index) in toDoList" :key="index" :class="['to-do', { done: item.doneFlag }]">
<a-checkbox v-model:checked="item.doneFlag" @change="handleCheckbox">
<span class="task">{{ item.title }}</span>
</a-checkbox>
<div v-if="!item.doneFlag" class="star-icon" @click="itemStar(item)">
<StarFilled v-if="item.starFlag" style="color: #ff8c00" />
<StarOutlined v-else style="color: #c0c0c0" />
</div>
<close-circle-outlined class="delete-icon" @click="toDelete(item)" />
</div>
<div v-for="(item, index) in doneList" :key="index" :class="['to-do', { done: item.doneFlag }]">
<a-checkbox v-model:checked="item.doneFlag" @change="handleCheckbox">
<span class="task">{{ item.title }}</span>
</a-checkbox>
<div v-if="!item.doneFlag" class="star-icon" @click="itemStar(item)">
<StarFilled v-if="item.starFlag" style="color: #ff8c00" />
<StarOutlined v-else style="color: #c0c0c0" />
</div>
<close-circle-outlined class="delete-icon" @click="toDelete(item)" />
</div>
</a-space>
</div>
</div>
</default-home-card>
<ToBeDoneModal ref="toBeDoneModalRef" @addToBeDone="addToBeDone" />
</template>
<script setup>
import DefaultHomeCard from '/@/views/system/home/components/default-home-card.vue';
import ToBeDoneModal from './to-be-done-modal.vue';
import localKey from '/@/constants/local-storage-key-const';
import { localRead, localSave } from '/@/utils/local-util';
import { useUserStore } from '/@/store/modules/system/user.js';
import { computed, ref, onMounted } from 'vue';
import { Modal } from 'ant-design-vue';
let toBeDoneList = ref([]);
onMounted(() => {
initTaskList();
});
function initTaskList() {
let localTaskList = localRead(localKey.TO_BE_DONE);
if (localTaskList) {
toBeDoneList.value = JSON.parse(localTaskList);
}
}
let toDoList = computed(() => {
return toBeDoneList.value.filter((e) => !e.doneFlag);
});
let doneList = computed(() => {
return toBeDoneList.value.filter((e) => e.doneFlag);
});
function handleCheckbox(e) {
localSave(localKey.TO_BE_DONE, JSON.stringify(toBeDoneList.value));
}
function itemStar(data) {
data.starFlag = !data.starFlag;
const index = toBeDoneList.value.findIndex((item) => item.title === data.title);
toBeDoneList.value.splice(index, 1);
if (data.starFlag) {
toBeDoneList.value.unshift(data);
} else {
toBeDoneList.value.push(data);
}
localSave(localKey.TO_BE_DONE, JSON.stringify(toBeDoneList.value));
}
//-------------------------任务新建-----------------------
let toBeDoneModalRef = ref();
function showAddToBeDone() {
toBeDoneModalRef.value.showModal();
}
// 添加待办工作
function addToBeDone(data) {
toBeDoneList.value.unshift(data);
useUserStore().toBeDoneCount = toBeDoneList.value.length;
localSave(localKey.TO_BE_DONE, JSON.stringify(toBeDoneList.value));
}
function toDelete(data) {
if (!data.doneFlag) {
Modal.confirm({
title: '提示',
content: '确定要删除吗?',
okText: '删除',
okType: 'danger',
onOk() {
deleteToBeDone(data);
},
cancelText: '取消',
onCancel() {},
});
} else {
deleteToBeDone(data);
}
}
// 删除待办工作
function deleteToBeDone(data) {
const index = toBeDoneList.value.findIndex((item) => item.title === data.title);
toBeDoneList.value.splice(index, 1);
useUserStore().toBeDoneCount = toBeDoneList.value.length;
localSave(localKey.TO_BE_DONE, JSON.stringify(toBeDoneList.value));
}
</script>
<style lang="less" scoped>
.center {
display: flex;
justify-content: center;
height: 100%;
overflow-y: auto;
&.column {
flex-direction: column;
width: 100%;
padding: 0 10px;
justify-content: flex-start;
}
}
.to-do {
width: 100%;
border: 1px solid #d3d3d3;
border-radius: 4px;
padding: 4px;
display: flex;
align-items: center;
.star-icon {
margin-left: auto;
cursor: pointer;
}
&.done {
text-decoration: line-through;
color: #8c8c8c;
.task {
color: #8c8c8c;
}
}
}
.delete-icon {
color: #f08080;
padding-left: 10px;
top: -5px;
right: -5px;
float: right;
}
</style>

View File

@@ -0,0 +1,63 @@
<template>
<a-modal v-model:open="visible" title="新建待办" @close="onClose">
<a-form ref="formRef" :model="form" :rules="rules">
<a-form-item label="标题" name="title">
<a-input v-model:value="form.title" placeholder="请输入标题" />
</a-form-item>
</a-form>
<template #footer>
<a-button @click="onClose">取消</a-button>
<a-button type="primary" @click="onSubmit">确定</a-button>
</template>
</a-modal>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { message } from 'ant-design-vue';
import _ from 'lodash';
defineExpose({
showModal,
});
const emit = defineEmits(['addToBeDone']);
// 组件ref
const formRef = ref();
const formDefault = {
title: undefined,
doneFlag: false,
starFlag: false,
starTime: 0,
};
let form = reactive({ ...formDefault });
const rules = {
title: [{ required: true, message: '标题不能为空' }],
};
const visible = ref(false);
function showModal() {
visible.value = true;
}
function onClose() {
Object.assign(form, formDefault);
visible.value = false;
}
function onSubmit() {
formRef.value
.validate()
.then(() => {
emit('addToBeDone', _.cloneDeep(form));
onClose();
})
.catch((error) => {
console.log('error', error);
message.error('参数验证错误,请仔细填写表单数据!');
});
}
</script>
<style lang="less" scoped></style>

View File

@@ -70,7 +70,7 @@
import HomeNotice from './home-notice.vue';
import HomeQuickEntry from './components/quick-entry/home-quick-entry.vue';
import OfficialAccountCard from './components/official-account-card.vue';
import ToBeDoneCard from './components/to-be-done-card.vue';
import ToBeDoneCard from './components/to-be-done-card/home-to-be-done.vue';
import ChangelogCard from './components/changelog-card.vue';
import Gauge from './components/echarts/gauge.vue';
import Category from './components/echarts/category.vue';