v1.0.0提交
This commit is contained in:
157
pages/notes.php
Normal file
157
pages/notes.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
/**
|
||||
* PerToolBox Front - 便签本页面
|
||||
*
|
||||
* Copyright (C) 2024 Sea Network Technology Studio
|
||||
* Author: Canglan <admin@sea-studio.top>
|
||||
* License: AGPL v3
|
||||
*/
|
||||
|
||||
require_once '../config.php';
|
||||
include_once '../header.php';
|
||||
include_once '../sidebar.php';
|
||||
?>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="card">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-2xl font-bold">📝 便签本</h1>
|
||||
<button id="addBtn" class="btn btn-primary">+ 新建便签</button>
|
||||
</div>
|
||||
|
||||
<!-- 便签网格 -->
|
||||
<div id="noteGrid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div class="text-center text-gray-400 py-8 col-span-full">加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 添加/编辑模态框 -->
|
||||
<div id="modal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
|
||||
<div class="bg-white rounded-lg w-full max-w-lg p-6">
|
||||
<h3 id="modalTitle" class="text-xl font-bold mb-4">新建便签</h3>
|
||||
<input type="text" id="noteTitle" placeholder="标题" class="form-input mb-3">
|
||||
<textarea id="noteContent" rows="6" placeholder="内容" class="form-input mb-3"></textarea>
|
||||
<input type="text" id="noteTags" placeholder="标签(用逗号分隔)" class="form-input mb-4">
|
||||
<div class="flex gap-2">
|
||||
<button id="modalConfirm" class="btn btn-primary flex-1">保存</button>
|
||||
<button id="modalCancel" class="btn btn-secondary flex-1">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentEditId = null;
|
||||
|
||||
async function loadNotes() {
|
||||
try {
|
||||
const notes = await apiRequest('/notes');
|
||||
renderNotes(notes);
|
||||
} catch (error) {
|
||||
document.getElementById('noteGrid').innerHTML = `<div class="text-center text-red-500 py-8 col-span-full">${error.message}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
function renderNotes(notes) {
|
||||
if (!notes.length) {
|
||||
document.getElementById('noteGrid').innerHTML = '<div class="text-center text-gray-400 py-8 col-span-full">暂无便签,新建一个吧~</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
const html = notes.map(note => `
|
||||
<div class="border rounded-lg p-4 hover:shadow-md transition bg-white">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<h3 class="font-bold text-lg">${escapeHtml(note.title)}</h3>
|
||||
<div class="flex gap-1">
|
||||
<button onclick="editNote(${note.id})" class="text-blue-500 hover:text-blue-700">✏️</button>
|
||||
<button onclick="deleteNote(${note.id})" class="text-red-500 hover:text-red-700">🗑️</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-gray-600 whitespace-pre-wrap text-sm">${escapeHtml(note.content || '').substring(0, 200)}${(note.content || '').length > 200 ? '...' : ''}</p>
|
||||
${note.tags && note.tags.length ? `<div class="mt-2 flex gap-1 flex-wrap">${note.tags.map(t => `<span class="text-xs bg-gray-100 px-2 py-0.5 rounded">${escapeHtml(t)}</span>`).join('')}</div>` : ''}
|
||||
<div class="mt-2 text-xs text-gray-400">${new Date(note.created_at).toLocaleString()}</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
document.getElementById('noteGrid').innerHTML = html;
|
||||
}
|
||||
|
||||
function openModal(editId = null) {
|
||||
currentEditId = editId;
|
||||
const modal = document.getElementById('modal');
|
||||
const title = document.getElementById('modalTitle');
|
||||
|
||||
if (editId) {
|
||||
title.textContent = '编辑便签';
|
||||
apiRequest(`/notes/${editId}`).then(note => {
|
||||
document.getElementById('noteTitle').value = note.title;
|
||||
document.getElementById('noteContent').value = note.content || '';
|
||||
document.getElementById('noteTags').value = (note.tags || []).join(',');
|
||||
});
|
||||
} else {
|
||||
title.textContent = '新建便签';
|
||||
document.getElementById('noteTitle').value = '';
|
||||
document.getElementById('noteContent').value = '';
|
||||
document.getElementById('noteTags').value = '';
|
||||
}
|
||||
modal.classList.remove('hidden');
|
||||
modal.classList.add('flex');
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
const modal = document.getElementById('modal');
|
||||
modal.classList.add('hidden');
|
||||
modal.classList.remove('flex');
|
||||
currentEditId = null;
|
||||
}
|
||||
|
||||
async function saveNote() {
|
||||
const data = {
|
||||
title: document.getElementById('noteTitle').value.trim(),
|
||||
content: document.getElementById('noteContent').value,
|
||||
tags: document.getElementById('noteTags').value.split(',').map(t => t.trim()).filter(t => t)
|
||||
};
|
||||
|
||||
if (!data.title) {
|
||||
showToast('请输入标题', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (currentEditId) {
|
||||
await apiRequest(`/notes/${currentEditId}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
} else {
|
||||
await apiRequest('/notes', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
closeModal();
|
||||
loadNotes();
|
||||
} catch (error) {
|
||||
showToast(error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteNote(id) {
|
||||
if (!confirm('确定删除吗?')) return;
|
||||
try {
|
||||
await apiRequest(`/notes/${id}`, { method: 'DELETE' });
|
||||
loadNotes();
|
||||
} catch (error) {
|
||||
showToast(error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('addBtn').addEventListener('click', () => openModal());
|
||||
document.getElementById('modalConfirm').addEventListener('click', saveNote);
|
||||
document.getElementById('modalCancel').addEventListener('click', closeModal);
|
||||
|
||||
recordUsage('notes');
|
||||
loadNotes();
|
||||
</script>
|
||||
|
||||
<?php include_once '../footer.php'; ?>
|
||||
Reference in New Issue
Block a user