更新website
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
// ==================== 官网管理 - 站点公告(平台端) ====================
|
||||
// 数据表:yz_platform_website_notice
|
||||
// 建表 SQL:go/docs/sql/create_platform_website_notice.sql
|
||||
//
|
||||
// 状态约定:0 草稿 / 1 已发布 / 2 已下线
|
||||
// 类型约定:1 通知公告 / 2 活动公告 / 3 系统维护
|
||||
|
||||
// 公告列表(分页):keyword / type / status / is_popup / page / pageSize
|
||||
export function listNotices(params) {
|
||||
return request({
|
||||
url: "/platform/website/notice/list",
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
// 公告详情(含富文本正文,供编辑回显)
|
||||
export function getNotice(id) {
|
||||
return request({
|
||||
url: `/platform/website/notice/${id}`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
// 新增公告
|
||||
export function createNotice(data) {
|
||||
return request({
|
||||
url: "/platform/website/notice",
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 编辑公告
|
||||
export function editNotice(id, data) {
|
||||
return request({
|
||||
url: `/platform/website/notice/${id}`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 删除公告(软删除)
|
||||
export function deleteNotice(id) {
|
||||
return request({
|
||||
url: `/platform/website/notice/${id}`,
|
||||
method: "delete",
|
||||
});
|
||||
}
|
||||
|
||||
// 批量删除公告
|
||||
export function batchDeleteNotices(ids) {
|
||||
return request({
|
||||
url: "/platform/website/notice/batchdelete",
|
||||
method: "post",
|
||||
data: { ids },
|
||||
});
|
||||
}
|
||||
|
||||
// 发布 / 下线(status 1 / 2)
|
||||
export function publishNotice(id) {
|
||||
return request({
|
||||
url: `/platform/website/notice/${id}/publish`,
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
export function unpublishNotice(id) {
|
||||
return request({
|
||||
url: `/platform/website/notice/${id}/unpublish`,
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
// 置顶 / 取消置顶
|
||||
export function topNotice(id) {
|
||||
return request({
|
||||
url: `/platform/website/notice/${id}/top`,
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
export function untopNotice(id) {
|
||||
return request({
|
||||
url: `/platform/website/notice/${id}/untop`,
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
// 标记为弹窗公告 / 取消弹窗
|
||||
export function popupNotice(id) {
|
||||
return request({
|
||||
url: `/platform/website/notice/${id}/popup`,
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
export function unpopupNotice(id) {
|
||||
return request({
|
||||
url: `/platform/website/notice/${id}/unpopup`,
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
<template>
|
||||
<el-drawer
|
||||
v-model="visible"
|
||||
:title="isEdit ? '编辑公告' : '新增公告'"
|
||||
size="780px"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
@closed="handleClosed"
|
||||
>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-form-item label="公告标题" prop="title">
|
||||
<el-input
|
||||
v-model="form.title"
|
||||
placeholder="请输入公告标题"
|
||||
maxlength="255"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="公告类型" prop="type">
|
||||
<el-select v-model="form.type" style="width: 200px">
|
||||
<el-option
|
||||
v-for="item in TYPE_OPTIONS"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="公告摘要" prop="summary">
|
||||
<el-input
|
||||
v-model="form.summary"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="列表卡片展示的摘要,留空则前台展示正文开头"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="公告正文">
|
||||
<div class="editor-container">
|
||||
<UmoEditor v-model="form.content" :cate="materialCateId" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="跳转地址" prop="link_url">
|
||||
<el-input
|
||||
v-model="form.link_url"
|
||||
placeholder="点击公告后跳转的地址,站内填 /news,站外填完整 URL;留空表示不可点击"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="生效时间" prop="start_time">
|
||||
<el-date-picker
|
||||
v-model="form.start_time"
|
||||
type="datetime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
placeholder="留空表示立即生效"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="失效时间" prop="end_time">
|
||||
<el-date-picker
|
||||
v-model="form.end_time"
|
||||
type="datetime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
placeholder="留空表示长期有效"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="首页弹窗">
|
||||
<el-switch v-model="form.is_popup" :active-value="1" :inactive-value="0" />
|
||||
<span class="field-tip">开启后该公告进入首页弹窗 / 侧栏公告区</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="置顶">
|
||||
<el-switch v-model="form.top" :active-value="1" :inactive-value="0" />
|
||||
<span class="field-tip">置顶公告在列表中优先展示</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input-number v-model="form.sort" :min="0" :max="9999" controls-position="right" />
|
||||
<span class="field-tip">数字越小越靠前</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio :value="0">草稿</el-radio>
|
||||
<el-radio :value="1">已发布</el-radio>
|
||||
<el-radio :value="2">已下线</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">
|
||||
{{ isEdit ? '保存' : '创建' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, watch, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { createNotice, editNotice, getNotice } from '@/api/notice'
|
||||
import { ensureWebsiteMaterialCate } from '@/utils/websiteUpload'
|
||||
import { formatDateTime } from '@/utils/datetime'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Boolean, default: false },
|
||||
isEdit: { type: Boolean, default: false },
|
||||
noticeId: { type: Number, default: 0 }
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'success'])
|
||||
|
||||
// 公告类型:与 go/controllers/platform_website_notice.go 保持一致
|
||||
const TYPE_OPTIONS = [
|
||||
{ value: 1, label: '通知公告' },
|
||||
{ value: 2, label: '活动公告' },
|
||||
{ value: 3, label: '系统维护' }
|
||||
]
|
||||
|
||||
const visible = ref(props.modelValue)
|
||||
const submitLoading = ref(false)
|
||||
const formRef = ref(null)
|
||||
// 「官网素材」文件分组ID:正文内插入的图片归入该分组
|
||||
const materialCateId = ref(0)
|
||||
|
||||
const form = reactive({
|
||||
title: '',
|
||||
summary: '',
|
||||
content: '',
|
||||
type: 1,
|
||||
link_url: '',
|
||||
is_popup: 0,
|
||||
top: 0,
|
||||
sort: 0,
|
||||
status: 0,
|
||||
start_time: '',
|
||||
end_time: ''
|
||||
})
|
||||
|
||||
const rules = {
|
||||
title: [{ required: true, message: '请输入公告标题', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
const isEdit = computed(() => props.isEdit)
|
||||
|
||||
/** 后端返回 RFC3339,转成 el-date-picker 需要的 YYYY-MM-DD HH:mm:ss;无值返回空串 */
|
||||
const toPickerValue = (value) => {
|
||||
if (!value) return ''
|
||||
const text = formatDateTime(value)
|
||||
return text === '-' ? '' : text
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
formRef.value?.clearValidate()
|
||||
Object.assign(form, {
|
||||
title: '',
|
||||
summary: '',
|
||||
content: '',
|
||||
type: 1,
|
||||
link_url: '',
|
||||
is_popup: 0,
|
||||
top: 0,
|
||||
sort: 0,
|
||||
status: 0,
|
||||
start_time: '',
|
||||
end_time: ''
|
||||
})
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
async (val) => {
|
||||
if (!val) {
|
||||
visible.value = false
|
||||
return
|
||||
}
|
||||
resetForm()
|
||||
if (props.isEdit && props.noticeId) {
|
||||
try {
|
||||
const res = await getNotice(props.noticeId)
|
||||
if (res.code === 200 && res.data) {
|
||||
const d = res.data
|
||||
Object.assign(form, {
|
||||
title: d.title || '',
|
||||
summary: d.summary || '',
|
||||
content: d.content || '',
|
||||
type: d.type ?? 1,
|
||||
link_url: d.link_url || '',
|
||||
is_popup: d.is_popup ?? 0,
|
||||
top: d.top ?? 0,
|
||||
sort: d.sort ?? 0,
|
||||
status: d.status ?? 0,
|
||||
start_time: toPickerValue(d.start_time),
|
||||
end_time: toPickerValue(d.end_time)
|
||||
})
|
||||
} else {
|
||||
ElMessage.error(res.msg || '获取公告详情失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('获取公告详情失败')
|
||||
}
|
||||
}
|
||||
// 数据就绪后再打开抽屉,保证富文本编辑器挂载时即可拿到回显内容
|
||||
visible.value = true
|
||||
}
|
||||
)
|
||||
|
||||
watch(visible, (val) => {
|
||||
emit('update:modelValue', val)
|
||||
})
|
||||
|
||||
const handleClosed = () => {
|
||||
resetForm()
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return
|
||||
await formRef.value.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
submitLoading.value = true
|
||||
try {
|
||||
const payload = {
|
||||
title: form.title,
|
||||
summary: form.summary,
|
||||
content: form.content,
|
||||
type: form.type,
|
||||
link_url: form.link_url,
|
||||
is_popup: form.is_popup,
|
||||
top: form.top,
|
||||
sort: form.sort,
|
||||
status: form.status,
|
||||
// 空串表示不限制,后端按 NULL 处理
|
||||
start_time: form.start_time || '',
|
||||
end_time: form.end_time || ''
|
||||
}
|
||||
|
||||
const res = isEdit.value
|
||||
? await editNotice(props.noticeId, payload)
|
||||
: await createNotice(payload)
|
||||
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(isEdit.value ? '保存成功' : '创建成功')
|
||||
visible.value = false
|
||||
emit('success')
|
||||
} else {
|
||||
ElMessage.error(res.msg || '操作失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('操作失败')
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 提前解析「官网素材」分组,供正文内插入图片时使用
|
||||
ensureWebsiteMaterialCate().then((id) => {
|
||||
materialCateId.value = id
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.editor-container {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.field-tip {
|
||||
margin-left: 10px;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,471 @@
|
||||
<template>
|
||||
<div class="container-box notice-manage">
|
||||
<div class="header-bar">
|
||||
<h2>站点公告</h2>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
:disabled="selectedIds.length === 0"
|
||||
@click="handleBatchDelete"
|
||||
>
|
||||
<el-icon><Delete /></el-icon>
|
||||
批量删除
|
||||
</el-button>
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增公告
|
||||
</el-button>
|
||||
<el-button @click="fetchList" :loading="loading">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
刷新
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-alert type="info" :closable="false" class="tips">
|
||||
<template #title>
|
||||
<div>
|
||||
官网通知 / 活动 / 系统维护类公告。仅 <b>已发布</b> 且当前时间处于
|
||||
<b>有效期内</b> 的公告会在官网展示;标记为「弹窗公告」的条目供首页弹窗区读取。
|
||||
前台接口:<code>GET /site/notices</code>(<code>?popup=1</code> 只取弹窗公告)。
|
||||
</div>
|
||||
</template>
|
||||
</el-alert>
|
||||
|
||||
<div class="search-bar">
|
||||
<el-input
|
||||
v-model="searchForm.keyword"
|
||||
placeholder="搜索公告标题 / 摘要"
|
||||
clearable
|
||||
style="width: 220px"
|
||||
@keyup.enter="handleSearch"
|
||||
@clear="handleSearch"
|
||||
/>
|
||||
<el-select
|
||||
v-model="searchForm.type"
|
||||
placeholder="全部类型"
|
||||
clearable
|
||||
style="width: 140px"
|
||||
@change="handleSearch"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in TYPE_OPTIONS"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<el-select
|
||||
v-model="searchForm.status"
|
||||
placeholder="全部状态"
|
||||
clearable
|
||||
style="width: 140px"
|
||||
@change="handleSearch"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in STATUS_OPTIONS"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<el-select
|
||||
v-model="searchForm.isPopup"
|
||||
placeholder="是否弹窗"
|
||||
clearable
|
||||
style="width: 140px"
|
||||
@change="handleSearch"
|
||||
>
|
||||
<el-option label="弹窗公告" :value="1" />
|
||||
<el-option label="普通公告" :value="0" />
|
||||
</el-select>
|
||||
<el-button type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button @click="resetSearch">重置</el-button>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
:data="noticeList"
|
||||
v-loading="loading"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="50" align="center" />
|
||||
<el-table-column prop="id" label="ID" width="70" align="center" />
|
||||
|
||||
<el-table-column label="公告标题" min-width="240" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.top === 1" size="small" type="danger" effect="plain">置顶</el-tag>
|
||||
<span class="title-text">{{ row.title }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="类型" width="110" align="center">
|
||||
<template #default="{ row }">{{ typeLabel(row.type) }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="弹窗" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
:model-value="row.is_popup === 1"
|
||||
@change="(val) => handlePopupChange(row, val)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="置顶" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
:model-value="row.top === 1"
|
||||
@change="(val) => handleTopChange(row, val)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="sort" label="排序" width="80" align="center" />
|
||||
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="statusTagType(row.status)" size="small">
|
||||
{{ statusLabel(row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="有效期" width="180" align="center">
|
||||
<template #default="{ row }">{{ validRange(row) }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="发布时间" width="170" align="center">
|
||||
<template #default="{ row }">{{ formatDateTime(row.publish_time) }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="200" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button size="small" text type="primary" @click="handleEdit(row)">
|
||||
<el-icon><Edit /></el-icon>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
text
|
||||
:type="row.status === 1 ? 'warning' : 'success'"
|
||||
@click="handleTogglePublish(row)"
|
||||
>
|
||||
<el-icon><Upload /></el-icon>
|
||||
{{ row.status === 1 ? '下线' : '发布' }}
|
||||
</el-button>
|
||||
<el-button size="small" text type="danger" @click="handleDelete(row)">
|
||||
<el-icon><Delete /></el-icon>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<template #empty>
|
||||
<el-empty description="暂无公告" :image-size="80" />
|
||||
</template>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.page"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="pagination.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<NoticeEdit
|
||||
v-model="dialogVisible"
|
||||
:is-edit="isEdit"
|
||||
:notice-id="editId"
|
||||
@success="fetchList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Refresh, Search, Edit, Delete, Upload } from '@element-plus/icons-vue'
|
||||
import { formatDateTime } from '@/utils/datetime'
|
||||
import {
|
||||
listNotices,
|
||||
deleteNotice,
|
||||
batchDeleteNotices,
|
||||
publishNotice,
|
||||
unpublishNotice,
|
||||
topNotice,
|
||||
untopNotice,
|
||||
popupNotice,
|
||||
unpopupNotice
|
||||
} from '@/api/notice'
|
||||
import NoticeEdit from './components/edit.vue'
|
||||
|
||||
// 公告类型 / 状态:与 go/controllers/platform_website_notice.go 保持一致
|
||||
const TYPE_OPTIONS = [
|
||||
{ value: 1, label: '通知公告' },
|
||||
{ value: 2, label: '活动公告' },
|
||||
{ value: 3, label: '系统维护' }
|
||||
]
|
||||
const STATUS_OPTIONS = [
|
||||
{ value: 0, label: '草稿' },
|
||||
{ value: 1, label: '已发布' },
|
||||
{ value: 2, label: '已下线' }
|
||||
]
|
||||
|
||||
const typeLabel = (type) =>
|
||||
TYPE_OPTIONS.find((item) => item.value === type)?.label || '通知公告'
|
||||
const statusLabel = (status) =>
|
||||
STATUS_OPTIONS.find((item) => item.value === status)?.label || '草稿'
|
||||
const statusTagType = (status) => {
|
||||
if (status === 1) return 'success'
|
||||
if (status === 2) return 'warning'
|
||||
return 'info'
|
||||
}
|
||||
|
||||
const loading = ref(false)
|
||||
const noticeList = ref([])
|
||||
const selectedIds = ref([])
|
||||
const searchForm = reactive({ keyword: '', type: '', status: '', isPopup: '' })
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const isEdit = ref(false)
|
||||
const editId = ref(0)
|
||||
|
||||
/** 有效期展示:两端都为空表示不限制 */
|
||||
const validRange = (row) => {
|
||||
const start = row.start_time ? formatDateTime(row.start_time) : ''
|
||||
const end = row.end_time ? formatDateTime(row.end_time) : ''
|
||||
if (!start && !end) return '长期有效'
|
||||
return `${start || '立即'} ~ ${end || '不限'}`
|
||||
}
|
||||
|
||||
const fetchList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await listNotices({
|
||||
keyword: searchForm.keyword,
|
||||
type: searchForm.type === '' ? '' : searchForm.type,
|
||||
status: searchForm.status === '' ? '' : searchForm.status,
|
||||
is_popup: searchForm.isPopup === '' ? '' : searchForm.isPopup,
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize
|
||||
})
|
||||
if (res.code === 200) {
|
||||
const data = res.data
|
||||
noticeList.value = Array.isArray(data) ? data : data?.list || []
|
||||
pagination.total = Array.isArray(data) ? data.length : data?.total || 0
|
||||
} else {
|
||||
ElMessage.error(res.msg || '获取公告列表失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('获取公告列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.page = 1
|
||||
fetchList()
|
||||
}
|
||||
|
||||
const resetSearch = () => {
|
||||
Object.assign(searchForm, { keyword: '', type: '', status: '', isPopup: '' })
|
||||
pagination.page = 1
|
||||
fetchList()
|
||||
}
|
||||
|
||||
const handleSizeChange = (val) => {
|
||||
pagination.pageSize = val
|
||||
pagination.page = 1
|
||||
fetchList()
|
||||
}
|
||||
|
||||
const handlePageChange = (val) => {
|
||||
pagination.page = val
|
||||
fetchList()
|
||||
}
|
||||
|
||||
const handleSelectionChange = (selection) => {
|
||||
selectedIds.value = selection.map((item) => item.id)
|
||||
}
|
||||
|
||||
const handleAdd = () => {
|
||||
isEdit.value = false
|
||||
editId.value = 0
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleEdit = (row) => {
|
||||
isEdit.value = true
|
||||
editId.value = row.id
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleTopChange = async (row, val) => {
|
||||
const next = val ? 1 : 0
|
||||
try {
|
||||
const res = next === 1 ? await topNotice(row.id) : await untopNotice(row.id)
|
||||
if (res.code === 200) {
|
||||
row.top = next
|
||||
ElMessage.success(next === 1 ? '已置顶' : '已取消置顶')
|
||||
} else {
|
||||
ElMessage.error(res.msg || '操作失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('操作失败')
|
||||
}
|
||||
}
|
||||
|
||||
const handlePopupChange = async (row, val) => {
|
||||
const next = val ? 1 : 0
|
||||
try {
|
||||
const res = next === 1 ? await popupNotice(row.id) : await unpopupNotice(row.id)
|
||||
if (res.code === 200) {
|
||||
row.is_popup = next
|
||||
ElMessage.success(next === 1 ? '已设为弹窗公告' : '已取消弹窗公告')
|
||||
} else {
|
||||
ElMessage.error(res.msg || '操作失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('操作失败')
|
||||
}
|
||||
}
|
||||
|
||||
const handleTogglePublish = async (row) => {
|
||||
const offline = row.status === 1
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
offline
|
||||
? `确定要下线公告「${row.title}」吗?下线后官网将不再展示。`
|
||||
: `确定要发布公告「${row.title}」吗?发布后官网立即可见(受有效期限制)。`,
|
||||
offline ? '下线确认' : '发布确认',
|
||||
{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
|
||||
)
|
||||
} catch (e) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = offline ? await unpublishNotice(row.id) : await publishNotice(row.id)
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(offline ? '已下线' : '已发布')
|
||||
fetchList()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '操作失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('操作失败')
|
||||
}
|
||||
}
|
||||
|
||||
const handleDelete = async (row) => {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定要删除公告「${row.title}」吗?`, '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
} catch (e) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await deleteNotice(row.id)
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('删除成功')
|
||||
fetchList()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '删除失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
}
|
||||
|
||||
const handleBatchDelete = async () => {
|
||||
if (selectedIds.value.length === 0) return
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定要删除选中的 ${selectedIds.value.length} 条公告吗?`,
|
||||
'批量删除确认',
|
||||
{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
|
||||
)
|
||||
} catch (e) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await batchDeleteNotices(selectedIds.value)
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('删除成功')
|
||||
selectedIds.value = []
|
||||
fetchList()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '删除失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container-box {
|
||||
padding: 16px;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
.header-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.tips {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user