Deploy / deploy (push) Canceled after 0s
- 侧栏按 概览 / 教学内容 / 学情分析 / 站点管理 分组,去掉超管菜单里的重复项; 菜单项的角色与路由守卫一一对应,没有题目权限的教师不再看到点了就被踢回首页的「题目」 - 顶栏:面包屑、回到前台、明暗切换、用户菜单(退出登录);窄屏侧栏自动收起 - 新增 PageHeader:标题 + 右侧主操作 + 下方筛选栏,编辑页带返回按钮 - 卡点分析 / 年度趋势 / 标签管理从题目列表的按钮挪进侧栏 - 首页改成统计卡片 + 班级排名卡片;设置页按钮移到卡片右上角 - 题目、比赛、题单、用户列表的「选项」列固定在右侧,不再被挤出屏幕 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
107 lines
2.9 KiB
Vue
107 lines
2.9 KiB
Vue
<script setup lang="ts">
|
|
import PageHeader from "admin/components/PageHeader.vue"
|
|
import { NSwitch } from "naive-ui"
|
|
import Pagination from "shared/components/Pagination.vue"
|
|
import { parseTime } from "utils/functions"
|
|
import type { AdminAnnouncementListItem } from "utils/types"
|
|
import { editAnnouncement, getAnnouncement, getAnnouncementList } from "../api"
|
|
import Actions from "./components/Actions.vue"
|
|
|
|
const message = useMessage()
|
|
const total = ref(0)
|
|
const query = reactive({
|
|
limit: 10,
|
|
page: 1,
|
|
})
|
|
const announcements = ref<AdminAnnouncementListItem[]>([])
|
|
|
|
const columns: DataTableColumn<AdminAnnouncementListItem>[] = [
|
|
{ title: "ID", key: "id", width: 60 },
|
|
{ title: "标题", key: "title", minWidth: 300 },
|
|
{ title: "标签", key: "tag", width: 80 },
|
|
{
|
|
title: "置顶",
|
|
key: "top",
|
|
render: (row) => (row.top ? "置顶" : ""),
|
|
width: 80,
|
|
},
|
|
{
|
|
title: "创建时间",
|
|
key: "createTime",
|
|
width: 180,
|
|
render: (row) => parseTime(row.createTime, "YYYY-MM-DD HH:mm:ss"),
|
|
},
|
|
{
|
|
title: "上次更新时间",
|
|
key: "lastUpdateTime",
|
|
width: 180,
|
|
render: (row) => parseTime(row.lastUpdateTime, "YYYY-MM-DD HH:mm:ss"),
|
|
},
|
|
{
|
|
title: "作者",
|
|
key: "createdBy",
|
|
render: (row) => row.createdBy.username,
|
|
width: 80,
|
|
},
|
|
{
|
|
title: "可见",
|
|
key: "visible",
|
|
render: (row) =>
|
|
h(NSwitch, {
|
|
value: row.visible,
|
|
size: "small",
|
|
rubberBand: false,
|
|
onUpdateValue: () => toggleVisible(row),
|
|
}),
|
|
},
|
|
{
|
|
title: "选项",
|
|
key: "actions",
|
|
width: 140,
|
|
render: (row) => h(Actions, { announcementID: row.id, onDeleted: listAnnouncements }),
|
|
},
|
|
]
|
|
|
|
// 列表响应不含 content(正文是 8MB 上限的富文本),而更新接口要求 content 必填 ——
|
|
// 拿列表里那行直接回传会 400。所以先取回整条再改。
|
|
async function toggleVisible(announcement: AdminAnnouncementListItem) {
|
|
const next = !announcement.visible
|
|
try {
|
|
const full = await getAnnouncement(announcement.id)
|
|
await editAnnouncement({
|
|
id: full.id,
|
|
title: full.title,
|
|
tag: full.tag,
|
|
content: full.content,
|
|
visible: next,
|
|
top: full.top,
|
|
})
|
|
announcement.visible = next
|
|
} catch {
|
|
message.error("修改可见性失败")
|
|
}
|
|
}
|
|
|
|
async function listAnnouncements() {
|
|
const offset = (query.page - 1) * query.limit
|
|
const res = await getAnnouncementList(offset, query.limit)
|
|
announcements.value = res.results
|
|
total.value = res.total
|
|
}
|
|
|
|
onMounted(listAnnouncements)
|
|
watch(query, listAnnouncements, { deep: true })
|
|
</script>
|
|
|
|
<template>
|
|
<PageHeader title="网站公告">
|
|
<template #actions>
|
|
<n-button type="primary" @click="$router.push({ name: 'admin announcement create' })">
|
|
新建公告
|
|
</n-button>
|
|
</template>
|
|
</PageHeader>
|
|
<n-data-table striped :columns="columns" :data="announcements" />
|
|
<Pagination :total="total" v-model:limit="query.limit" v-model:page="query.page" />
|
|
</template>
|