feat: 重构前端项目结构并优化代码

refactor: 迁移前端资源文件至web目录
feat: 新增多种图标资源
style: 统一代码风格和格式化配置
docs: 更新README和文档说明
chore: 更新依赖和配置文件
fix: 修复部分类型定义和枚举
perf: 优化路由和组件加载逻辑
This commit is contained in:
zhangtao
2026-04-29 00:02:09 +08:00
parent 10a35bb4b5
commit eb150bcede
887 changed files with 116514 additions and 33990 deletions
@@ -0,0 +1,111 @@
<template>
<div>
<ElForm class="w-full mx-auto mb-10" @submit.prevent="addComment">
<ElFormItem prop="author" class="mt-5">
<ElInput
v-model="newComment.author"
placeholder="你的名称"
class="block w-full"
clearable
/>
</ElFormItem>
<ElFormItem prop="content">
<ElInput
v-model="newComment.content"
placeholder="简单说两句..."
type="textarea"
:rows="5"
clearable
/>
</ElFormItem>
<ElFormItem>
<div class="flex justify-end w-full">
<ElButton type="primary" @click="addComment">发布</ElButton>
</div>
</ElFormItem>
</ElForm>
<ul>
<div class="pb-5 text-lg font-medium">评论 {{ comments.length }}</div>
<CommentItem
v-for="comment in comments.slice().reverse()"
:key="comment.id"
:comment="comment"
:show-reply-form="showReplyForm"
class="pb-2.5 mb-5 border-b border-g-400"
@toggle-reply="toggleReply"
@add-reply="addReply"
/>
</ul>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import CommentItem from './widget/CommentItem.vue';
import { commentList, Comment } from '@/mock/temp/commentDetail';
const comments = commentList;
const newComment = ref<Partial<Comment>>({
author: '',
content: '',
});
const showReplyForm = ref<number | null>(null);
const addComment = () => {
if (!newComment.value.author?.trim() || !newComment.value.content?.trim()) {
ElMessage.warning('请填写完整的评论信息');
return;
}
comments.value.push({
id: Date.now(),
author: newComment.value.author.trim(),
content: newComment.value.content.trim(),
timestamp: new Date().toISOString(),
replies: [],
});
newComment.value.author = '';
newComment.value.content = '';
ElMessage.success('评论发布成功');
};
const addReply = (commentId: number, replyAuthor: string, replyContent: string) => {
if (!replyAuthor?.trim() || !replyContent?.trim()) {
ElMessage.warning('请填写完整的回复信息');
return;
}
const comment = findComment(comments.value, commentId);
if (comment) {
comment.replies.push({
id: Date.now(),
author: replyAuthor.trim(),
content: replyContent.trim(),
timestamp: new Date().toISOString(),
replies: [],
});
showReplyForm.value = null;
ElMessage.success('回复发布成功');
}
};
const toggleReply = (commentId: number) => {
showReplyForm.value = showReplyForm.value === commentId ? null : commentId;
};
const findComment = (comments: Comment[], commentId: number): Comment | undefined => {
for (const comment of comments) {
if (comment.id === commentId) {
return comment;
}
const found = findComment(comment.replies, commentId);
if (found) {
return found;
}
}
return undefined;
};
</script>
@@ -0,0 +1,121 @@
<template>
<li>
<div>
<div class="flex-c">
<div
class="size-5 mr-2.5 text-xs font-medium text-white rounded-full flex-cc"
:style="{ background: randomColor() }"
>
{{ comment.author.substring(0, 1) }}
</div>
<strong class="block text-sm font-medium">{{ comment.author }}</strong>
</div>
<span class="block mt-2.5 text-sm text-g-700">{{ comment.content }}</span>
<div class="flex-c mt-2.5">
<span class="text-xs text-g-700">{{ formatDate(comment.timestamp) }}</span>
<div
class="ml-5 text-xs text-g-700 c-p select-none hover:text-theme"
@click="toggleReply(comment.id)"
>
回复
</div>
</div>
</div>
<ul v-if="comment.replies.length > 0" class="pl-2.5">
<CommentItem
v-for="reply in comment.replies"
:key="reply.id"
:comment="reply"
:show-reply-form="showReplyForm"
class="mt-5"
@toggle-reply="toggleReply"
@add-reply="addReply"
/>
</ul>
<ElForm v-if="showReplyForm === comment.id" class="mt-4" @submit.prevent="handleSubmit">
<ElFormItem prop="author">
<ElInput v-model="replyAuthor" placeholder="你的名称" clearable />
</ElFormItem>
<ElFormItem prop="content">
<ElInput
v-model="replyContent"
placeholder="你的回复..."
type="textarea"
:rows="3"
clearable
/>
</ElFormItem>
<ElFormItem>
<div class="flex justify-end gap-2 w-full">
<ElButton @click="toggleReply(comment.id)">取消</ElButton>
<ElButton type="primary" @click="handleSubmit">发布</ElButton>
</div>
</ElFormItem>
</ElForm>
</li>
</template>
<script setup lang="ts">
import AppConfig from '@/config';
import { ref } from 'vue';
interface Comment {
id: number;
author: string;
content: string;
timestamp: string;
replies: Comment[];
}
const props = defineProps<{
comment: Comment;
showReplyForm: number | null;
}>();
const emit = defineEmits<{
(event: 'toggle-reply', commentId: number): void;
(event: 'add-reply', commentId: number, replyAuthor: string, replyContent: string): void;
}>();
const replyAuthor = ref('');
const replyContent = ref('');
const toggleReply = (commentId: number) => {
emit('toggle-reply', commentId);
};
const addReply = (commentId: number, author: string, content: string) => {
emit('add-reply', commentId, author, content);
replyAuthor.value = '';
replyContent.value = '';
};
const handleSubmit = () => {
if (!replyAuthor.value.trim() || !replyContent.value.trim()) {
return;
}
emit('add-reply', props.comment.id, replyAuthor.value, replyContent.value);
replyAuthor.value = '';
replyContent.value = '';
};
const formatDate = (timestamp: string) => {
const date = new Date(timestamp);
return date.toLocaleString();
};
let lastColor: string | null = null;
const randomColor = () => {
let newColor: string;
do {
const index = Math.floor(Math.random() * AppConfig.systemMainColor.length);
newColor = AppConfig.systemMainColor[index];
} while (newColor === lastColor);
lastColor = newColor;
return newColor;
};
</script>