|
|
@@ -43,12 +43,12 @@
|
|
|
/>
|
|
|
<el-table-column
|
|
|
prop="startTime"
|
|
|
- label="考试时间"
|
|
|
+ label="测评时间"
|
|
|
width="150"
|
|
|
/>
|
|
|
<el-table-column
|
|
|
prop="duration"
|
|
|
- label="考试时长(分钟)"
|
|
|
+ label="测评时长(分钟)"
|
|
|
width="150"
|
|
|
/>
|
|
|
<el-table-column
|
|
|
@@ -124,15 +124,25 @@
|
|
|
width="320"
|
|
|
>
|
|
|
<template slot-scope="scope">
|
|
|
+ <el-button
|
|
|
+ size="mini"
|
|
|
+ type="info"
|
|
|
+ @click="evalUser(scope.row)"
|
|
|
+ >测评用户</el-button>
|
|
|
<el-button
|
|
|
size="mini"
|
|
|
type="warning"
|
|
|
- @click="previewPaper(scope.$index, scope.row)"
|
|
|
+ @click="previewPaper(scope.row)"
|
|
|
>预览</el-button>
|
|
|
+ <el-button
|
|
|
+ size="mini"
|
|
|
+ type="info"
|
|
|
+ @click="printPaper(scope.row)"
|
|
|
+ >打印</el-button>
|
|
|
<el-button
|
|
|
size="mini"
|
|
|
type="warning"
|
|
|
- @click="handleDelete(scope.$index, scope.row)"
|
|
|
+ @click="handleDelete(scope.row)"
|
|
|
>删除</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
@@ -149,11 +159,101 @@
|
|
|
@next-click="handleCurrentChange"
|
|
|
/>
|
|
|
</el-main>
|
|
|
+
|
|
|
+ <!-- 3. 选择测评用户弹窗 -->
|
|
|
+ <!-- ================= 弹窗 1:当前已指派的测评用户列表 ================= -->
|
|
|
+ <el-dialog
|
|
|
+ title="已指派测评用户管理"
|
|
|
+ :visible.sync="userDialogVisible"
|
|
|
+ width="75%"
|
|
|
+ @close="handleUserDialogClose"
|
|
|
+ >
|
|
|
+ <div style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
|
|
|
+ <div>
|
|
|
+ 当前试卷:<span style="color: #409EFF; font-weight: bold;">{{ currentSelectPaper.paperName }}</span>
|
|
|
+ </div>
|
|
|
+ <!-- 触发第二级弹窗的按钮 -->
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ icon="el-icon-plus"
|
|
|
+ size="small"
|
|
|
+ @click="openCandidateDialog"
|
|
|
+ >添加测评用户</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 已加入用户表格(展示当前参加测评的用户) -->
|
|
|
+ <el-table
|
|
|
+ v-loading="userLoading"
|
|
|
+ :data="allUserList"
|
|
|
+ border
|
|
|
+ size="small"
|
|
|
+ height="350px"
|
|
|
+ style="width: 100%"
|
|
|
+ >
|
|
|
+ <el-table-column type="index" label="序号" width="60" align="center" />
|
|
|
+ <el-table-column prop="userId" label="用户 ID" width="120" />
|
|
|
+ <el-table-column prop="username" label="用户名" />
|
|
|
+ <!-- 可以在这里预留删除/移出当前测评用户的动作按钮 -->
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button size="small" type="primary" @click="userDialogVisible = false">关 闭</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- ================= 弹窗 2:选择候选用户(添加新用户) ================= -->
|
|
|
+ <el-dialog
|
|
|
+ title="添加需要参加测评的用户"
|
|
|
+ :visible.sync="candidateDialogVisible"
|
|
|
+ width="65%"
|
|
|
+ append-to-body
|
|
|
+ @close="handleCandidateDialogClose"
|
|
|
+ >
|
|
|
+ <!-- 搜索过滤栏 -->
|
|
|
+ <div style="margin-bottom: 15px;">
|
|
|
+ <el-input
|
|
|
+ v-model="candidateQuery.keyword"
|
|
|
+ placeholder="输入用户名搜索候选用户..."
|
|
|
+ prefix-icon="el-icon-search"
|
|
|
+ size="small"
|
|
|
+ style="width: 260px; margin-right: 10px;"
|
|
|
+ clearable
|
|
|
+ @input="getCandidateList"
|
|
|
+ />
|
|
|
+ <el-button type="primary" size="small" @click="getCandidateList">查询</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 候选用户多选表格 -->
|
|
|
+ <el-table
|
|
|
+ ref="candidateTableRef"
|
|
|
+ v-loading="candidateLoading"
|
|
|
+ :data="candidateUserList"
|
|
|
+ border
|
|
|
+ size="small"
|
|
|
+ height="300px"
|
|
|
+ style="width: 100%"
|
|
|
+ @selection-change="handleCandidateSelectionChange"
|
|
|
+ >
|
|
|
+ <el-table-column type="selection" width="55" align="center" />
|
|
|
+ <el-table-column prop="userId" label="用户 ID" width="120" />
|
|
|
+ <el-table-column prop="username" label="用户名" />
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button size="small" @click="candidateDialogVisible = false">取 消</el-button>
|
|
|
+ <el-button
|
|
|
+ size="small"
|
|
|
+ type="success"
|
|
|
+ :disabled="selectedCandidates.length === 0"
|
|
|
+ @click="submitAddEvalUsers"
|
|
|
+ >确认添加 (已选 {{ selectedCandidates.length }} 人)</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
</el-container>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { getSubjectKV, getPapers, deletePaper } from '@/api/exam'
|
|
|
+import { getSubjectKV, getPapers, deletePaper, addEvalUsers, getEvalUsers, getCandidateUsers } from '@/api/exam'
|
|
|
|
|
|
export default {
|
|
|
name: 'ExamPaperList',
|
|
|
@@ -171,7 +271,25 @@ export default {
|
|
|
pageNumber: 1,
|
|
|
pageSize: 10
|
|
|
},
|
|
|
- allSubject: []
|
|
|
+ allSubject: [],
|
|
|
+ // ****************** 新增:用户分配相关变量 ******************
|
|
|
+ userDialogVisible: false, // 控制弹窗显示
|
|
|
+ userLoading: false, // 表格加载状态
|
|
|
+ currentSelectPaper: {}, // 当前操作的行对象
|
|
|
+ allUserList: [], // 穿梭框/表格里的所有用户数据集
|
|
|
+ selectedUsers: [], // 当前勾选的用户数组
|
|
|
+ userQuery: { // 用户过滤条件
|
|
|
+ keyword: ''
|
|
|
+ },
|
|
|
+ // ****************** 级联弹窗相关状态变量 ******************
|
|
|
+ // 弹窗 2 (候选用户) 变量
|
|
|
+ candidateDialogVisible: false,
|
|
|
+ candidateLoading: false,
|
|
|
+ candidateUserList: [], // 接口返回的候选学生列表
|
|
|
+ selectedCandidates: [], // 在弹窗2中勾选中的待添加学生
|
|
|
+ candidateQuery: {
|
|
|
+ keyword: '' // 候选人关键字检索
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
created() {
|
|
|
@@ -194,20 +312,10 @@ export default {
|
|
|
this.dataList = resp.data.list
|
|
|
this.totalSize = resp.data.totalSize
|
|
|
} else {
|
|
|
- this.$notify({
|
|
|
- title: '提示',
|
|
|
- message: resp.msg,
|
|
|
- type: 'warning',
|
|
|
- duration: 3000
|
|
|
- })
|
|
|
+ this.$message.error(resp.msg)
|
|
|
}
|
|
|
}).catch(error => {
|
|
|
- this.$notify({
|
|
|
- title: '提示',
|
|
|
- message: error.message,
|
|
|
- type: 'error',
|
|
|
- duration: 3000
|
|
|
- })
|
|
|
+ this.$message.error(error.message)
|
|
|
})
|
|
|
},
|
|
|
getSubjects() {
|
|
|
@@ -224,42 +332,151 @@ export default {
|
|
|
this.queryInfo.pageSize = this.pageSize
|
|
|
this.getData(this.queryInfo)
|
|
|
},
|
|
|
- handleDelete(index, row) {
|
|
|
+ /* ==================== 弹窗 1:已指派用户管理逻辑 ==================== */
|
|
|
+ // 点击主表格“测评用户”按钮触发
|
|
|
+ evalUser(row) {
|
|
|
+ this.currentSelectPaper = row
|
|
|
+ this.userDialogVisible = true
|
|
|
+ this.getJoinedUserList()
|
|
|
+ },
|
|
|
+
|
|
|
+ // 动态拉取当前试卷已经存在的测评用户
|
|
|
+ getJoinedUserList() {
|
|
|
+ this.userLoading = true
|
|
|
+ const queryParams = {
|
|
|
+ paperId: this.currentSelectPaper.paperId
|
|
|
+ }
|
|
|
+ getEvalUsers(queryParams).then(resp => {
|
|
|
+ if (resp.code === 0) {
|
|
|
+ this.allUserList = resp.data || []
|
|
|
+ } else {
|
|
|
+ this.$message.warning(resp.msg)
|
|
|
+ }
|
|
|
+ }).catch(error => {
|
|
|
+ this.$message.error('拉取已指派用户失败: ' + error.message)
|
|
|
+ }).finally(() => {
|
|
|
+ this.userLoading = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 弹窗 1 关闭时销毁缓存
|
|
|
+ handleUserDialogClose() {
|
|
|
+ this.allUserList = []
|
|
|
+ this.currentSelectPaper = {}
|
|
|
+ },
|
|
|
+ /* ==================== 弹窗 2:候选用户选择与添加逻辑 ==================== */
|
|
|
+ // 打开添加候选人弹窗
|
|
|
+ openCandidateDialog() {
|
|
|
+ this.candidateDialogVisible = true
|
|
|
+ this.getCandidateList()
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取可供选择的候选用户列表
|
|
|
+ getCandidateList() {
|
|
|
+ this.candidateLoading = true
|
|
|
+ const queryParams = {
|
|
|
+ paperId: this.currentSelectPaper.paperId,
|
|
|
+ keyword: this.candidateQuery.keyword // 传递搜索关键词给后端(若后端支持)
|
|
|
+ }
|
|
|
+
|
|
|
+ getCandidateUsers(queryParams).then(resp => {
|
|
|
+ if (resp.code === 0) {
|
|
|
+ const respData = resp.data || []
|
|
|
+ // 如果后端接口不支持 keyword 筛选,则由前端进行客户端纯文本过滤:
|
|
|
+ if (this.candidateQuery.keyword) {
|
|
|
+ this.candidateUserList = respData.filter(u =>
|
|
|
+ u.username.includes(this.candidateQuery.keyword)
|
|
|
+ )
|
|
|
+ } else {
|
|
|
+ this.candidateUserList = respData
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.$message.warning(resp.msg)
|
|
|
+ }
|
|
|
+ }).catch(error => {
|
|
|
+ this.$message.error('拉取候选用户失败: ' + error.message)
|
|
|
+ }).finally(() => {
|
|
|
+ this.candidateLoading = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 监听候选人表格的勾选改变
|
|
|
+ handleCandidateSelectionChange(val) {
|
|
|
+ this.selectedCandidates = val
|
|
|
+ },
|
|
|
+
|
|
|
+ // 确认将勾选的候选人添加至测评
|
|
|
+ submitAddEvalUsers() {
|
|
|
+ const paperId = this.currentSelectPaper.paperId
|
|
|
+ const userIds = this.selectedCandidates.map(item => item.userId)
|
|
|
+
|
|
|
+ const jsonData = {
|
|
|
+ paperId: paperId,
|
|
|
+ userIds: userIds
|
|
|
+ }
|
|
|
+
|
|
|
+ addEvalUsers(jsonData).then(resp => {
|
|
|
+ if (resp.code === 0) {
|
|
|
+ this.$message.success(`成功为试卷添加了 ${userIds.length} 个测评用户!`)
|
|
|
+ this.candidateDialogVisible = false // 关闭候选弹窗
|
|
|
+ this.getJoinedUserList() // 刷新弹窗1中的已加入用户列表,形成无缝视觉联动
|
|
|
+ } else {
|
|
|
+ this.$message.warning(resp.msg)
|
|
|
+ }
|
|
|
+ }).catch(error => {
|
|
|
+ this.$message.error('添加失败: ' + error.message)
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 弹窗 2 关闭时重置状态
|
|
|
+ handleCandidateDialogClose() {
|
|
|
+ this.candidateQuery.keyword = ''
|
|
|
+ this.selectedCandidates = []
|
|
|
+ this.candidateUserList = []
|
|
|
+ if (this.$refs.candidateTableRef) {
|
|
|
+ this.$refs.candidateTableRef.clearSelection()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ previewPaper(row) {
|
|
|
+ const paperId = row.paperId
|
|
|
+ const routeUrl = this.$router.resolve({
|
|
|
+ path: '/exam/paper/preview',
|
|
|
+ query: {
|
|
|
+ paperId: paperId
|
|
|
+ }
|
|
|
+ })
|
|
|
+ window.open(routeUrl.href, '_blank')
|
|
|
+ },
|
|
|
+ printPaper(row) {
|
|
|
+ this.$message.info('打印试卷未实现')
|
|
|
+ /* const paperId = row.paperId
|
|
|
+ const routeUrl = this.$router.resolve({
|
|
|
+ path: '/exams_print',
|
|
|
+ query: {
|
|
|
+ paperId: paperId
|
|
|
+ }
|
|
|
+ })
|
|
|
+ window.open(routeUrl.href, '_blank')
|
|
|
+ */
|
|
|
+ },
|
|
|
+ handleDelete(row) {
|
|
|
this.$confirm('确定要删除 ' + row.paperName + '?', '提示', {
|
|
|
confirmButtonText: '确定',
|
|
|
cancelButtonText: '取消',
|
|
|
type: 'warning'
|
|
|
}).then(() => {
|
|
|
deletePaper(row.paperId).then(resp => {
|
|
|
+ this.$message.info(resp.msg)
|
|
|
if (resp.code === 0) {
|
|
|
- this.$notify({
|
|
|
- title: '提示',
|
|
|
- message: '稿件已删除',
|
|
|
- type: 'warning',
|
|
|
- duration: 3000
|
|
|
- })
|
|
|
this.$router.go(0)
|
|
|
}
|
|
|
})
|
|
|
- }).catch(() => {
|
|
|
- this.$message({
|
|
|
- type: 'info',
|
|
|
- message: '已取消'
|
|
|
- })
|
|
|
+ }).catch((error) => {
|
|
|
+ this.$message.error(error.message)
|
|
|
})
|
|
|
},
|
|
|
addExamPaper() {
|
|
|
this.$router.push('/exam/paper/add')
|
|
|
- },
|
|
|
- previewPaper(index, row) {
|
|
|
- const paperId = row.paperId
|
|
|
- const routeUrl = this.$router.resolve({
|
|
|
- path: '/exam/paper/preview',
|
|
|
- query: {
|
|
|
- paperId: paperId
|
|
|
- }
|
|
|
- })
|
|
|
- window.open(routeUrl.href, '_blank')
|
|
|
}
|
|
|
}
|
|
|
}
|