优化毕业审核、学位审核
This commit is contained in:
1 parent
71ee21b063
commit
5dc1ae4e3a
19 files changed
+9645
-57
No files matched your search
@@ -1,7 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
|
||||
import { Check, Close, Medal, Plus, Refresh, Stamp } from '@element-plus/icons-vue'
|
||||
import { Check, Close, Download, Medal, Plus, Refresh, Stamp } from '@element-plus/icons-vue'
|
||||
import http, { apiErrorMessage } from '../api/http'
|
||||
import { downloadApiFile } from '../api/excel'
|
||||
import { useAuthStore } from '../stores/auth'
|
||||
|
||||
const auth = useAuthStore()
|
||||
@@ -17,6 +18,10 @@ const reviewDialog = ref(false)
|
||||
const reviewTarget = ref<any | null>(null)
|
||||
const keyword = ref('')
|
||||
const conclusionFilter = ref('')
|
||||
const majorId = ref('')
|
||||
const administrativeClassId = ref('')
|
||||
const majors = ref<any[]>([])
|
||||
const classes = ref<any[]>([])
|
||||
const resultPage = ref(1)
|
||||
const resultCursors = ref<string[]>([])
|
||||
const nextResultCursor = ref<string>()
|
||||
@@ -27,6 +32,7 @@ let filterTimer: ReturnType<typeof setTimeout> | undefined
|
||||
const batchForm = reactive({
|
||||
name: '2030届学士学位授予审核',
|
||||
graduationYear: 2030,
|
||||
enrollmentYear: 2026,
|
||||
degreeName: '工学学士',
|
||||
minimumGradePoint: 2,
|
||||
notes: '',
|
||||
@@ -52,7 +58,10 @@ async function load() {
|
||||
myResult.value = (await http.get('/degree-awards/my-result')).data
|
||||
return
|
||||
}
|
||||
batches.value = (await http.get('/degree-awards/batches')).data
|
||||
const [batchResponse, majorResponse, classResponse] = await Promise.all([
|
||||
http.get('/degree-awards/batches'), http.get('/base-data/majors'), http.get('/base-data/classes'),
|
||||
])
|
||||
batches.value = batchResponse.data; majors.value = majorResponse.data; classes.value = classResponse.data
|
||||
const batch = batches.value.find((x) => x.id === selected.value?.id) ?? batches.value[0]
|
||||
if (batch) await selectBatch(batch.id)
|
||||
else selected.value = null
|
||||
@@ -79,6 +88,8 @@ async function loadBatch(id = selected.value?.id) {
|
||||
pageSize: resultPageSize,
|
||||
keyword: keyword.value.trim() || undefined,
|
||||
conclusion: conclusionFilter.value || undefined,
|
||||
majorId: majorId.value || undefined,
|
||||
administrativeClassId: administrativeClassId.value || undefined,
|
||||
},
|
||||
})
|
||||
if (requestId === resultRequestId.value) selected.value = response.data
|
||||
@@ -92,6 +103,8 @@ async function loadBatch(id = selected.value?.id) {
|
||||
if (requestId === resultRequestId.value) loading.value = false
|
||||
}
|
||||
}
|
||||
async function exportRows() { try { await downloadApiFile(`/degree-awards/batches/${selected.value.id}/export.xlsx`, '学位授予审核.xlsx', { params: { keyword: keyword.value.trim() || undefined, conclusion: conclusionFilter.value || undefined, majorId: majorId.value || undefined, administrativeClassId: administrativeClassId.value || undefined } }); ElMessage.success('已导出当前筛选范围的全部记录。') } catch (error) { ElMessage.error(apiErrorMessage(error)) } }
|
||||
async function removeBatch() { try { await ElMessageBox.confirm(`删除草稿批次“${selected.value.name}”及其审核结果?此操作不可恢复。`, '删除授予批次', { type: 'warning', confirmButtonText: '删除' }); await http.delete(`/degree-awards/batches/${selected.value.id}`); ElMessage.success('草稿批次已删除。'); await load() } catch (error: any) { if (error !== 'cancel' && error !== 'close') ElMessage.error(apiErrorMessage(error)) } }
|
||||
|
||||
async function nextResultPage() { if (nextResultCursor.value && !loading.value) { resultCursors.value.push(nextResultCursor.value); resultPage.value++; await loadBatch() } }
|
||||
async function previousResultPage() { if (resultCursors.value.length && !loading.value) { resultCursors.value.pop(); resultPage.value--; await loadBatch() } }
|
||||
@@ -100,7 +113,8 @@ async function createBatch() {
|
||||
const response = await http.post('/degree-awards/batches', batchForm)
|
||||
createDialog.value = false
|
||||
await http.post(`/degree-awards/batches/${response.data.id}/calculate`)
|
||||
ElMessage.success('授予批次已建立,并完成首次规则计算。')
|
||||
ElMessage.success('授予批次已建立,规则计算已进入后台队列。')
|
||||
ElMessage.success('已提交后台重新计算,请刷新查看结果。')
|
||||
await load()
|
||||
} catch (error) {
|
||||
ElMessage.error(apiErrorMessage(error))
|
||||
@@ -150,7 +164,7 @@ async function publish() {
|
||||
}
|
||||
}
|
||||
|
||||
watch([keyword, conclusionFilter], () => {
|
||||
watch([keyword, conclusionFilter, majorId, administrativeClassId], () => {
|
||||
resultPage.value = 1
|
||||
resultCursors.value = []
|
||||
nextResultCursor.value = undefined
|
||||
@@ -201,9 +215,8 @@ onMounted(load)
|
||||
</section>
|
||||
<section v-if="selected" class="degree-workbench" v-loading="loading">
|
||||
<header>
|
||||
<div><span>CONFERRAL REGISTER</span><h3>{{ selected.name }}</h3><p>{{ selected.degreeName }} · 最低平均绩点 {{ selected.minimumGradePoint }} · 计算于 {{ dateText(selected.calculatedAt) }}</p></div>
|
||||
<div v-if="selected.status === 'Draft' && isPublisher"><el-button :icon="Refresh" @click="calculate">重新计算</el-button><el-button type="primary" :icon="Stamp" @click="publish">发布结果</el-button></div>
|
||||
<el-tag v-else type="success" effect="plain">授予结果已锁定</el-tag>
|
||||
<div><span>CONFERRAL REGISTER</span><h3>{{ selected.name }}</h3><p>{{ selected.degreeName }} · 最低平均绩点 {{ selected.minimumGradePoint }} · {{ selected.calculationStatus === 'Queued' ? '后台计算排队中' : selected.calculationStatus === 'Running' ? '后台计算进行中' : `计算于 ${dateText(selected.calculatedAt)}` }}</p></div>
|
||||
<div><el-button :icon="Download" @click="exportRows">导出</el-button><template v-if="selected.status === 'Draft' && isPublisher"><el-button :icon="Refresh" @click="calculate">重新计算</el-button><el-button type="danger" plain @click="removeBatch">删除批次</el-button><el-button type="primary" :icon="Stamp" @click="publish">发布结果</el-button></template><el-tag v-else type="success" effect="plain">授予结果已锁定</el-tag></div>
|
||||
</header>
|
||||
<div class="degree-summary">
|
||||
<div><span>参审人数</span><b>{{ selected.resultCount }}</b></div>
|
||||
@@ -214,6 +227,8 @@ onMounted(load)
|
||||
<div class="graduation-filter">
|
||||
<el-input v-model="keyword" clearable placeholder="搜索学号、姓名、专业或班级" />
|
||||
<el-select v-model="conclusionFilter" clearable placeholder="全部结论"><el-option label="建议授予" value="Granted" /><el-option label="暂不授予" value="NotGranted" /></el-select>
|
||||
<el-select v-model="majorId" clearable filterable placeholder="全部专业"><el-option v-for="item in majors" :key="item.id" :label="item.name" :value="item.id" /></el-select>
|
||||
<el-select v-model="administrativeClassId" clearable filterable placeholder="全部班级"><el-option v-for="item in classes.filter((x: any) => !majorId || x.majorId === majorId)" :key="item.id" :label="`${item.majorName} · ${item.name}`" :value="item.id" /></el-select>
|
||||
<span>共 {{ resultTotal }} 条</span>
|
||||
</div>
|
||||
<div class="degree-result-list">
|
||||
@@ -234,7 +249,7 @@ onMounted(load)
|
||||
<el-dialog v-model="createDialog" title="新建学位授予批次" width="640px">
|
||||
<el-form label-position="top">
|
||||
<el-form-item label="批次名称"><el-input v-model="batchForm.name" /></el-form-item>
|
||||
<div class="form-grid three"><el-form-item label="毕业年份"><el-input-number v-model="batchForm.graduationYear" :min="2000" :max="2200" /></el-form-item><el-form-item label="学位名称"><el-input v-model="batchForm.degreeName" /></el-form-item><el-form-item label="最低平均绩点"><el-input-number v-model="batchForm.minimumGradePoint" :min="0" :max="5" :step="0.1" /></el-form-item></div>
|
||||
<div class="form-grid three"><el-form-item label="毕业年份"><el-input-number v-model="batchForm.graduationYear" :min="2000" :max="2200" /></el-form-item><el-form-item label="目标入学年级"><el-input-number v-model="batchForm.enrollmentYear" :min="2000" :max="2200" /></el-form-item><el-form-item label="学位名称"><el-input v-model="batchForm.degreeName" /></el-form-item><el-form-item label="最低平均绩点"><el-input-number v-model="batchForm.minimumGradePoint" :min="0" :max="5" :step="0.1" /></el-form-item></div>
|
||||
<el-form-item label="说明"><el-input v-model="batchForm.notes" type="textarea" :rows="3" /></el-form-item>
|
||||
</el-form>
|
||||
<template #footer><el-button @click="createDialog=false">取消</el-button><el-button type="primary" @click="createBatch">建立并计算</el-button></template>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
|
||||
import { Check, DocumentChecked, Plus, Refresh, Stamp } from '@element-plus/icons-vue'
|
||||
import { Check, DocumentChecked, Download, Plus, Refresh, Stamp } from '@element-plus/icons-vue'
|
||||
import http, { apiErrorMessage } from '../api/http'
|
||||
import { downloadApiFile } from '../api/excel'
|
||||
import { useAuthStore } from '../stores/auth'
|
||||
|
||||
const auth = useAuthStore()
|
||||
@@ -17,6 +18,10 @@ const decisionDialog = ref(false)
|
||||
const decisionTarget = ref<any | null>(null)
|
||||
const keyword = ref('')
|
||||
const conclusionFilter = ref('')
|
||||
const majorId = ref('')
|
||||
const administrativeClassId = ref('')
|
||||
const majors = ref<any[]>([])
|
||||
const classes = ref<any[]>([])
|
||||
const resultPage = ref(1)
|
||||
const resultPageSize = 20
|
||||
const resultRequestId = ref(0)
|
||||
@@ -51,7 +56,10 @@ async function load() {
|
||||
myResult.value = (await http.get('/graduation-audits/my-result')).data
|
||||
return
|
||||
}
|
||||
batches.value = (await http.get('/graduation-audits/batches')).data
|
||||
const [batchResponse, majorResponse, classResponse] = await Promise.all([
|
||||
http.get('/graduation-audits/batches'), http.get('/base-data/majors'), http.get('/base-data/classes'),
|
||||
])
|
||||
batches.value = batchResponse.data; majors.value = majorResponse.data; classes.value = classResponse.data
|
||||
const batch = batches.value.find((x) => x.id === selected.value?.id) ?? batches.value[0]
|
||||
if (batch) await selectBatch(batch.id)
|
||||
else selected.value = null
|
||||
@@ -76,6 +84,8 @@ async function loadBatch(id = selected.value?.id) {
|
||||
pageSize: resultPageSize,
|
||||
keyword: keyword.value.trim() || undefined,
|
||||
conclusion: conclusionFilter.value || undefined,
|
||||
majorId: majorId.value || undefined,
|
||||
administrativeClassId: administrativeClassId.value || undefined,
|
||||
},
|
||||
})
|
||||
if (requestId === resultRequestId.value) selected.value = response.data
|
||||
@@ -85,13 +95,15 @@ async function loadBatch(id = selected.value?.id) {
|
||||
if (requestId === resultRequestId.value) loading.value = false
|
||||
}
|
||||
}
|
||||
async function exportRows() { try { await downloadApiFile(`/graduation-audits/batches/${selected.value.id}/export.xlsx`, '毕业资格审核.xlsx', { params: { keyword: keyword.value.trim() || undefined, conclusion: conclusionFilter.value || undefined, majorId: majorId.value || undefined, administrativeClassId: administrativeClassId.value || undefined } }); ElMessage.success('已导出当前筛选范围的全部记录。') } catch (error) { ElMessage.error(apiErrorMessage(error)) } }
|
||||
async function removeBatch() { try { await ElMessageBox.confirm(`删除草稿批次“${selected.value.name}”及其审核结果?此操作不可恢复。`, '删除审核批次', { type: 'warning', confirmButtonText: '删除' }); await http.delete(`/graduation-audits/batches/${selected.value.id}`); ElMessage.success('草稿批次已删除。'); await load() } catch (error: any) { if (error !== 'cancel' && error !== 'close') ElMessage.error(apiErrorMessage(error)) } }
|
||||
async function createBatch() {
|
||||
if (!batchForm.name.trim()) return
|
||||
try {
|
||||
const response = await http.post('/graduation-audits/batches', batchForm)
|
||||
createDialog.value = false
|
||||
await http.post(`/graduation-audits/batches/${response.data.id}/calculate`)
|
||||
ElMessage.success('审核批次已建立,并完成首次资格计算。')
|
||||
ElMessage.success('审核批次已建立,资格计算已进入后台队列。')
|
||||
await load()
|
||||
} catch (error) {
|
||||
ElMessage.error(apiErrorMessage(error))
|
||||
@@ -103,7 +115,7 @@ async function calculate() {
|
||||
type: 'warning', confirmButtonText: '重新计算',
|
||||
})
|
||||
await http.post(`/graduation-audits/batches/${selected.value.id}/calculate`)
|
||||
ElMessage.success('已按最新培养方案与发布成绩重新计算。')
|
||||
ElMessage.success('已提交后台重新计算,请刷新查看结果。')
|
||||
await load()
|
||||
} catch (error: any) {
|
||||
if (error !== 'cancel' && error !== 'close') ElMessage.error(apiErrorMessage(error))
|
||||
@@ -144,7 +156,7 @@ async function publish() {
|
||||
}
|
||||
}
|
||||
|
||||
watch([keyword, conclusionFilter], () => {
|
||||
watch([keyword, conclusionFilter, majorId, administrativeClassId], () => {
|
||||
resultPage.value = 1
|
||||
if (filterTimer) clearTimeout(filterTimer)
|
||||
filterTimer = setTimeout(() => loadBatch(), 300)
|
||||
@@ -210,12 +222,16 @@ onMounted(load)
|
||||
|
||||
<section v-if="selected" class="graduation-workbench" v-loading="loading">
|
||||
<header>
|
||||
<div><span>AUDIT REGISTER</span><h3>{{ selected.name }}</h3><p>计算时间 {{ dateText(selected.calculatedAt) }} · 规则基于已发布培养方案与成绩</p></div>
|
||||
<div v-if="selected.status === 'Draft' && isPublisher">
|
||||
<div><span>AUDIT REGISTER</span><h3>{{ selected.name }}</h3><p>{{ selected.calculationStatus === 'Queued' ? '后台计算排队中' : selected.calculationStatus === 'Running' ? '后台计算进行中' : `计算时间 ${dateText(selected.calculatedAt)}` }} · 规则基于已发布培养方案与成绩</p></div>
|
||||
<div>
|
||||
<el-button :icon="Download" @click="exportRows">导出</el-button>
|
||||
<template v-if="selected.status === 'Draft' && isPublisher">
|
||||
<el-button :icon="Refresh" @click="calculate">重新计算</el-button>
|
||||
<el-button type="danger" plain @click="removeBatch">删除批次</el-button>
|
||||
<el-button type="primary" :icon="Stamp" @click="publish">发布结果</el-button>
|
||||
</template>
|
||||
<el-tag v-else type="success" effect="plain">结果已锁定</el-tag>
|
||||
</div>
|
||||
<el-tag v-else type="success" effect="plain">结果已锁定</el-tag>
|
||||
</header>
|
||||
|
||||
<div class="graduation-summary">
|
||||
@@ -231,6 +247,8 @@ onMounted(load)
|
||||
<el-option label="符合毕业条件" value="Eligible" />
|
||||
<el-option label="暂不符合" value="Ineligible" />
|
||||
</el-select>
|
||||
<el-select v-model="majorId" clearable filterable placeholder="全部专业"><el-option v-for="item in majors" :key="item.id" :label="item.name" :value="item.id" /></el-select>
|
||||
<el-select v-model="administrativeClassId" clearable filterable placeholder="全部班级"><el-option v-for="item in classes.filter((x: any) => !majorId || x.majorId === majorId)" :key="item.id" :label="`${item.majorName} · ${item.name}`" :value="item.id" /></el-select>
|
||||
<span>共 {{ resultTotal }} 条</span>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in new issue
Block a user