工作台界面-初版
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user