update
Deploy / deploy (push) Canceled after 0s

This commit is contained in:
xuyue committed 2026-09-27 19:36:28 +08:00
1 parent 23844ae301
commit d25b5dbe6d
268 files changed
+3684 -8861

No files matched your search

@@ -62,15 +62,9 @@ async function handleUpdateStatus() {
<template>
<n-flex>
<n-button size="small" secondary type="primary" @click="goEdit">
编辑
</n-button>
<n-button size="small" secondary type="info" @click="goDetail">
详情
</n-button>
<n-button size="small" secondary type="warning" @click="openStatusModal">
状态
</n-button>
<n-button size="small" secondary type="primary" @click="goEdit"> 编辑 </n-button>
<n-button size="small" secondary type="info" @click="goDetail"> 详情 </n-button>
<n-button size="small" secondary type="warning" @click="openStatusModal"> 状态 </n-button>
<n-popconfirm @positive-click="handleDeleteProblemSet">
<template #trigger>
<n-button secondary size="small" type="error">删除</n-button>
@@ -79,20 +73,11 @@ async function handleUpdateStatus() {
</n-popconfirm>
</n-flex>
<n-modal
v-model:show="showStatusModal"
preset="card"
title="更新题单状态"
style="width: 400px"
>
<n-modal v-model:show="showStatusModal" preset="card" title="更新题单状态" style="width: 400px">
<n-space vertical>
<n-form>
<n-form-item label="状态" required>
<n-select
v-model:value="newStatus"
:options="statusOptions"
placeholder="选择状态"
/>
<n-select v-model:value="newStatus" :options="statusOptions" placeholder="选择状态" />
</n-form-item>
</n-form>
</n-space>
@@ -55,9 +55,7 @@ defineEmits<Emits>()
title: '条件值',
key: 'condition_value',
render: (row) => {
return row.conditionType === 'all_problems'
? '-'
: row.conditionValue
return row.conditionType === 'all_problems' ? '-' : row.conditionValue
},
},
{ title: '描述', key: 'description' },
@@ -28,9 +28,7 @@ const emit = defineEmits<Emits>()
const badgeName = ref("")
const badgeDescription = ref("")
const badgeIcon = ref("")
const badgeConditionType = ref<"all_problems" | "problem_count" | "score">(
"all_problems",
)
const badgeConditionType = ref<"all_problems" | "problem_count" | "score">("all_problems")
const badgeConditionValue = ref(1)
// 预设奖章图标选项
@@ -99,12 +97,7 @@ watch(
<n-input v-model:value="badgeName" placeholder="请输入奖章名称" />
</n-form-item>
<n-form-item label="描述">
<n-input
v-model:value="badgeDescription"
type="textarea"
placeholder="奖章描述"
required
/>
<n-input v-model:value="badgeDescription" type="textarea" placeholder="奖章描述" required />
</n-form-item>
<n-form-item label="图标" required>
<n-flex align="center" gap="small">
@@ -115,17 +108,13 @@ watch(
:style="{
width: '60px',
height: '60px',
border:
badgeIcon === option.value
? '2px solid #1890ff'
: '1px solid #d9d9d9',
border: badgeIcon === option.value ? '2px solid #1890ff' : '1px solid #d9d9d9',
borderRadius: '4px',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor:
badgeIcon === option.value ? '#f0f8ff' : 'transparent',
backgroundColor: badgeIcon === option.value ? '#f0f8ff' : 'transparent',
}"
>
<n-image
@@ -147,10 +136,7 @@ watch(
:options="conditionTypeOptions"
/>
</n-form-item>
<n-form-item
label="条件值"
v-if="badgeConditionType !== 'all_problems'"
>
<n-form-item label="条件值" v-if="badgeConditionType !== 'all_problems'">
<n-input-number
style="width: 120px"
v-model:value="badgeConditionValue"
@@ -21,9 +21,7 @@ defineEmits<Emits>()
<div>
<n-flex justify="space-between" align="center" style="margin-bottom: 16px">
<h3>题目列表</h3>
<n-button type="primary" @click="$emit('add-problem')">
添加题目
</n-button>
<n-button type="primary" @click="$emit('add-problem')"> 添加题目 </n-button>
</n-flex>
<n-data-table
:columns="[
@@ -75,16 +75,10 @@ watch(
<n-input :value="problem.title" disabled />
</n-form-item>
<n-form-item v-else label="题目ID" required>
<n-input
v-model:value="problemId"
placeholder="请输入题目的显示ID(如:1001)"
/>
<n-input v-model:value="problemId" placeholder="请输入题目的显示ID(如:1001)" />
</n-form-item>
<n-form-item label="顺序">
<n-input-number
v-model:value="problemOrder"
placeholder="题目在题单中的顺序"
/>
<n-input-number v-model:value="problemOrder" placeholder="题目在题单中的顺序" />
</n-form-item>
<n-form-item label="是否必做">
<n-switch v-model:value="problemRequired" />
@@ -93,11 +87,7 @@ watch(
<n-input-number v-model:value="problemScore" placeholder="题目分数" />
</n-form-item>
<n-form-item label="提示">
<n-input
v-model:value="problemHint"
type="textarea"
placeholder="题目提示"
/>
<n-input v-model:value="problemHint" type="textarea" placeholder="题目提示" />
</n-form-item>
</n-form>
<template #footer>
@@ -22,8 +22,7 @@ const progressColumns = [
title: "加入时间",
key: "joinTime",
width: 180,
render: (row: AdminProblemSetProgress) =>
parseTime(row.joinTime, "YYYY-MM-DD HH:mm:ss"),
render: (row: AdminProblemSetProgress) => parseTime(row.joinTime, "YYYY-MM-DD HH:mm:ss"),
},
{ title: "已完成", key: "completedProblemsCount", width: 100 },
{ title: "总题目", key: "totalProblemsCount", width: 100 },
@@ -31,8 +30,7 @@ const progressColumns = [
title: "进度",
key: "progressPercentage",
width: 100,
render: (row: AdminProblemSetProgress) =>
`${row.progressPercentage.toFixed(0)}%`,
render: (row: AdminProblemSetProgress) => `${row.progressPercentage.toFixed(0)}%`,
},
{
title: "是否完成",
+1 -4
View File
@@ -237,10 +237,7 @@ onMounted(() => {
</n-tab-pane>
<n-tab-pane name="progress" tab="进度管理">
<ProgressManagement
:progress="progress"
@remove-user="handleRemoveUser"
/>
<ProgressManagement :progress="progress" @remove-user="handleRemoveUser" />
</n-tab-pane>
</n-tabs>
+2 -9
View File
@@ -23,10 +23,7 @@ const formData = ref<CreateProblemSetData & Partial<EditProblemSetData>>({
// n-date-picker 按浏览器本地渲染,所以要平移一次再绑定(见 utils/functions.ts
// 的 toPickerValue)。`formData.endTime` 里始终存**真实时刻**,只有喂给选择器那一步换。
const endTimeTimestamp = computed({
get: () =>
formData.value.endTime
? toPickerValue(formData.value.endTime.getTime())
: null,
get: () => (formData.value.endTime ? toPickerValue(formData.value.endTime.getTime()) : null),
set: (val: number | null) => {
formData.value.endTime = val ? new Date(fromPickerValue(val)) : null
},
@@ -89,11 +86,7 @@ async function handleSubmit() {
}
router.push({ name: "admin problemset list" })
} catch (err) {
message.error(
(isEdit.value ? "更新" : "创建") +
"题单失败:" +
errorMessage(err, "未知错误"),
)
message.error((isEdit.value ? "更新" : "创建") + "题单失败:" + errorMessage(err, "未知错误"))
} finally {
loading.value = false
}
+5 -23
View File
@@ -58,11 +58,7 @@ const columns: DataTableColumn<AdminProblemSet>[] = [
Hard: { type: "error" as const, text: "困难" },
}
const config = difficultyMap[row.difficulty]
return h(
NTag,
{ type: config.type, size: "small" },
{ default: () => config.text },
)
return h(NTag, { type: config.type, size: "small" }, { default: () => config.text })
},
},
{
@@ -76,11 +72,7 @@ const columns: DataTableColumn<AdminProblemSet>[] = [
draft: { type: "info" as const, text: "草稿" },
}
const config = statusMap[row.status]
return h(
NTag,
{ type: config.type, size: "small" },
{ default: () => config.text },
)
return h(NTag, { type: config.type, size: "small" }, { default: () => config.text })
},
},
{
@@ -146,20 +138,14 @@ watchDebounced(() => query.keyword, listProblemSets, {
})
// 监听其他查询条件变化
watch(
() => [query.page, query.limit, query.difficulty, query.status],
listProblemSets,
)
watch(() => [query.page, query.limit, query.difficulty, query.status], listProblemSets)
</script>
<template>
<n-flex class="titleWrapper" justify="space-between">
<n-flex align="center">
<h2 class="title">题单管理</h2>
<n-button
type="primary"
@click="$router.push({ name: 'admin problemset create' })"
>
<n-button type="primary" @click="$router.push({ name: 'admin problemset create' })">
新建题单
</n-button>
</n-flex>
@@ -194,11 +180,7 @@ watch(
</n-flex>
</n-flex>
<n-data-table striped :columns="columns" :data="problemSets" />
<Pagination
:total="total"
v-model:limit="query.limit"
v-model:page="query.page"
/>
<Pagination :total="total" v-model:limit="query.limit" v-model:page="query.page" />
</template>
<style scoped>