edit problem.

This commit is contained in:
2023-03-29 20:56:00 +08:00
parent 0ef36abb13
commit c97b2c4879
5 changed files with 124 additions and 51 deletions

View File

@@ -1,7 +1,7 @@
import http from "utils/http" import http from "utils/http"
import { import {
AdminProblem,
BlankProblem, BlankProblem,
Problem,
TestcaseUploadedReturns, TestcaseUploadedReturns,
User, User,
} from "~/utils/types" } from "~/utils/types"
@@ -21,7 +21,7 @@ export async function getProblemList(
params: { paging: true, offset, limit, keyword, contest_id: contestID }, params: { paging: true, offset, limit, keyword, contest_id: contestID },
}) })
return { return {
results: res.data.results.map((result: Problem) => ({ results: res.data.results.map((result: AdminProblem) => ({
id: result.id, id: result.id,
_id: result._id, _id: result._id,
title: result.title, title: result.title,
@@ -41,16 +41,16 @@ export function deleteContestProblem(id: number) {
return http.delete("admin/contest/problem", { params: { id } }) return http.delete("admin/contest/problem", { params: { id } })
} }
export function editProblem(problem: Problem | BlankProblem) { export function editProblem(problem: AdminProblem | BlankProblem) {
return http.put("admin/problem", problem) return http.put("admin/problem", problem)
} }
export function editContestProblem(problem: Problem | BlankProblem) { export function editContestProblem(problem: AdminProblem | BlankProblem) {
return http.put("admin/contest/problem", problem) return http.put("admin/contest/problem", problem)
} }
export function getProblem(id: number) { export function getProblem(id: string | number) {
return http.get("admin/problem", { params: { id } }) return http.get<AdminProblem>("admin/problem", { params: { id } })
} }
export function getContestProblem(id: number) { export function getContestProblem(id: number) {

View File

@@ -43,6 +43,7 @@ function goEdit() {
<n-button size="small" secondary type="primary" @click="goEdit"> <n-button size="small" secondary type="primary" @click="goEdit">
编辑 编辑
</n-button> </n-button>
<n-button size="small" secondary type="info">查看</n-button>
<n-popconfirm @positive-click="handleDeleteProblem"> <n-popconfirm @positive-click="handleDeleteProblem">
<template #trigger> <template #trigger>
<n-button secondary size="small" type="error">删除</n-button> <n-button secondary size="small" type="error">删除</n-button>

View File

@@ -13,10 +13,12 @@ import {
createProblem, createProblem,
editContestProblem, editContestProblem,
editProblem, editProblem,
getProblem,
uploadTestcases, uploadTestcases,
} from "../api" } from "../api"
interface Props { interface Props {
problemID?: string
contestID?: string contestID?: string
} }
@@ -66,7 +68,8 @@ const currentActiveTemplate = ref<LANGUAGE>("C")
const existingTags = shallowRef<Tag[]>([]) const existingTags = shallowRef<Tag[]>([])
const fromExistingTags = shallowRef<string[]>([]) const fromExistingTags = shallowRef<string[]>([])
const newTags = shallowRef<string[]>([]) const newTags = shallowRef<string[]>([])
const [needTemplate] = useToggle(false) const [needTemplate, toggleNeedTemplate] = useToggle(false)
const [ready, toggleReady] = useToggle(false)
const difficultyOptions: SelectOption[] = [ const difficultyOptions: SelectOption[] = [
{ label: "简单", value: "Low" }, { label: "简单", value: "Low" },
@@ -87,6 +90,53 @@ const tagOptions = computed(() =>
existingTags.value.map((tag) => ({ label: tag.name, value: tag.name })) existingTags.value.map((tag) => ({ label: tag.name, value: tag.name }))
) )
async function getProblemDetail() {
if (!props.problemID) return
const { data } = await getProblem(props.problemID)
toggleReady(true)
problem.id = data.id
problem._id = data._id
problem.title = data.title
problem.description = data.description
problem.input_description = data.input_description
problem.output_description = data.output_description
problem.time_limit = data.time_limit
problem.memory_limit = data.memory_limit
problem.memory_limit = data.memory_limit
problem.difficulty = data.difficulty
problem.visible = data.visible
problem.share_submission = data.share_submission
problem.tags = data.tags
problem.languages = data.languages
problem.template = data.template
problem.samples = data.samples
problem.samples = data.samples
problem.spj = data.spj
problem.spj_language = data.spj_language
problem.spj_code = data.spj_code
problem.spj_compile_ok = data.spj_compile_ok
problem.test_case_id = data.test_case_id
problem.test_case_score = data.test_case_score
problem.rule_type = data.rule_type
problem.hint = data.hint
problem.source = data.source
problem.io_mode = data.io_mode
if (problem.contest_id) {
problem.contest_id = problem.contest_id
}
// 下面是用来显示的:
// 代码模板 和 模板开关
problem.languages.forEach((lang) => {
if (data.template[lang]) {
template[lang] = data.template[lang]
toggleNeedTemplate(true)
}
})
// 标签
fromExistingTags.value = data.tags
}
async function listTags() { async function listTags() {
const res = await getProblemTagList() const res = await getProblemTagList()
existingTags.value = res.data existingTags.value = res.data
@@ -145,6 +195,7 @@ async function handleUploadTestcases({ file }: UploadCustomRequestOptions) {
// TODO: 还没有完成 // TODO: 还没有完成
function downloadTestcases() {} function downloadTestcases() {}
// 题目是否有漏写的
function detectProblemCompletion() { function detectProblemCompletion() {
let flag = false let flag = false
// 标题 // 标题
@@ -229,7 +280,12 @@ async function submit() {
} }
try { try {
await api!(problem) await api!(problem)
message.success("恭喜你 💐 出题成功") if (
route.name === "admin problem create" ||
route.name === "admin contest problem create"
) {
message.success("恭喜你 💐 出题成功")
}
if ( if (
route.name === "admin problem create" || route.name === "admin problem create" ||
route.name === "admin problem edit" route.name === "admin problem edit"
@@ -252,6 +308,14 @@ async function submit() {
onMounted(() => { onMounted(() => {
listTags() listTags()
getProblemDetail()
if (
route.name === "admin problem create" ||
route.name === "admin contest problem create"
) {
toggleReady(true)
}
}) })
watch([fromExistingTags, newTags], (tags) => { watch([fromExistingTags, newTags], (tags) => {
@@ -293,12 +357,21 @@ watch([fromExistingTags, newTags], (tags) => {
</n-form-item> </n-form-item>
</n-form> </n-form>
<TextEditor <TextEditor
v-if="ready"
v-model:value="problem.description" v-model:value="problem.description"
title="题目本体" title="题目本体"
:min-height="300" :min-height="300"
/> />
<TextEditor v-model:value="problem.input_description" title="输入的描述" /> <TextEditor
<TextEditor v-model:value="problem.output_description" title="输出的描述" /> v-if="ready"
v-model:value="problem.input_description"
title="输入的描述"
/>
<TextEditor
v-if="ready"
v-model:value="problem.output_description"
title="输出的描述"
/>
<div class="box" v-for="(sample, index) in problem.samples" :key="index"> <div class="box" v-for="(sample, index) in problem.samples" :key="index">
<n-space justify="space-between" align="center"> <n-space justify="space-between" align="center">
<strong>测试样例 {{ index + 1 }}</strong> <strong>测试样例 {{ index + 1 }}</strong>
@@ -329,7 +402,7 @@ watch([fromExistingTags, newTags], (tags) => {
<n-button class="addSamples box" tertiary type="primary" @click="addSample"> <n-button class="addSamples box" tertiary type="primary" @click="addSample">
添加用例 添加用例
</n-button> </n-button>
<TextEditor v-model:value="problem.hint" title="提示" /> <TextEditor v-if="ready" v-model:value="problem.hint" title="提示" />
<n-form> <n-form>
<n-form-item label="题目的来源"> <n-form-item label="题目的来源">
<n-input <n-input

View File

@@ -44,7 +44,7 @@ const columns: DataTableColumn<AdminProblemFiltered>[] = [
{ {
title: "选项", title: "选项",
key: "actions", key: "actions",
width: 200, width: 250,
render: (row) => render: (row) =>
h(Actions, { h(Actions, {
problemID: row.id, problemID: row.id,

View File

@@ -72,6 +72,18 @@ export interface Tag {
name: string name: string
} }
export interface TestcaseUploadedReturns {
id: string
info: Testcase[]
spj: boolean
}
export interface Testcase {
input_name: string
output_name: string
score: string
}
export interface Problem { export interface Problem {
_id: string _id: string
id: number id: number
@@ -112,6 +124,32 @@ export interface Problem {
visible: boolean visible: boolean
} }
export type AdminProblem = Problem & AlterProblem
interface AlterProblem {
spj_language: string
spj_code: string
spj_compile_ok: boolean
test_case_id: string
test_case_score: Testcase[]
contest_id?: string
}
type ExcludeKeys =
| "id"
| "created_by"
| "create_time"
| "last_update_time"
| "my_status"
| "contest"
| "statistic_info"
| "accepted_number"
| "submission_number"
| "total_score"
export type BlankProblem = Omit<Problem, ExcludeKeys> &
AlterProblem & { id?: number }
export interface ProblemFiltered { export interface ProblemFiltered {
_id: string _id: string
id: number id: number
@@ -262,42 +300,3 @@ export interface ContestRank {
submission_info: { [key: string]: SubmissionInfo } submission_info: { [key: string]: SubmissionInfo }
contest: number contest: number
} }
export interface TestcaseUploadedReturns {
id: string
info: Testcase[]
spj: boolean
}
export interface Testcase {
stripped_output_md5: string
input_size: number
output_size: number
input_name: string
output_name: string
score?: string
}
interface AlterProblem {
spj_language: string
spj_code: string
spj_compile_ok: boolean
test_case_id: string
test_case_score: Testcase[]
contest_id?: string
}
type ExcludeKeys =
| "id"
| "created_by"
| "create_time"
| "last_update_time"
| "my_status"
| "contest"
| "statistic_info"
| "accepted_number"
| "submission_number"
| "total_score"
export type BlankProblem = Omit<Problem, ExcludeKeys> &
AlterProblem & { id?: number }