feat: 添加新闻管理功能,包括新闻列表和添加新闻表单
This commit is contained in:
142
src/views/news/components/add.vue
Normal file
142
src/views/news/components/add.vue
Normal 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>
|
||||
95
src/views/news/index.vue
Normal file
95
src/views/news/index.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<script lang="ts" setup>
|
||||
import { h, useTemplateRef } from 'vue';
|
||||
import { useDialog } from 'naive-ui';
|
||||
import dayjs from 'dayjs';
|
||||
import { client, safeClient } from '@/service/api';
|
||||
import type { TableBaseColumns, TableFetchData, TableInst } from '@/components/table';
|
||||
import Add from './components/add.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'NewsManagement'
|
||||
});
|
||||
|
||||
const dialog = useDialog();
|
||||
const tableInst = useTemplateRef<TableInst>('tableInst');
|
||||
|
||||
const fetchData: TableFetchData = ({ pagination, filter }) => {
|
||||
return safeClient(() => client.api.admin.news.get({ query: { ...pagination, ...filter } }));
|
||||
};
|
||||
|
||||
const columns: TableBaseColumns = [
|
||||
{
|
||||
key: 'title',
|
||||
title: '标题'
|
||||
},
|
||||
{
|
||||
key: 'summary',
|
||||
title: '摘要'
|
||||
},
|
||||
{
|
||||
key: 'hasVideo',
|
||||
title: '是否有视频'
|
||||
},
|
||||
{
|
||||
key: 'isHot',
|
||||
title: '是否热门'
|
||||
},
|
||||
{
|
||||
key: 'isPinned',
|
||||
title: '是否置顶'
|
||||
},
|
||||
{
|
||||
key: 'attachmentIds',
|
||||
title: '附件文件个数',
|
||||
render: (row: any) => {
|
||||
return row.attachmentIds ? row.attachmentIds.length : 0;
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'sortOrder',
|
||||
title: '排序值'
|
||||
},
|
||||
{
|
||||
key: 'publishedAt',
|
||||
title: '发布时间',
|
||||
render: (row: any) => {
|
||||
return dayjs(row.publishedAt).format('YYYY-MM-DD HH:mm');
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'operations',
|
||||
title: '操作',
|
||||
width: 150,
|
||||
fixed: 'right',
|
||||
operations: (row: any) => [
|
||||
{
|
||||
contentText: '编辑',
|
||||
size: 'small',
|
||||
onClick: () => {
|
||||
// 编辑操作
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
function handleAdd() {
|
||||
dialog.create({
|
||||
title: '添加新闻',
|
||||
showIcon: false,
|
||||
style: { width: '800px' },
|
||||
content: () =>
|
||||
h(Add, {
|
||||
onClose: () => {
|
||||
tableInst.value?.reload();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TableBase ref="tableInst" :fetch-data="fetchData" :columns="columns" @add="handleAdd" />
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped></style>
|
||||
Reference in New Issue
Block a user