|
@@ -36,7 +36,6 @@
|
|
|
>
|
|
>
|
|
|
<template #columns>
|
|
<template #columns>
|
|
|
<a-table-column title="ID" data-index="id" :width="80" />
|
|
<a-table-column title="ID" data-index="id" :width="80" />
|
|
|
- <a-table-column title="备注" data-index="name" :width="140" ellipsis tooltip />
|
|
|
|
|
<a-table-column title="学号" data-index="student_num" :width="130" />
|
|
<a-table-column title="学号" data-index="student_num" :width="130" />
|
|
|
<a-table-column title="选课批次" :width="220" ellipsis tooltip>
|
|
<a-table-column title="选课批次" :width="220" ellipsis tooltip>
|
|
|
<template #cell="{ record }">
|
|
<template #cell="{ record }">
|
|
@@ -59,10 +58,13 @@
|
|
|
<a-table-column title="结果" :width="220" ellipsis tooltip>
|
|
<a-table-column title="结果" :width="220" ellipsis tooltip>
|
|
|
<template #cell="{ record }">{{ resultText(record) }}</template>
|
|
<template #cell="{ record }">{{ resultText(record) }}</template>
|
|
|
</a-table-column>
|
|
</a-table-column>
|
|
|
|
|
+ <a-table-column title="备注" :width="140" ellipsis tooltip>
|
|
|
|
|
+ <template #cell="{ record }">{{ record.name || '-' }}</template>
|
|
|
|
|
+ </a-table-column>
|
|
|
<a-table-column title="更新时间" :width="180">
|
|
<a-table-column title="更新时间" :width="180">
|
|
|
<template #cell="{ record }">{{ formatTime(record.update_time) }}</template>
|
|
<template #cell="{ record }">{{ formatTime(record.update_time) }}</template>
|
|
|
</a-table-column>
|
|
</a-table-column>
|
|
|
- <a-table-column title="操作" :width="220" :fixed="tableFixed('right')">
|
|
|
|
|
|
|
+ <a-table-column title="操作" :width="280" :fixed="tableFixed('right')">
|
|
|
<template #cell="{ record }">
|
|
<template #cell="{ record }">
|
|
|
<a-space wrap>
|
|
<a-space wrap>
|
|
|
<a-button
|
|
<a-button
|
|
@@ -84,6 +86,7 @@
|
|
|
暂停
|
|
暂停
|
|
|
</a-button>
|
|
</a-button>
|
|
|
<a-button v-if="canSubmit" type="text" size="small" :disabled="!canEdit(record)" @click="openModal(record)">编辑</a-button>
|
|
<a-button v-if="canSubmit" type="text" size="small" :disabled="!canEdit(record)" @click="openModal(record)">编辑</a-button>
|
|
|
|
|
+ <a-button v-if="canSubmit" type="text" size="small" @click="copyTask(record)">复制</a-button>
|
|
|
<a-popconfirm v-if="canSubmit" content="确认取消该抢课任务?" @ok="cancelTask(record)">
|
|
<a-popconfirm v-if="canSubmit" content="确认取消该抢课任务?" @ok="cancelTask(record)">
|
|
|
<a-button type="text" status="danger" size="small" :disabled="!canCancel(record)">取消</a-button>
|
|
<a-button type="text" status="danger" size="small" :disabled="!canCancel(record)">取消</a-button>
|
|
|
</a-popconfirm>
|
|
</a-popconfirm>
|
|
@@ -101,16 +104,25 @@
|
|
|
|
|
|
|
|
<a-modal
|
|
<a-modal
|
|
|
v-model:visible="visible"
|
|
v-model:visible="visible"
|
|
|
- :title="form.id ? '编辑抢课任务' : '提交抢课任务'"
|
|
|
|
|
|
|
+ :title="modalTitle"
|
|
|
:width="isMobile ? '100%' : '720px'"
|
|
:width="isMobile ? '100%' : '720px'"
|
|
|
draggable
|
|
draggable
|
|
|
esc-to-close
|
|
esc-to-close
|
|
|
:ok-loading="saving"
|
|
:ok-loading="saving"
|
|
|
:on-before-ok="submitTask"
|
|
:on-before-ok="submitTask"
|
|
|
>
|
|
>
|
|
|
|
|
+ <a-spin :loading="detailLoading" style="width: 100%">
|
|
|
<a-form :model="form" layout="vertical" class="task-form">
|
|
<a-form :model="form" layout="vertical" class="task-form">
|
|
|
- <a-form-item label="备注名" required>
|
|
|
|
|
- <a-input v-model="form.name" placeholder="例如:张三选修课" allow-clear />
|
|
|
|
|
|
|
+ <a-form-item label="备注">
|
|
|
|
|
+ <a-textarea
|
|
|
|
|
+ v-model="form.name"
|
|
|
|
|
+ no-trim
|
|
|
|
|
+ placeholder="添加对任务的备注(非必填)"
|
|
|
|
|
+ :max-length="{ length: 50 }"
|
|
|
|
|
+ allow-clear
|
|
|
|
|
+ show-word-limit
|
|
|
|
|
+ :auto-size="{ minRows: 2, maxRows: 4 }"
|
|
|
|
|
+ />
|
|
|
</a-form-item>
|
|
</a-form-item>
|
|
|
<a-form-item label="选课批次" required>
|
|
<a-form-item label="选课批次" required>
|
|
|
<a-select v-model="form.batch_id" placeholder="请选择抢课批次" allow-clear allow-search>
|
|
<a-select v-model="form.batch_id" placeholder="请选择抢课批次" allow-clear allow-search>
|
|
@@ -127,7 +139,7 @@
|
|
|
</a-col>
|
|
</a-col>
|
|
|
<a-col :xs="24" :sm="12">
|
|
<a-col :xs="24" :sm="12">
|
|
|
<a-form-item label="教务密码" :required="!form.id">
|
|
<a-form-item label="教务密码" :required="!form.id">
|
|
|
- <a-input-password v-model="form.password" :placeholder="form.id ? '不填则不修改' : '请输入教务密码'" />
|
|
|
|
|
|
|
+ <a-input-password v-model="form.password" :placeholder="passwordPlaceholder" />
|
|
|
</a-form-item>
|
|
</a-form-item>
|
|
|
</a-col>
|
|
</a-col>
|
|
|
</a-row>
|
|
</a-row>
|
|
@@ -152,14 +164,15 @@
|
|
|
</a-col>
|
|
</a-col>
|
|
|
</a-row>
|
|
</a-row>
|
|
|
</a-form>
|
|
</a-form>
|
|
|
|
|
+ </a-spin>
|
|
|
</a-modal>
|
|
</a-modal>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
import { reactive, ref, onMounted, onUnmounted, computed } from 'vue'
|
|
import { reactive, ref, onMounted, onUnmounted, computed } from 'vue'
|
|
|
-import { Notification, Modal } from '@arco-design/web-vue'
|
|
|
|
|
-import { getQkTask, saveQkTask, deleteQkTask, startQkTask, pauseQkTask, getQkBatchList } from '@/api/qk'
|
|
|
|
|
|
|
+import { Notification } from '@arco-design/web-vue'
|
|
|
|
|
+import { getQkTask, getQkTaskDetail, saveQkTask, deleteQkTask, startQkTask, pauseQkTask, getQkBatchList } from '@/api/qk'
|
|
|
import { useResponsiveTable } from '@/hooks/useResponsiveTable'
|
|
import { useResponsiveTable } from '@/hooks/useResponsiveTable'
|
|
|
import { hasAnyPermission, QK_ASSISTANT_CONTROL_CODES, QK_ASSISTANT_SUBMIT_CODES } from '@/utils/permission'
|
|
import { hasAnyPermission, QK_ASSISTANT_CONTROL_CODES, QK_ASSISTANT_SUBMIT_CODES } from '@/utils/permission'
|
|
|
import {
|
|
import {
|
|
@@ -175,7 +188,9 @@ const canControl = computed(() => hasAnyPermission(QK_ASSISTANT_CONTROL_CODES))
|
|
|
|
|
|
|
|
const loading = ref(false)
|
|
const loading = ref(false)
|
|
|
const saving = ref(false)
|
|
const saving = ref(false)
|
|
|
|
|
+const detailLoading = ref(false)
|
|
|
const visible = ref(false)
|
|
const visible = ref(false)
|
|
|
|
|
+const isCopy = ref(false)
|
|
|
const data = ref([])
|
|
const data = ref([])
|
|
|
const batchOptions = ref([])
|
|
const batchOptions = ref([])
|
|
|
const form = reactive({
|
|
const form = reactive({
|
|
@@ -195,6 +210,16 @@ const targetCount = computed(() => {
|
|
|
})
|
|
})
|
|
|
const minInterval = computed(() => getMinQkInterval(targetCount.value))
|
|
const minInterval = computed(() => getMinQkInterval(targetCount.value))
|
|
|
const targetHint = computed(() => getQkTargetHint(form.coursesText, form.courseGroupsText))
|
|
const targetHint = computed(() => getQkTargetHint(form.coursesText, form.courseGroupsText))
|
|
|
|
|
+const modalTitle = computed(() => {
|
|
|
|
|
+ if (form.id) return '编辑抢课任务'
|
|
|
|
|
+ if (isCopy.value) return '复制抢课任务'
|
|
|
|
|
+ return '提交抢课任务'
|
|
|
|
|
+})
|
|
|
|
|
+const passwordPlaceholder = computed(() => {
|
|
|
|
|
+ if (form.id) return '已自动填充,修改后保存将更新密码'
|
|
|
|
|
+ if (isCopy.value) return '已自动填充'
|
|
|
|
|
+ return '请输入教务密码'
|
|
|
|
|
+})
|
|
|
|
|
|
|
|
const splitLines = splitQkLines
|
|
const splitLines = splitQkLines
|
|
|
|
|
|
|
@@ -236,6 +261,7 @@ const canCancel = (record) => ['paused', 'pending', 'failed'].includes(record.st
|
|
|
const resultText = (record) => record.error_msg || record.result_json?.message || record.result_json?.course || '-'
|
|
const resultText = (record) => record.error_msg || record.result_json?.message || record.result_json?.course || '-'
|
|
|
|
|
|
|
|
const resetForm = () => {
|
|
const resetForm = () => {
|
|
|
|
|
+ isCopy.value = false
|
|
|
Object.assign(form, {
|
|
Object.assign(form, {
|
|
|
id: '',
|
|
id: '',
|
|
|
name: '',
|
|
name: '',
|
|
@@ -249,38 +275,63 @@ const resetForm = () => {
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const openModal = (record) => {
|
|
|
|
|
- resetForm()
|
|
|
|
|
- if (record) {
|
|
|
|
|
- Object.assign(form, {
|
|
|
|
|
- id: record.id,
|
|
|
|
|
- name: record.name,
|
|
|
|
|
- batch_id: record.batch_id || '',
|
|
|
|
|
- student_num: record.student_num,
|
|
|
|
|
- coursesText: (record.courses || []).join('\n'),
|
|
|
|
|
- courseGroupsText: (record.course_groups || []).join('\n'),
|
|
|
|
|
- enable_ggxxk: record.enable_ggxxk,
|
|
|
|
|
- interval_ms: record.interval_ms
|
|
|
|
|
- })
|
|
|
|
|
|
|
+const fillFormFromTask = (task, { copy = false } = {}) => {
|
|
|
|
|
+ Object.assign(form, {
|
|
|
|
|
+ id: copy ? '' : task.id,
|
|
|
|
|
+ name: task.name,
|
|
|
|
|
+ batch_id: task.batch_id || '',
|
|
|
|
|
+ student_num: task.student_num,
|
|
|
|
|
+ password: task.password || '',
|
|
|
|
|
+ coursesText: (task.courses || []).join('\n'),
|
|
|
|
|
+ courseGroupsText: (task.course_groups || []).join('\n'),
|
|
|
|
|
+ enable_ggxxk: task.enable_ggxxk,
|
|
|
|
|
+ interval_ms: task.interval_ms
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const loadTaskDetail = async (id) => {
|
|
|
|
|
+ const res = await getQkTaskDetail({ id })
|
|
|
|
|
+ if (!res || res.code !== 0) {
|
|
|
|
|
+ throw new Error(res?.msg || '获取任务详情失败')
|
|
|
}
|
|
}
|
|
|
- visible.value = true
|
|
|
|
|
|
|
+ const task = res.data?.task
|
|
|
|
|
+ if (!task) {
|
|
|
|
|
+ throw new Error('任务不存在')
|
|
|
|
|
+ }
|
|
|
|
|
+ return task
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const buildCopySnapshot = (validated) => ({
|
|
|
|
|
- name: validated.name,
|
|
|
|
|
- batch_id: validated.batch_id,
|
|
|
|
|
- student_num: validated.student_num,
|
|
|
|
|
- password: validated.password || '',
|
|
|
|
|
- coursesText: validated.courses.join('\n'),
|
|
|
|
|
- courseGroupsText: validated.courseGroups.join('\n'),
|
|
|
|
|
- enable_ggxxk: form.enable_ggxxk,
|
|
|
|
|
- interval_ms: validated.intervalMs
|
|
|
|
|
-})
|
|
|
|
|
|
|
+const openModal = async (record) => {
|
|
|
|
|
+ resetForm()
|
|
|
|
|
+ visible.value = true
|
|
|
|
|
+ if (!record) return
|
|
|
|
|
+ try {
|
|
|
|
|
+ detailLoading.value = true
|
|
|
|
|
+ const task = await loadTaskDetail(record.id)
|
|
|
|
|
+ fillFormFromTask(task)
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ visible.value = false
|
|
|
|
|
+ Notification.error({ title: '获取任务详情失败', content: error.message || '请稍后再试' })
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ detailLoading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-const openModalFromSnapshot = (snapshot) => {
|
|
|
|
|
|
|
+const copyTask = async (record) => {
|
|
|
resetForm()
|
|
resetForm()
|
|
|
- Object.assign(form, snapshot)
|
|
|
|
|
|
|
+ isCopy.value = true
|
|
|
visible.value = true
|
|
visible.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ detailLoading.value = true
|
|
|
|
|
+ const task = await loadTaskDetail(record.id)
|
|
|
|
|
+ fillFormFromTask(task, { copy: true })
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ visible.value = false
|
|
|
|
|
+ isCopy.value = false
|
|
|
|
|
+ Notification.error({ title: '复制失败', content: error.message || '请稍后再试' })
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ detailLoading.value = false
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const loadBatches = async () => {
|
|
const loadBatches = async () => {
|
|
@@ -338,15 +389,8 @@ const submitTask = async () => {
|
|
|
Notification.error({ title: '保存抢课任务失败', content: res?.msg || '请稍后再试' })
|
|
Notification.error({ title: '保存抢课任务失败', content: res?.msg || '请稍后再试' })
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
|
- const snapshot = buildCopySnapshot(validated)
|
|
|
|
|
|
|
+ Notification.success({ title: '保存成功' })
|
|
|
await getList()
|
|
await getList()
|
|
|
- Modal.confirm({
|
|
|
|
|
- title: '保存成功',
|
|
|
|
|
- content: '是否复制此任务并继续提交新任务?',
|
|
|
|
|
- okText: '复制任务',
|
|
|
|
|
- cancelText: '关闭',
|
|
|
|
|
- onOk: () => openModalFromSnapshot(snapshot)
|
|
|
|
|
- })
|
|
|
|
|
return true
|
|
return true
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
Notification.error({ title: '保存抢课任务失败', content: error.message || '请稍后再试' })
|
|
Notification.error({ title: '保存抢课任务失败', content: error.message || '请稍后再试' })
|