Files
ctms/frontend/src/views/workbench/components/PersonalTodo.vue
T
2025-12-17 22:37:51 +08:00

109 lines
2.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<el-card shadow="never" class="todo-card">
<div class="section-header">
<span>个人待办本地</span>
</div>
<div class="input-row">
<el-input v-model="input" placeholder="记录一个备忘..." @keyup.enter.native="add" />
<el-button type="primary" @click="add">添加</el-button>
</div>
<div v-if="todos.length" class="todo-list">
<div v-for="item in todos" :key="item.id" class="todo-item">
<el-checkbox v-model="item.done" @change="save">{{ item.text }}</el-checkbox>
<el-button link type="danger" size="small" @click="remove(item.id)">删除</el-button>
</div>
</div>
<div v-else class="empty">暂无待办可添加你的个人备忘</div>
</el-card>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
const props = defineProps<{ storageKey: string | undefined }>();
interface TodoItem {
id: string;
text: string;
done: boolean;
}
const input = ref("");
const todos = ref<TodoItem[]>([]);
const load = () => {
if (!props.storageKey) return;
const raw = localStorage.getItem(props.storageKey);
if (raw) {
try {
todos.value = JSON.parse(raw) || [];
} catch {
todos.value = [];
}
}
};
const save = () => {
if (!props.storageKey) return;
localStorage.setItem(props.storageKey, JSON.stringify(todos.value));
};
const add = () => {
const text = input.value.trim();
if (!text) return;
todos.value.unshift({
id: crypto.randomUUID ? crypto.randomUUID() : Date.now().toString(),
text,
done: false,
});
input.value = "";
save();
};
const remove = (id: string) => {
todos.value = todos.value.filter((t) => t.id !== id);
save();
};
watch(
() => props.storageKey,
() => load(),
{ immediate: true }
);
onMounted(() => {
load();
});
</script>
<style scoped>
.todo-card {
min-height: 200px;
}
.section-header {
font-weight: 600;
margin-bottom: 8px;
}
.input-row {
display: flex;
gap: 8px;
margin-bottom: 8px;
}
.todo-list {
display: flex;
flex-direction: column;
gap: 6px;
}
.todo-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 6px 8px;
border: 1px solid #ebeef5;
border-radius: 6px;
}
.empty {
color: #888;
}
</style>