浏览代码

考试管理页面更新

cfort 1 年之前
父节点
当前提交
936fc5e2b8
共有 2 个文件被更改,包括 805 次插入6 次删除
  1. 74 6
      src/views/platform/examination/constants.js
  2. 731 0
      src/views/platform/examination/exam/list.vue

+ 74 - 6
src/views/platform/examination/constants.js

@@ -19,16 +19,16 @@ export const paperTypeOptions = [
 
 export const examTypeOptions = [
     {
-        label: '培训',
-        value: '培训'
+        label: '培训考试',
+        value: '培训考试'
     },
     {
-        label: '发布',
-        value: '发布'
+        label: '自主考核',
+        value: '自主考核'
     },
     {
-        label: '自主',
-        value: '自主'
+        label: '常规',
+        value: '常规'
     }
 ]
 
@@ -104,3 +104,71 @@ export const defaultOptions = [
         content: ''
     }
 ]
+
+export const statusOption = [
+    {
+        label: '未发布',
+        value: '未发布',
+        type: 'info'
+    },
+    {
+        label: '已取消',
+        value: '已取消',
+        type: 'warning'
+    },
+    {
+        label: '已发布',
+        value: '已发布',
+        type: 'primary'
+    },
+    {
+        label: '已结束',
+        value: '已结束',
+        type: 'success'
+    }
+]
+
+const qualifiedType = [
+    {
+        label: '达标',
+        value: '达标',
+        type: 'success'
+    },
+    {
+        label: '未达标',
+        value: '未达标',
+        type: 'danger'
+    },
+    {
+        label: '考试未结束',
+        value: '考试未结束',
+        type: 'warning'
+    }
+]
+
+export const basicColumn = [
+    { prop: 'examName', label: '考试名称', minWidth: 200 },
+    { prop: 'examType', label: '考试类型', width: 90 },
+    { prop: 'bankName', label: '考试题库', width: 160 },
+    { prop: 'examState', label: '状态', width: 80, tags: statusOption },
+    { prop: 'totalScore', label: '总分', width: 65 }
+]
+
+export const infoColumn = [
+    { prop: 'questionCount', label: '题数', width: 65 },
+    { prop: 'duration', label: '考试时长', width: 100 },
+    { prop: 'limitCount', label: '限考次数', width: 85 },
+    { prop: 'limitDate', label: '限考时间', width: 120 },
+    { prop: 'isRand', label: '是否随机', slotName: 'isRand', width: 65 }
+]
+
+export const resultColumn = [
+    { prop: 'qualifiedRadio', label: '达标分值占比', width: 75 },
+    { prop: 'scoringType', label: '计分方式', width: 85 },
+    { prop: 'examineeCount', label: '考试人数', width: 65 },
+    { prop: 'examFinishCount', label: '完考人数', width: 65 },
+    { prop: 'maxScore', label: '最高分 ', width: 70 },
+    { prop: 'minScore', label: '最低分', width: 70 },
+    { prop: 'avgScore', label: '平均分', width: 70 },
+    { prop: 'passRate', label: '达标率', width: 70 }
+]

+ 731 - 0
src/views/platform/examination/exam/list.vue

@@ -0,0 +1,731 @@
+<template>
+    <div class="main-container">
+        <ibps-crud
+            v-if="showTable"
+            ref="crud"
+            :display-field="title"
+            :height="height"
+            :data="listData"
+            :toolbars="listConfig.toolbars"
+            :search-form="listConfig.searchForm"
+            :pk-key="pkKey"
+            :index-row="false"
+            :columns="listConfig.columns"
+            :row-handle="listConfig.rowHandle"
+            :pagination="pagination"
+            :loading="loading"
+            @action-event="handleAction"
+            @sort-change="handleSortChange"
+            @pagination-change="handlePaginationChange"
+            @row-dblclick="handleRowDblclick"
+        >
+            <!-- 查询参数插槽 -->
+            <template slot="examBankId">
+                <ibps-custom-dialog
+                    v-model="examBankId"
+                    size="mini"
+                    template-key="tkdhk"
+                    :multiple="true"
+                    :temp-search="true"
+                    type="dialog"
+                    class="custom-dialog"
+                    placeholder="请选择"
+                    icon="ibps-icon-search"
+                    style="width: 150px;"
+                />
+            </template>
+            <template slot="isRand" slot-scope="scope">
+                <div>{{ scope.row.isRand ? '是' : '否' }}</div>
+            </template>
+        </ibps-crud>
+        <exam-edit
+            v-if="showEditDialog"
+            :id="examInfo.examId"
+            :visible.sync="showEditDialog"
+            :is-disabled="examInfo.state !== '未发布'"
+            @callback="search"
+            @close="visible => showEditDialog = visible"
+        />
+        <exam-detail
+            v-if="showDetailDialog"
+            :visible.sync="showDetailDialog"
+            :bank-id="examInfo.bankId"
+            :exam-id="examInfo.examId"
+            @close="visible => showDetailDialog = visible"
+        />
+        <exam-judge
+            v-if="showJudgeDialog"
+            :id="selection"
+            :visible.sync="showJudgeDialog"
+            @close="visible => showJudgeDialog = visible"
+        />
+    </div>
+</template>
+
+<script>
+import { examTypeOptions, statusOption, basicColumn, infoColumn, resultColumn } from '../constants'
+import ActionUtils from '@/utils/action'
+import FixHeight from '@/mixins/height'
+import { max, min, mean, sum, maxBy, minBy, meanBy, round, keyBy, mapValues } from 'lodash'
+
+const sortField = {
+    CREATE_TIME_: 'ex.chuang_jian_shi_j',
+    PUBLISH_DATE_: 'ex.fa_bu_shi_jian_'
+}
+
+export default {
+    components: {
+        ExamEdit: () => import('./edit'),
+        ExamDetail: () => import('./detail'),
+        ExamJudge: () => import('../question/judge'),
+        IbpsCustomDialog: () => import('@/business/platform/data/templaterender/custom-dialog')
+    },
+    mixins: [FixHeight],
+    data () {
+        const roleList = ['xtgljs', 'pxglxzfzr']
+        const { isSuper, role, userId, userList = [] } = this.$store.getters || {}
+        const { first, second } = this.$store.getters.level || {}
+        const hasRole = isSuper || role.some(r => roleList.includes(r.alias))
+        const userOption = userList.map(item => ({ label: item.userName, value: item.userId }))
+        const endColumn = [
+            { prop: 'createTime', label: '创建时间', dateFormat: 'yyyy-MM-dd HH:mm', sortable: 'custom', width: 120 },
+            { prop: 'publishDate', label: '发布时间', dateFormat: 'yyyy-MM-dd HH:mm', sortable: 'custom', width: 120 },
+            { prop: 'createBy', label: '创建人', tags: userOption, width: 90 }
+        ]
+        const showType = 'info'
+        return {
+            userId,
+            userList,
+            userOption,
+            hasRole,
+            showType,
+            endColumn,
+            level: second || first,
+            title: '考试管理',
+            pkKey: 'id', // 主键  如果主键不是pk需要传主键
+            loading: true,
+            height: document.clientHeight,
+            listData: [],
+            pagination: {},
+            sorts: {},
+            showEditDialog: false,
+            showDetailDialog: false,
+            showJudgeDialog: false,
+            params: {},
+            selection: '',
+            examInfo: {
+                examId: '',
+                bankId: '',
+                state: ''
+            },
+            examBankId: '',
+            showTable: true,
+            listConfig: {
+                toolbars: [
+                    { key: 'search' },
+                    { key: 'create', label: '新建考试', type: 'success', icon: 'ibps-icon-plus' },
+                    { key: 'remove' },
+                    { key: 'judge', label: '试题评阅', type: 'info', icon: 'ibps-icon-adjust' },
+                    { key: 'change', label: `${this.showType === 'info' ? '考试结果' : '考试信息'}`, type: 'warning', icon: 'el-icon-s-operation' }
+                ],
+                searchForm: {
+                    forms: [
+                        { prop: 'examName', label: '考试名称', itemWidth: 150 },
+                        { prop: 'examType', label: '考试类型', itemWidth: 150, fieldType: 'select', multiple: 'Y', options: examTypeOptions },
+                        { prop: 'examBank', label: '考试题库', fieldType: 'slot', slotName: 'examBankId', itemWidth: 150 },
+                        { prop: 'examState', label: '考试状态', itemWidth: 150, fieldType: 'select', multiple: 'Y', options: statusOption },
+                        { prop: ['createTime0', 'createTime1'], label: '创建时间', fieldType: 'daterange' },
+                        { prop: ['publishDate0', 'publishDate1'], label: '发布时间', fieldType: 'daterange' }
+                    ]
+                },
+                // 表格字段配置
+                columns: [
+                    ...basicColumn,
+                    ...infoColumn,
+                    ...endColumn
+                ],
+                rowHandle: {
+                    // effect: 'display',
+                    actions: [
+                        {
+                            key: 'publish',
+                            label: '发布考试',
+                            type: 'primary',
+                            icon: 'ibps-icon-send',
+                            hidden: (row, index) => {
+                                return row.examState !== '未发布'
+                            }
+                        },
+                        {
+                            key: 'close',
+                            label: '取消考试',
+                            type: 'primary',
+                            icon: 'ibps-icon-trash',
+                            hidden: (row, index) => {
+                                return row.examState !== '未发布'
+                            }
+                        },
+                        {
+                            key: 'attend',
+                            label: '报名考试',
+                            type: 'primary',
+                            icon: 'ibps-icon-bookmark',
+                            hidden: (row, index) => {
+                                // 未发布且未报名
+                                return row.examState !== '未发布' || row.examinee.includes(this.userId) || row.allowRegist !== '是'
+                            }
+                        },
+                        {
+                            key: 'cancel',
+                            label: '取消报名',
+                            type: 'primary',
+                            icon: 'ibps-icon-minus-square',
+                            hidden: (row, index) => {
+                                return row.examState !== '未发布' || !row.examinee.includes(this.userId)
+                            }
+                        },
+                        {
+                            key: 'modify',
+                            label: '编辑考试',
+                            type: 'primary',
+                            icon: 'ibps-icon-edit',
+                            hidden: (row, index) => {
+                                return row.examState !== '未发布'
+                            }
+                        },
+                        {
+                            key: 'info',
+                            label: '考试明细',
+                            type: 'primary',
+                            icon: 'ibps-icon-list-alt',
+                            hidden: (row, index) => {
+                                return ['已取消', '未发布'].includes(row.examState)
+                            }
+                        }
+                    ]
+                }
+            }
+        }
+    },
+    created () {
+    },
+    mounted () {
+        this.loadData()
+    },
+    methods: {
+        // 加载数据
+        loadData () {
+            this.loading = true
+            this.getData(this.getSearchFormData()).then(res => {
+                this.loading = false
+                ActionUtils.handleListData(this, res.data)
+            })
+        },
+        getData ({ parameters, requestPage, sorts }) {
+            const { pageNo = 1, limit = 20 } = requestPage || {}
+            let sortParams = ''
+            if (sorts && sorts.length) {
+                sortParams = sorts.map(i => `${sortField[i.field]} ${i.order}`).join(',')
+            } else {
+                sortParams = 'ex.chuang_jian_shi_j desc, ex.fa_bu_shi_jian_ desc'
+            }
+            const params = this.getParams(parameters)
+            const sql = `select qb.ti_ku_ming_cheng_ as bankName, ex.id_ as examId, ex.ti_ku_id_ as bankId, e.id_ as paperId, ex.zhuang_tai_ as examState, e.zhuang_tai_ as paperState, qb.ti_shu_ as questionCount, qb.zong_fen_ as totalScore, ex.kao_shi_ming_chen as examName, ex.kao_shi_lei_xing_ as examType, ex.can_kao_ren_yuan_ as examinee, e.kao_shi_ren_ as examineeId, ex.create_by_ as createBy, ex.chuang_jian_shi_j as createTime, ex.fa_bu_shi_jian_ as publishDate, ex.fa_bu_ren_ as publisher, ex.xian_kao_shi_jian as limitDate, ex.kao_shi_shi_chang as duration, ex.xian_kao_ci_shu_ as limitCount, ex.da_biao_zhan_bi_ as qualifiedRadio, ex.ji_fen_fang_shi_ as scoringType, ex.yun_xu_bao_ming_ as allowRegist, ex.kao_shi_miao_shu_ as examDesc, ex.shu_ju_yong_tu_ as dataType, ex.sui_ji_chou_ti_ as isRand, ex.sui_ji_ti_shu_ as randNumber, ex.chou_ti_zong_fen_ as randScore, ex.ti_mu_zong_shu_ as randTotal, e.de_fen_ as score, e.bao_ming_shi_jian as applyTime, e.kai_shi_shi_jian_ as startTime, e.jie_shu_shi_jian_ as endTime from t_exams ex left join t_question_bank qb on ex.ti_ku_id_ = qb.id_ left join t_examination e on e.exam_id_ = ex.id_ where ex.di_dian_ = '${this.level}'${params} order by ${sortParams}`
+            return new Promise((resolve, reject) => {
+                this.$common.request('sql', sql).then(res => {
+                    const { data = [] } = res.variables || {}
+                    if (!data.length) {
+                        resolve({
+                            dataResult: [],
+                            pageResult: {
+                                limit: 20,
+                                page: 1,
+                                totalCount: 0,
+                                totalPages: 0
+                            }
+                        })
+                        return
+                    }
+                    const archiveData = []
+                    const scorrType = {
+                        '最高分': 'max',
+                        '平均分': 'avg',
+                        '最近得分': 'latest'
+                    }
+                    data.forEach(item => {
+                        const examIndex = archiveData.findIndex(i => i.examId === item.examId)
+                        const temp = {
+                            paperId: item.paperId,
+                            paperState: item.paperState,
+                            examineeId: item.examineeId,
+                            score: item.score,
+                            applyTime: item.applyTime,
+                            startTime: item.startTime,
+                            endTime: item.endTime
+                        }
+                        if (examIndex === -1) {
+                            archiveData.push({
+                                examId: item.examId,
+                                examName: item.examName,
+                                examType: item.examType,
+                                examState: item.examState,
+                                bankId: item.bankId,
+                                bankName: item.bankName,
+                                examinee: item.examinee,
+                                questionCount: item.isRand === '1' ? parseFloat(item.randNumber) : parseFloat(item.questionCount),
+                                duration: item.duration,
+                                limitCount: item.limitCount,
+                                limitDate: item.limitDate,
+                                qualifiedRadio: item.qualifiedRadio,
+                                scoringType: item.scoringType,
+                                allowRegist: item.allowRegist,
+                                isRand: item.isRand,
+                                examDesc: item.examDesc,
+                                createTime: item.createTime,
+                                publishDate: item.publishDate,
+                                publisher: item.publisher,
+                                createBy: item.createBy,
+                                dataType: item.dataType,
+                                totalScore: item.isRand === '1' ? parseFloat(item.randScore) : parseFloat(item.totalScore),
+                                paperList: [temp],
+                                scoreList: [parseFloat(item.score || -1)],
+                                statusList: [item.paperState]
+                            })
+                        } else {
+                            archiveData[examIndex].scoreList.push(parseFloat(item.score || -1))
+                            archiveData[examIndex].statusList.push(item.paperState)
+                            archiveData[examIndex].paperList.push(temp)
+                        }
+                    })
+                    const nodatadesc = '/'
+                    archiveData.forEach((item, index) => {
+                        const finishScore = item.scoreList.filter(i => i !== -1)
+                        const examCount = item.scoreList.length
+                        item.paperList.forEach(paper => {
+                            paper.userName = this.transformUser(item.examineeId)
+                            paper.max = finishScore.length ? round(max(finishScore), 2) : nodatadesc
+                            paper.min = finishScore.length ? round(min(finishScore), 2) : nodatadesc
+                            paper.avg = finishScore.length ? round(mean(finishScore), 2) : nodatadesc
+                            paper.sum = finishScore.length ? round(sum(finishScore), 2) : nodatadesc
+                            paper.latest = finishScore.length ? round(finishScore[0], 2) : nodatadesc
+                            paper.examCount = examCount
+                            paper.finishCount = finishScore.length
+                            paper.count = `${paper.examCount}/${paper.finishCount}`
+                            paper.examStatus = paper.examCount === paper.finishCount ? '已完成' : '未完成'
+                            paper.resultScore = paper[scorrType[paper.scoringType]]
+                            paper.isQualified = paper.examStatus === '已完成' ? paper.resultScore >= (parseFloat(paper.qualifiedRadio) / 100 * parseFloat(paper.totalScore)) ? '达标' : '未达标' : '考试未结束'
+                        })
+                        const finishList = item.paperList.filter(i => i.examStatus === '已完成')
+                        item.maxScore = finishList.length ? maxBy(finishList, 'max').max : nodatadesc
+                        item.minScore = finishList.length ? minBy(finishList, 'min').min : nodatadesc
+                        item.avgScore = finishList.length ? meanBy(finishList, 'avg').toFixed(2) : nodatadesc
+                        item.passRate = finishList.length ? this.getPassRate(finishList) : nodatadesc
+                        item.examineeCount = item.examinee ? item.examinee.split(',').length : 0
+                        item.examFinishCount = item.paperList.filter(i => i.examStatus === '已完成').length
+                    })
+                    const page = {
+                        limit,
+                        page: pageNo,
+                        totalCount: archiveData.length,
+                        totalPages: Math.ceil(archiveData.length / limit)
+                    }
+                    const result = {
+                        data: {
+                            dataResult: archiveData.slice((pageNo - 1) * limit, pageNo * limit),
+                            pageResult: page
+                        }
+                    }
+                    resolve(result)
+                }).catch(error => {
+                    reject(error)
+                })
+            })
+        },
+        // 组装SQL查询参数
+        getParams (parameters) {
+            const temp = mapValues(keyBy(parameters, 'key'), 'value')
+            let params = ''
+
+            const addCondition = (condition, value, isArray = false) => {
+                if (this.$utils.isNotEmpty(value)) {
+                    if (isArray) {
+                        const conditions = value.map(v => `${condition} = '${v}'`).join(' or ')
+                        params += ` and (${conditions})`
+                    } else {
+                        params += ` and ${condition} like '%${value}%'`
+                    }
+                }
+            }
+            addCondition('ex.kao_shi_ming_chen', temp.examName)
+            addCondition('ex.kao_shi_lei_xing_', temp.examType, true)
+            addCondition('ex.zhuang_tai_', temp.examState, true)
+
+            if (this.examBankId) {
+                const conditions = this.examBankId.split(',').map(id => `ex.ti_ku_id_ = '${id}'`).join(' or ')
+                params += ` and (${conditions})`
+            }
+
+            const addDateCondition = (key, field) => {
+                const dateParam = parameters.find(i => i.key.includes(key))
+                if (dateParam) {
+                    params += ` and (${field} >= '${temp[key + '0']}' and ${field} <= '${temp[key + '1']}' or ${field} is null)`
+                }
+            }
+            addDateCondition('createTime', 'ex.chuang_jian_shi_j')
+            addDateCondition('publishDate', 'ex.fa_bu_shi_jian_')
+            console.log(params)
+            return params
+        },
+        /**
+         * 获取格式化参数
+         */
+        getSearchFormData () {
+            return ActionUtils.formatParams(
+                this.$refs['crud'] ? this.$refs['crud'].getSearcFormData() : {},
+                this.pagination,
+                this.sorts
+            )
+        },
+        /**
+         * 处理分页事件
+         */
+        handlePaginationChange (page) {
+            ActionUtils.setPagination(this.pagination, page)
+            this.loadData()
+        },
+        /**
+         * 处理排序
+         */
+        handleSortChange (sort) {
+            ActionUtils.setSorts(this.sorts, sort)
+            this.loadData()
+        },
+        /**
+         * 查询
+         */
+        search () {
+            this.loadData()
+        },
+        handleRowDblclick (row) {
+            if (['已取消', '未发布'].includes(row.examState)) {
+                return this.$message.info('暂无详情数据!')
+            }
+            this.examInfo = {
+                examId: row.examId,
+                bankId: row.bankId
+            }
+            this.showDetailDialog = true
+        },
+        /**
+         * 处理按钮事件
+         */
+        handleAction (command, position, selection, data) {
+            const ids = data && data.length ? data.map(i => i.examId) : []
+            switch (command) {
+                case 'search':
+                    ActionUtils.setFirstPagination(this.pagination)
+                    this.search()
+                    break
+                case 'create':
+                    this.examInfo = {
+                        examId: '',
+                        state: '未发布'
+                    }
+                    this.showEditDialog = true
+                    break
+                case 'remove':
+                    this.handleRemove(ids)
+                    break
+                case 'judge':
+                    this.selection = ids.join(',')
+                    this.showJudgeDialog = true
+                    break
+                case 'change':
+                    this.handleColumnChange()
+                    break
+                case 'publish':
+                    this.handlePublish(data)
+                    break
+                case 'close':
+                    this.handleClose(data)
+                    break
+                case 'attend':
+                    this.handleAttend(data)
+                    break
+                case 'cancel':
+                    this.handleCancel(data)
+                    break
+                case 'modify':
+                    if (!this.hasRole && this.userId !== data.createBy) {
+                        return this.$message.warning('您无权编辑这场考试,请联系考试创建人或系统管理员!')
+                    }
+                    this.examInfo = {
+                        examId: data.examId,
+                        state: data.examState
+                    }
+                    this.showEditDialog = true
+                    break
+                case 'info':
+                    this.examInfo = {
+                        examId: data.examId,
+                        bankId: data.bankId
+                    }
+                    this.showDetailDialog = true
+                    break
+                default:
+                    break
+            }
+        },
+        /**
+         * 切换显示信息
+         */
+        handleColumnChange () {
+            let temp = []
+            if (this.showType === 'info') {
+                temp = resultColumn
+                this.showType = 'result'
+            } else {
+                temp = infoColumn
+                this.showType = 'info'
+            }
+            this.listConfig.columns = [
+                ...basicColumn,
+                ...temp,
+                ...this.endColumn
+            ]
+            this.updateToolbarLabel()
+            this.showTable = false
+            setTimeout(() => {
+                this.showTable = true
+            }, 10)
+        },
+        /**
+         * 更新按钮名称
+         */
+        updateToolbarLabel () {
+            this.listConfig.toolbars = this.listConfig.toolbars.map(toolbar => {
+                if (toolbar.key === 'change') {
+                    toolbar.label = this.showType === 'info' ? '考试结果' : '考试信息'
+                }
+                return toolbar
+            })
+        },
+        /**
+         * 发布考试
+         */
+        async handlePublish (data) {
+            const { examId, bankId, bankName, questionCount, totalScore, examName, limitCount, limitDate, duration, examinee, qualifiedRadio, scoringType, allowRegist, createBy } = data || {}
+            if (!this.hasRole && this.userId !== createBy) {
+                return this.$message.warning('您无权发布这场考试,请联系考试创建人或系统管理员!')
+            }
+            const examNameDesc = `<div><span style="font-weight: 600;">考试名称:</span><span style="color: #f56c6c;">${examName}</span></div>`
+            const bankNameDesc = `<div><span style="font-weight: 600;">考试题库:</span><span style="color: #f56c6c;">${bankName}</span></div>`
+            const quesitonCountDesc = `<div><span style="font-weight: 600;">题目数量:</span><span style="color: #f56c6c;">${questionCount || 0}</span></div>`
+            const scoreDesc = `<div><span style="font-weight: 600;">考试总分:</span><span style="color: #f56c6c;">${totalScore || 0}</span></div>`
+            const examineeDesc = `<div><span style="font-weight: 600;">考试人数:</span><span style="color: #f56c6c;">${examinee ? examinee.split(',').length : 0}</span></div>`
+            const limitDateDesc = `<div><span style="font-weight: 600;">限考时间:</span><span style="color: #f56c6c;">${limitDate}</span></div>`
+            const limitCountDesc = `<div><span style="font-weight: 600;">限考次数:</span><span style="color: #f56c6c;">${limitCount}</span></div>`
+            const temp = duration === '不限' || !duration ? '不限' : this.transformTime(duration)
+            const durationDesc = `<div><span style="font-weight: 600;">考试时长:</span><span style="color: #f56c6c;">${temp}</span></div>`
+            const qualifiedRadioDesc = `<div><span style="font-weight: 600;">达标分数占比:</span><span style="color: #f56c6c;">${qualifiedRadio}%</span></div>`
+            const scoringTypeDesc = `<div><span style="font-weight: 600;">计分方式:</span><span style="color: #f56c6c;">${scoringType}</span></div>`
+            const allowRegistDesc = `<div><span style="font-weight: 600;">是否允许报名:</span><span style="color: #f56c6c;">${allowRegist}</span></div>`
+            const tip = `<div style="font-size: 16px;">发布后将为所有参考人员发放试卷并通知考试,考试发布后不可取消,是否确认</div>`
+            this.$confirm(`<p style="font-size: 16px;font-weight: 600;">当前考试信息如下:</p>${examNameDesc}${bankNameDesc}${quesitonCountDesc}${scoreDesc}${examineeDesc}${limitDateDesc}${limitCountDesc}${durationDesc}${qualifiedRadioDesc}${scoringTypeDesc}${allowRegistDesc}${tip}`, '提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'info',
+                showClose: false,
+                closeOnClickModal: false,
+                dangerouslyUseHTMLString: true
+            }).then(() => {
+                const params = {
+                    tableName: 't_exams',
+                    updList: [{
+                        where: {
+                            id_: examId
+                        },
+                        param: {
+                            fa_bu_ren_: this.userId,
+                            fa_bu_shi_jian_: this.$common.getDateNow(19),
+                            zhuang_tai_: '已发布'
+                        }
+                    }]
+                }
+                // 更新考试状态
+                this.$common.request('update', params).then(() => {
+                    this.$message.success('发布考试成功!')
+                    this.search()
+                    // 发放试卷
+                    this.createPaper(data, examinee)
+                })
+            }).catch(() => {})
+        },
+        /**
+         * 创建试卷
+         */
+        createPaper (data, examinees) {
+            const { examId, bankId, examName, questionCount, totalScore, duration, qualifiedRadio, limitDate, limitCount } = data || {}
+            const examineeList = examinees.split(',')
+            const currentTime = this.$common.getDateNow(19)
+            const paramWhere = examineeList.map(i => ({
+                exam_id_: examId,
+                ti_ku_id_: bankId,
+                di_dian_: this.level,
+                kao_shi_ren_: i,
+                bu_men_: '',
+                bao_ming_shi_jian: currentTime,
+                ti_ku_zong_fen_: totalScore,
+                zhuang_tai_: '未开始',
+                sheng_yu_shi_chan: duration,
+                da_biao_zhan_bi_: qualifiedRadio
+            }))
+            const addParams = {
+                tableName: 't_examination',
+                paramWhere
+            }
+            this.$common.request('add', addParams).then(() => {
+                // 发送通知
+                const limitTime = duration === '不限' || !duration ? '不限' : this.transformTime(duration)
+                const msgContent = `您参加的考试【${examName}】已发布,该考试限考时间【${limitDate}】,限考次数【${limitCount}】,考试时长【${limitTime}】,题数【${questionCount}】,总分【${totalScore}】,请及时完成考试!`
+                examineeList.map(i => this.$common.sendMsg({
+                    subject: '考试信息提醒',
+                    content: msgContent,
+                    receiverId: i,
+                    canreplay: '0'
+                }))
+                // 添加日程
+                const now = this.$common.getDateNow(10)
+                const paramsList = examineeList.map(i => ({
+                    title_: `考试【${examName}】`,
+                    content_: `考试名称:【${examName}】\n开始时间:【${now}】\n结束时间:【${limitDate}】\n限考次数:【${limitCount}】\n考试时长:【${limitTime}】\n题数:【${questionCount}】\n总分:【${totalScore}】`,
+                    start_time_: now,
+                    end_time_: limitDate !== '不限' ? limitDate.slice(0, 10) : now,
+                    emergency_state_: '2',
+                    user_id_: i,
+                    user_name_: this.transformUser(i)
+                }))
+                this.$common.request('add', {
+                    tableName: 'ibps_party_user_calendar',
+                    paramWhere: paramsList
+                }).then(() => {
+                    console.log('添加日程数据成功')
+                })
+            })
+        },
+        /**
+         * 取消考试
+         */
+        handleClose ({ examId, createBy }) {
+            if (!this.hasRole && this.userId !== createBy) {
+                return this.$message.warning('您无权取消这场考试,请联系考试创建人或系统管理员!')
+            }
+            const params = {
+                tableName: 't_exams',
+                updList: [{
+                    where: {
+                        id_: examId
+                    },
+                    param: {
+                        examState: '已取消'
+                    }
+                }]
+            }
+            this.$common.request('update', params).then(() => {
+                this.$message.success('取消考试成功!')
+                this.search()
+            })
+        },
+        /**
+         * 报名考试
+         */
+        handleAttend (data) {
+            const { examId, examState, examinee } = data
+            const examineeList = examinee ? examinee.split(',') : []
+            examineeList.push(this.userId)
+            const params = {
+                tableName: 't_exams',
+                updList: [{
+                    where: {
+                        id_: examId
+                    },
+                    param: {
+                        can_kao_ren_yuan_: examineeList.join(',')
+                    }
+                }]
+            }
+            // 更新参考人员
+            this.$common.request('update', params).then(() => {
+                if (examState === '未发布') {
+                    this.$message.success('报名考试成功!该考试还未发布,请等待考试发布后再开始考试~')
+                } else {
+                    this.createPaper(data, this.userId)
+                    this.$message.success('报名考试成功!请前往【我的考试】开始考试')
+                }
+                this.search()
+            })
+        },
+        /**
+         * 取消报名
+         */
+        handleCancel (data) {
+            const { examId, examinee } = data
+            const examineeList = examinee.split(',').filter(item => item !== this.userId).join(',')
+            const params = {
+                tableName: 't_exams',
+                updList: [{
+                    where: {
+                        id_: examId
+                    },
+                    param: {
+                        can_kao_ren_yuan_: examineeList
+                    }
+                }]
+            }
+            this.$common.request('update', params).then(() => {
+                this.$message.success('取消报名成功!')
+                this.search()
+            })
+        },
+        /**
+         * 删除考试
+         */
+        handleRemove (ids) {
+            if (!ids || !ids.length) {
+                return this.$message.warning('请选择要删除的考试!')
+            }
+            this.$confirm('数据一旦删除无法恢复,确定要删除选中的考试吗?', '提示', {
+                confirmButtonText: '确认',
+                cancelButtonText: '取消',
+                type: 'warning',
+                showClose: false,
+                closeOnClickModal: false
+            }).then(() => {
+                this.$common.request('delete', {
+                    tableName: 't_exams',
+                    paramWhere: { id_: ids.join(',') }
+                }).then(() => {
+                    ActionUtils.removeSuccessMessage()
+                    this.search()
+                })
+            })
+        },
+        transformUser (userId) {
+            const user = this.userList.find(u => u.userId === userId) || {}
+            return user.userName || '-'
+        },
+        getPassRate (list) {
+            const passScore = parseFloat(list[0].qualifiedRadio) / 100 * parseFloat(list[0].totalScore)
+            const passList = list.filter(i => i.resultScore >= passScore)
+            return (passList.length / list.length * 100).toFixed(2) + '%'
+        }
+    }
+}
+</script>
+<style lang="scss">
+    .attachment-uploader-dialog {
+        .el-dialog__body {
+            height: calc(57vh - 100px) !important;
+        }
+    }
+</style>