后台题单接口下发的是扁平结构(displayId / title / isRequired),前端却按前台 题单页的嵌套结构取值,naive-ui 的 key 也不解析点号路径,于是「题目ID」「题目 标题」两列永远是空的。同一处还连累了另外几个操作: - 编辑题目弹窗读 problem.problem.title,点「编辑」直接抛错; - 添加题目发 problem_id / is_required,api 层取 problemId,出站是 undefined, 被后端按参数错误 400 掉; - 编辑题目发 is_required,「必做」怎么改都不生效; - 新建/编辑奖章发 condition_type,toBadgeBody 读 conditionType,同样 400。 根因是 admin/api.ts 把这批后台接口的返回值标成了 oj 侧的 ProblemSet / ProblemSetBadge / ProblemSetProblem,加上 detail.vue 四个 handler 用 data: any 接弹窗数据,字段拼错编译器一句都不吭。现在返回值全部换成 Admin* 契约类型, handler 换成 AddProblemToSetRequest / UpdateProblemInSetRequest 和一个本地 BadgeFormData(条件类型是「完成所有题目」时不带 conditionValue,后端补 0), 两个奖章弹窗里的 const data: any 也一并拆掉。 验证:dev 栈实跑,列表两列有值、编辑弹窗正常打开、加题 / 改必做 / 建奖章 / 改奖章四条链路走完界面都成功落库;bun run type-check 通过。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011WmMi9tPrnSAwwAy2i4WAa
This commit is contained in:
@@ -38,10 +38,10 @@ import type {
|
|||||||
Tutorial,
|
Tutorial,
|
||||||
User,
|
User,
|
||||||
WebsiteConfig,
|
WebsiteConfig,
|
||||||
ProblemSet,
|
AdminProblemSetBadge,
|
||||||
ProblemSetBadge,
|
AdminProblemSetList,
|
||||||
ProblemSetList,
|
AdminProblemSet,
|
||||||
ProblemSetProblem,
|
AdminProblemSetProblem,
|
||||||
TutorialListItem,
|
TutorialListItem,
|
||||||
} from "utils/types"
|
} from "utils/types"
|
||||||
|
|
||||||
@@ -498,20 +498,20 @@ export function getProblemSetList(
|
|||||||
difficulty = "",
|
difficulty = "",
|
||||||
status = "",
|
status = "",
|
||||||
) {
|
) {
|
||||||
return api.get<ProblemSetList>("admin/problem-sets", {
|
return api.get<AdminProblemSetList>("admin/problem-sets", {
|
||||||
params: { offset, limit, keyword, difficulty, status },
|
params: { offset, limit, keyword, difficulty, status },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getProblemSetDetail(id: number) {
|
export function getProblemSetDetail(id: number) {
|
||||||
return api.get<ProblemSet>(`admin/problem-sets/${id}`)
|
return api.get<AdminProblemSet>(`admin/problem-sets/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProblemSetBody {
|
interface ProblemSetBody {
|
||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
difficulty?: ProblemSet["difficulty"]
|
difficulty?: AdminProblemSet["difficulty"]
|
||||||
status?: ProblemSet["status"]
|
status?: AdminProblemSet["status"]
|
||||||
// 表单里是 Date,出站要 ISO 串
|
// 表单里是 Date,出站要 ISO 串
|
||||||
endTime?: Date | null
|
endTime?: Date | null
|
||||||
visible?: boolean
|
visible?: boolean
|
||||||
@@ -529,11 +529,11 @@ function toProblemSetBody(data: ProblemSetBody) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createProblemSet(data: ProblemSetBody) {
|
export function createProblemSet(data: ProblemSetBody) {
|
||||||
return api.post<ProblemSet>("admin/problem-sets", toProblemSetBody(data))
|
return api.post<AdminProblemSet>("admin/problem-sets", toProblemSetBody(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function editProblemSet(data: ProblemSetBody & { id: number }) {
|
export function editProblemSet(data: ProblemSetBody & { id: number }) {
|
||||||
return api.put<ProblemSet>(
|
return api.put<AdminProblemSet>(
|
||||||
`admin/problem-sets/${data.id}`,
|
`admin/problem-sets/${data.id}`,
|
||||||
toProblemSetBody(data),
|
toProblemSetBody(data),
|
||||||
)
|
)
|
||||||
@@ -544,16 +544,16 @@ export function deleteProblemSet(id: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function toggleProblemSetVisible(id: number) {
|
export function toggleProblemSetVisible(id: number) {
|
||||||
return api.put<ProblemSet>(`admin/problem-sets/${id}/visibility`)
|
return api.put<AdminProblemSet>(`admin/problem-sets/${id}/visibility`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateProblemSetStatus(id: number, status: string) {
|
export function updateProblemSetStatus(id: number, status: string) {
|
||||||
return api.put<ProblemSet>(`admin/problem-sets/${id}/status`, { status })
|
return api.put<AdminProblemSet>(`admin/problem-sets/${id}/status`, { status })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 题单题目管理 API
|
// 题单题目管理 API
|
||||||
export function getProblemSetProblems(problemSetId: number) {
|
export function getProblemSetProblems(problemSetId: number) {
|
||||||
return api.get<ProblemSetProblem[]>(
|
return api.get<AdminProblemSetProblem[]>(
|
||||||
`admin/problem-sets/${problemSetId}/problems`,
|
`admin/problem-sets/${problemSetId}/problems`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -604,7 +604,7 @@ export function removeProblemFromSet(
|
|||||||
|
|
||||||
// 题单奖章管理 API
|
// 题单奖章管理 API
|
||||||
export function getProblemSetBadges(problemSetId: number) {
|
export function getProblemSetBadges(problemSetId: number) {
|
||||||
return api.get<ProblemSetBadge[]>(
|
return api.get<AdminProblemSetBadge[]>(
|
||||||
`admin/problem-sets/${problemSetId}/badges`,
|
`admin/problem-sets/${problemSetId}/badges`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -613,7 +613,7 @@ interface BadgeBody {
|
|||||||
name?: string
|
name?: string
|
||||||
description?: string
|
description?: string
|
||||||
icon?: string
|
icon?: string
|
||||||
conditionType?: ProblemSetBadge["conditionType"]
|
conditionType?: AdminProblemSetBadge["conditionType"]
|
||||||
conditionValue?: number
|
conditionValue?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,7 +628,7 @@ function toBadgeBody(data: BadgeBody) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createProblemSetBadge(problemSetId: number, data: BadgeBody) {
|
export function createProblemSetBadge(problemSetId: number, data: BadgeBody) {
|
||||||
return api.post<ProblemSetBadge>(
|
return api.post<AdminProblemSetBadge>(
|
||||||
`admin/problem-sets/${problemSetId}/badges`,
|
`admin/problem-sets/${problemSetId}/badges`,
|
||||||
toBadgeBody(data),
|
toBadgeBody(data),
|
||||||
)
|
)
|
||||||
@@ -639,7 +639,7 @@ export function editProblemSetBadge(
|
|||||||
badgeId: number,
|
badgeId: number,
|
||||||
data: BadgeBody,
|
data: BadgeBody,
|
||||||
) {
|
) {
|
||||||
return api.put<ProblemSetBadge>(
|
return api.put<AdminProblemSetBadge>(
|
||||||
`admin/problem-sets/${problemSetId}/badges/${badgeId}`,
|
`admin/problem-sets/${problemSetId}/badges/${badgeId}`,
|
||||||
toBadgeBody(data),
|
toBadgeBody(data),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ interface Emits {
|
|||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
icon: string
|
icon: string
|
||||||
condition_type: "all_problems" | "problem_count" | "score"
|
conditionType: "all_problems" | "problem_count" | "score"
|
||||||
condition_value?: number
|
conditionValue?: number
|
||||||
},
|
},
|
||||||
): void
|
): void
|
||||||
}
|
}
|
||||||
@@ -45,19 +45,16 @@ const conditionTypeOptions = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
const data: any = {
|
emit("confirm", {
|
||||||
name: newBadgeName.value,
|
name: newBadgeName.value,
|
||||||
description: newBadgeDescription.value,
|
description: newBadgeDescription.value,
|
||||||
icon: newBadgeIcon.value,
|
icon: newBadgeIcon.value,
|
||||||
condition_type: newBadgeConditionType.value,
|
conditionType: newBadgeConditionType.value,
|
||||||
}
|
// 只有非"完成所有题目"时才带条件值
|
||||||
|
...(newBadgeConditionType.value === "all_problems"
|
||||||
// 只有非"完成所有题目"时才添加条件值
|
? {}
|
||||||
if (newBadgeConditionType.value !== "all_problems") {
|
: { conditionValue: newBadgeConditionValue.value }),
|
||||||
data.conditionValue = newBadgeConditionValue.value
|
})
|
||||||
}
|
|
||||||
|
|
||||||
emit("confirm", data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCancel() {
|
function handleCancel() {
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ interface Emits {
|
|||||||
(
|
(
|
||||||
e: "confirm",
|
e: "confirm",
|
||||||
data: {
|
data: {
|
||||||
problem_id: string
|
problemId: string
|
||||||
order: number
|
order: number
|
||||||
is_required: boolean
|
isRequired: boolean
|
||||||
score: number
|
score: number
|
||||||
hint: string
|
hint: string
|
||||||
},
|
},
|
||||||
@@ -28,9 +28,9 @@ const newProblemHint = ref("")
|
|||||||
|
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
emit("confirm", {
|
emit("confirm", {
|
||||||
problem_id: newProblemId.value,
|
problemId: newProblemId.value,
|
||||||
order: newProblemOrder.value,
|
order: newProblemOrder.value,
|
||||||
is_required: newProblemRequired.value,
|
isRequired: newProblemRequired.value,
|
||||||
score: newProblemScore.value,
|
score: newProblemScore.value,
|
||||||
hint: newProblemHint.value,
|
hint: newProblemHint.value,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { h } from "vue"
|
import { h } from "vue"
|
||||||
import type { ProblemSetBadge } from "utils/types"
|
import type { AdminProblemSetBadge } from "utils/types"
|
||||||
import { NButton, NImage } from "naive-ui"
|
import { NButton, NImage } from "naive-ui"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
badges: ProblemSetBadge[]
|
badges: AdminProblemSetBadge[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
(e: "add-badge"): void
|
(e: "add-badge"): void
|
||||||
(e: "edit-badge", badge: ProblemSetBadge): void
|
(e: "edit-badge", badge: AdminProblemSetBadge): void
|
||||||
(e: "delete-badge", badgeId: number): void
|
(e: "delete-badge", badgeId: number): void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ProblemSetBadge } from "utils/types"
|
import type { AdminProblemSetBadge } from "utils/types"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
show: boolean
|
show: boolean
|
||||||
badge: ProblemSetBadge | null
|
badge: AdminProblemSetBadge | null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
@@ -14,8 +14,8 @@ interface Emits {
|
|||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
icon: string
|
icon: string
|
||||||
condition_type: "all_problems" | "problem_count" | "score"
|
conditionType: "all_problems" | "problem_count" | "score"
|
||||||
condition_value?: number
|
conditionValue?: number
|
||||||
},
|
},
|
||||||
): void
|
): void
|
||||||
}
|
}
|
||||||
@@ -49,19 +49,16 @@ const conditionTypeOptions = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
const data: any = {
|
emit("confirm", {
|
||||||
name: editBadgeName.value,
|
name: editBadgeName.value,
|
||||||
description: editBadgeDescription.value,
|
description: editBadgeDescription.value,
|
||||||
icon: editBadgeIcon.value,
|
icon: editBadgeIcon.value,
|
||||||
condition_type: editBadgeConditionType.value,
|
conditionType: editBadgeConditionType.value,
|
||||||
}
|
// 只有非"完成所有题目"时才带条件值
|
||||||
|
...(editBadgeConditionType.value === "all_problems"
|
||||||
// 只有非"完成所有题目"时才添加条件值
|
? {}
|
||||||
if (editBadgeConditionType.value !== "all_problems") {
|
: { conditionValue: editBadgeConditionValue.value }),
|
||||||
data.conditionValue = editBadgeConditionValue.value
|
})
|
||||||
}
|
|
||||||
|
|
||||||
emit("confirm", data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCancel() {
|
function handleCancel() {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ProblemSetProblem } from "utils/types"
|
import type { AdminProblemSetProblem } from "utils/types"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
show: boolean
|
show: boolean
|
||||||
problem: ProblemSetProblem | null
|
problem: AdminProblemSetProblem | null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
@@ -12,7 +12,7 @@ interface Emits {
|
|||||||
e: "confirm",
|
e: "confirm",
|
||||||
data: {
|
data: {
|
||||||
order: number
|
order: number
|
||||||
is_required: boolean
|
isRequired: boolean
|
||||||
score: number
|
score: number
|
||||||
hint: string
|
hint: string
|
||||||
},
|
},
|
||||||
@@ -30,7 +30,7 @@ const editProblemHint = ref("")
|
|||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
emit("confirm", {
|
emit("confirm", {
|
||||||
order: editProblemOrder.value,
|
order: editProblemOrder.value,
|
||||||
is_required: editProblemRequired.value,
|
isRequired: editProblemRequired.value,
|
||||||
score: editProblemScore.value,
|
score: editProblemScore.value,
|
||||||
hint: editProblemHint.value || "",
|
hint: editProblemHint.value || "",
|
||||||
})
|
})
|
||||||
@@ -65,7 +65,7 @@ watch(
|
|||||||
>
|
>
|
||||||
<n-form v-if="problem">
|
<n-form v-if="problem">
|
||||||
<n-form-item label="题目标题">
|
<n-form-item label="题目标题">
|
||||||
<n-input :value="problem.problem.title" disabled />
|
<n-input :value="problem.title" disabled />
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item label="顺序">
|
<n-form-item label="顺序">
|
||||||
<n-input-number
|
<n-input-number
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { h } from "vue"
|
import { h } from "vue"
|
||||||
import { NDataTable, NButton, NFlex } from "naive-ui"
|
import { NDataTable, NButton, NFlex } from "naive-ui"
|
||||||
import type { ProblemSetProblem } from "utils/types"
|
import type { AdminProblemSetProblem } from "utils/types"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
problems: ProblemSetProblem[]
|
problems: AdminProblemSetProblem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
(e: "add-problem"): void
|
(e: "add-problem"): void
|
||||||
(e: "edit-problem", problem: ProblemSetProblem): void
|
(e: "edit-problem", problem: AdminProblemSetProblem): void
|
||||||
(e: "remove-problem", problemSetProblemId: number): void
|
(e: "remove-problem", problemSetProblemId: number): void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,12 +27,12 @@ defineEmits<Emits>()
|
|||||||
</n-flex>
|
</n-flex>
|
||||||
<n-data-table
|
<n-data-table
|
||||||
:columns="[
|
:columns="[
|
||||||
{ title: '题目ID', key: 'problem._id', width: 80 },
|
{ title: '题目ID', key: 'displayId', width: 80 },
|
||||||
{ title: '题目标题', key: 'problem.title', minWidth: 200 },
|
{ title: '题目标题', key: 'title', minWidth: 200 },
|
||||||
{ title: '顺序', key: 'order', width: 80 },
|
{ title: '顺序', key: 'order', width: 80 },
|
||||||
{
|
{
|
||||||
title: '必做',
|
title: '必做',
|
||||||
key: 'is_required',
|
key: 'isRequired',
|
||||||
width: 80,
|
width: 80,
|
||||||
render: (row) => (row.isRequired ? '是' : '否'),
|
render: (row) => (row.isRequired ? '是' : '否'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { parseTime } from "utils/functions"
|
import { parseTime } from "utils/functions"
|
||||||
import type { ProblemSet } from "utils/types"
|
import type { AdminProblemSet } from "utils/types"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
problemSet: ProblemSet
|
problemSet: AdminProblemSet
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>()
|
defineProps<Props>()
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { NTabPane, NTabs, NButton, NFlex } from "naive-ui"
|
import { NTabPane, NTabs, NButton, NFlex } from "naive-ui"
|
||||||
import type {
|
import type {
|
||||||
ProblemSet,
|
AdminProblemSet,
|
||||||
ProblemSetProblem,
|
AdminProblemSetProblem,
|
||||||
ProblemSetBadge,
|
AddProblemToSetRequest,
|
||||||
|
UpdateProblemInSetRequest,
|
||||||
|
CreateProblemSetBadgeRequest,
|
||||||
|
AdminProblemSetBadge,
|
||||||
AdminProblemSetProgress,
|
AdminProblemSetProgress,
|
||||||
} from "utils/types"
|
} from "utils/types"
|
||||||
import {
|
import {
|
||||||
@@ -32,11 +35,16 @@ const route = useRoute()
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
|
||||||
|
/** 奖章弹窗的表单值:条件类型是「完成所有题目」时不带 conditionValue,后端补 0 */
|
||||||
|
type BadgeFormData = Omit<CreateProblemSetBadgeRequest, "conditionValue"> & {
|
||||||
|
conditionValue?: number
|
||||||
|
}
|
||||||
|
|
||||||
const problemSetId = computed(() => Number(route.params.problemSetId))
|
const problemSetId = computed(() => Number(route.params.problemSetId))
|
||||||
|
|
||||||
const problemSet = ref<ProblemSet | null>(null)
|
const problemSet = ref<AdminProblemSet | null>(null)
|
||||||
const problems = ref<ProblemSetProblem[]>([])
|
const problems = ref<AdminProblemSetProblem[]>([])
|
||||||
const badges = ref<ProblemSetBadge[]>([])
|
const badges = ref<AdminProblemSetBadge[]>([])
|
||||||
const progress = ref<AdminProblemSetProgress[]>([])
|
const progress = ref<AdminProblemSetProgress[]>([])
|
||||||
|
|
||||||
// 模态框状态
|
// 模态框状态
|
||||||
@@ -46,8 +54,8 @@ const showAddBadgeModal = ref(false)
|
|||||||
const showEditBadgeModal = ref(false)
|
const showEditBadgeModal = ref(false)
|
||||||
|
|
||||||
// 编辑数据
|
// 编辑数据
|
||||||
const editingProblem = ref<ProblemSetProblem | null>(null)
|
const editingProblem = ref<AdminProblemSetProblem | null>(null)
|
||||||
const editingBadge = ref<ProblemSetBadge | null>(null)
|
const editingBadge = ref<AdminProblemSetBadge | null>(null)
|
||||||
|
|
||||||
async function loadProblemSetDetail() {
|
async function loadProblemSetDetail() {
|
||||||
try {
|
try {
|
||||||
@@ -85,7 +93,7 @@ async function loadProgress() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleAddProblem(data: any) {
|
async function handleAddProblem(data: AddProblemToSetRequest) {
|
||||||
try {
|
try {
|
||||||
await addProblemToSet(problemSetId.value, data)
|
await addProblemToSet(problemSetId.value, data)
|
||||||
message.success("题目添加成功")
|
message.success("题目添加成功")
|
||||||
@@ -108,7 +116,7 @@ async function handleRemoveProblem(problemSetProblemId: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleEditProblem(data: any) {
|
async function handleEditProblem(data: UpdateProblemInSetRequest) {
|
||||||
if (!editingProblem.value) return
|
if (!editingProblem.value) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -121,7 +129,7 @@ async function handleEditProblem(data: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleAddBadge(data: any) {
|
async function handleAddBadge(data: BadgeFormData) {
|
||||||
try {
|
try {
|
||||||
await createProblemSetBadge(problemSetId.value, data)
|
await createProblemSetBadge(problemSetId.value, data)
|
||||||
message.success("奖章创建成功")
|
message.success("奖章创建成功")
|
||||||
@@ -142,7 +150,7 @@ async function handleDeleteBadge(badgeId: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleEditBadge(data: any) {
|
async function handleEditBadge(data: BadgeFormData) {
|
||||||
if (!editingBadge.value) return
|
if (!editingBadge.value) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -173,12 +181,12 @@ function openAddBadgeModal() {
|
|||||||
showAddBadgeModal.value = true
|
showAddBadgeModal.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function openEditProblemModal(problem: ProblemSetProblem) {
|
function openEditProblemModal(problem: AdminProblemSetProblem) {
|
||||||
editingProblem.value = problem
|
editingProblem.value = problem
|
||||||
showEditProblemModal.value = true
|
showEditProblemModal.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function openEditBadgeModal(badge: ProblemSetBadge) {
|
function openEditBadgeModal(badge: AdminProblemSetBadge) {
|
||||||
editingBadge.value = badge
|
editingBadge.value = badge
|
||||||
showEditBadgeModal.value = true
|
showEditBadgeModal.value = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
import Pagination from "shared/components/Pagination.vue"
|
import Pagination from "shared/components/Pagination.vue"
|
||||||
import { usePagination } from "shared/composables/pagination"
|
import { usePagination } from "shared/composables/pagination"
|
||||||
import { parseTime } from "utils/functions"
|
import { parseTime } from "utils/functions"
|
||||||
import type { ProblemSet } from "utils/types"
|
import type { AdminProblemSet } from "utils/types"
|
||||||
import { getProblemSetList, toggleProblemSetVisible } from "../api"
|
import { getProblemSetList, toggleProblemSetVisible } from "../api"
|
||||||
import Actions from "./components/Actions.vue"
|
import Actions from "./components/Actions.vue"
|
||||||
import { NTag, NSwitch } from "naive-ui"
|
import { NTag, NSwitch } from "naive-ui"
|
||||||
|
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const problemSets = ref<ProblemSet[]>([])
|
const problemSets = ref<AdminProblemSet[]>([])
|
||||||
|
|
||||||
interface ProblemSetQuery {
|
interface ProblemSetQuery {
|
||||||
keyword: string
|
keyword: string
|
||||||
@@ -37,7 +37,7 @@ const statusOptions = [
|
|||||||
{ label: "草稿", value: "draft" },
|
{ label: "草稿", value: "draft" },
|
||||||
]
|
]
|
||||||
|
|
||||||
const columns: DataTableColumn<ProblemSet>[] = [
|
const columns: DataTableColumn<AdminProblemSet>[] = [
|
||||||
{ title: "ID", key: "id", width: 80 },
|
{ title: "ID", key: "id", width: 80 },
|
||||||
{ title: "标题", key: "title", minWidth: 200 },
|
{ title: "标题", key: "title", minWidth: 200 },
|
||||||
{ title: "描述", key: "description", minWidth: 300, ellipsis: true },
|
{ title: "描述", key: "description", minWidth: 300, ellipsis: true },
|
||||||
|
|||||||
@@ -408,6 +408,13 @@ export type {
|
|||||||
AcmHelperItem,
|
AcmHelperItem,
|
||||||
AdminContestList,
|
AdminContestList,
|
||||||
AdminProblemSetProgress,
|
AdminProblemSetProgress,
|
||||||
|
AdminProblemSetProblem,
|
||||||
|
AdminProblemSet,
|
||||||
|
AdminProblemSetList,
|
||||||
|
AdminProblemSetBadge,
|
||||||
|
AddProblemToSetRequest,
|
||||||
|
UpdateProblemInSetRequest,
|
||||||
|
CreateProblemSetBadgeRequest,
|
||||||
AdminAiReport,
|
AdminAiReport,
|
||||||
AdminAiReportListItem,
|
AdminAiReportListItem,
|
||||||
AdminAiReportList,
|
AdminAiReportList,
|
||||||
|
|||||||
Reference in New Issue
Block a user