This commit is contained in:
李琦
2026-01-15 16:37:58 +08:00
parent 944d642d38
commit 782bcdd4d7
6 changed files with 1132 additions and 118 deletions

View File

@@ -1,95 +1,97 @@
<template>
<div class="post-form-container">
<h1 class="page-title">{{ isEditing ? '编辑文章' : '新建文章' }}</h1>
<div class="form-container">
<form @submit.prevent="handleSubmit" class="post-form">
<!-- Title Field -->
<div class="form-group">
<label for="title">文章标题</label>
<input
type="text"
id="title"
v-model="form.title"
placeholder="请输入文章标题"
required
<input
type="text"
id="title"
v-model="form.title"
placeholder="请输入文章标题"
required
/>
<div class="error-message" v-if="errors.title">
{{ errors.title }}
</div>
</div>
<!-- Category Field -->
<div class="form-group">
<label for="category">分类</label>
<input
type="text"
id="category"
v-model="form.category"
placeholder="请输入文章分类"
required
<input
type="text"
id="category"
v-model="form.category"
placeholder="请输入文章分类"
required
/>
<div class="error-message" v-if="errors.category">
{{ errors.category }}
</div>
</div>
<!-- Date Field -->
<div class="form-group">
<label for="date">发布日期</label>
<input
type="date"
id="date"
v-model="form.date"
required
<input
type="date"
id="date"
v-model="form.date"
required
/>
<div class="error-message" v-if="errors.date">
{{ errors.date }}
</div>
</div>
<!-- Excerpt Field -->
<div class="form-group">
<label for="excerpt">文章摘要</label>
<textarea
id="excerpt"
v-model="form.excerpt"
placeholder="请输入文章摘要"
rows="3"
<textarea
id="excerpt"
v-model="form.excerpt"
placeholder="请输入文章摘要"
rows="3"
></textarea>
<div class="error-message" v-if="errors.excerpt">
{{ errors.excerpt }}
</div>
</div>
<!-- Content Field -->
<!-- Content Field - 使用 Markdown 编辑器 -->
<div class="form-group">
<label for="content">文章内容</label>
<textarea
id="content"
v-model="form.content"
placeholder="请输入文章内容"
rows="10"
required
></textarea>
<label>文章内容</label>
<div class="editor-wrapper">
<MdEditor
v-model="form.content"
theme="dark"
:preview="false"
placeholder="请输入 Markdown 内容..."
class="custom-md-editor"
/>
</div>
<div class="error-message" v-if="errors.content">
{{ errors.content }}
</div>
</div>
<!-- Is Published Field -->
<div class="form-group">
<label for="isPublished">发布状态</label>
<CustomSelect
v-model="form.isPublished"
:options="publishStatusOptions"
placeholder="请选择发布状态"
v-model="form.isPublished"
:options="publishStatusOptions"
placeholder="请选择发布状态"
/>
<div class="error-message" v-if="errors.isPublished">
{{ errors.isPublished }}
</div>
</div>
<!-- Submit Buttons -->
<div class="form-actions">
<button type="button" class="cancel-btn" @click="handleCancel">
@@ -107,6 +109,10 @@
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
// 引入 md-editor-v3
import { MdEditor } from 'md-editor-v3'
import 'md-editor-v3/lib/style.css'
import { useToast } from '../../composables/useToast'
import { createPost, updatePost, fetchPost } from '../../services/api'
import CustomSelect from '../../components/CustomSelect.vue'
@@ -140,33 +146,33 @@ const publishStatusOptions = [
const validateForm = (): boolean => {
// Reset errors
Object.keys(errors).forEach(key => delete errors[key])
let isValid = true
// Validate title
if (!form.title.trim()) {
errors.title = '文章标题不能为空'
isValid = false
}
// Validate category
if (!form.category.trim()) {
errors.category = '文章分类不能为空'
isValid = false
}
// Validate date
if (!form.date) {
errors.date = '发布日期不能为空'
isValid = false
}
// Validate content
if (!form.content.trim()) {
errors.content = '文章内容不能为空'
isValid = false
}
return isValid
}
@@ -175,9 +181,9 @@ const handleSubmit = async () => {
if (!validateForm()) {
return
}
isSubmitting.value = true
try {
if (isEditing.value) {
// Update existing post
@@ -188,7 +194,7 @@ const handleSubmit = async () => {
await createPost(form)
toast.success('文章创建成功')
}
// Redirect to posts list
router.push('/admin/posts')
} catch (error: any) {
@@ -211,7 +217,7 @@ onMounted(async () => {
try {
const postId = route.params.id as string
const post = await fetchPost(postId)
// Populate form with post data
form.title = post.title
form.category = post.category
@@ -350,19 +356,54 @@ onMounted(async () => {
cursor: not-allowed;
}
/* MdEditor Customization */
.editor-wrapper {
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 0.5rem;
overflow: hidden;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.editor-wrapper:focus-within {
border-color: #d4b383;
box-shadow: 0 0 0 3px rgba(212, 179, 131, 0.2);
}
:deep(.custom-md-editor) {
background-color: rgba(255, 255, 255, 0.05) !important;
--md-bk-color: transparent !important;
--md-color: white !important;
--md-border-color: transparent !important;
height: 500px;
}
:deep(.md-editor-toolbar-wrapper) {
background-color: rgba(0, 0, 0, 0.2) !important;
border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
}
:deep(.md-editor-content) {
background-color: transparent !important;
}
:deep(.md-editor-footer) {
background-color: rgba(0, 0, 0, 0.2) !important;
border-top: 1px solid rgba(255, 255, 255, 0.1) !important;
}
/* Responsive Design */
@media (max-width: 768px) {
.form-container {
padding: 1.5rem;
}
.form-actions {
flex-direction: column;
}
.cancel-btn,
.submit-btn {
width: 100%;
}
}
</style>
</style>

View File

@@ -1,68 +1,70 @@
<template>
<div class="snippet-form-container">
<h1 class="page-title">{{ isEditing ? '编辑代码片段' : '新建代码片段' }}</h1>
<div class="form-container">
<form @submit.prevent="handleSubmit" class="snippet-form">
<!-- Title Field -->
<div class="form-group">
<label for="title">标题</label>
<input
type="text"
id="title"
v-model="form.title"
placeholder="请输入代码片段标题"
required
<input
type="text"
id="title"
v-model="form.title"
placeholder="请输入代码片段标题"
required
/>
<div class="error-message" v-if="errors.title">
{{ errors.title }}
</div>
</div>
<!-- Type Field -->
<div class="form-group">
<label for="type">类型</label>
<input
type="text"
id="type"
v-model="form.type"
placeholder="请输入代码类型js、css、html等"
required
<input
type="text"
id="type"
v-model="form.type"
placeholder="请输入代码类型js、css、html等"
required
/>
<div class="error-message" v-if="errors.type">
{{ errors.type }}
</div>
</div>
<!-- Code Field -->
<!-- Code Field - Updated to MdEditor for better editing experience -->
<div class="form-group">
<label for="code">代码内容</label>
<textarea
id="code"
v-model="form.code"
placeholder="请输入代码内容"
rows="10"
required
></textarea>
<label>代码内容</label>
<div class="editor-wrapper">
<MdEditor
v-model="form.code"
theme="dark"
:preview="false"
placeholder="请输入代码..."
class="custom-md-editor"
/>
</div>
<div class="error-message" v-if="errors.code">
{{ errors.code }}
</div>
</div>
<!-- Description Field -->
<div class="form-group">
<label for="description">描述</label>
<textarea
id="description"
v-model="form.description"
placeholder="请输入代码片段描述"
rows="3"
<textarea
id="description"
v-model="form.description"
placeholder="请输入代码片段描述"
rows="3"
></textarea>
<div class="error-message" v-if="errors.description">
{{ errors.description }}
</div>
</div>
<!-- Submit Buttons -->
<div class="form-actions">
<button type="button" class="cancel-btn" @click="handleCancel">
@@ -80,6 +82,10 @@
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
// Import MdEditor
import { MdEditor } from 'md-editor-v3'
import 'md-editor-v3/lib/style.css'
import { useToast } from '../../composables/useToast'
import { createSnippet, updateSnippet, fetchSnippet } from '../../services/api'
@@ -104,27 +110,27 @@ const form = reactive({
const validateForm = (): boolean => {
// Reset errors
Object.keys(errors).forEach(key => delete errors[key])
let isValid = true
// Validate title
if (!form.title.trim()) {
errors.title = '代码片段标题不能为空'
isValid = false
}
// Validate type
if (!form.type.trim()) {
errors.type = '代码类型不能为空'
isValid = false
}
// Validate code
if (!form.code.trim()) {
errors.code = '代码内容不能为空'
isValid = false
}
return isValid
}
@@ -133,9 +139,9 @@ const handleSubmit = async () => {
if (!validateForm()) {
return
}
isSubmitting.value = true
try {
if (isEditing.value) {
// Update existing snippet
@@ -146,7 +152,7 @@ const handleSubmit = async () => {
await createSnippet(form)
toast.success('代码片段创建成功')
}
// Redirect to snippets list
router.push('/admin/snippets')
} catch (error: any) {
@@ -304,19 +310,54 @@ onMounted(async () => {
cursor: not-allowed;
}
/* MdEditor Customization (Consistent with PostForm) */
.editor-wrapper {
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 0.5rem;
overflow: hidden;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.editor-wrapper:focus-within {
border-color: #d4b383;
box-shadow: 0 0 0 3px rgba(212, 179, 131, 0.2);
}
:deep(.custom-md-editor) {
background-color: rgba(255, 255, 255, 0.05) !important;
--md-bk-color: transparent !important;
--md-color: white !important;
--md-border-color: transparent !important;
height: 500px;
}
:deep(.md-editor-toolbar-wrapper) {
background-color: rgba(0, 0, 0, 0.2) !important;
border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
}
:deep(.md-editor-content) {
background-color: transparent !important;
}
:deep(.md-editor-footer) {
background-color: rgba(0, 0, 0, 0.2) !important;
border-top: 1px solid rgba(255, 255, 255, 0.1) !important;
}
/* Responsive Design */
@media (max-width: 768px) {
.form-container {
padding: 1.5rem;
}
.form-actions {
flex-direction: column;
}
.cancel-btn,
.submit-btn {
width: 100%;
}
}
</style>
</style>