You've already forked SmartisanNote.Remake
优化 头部便签管理点击区域;
补充注释;
This commit is contained in:
63
package-lock.json
generated
63
package-lock.json
generated
@@ -13,6 +13,7 @@
|
|||||||
"@capacitor/cli": "^5.7.2",
|
"@capacitor/cli": "^5.7.2",
|
||||||
"@capacitor/core": "^5.7.2",
|
"@capacitor/core": "^5.7.2",
|
||||||
"@capacitor/ios": "^5.7.2",
|
"@capacitor/ios": "^5.7.2",
|
||||||
|
"@ionic/vue": "^8.7.6",
|
||||||
"@vue/cli-service": "^5.0.9",
|
"@vue/cli-service": "^5.0.9",
|
||||||
"@vue/compiler-sfc": "^3.5.22",
|
"@vue/compiler-sfc": "^3.5.22",
|
||||||
"basic-ftp": "^5.0.5",
|
"basic-ftp": "^5.0.5",
|
||||||
@@ -2150,6 +2151,26 @@
|
|||||||
"node": ">=16.0.0"
|
"node": ">=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ionic/core": {
|
||||||
|
"version": "8.7.6",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@ionic/core/-/core-8.7.6.tgz",
|
||||||
|
"integrity": "sha512-ufV64Pl0BYSoNla+DaTRXTS3hX6MQZZJPhAR3fJQ4N5Fg/vwMcHADQffstKZeoPqk6mbJoLqoTBjcWvaLRdO0g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@stencil/core": "4.38.0",
|
||||||
|
"ionicons": "^8.0.13",
|
||||||
|
"tslib": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@ionic/core/node_modules/ionicons": {
|
||||||
|
"version": "8.0.13",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ionicons/-/ionicons-8.0.13.tgz",
|
||||||
|
"integrity": "sha512-2QQVyG2P4wszne79jemMjWYLp0DBbDhr4/yFroPCxvPP1wtMxgdIV3l5n+XZ5E9mgoXU79w7yTWpm2XzJsISxQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@stencil/core": "^4.35.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@ionic/utils-array": {
|
"node_modules/@ionic/utils-array": {
|
||||||
"version": "2.1.6",
|
"version": "2.1.6",
|
||||||
"resolved": "https://registry.npmmirror.com/@ionic/utils-array/-/utils-array-2.1.6.tgz",
|
"resolved": "https://registry.npmmirror.com/@ionic/utils-array/-/utils-array-2.1.6.tgz",
|
||||||
@@ -2359,6 +2380,26 @@
|
|||||||
"node": ">=16.0.0"
|
"node": ">=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ionic/vue": {
|
||||||
|
"version": "8.7.6",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@ionic/vue/-/vue-8.7.6.tgz",
|
||||||
|
"integrity": "sha512-gK5x5Y0ZpZAW12gjvyBO9oUfwDZxMS7y0xcO0P9qzo++h3ZLcFcSGjHs8D4isUY/mF6mRagt1Y/5b0xDhgUBBw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@ionic/core": "8.7.6",
|
||||||
|
"@stencil/vue-output-target": "0.10.7",
|
||||||
|
"ionicons": "^8.0.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@ionic/vue/node_modules/ionicons": {
|
||||||
|
"version": "8.0.13",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ionicons/-/ionicons-8.0.13.tgz",
|
||||||
|
"integrity": "sha512-2QQVyG2P4wszne79jemMjWYLp0DBbDhr4/yFroPCxvPP1wtMxgdIV3l5n+XZ5E9mgoXU79w7yTWpm2XzJsISxQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@stencil/core": "^4.35.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.13",
|
"version": "0.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||||
@@ -2936,6 +2977,28 @@
|
|||||||
"@rollup/rollup-win32-x64-msvc": "4.34.9"
|
"@rollup/rollup-win32-x64-msvc": "4.34.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@stencil/vue-output-target": {
|
||||||
|
"version": "0.10.7",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@stencil/vue-output-target/-/vue-output-target-0.10.7.tgz",
|
||||||
|
"integrity": "sha512-IYxDe+SLCkwhwsWRdynE31rTK1zN3hVwwojQ/V9lrN8Gnx4PTvrUQHiRno9jFo1dk+EaBZWX9gZSmXta0ZaZew==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@stencil/core": ">=2.0.0 || >=3 || >= 4.0.0-beta.0 || >= 4.0.0",
|
||||||
|
"vue": "^3.4.38",
|
||||||
|
"vue-router": "^4.5.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@stencil/core": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"vue": {
|
||||||
|
"optional": false
|
||||||
|
},
|
||||||
|
"vue-router": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@surma/rollup-plugin-off-main-thread": {
|
"node_modules/@surma/rollup-plugin-off-main-thread": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmmirror.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
"resolved": "https://registry.npmmirror.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"@capacitor/cli": "^5.7.2",
|
"@capacitor/cli": "^5.7.2",
|
||||||
"@capacitor/core": "^5.7.2",
|
"@capacitor/core": "^5.7.2",
|
||||||
"@capacitor/ios": "^5.7.2",
|
"@capacitor/ios": "^5.7.2",
|
||||||
|
"@ionic/vue": "^8.7.6",
|
||||||
"@vue/cli-service": "^5.0.9",
|
"@vue/cli-service": "^5.0.9",
|
||||||
"@vue/compiler-sfc": "^3.5.22",
|
"@vue/compiler-sfc": "^3.5.22",
|
||||||
"basic-ftp": "^5.0.5",
|
"basic-ftp": "^5.0.5",
|
||||||
|
|||||||
@@ -6,5 +6,4 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import '@/common/base.css'
|
import '@/common/base.css'
|
||||||
// App根组件不需要额外的逻辑
|
</script>
|
||||||
</script>
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
<img class="left-icon" :src="leftIconSource" @click="handleLeftAction" />
|
<img class="left-icon" :src="leftIconSource" @click="handleLeftAction" />
|
||||||
|
|
||||||
<!-- 标题区域 -->
|
<!-- 标题区域 -->
|
||||||
<div class="title-container" @click="handleTitlePress">
|
<div class="title-container">
|
||||||
<span class="text">{{ title }}</span>
|
<span class="text" @click="handleTitlePress">{{ title }}</span>
|
||||||
<!-- 文件夹展开图标 -->
|
<!-- 文件夹展开图标 -->
|
||||||
<img v-if="showFolderIcon" class="folder-icon" :src="folderExpanded ? '/assets/icons/drawable-xxhdpi/folder_title_arrow_pressed.png' : '/assets/icons/drawable-xxhdpi/folder_title_arrow_normal.png'" @click.stop="handleFolderToggle" />
|
<img v-if="showFolderIcon" class="folder-icon" :src="folderExpanded ? '/assets/icons/drawable-xxhdpi/folder_title_arrow_pressed.png' : '/assets/icons/drawable-xxhdpi/folder_title_arrow_normal.png'" @click.stop="handleFolderToggle" />
|
||||||
</div>
|
</div>
|
||||||
@@ -118,7 +118,7 @@ const handleLeftAction = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAction = (actionType) => {
|
const handleAction = actionType => {
|
||||||
// 处理右侧操作按钮点击事件
|
// 处理右侧操作按钮点击事件
|
||||||
if (props.onAction) {
|
if (props.onAction) {
|
||||||
props.onAction(actionType)
|
props.onAction(actionType)
|
||||||
@@ -156,7 +156,7 @@ const handleTitlePress = () => {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.right-group {
|
.right-group {
|
||||||
gap: .6rem;
|
gap: 0.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image_4-placeholder {
|
.image_4-placeholder {
|
||||||
|
|||||||
@@ -79,13 +79,15 @@ const isSlided = ref(false) // 是否已经滑动到阈值
|
|||||||
|
|
||||||
const formattedDate = computed(() => {
|
const formattedDate = computed(() => {
|
||||||
// 直接返回已经格式化的日期字符串
|
// 直接返回已经格式化的日期字符串
|
||||||
|
// 日期格式化已在父组件中完成
|
||||||
return props.date
|
return props.date
|
||||||
})
|
})
|
||||||
|
|
||||||
// 处理显示内容,过滤HTML标签并只显示第一行
|
// 处理显示内容,过滤HTML标签并只显示第一行
|
||||||
|
// 用于在便签列表中显示便签的预览内容
|
||||||
const displayContent = computed(() => {
|
const displayContent = computed(() => {
|
||||||
console.log('NoteItem content:', props.content)
|
console.log('NoteItem content:', props.content)
|
||||||
// 过滤HTML标签
|
// 过滤HTML标签,只保留纯文本内容
|
||||||
let text = props.content.replace(/<[^>]*>/g, '')
|
let text = props.content.replace(/<[^>]*>/g, '')
|
||||||
console.log('NoteItem text without HTML:', text)
|
console.log('NoteItem text without HTML:', text)
|
||||||
|
|
||||||
@@ -100,8 +102,11 @@ const displayContent = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 滑动阈值(删除按钮宽度)
|
// 滑动阈值(删除按钮宽度)
|
||||||
|
// 当滑动距离超过此值时,显示删除按钮
|
||||||
const SLIDE_THRESHOLD = 64 // 4rem 转换为 px
|
const SLIDE_THRESHOLD = 64 // 4rem 转换为 px
|
||||||
|
|
||||||
|
// 处理便签点击事件
|
||||||
|
// 只有在未滑动状态下才触发点击事件,避免与滑动操作冲突
|
||||||
const handlePress = () => {
|
const handlePress = () => {
|
||||||
// 只有在未滑动状态下才触发点击事件
|
// 只有在未滑动状态下才触发点击事件
|
||||||
if (slideOffset.value === 0 && props.onPress) {
|
if (slideOffset.value === 0 && props.onPress) {
|
||||||
@@ -109,31 +114,39 @@ const handlePress = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理星标切换事件
|
||||||
|
// 点击星标图标时调用父组件传递的回调函数
|
||||||
const handleStarToggle = () => {
|
const handleStarToggle = () => {
|
||||||
if (props.onStarToggle) {
|
if (props.onStarToggle) {
|
||||||
props.onStarToggle()
|
props.onStarToggle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理置顶切换事件
|
||||||
|
// 点击置顶图标时调用父组件传递的回调函数
|
||||||
const handleTopToggle = () => {
|
const handleTopToggle = () => {
|
||||||
if (props.onTopToggle) {
|
if (props.onTopToggle) {
|
||||||
props.onTopToggle()
|
props.onTopToggle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理删除事件
|
||||||
|
// 点击删除按钮时调用父组件传递的回调函数
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
if (props.onDelete) {
|
if (props.onDelete) {
|
||||||
props.onDelete()
|
props.onDelete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 触摸开始
|
// 触摸开始事件处理函数
|
||||||
|
// 记录触摸开始时的X坐标,用于计算滑动距离
|
||||||
const handleTouchStart = e => {
|
const handleTouchStart = e => {
|
||||||
// 重置滑动状态
|
// 重置滑动状态
|
||||||
startX.value = e.touches[0].clientX
|
startX.value = e.touches[0].clientX
|
||||||
}
|
}
|
||||||
|
|
||||||
// 触摸移动
|
// 触摸移动事件处理函数
|
||||||
|
// 根据手指移动距离计算便签条的水平偏移量
|
||||||
const handleTouchMove = e => {
|
const handleTouchMove = e => {
|
||||||
if (!startX.value) return
|
if (!startX.value) return
|
||||||
|
|
||||||
@@ -147,15 +160,15 @@ const handleTouchMove = e => {
|
|||||||
// 设置滑动状态
|
// 设置滑动状态
|
||||||
isSliding.value = true
|
isSliding.value = true
|
||||||
|
|
||||||
// 应用阻尼效果
|
// 应用阻尼效果,使超过阈值后的滑动更加困难
|
||||||
let offset = 0
|
let offset = 0
|
||||||
if (diffX <= SLIDE_THRESHOLD) {
|
if (diffX <= SLIDE_THRESHOLD) {
|
||||||
// 线性滑动
|
// 线性滑动,在阈值内正常滑动
|
||||||
offset = diffX
|
offset = diffX
|
||||||
} else {
|
} else {
|
||||||
// 超过阈值后应用阻尼效果
|
// 超过阈值后应用阻尼效果,增加滑动阻力
|
||||||
const excess = diffX - SLIDE_THRESHOLD
|
const excess = diffX - SLIDE_THRESHOLD
|
||||||
offset = SLIDE_THRESHOLD + excess * 0.03 // 0.3 为阻尼系数
|
offset = SLIDE_THRESHOLD + excess * 0.03 // 0.03 为阻尼系数
|
||||||
}
|
}
|
||||||
|
|
||||||
slideOffset.value = offset
|
slideOffset.value = offset
|
||||||
@@ -171,12 +184,14 @@ const handleTouchMove = e => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 触摸结束
|
// 触摸结束事件处理函数
|
||||||
|
// 根据滑动距离决定便签条的最终位置
|
||||||
const handleTouchEnd = () => {
|
const handleTouchEnd = () => {
|
||||||
if (!startX.value) return
|
if (!startX.value) return
|
||||||
|
|
||||||
// 如果滑动超过阈值,保持滑出状态;否则回弹
|
// 如果滑动超过阈值,保持滑出状态;否则回弹
|
||||||
if (slideOffset.value >= SLIDE_THRESHOLD) {
|
if (slideOffset.value >= SLIDE_THRESHOLD) {
|
||||||
|
// 保持滑出状态,显示删除按钮
|
||||||
slideOffset.value = SLIDE_THRESHOLD
|
slideOffset.value = SLIDE_THRESHOLD
|
||||||
isSlided.value = true
|
isSlided.value = true
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -50,42 +50,43 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 工具配置
|
// 工具栏配置
|
||||||
|
// 定义富文本编辑器的所有工具按钮及其功能
|
||||||
const tools = ref([
|
const tools = ref([
|
||||||
{
|
{
|
||||||
name: 'bold',
|
name: 'bold', // 加粗工具
|
||||||
icon: '/assets/icons/drawable-xxhdpi/rtf_bold_normal.9.png',
|
icon: '/assets/icons/drawable-xxhdpi/rtf_bold_normal.9.png',
|
||||||
action: () => formatText('bold'),
|
action: () => formatText('bold'), // 执行加粗格式化
|
||||||
active: false,
|
active: false, // 工具是否处于激活状态
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'center',
|
name: 'center', // 居中对齐工具
|
||||||
icon: '/assets/icons/drawable-xxhdpi/rtf_center_normal.9.png',
|
icon: '/assets/icons/drawable-xxhdpi/rtf_center_normal.9.png',
|
||||||
action: () => formatText('justifyCenter'),
|
action: () => formatText('justifyCenter'), // 执行居中对齐格式化
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'todo',
|
name: 'todo', // 待办事项工具
|
||||||
icon: '/assets/icons/drawable-xxhdpi/rtf_gtasks_normal.9.png',
|
icon: '/assets/icons/drawable-xxhdpi/rtf_gtasks_normal.9.png',
|
||||||
action: () => formatText('insertTodoList'),
|
action: () => formatText('insertTodoList'), // 插入待办事项列表
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'list',
|
name: 'list', // 无序列表工具
|
||||||
icon: '/assets/icons/drawable-xxhdpi/rtf_list_normal.9.png',
|
icon: '/assets/icons/drawable-xxhdpi/rtf_list_normal.9.png',
|
||||||
action: () => formatText('insertUnorderedList'),
|
action: () => formatText('insertUnorderedList'), // 插入无序列表
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'header',
|
name: 'header', // 标题工具
|
||||||
icon: '/assets/icons/drawable-xxhdpi/rtf_header_normal.9.png',
|
icon: '/assets/icons/drawable-xxhdpi/rtf_header_normal.9.png',
|
||||||
action: () => formatText('formatBlock', 'h2'),
|
action: () => formatText('formatBlock', 'h2'), // 格式化为二级标题
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'quote',
|
name: 'quote', // 引用工具
|
||||||
icon: '/assets/icons/drawable-xxhdpi/rtf_quot_normal.9.png',
|
icon: '/assets/icons/drawable-xxhdpi/rtf_quot_normal.9.png',
|
||||||
action: () => insertQuote(),
|
action: () => insertQuote(), // 插入引用格式
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
@@ -112,6 +113,7 @@ const handleInput = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查当前选区是否已经在某种格式中
|
// 检查当前选区是否已经在某种格式中
|
||||||
|
// 用于防止重复应用相同的格式,例如重复加粗
|
||||||
const isAlreadyInFormat = formatType => {
|
const isAlreadyInFormat = formatType => {
|
||||||
const selection = window.getSelection()
|
const selection = window.getSelection()
|
||||||
if (selection.rangeCount > 0) {
|
if (selection.rangeCount > 0) {
|
||||||
@@ -121,10 +123,15 @@ const isAlreadyInFormat = formatType => {
|
|||||||
// 向上查找父元素,检查是否已经在指定格式中
|
// 向上查找父元素,检查是否已经在指定格式中
|
||||||
let current = container.nodeType === Node.TEXT_NODE ? container.parentElement : container
|
let current = container.nodeType === Node.TEXT_NODE ? container.parentElement : container
|
||||||
while (current && current !== editorRef.value) {
|
while (current && current !== editorRef.value) {
|
||||||
|
// 检查加粗格式
|
||||||
if (formatType === 'bold' && current.tagName === 'B') return true
|
if (formatType === 'bold' && current.tagName === 'B') return true
|
||||||
|
// 检查居中对齐格式
|
||||||
if (formatType === 'center' && current.style.textAlign === 'center') return true
|
if (formatType === 'center' && current.style.textAlign === 'center') return true
|
||||||
|
// 检查标题格式
|
||||||
if (formatType === 'header' && current.tagName === 'H2') return true
|
if (formatType === 'header' && current.tagName === 'H2') return true
|
||||||
|
// 检查引用格式
|
||||||
if (formatType === 'quote' && (current.tagName === 'BLOCKQUOTE' || current.classList.contains('quote-content'))) return true
|
if (formatType === 'quote' && (current.tagName === 'BLOCKQUOTE' || current.classList.contains('quote-content'))) return true
|
||||||
|
// 检查列表格式
|
||||||
if (formatType === 'list' && (current.tagName === 'UL' || current.tagName === 'OL' || current.tagName === 'LI')) return true
|
if (formatType === 'list' && (current.tagName === 'UL' || current.tagName === 'OL' || current.tagName === 'LI')) return true
|
||||||
current = current.parentElement
|
current = current.parentElement
|
||||||
}
|
}
|
||||||
@@ -133,6 +140,7 @@ const isAlreadyInFormat = formatType => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否在列表、引用或待办事项中(用于嵌套限制)
|
// 检查是否在列表、引用或待办事项中(用于嵌套限制)
|
||||||
|
// 防止在已有的列表、引用或待办事项中再次插入相同类型的元素
|
||||||
const isInListOrQuote = () => {
|
const isInListOrQuote = () => {
|
||||||
const selection = window.getSelection()
|
const selection = window.getSelection()
|
||||||
if (selection.rangeCount > 0) {
|
if (selection.rangeCount > 0) {
|
||||||
@@ -142,7 +150,10 @@ const isInListOrQuote = () => {
|
|||||||
// 向上查找父元素,检查是否在列表、引用或待办事项中
|
// 向上查找父元素,检查是否在列表、引用或待办事项中
|
||||||
let current = container.nodeType === Node.TEXT_NODE ? container.parentElement : container
|
let current = container.nodeType === Node.TEXT_NODE ? container.parentElement : container
|
||||||
while (current && current !== editorRef.value) {
|
while (current && current !== editorRef.value) {
|
||||||
if (current.tagName === 'UL' || current.tagName === 'OL' || current.tagName === 'LI' || current.tagName === 'BLOCKQUOTE' || current.classList.contains('quote-content') || current.classList.contains('todo-container')) {
|
// 检查是否在列表、引用或待办事项中
|
||||||
|
if (current.tagName === 'UL' || current.tagName === 'OL' || current.tagName === 'LI' ||
|
||||||
|
current.tagName === 'BLOCKQUOTE' || current.classList.contains('quote-content') ||
|
||||||
|
current.classList.contains('todo-container')) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
current = current.parentElement
|
current = current.parentElement
|
||||||
@@ -152,8 +163,10 @@ const isInListOrQuote = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 格式化文本
|
// 格式化文本
|
||||||
|
// 根据指定的命令和值对选中文本应用格式
|
||||||
const formatText = (command, value = null) => {
|
const formatText = (command, value = null) => {
|
||||||
// 检查是否已经应用了相同的格式,如果已应用则取消格式
|
// 检查是否已经应用了相同的格式,如果已应用则取消格式
|
||||||
|
// 例如,如果文本已经是加粗的,再次点击加粗按钮会取消加粗
|
||||||
if (command === 'bold' && isAlreadyInFormat('bold')) {
|
if (command === 'bold' && isAlreadyInFormat('bold')) {
|
||||||
document.execCommand('bold', false, null)
|
document.execCommand('bold', false, null)
|
||||||
updateToolbarState()
|
updateToolbarState()
|
||||||
@@ -161,6 +174,7 @@ const formatText = (command, value = null) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理居中对齐切换:如果已居中则取消居中
|
||||||
if (command === 'justifyCenter' && isAlreadyInFormat('center')) {
|
if (command === 'justifyCenter' && isAlreadyInFormat('center')) {
|
||||||
document.execCommand('justifyLeft', false, null)
|
document.execCommand('justifyLeft', false, null)
|
||||||
updateToolbarState()
|
updateToolbarState()
|
||||||
@@ -168,6 +182,7 @@ const formatText = (command, value = null) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理标题格式切换:如果已是标题则转为普通段落
|
||||||
if (command === 'formatBlock' && value === 'h2' && isAlreadyInFormat('header')) {
|
if (command === 'formatBlock' && value === 'h2' && isAlreadyInFormat('header')) {
|
||||||
document.execCommand('formatBlock', false, '<p>')
|
document.execCommand('formatBlock', false, '<p>')
|
||||||
updateToolbarState()
|
updateToolbarState()
|
||||||
@@ -175,6 +190,7 @@ const formatText = (command, value = null) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理列表格式切换:如果已是列表则取消列表
|
||||||
if (command === 'insertUnorderedList' && isAlreadyInFormat('list')) {
|
if (command === 'insertUnorderedList' && isAlreadyInFormat('list')) {
|
||||||
document.execCommand('insertUnorderedList', false, null)
|
document.execCommand('insertUnorderedList', false, null)
|
||||||
updateToolbarState()
|
updateToolbarState()
|
||||||
@@ -189,13 +205,16 @@ const formatText = (command, value = null) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查嵌套限制
|
// 检查嵌套限制,防止在列表、引用中再次插入列表或引用
|
||||||
if ((command === 'insertUnorderedList' || (command === 'formatBlock' && value === 'blockquote')) && isInListOrQuote()) {
|
if ((command === 'insertUnorderedList' || (command === 'formatBlock' && value === 'blockquote')) && isInListOrQuote()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 执行格式化命令
|
||||||
document.execCommand(command, false, value)
|
document.execCommand(command, false, value)
|
||||||
|
// 更新工具栏状态以反映当前格式
|
||||||
updateToolbarState()
|
updateToolbarState()
|
||||||
|
// 触发输入事件以更新内容
|
||||||
handleInput()
|
handleInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,39 +302,40 @@ const insertQuote = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 插入待办事项列表
|
// 插入待办事项列表
|
||||||
|
// 创建一个可交互的待办事项元素,包含复选框图标和可编辑内容区域
|
||||||
const insertTodoList = () => {
|
const insertTodoList = () => {
|
||||||
const selection = window.getSelection()
|
const selection = window.getSelection()
|
||||||
if (selection.rangeCount > 0) {
|
if (selection.rangeCount > 0) {
|
||||||
const range = selection.getRangeAt(0)
|
const range = selection.getRangeAt(0)
|
||||||
|
|
||||||
// 检查嵌套限制
|
// 检查嵌套限制,防止在列表或引用中插入待办事项
|
||||||
if (isInListOrQuote()) return
|
if (isInListOrQuote()) return
|
||||||
|
|
||||||
// 创建待办事项容器
|
// 创建待办事项容器
|
||||||
const todoContainer = document.createElement('div')
|
const todoContainer = document.createElement('div')
|
||||||
todoContainer.contentEditable = false
|
todoContainer.contentEditable = false // 容器本身不可编辑
|
||||||
todoContainer.className = 'todo-container'
|
todoContainer.className = 'todo-container'
|
||||||
|
|
||||||
// 创建图标元素
|
// 创建图标元素(复选框)
|
||||||
const icon = document.createElement('img')
|
const icon = document.createElement('img')
|
||||||
icon.className = 'todo-icon'
|
icon.className = 'todo-icon'
|
||||||
icon.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png'
|
icon.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png' // 未完成状态图标
|
||||||
icon.alt = '待办事项'
|
icon.alt = '待办事项'
|
||||||
|
|
||||||
// 创建内容容器
|
// 创建内容容器(可编辑区域)
|
||||||
const contentSpan = document.createElement('div')
|
const contentSpan = document.createElement('div')
|
||||||
contentSpan.contentEditable = true
|
contentSpan.contentEditable = true // 内容区域可编辑
|
||||||
contentSpan.className = 'todo-content'
|
contentSpan.className = 'todo-content'
|
||||||
contentSpan.textContent = '待办事项'
|
contentSpan.textContent = '待办事项' // 默认文本
|
||||||
|
|
||||||
// 组装元素
|
// 组装元素:将图标和内容区域添加到容器中
|
||||||
todoContainer.appendChild(icon)
|
todoContainer.appendChild(icon)
|
||||||
todoContainer.appendChild(contentSpan)
|
todoContainer.appendChild(contentSpan)
|
||||||
|
|
||||||
// 插入到当前光标位置
|
// 插入到当前光标位置
|
||||||
range.insertNode(todoContainer)
|
range.insertNode(todoContainer)
|
||||||
|
|
||||||
// 添加换行
|
// 添加换行,确保待办事项下方有空白行
|
||||||
const br = document.createElement('br')
|
const br = document.createElement('br')
|
||||||
todoContainer.parentNode.insertBefore(br, todoContainer.nextSibling)
|
todoContainer.parentNode.insertBefore(br, todoContainer.nextSibling)
|
||||||
|
|
||||||
@@ -338,19 +358,21 @@ const insertTodoList = () => {
|
|||||||
}
|
}
|
||||||
}, 0)
|
}, 0)
|
||||||
|
|
||||||
// 添加事件监听器到图标
|
// 添加事件监听器到图标,实现待办事项完成状态切换
|
||||||
icon.addEventListener('click', function () {
|
icon.addEventListener('click', function () {
|
||||||
// 根据当前状态切换图标
|
// 根据当前状态切换图标和样式
|
||||||
if (this.src.includes('rtf_icon_gtasks.png')) {
|
if (this.src.includes('rtf_icon_gtasks.png')) {
|
||||||
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks_light.png'
|
// 切换到完成状态
|
||||||
contentSpan.style.color = 'var(--text-tertiary)'
|
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks_light.png' // 完成状态图标
|
||||||
contentSpan.style.textDecoration = 'line-through'
|
contentSpan.style.color = 'var(--text-tertiary)' // 灰色文字
|
||||||
|
contentSpan.style.textDecoration = 'line-through' // 添加删除线
|
||||||
} else {
|
} else {
|
||||||
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png'
|
// 切换到未完成状态
|
||||||
contentSpan.style.color = 'var(--note-content)'
|
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png' // 未完成状态图标
|
||||||
contentSpan.style.textDecoration = 'none'
|
contentSpan.style.color = 'var(--note-content)' // 正常文字颜色
|
||||||
|
contentSpan.style.textDecoration = 'none' // 移除删除线
|
||||||
}
|
}
|
||||||
handleInput()
|
handleInput() // 触发内容更新
|
||||||
})
|
})
|
||||||
|
|
||||||
// 添加事件监听器到内容区域,监听内容变化和按键事件
|
// 添加事件监听器到内容区域,监听内容变化和按键事件
|
||||||
@@ -365,8 +387,8 @@ const insertTodoList = () => {
|
|||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
contentSpan.addEventListener('input', checkContent)
|
contentSpan.addEventListener('input', checkContent) // 内容输入时检查
|
||||||
contentSpan.addEventListener('blur', checkContent)
|
contentSpan.addEventListener('blur', checkContent) // 失去焦点时检查
|
||||||
|
|
||||||
// 添加焦点事件监听器,确保工具栏在待办事项获得焦点时保持可见
|
// 添加焦点事件监听器,确保工具栏在待办事项获得焦点时保持可见
|
||||||
contentSpan.addEventListener('focus', () => {
|
contentSpan.addEventListener('focus', () => {
|
||||||
|
|||||||
24
src/main.js
24
src/main.js
@@ -3,30 +3,48 @@ import { createRouter, createWebHashHistory } from 'vue-router'
|
|||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
|
|
||||||
// Pages
|
// 导入页面组件
|
||||||
|
// 便签列表页面
|
||||||
import NoteListPage from './pages/NoteListPage.vue'
|
import NoteListPage from './pages/NoteListPage.vue'
|
||||||
|
// 便签编辑页面(用于新建和编辑便签)
|
||||||
import NoteEditorPage from './pages/NoteEditorPage.vue'
|
import NoteEditorPage from './pages/NoteEditorPage.vue'
|
||||||
|
// 文件夹管理页面
|
||||||
import FolderPage from './pages/FolderPage.vue'
|
import FolderPage from './pages/FolderPage.vue'
|
||||||
|
// 设置页面
|
||||||
import SettingsPage from './pages/SettingsPage.vue'
|
import SettingsPage from './pages/SettingsPage.vue'
|
||||||
|
|
||||||
// Router
|
// 配置路由规则
|
||||||
|
// 定义应用的所有路由路径和对应的组件
|
||||||
const routes = [
|
const routes = [
|
||||||
|
// 根路径重定向到便签列表页面
|
||||||
{ path: '/', redirect: '/notes' },
|
{ path: '/', redirect: '/notes' },
|
||||||
|
// 便签列表页面路由
|
||||||
{ path: '/notes', component: NoteListPage },
|
{ path: '/notes', component: NoteListPage },
|
||||||
|
// 编辑便签页面路由(带便签ID参数)
|
||||||
{ path: '/notes/:id', component: NoteEditorPage, props: true },
|
{ path: '/notes/:id', component: NoteEditorPage, props: true },
|
||||||
|
// 新建便签页面路由
|
||||||
{ path: '/editor', component: NoteEditorPage },
|
{ path: '/editor', component: NoteEditorPage },
|
||||||
|
// 编辑便签页面路由(带便签ID参数)
|
||||||
{ path: '/editor/:id', component: NoteEditorPage, props: true },
|
{ path: '/editor/:id', component: NoteEditorPage, props: true },
|
||||||
|
// 文件夹管理页面路由
|
||||||
{ path: '/folders', component: FolderPage },
|
{ path: '/folders', component: FolderPage },
|
||||||
|
// 设置页面路由
|
||||||
{ path: '/settings', component: SettingsPage }
|
{ path: '/settings', component: SettingsPage }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// 创建路由实例
|
||||||
|
// 使用Hash模式以支持静态文件部署
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(),
|
history: createWebHashHistory(),
|
||||||
routes
|
routes
|
||||||
})
|
})
|
||||||
|
|
||||||
// App
|
// 创建并挂载Vue应用实例
|
||||||
|
// 配置Pinia状态管理和Vue Router路由
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
// 使用Pinia进行状态管理
|
||||||
app.use(createPinia())
|
app.use(createPinia())
|
||||||
|
// 使用Vue Router进行路由管理
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
// 挂载应用到DOM元素
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
@@ -29,12 +29,14 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
import { useAppStore } from '../stores/useAppStore'
|
import { useAppStore } from '../stores/useAppStore'
|
||||||
import { search, closeCircle } from 'ionicons/icons'
|
import { search, closeCircle } from 'ionicons/icons'
|
||||||
import FolderManage from '../components/FolderManage.vue'
|
import FolderManage from '../components/FolderManage.vue'
|
||||||
import Header from '../components/Header.vue'
|
import Header from '../components/Header.vue'
|
||||||
|
|
||||||
const store = useAppStore()
|
const store = useAppStore()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
// 加载初始数据
|
// 加载初始数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -44,7 +46,8 @@ onMounted(() => {
|
|||||||
const searchQuery = ref('')
|
const searchQuery = ref('')
|
||||||
const selectedFolder = ref('all')
|
const selectedFolder = ref('all')
|
||||||
|
|
||||||
// Calculate note count for each folder
|
// 计算每个文件夹中的便签数量
|
||||||
|
// 遍历所有自定义文件夹,统计每个文件夹中的便签数量
|
||||||
const foldersWithCount = computed(() => {
|
const foldersWithCount = computed(() => {
|
||||||
return store.folders.map(folder => {
|
return store.folders.map(folder => {
|
||||||
const noteCount = store.notes.filter(note => note.folderId === folder.id).length
|
const noteCount = store.notes.filter(note => note.folderId === folder.id).length
|
||||||
@@ -55,13 +58,17 @@ const foldersWithCount = computed(() => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add default folders at the beginning
|
// 添加默认文件夹(全部便签、加星便签、回收站)到列表开头
|
||||||
|
// 计算全部便签数量
|
||||||
const allNotesCount = computed(() => store.notes.length)
|
const allNotesCount = computed(() => store.notes.length)
|
||||||
|
// 计算加星便签数量
|
||||||
const starredNotesCount = computed(() => store.notes.filter(note => note.isStarred).length)
|
const starredNotesCount = computed(() => store.notes.filter(note => note.isStarred).length)
|
||||||
// Assuming we have a way to track deleted notes in the future
|
// 回收站便签数量(暂未实现完整功能)
|
||||||
const trashNotesCount = 0
|
const trashNotesCount = 0
|
||||||
|
// 归档便签数量(暂未实现完整功能)
|
||||||
const archiveCount = 0
|
const archiveCount = 0
|
||||||
|
|
||||||
|
// 合并默认文件夹和自定义文件夹
|
||||||
const foldersWithAllNotes = computed(() => {
|
const foldersWithAllNotes = computed(() => {
|
||||||
return [
|
return [
|
||||||
{ id: 'all', name: '全部便签', noteCount: allNotesCount.value, createdAt: new Date() },
|
{ id: 'all', name: '全部便签', noteCount: allNotesCount.value, createdAt: new Date() },
|
||||||
@@ -74,26 +81,28 @@ const foldersWithAllNotes = computed(() => {
|
|||||||
const handleFolderPress = folderId => {
|
const handleFolderPress = folderId => {
|
||||||
// 更新选中的文件夹状态
|
// 更新选中的文件夹状态
|
||||||
selectedFolder.value = folderId
|
selectedFolder.value = folderId
|
||||||
// 在实际应用中,这里会将选中的文件夹传递回NoteListScreen
|
// 使用vue-router导航回便签列表页面,并传递文件夹参数
|
||||||
// 通过导航参数传递选中的文件夹ID
|
router.push(`/notes?folder=${folderId}`)
|
||||||
window.location.hash = `#/notes?folder=${folderId}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理添加文件夹按钮点击事件
|
||||||
|
// 在完整实现中,这里会打开文件夹创建对话框
|
||||||
const handleAddFolder = () => {
|
const handleAddFolder = () => {
|
||||||
// In a full implementation, this would open a folder creation dialog
|
|
||||||
console.log('Add folder pressed')
|
console.log('Add folder pressed')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理搜索功能
|
||||||
|
// 在完整实现中,这里会根据搜索关键词过滤文件夹
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
// In a full implementation, this would filter folders based on searchQuery
|
|
||||||
console.log('Search for:', searchQuery.value)
|
console.log('Search for:', searchQuery.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleBackPress = () => {
|
const handleBackPress = () => {
|
||||||
window.history.back()
|
router.back()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter folders based on search query
|
// 根据搜索关键词过滤文件夹
|
||||||
|
// 将文件夹名称转换为小写进行模糊匹配
|
||||||
const filteredFolders = computed(() => {
|
const filteredFolders = computed(() => {
|
||||||
return foldersWithAllNotes.value.filter(folder => folder.name.toLowerCase().includes(searchQuery.value.toLowerCase()))
|
return foldersWithAllNotes.value.filter(folder => folder.name.toLowerCase().includes(searchQuery.value.toLowerCase()))
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, nextTick, watch } from 'vue'
|
import { ref, computed, onMounted, nextTick, watch } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
import { useAppStore } from '../stores/useAppStore'
|
import { useAppStore } from '../stores/useAppStore'
|
||||||
import Header from '../components/Header.vue'
|
import Header from '../components/Header.vue'
|
||||||
import RichTextEditor from '../components/RichTextEditor.vue'
|
import RichTextEditor from '../components/RichTextEditor.vue'
|
||||||
@@ -53,31 +54,35 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 为了保持向后兼容性,我们也支持noteId属性
|
// 为了保持向后兼容性,我们也支持noteId属性
|
||||||
|
// 通过计算属性确保无论使用id还是noteId都能正确获取便签ID
|
||||||
const noteId = computed(() => props.id || props.noteId)
|
const noteId = computed(() => props.id || props.noteId)
|
||||||
|
|
||||||
const store = useAppStore()
|
const store = useAppStore()
|
||||||
|
const router = useRouter()
|
||||||
const editorRef = ref(null)
|
const editorRef = ref(null)
|
||||||
|
|
||||||
// 设置便签内容的函数
|
// 设置便签内容的函数
|
||||||
|
// 用于在编辑器中加载指定便签的内容
|
||||||
const setNoteContent = async (noteId) => {
|
const setNoteContent = async (noteId) => {
|
||||||
// 确保store数据已加载
|
// 确保store数据已加载,如果便签列表为空则先加载数据
|
||||||
if (store.notes.length === 0) {
|
if (store.notes.length === 0) {
|
||||||
await store.loadData()
|
await store.loadData()
|
||||||
console.log('Store loaded, notes count:', store.notes.length)
|
console.log('Store loaded, notes count:', store.notes.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从store中查找指定ID的便签
|
||||||
const note = store.notes.find(n => n.id === noteId)
|
const note = store.notes.find(n => n.id === noteId)
|
||||||
console.log('Found note:', note)
|
console.log('Found note:', note)
|
||||||
|
|
||||||
// 确保编辑器已经初始化
|
// 确保编辑器已经初始化完成
|
||||||
await nextTick()
|
await nextTick()
|
||||||
console.log('Editor ref:', editorRef.value)
|
console.log('Editor ref:', editorRef.value)
|
||||||
|
|
||||||
if (note) {
|
if (note) {
|
||||||
console.log('Setting content:', note.content)
|
console.log('Setting content:', note.content)
|
||||||
// 无论editorRef是否可用,都先设置content的值
|
// 无论editorRef是否可用,都先设置content的值作为备份
|
||||||
content.value = note.content || ''
|
content.value = note.content || ''
|
||||||
// 如果editorRef可用,直接设置内容
|
// 如果editorRef可用,直接设置编辑器内容
|
||||||
if (editorRef.value) {
|
if (editorRef.value) {
|
||||||
editorRef.value.setContent(note.content || '')
|
editorRef.value.setContent(note.content || '')
|
||||||
}
|
}
|
||||||
@@ -113,11 +118,12 @@ watch(() => store.notes, async (newNotes) => {
|
|||||||
}
|
}
|
||||||
}, { immediate: true })
|
}, { immediate: true })
|
||||||
|
|
||||||
// Check if we're editing an existing note
|
// 检查是否正在编辑现有便签
|
||||||
|
// 如果noteId存在则表示是编辑模式,否则是新建模式
|
||||||
const isEditing = !!noteId.value
|
const isEditing = !!noteId.value
|
||||||
const existingNote = isEditing ? store.notes.find(n => n.id === noteId.value) : null
|
const existingNote = isEditing ? store.notes.find(n => n.id === noteId.value) : null
|
||||||
|
|
||||||
// Initialize state with existing note data or empty strings
|
// 初始化内容状态,如果是编辑现有便签则使用便签内容,否则为空字符串
|
||||||
const content = ref(existingNote?.content || '')
|
const content = ref(existingNote?.content || '')
|
||||||
|
|
||||||
// 当组件挂载时,确保编辑器初始化为空内容(针对新建便签)
|
// 当组件挂载时,确保编辑器初始化为空内容(针对新建便签)
|
||||||
@@ -137,6 +143,7 @@ watch(() => store.notes, async (newNotes) => {
|
|||||||
const showAlert = ref(false)
|
const showAlert = ref(false)
|
||||||
|
|
||||||
// 防抖函数
|
// 防抖函数
|
||||||
|
// 用于避免函数在短时间内被频繁调用,提高性能
|
||||||
const debounce = (func, delay) => {
|
const debounce = (func, delay) => {
|
||||||
let timeoutId
|
let timeoutId
|
||||||
return function (...args) {
|
return function (...args) {
|
||||||
@@ -146,18 +153,21 @@ const debounce = (func, delay) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 防抖处理内容变化
|
// 防抖处理内容变化
|
||||||
|
// 延迟300ms更新内容,避免用户输入时频繁触发更新
|
||||||
const debouncedHandleContentChange = debounce((newContent) => {
|
const debouncedHandleContentChange = debounce((newContent) => {
|
||||||
content.value = newContent
|
content.value = newContent
|
||||||
console.log('Content updated:', newContent)
|
console.log('Content updated:', newContent)
|
||||||
}, 300)
|
}, 300)
|
||||||
|
|
||||||
// 监听编辑器内容变化
|
// 监听编辑器内容变化
|
||||||
|
// 当编辑器内容发生变化时调用此函数
|
||||||
const handleContentChange = (newContent) => {
|
const handleContentChange = (newContent) => {
|
||||||
console.log('Editor content changed:', newContent)
|
console.log('Editor content changed:', newContent)
|
||||||
debouncedHandleContentChange(newContent)
|
debouncedHandleContentChange(newContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算属性
|
// 计算属性 - 格式化时间显示
|
||||||
|
// 如果是编辑现有便签则显示便签的更新时间,否则显示当前时间
|
||||||
const formattedTime = computed(() => {
|
const formattedTime = computed(() => {
|
||||||
if (existingNote?.updatedAt) {
|
if (existingNote?.updatedAt) {
|
||||||
return formatNoteEditorDate(existingNote.updatedAt)
|
return formatNoteEditorDate(existingNote.updatedAt)
|
||||||
@@ -165,8 +175,10 @@ const formattedTime = computed(() => {
|
|||||||
return formatNoteEditorDate(new Date())
|
return formatNoteEditorDate(new Date())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 计算属性 - 计算字数
|
||||||
|
// 移除HTML标签后计算纯文本字数
|
||||||
const wordCount = computed(() => {
|
const wordCount = computed(() => {
|
||||||
// 移除HTML标签计算字数
|
// 使用正则表达式移除HTML标签,只保留纯文本内容
|
||||||
const textContent = content.value.replace(/<[^>]*>/g, '')
|
const textContent = content.value.replace(/<[^>]*>/g, '')
|
||||||
return textContent.length || 0
|
return textContent.length || 0
|
||||||
})
|
})
|
||||||
@@ -191,7 +203,7 @@ const handleSave = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Navigate back to the previous screen
|
// Navigate back to the previous screen
|
||||||
window.location.hash = '#/notes'
|
router.push('/notes')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// In a full implementation, show an alert or toast
|
// In a full implementation, show an alert or toast
|
||||||
console.log('Save error: Failed to save note. Please try again.')
|
console.log('Save error: Failed to save note. Please try again.')
|
||||||
@@ -206,7 +218,7 @@ const handleCancel = () => {
|
|||||||
if (hasUnsavedChanges) {
|
if (hasUnsavedChanges) {
|
||||||
showAlert.value = true
|
showAlert.value = true
|
||||||
} else {
|
} else {
|
||||||
window.location.hash = '#/notes'
|
router.push('/notes')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +235,7 @@ const handleCreate = async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Navigate back to the previous screen
|
// Navigate back to the previous screen
|
||||||
window.location.hash = '#/notes'
|
router.push('/notes')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// In a full implementation, show an alert or toast
|
// In a full implementation, show an alert or toast
|
||||||
console.log('Create error: Failed to create note. Please try again.')
|
console.log('Create error: Failed to create note. Please try again.')
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<ion-app>
|
<ion-app>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<Header :title="headerTitle" :onAction="handleHeaderAction" actionIcon="create" leftType="settings" :onLeftAction="handleSettingsPress" :onFolderToggle="handleFolderToggle" :isFolderExpanded="isFolderExpanded" :onTitlePress="handleFolderToggle" />
|
<Header
|
||||||
|
:title="headerTitle"
|
||||||
|
:onAction="handleHeaderAction"
|
||||||
|
actionIcon="create"
|
||||||
|
leftType="settings"
|
||||||
|
:onLeftAction="handleSettingsPress"
|
||||||
|
:onFolderToggle="handleFolderToggle"
|
||||||
|
:isFolderExpanded="isFolderExpanded"
|
||||||
|
:onTitlePress="handleFolderToggle" />
|
||||||
|
|
||||||
<!-- 悬浮文件夹列表 - 使用绝对定位实现 -->
|
<!-- 悬浮文件夹列表 - 使用绝对定位实现 -->
|
||||||
<div
|
<div v-if="isFolderExpanded" class="folder-list">
|
||||||
v-if="isFolderExpanded"
|
|
||||||
class="folder-list">
|
|
||||||
<FolderManage
|
<FolderManage
|
||||||
:allCount="allNotesCount"
|
:allCount="allNotesCount"
|
||||||
:starredCount="starredNotesCount"
|
:starredCount="starredNotesCount"
|
||||||
@@ -60,6 +66,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
import { useAppStore } from '../stores/useAppStore'
|
import { useAppStore } from '../stores/useAppStore'
|
||||||
import NoteItem from '../components/NoteItem.vue'
|
import NoteItem from '../components/NoteItem.vue'
|
||||||
import Header from '../components/Header.vue'
|
import Header from '../components/Header.vue'
|
||||||
@@ -68,22 +75,25 @@ import SearchBar from '../components/SearchBar.vue'
|
|||||||
import { formatNoteListDate } from '../utils/dateUtils'
|
import { formatNoteListDate } from '../utils/dateUtils'
|
||||||
|
|
||||||
const store = useAppStore()
|
const store = useAppStore()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
// 加载初始数据
|
// 页面挂载时加载初始数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 检查URL参数是否包含mock数据加载指令
|
// 检查URL参数是否包含mock数据加载指令,用于开发和演示
|
||||||
const urlParams = new URLSearchParams(window.location.search)
|
const urlParams = new URLSearchParams(window.location.search)
|
||||||
if (urlParams.get('mock') === 'true') {
|
if (urlParams.get('mock') === 'true') {
|
||||||
|
// 加载预设的模拟数据
|
||||||
store.loadMockData()
|
store.loadMockData()
|
||||||
} else {
|
} else {
|
||||||
|
// 从localStorage加载用户数据
|
||||||
store.loadData()
|
store.loadData()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const searchQuery = ref('')
|
const searchQuery = ref('')
|
||||||
const sortBy = ref('date') // 'date', 'title', 'starred'
|
const sortBy = ref('date') // 排序方式:'date'(按日期)、'title'(按标题)、'starred'(按星标)
|
||||||
const isFolderExpanded = ref(false)
|
const isFolderExpanded = ref(false) // 文件夹列表是否展开
|
||||||
const currentFolder = ref('all') // 默认文件夹是"全部便签"
|
const currentFolder = ref('all') // 当前选中的文件夹,默认是"全部便签"
|
||||||
const showAlert = ref(false)
|
const showAlert = ref(false)
|
||||||
const noteToDelete = ref(null)
|
const noteToDelete = ref(null)
|
||||||
|
|
||||||
@@ -101,13 +111,11 @@ const trashNotesCount = computed(() => {
|
|||||||
const filteredNotes = computed(() => {
|
const filteredNotes = computed(() => {
|
||||||
// 预处理搜索查询,提高性能
|
// 预处理搜索查询,提高性能
|
||||||
const lowerCaseQuery = searchQuery.value.toLowerCase().trim()
|
const lowerCaseQuery = searchQuery.value.toLowerCase().trim()
|
||||||
|
|
||||||
return store.notes.filter(note => {
|
return store.notes.filter(note => {
|
||||||
// 先检查搜索条件
|
// 先检查搜索条件
|
||||||
const matchesSearch = !lowerCaseQuery ||
|
const matchesSearch = !lowerCaseQuery || note.title.toLowerCase().includes(lowerCaseQuery) || note.content.toLowerCase().includes(lowerCaseQuery)
|
||||||
note.title.toLowerCase().includes(lowerCaseQuery) ||
|
|
||||||
note.content.toLowerCase().includes(lowerCaseQuery)
|
|
||||||
|
|
||||||
if (!matchesSearch) return false
|
if (!matchesSearch) return false
|
||||||
|
|
||||||
// 再检查文件夹条件
|
// 再检查文件夹条件
|
||||||
@@ -128,7 +136,9 @@ const filteredNotes = computed(() => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Filter and sort notes
|
// 过滤并排序便签列表
|
||||||
|
// 首先按置顶状态排序,置顶的便签排在前面
|
||||||
|
// 然后根据sortBy的值进行二次排序
|
||||||
const filteredAndSortedNotes = computed(() => {
|
const filteredAndSortedNotes = computed(() => {
|
||||||
return [...filteredNotes.value].sort((a, b) => {
|
return [...filteredNotes.value].sort((a, b) => {
|
||||||
// 置顶的便签排在前面
|
// 置顶的便签排在前面
|
||||||
@@ -138,9 +148,10 @@ const filteredAndSortedNotes = computed(() => {
|
|||||||
// 根据排序方式排序
|
// 根据排序方式排序
|
||||||
switch (sortBy.value) {
|
switch (sortBy.value) {
|
||||||
case 'title':
|
case 'title':
|
||||||
|
// 按标题字母顺序排序
|
||||||
return a.title.localeCompare(b.title)
|
return a.title.localeCompare(b.title)
|
||||||
case 'starred':
|
case 'starred':
|
||||||
// 加星的便签排在前面
|
// 按星标状态排序,加星的便签排在前面
|
||||||
return (b.isStarred ? 1 : 0) - (a.isStarred ? 1 : 0)
|
return (b.isStarred ? 1 : 0) - (a.isStarred ? 1 : 0)
|
||||||
case 'date':
|
case 'date':
|
||||||
default:
|
default:
|
||||||
@@ -170,17 +181,17 @@ const allNotesCount = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const handleNotePress = noteId => {
|
const handleNotePress = noteId => {
|
||||||
// 导航到编辑页面的逻辑将在路由中处理
|
// 使用vue-router导航到编辑页面
|
||||||
window.location.hash = `#/editor/${noteId}`
|
router.push(`/editor/${noteId}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAddNote = () => {
|
const handleAddNote = () => {
|
||||||
// 导航到编辑页面的逻辑将在路由中处理
|
// 使用vue-router导航到新建便签页面
|
||||||
window.location.hash = '#/editor'
|
router.push('/editor')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理Header组件的操作按钮点击事件
|
// 处理Header组件的操作按钮点击事件
|
||||||
const handleHeaderAction = (actionType) => {
|
const handleHeaderAction = actionType => {
|
||||||
if (actionType === 'create') {
|
if (actionType === 'create') {
|
||||||
handleAddNote()
|
handleAddNote()
|
||||||
}
|
}
|
||||||
@@ -236,13 +247,14 @@ const confirmDeleteNote = async () => {
|
|||||||
showAlert.value = false
|
showAlert.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理排序方式切换
|
||||||
|
// 循环切换排序选项:按日期 -> 按标题 -> 按星标 -> 按日期...
|
||||||
const handleSort = () => {
|
const handleSort = () => {
|
||||||
// In a full implementation, this would cycle through sort options
|
|
||||||
const sortOptions = ['date', 'title', 'starred']
|
const sortOptions = ['date', 'title', 'starred']
|
||||||
const currentIndex = sortOptions.indexOf(sortBy.value)
|
const currentIndex = sortOptions.indexOf(sortBy.value)
|
||||||
const nextIndex = (currentIndex + 1) % sortOptions.length
|
const nextIndex = (currentIndex + 1) % sortOptions.length
|
||||||
sortBy.value = sortOptions[nextIndex]
|
sortBy.value = sortOptions[nextIndex]
|
||||||
console.log('Sort by:', sortOptions[nextIndex])
|
console.log('当前排序方式:', sortOptions[nextIndex])
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAllNotesClick = () => {
|
const handleAllNotesClick = () => {
|
||||||
@@ -261,13 +273,13 @@ const handleTrashNotesClick = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleFolderPress = () => {
|
const handleFolderPress = () => {
|
||||||
// 导航到文件夹页面的逻辑将在路由中处理
|
// 使用vue-router导航到文件夹页面
|
||||||
window.location.hash = '#/folders'
|
router.push('/folders')
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSettingsPress = () => {
|
const handleSettingsPress = () => {
|
||||||
// 导航到设置页面的逻辑将在路由中处理
|
// 使用vue-router导航到设置页面
|
||||||
window.location.hash = '#/settings'
|
router.push('/settings')
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleFolderToggle = () => {
|
const handleFolderToggle = () => {
|
||||||
@@ -278,7 +290,7 @@ const handleFolderToggle = () => {
|
|||||||
const handleSearch = query => {
|
const handleSearch = query => {
|
||||||
// 搜索功能已在computed属性filteredAndSortedNotes中实现
|
// 搜索功能已在computed属性filteredAndSortedNotes中实现
|
||||||
console.log('Search for:', query)
|
console.log('Search for:', query)
|
||||||
|
|
||||||
// 可以在这里添加搜索统计或其它功能
|
// 可以在这里添加搜索统计或其它功能
|
||||||
if (query && query.length > 0) {
|
if (query && query.length > 0) {
|
||||||
console.log(`Found ${filteredAndSortedNotes.value.length} matching notes`)
|
console.log(`Found ${filteredAndSortedNotes.value.length} matching notes`)
|
||||||
@@ -288,7 +300,7 @@ const handleSearch = query => {
|
|||||||
const handleClearSearch = () => {
|
const handleClearSearch = () => {
|
||||||
// 清除搜索已在v-model中处理
|
// 清除搜索已在v-model中处理
|
||||||
console.log('Search cleared')
|
console.log('Search cleared')
|
||||||
|
|
||||||
// 清除搜索后可以重置一些状态
|
// 清除搜索后可以重置一些状态
|
||||||
setSearchQuery('')
|
setSearchQuery('')
|
||||||
}
|
}
|
||||||
@@ -303,7 +315,8 @@ const handleSearchBlur = () => {
|
|||||||
// 可以在这里添加失去焦点时的特殊处理
|
// 可以在这里添加失去焦点时的特殊处理
|
||||||
}
|
}
|
||||||
|
|
||||||
// 防抖搜索函数,避免频繁触发搜索
|
// 防抖函数,用于避免频繁触发搜索
|
||||||
|
// 通过延迟执行函数,只在最后一次调用后执行
|
||||||
const debounceSearch = (func, delay) => {
|
const debounceSearch = (func, delay) => {
|
||||||
let timeoutId
|
let timeoutId
|
||||||
return function (...args) {
|
return function (...args) {
|
||||||
@@ -312,8 +325,8 @@ const debounceSearch = (func, delay) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 防抖搜索处理
|
// 防抖搜索处理函数,延迟300ms执行搜索
|
||||||
const debouncedHandleSearch = debounceSearch((query) => {
|
const debouncedHandleSearch = debounceSearch(query => {
|
||||||
handleSearch(query)
|
handleSearch(query)
|
||||||
}, 300)
|
}, 300)
|
||||||
|
|
||||||
@@ -382,4 +395,4 @@ const notes = computed(() => store.notes)
|
|||||||
.note-item {
|
.note-item {
|
||||||
margin: 0.4rem 0;
|
margin: 0.4rem 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -81,61 +81,75 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onMounted } from 'vue';
|
import { computed, onMounted } from 'vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
import { useAppStore } from '../stores/useAppStore';
|
import { useAppStore } from '../stores/useAppStore';
|
||||||
import Header from '../components/Header.vue';
|
import Header from '../components/Header.vue';
|
||||||
|
|
||||||
const store = useAppStore();
|
const store = useAppStore();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
// 加载初始数据
|
// 页面挂载时加载初始数据
|
||||||
|
// 从localStorage加载用户设置和便签数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
store.loadData();
|
store.loadData();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 切换云同步设置
|
||||||
|
// 调用store中的方法更新云同步状态
|
||||||
const toggleCloudSync = () => {
|
const toggleCloudSync = () => {
|
||||||
store.toggleCloudSync();
|
store.toggleCloudSync();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 切换深色模式设置
|
||||||
|
// 调用store中的方法更新深色模式状态
|
||||||
const toggleDarkMode = () => {
|
const toggleDarkMode = () => {
|
||||||
store.toggleDarkMode();
|
store.toggleDarkMode();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理登录云同步按钮点击事件
|
||||||
|
// 在完整实现中,这里会打开登录界面
|
||||||
const handleLogin = () => {
|
const handleLogin = () => {
|
||||||
// In a full implementation, this would open a login screen
|
|
||||||
console.log('Login to cloud');
|
console.log('Login to cloud');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理隐私政策按钮点击事件
|
||||||
|
// 在完整实现中,这里会显示隐私政策内容
|
||||||
const handlePrivacyPolicy = () => {
|
const handlePrivacyPolicy = () => {
|
||||||
// In a full implementation, this would show the privacy policy
|
|
||||||
console.log('Privacy policy');
|
console.log('Privacy policy');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理服务条款按钮点击事件
|
||||||
|
// 在完整实现中,这里会显示服务条款内容
|
||||||
const handleTermsOfService = () => {
|
const handleTermsOfService = () => {
|
||||||
// In a full implementation, this would show the terms of service
|
|
||||||
console.log('Terms of service');
|
console.log('Terms of service');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理备份便签按钮点击事件
|
||||||
|
// 在完整实现中,这里会执行便签备份操作
|
||||||
const handleBackup = () => {
|
const handleBackup = () => {
|
||||||
// In a full implementation, this would backup notes
|
|
||||||
console.log('Backup notes');
|
console.log('Backup notes');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理恢复便签按钮点击事件
|
||||||
|
// 在完整实现中,这里会执行便签恢复操作
|
||||||
const handleRestore = () => {
|
const handleRestore = () => {
|
||||||
// In a full implementation, this would restore notes
|
|
||||||
console.log('Restore notes');
|
console.log('Restore notes');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理导出便签按钮点击事件
|
||||||
|
// 在完整实现中,这里会执行便签导出操作
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
// In a full implementation, this would export notes
|
|
||||||
console.log('Export notes');
|
console.log('Export notes');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理导入便签按钮点击事件
|
||||||
|
// 在完整实现中,这里会执行便签导入操作
|
||||||
const handleImport = () => {
|
const handleImport = () => {
|
||||||
// In a full implementation, this would import notes
|
|
||||||
console.log('Import notes');
|
console.log('Import notes');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBackPress = () => {
|
const handleBackPress = () => {
|
||||||
window.history.back();
|
router.back();
|
||||||
};
|
};
|
||||||
|
|
||||||
const settings = computed(() => store.settings);
|
const settings = computed(() => store.settings);
|
||||||
|
|||||||
@@ -2,27 +2,59 @@ import { defineStore } from 'pinia'
|
|||||||
import * as storage from '../utils/storage'
|
import * as storage from '../utils/storage'
|
||||||
import { getCurrentDateTime, getPastDate } from '../utils/dateUtils'
|
import { getCurrentDateTime, getPastDate } from '../utils/dateUtils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用状态管理Store
|
||||||
|
* 使用Pinia进行状态管理,包含便签、文件夹和设置数据
|
||||||
|
*/
|
||||||
export const useAppStore = defineStore('app', {
|
export const useAppStore = defineStore('app', {
|
||||||
|
/**
|
||||||
|
* 状态定义
|
||||||
|
* 包含应用的核心数据:便签列表、文件夹列表和设置
|
||||||
|
*/
|
||||||
state: () => ({
|
state: () => ({
|
||||||
notes: [],
|
notes: [], // 便签列表
|
||||||
folders: [],
|
folders: [], // 文件夹列表
|
||||||
settings: { cloudSync: false, darkMode: false },
|
settings: { cloudSync: false, darkMode: false }, // 应用设置
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算属性
|
||||||
|
* 基于状态派生的计算值
|
||||||
|
*/
|
||||||
getters: {
|
getters: {
|
||||||
|
/**
|
||||||
|
* 计算加星便签数量
|
||||||
|
* @param {Object} state - 当前状态对象
|
||||||
|
* @returns {number} 加星便签的数量
|
||||||
|
*/
|
||||||
starredNotesCount: state => {
|
starredNotesCount: state => {
|
||||||
return state.notes.filter(note => note.isStarred).length
|
return state.notes.filter(note => note.isStarred).length
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算所有便签数量
|
||||||
|
* @param {Object} state - 当前状态对象
|
||||||
|
* @returns {number} 所有便签的数量
|
||||||
|
*/
|
||||||
allNotesCount: state => {
|
allNotesCount: state => {
|
||||||
return state.notes.length
|
return state.notes.length
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态变更操作
|
||||||
|
* 包含所有修改状态的方法
|
||||||
|
*/
|
||||||
actions: {
|
actions: {
|
||||||
// 初始化数据
|
/**
|
||||||
|
* 初始化数据
|
||||||
|
* 从localStorage加载便签、文件夹和设置数据
|
||||||
|
* 如果没有数据则加载预设的mock数据
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async loadData() {
|
async loadData() {
|
||||||
try {
|
try {
|
||||||
|
// 从localStorage加载数据
|
||||||
const loadedNotes = await storage.getNotes()
|
const loadedNotes = await storage.getNotes()
|
||||||
const loadedFolders = await storage.getFolders()
|
const loadedFolders = await storage.getFolders()
|
||||||
const loadedSettings = await storage.getSettings()
|
const loadedSettings = await storage.getSettings()
|
||||||
@@ -31,6 +63,7 @@ export const useAppStore = defineStore('app', {
|
|||||||
if (loadedNotes.length === 0 && loadedFolders.length === 0) {
|
if (loadedNotes.length === 0 && loadedFolders.length === 0) {
|
||||||
this.loadMockData()
|
this.loadMockData()
|
||||||
} else {
|
} else {
|
||||||
|
// 否则使用加载的数据
|
||||||
this.notes = loadedNotes
|
this.notes = loadedNotes
|
||||||
this.folders = loadedFolders
|
this.folders = loadedFolders
|
||||||
this.settings = loadedSettings
|
this.settings = loadedSettings
|
||||||
@@ -40,7 +73,11 @@ export const useAppStore = defineStore('app', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 加载mock数据
|
/**
|
||||||
|
* 加载预设的mock数据
|
||||||
|
* 用于开发和演示目的,提供示例便签、文件夹和设置
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async loadMockData() {
|
async loadMockData() {
|
||||||
// Mock notes - 使用固定的日期值以避免每次运行时变化
|
// Mock notes - 使用固定的日期值以避免每次运行时变化
|
||||||
const fixedCurrentDate = '2025-10-12T10:00:00.000Z';
|
const fixedCurrentDate = '2025-10-12T10:00:00.000Z';
|
||||||
@@ -50,6 +87,7 @@ export const useAppStore = defineStore('app', {
|
|||||||
const fixedFourDaysAgo = '2025-10-08T10:00:00.000Z';
|
const fixedFourDaysAgo = '2025-10-08T10:00:00.000Z';
|
||||||
const fixedFiveDaysAgo = '2025-10-07T10:00:00.000Z';
|
const fixedFiveDaysAgo = '2025-10-07T10:00:00.000Z';
|
||||||
|
|
||||||
|
// 预设的便签示例数据
|
||||||
const mockNotes = [
|
const mockNotes = [
|
||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
@@ -58,10 +96,10 @@ export const useAppStore = defineStore('app', {
|
|||||||
createdAt: fixedCurrentDate,
|
createdAt: fixedCurrentDate,
|
||||||
updatedAt: fixedCurrentDate,
|
updatedAt: fixedCurrentDate,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
isStarred: true,
|
isStarred: true, // 加星便签
|
||||||
isTop: true,
|
isTop: true, // 置顶便签
|
||||||
hasImage: false,
|
hasImage: false, // 不包含图片
|
||||||
isDeleted: false,
|
isDeleted: false, // 未删除
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -71,10 +109,10 @@ export const useAppStore = defineStore('app', {
|
|||||||
createdAt: fixedYesterday,
|
createdAt: fixedYesterday,
|
||||||
updatedAt: fixedYesterday,
|
updatedAt: fixedYesterday,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
isStarred: true,
|
isStarred: true, // 加星便签
|
||||||
isTop: false,
|
isTop: false, // 非置顶
|
||||||
hasImage: true,
|
hasImage: true, // 包含图片
|
||||||
isDeleted: false,
|
isDeleted: false, // 未删除
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -84,10 +122,10 @@ export const useAppStore = defineStore('app', {
|
|||||||
createdAt: fixedTwoDaysAgo,
|
createdAt: fixedTwoDaysAgo,
|
||||||
updatedAt: fixedTwoDaysAgo,
|
updatedAt: fixedTwoDaysAgo,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
isStarred: false,
|
isStarred: false, // 非加星
|
||||||
isTop: false,
|
isTop: false, // 非置顶
|
||||||
hasImage: false,
|
hasImage: false, // 不包含图片
|
||||||
isDeleted: false,
|
isDeleted: false, // 未删除
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -97,10 +135,10 @@ export const useAppStore = defineStore('app', {
|
|||||||
createdAt: fixedThreeDaysAgo,
|
createdAt: fixedThreeDaysAgo,
|
||||||
updatedAt: fixedThreeDaysAgo,
|
updatedAt: fixedThreeDaysAgo,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
isStarred: false,
|
isStarred: false, // 非加星
|
||||||
isTop: false,
|
isTop: false, // 非置顶
|
||||||
hasImage: false,
|
hasImage: false, // 不包含图片
|
||||||
isDeleted: false,
|
isDeleted: false, // 未删除
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -110,10 +148,10 @@ export const useAppStore = defineStore('app', {
|
|||||||
createdAt: fixedFourDaysAgo,
|
createdAt: fixedFourDaysAgo,
|
||||||
updatedAt: fixedFourDaysAgo,
|
updatedAt: fixedFourDaysAgo,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
isStarred: false,
|
isStarred: false, // 非加星
|
||||||
isTop: false,
|
isTop: false, // 非置顶
|
||||||
hasImage: false,
|
hasImage: false, // 不包含图片
|
||||||
isDeleted: false,
|
isDeleted: false, // 未删除
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -123,15 +161,16 @@ export const useAppStore = defineStore('app', {
|
|||||||
createdAt: fixedFiveDaysAgo,
|
createdAt: fixedFiveDaysAgo,
|
||||||
updatedAt: fixedFiveDaysAgo,
|
updatedAt: fixedFiveDaysAgo,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
isStarred: false,
|
isStarred: false, // 非加星
|
||||||
isTop: false,
|
isTop: false, // 非置顶
|
||||||
hasImage: false,
|
hasImage: false, // 不包含图片
|
||||||
isDeleted: true,
|
isDeleted: true, // 已删除
|
||||||
deletedAt: fixedYesterday,
|
deletedAt: fixedYesterday,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
// Mock folders - 使用固定的日期值
|
// Mock folders - 使用固定的日期值
|
||||||
|
// 预设的文件夹示例数据
|
||||||
const mockFolders = [
|
const mockFolders = [
|
||||||
{
|
{
|
||||||
id: 'folder1',
|
id: 'folder1',
|
||||||
@@ -151,11 +190,13 @@ export const useAppStore = defineStore('app', {
|
|||||||
]
|
]
|
||||||
|
|
||||||
// Mock settings
|
// Mock settings
|
||||||
|
// 预设的设置示例数据
|
||||||
const mockSettings = {
|
const mockSettings = {
|
||||||
cloudSync: false,
|
cloudSync: false, // 云同步关闭
|
||||||
darkMode: false,
|
darkMode: false, // 深色模式关闭
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新store状态
|
||||||
this.notes = mockNotes
|
this.notes = mockNotes
|
||||||
this.folders = mockFolders
|
this.folders = mockFolders
|
||||||
this.settings = mockSettings
|
this.settings = mockSettings
|
||||||
@@ -166,7 +207,10 @@ export const useAppStore = defineStore('app', {
|
|||||||
await storage.saveSettings(mockSettings)
|
await storage.saveSettings(mockSettings)
|
||||||
},
|
},
|
||||||
|
|
||||||
// 保存notes到localStorage
|
/**
|
||||||
|
* 保存便签数据到localStorage
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async saveNotes() {
|
async saveNotes() {
|
||||||
try {
|
try {
|
||||||
await storage.saveNotes(this.notes)
|
await storage.saveNotes(this.notes)
|
||||||
@@ -175,7 +219,10 @@ export const useAppStore = defineStore('app', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 保存folders到localStorage
|
/**
|
||||||
|
* 保存文件夹数据到localStorage
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async saveFolders() {
|
async saveFolders() {
|
||||||
try {
|
try {
|
||||||
await storage.saveFolders(this.folders)
|
await storage.saveFolders(this.folders)
|
||||||
@@ -184,7 +231,10 @@ export const useAppStore = defineStore('app', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 保存settings到localStorage
|
/**
|
||||||
|
* 保存设置数据到localStorage
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
try {
|
try {
|
||||||
await storage.saveSettings(this.settings)
|
await storage.saveSettings(this.settings)
|
||||||
@@ -193,11 +243,20 @@ export const useAppStore = defineStore('app', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Note functions
|
/**
|
||||||
|
* 便签操作函数
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加新便签
|
||||||
|
* @param {Object} note - 便签对象
|
||||||
|
* @returns {Promise<Object>} 新创建的便签对象
|
||||||
|
*/
|
||||||
async addNote(note) {
|
async addNote(note) {
|
||||||
try {
|
try {
|
||||||
const newNote = await storage.addNote(note)
|
const newNote = await storage.addNote(note)
|
||||||
this.notes.push(newNote)
|
this.notes.push(newNote)
|
||||||
|
|
||||||
return newNote
|
return newNote
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error adding note:', error)
|
console.error('Error adding note:', error)
|
||||||
@@ -205,6 +264,12 @@ export const useAppStore = defineStore('app', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新便签
|
||||||
|
* @param {string} id - 便签ID
|
||||||
|
* @param {Object} updates - 要更新的属性对象
|
||||||
|
* @returns {Promise<Object>} 更新后的便签对象
|
||||||
|
*/
|
||||||
async updateNote(id, updates) {
|
async updateNote(id, updates) {
|
||||||
try {
|
try {
|
||||||
const updatedNote = await storage.updateNote(id, updates)
|
const updatedNote = await storage.updateNote(id, updates)
|
||||||
@@ -221,6 +286,11 @@ export const useAppStore = defineStore('app', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除便签
|
||||||
|
* @param {string} id - 要删除的便签ID
|
||||||
|
* @returns {Promise<boolean>} 删除成功返回true,失败返回false
|
||||||
|
*/
|
||||||
async deleteNote(id) {
|
async deleteNote(id) {
|
||||||
try {
|
try {
|
||||||
const result = await storage.deleteNote(id)
|
const result = await storage.deleteNote(id)
|
||||||
@@ -234,7 +304,12 @@ export const useAppStore = defineStore('app', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 将便签移至回收站
|
/**
|
||||||
|
* 将便签移至回收站
|
||||||
|
* 将便签标记为已删除状态,并记录删除时间
|
||||||
|
* @param {string} id - 便签ID
|
||||||
|
* @returns {Promise<Object>} 更新后的便签对象
|
||||||
|
*/
|
||||||
async moveToTrash(id) {
|
async moveToTrash(id) {
|
||||||
try {
|
try {
|
||||||
const updatedNote = await storage.updateNote(id, { isDeleted: true, deletedAt: getCurrentDateTime() })
|
const updatedNote = await storage.updateNote(id, { isDeleted: true, deletedAt: getCurrentDateTime() })
|
||||||
@@ -251,7 +326,12 @@ export const useAppStore = defineStore('app', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 永久删除便签
|
/**
|
||||||
|
* 永久删除便签
|
||||||
|
* 从便签列表中彻底移除便签
|
||||||
|
* @param {string} id - 便签ID
|
||||||
|
* @returns {Promise<boolean>} 删除成功返回true,失败返回false
|
||||||
|
*/
|
||||||
async permanentlyDeleteNote(id) {
|
async permanentlyDeleteNote(id) {
|
||||||
try {
|
try {
|
||||||
const result = await storage.deleteNote(id)
|
const result = await storage.deleteNote(id)
|
||||||
@@ -265,7 +345,15 @@ export const useAppStore = defineStore('app', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Folder functions
|
/**
|
||||||
|
* 文件夹操作函数
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加新文件夹
|
||||||
|
* @param {Object} folder - 文件夹对象
|
||||||
|
* @returns {Promise<Object>} 新创建的文件夹对象
|
||||||
|
*/
|
||||||
async addFolder(folder) {
|
async addFolder(folder) {
|
||||||
try {
|
try {
|
||||||
const newFolder = await storage.addFolder(folder)
|
const newFolder = await storage.addFolder(folder)
|
||||||
@@ -277,7 +365,15 @@ export const useAppStore = defineStore('app', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Settings functions
|
/**
|
||||||
|
* 设置操作函数
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新设置
|
||||||
|
* @param {Object} newSettings - 新的设置对象
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async updateSettings(newSettings) {
|
async updateSettings(newSettings) {
|
||||||
try {
|
try {
|
||||||
const updatedSettings = { ...this.settings, ...newSettings }
|
const updatedSettings = { ...this.settings, ...newSettings }
|
||||||
@@ -289,12 +385,20 @@ export const useAppStore = defineStore('app', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 切换云同步设置
|
/**
|
||||||
|
* 切换云同步设置
|
||||||
|
* 开启或关闭云同步功能
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async toggleCloudSync() {
|
async toggleCloudSync() {
|
||||||
await this.updateSettings({ cloudSync: !this.settings.cloudSync })
|
await this.updateSettings({ cloudSync: !this.settings.cloudSync })
|
||||||
},
|
},
|
||||||
|
|
||||||
// 切换深色模式设置
|
/**
|
||||||
|
* 切换深色模式设置
|
||||||
|
* 开启或关闭深色模式
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async toggleDarkMode() {
|
async toggleDarkMode() {
|
||||||
await this.updateSettings({ darkMode: !this.settings.darkMode })
|
await this.updateSettings({ darkMode: !this.settings.darkMode })
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
import { getCurrentDateTime, getTimestamp } from './dateUtils'
|
import { getCurrentDateTime, getTimestamp } from './dateUtils'
|
||||||
|
|
||||||
// Storage keys
|
// 本地存储键名常量
|
||||||
const NOTES_KEY = 'notes';
|
// 用于在localStorage中标识不同类型的数据
|
||||||
const FOLDERS_KEY = 'folders';
|
const NOTES_KEY = 'notes'; // 便签数据键名
|
||||||
const SETTINGS_KEY = 'settings';
|
const FOLDERS_KEY = 'folders'; // 文件夹数据键名
|
||||||
|
const SETTINGS_KEY = 'settings'; // 设置数据键名
|
||||||
|
|
||||||
// Notes functions
|
// 便签操作函数
|
||||||
|
// 提供便签的增删改查功能
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有便签数据
|
||||||
|
* 从localStorage中读取便签数据并解析为JavaScript对象
|
||||||
|
* @returns {Promise<Array>} 便签数组,如果读取失败则返回空数组
|
||||||
|
*/
|
||||||
export const getNotes = async () => {
|
export const getNotes = async () => {
|
||||||
try {
|
try {
|
||||||
const notesJson = localStorage.getItem(NOTES_KEY);
|
const notesJson = localStorage.getItem(NOTES_KEY);
|
||||||
@@ -16,6 +24,12 @@ export const getNotes = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存便签数据
|
||||||
|
* 将便签数组转换为JSON字符串并保存到localStorage
|
||||||
|
* @param {Array} notes - 便签数组
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
export const saveNotes = async (notes) => {
|
export const saveNotes = async (notes) => {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(NOTES_KEY, JSON.stringify(notes));
|
localStorage.setItem(NOTES_KEY, JSON.stringify(notes));
|
||||||
@@ -24,19 +38,27 @@ export const saveNotes = async (notes) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加新便签
|
||||||
|
* 创建一个新的便签对象并添加到便签列表中
|
||||||
|
* @param {Object} note - 便签对象,包含便签内容和其他属性
|
||||||
|
* @returns {Promise<Object>} 新创建的便签对象
|
||||||
|
*/
|
||||||
export const addNote = async (note) => {
|
export const addNote = async (note) => {
|
||||||
|
// 创建新的便签对象,添加必要的属性
|
||||||
const newNote = {
|
const newNote = {
|
||||||
...note,
|
...note,
|
||||||
id: getTimestamp().toString(),
|
id: getTimestamp().toString(), // 使用时间戳生成唯一ID
|
||||||
createdAt: getCurrentDateTime(),
|
createdAt: getCurrentDateTime(), // 创建时间
|
||||||
updatedAt: getCurrentDateTime(),
|
updatedAt: getCurrentDateTime(), // 更新时间
|
||||||
isStarred: note.isStarred || false,
|
isStarred: note.isStarred || false, // 是否加星
|
||||||
isTop: note.isTop || false,
|
isTop: note.isTop || false, // 是否置顶
|
||||||
hasImage: note.hasImage || false,
|
hasImage: note.hasImage || false, // 是否包含图片
|
||||||
isDeleted: note.isDeleted || false,
|
isDeleted: note.isDeleted || false, // 是否已删除
|
||||||
deletedAt: note.deletedAt || null
|
deletedAt: note.deletedAt || null // 删除时间
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取现有便签列表,添加新便签并保存
|
||||||
const notes = await getNotes();
|
const notes = await getNotes();
|
||||||
notes.push(newNote);
|
notes.push(newNote);
|
||||||
await saveNotes(notes);
|
await saveNotes(notes);
|
||||||
@@ -44,35 +66,62 @@ export const addNote = async (note) => {
|
|||||||
return newNote;
|
return newNote;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新便签
|
||||||
|
* 根据ID查找并更新便签信息
|
||||||
|
* @param {string} id - 便签ID
|
||||||
|
* @param {Object} updates - 要更新的属性对象
|
||||||
|
* @returns {Promise<Object|null>} 更新后的便签对象,如果未找到则返回null
|
||||||
|
*/
|
||||||
export const updateNote = async (id, updates) => {
|
export const updateNote = async (id, updates) => {
|
||||||
|
// 获取所有便签并查找要更新的便签
|
||||||
const notes = await getNotes();
|
const notes = await getNotes();
|
||||||
const index = notes.findIndex(note => note.id === id);
|
const index = notes.findIndex(note => note.id === id);
|
||||||
|
|
||||||
|
// 如果未找到指定ID的便签,返回null
|
||||||
if (index === -1) return null;
|
if (index === -1) return null;
|
||||||
|
|
||||||
|
// 创建更新后的便签对象
|
||||||
const updatedNote = {
|
const updatedNote = {
|
||||||
...notes[index],
|
...notes[index],
|
||||||
...updates,
|
...updates,
|
||||||
updatedAt: getCurrentDateTime(),
|
updatedAt: getCurrentDateTime(), // 更新最后修改时间
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 更新便签列表并保存
|
||||||
notes[index] = updatedNote;
|
notes[index] = updatedNote;
|
||||||
await saveNotes(notes);
|
await saveNotes(notes);
|
||||||
|
|
||||||
return updatedNote;
|
return updatedNote;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除便签
|
||||||
|
* 根据ID从便签列表中移除便签
|
||||||
|
* @param {string} id - 要删除的便签ID
|
||||||
|
* @returns {Promise<boolean>} 删除成功返回true,未找到便签返回false
|
||||||
|
*/
|
||||||
export const deleteNote = async (id) => {
|
export const deleteNote = async (id) => {
|
||||||
|
// 获取所有便签并过滤掉要删除的便签
|
||||||
const notes = await getNotes();
|
const notes = await getNotes();
|
||||||
const filteredNotes = notes.filter(note => note.id !== id);
|
const filteredNotes = notes.filter(note => note.id !== id);
|
||||||
|
|
||||||
|
// 如果便签数量没有变化,说明未找到要删除的便签
|
||||||
if (notes.length === filteredNotes.length) return false;
|
if (notes.length === filteredNotes.length) return false;
|
||||||
|
|
||||||
|
// 保存更新后的便签列表
|
||||||
await saveNotes(filteredNotes);
|
await saveNotes(filteredNotes);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Folders functions
|
// 文件夹操作函数
|
||||||
|
// 提供文件夹的增删改查功能
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有文件夹数据
|
||||||
|
* 从localStorage中读取文件夹数据并解析为JavaScript对象
|
||||||
|
* @returns {Promise<Array>} 文件夹数组,如果读取失败则返回空数组
|
||||||
|
*/
|
||||||
export const getFolders = async () => {
|
export const getFolders = async () => {
|
||||||
try {
|
try {
|
||||||
const foldersJson = localStorage.getItem(FOLDERS_KEY);
|
const foldersJson = localStorage.getItem(FOLDERS_KEY);
|
||||||
@@ -83,6 +132,12 @@ export const getFolders = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存文件夹数据
|
||||||
|
* 将文件夹数组转换为JSON字符串并保存到localStorage
|
||||||
|
* @param {Array} folders - 文件夹数组
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
export const saveFolders = async (folders) => {
|
export const saveFolders = async (folders) => {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(FOLDERS_KEY, JSON.stringify(folders));
|
localStorage.setItem(FOLDERS_KEY, JSON.stringify(folders));
|
||||||
@@ -91,13 +146,21 @@ export const saveFolders = async (folders) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加新文件夹
|
||||||
|
* 创建一个新的文件夹对象并添加到文件夹列表中
|
||||||
|
* @param {Object} folder - 文件夹对象,包含文件夹名称等属性
|
||||||
|
* @returns {Promise<Object>} 新创建的文件夹对象
|
||||||
|
*/
|
||||||
export const addFolder = async (folder) => {
|
export const addFolder = async (folder) => {
|
||||||
|
// 创建新的文件夹对象,添加必要的属性
|
||||||
const newFolder = {
|
const newFolder = {
|
||||||
...folder,
|
...folder,
|
||||||
id: getTimestamp().toString(),
|
id: getTimestamp().toString(), // 使用时间戳生成唯一ID
|
||||||
createdAt: getCurrentDateTime(),
|
createdAt: getCurrentDateTime(), // 创建时间
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取现有文件夹列表,添加新文件夹并保存
|
||||||
const folders = await getFolders();
|
const folders = await getFolders();
|
||||||
folders.push(newFolder);
|
folders.push(newFolder);
|
||||||
await saveFolders(folders);
|
await saveFolders(folders);
|
||||||
@@ -105,17 +168,32 @@ export const addFolder = async (folder) => {
|
|||||||
return newFolder;
|
return newFolder;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Settings functions
|
// 设置操作函数
|
||||||
|
// 提供应用设置的读取和保存功能
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取应用设置
|
||||||
|
* 从localStorage中读取设置数据并解析为JavaScript对象
|
||||||
|
* @returns {Promise<Object>} 设置对象,如果读取失败则返回默认设置
|
||||||
|
*/
|
||||||
export const getSettings = async () => {
|
export const getSettings = async () => {
|
||||||
try {
|
try {
|
||||||
const settingsJson = localStorage.getItem(SETTINGS_KEY);
|
const settingsJson = localStorage.getItem(SETTINGS_KEY);
|
||||||
|
// 如果没有保存的设置,返回默认设置
|
||||||
return settingsJson ? JSON.parse(settingsJson) : { cloudSync: false, darkMode: false };
|
return settingsJson ? JSON.parse(settingsJson) : { cloudSync: false, darkMode: false };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error getting settings:', error);
|
console.error('Error getting settings:', error);
|
||||||
|
// 出错时返回默认设置
|
||||||
return { cloudSync: false, darkMode: false };
|
return { cloudSync: false, darkMode: false };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存应用设置
|
||||||
|
* 将设置对象转换为JSON字符串并保存到localStorage
|
||||||
|
* @param {Object} settings - 设置对象
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
export const saveSettings = async (settings) => {
|
export const saveSettings = async (settings) => {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
|
localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
|
||||||
|
|||||||
Reference in New Issue
Block a user