feat(评论管理): 添加评论地址字段并改进状态选择方式
在评论管理功能中新增postSlug字段,用于存储评论所属文章的地址 将状态切换按钮改为下拉选择框,提升用户体验 同时调整了相关字体大小和样式
This commit is contained in:
@@ -115,6 +115,7 @@ export function updateComment(data: {
|
||||
name: string;
|
||||
email: string;
|
||||
url?: string | null;
|
||||
postSlug?: string;
|
||||
contentText: string;
|
||||
status?: string;
|
||||
}): Promise<{ message: string }> {
|
||||
@@ -123,6 +124,7 @@ export function updateComment(data: {
|
||||
name: data.name,
|
||||
email: data.email,
|
||||
url: data.url ?? null,
|
||||
postSlug: data.postSlug,
|
||||
content: data.contentText,
|
||||
status: data.status
|
||||
});
|
||||
|
||||
@@ -82,27 +82,15 @@
|
||||
</div>
|
||||
<div class="table-cell table-cell-actions">
|
||||
<div class="table-actions">
|
||||
<button
|
||||
class="table-action"
|
||||
@click="changeStatus(item, 'approved')"
|
||||
:disabled="item.status === 'approved'"
|
||||
<select
|
||||
class="status-select"
|
||||
:value="item.status"
|
||||
@change="handleStatusChange(item, $event)"
|
||||
>
|
||||
通过
|
||||
</button>
|
||||
<button
|
||||
class="table-action"
|
||||
@click="changeStatus(item, 'pending')"
|
||||
:disabled="item.status === 'pending'"
|
||||
>
|
||||
待审
|
||||
</button>
|
||||
<button
|
||||
class="table-action"
|
||||
@click="changeStatus(item, 'rejected')"
|
||||
:disabled="item.status === 'rejected'"
|
||||
>
|
||||
拒绝
|
||||
</button>
|
||||
<option value="approved">通过</option>
|
||||
<option value="pending">待审</option>
|
||||
<option value="rejected">拒绝</option>
|
||||
</select>
|
||||
<button class="table-action" @click="openEdit(item)">编辑</button>
|
||||
<button
|
||||
class="table-action table-action-danger"
|
||||
@@ -204,6 +192,10 @@
|
||||
<label class="form-label">访客网址</label>
|
||||
<input v-model="editForm.url" class="form-input" type="text" />
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label class="form-label">评论地址</label>
|
||||
<input v-model="editForm.postSlug" class="form-input" type="text" />
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label class="form-label">评论内容</label>
|
||||
<textarea
|
||||
@@ -272,6 +264,7 @@ const editForm = ref<{
|
||||
name: string;
|
||||
email: string;
|
||||
url: string;
|
||||
postSlug: string;
|
||||
contentText: string;
|
||||
status: string;
|
||||
} | null>(null);
|
||||
@@ -390,6 +383,15 @@ async function changeStatus(item: CommentItem, status: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleStatusChange(item: CommentItem, event: Event) {
|
||||
const target = event.target as HTMLSelectElement;
|
||||
const status = target.value;
|
||||
if (!status || status === item.status) {
|
||||
return;
|
||||
}
|
||||
changeStatus(item, status);
|
||||
}
|
||||
|
||||
async function removeComment(item: CommentItem) {
|
||||
if (!window.confirm(`确认删除评论 ${item.id} 吗`)) {
|
||||
return;
|
||||
@@ -438,6 +440,7 @@ function openEdit(item: CommentItem) {
|
||||
name: item.name,
|
||||
email: item.email,
|
||||
url: item.url || "",
|
||||
postSlug: item.postSlug || "",
|
||||
contentText: item.contentText,
|
||||
status: item.status,
|
||||
};
|
||||
@@ -457,7 +460,15 @@ async function submitEdit() {
|
||||
return;
|
||||
}
|
||||
const current = editForm.value;
|
||||
if (!current.name.trim() || !current.email.trim() || !current.contentText.trim()) {
|
||||
const trimmedName = current.name.trim();
|
||||
const trimmedEmail = current.email.trim();
|
||||
const trimmedContent = current.contentText.trim();
|
||||
const trimmedUrl = current.url.trim();
|
||||
const trimmedPostSlug = current.postSlug.trim();
|
||||
const commentIndex = comments.value.findIndex((c) => c.id === current.id);
|
||||
const existingComment = commentIndex !== -1 ? comments.value[commentIndex] : null;
|
||||
const newPostSlug = trimmedPostSlug || existingComment?.postSlug || "";
|
||||
if (!trimmedName || !trimmedEmail || !trimmedContent) {
|
||||
error.value = "昵称、邮箱和内容不能为空";
|
||||
return;
|
||||
}
|
||||
@@ -466,20 +477,21 @@ async function submitEdit() {
|
||||
try {
|
||||
await updateComment({
|
||||
id: current.id,
|
||||
name: current.name.trim(),
|
||||
email: current.email.trim(),
|
||||
url: current.url.trim() || null,
|
||||
contentText: current.contentText,
|
||||
name: trimmedName,
|
||||
email: trimmedEmail,
|
||||
url: trimmedUrl || null,
|
||||
postSlug: newPostSlug,
|
||||
contentText: trimmedContent,
|
||||
status: current.status,
|
||||
});
|
||||
const index = comments.value.findIndex((c) => c.id === current.id);
|
||||
if (index !== -1) {
|
||||
comments.value[index] = {
|
||||
...comments.value[index],
|
||||
name: current.name.trim(),
|
||||
email: current.email.trim(),
|
||||
url: current.url.trim() || null,
|
||||
contentText: current.contentText,
|
||||
if (commentIndex !== -1) {
|
||||
comments.value[commentIndex] = {
|
||||
...comments.value[commentIndex],
|
||||
name: trimmedName,
|
||||
email: trimmedEmail,
|
||||
url: trimmedUrl || null,
|
||||
postSlug: newPostSlug,
|
||||
contentText: trimmedContent,
|
||||
status: current.status,
|
||||
};
|
||||
}
|
||||
@@ -707,7 +719,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.cell-path {
|
||||
font-size: 12px;
|
||||
font-size: 13px;
|
||||
color: #2774cb;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -764,6 +776,14 @@ onMounted(() => {
|
||||
background-color: #ffebe9;
|
||||
}
|
||||
|
||||
.status-select {
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d7de;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.table-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
@@ -775,7 +795,7 @@ onMounted(() => {
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d7de;
|
||||
background-color: #ffffff;
|
||||
font-size: 12px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ export const updateComment = async (c: Context<{ Bindings: Bindings }>) => {
|
||||
}
|
||||
|
||||
const existing = await c.env.CWD_DB.prepare(
|
||||
'SELECT id, status FROM Comment WHERE id = ?'
|
||||
'SELECT id, status, post_slug FROM Comment WHERE id = ?'
|
||||
)
|
||||
.bind(id)
|
||||
.first<{ id: number; status: string }>();
|
||||
.first<{ id: number; status: string; post_slug: string }>();
|
||||
|
||||
if (!existing) {
|
||||
return c.json({ message: 'Comment not found' }, 404);
|
||||
@@ -38,6 +38,15 @@ export const updateComment = async (c: Context<{ Bindings: Bindings }>) => {
|
||||
const rawEmail = typeof body.email === 'string' ? body.email : '';
|
||||
const rawUrl = typeof body.url === 'string' ? body.url : '';
|
||||
const rawStatus = typeof body.status === 'string' ? body.status : existing.status;
|
||||
const hasPostSlugField =
|
||||
Object.prototype.hasOwnProperty.call(body, 'postSlug') ||
|
||||
Object.prototype.hasOwnProperty.call(body, 'post_slug');
|
||||
const rawPostSlug =
|
||||
typeof body.postSlug === 'string'
|
||||
? body.postSlug
|
||||
: typeof body.post_slug === 'string'
|
||||
? body.post_slug
|
||||
: '';
|
||||
|
||||
const contentSource =
|
||||
typeof body.content === 'string'
|
||||
@@ -50,6 +59,9 @@ export const updateComment = async (c: Context<{ Bindings: Bindings }>) => {
|
||||
const email = rawEmail.trim();
|
||||
const url = rawUrl.trim() || null;
|
||||
const status = rawStatus.trim();
|
||||
const postSlug = hasPostSlugField
|
||||
? (rawPostSlug.trim() || existing.post_slug)
|
||||
: existing.post_slug;
|
||||
|
||||
if (!name) {
|
||||
return c.json({ message: '昵称不能为空' }, 400);
|
||||
@@ -78,9 +90,9 @@ export const updateComment = async (c: Context<{ Bindings: Bindings }>) => {
|
||||
});
|
||||
|
||||
const { success } = await c.env.CWD_DB.prepare(
|
||||
'UPDATE Comment SET name = ?, email = ?, url = ?, content_text = ?, content_html = ?, status = ? WHERE id = ?'
|
||||
'UPDATE Comment SET name = ?, email = ?, url = ?, content_text = ?, content_html = ?, status = ?, post_slug = ? WHERE id = ?'
|
||||
)
|
||||
.bind(name, email, url, contentText, contentHtml, status, id)
|
||||
.bind(name, email, url, contentText, contentHtml, status, postSlug, id)
|
||||
.run();
|
||||
|
||||
if (!success) {
|
||||
|
||||
Reference in New Issue
Block a user