|
@@ -0,0 +1,273 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <ContentWrap>
|
|
|
|
|
+ <el-form
|
|
|
|
|
+ ref="queryFormRef"
|
|
|
|
|
+ :inline="true"
|
|
|
|
|
+ :model="queryParams"
|
|
|
|
|
+ class="-mb-15px"
|
|
|
|
|
+ label-width="80px"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-form-item label="资讯标题" prop="newsName">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="queryParams.newsName"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ class="!w-240px"
|
|
|
|
|
+ placeholder="请输入资讯标题"
|
|
|
|
|
+ @keyup.enter="handleQuery"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="资讯类别" prop="newsCategory">
|
|
|
|
|
+ <el-select
|
|
|
|
|
+ v-model="queryParams.newsCategory"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ class="!w-240px"
|
|
|
|
|
+ placeholder="请选择资讯类别"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-option
|
|
|
|
|
+ v-for="dict in getIntDictOptions(DICT_TYPE.NEWS_CATEGORY)"
|
|
|
|
|
+ :key="dict.value"
|
|
|
|
|
+ :label="dict.label"
|
|
|
|
|
+ :value="dict.value"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item>
|
|
|
|
|
+ <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" />搜索</el-button>
|
|
|
|
|
+ <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" />重置</el-button>
|
|
|
|
|
+ <el-button type="primary" plain @click="openForm('create')">
|
|
|
|
|
+ <Icon icon="ep:plus" class="mr-5px" />新增
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ </ContentWrap>
|
|
|
|
|
+
|
|
|
|
|
+ <ContentWrap>
|
|
|
|
|
+ <el-table v-loading="loading" :data="list" row-key="id">
|
|
|
|
|
+ <el-table-column label="资讯标题" prop="newsName" min-width="260" show-overflow-tooltip />
|
|
|
|
|
+ <el-table-column label="资讯类别" prop="newsCategory" align="center" width="180">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <dict-tag :type="DICT_TYPE.NEWS_CATEGORY" :value="row.newsCategory" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="创建时间" prop="createTime" align="center" width="180">
|
|
|
|
|
+ <template #default="{ row }">{{ formatDate(row.createTime) }}</template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="操作" align="center" width="220" fixed="right">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-button link type="primary" @click="openDetail(row.id)">查看</el-button>
|
|
|
|
|
+ <el-button link type="primary" @click="openForm('update', row.id)">编辑</el-button>
|
|
|
|
|
+ <el-button link type="danger" @click="handleDelete(row.id)">删除</el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+
|
|
|
|
|
+ <Pagination
|
|
|
|
|
+ v-model:page="queryParams.pageNo"
|
|
|
|
|
+ v-model:limit="queryParams.pageSize"
|
|
|
|
|
+ :total="total"
|
|
|
|
|
+ @pagination="getList"
|
|
|
|
|
+ />
|
|
|
|
|
+ </ContentWrap>
|
|
|
|
|
+
|
|
|
|
|
+ <Dialog v-model="dialogVisible" :title="dialogTitle" width="800px" destroy-on-close>
|
|
|
|
|
+ <el-form
|
|
|
|
|
+ ref="formRef"
|
|
|
|
|
+ v-loading="formLoading"
|
|
|
|
|
+ :model="formData"
|
|
|
|
|
+ :rules="formRules"
|
|
|
|
|
+ label-width="80px"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-form-item label="资讯标题" prop="newsName">
|
|
|
|
|
+ <el-input v-model="formData.newsName" placeholder="请输入资讯标题" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="资讯类别" prop="newsCategory">
|
|
|
|
|
+ <el-select v-model="formData.newsCategory" clearable placeholder="请选择资讯类别">
|
|
|
|
|
+ <el-option
|
|
|
|
|
+ v-for="dict in getIntDictOptions(DICT_TYPE.NEWS_CATEGORY)"
|
|
|
|
|
+ :key="dict.value"
|
|
|
|
|
+ :label="dict.label"
|
|
|
|
|
+ :value="dict.value"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="资讯内容" prop="content">
|
|
|
|
|
+ <Editor v-model="formData.content" height="300px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <el-button @click="dialogVisible = false">取 消</el-button>
|
|
|
|
|
+ <el-button type="primary" :loading="submitLoading" @click="submitForm">确 定</el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <Dialog v-model="detailVisible" title="资讯详情" width="800px" destroy-on-close>
|
|
|
|
|
+ <div v-loading="detailLoading" class="news-detail">
|
|
|
|
|
+ <h2>{{ detailData.newsName }}</h2>
|
|
|
|
|
+ <div class="news-detail-meta">
|
|
|
|
|
+ <dict-tag :type="DICT_TYPE.NEWS_CATEGORY" :value="detailData.newsCategory" />
|
|
|
|
|
+ <span>{{ formatDate(detailData.createTime) }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="news-detail-content" v-html="detailData.content"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup lang="ts">
|
|
|
|
|
+import { onMounted, reactive, ref } from 'vue'
|
|
|
|
|
+import { ElMessage, ElMessageBox, FormRules } from 'element-plus'
|
|
|
|
|
+import { createNews, deleteNews, getNewsDetail, getNewsList, updateNews } from '@/api/technology'
|
|
|
|
|
+import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
|
|
|
|
+import { formatDate } from '@/utils/formatTime'
|
|
|
|
|
+
|
|
|
|
|
+type NewsFormData = {
|
|
|
|
|
+ id?: number
|
|
|
|
|
+ newsName: string
|
|
|
|
|
+ newsCategory?: string | number
|
|
|
|
|
+ content: string
|
|
|
|
|
+ createTime?: string
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+defineOptions({ name: 'NewsList' })
|
|
|
|
|
+
|
|
|
|
|
+const createDefaultFormData = (): NewsFormData => ({
|
|
|
|
|
+ id: undefined,
|
|
|
|
|
+ newsName: '',
|
|
|
|
|
+ newsCategory: undefined,
|
|
|
|
|
+ content: ''
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const loading = ref(false)
|
|
|
|
|
+const total = ref(0)
|
|
|
|
|
+const list = ref<any[]>([])
|
|
|
|
|
+const queryFormRef = ref()
|
|
|
|
|
+const queryParams = reactive({
|
|
|
|
|
+ pageNo: 1,
|
|
|
|
|
+ pageSize: 10,
|
|
|
|
|
+ newsName: undefined as string | undefined,
|
|
|
|
|
+ newsCategory: undefined as string | number | undefined
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const dialogVisible = ref(false)
|
|
|
|
|
+const dialogTitle = ref('')
|
|
|
|
|
+const dialogType = ref<'create' | 'update'>('create')
|
|
|
|
|
+const formLoading = ref(false)
|
|
|
|
|
+const submitLoading = ref(false)
|
|
|
|
|
+const formRef = ref()
|
|
|
|
|
+const formData = ref<NewsFormData>(createDefaultFormData())
|
|
|
|
|
+const formRules = reactive<FormRules>({
|
|
|
|
|
+ newsName: [{ required: true, message: '请输入资讯标题', trigger: 'blur' }],
|
|
|
|
|
+ newsCategory: [{ required: true, message: '请选择资讯类别', trigger: 'change' }],
|
|
|
|
|
+ content: [{ required: true, message: '请输入资讯内容', trigger: 'blur' }]
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const detailVisible = ref(false)
|
|
|
|
|
+const detailLoading = ref(false)
|
|
|
|
|
+const detailData = ref<NewsFormData>(createDefaultFormData())
|
|
|
|
|
+
|
|
|
|
|
+const getList = async () => {
|
|
|
|
|
+ loading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const data = await getNewsList(queryParams)
|
|
|
|
|
+ list.value = data.list || []
|
|
|
|
|
+ total.value = data.total || 0
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const handleQuery = () => {
|
|
|
|
|
+ queryParams.pageNo = 1
|
|
|
|
|
+ getList()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const resetQuery = () => {
|
|
|
|
|
+ queryFormRef.value?.resetFields()
|
|
|
|
|
+ handleQuery()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const resetForm = () => {
|
|
|
|
|
+ formData.value = createDefaultFormData()
|
|
|
|
|
+ formRef.value?.resetFields()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const openForm = async (type: 'create' | 'update', id?: number) => {
|
|
|
|
|
+ dialogVisible.value = true
|
|
|
|
|
+ dialogType.value = type
|
|
|
|
|
+ dialogTitle.value = type === 'create' ? '新增资讯' : '编辑资讯'
|
|
|
|
|
+ resetForm()
|
|
|
|
|
+ if (type === 'update' && id) {
|
|
|
|
|
+ formLoading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ formData.value = { ...createDefaultFormData(), ...(await getNewsDetail(id)) }
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ formLoading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const submitForm = async () => {
|
|
|
|
|
+ const valid = await formRef.value?.validate().catch(() => false)
|
|
|
|
|
+ if (!valid) return
|
|
|
|
|
+ submitLoading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (dialogType.value === 'create') {
|
|
|
|
|
+ await createNews(formData.value)
|
|
|
|
|
+ ElMessage.success('新增成功')
|
|
|
|
|
+ } else {
|
|
|
|
|
+ await updateNews(formData.value)
|
|
|
|
|
+ ElMessage.success('修改成功')
|
|
|
|
|
+ }
|
|
|
|
|
+ dialogVisible.value = false
|
|
|
|
|
+ await getList()
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ submitLoading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const openDetail = async (id: number) => {
|
|
|
|
|
+ detailVisible.value = true
|
|
|
|
|
+ detailLoading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ detailData.value = { ...createDefaultFormData(), ...(await getNewsDetail(id)) }
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ detailLoading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const handleDelete = async (id: number) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ await ElMessageBox.confirm('确定要删除该资讯吗?', '提示', {
|
|
|
|
|
+ type: 'warning',
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消'
|
|
|
|
|
+ })
|
|
|
|
|
+ await deleteNews(id)
|
|
|
|
|
+ ElMessage.success('删除成功')
|
|
|
|
|
+ await getList()
|
|
|
|
|
+ } catch {}
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+onMounted(getList)
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
|
+.news-detail h2 {
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.news-detail-meta {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 16px;
|
|
|
|
|
+ margin: 16px 0 24px;
|
|
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.news-detail-content {
|
|
|
|
|
+ min-height: 180px;
|
|
|
|
|
+ line-height: 1.8;
|
|
|
|
|
+ overflow-wrap: anywhere;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|