Compare commits

...

2 Commits

Author SHA1 Message Date
c4ac0f06cb fix
Some checks failed
Deploy / deploy (build, debian, 22, /root/OJDeploy/data/clientnext) (push) Has been cancelled
Deploy / deploy (build:staging, school, 8822, /root/OJ/data/dist) (push) Has been cancelled
2026-05-21 19:30:36 -06:00
776cfdf9de feat: add contest clone button to admin contest list 2026-05-21 19:21:40 -06:00
4 changed files with 23 additions and 3 deletions

View File

@@ -160,6 +160,10 @@ export function editContest(contest: Contest | BlankContest) {
return http.put("admin/contest", contest) return http.put("admin/contest", contest)
} }
export function cloneContest(contest_id: number) {
return http.post("admin/contest/clone", { contest_id })
}
export function getContest(id: string) { export function getContest(id: string) {
return http.get<Contest & { password: string }>("admin/contest", { return http.get<Contest & { password: string }>("admin/contest", {
params: { id }, params: { id },

View File

@@ -1,11 +1,13 @@
<script lang="ts" setup> <script lang="ts" setup>
import { Contest } from "utils/types" import { Contest } from "utils/types"
import { cloneContest } from "../../api"
interface Props { interface Props {
contest: Contest contest: Contest
} }
const props = defineProps<Props>() const props = defineProps<Props>()
const router = useRouter() const router = useRouter()
const message = useMessage()
function goEdit() { function goEdit() {
router.push({ router.push({
@@ -28,6 +30,19 @@ function goACMHelper() {
}) })
} }
async function clone() {
try {
const res = await cloneContest(props.contest.id)
message.success("复制成功")
router.push({
name: "admin contest edit",
params: { contestID: res.data.id },
})
} catch {
message.error("复制失败")
}
}
const isACM = computed(() => props.contest.rule_type === "ACM") const isACM = computed(() => props.contest.rule_type === "ACM")
</script> </script>
<template> <template>
@@ -47,6 +62,7 @@ const isACM = computed(() => props.contest.rule_type === "ACM")
<n-button size="small" type="info" secondary @click="goEdit"> <n-button size="small" type="info" secondary @click="goEdit">
编辑 编辑
</n-button> </n-button>
<n-button size="small" secondary @click="clone"> 复制 </n-button>
</n-flex> </n-flex>
</template> </template>
<style scoped></style> <style scoped></style>

View File

@@ -4,7 +4,7 @@ import ContestTitle from "shared/components/ContestTitle.vue"
import ContestType from "shared/components/ContestType.vue" import ContestType from "shared/components/ContestType.vue"
import Pagination from "shared/components/Pagination.vue" import Pagination from "shared/components/Pagination.vue"
import { CONTEST_STATUS } from "utils/constants" import { CONTEST_STATUS } from "utils/constants"
import { Contest } from "utils/types" import type { Contest } from "utils/types"
import { editContest, getContestList } from "../api" import { editContest, getContestList } from "../api"
import Actions from "./components/Actions.vue" import Actions from "./components/Actions.vue"
@@ -66,7 +66,7 @@ const columns: DataTableColumn<Contest>[] = [
{ {
title: "选项", title: "选项",
key: "actions", key: "actions",
width: 220, width: 260,
render: (row) => h(Actions, { contest: row }), render: (row) => h(Actions, { contest: row }),
}, },
] ]

View File

@@ -3,7 +3,7 @@ import { useRouteQuery } from "@vueuse/router"
import { NTag } from "naive-ui" import { NTag } from "naive-ui"
import { getContestList } from "oj/api" import { getContestList } from "oj/api"
import { duration, parseTime } from "utils/functions" import { duration, parseTime } from "utils/functions"
import { Contest } from "utils/types" import type { Contest } from "utils/types"
import ContestTitle from "shared/components/ContestTitle.vue" import ContestTitle from "shared/components/ContestTitle.vue"
import Pagination from "shared/components/Pagination.vue" import Pagination from "shared/components/Pagination.vue"
import { useAuthModalStore } from "shared/store/authModal" import { useAuthModalStore } from "shared/store/authModal"