feat: 添加新闻管理功能,包括新闻列表和添加新闻表单

This commit is contained in:
2026-01-19 19:40:02 +07:00
parent 26056e8e21
commit 07b75dc03e
11 changed files with 279 additions and 30 deletions

View File

@@ -0,0 +1,142 @@
<script lang="ts" setup>
import { ref } from 'vue';
import type { FormInst, FormRules, UploadFileInfo } from 'naive-ui';
import { client, safeClient } from '@/service/api';
import UploadS3 from '@/components/upload/index.vue';
defineOptions({
name: 'NewsAdd'
});
const emit = defineEmits<{
(e: 'close'): void;
}>();
type NewsItem = Treaty.Body<typeof client.api.admin.news.post>;
const formRef = ref<FormInst | null>(null);
const loading = ref(false);
const formModel = ref<NewsItem>({
title: '',
summary: '',
content: '',
hasVideo: false,
isHot: false,
isPinned: false,
thumbnailId: null,
attachmentIds: [],
sortOrder: 0
});
const rules: FormRules = {
title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
summary: [{ required: true, message: '请输入摘要', trigger: 'blur' }]
};
async function handleSubmit() {
await formRef.value?.validate();
loading.value = true;
try {
const result = await safeClient(() =>
client.api.admin.news.post({
...formModel.value
})
);
if (result.data) {
window.$message?.success('创建成功');
resetForm();
emit('close');
}
} finally {
loading.value = false;
}
}
function resetForm() {
formModel.value = {
title: '',
summary: '',
content: '',
hasVideo: false,
isHot: false,
isPinned: false,
attachmentIds: [],
sortOrder: 0,
publishedAt: null
};
}
</script>
<template>
<div>
<NForm ref="formRef" :model="formModel" :rules="rules" label-placement="left" :label-width="100">
<NFormItem label="缩略图" path="thumbnailId">
<UploadS3
:model-value="formModel.thumbnailId ? [formModel.thumbnailId] : undefined"
:max-size="20"
:max-files="1"
accept="image/*"
placeholder="上传图片"
:fetch-options="{ businessType: 'news_attachment' }"
@update:model-value="evt => (formModel.thumbnailId = evt.length > 0 ? evt[0] : undefined)"
/>
</NFormItem>
<NFormItem label="标题" path="title">
<NInput v-model:value="formModel.title" placeholder="请输入标题" />
</NFormItem>
<NFormItem label="摘要" path="summary">
<NInput
v-model:value="formModel.summary"
type="textarea"
placeholder="请输入摘要"
:autosize="{ minRows: 3, maxRows: 5 }"
/>
</NFormItem>
<NFormItem label="内容" path="content">
<NInput
v-model:value="formModel.content"
type="textarea"
placeholder="请输入内容"
:autosize="{ minRows: 5, maxRows: 10 }"
/>
</NFormItem>
<NGrid cols="2" x-gap="16px">
<NFormItemGi label="是否热门" path="isHot">
<NSwitch v-model:value="formModel.isHot" />
</NFormItemGi>
<NFormItemGi label="是否置顶" path="isPinned">
<NSwitch v-model:value="formModel.isPinned" />
</NFormItemGi>
</NGrid>
<NFormItem label="排序值" path="sortOrder">
<NInputNumber v-model:value="formModel.sortOrder" placeholder="请输入排序值" class="w-full" />
</NFormItem>
<NFormItem label="附件文件" path="attachmentIds">
<UploadS3
:model-value="formModel.attachmentIds || []"
:max-size="20"
:max-files="3"
placeholder="上传附件"
:fetch-options="{ businessType: 'news_attachment' }"
@update:model-value="evt => (formModel.attachmentIds = evt.length > 0 ? evt : undefined)"
/>
</NFormItem>
</NForm>
<div class="mt-16px flex justify-end gap-12px">
<NButton @click="emit('close')">取消</NButton>
<NButton type="primary" :loading="loading" @click="handleSubmit">确定</NButton>
</div>
</div>
</template>
<style lang="scss" scoped></style>