Bläddra i källkod

考试功能更新

cfort 2 år sedan
förälder
incheckning
aa3552db21

+ 30 - 0
src/views/platform/examine/constants.js → src/views/platform/examination/constants.js

@@ -17,6 +17,36 @@ export const paperTypeOptions = [
     }
     }
 ]
 ]
 
 
+export const examTypeOptions = [
+    {
+        label: '培训',
+        value: '培训'
+    },
+    {
+        label: '发布',
+        value: '发布'
+    },
+    {
+        label: '自主',
+        value: '自主'
+    }
+]
+
+export const scoringType = [
+    {
+        label: '平均分',
+        value: '平均分'
+    },
+    {
+        label: '最高分',
+        value: '最高分'
+    },
+    {
+        label: '最近得分',
+        value: '最近得分'
+    }
+]
+
 export const questionType = [
 export const questionType = [
     {
     {
         label: '单选题',
         label: '单选题',

+ 458 - 0
src/views/platform/examination/exam/detail.vue

@@ -0,0 +1,458 @@
+<template>
+    <el-dialog
+        :title="title"
+        :visible.sync="dialogVisible"
+        :close-on-click-modal="false"
+        :close-on-press-escape="false"
+        :show-close="false"
+        append-to-body
+        fullscreen
+        class="dialog paper-detail-dialog"
+        top="0"
+        @open="loadData"
+        @close="closeDialog"
+    >
+        <div class="container">
+            <div class="paper-info">
+                <div class="info-item">
+                    <span class="label">考试名称:</span>
+                    <span class="value">{{ paperData.examName }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">创建人:</span>
+                    <span class="value">{{ transformUser(paperData.createBy) }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">创建时间:</span>
+                    <span class="value">{{ paperData.createTime }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">发布时间:</span>
+                    <span class="value">{{ paperData.publishDate }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">限考时间:</span>
+                    <span class="value">{{ paperData.limitDate }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">考试时长:</span>
+                    <span class="value">{{ transformTime(paperData.duration) }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">限考次数:</span>
+                    <span class="value">{{ paperData.limitCount }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">参考人数:</span>
+                    <span class="value">{{ paperList.length }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">题库名称:</span>
+                    <span class="value">{{ paperData.bankName }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">题目数量:</span>
+                    <span class="value">{{ paperData.totalCount }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">总分:</span>
+                    <span class="value">{{ paperData.totalScore }}分</span>
+                </div>
+                <div class="info-item">
+                    <el-tooltip effect="dark" content="达标分值占总分的比率" placement="top">
+                        <span class="label">达标占比:</span>
+                    </el-tooltip>
+                    <span class="value">{{ paperData.qualifiedRadio }}%</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">最高分:</span>
+                    <span class="value">{{ maxScore }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">最低分:</span>
+                    <span class="value">{{ minScore }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">平均分:</span>
+                    <span class="value">{{ avgScore }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">计分方式:</span>
+                    <span class="value">{{ paperData.scoringType }}</span>
+                </div>
+                <div class="info-item">
+                    <span class="label">达标率:</span>
+                    <span class="value">-</span>
+                </div>
+            </div>
+            <div class="paper-table">
+                <el-table
+                    ref="elTable"
+                    :data="paperList"
+                    border
+                    stripe
+                    highlight-current-row
+                    header-row-class-name="exam-table-header"
+                    style="width: 100%"
+                    class="exam-table"
+                    @row-dbclick="handleRowDblclick"
+                >
+                    <el-table-column label="序号" type="index" width="50" />
+                    <el-table-column
+                        prop="userName"
+                        label="考生姓名"
+                        width="100"
+                    />
+                    <el-table-column
+                        prop="count"
+                        label="参考次数/完成次数"
+                        width="90"
+                    />
+                    <el-table-column
+                        prop=""
+                        label="考试成绩"
+                    >
+                        <el-table-column
+                            prop="max"
+                            label="最高得分"
+                            width="90"
+                        />
+                        <el-table-column
+                            prop="min"
+                            label="最低得分"
+                            width="90"
+                        />
+                        <el-table-column
+                            prop="avg"
+                            label="平均得分"
+                            width="90"
+                        />
+                        <el-table-column
+                            prop="latest"
+                            label="最近得分"
+                            width="90"
+                        />
+                    </el-table-column>
+                    <el-table-column
+                        prop="latest"
+                        label="最终成绩"
+                        width="90"
+                    />
+                    <el-table-column prop="isQualified" label="是否达标">
+                        <template slot-scope="scope">
+                            <el-tag :type="getTagType(scope.row)" size="medium" class="score">{{ scope.row.isQualified }}</el-tag>
+                        </template>
+                    </el-table-column>
+                    <!-- <el-table-column
+                        fixed="right"
+                        label="操作"
+                        width="60"
+                    >
+                        <template slot-scope="scope">
+                            <el-button type="text" size="small" @click="handleRowDblclick(scope.row)">详情</el-button>
+                        </template>
+                    </el-table-column> -->
+                </el-table>
+            </div>
+        </div>
+        <div slot="footer" class="el-dialog--center">
+            <ibps-toolbar
+                :actions="toolbars"
+                @action-event="handleActionEvent"
+            />
+        </div>
+        <paper-detail
+            v-if="paperDialogVisible"
+            :id="paperId"
+            :visible.sync="paperDialogVisible"
+            :bank-id="bankId"
+            :exam-id="examId"
+            :examinee-id="examineeId"
+            @close="paperDialogVisible = false"
+        />
+    </el-dialog>
+</template>
+
+<script>
+import { max, min, mean, sum, maxBy, minBy, meanBy, round } from 'lodash'
+const qualifiedType = [
+    {
+        value: '达标',
+        type: 'success'
+    },
+    {
+        value: '未达标',
+        type: 'danger'
+    },
+    {
+        value: '考试未结束',
+        type: 'warning'
+    }
+]
+export default {
+    components: {
+        IbpsImage: () => import('@/business/platform/file/image'),
+        PaperDetail: () => import('../questionBank/detail')
+    },
+    props: {
+        visible: {
+            type: Boolean,
+            default: false
+        },
+        bankId: {
+            type: String,
+            default: ''
+        },
+        examId: {
+            type: String,
+            default: ''
+        },
+        id: {
+            type: String,
+            default: ''
+        }
+    },
+    data () {
+        return {
+            title: '考试详情',
+            dialogVisible: this.visible,
+            paperDialogVisible: false,
+            toolbars: [
+                { key: 'cancel', label: '退出' }
+            ],
+            paperList: [],
+            paperData: [],
+            paperId: '',
+            examineeId: '',
+            maxScore: '',
+            minScore: '',
+            avgScore: ''
+        }
+    },
+    watch: {
+        visible: {
+            handler (val, oldVal) {
+                this.dialogVisible = this.visible
+            }
+        }
+    },
+    mounted () {
+        this.loadData()
+        // 监听键盘事件
+        window.addEventListener('keyup', this.handleKeyPress)
+    },
+    beforeDestroy () {
+        window.removeEventListener('keyup', this.handleKeyPress)
+    },
+    methods: {
+        // 获取题库数据
+        async loadData () {
+            if (!this.examId) {
+                this.$message.error('获取题目信息失败,请重试!')
+                this.closeDialog()
+                return
+            }
+            this.paperList = await this.getQuestionData()
+            console.log(this.paperList)
+            this.paperData = this.paperList[0]
+        },
+        handleActionEvent ({ key }) {
+            switch (key) {
+                case 'cancel':
+                    this.closeDialog()
+                    break
+                default:
+                    break
+            }
+        },
+        handleKeyPress (event) {
+            if (event.keyCode === 27 || event.key === 'Esc') {
+                this.closeDialog()
+            }
+        },
+        getTagType (row) {
+            const temp = qualifiedType.find(i => i.value === row.isQualified)
+            return temp ? temp.type : 'default'
+        },
+        transformUser (userId) {
+            const { userList = [] } = this.$store.getters
+            const user = userList.find(u => u.userId === userId) || {}
+            return user.userName || '-'
+        },
+        transformTime (timeStamp) {
+            if (timeStamp === '不限') return timeStamp
+            const hours = Math.floor(parseInt(timeStamp) / 3600000)
+            const minutes = Math.floor((parseInt(timeStamp) % 3600000) / 60000)
+            return hours + '小时' + minutes + '分钟'
+        },
+        getQuestionData () {
+            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.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.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, 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, t_question_bank qb, t_examination e where ex.ti_ku_id_ = qb.id_ and e.exam_id_ = ex.id_ and ex.id_ = '${this.examId}' order by e.kao_shi_ren_ desc, e.jie_shu_shi_jian_ desc`
+            return new Promise((resolve, reject) => {
+                this.$common.request('sql', sql).then(res => {
+                    const { data = [] } = res.variables || {}
+                    if (!data.length) {
+                        this.$message.error('未查询到已提交的考试记录,请先完成考试!')
+                        this.closeDialog()
+                        return
+                    }
+                    const result = []
+                    const scorrType = {
+                        '最高分': 'max',
+                        '平均分': 'avg',
+                        '最近得分': 'latest'
+                    }
+                    data.forEach(item => {
+                        const index = result.findIndex(i => i.examineeId === item.examineeId)
+                        if (index === -1) {
+                            result.push({
+                                ...item,
+                                totalCount: data.length,
+                                totalScore: parseFloat(item.totalScore),
+                                statusList: [item.paperState],
+                                scoreList: [parseFloat(item.score || -1)]
+                            })
+                        } else {
+                            result[index].scoreList.push(parseFloat(item.score || -1))
+                            result[index].statusList.push(item.paperState)
+                        }
+                    })
+                    const nodatadesc = '无已完成考试'
+                    result.forEach((item, index) => {
+                        const finishScore = item.scoreList.filter(i => i !== -1)
+                        item.userName = this.transformUser(item.examineeId)
+                        item.max = finishScore.length ? round(max(finishScore), 2) : nodatadesc
+                        item.min = finishScore.length ? round(min(finishScore), 2) : nodatadesc
+                        item.avg = finishScore.length ? round(mean(finishScore), 2) : nodatadesc
+                        item.sum = finishScore.length ? round(sum(finishScore), 2) : nodatadesc
+                        item.latest = finishScore.length ? round(finishScore[0], 2) : nodatadesc
+                        item.examCount = item.scoreList.length
+                        item.finishCount = finishScore.length
+                        item.count = `${item.examCount}/${item.finishCount}`
+                        item.examStatus = item.examCount === item.finishCount ? '已完成' : '未完成'
+                        item.resultScore = item[scorrType[item.scoringType]]
+                        item.isQualified = item.examStatus === '已完成' ? item.resultScore >= (parseFloat(item.qualifiedRadio) / 100 * parseFloat(item.totalScore)) ? '达标' : '未达标' : '考试未结束'
+                    })
+                    const finishList = result.filter(i => i.examStatus === '已完成')
+                    this.maxScore = finishList.length ? maxBy(finishList, 'max').max : nodatadesc
+                    this.minScore = finishList.length ? minBy(finishList, 'min').min : nodatadesc
+                    this.avgScore = finishList.length ? meanBy(finishList, 'avg').avg : nodatadesc
+                    resolve(result)
+                }).catch(error => {
+                    reject(error)
+                })
+            })
+        },
+        handleRowDblclick (row) {
+            this.paperId = row.paperId
+            this.examineeId = row.examineeId
+            this.paperDialogVisible = true
+        },
+        // 关闭当前窗口
+        closeDialog () {
+            this.$emit('close', false)
+        }
+    }
+}
+</script>
+<style lang="scss" scoped>
+    .paper-detail-dialog {
+        ::v-deep {
+            .el-dialog__body {
+                position: relative;
+                height: calc(100vh - 115px);
+                width: 1080px;
+                margin: 0 auto;
+                box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+                .el-radio, .el-checkbox {
+                    display: block;
+                    margin-bottom: 10px;
+                    pointer-events: none;
+                    &:last-child {
+                        margin-bottom: 0;
+                    }
+                }
+                .el-radio-button {
+                    pointer-events: none;
+                }
+                .el-radio__label, .el-checkbox__label {
+                    font-size: 16px;
+                }
+                .el-input {
+                    margin-bottom: 10px;
+                    pointer-events: none;
+                    &:last-child {
+                        margin-bottom: 0;
+                    }
+                }
+                .el-tag {
+                    margin-right: 0;
+                }
+                .ibps-p-0 {
+                    margin: 0;
+                    .list-group {
+                        display: inline-block;
+                        width: 100%;
+                    }
+                }
+            }
+            .el-dialog__header {
+                text-align: center;
+            }
+        }
+        .container {
+            position: relative;
+            height: calc(100vh - 160px);
+            padding: 20px;
+            .paper-info {
+                display: flex;
+                flex-wrap: wrap;
+                justify-content: flex-start;
+                margin-bottom: 20px;
+                background-color: #f5f5f5;
+                border: 1px solid #ddd;
+                padding: 10px;
+                border-radius: 5px;
+                font-size: 16px;
+            }
+
+            .info-item {
+                width: 33.3%;
+                margin-bottom: 20px;
+                display: flex;
+                align-items: center;
+                .label {
+                    width: 100px;
+                    font-weight: bold;
+                    color: #333;
+                }
+                .value {
+                    flex: 1;
+                    color: #666;
+                    white-space: nowrap;
+                    overflow: hidden;
+                    text-overflow: ellipsis;
+                }
+            }
+
+            .paper-table {
+                .exam-table-header {
+                    text-align: center;
+                }
+                ::v-deep {
+                    .el-table {
+                        th {
+                            font-size: 14px !important;
+                            text-align: center;
+                        }
+                        td {
+                            font-size: 14px !important;
+                        }
+                        .el-table__row {
+                            cursor: pointer;
+                        }
+                    }
+                }
+            }
+        }
+    }
+</style>

+ 431 - 0
src/views/platform/examination/exam/edit.vue

@@ -0,0 +1,431 @@
+<template>
+    <el-dialog
+        :title="title"
+        :visible.sync="dialogVisible"
+        :close-on-click-modal="false"
+        :close-on-press-escape="false"
+        append-to-body
+        width="60%"
+        class="dialog exam-dialog"
+        top="6vh"
+        @close="closeDialog"
+        @open="getExamData"
+    >
+        <el-form
+            ref="form"
+            :label-width="formLabelWidth"
+            :model="form"
+            :rules="rules"
+            class="exam-form"
+            @submit.native.prevent
+        >
+            <el-form-item label="考试名称:" prop="kao_shi_ming_chen">
+                <el-input v-model="form.kao_shi_ming_chen" type="text" :maxlength="256" placeholder="请输入考试名称" />
+            </el-form-item>
+            <!-- <el-form-item label="考试类型:" prop="kao_shi_lei_xing_">
+                <el-select
+                    v-model="form.kao_shi_lei_xing_"
+                    filterable
+                    allow-create
+                    width="100%"
+                    placeholder="请选择考试类型"
+                >
+                    <el-option
+                        v-for="item in examTypeOptions"
+                        :key="item.value"
+                        :label="item.label"
+                        :value="item.value"
+                    />
+                </el-select>
+            </el-form-item> -->
+            <el-form-item label="考试题库:" prop="ti_ku_id_">
+                <ibps-custom-dialog
+                    v-model="form.ti_ku_id_"
+                    size="small"
+                    template-key="tkdhk"
+                    :multiple="false"
+                    type="dialog"
+                    class="custom-dialog"
+                    placeholder="请选择考试题库"
+                />
+            </el-form-item>
+            <el-form-item label="限考时间:" prop="xian_kao_shi_jian">
+                <el-radio-group v-model="form.isDateLimit" @change="changeLimit(form.isDateLimit, 'xian_kao_shi_jian', null)">
+                    <el-radio label="0">不限</el-radio>
+                    <el-radio label="1">限制</el-radio>
+                </el-radio-group>
+                <el-date-picker
+                    v-if="form.isDateLimit === '1'"
+                    v-model="form.xian_kao_shi_jian"
+                    type="datetime"
+                    placeholder="请选择考试限制提交时间"
+                    align="right"
+                    default-time="12:00:00"
+                    class="date-picker"
+                    :picker-options="pickerOptions"
+                />
+            </el-form-item>
+            <el-form-item label="参考人员:" prop="can_kao_ren_yuan_">
+                <ibps-custom-dialog
+                    v-model="form.can_kao_ren_yuan_"
+                    size="small"
+                    template-key="gjxcxryk"
+                    multiple
+                    type="dialog"
+                    class="custom-dialog"
+                    placeholder="请选择需参加考试的人员"
+                />
+            </el-form-item>
+            <el-form-item prop="isCountLimit" class="inline-item">
+                <template slot="label">
+                    限考次数
+                    <el-tooltip effect="dark" content="限制是否可重复参加,以及可参加考试的最大次数" placement="top">
+                        <i class="el-icon-question question-icon">:</i>
+                    </el-tooltip>
+                </template>
+                <el-radio-group v-model="form.isCountLimit" @change="changeLimit(form.isCountLimit, 'xian_kao_ci_shu_', 1)">
+                    <el-radio label="0">不限</el-radio>
+                    <el-radio label="1">限制</el-radio>
+                </el-radio-group>
+                <div v-if="form.isCountLimit === '1'" class="time">
+                    <el-input-number
+                        v-model="form.xian_kao_ci_shu_"
+                        :min="1"
+                        :precision="0"
+                        placeholder="请输入单个用户最大限考次数"
+                    />
+                    <div class="unit">次</div>
+                </div>
+            </el-form-item>
+            <el-form-item v-if="form.isCountLimit === '0' || form.isCountLimit === '1' && form.xian_kao_ci_shu_ > 1" prop="ji_fen_fang_shi_">
+                <template slot="label">
+                    计分方式
+                    <el-tooltip effect="dark" content="仅限考次数大于1时有效" placement="top">
+                        <i class="el-icon-question question-icon">:</i>
+                    </el-tooltip>
+                </template>
+                <el-radio-group v-model="form.ji_fen_fang_shi_">
+                    <el-radio label="平均分">平均分</el-radio>
+                    <el-radio label="最高分">最高分</el-radio>
+                    <el-radio label="最近得分">最近得分</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item label="考试时长:" prop="isTimeLimit" class="inline-item">
+                <el-radio-group v-model="form.isTimeLimit">
+                    <el-radio label="0">不限</el-radio>
+                    <el-radio label="1">限制</el-radio>
+                </el-radio-group>
+                <template v-if="form.isTimeLimit === '1'">
+                    <div class="time">
+                        <el-input-number
+                            v-model="form.hours"
+                            :min="0"
+                            :max="72"
+                            :precision="0"
+                        />
+                        <div class="unit">小时</div>
+                    </div>
+                    <div class="time">
+                        <el-input-number
+                            v-model="form.minutes"
+                            :min="0"
+                            :max="59"
+                            :precision="0"
+                        />
+                        <div class="unit">分钟</div>
+                    </div>
+                </template>
+            </el-form-item>
+            <el-form-item label="达标分值占比:" prop="da_biao_zhan_bi_">
+                <el-input-number
+                    v-model="form.da_biao_zhan_bi_"
+                    :min="50"
+                    :max="100"
+                    :precision="0"
+                    placeholder="请输入达标分值占比"
+                />
+                <div class="unit">%</div>
+            </el-form-item>
+            <el-form-item prop="yun_xu_bao_ming_">
+                <template slot="label">
+                    允许自主报名
+                    <el-tooltip effect="dark" content="限制非参考人员是否可报名参加该考试" placement="top">
+                        <i class="el-icon-question question-icon">:</i>
+                    </el-tooltip>
+                </template>
+                <el-radio-group v-model="form.yun_xu_bao_ming_">
+                    <el-radio label="是">是</el-radio>
+                    <el-radio label="否">否</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item prop="guan_lian_id_">
+                <template slot="label">
+                    关联培训记录
+                    <el-tooltip effect="dark" content="关联培训记录" placement="top">
+                        <i class="el-icon-question question-icon">:</i>
+                    </el-tooltip>
+                </template>
+                <ibps-custom-dialog
+                    v-model="form.guan_lian_id_"
+                    size="small"
+                    template-key="pxjldhk"
+                    :multiple="false"
+                    type="dialog"
+                    class="custom-dialog"
+                    placeholder="请选择培训记录"
+                />
+            </el-form-item>
+            <el-form-item label="考试描述:" prop="kao_shi_miao_shu_">
+                <el-input v-model="form.kao_shi_miao_shu_" type="textarea" :rows="4" placeholder="请输入描述内容" />
+            </el-form-item>
+        </el-form>
+        <div slot="footer" class="el-dialog--center">
+            <ibps-toolbar
+                :actions="toolbars"
+                @action-event="handleActionEvent"
+            />
+        </div>
+    </el-dialog>
+</template>
+
+<script>
+import ActionUtils from '@/utils/action'
+import { examTypeOptions, scoringType } from '../constants'
+export default {
+    components: {
+        IbpsCustomDialog: () => import('@/business/platform/data/templaterender/custom-dialog')
+    },
+    props: {
+        visible: {
+            type: Boolean,
+            default: false
+        },
+        id: {
+            type: String,
+            default: ''
+        }
+    },
+    data () {
+        const { userList = [], deptList = [], userId, level } = this.$store.getters || {}
+        return {
+            userList,
+            examTypeOptions,
+            deptList: deptList.filter(i => i.depth === 4),
+            title: this.id ? '编辑考试' : '新建考试',
+            formLabelWidth: '135px',
+            dialogVisible: this.visible,
+            dialogLoading: false,
+            form: {
+                di_dian_: level.second || level.first,
+                chuang_jian_shi_j: '',
+                kao_shi_ming_chen: '',
+                kao_shi_lei_xing_: '发布',
+                ti_ku_id_: '',
+                guan_lian_id_: '',
+                xian_kao_shi_jian: '不限',
+                xian_kao_ci_shu_: '不限',
+                can_kao_ren_yuan_: '',
+                kao_shi_shi_chang: '',
+                zhuang_tai_: '未发布',
+                da_biao_zhan_bi_: 60,
+                ji_fen_fang_shi_: scoringType.length ? scoringType[0].value : '',
+                kao_shi_miao_shu_: '',
+                yun_xu_bao_ming_: '否',
+                isCountLimit: '0',
+                isTimeLimit: '0',
+                isDateLimit: '0',
+                hours: 2,
+                minutes: 30
+            },
+            pickerOptions: {
+                disabledDate (time) {
+                    // 禁用当前日期之前的日期
+                    return time.getTime() < Date.now() - 8.64e7
+                }
+            },
+            toolbars: [
+                {
+                    key: 'submit',
+                    icon: 'ibps-icon-save',
+                    label: '保存',
+                    hidden: () => {
+                        return this.readonly
+                    }
+                },
+                { key: 'cancel', label: '关闭' }
+            ],
+            rules: {
+                kao_shi_ming_chen: [{ required: true, message: this.$t('validate.required') }],
+                // kao_shi_lei_xing_: [{ required: true, message: this.$t('validate.required') }],
+                ti_ku_id_: [{ required: true, message: this.$t('validate.required') }],
+                xian_kao_shi_jian: [{ required: true, message: this.$t('validate.required') }],
+                xian_kao_ci_shu_: [{ required: true, message: this.$t('validate.required') }],
+                can_kao_ren_yuan_: [{ required: true, message: this.$t('validate.required') }],
+                kao_shi_shi_chang: [{ required: true, message: this.$t('validate.required') }],
+                da_biao_zhan_bi_: [{ required: true, message: this.$t('validate.required') }]
+            }
+
+        }
+    },
+    watch: {
+        visible: {
+            handler: function (val, oldVal) {
+                this.dialogVisible = this.visible
+            }
+            // immediate: true
+        }
+    },
+    created () {
+        this.getExamData()
+    },
+    methods: {
+        changeLimit (e, type, defaultValue) {
+            this.form[type] = e === '1' ? defaultValue : '不限'
+        },
+        handleActionEvent ({ key }) {
+            switch (key) {
+                case 'submit':
+                    this.handleSubmit()
+                    break
+                case 'cancel':
+                    this.closeDialog()
+                    break
+                default:
+                    break
+            }
+        },
+        // 获取考试数据
+        getExamData () {
+            if (this.$utils.isEmpty(this.id)) {
+                return
+            }
+            const sql = `select id_, create_by_, ti_ku_id_, guan_lian_id_, kao_shi_ming_chen, kao_shi_lei_xing_, chuang_jian_shi_j, fa_bu_shi_jian_, fa_bu_ren_, xian_kao_shi_jian, xian_kao_ci_shu_, kao_shi_shi_chang, can_kao_ren_yuan_, zhuang_tai_, da_biao_zhan_bi_, ji_fen_fang_shi_, kao_shi_miao_shu_ from t_exams where id_ = '${this.id}'`
+            this.$common.request('sql', sql).then(res => {
+                const { data = [] } = res.variables || {}
+                if (!data.length) {
+                    this.$message.error('数据不存在')
+                    return
+                }
+                data[0].isCountLimit = data[0].xian_kao_ci_shu_ === '不限' ? '0' : '1'
+                data[0].isDateLimit = data[0].xian_kao_shi_jian === '不限' ? '0' : '1'
+                if (data[0].kao_shi_shi_chang === '不限') {
+                    data[0].isTimeLimit = '0'
+                    data[0].hours = null
+                    data[0].minutes = null
+                } else {
+                    data[0].isTimeLimit = '1'
+                    data[0].hours = Math.floor(data[0].kao_shi_shi_chang / (1000 * 60 * 60))
+                    data[0].minutes = (data[0].kao_shi_shi_chang % (1000 * 60 * 60)) / (60 * 1000)
+                }
+                this.form = data[0]
+            })
+        },
+        handleSubmit () {
+            this.$refs.form.validate((valid) => {
+                if (valid) {
+                    const { isTimeLimit, xian_kao_shi_jian = '' } = this.form || {}
+                    // 转换考试时长
+                    if (isTimeLimit === '0') {
+                        this.form.kao_shi_shi_chang = '不限'
+                    } else {
+                        this.form.kao_shi_shi_chang = (this.form.hours * 60 + this.form.minutes) * 60 * 1000
+                    }
+                    delete this.form.isDateLimit
+                    delete this.form.isCountLimit
+                    delete this.form.isTimeLimit
+                    delete this.form.hours
+                    delete this.form.minutes
+                    this.form.chuang_jian_shi_j = this.$common.getDateNow(19)
+                    this.form.xian_kao_shi_jian = xian_kao_shi_jian !== '不限' ? this.$common.getFormatDate('string', 16, xian_kao_shi_jian) : xian_kao_shi_jian
+                    // 表单验证通过,提交表单
+                    this.submitForm()
+                } else {
+                    ActionUtils.saveErrorMessage()
+                }
+            })
+        },
+        submitForm () {
+            const addParams = {
+                tableName: 't_exams',
+                paramWhere: [this.form]
+            }
+            const updateParams = {
+                tableName: 't_exams',
+                updList: [
+                    {
+                        where: {
+                            id_: this.id
+                        },
+                        param: this.form
+                    }
+                ]
+            }
+            const type = this.id ? 'update' : 'add'
+            const params = type === 'add' ? addParams : updateParams
+            this.$common.request(type, params).then(() => {
+                this.$message.success(this.id ? '修改考试成功' : '新建考试成功')
+                this.closeDialog()
+            })
+        },
+        // 关闭当前窗口
+        closeDialog () {
+            this.$emit('close', false)
+        }
+    }
+}
+</script>
+<style lang="scss" scoped>
+    .exam-dialog {
+        ::v-deep {
+            .el-dialog {
+                max-width: 1080px;
+            }
+            .el-dialog__body {
+                height: calc(88vh - 200px);
+            }
+            .el-form-item {
+                margin-bottom: 14px !important;
+                &:last-child {
+                    margin-bottom: 0 !important;
+                }
+                .el-form-item__label {
+                    font-size: 14px !important;
+                }
+            }
+            .el-form-item--small .el-form-item__error {
+                padding-top: 6px;
+            }
+        }
+        .exam-form {
+            padding: 20px;
+            .question-icon {
+                font-size: 13px;
+                color: #606060;
+            }
+            .date-picker {
+                margin-left: 20px;
+            }
+            .custom-dialog {
+                ::v-deep {
+                    .el-input--prefix .el-input__inner {
+                        padding-left: 15px;
+                    }
+                }
+            }
+        }
+        .inline-item {
+            ::v-deep {
+                .el-radio-group {
+                    margin-right: 20px;
+                }
+            }
+            .time {
+                display: inline-block;
+            }
+        }
+        .unit {
+            display: inline-block;
+            margin: 0 20px 0 5px;
+        }
+    }
+</style>

+ 123 - 25
src/views/platform/examine/question/edit.vue → src/views/platform/examination/question/edit.vue

@@ -55,7 +55,7 @@
                     </el-select>
                     </el-select>
                 </el-form-item>
                 </el-form-item>
             </div>
             </div>
-            <div class="inline-item">
+            <div class="inline-item" :class="['单选题', '多选题', '判断题'].includes(form.ti_xing_) ? 'mb-20' : ''">
                 <el-form-item label="评分方式:" prop="ping_fen_fang_shi">
                 <el-form-item label="评分方式:" prop="ping_fen_fang_shi">
                     <el-radio-group v-model="questionRateType" disabled>
                     <el-radio-group v-model="questionRateType" disabled>
                         <el-radio-button label="自动">自动</el-radio-button>
                         <el-radio-button label="自动">自动</el-radio-button>
@@ -89,6 +89,28 @@
                     placeholder="请输入题干内容"
                     placeholder="请输入题干内容"
                 />
                 />
             </el-form-item>
             </el-form-item>
+            <el-form-item label="标签:" prop="biao_qian_">
+                <el-tag
+                    v-for="tag in questionTags"
+                    :key="tag"
+                    closable
+                    size="medium"
+                    :disable-transitions="false"
+                    @close="handleTagDelete(tag)"
+                >
+                    {{ tag }}
+                </el-tag>
+                <el-input
+                    v-if="tagInputVisible"
+                    ref="saveTagInput"
+                    v-model="tagValue"
+                    class="input-new-tag"
+                    size="small"
+                    @keyup.enter.native="handleTagConfirm"
+                    @blur="handleTagConfirm"
+                />
+                <el-button v-else class="button-new-tag" size="small" @click="showTagEdit">+ 添 加</el-button>
+            </el-form-item>
             <el-form-item label="附图:" prop="fu_tu_">
             <el-form-item label="附图:" prop="fu_tu_">
                 <ibps-image
                 <ibps-image
                     v-model="form.fu_tu_"
                     v-model="form.fu_tu_"
@@ -101,7 +123,7 @@
                     :disabled="false"
                     :disabled="false"
                 />
                 />
             </el-form-item>
             </el-form-item>
-            <div class="inline-item">
+            <div class="inline-item" :class="['单选题', '多选题'].includes(form.ti_xing_) ? '' : 'mb-20'">
                 <el-form-item label="分值:" prop="fen_zhi_" :maxlength="8">
                 <el-form-item label="分值:" prop="fen_zhi_" :maxlength="8">
                     <el-input-number
                     <el-input-number
                         v-model="form.fen_zhi_"
                         v-model="form.fen_zhi_"
@@ -236,7 +258,7 @@ export default {
             type: Boolean,
             type: Boolean,
             default: false
             default: false
         },
         },
-        paperId: {
+        bankId: {
             type: String,
             type: String,
             default: ''
             default: ''
         },
         },
@@ -253,14 +275,15 @@ export default {
             questionType,
             questionType,
             rateType,
             rateType,
             deptList: deptList.filter(i => i.depth === 4),
             deptList: deptList.filter(i => i.depth === 4),
-            title: '添加题目',
+            title: this.id ? '编辑题目' : '添加题目',
             formLabelWidth: '120px',
             formLabelWidth: '120px',
             dialogVisible: this.visible,
             dialogVisible: this.visible,
             dialogLoading: false,
             dialogLoading: false,
-            filePreviewVisible: false,
+            tagInputVisible: false,
+            tagValue: '',
             form: {
             form: {
                 // bu_men_: '',
                 // bu_men_: '',
-                parent_id_: this.paperId,
+                parent_id_: this.bankId,
                 chu_ti_ren_: userId,
                 chu_ti_ren_: userId,
                 chu_ti_shi_jian_: this.$common.getDateNow(19),
                 chu_ti_shi_jian_: this.$common.getDateNow(19),
                 ti_gan_: '',
                 ti_gan_: '',
@@ -276,6 +299,7 @@ export default {
                 bei_zhu_: '',
                 bei_zhu_: '',
                 zhuang_tai_: '启用'
                 zhuang_tai_: '启用'
             },
             },
+            questionTags: [],
             toolbars: [
             toolbars: [
                 {
                 {
                     key: 'submit',
                     key: 'submit',
@@ -334,17 +358,10 @@ export default {
             this.optionList.map(i => (i.radio = null))
             this.optionList.map(i => (i.radio = null))
             this.optionList[index].radio = value
             this.optionList[index].radio = value
         },
         },
-        changeCheckbox (index, value) {
-            console.log(value)
-            // if (this.optionList[index].checkbox) {
-
-            // }
-            // this.optionList[index].checkbox = [value]
-        },
         changeQuestionType (value) {
         changeQuestionType (value) {
             if (value === '填空题') {
             if (value === '填空题') {
                 this.optionList = [{
                 this.optionList = [{
-                    value: 'A',
+                    value: '',
                     radio: null,
                     radio: null,
                     checkbox: [],
                     checkbox: [],
                     content: ''
                     content: ''
@@ -389,6 +406,22 @@ export default {
             ]
             ]
             return this.userList
             return this.userList
         },
         },
+        handleTagDelete (tag) {
+            this.questionTags.splice(this.questionTags.indexOf(tag), 1)
+        },
+        showTagEdit () {
+            this.tagInputVisible = true
+            this.$nextTick(_ => {
+                this.$refs.saveTagInput.$refs.input.focus()
+            })
+        },
+        handleTagConfirm () {
+            if (this.tagValue) {
+                this.questionTags.push(this.tagValue)
+            }
+            this.tagInputVisible = false
+            this.tagValue = ''
+        },
         handleActionEvent ({ key }) {
         handleActionEvent ({ key }) {
             switch (key) {
             switch (key) {
                 case 'submit':
                 case 'submit':
@@ -406,15 +439,50 @@ export default {
             if (this.$utils.isEmpty(this.id)) {
             if (this.$utils.isEmpty(this.id)) {
                 return
                 return
             }
             }
-            const sql = `select id_, bian_zhi_ren_, bian_zhi_bu_men_, bian_zhi_shi_jian, ti_gan_, ti_xing_, xuan_xiang_lei_xi, xian_kao_ci_shu_, ping_fen_ren_, bei_zhu_, suo_shu_fan_wei_ from t_question where id_ = '${this.id}'`
+            const sql = `select id_, chu_ti_ren_, bu_men_, chu_ti_shi_jian_, ti_gan_, ti_xing_, xuan_xiang_lei_xi, biao_qian_, da_an_, zheng_que_da_an_, ping_fen_fang_shi, ping_fen_ren_, fen_zhi_, zhuang_tai_, xuan_xiang_shu_, fu_tu_, bei_zhu_ from t_questions where id_ = '${this.id}'`
             this.$common.request('sql', sql).then(res => {
             this.$common.request('sql', sql).then(res => {
                 const { data = [] } = res.variables || {}
                 const { data = [] } = res.variables || {}
                 if (!data.length) {
                 if (!data.length) {
-                    this.$message.error('数据不存在')
-                    return
+                    return this.$message.error('获取题目数据失败!')
+                }
+                const item = data[0]
+                if (item.ti_xing_ === '填空题') {
+                    const rightKey = item.zheng_que_da_an_ ? JSON.parse(item.zheng_que_da_an_) : []
+                    this.optionList = rightKey.map(i => ({
+                        value: '',
+                        radio: null,
+                        checkbox: [],
+                        content: i
+                    }))
+                } else if (item.ti_xing_ === '单选题') {
+                    const rightKey = item.zheng_que_da_an_ || ''
+                    const options = item.da_an_ ? JSON.parse(item.da_an_) : {}
+                    this.optionList = []
+                    Object.keys(options).forEach(key => {
+                        this.optionList.push({
+                            value: key,
+                            radio: key === rightKey ? key : null,
+                            checkbox: [],
+                            content: options[key]
+                        })
+                    })
+                } else if (item.ti_xing_ === '多选题') {
+                    const rightKey = item.zheng_que_da_an_ ? item.zheng_que_da_an_.split(',') : []
+                    const options = item.da_an_ ? JSON.parse(item.da_an_) : {}
+                    this.optionList = []
+                    Object.keys(options).forEach(key => {
+                        this.optionList.push({
+                            value: key,
+                            radio: null,
+                            checkbox: rightKey,
+                            content: options[key]
+                        })
+                    })
                 }
                 }
-                this.form = data[0]
-                this.form.isLimit = data[0].xian_kao_ci_shu_ === '不限' ? 0 : 1
+                item.fen_zhi_ = parseInt(item.fen_zhi_)
+                item.fu_tu_ = item.fu_tu_ ? JSON.parse(item.fu_tu_) : ''
+                this.questionTags = item.biao_qian_ ? item.biao_qian_.split(',') : []
+                this.form = item
             })
             })
         },
         },
         handleSubmit () {
         handleSubmit () {
@@ -442,6 +510,7 @@ export default {
                 }
                 }
                 a3.push(item.content)
                 a3.push(item.content)
             })
             })
+            this.form.biao_qian_ = this.questionTags.join(',')
             this.form.ping_fen_fang_shi = this.questionRateType
             this.form.ping_fen_fang_shi = this.questionRateType
             switch (this.form.ti_xing_) {
             switch (this.form.ti_xing_) {
                 case '单选题':
                 case '单选题':
@@ -498,7 +567,7 @@ export default {
             })
             })
         },
         },
         updatePaper () {
         updatePaper () {
-            const sql = `select fen_zhi_ from t_questions where parent_id_ = '${this.paperId}'`
+            const sql = `select fen_zhi_ from t_questions where parent_id_ = '${this.bankId}'`
             this.$common.request('sql', sql).then(res => {
             this.$common.request('sql', sql).then(res => {
                 const { data = [] } = res.variables || {}
                 const { data = [] } = res.variables || {}
                 const params = {
                 const params = {
@@ -506,7 +575,7 @@ export default {
                     updList: [
                     updList: [
                         {
                         {
                             where: {
                             where: {
-                                id_: this.paperId
+                                id_: this.bankId
                             },
                             },
                             param: {
                             param: {
                                 ti_shu_: data.length,
                                 ti_shu_: data.length,
@@ -530,15 +599,20 @@ export default {
 <style lang="scss" scoped>
 <style lang="scss" scoped>
     .question-dialog {
     .question-dialog {
         ::v-deep {
         ::v-deep {
+            .el-dialog {
+                min-width: 1080px;
+            }
             .el-dialog__body {
             .el-dialog__body {
                 height: calc(88vh - 200px);
                 height: calc(88vh - 200px);
             }
             }
-            .question-form > .el-form-item:first-child {
-                margin-top: 20px;
-            }
             .el-form-item {
             .el-form-item {
                 margin-bottom: 14px !important;
                 margin-bottom: 14px !important;
-                padding: 0 20px;
+                &:last-child {
+                    margin-bottom: 0 !important;
+                }
+                .el-form-item__label {
+                    font-size: 14px !important;
+                }
             }
             }
             .el-form-item--small .el-form-item__error {
             .el-form-item--small .el-form-item__error {
                 padding-top: 6px;
                 padding-top: 6px;
@@ -552,6 +626,27 @@ export default {
                     background-color: #409EFF;
                     background-color: #409EFF;
                 }
                 }
             }
             }
+            .el-tag {
+                margin-right: 10px;
+                height: 32px;
+                line-height: 30px;
+                .el-icon-close {
+                    top: 0px;
+                }
+            }
+        }
+        .button-new-tag {
+            height: 32px;
+            line-height: 30px;
+            padding-top: 0;
+            padding-bottom: 0;
+        }
+        .input-new-tag {
+            width: 100px;
+            vertical-align: bottom;
+        }
+        .question-form {
+            padding: 20px;
         }
         }
         .ibps-image {
         .ibps-image {
             font-size: 0;
             font-size: 0;
@@ -570,6 +665,9 @@ export default {
                 }
                 }
             }
             }
         }
         }
+        .mb-20 {
+            margin-bottom: 20px;
+        }
         .option-item {
         .option-item {
             ::v-deep {
             ::v-deep {
                 .el-form-item__content {
                 .el-form-item__content {

+ 2 - 4
src/views/platform/examine/question/judge.vue → src/views/platform/examination/question/judge.vue

@@ -118,10 +118,6 @@ export default {
             type: Boolean,
             type: Boolean,
             default: false
             default: false
         },
         },
-        paperId: {
-            type: String,
-            default: ''
-        },
         id: {
         id: {
             type: String,
             type: String,
             default: ''
             default: ''
@@ -475,6 +471,8 @@ export default {
                 position: absolute;
                 position: absolute;
                 width: calc(100% - 40px);
                 width: calc(100% - 40px);
                 bottom: 20px;
                 bottom: 20px;
+                height: 80px;
+                overflow-y: auto;
                 .el-progress {
                 .el-progress {
                     width: 100%;
                     width: 100%;
                     margin-bottom: 10px;
                     margin-bottom: 10px;

+ 21 - 15
src/views/platform/examine/questionBank/detail.vue → src/views/platform/examination/questionBank/detail.vue

@@ -23,11 +23,11 @@
                     <span class="value">{{ paperData.totalCount }}</span>
                     <span class="value">{{ paperData.totalCount }}</span>
                 </div>
                 </div>
                 <div class="info-item">
                 <div class="info-item">
-                    <span class="label">总分</span>
+                    <span class="label">总分</span>
                     <span class="value">{{ paperData.totalScore }}分</span>
                     <span class="value">{{ paperData.totalScore }}分</span>
                 </div>
                 </div>
                 <div class="info-item">
                 <div class="info-item">
-                    <span class="label">达标分数占比:</span>
+                    <span class="label">达标占比:</span>
                     <span class="value">{{ paperData.qualifiedRadio }}%</span>
                     <span class="value">{{ paperData.qualifiedRadio }}%</span>
                 </div>
                 </div>
                 <div class="info-item">
                 <div class="info-item">
@@ -200,19 +200,26 @@ export default {
             type: Boolean,
             type: Boolean,
             default: false
             default: false
         },
         },
-        paperId: {
+        bankId: {
+            type: String,
+            default: ''
+        },
+        examId: {
             type: String,
             type: String,
             default: ''
             default: ''
         },
         },
         id: {
         id: {
             type: String,
             type: String,
             default: ''
             default: ''
+        },
+        examineeId: {
+            type: String,
+            default: ''
         }
         }
     },
     },
     data () {
     data () {
-        const { userId } = this.$store.getters || {}
         return {
         return {
-            title: '试详情',
+            title: '试详情',
             dialogVisible: this.visible,
             dialogVisible: this.visible,
             toolbars: [
             toolbars: [
                 { key: 'cancel', label: '退出' }
                 { key: 'cancel', label: '退出' }
@@ -221,8 +228,7 @@ export default {
             paperData: [],
             paperData: [],
             maxScore: '',
             maxScore: '',
             minScore: '',
             minScore: '',
-            showPaperId: '',
-            userId
+            showPaperId: ''
         }
         }
     },
     },
     computed: {
     computed: {
@@ -248,15 +254,14 @@ export default {
     methods: {
     methods: {
         // 获取题库数据
         // 获取题库数据
         async loadData () {
         async loadData () {
-            if (!this.paperId) {
+            if (!this.bankId) {
                 this.$message.error('获取题目信息失败,请重试!')
                 this.$message.error('获取题目信息失败,请重试!')
                 this.closeDialog()
                 this.closeDialog()
                 return
                 return
             }
             }
             this.paperList = await this.getQuestionData()
             this.paperList = await this.getQuestionData()
-            this.paperData = this.paperList.find(i => i.dataId === this.id)
-            this.showPaperId = this.id
-            console.log(this.paperData)
+            this.paperData = this.paperList.find(i => i.dataId === this.id) || this.paperList[0]
+            this.showPaperId = this.paperData.dataId
         },
         },
         handleActionEvent ({ key }) {
         handleActionEvent ({ key }) {
             switch (key) {
             switch (key) {
@@ -278,12 +283,13 @@ export default {
             return user.userName || '-'
             return user.userName || '-'
         },
         },
         getQuestionData () {
         getQuestionData () {
-            const sql = `select e.id_ as dataId, e.kao_shi_ren_ as examinee, e.bu_men_ as dept, e.zhuang_tai_ as status, e.bao_ming_shi_jian as applyTime, e.kai_shi_shi_jian_ as startTime, e.jie_shu_shi_jian_ as endTime, e.ti_ku_zong_fen_ as totalScore, e.da_biao_zhan_bi_ as qualifiedRadio, e.de_fen_ as resultScore, ed.ti_mu_id_ as questionId, ed.ti_gan_ as stem, ed.ti_xing_ as questionType, ed.fen_zhi_ as questionScore, ed.fu_tu_ as img, ed.xuan_xiang_lei_xi as optionsType, ed.xuan_xiang_ as options, ed.can_kao_da_an_ as rightKey, ed.ping_fen_fang_shi as rateType, ed.ping_fen_ren_ as rater, ed.hui_da_ as answer, ed.ping_yue_shi_jian as rateTime, ed.de_fen_ as score, ed.jie_xi_ as analysis, q.ti_ku_ming_cheng_ as paperName, q.ji_fen_fang_shi_ as scoringType from t_examination e, t_examination_detail ed, t_question_bank q where e.id_ = ed.parent_id_ and e.ti_ku_id_ = q.id_ and e.ti_ku_id_ = '${this.paperId}' and (e.zhuang_tai_ = '已完成' or e.zhuang_tai_ = '已交卷') order by field(ed.ti_xing_, '单选题', '多选题', '判断题', '填空题', '简答题')`
+            const param = this.examId ? `and e.exam_id_ = '${this.examId}'` : 'and e.exam_id_ is null'
+            const sql = `select e.id_ as dataId, e.exam_id_ as examId, e.kao_shi_ren_ as examinee, e.bu_men_ as dept, e.zhuang_tai_ as status, e.bao_ming_shi_jian as applyTime, e.kai_shi_shi_jian_ as startTime, e.jie_shu_shi_jian_ as endTime, e.ti_ku_zong_fen_ as totalScore, e.de_fen_ as resultScore, ed.ti_mu_id_ as questionId, ed.ti_gan_ as stem, ed.ti_xing_ as questionType, ed.fen_zhi_ as questionScore, ed.fu_tu_ as img, ed.xuan_xiang_lei_xi as optionsType, ed.xuan_xiang_ as options, ed.can_kao_da_an_ as rightKey, ed.ping_fen_fang_shi as rateType, ed.ping_fen_ren_ as rater, ed.hui_da_ as answer, ed.ping_yue_shi_jian as rateTime, ed.de_fen_ as score, ed.jie_xi_ as analysis, q.ti_ku_ming_cheng_ as paperName, case when e.exam_id_ is not null then ex.da_biao_zhan_bi_ else q.da_biao_zhan_bi_ end as qualifiedRadio, case when e.exam_id_ is not null then ex.ji_fen_fang_shi_ else q.ji_fen_fang_shi_ end as scoringType, case when e.exam_id_ is not null then ex.kao_shi_ming_chen else '自主考核' end as examName, case when e.exam_id_ is not null then ex.xian_kao_shi_jian else '不限' end as limitDate from t_examination e left join t_examination_detail ed on e.id_ = ed.parent_id_ left join  t_question_bank q on e.ti_ku_id_ = q.id_ left join  t_exams ex on e.exam_id_ = ex.id_ where e.ti_ku_id_ = '${this.bankId}' ${param} and e.kao_shi_ren_ = '${this.examineeId}' and (e.zhuang_tai_ = '已完成' or e.zhuang_tai_ = '已交卷') order by field(ed.ti_xing_, '单选题', '多选题', '判断题', '填空题', '简答题')`
             return new Promise((resolve, reject) => {
             return new Promise((resolve, reject) => {
                 this.$common.request('sql', sql).then(res => {
                 this.$common.request('sql', sql).then(res => {
                     const { data = [] } = res.variables || {}
                     const { data = [] } = res.variables || {}
                     if (!data.length) {
                     if (!data.length) {
-                        this.$message.error('获取题目信息失败!')
+                        this.$message.error('未查询到已提交的考试记录,请先完成考试!')
                         this.closeDialog()
                         this.closeDialog()
                         return
                         return
                     }
                     }
@@ -318,7 +324,7 @@ export default {
                                 qualifiedRadio,
                                 qualifiedRadio,
                                 isQualified: status === '已完成' ? parseFloat(resultScore) >= (parseFloat(qualifiedRadio) / 100 * parseFloat(totalScore)) : '',
                                 isQualified: status === '已完成' ? parseFloat(resultScore) >= (parseFloat(qualifiedRadio) / 100 * parseFloat(totalScore)) : '',
                                 paperName,
                                 paperName,
-                                totalScore: parseFloat(resultScore),
+                                totalScore: parseFloat(totalScore),
                                 resultScore: parseFloat(resultScore),
                                 resultScore: parseFloat(resultScore),
                                 totalCount: data.length,
                                 totalCount: data.length,
                                 scoringType,
                                 scoringType,
@@ -441,7 +447,7 @@ export default {
                 display: flex;
                 display: flex;
                 align-items: center;
                 align-items: center;
                 .label {
                 .label {
-                    width: 120px;
+                    width: 100px;
                     font-weight: bold;
                     font-weight: bold;
                     color: #333;
                     color: #333;
                 }
                 }

+ 208 - 20
src/views/platform/examine/questionBank/edit.vue → src/views/platform/examination/questionBank/edit.vue

@@ -16,7 +16,7 @@
             :label-width="formLabelWidth"
             :label-width="formLabelWidth"
             :model="form"
             :model="form"
             :rules="rules"
             :rules="rules"
-            class="question-form"
+            class="paper-form"
             @submit.native.prevent
             @submit.native.prevent
         >
         >
             <el-form-item label="题库名称:" prop="ti_ku_ming_cheng_">
             <el-form-item label="题库名称:" prop="ti_ku_ming_cheng_">
@@ -44,6 +44,18 @@
                     <el-radio label="不可用">不可用</el-radio>
                     <el-radio label="不可用">不可用</el-radio>
                 </el-radio-group>
                 </el-radio-group>
             </el-form-item>
             </el-form-item>
+            <el-form-item prop="shi_fou_gong_kai_">
+                <template slot="label">
+                    是否公开
+                    <el-tooltip effect="dark" content="限制该题库是否可自主考核。若您希望该题库仅用于考试中,则需要设置为“否" placement="top">
+                        <i class="el-icon-question question-icon">:</i>
+                    </el-tooltip>
+                </template>
+                <el-radio-group v-model="form.shi_fou_gong_kai_">
+                    <el-radio label="是">是</el-radio>
+                    <el-radio label="否">否</el-radio>
+                </el-radio-group>
+            </el-form-item>
             <el-form-item label="所属范围:" prop="suo_shu_fan_wei_" class="inline-item">
             <el-form-item label="所属范围:" prop="suo_shu_fan_wei_" class="inline-item">
                 <el-radio-group v-model="form.suo_shu_fan_wei_">
                 <el-radio-group v-model="form.suo_shu_fan_wei_">
                     <el-radio label="科级">科级</el-radio>
                     <el-radio label="科级">科级</el-radio>
@@ -135,12 +147,124 @@
                 <el-input v-model="form.miao_shu_" type="textarea" :rows="4" placeholder="请输入描述内容" />
                 <el-input v-model="form.miao_shu_" type="textarea" :rows="4" placeholder="请输入描述内容" />
             </el-form-item>
             </el-form-item>
         </el-form>
         </el-form>
+        <div class="question-table">
+            <el-table
+                ref="elTable"
+                :data="questionData"
+                border
+                stripe
+                highlight-current-row
+                style="width: 100%"
+                max-height="400px"
+                class="exam-table"
+                @row-dblclick="handleRowDblclick"
+            >
+                <el-table-column label="序号" type="index" width="50" />
+                <el-table-column
+                    prop="content"
+                    label="题干"
+                    min-width="150"
+                >
+                    <template slot-scope="scope">
+                        <el-popover trigger="hover" placement="top">
+                            <div class="question-info">
+                                <div class="question-info-item">
+                                    <div class="label">出题人</div>
+                                    <div class="value">{{ transformUser(scope.row.creator) }}</div>
+                                </div>
+                                <div class="question-info-item">
+                                    <div class="label">选项类型</div>
+                                    <div class="value">{{ scope.row.optionType || '—' }}</div>
+                                </div>
+                                <div class="question-info-item">
+                                    <div class="label">评分方式</div>
+                                    <div class="value">{{ scope.row.rateType }}</div>
+                                </div>
+                                <div class="question-info-item">
+                                    <div class="label">评分人</div>
+                                    <div class="value">{{ scope.row.rater || '—' }}</div>
+                                </div>
+                                <div class="question-info-item">
+                                    <div class="label">标签</div>
+                                    <div class="value">{{ scope.row.quesTag }}</div>
+                                </div>
+                                <div class="question-info-item">
+                                    <div class="label">状态</div>
+                                    <div class="value">{{ scope.row.quesState }}</div>
+                                </div>
+                            </div>
+                            <div slot="reference" class="name-wrapper">{{ scope.row.content }}</div>
+                        </el-popover>
+                    </template>
+                </el-table-column>
+                <el-table-column
+                    prop="quesType"
+                    label="题型"
+                    width="70"
+                />
+                <!-- <el-table-column
+                    prop="optionType"
+                    label="选项类型"
+                    width="70"
+                />
+                <el-table-column
+                    prop="rateType"
+                    label="评分方式"
+                    width="70"
+                />
+                <el-table-column
+                    prop="rater"
+                    label="评分人"
+                    width="70"
+                >
+                    <template slot-scope="scope">
+                        <div>{{ transformUser(scope.row.rater) }}</div>
+                    </template>
+                </el-table-column> -->
+                <el-table-column
+                    prop="score"
+                    label="分值"
+                    width="75"
+                    sortable
+                />
+                <!-- <el-table-column
+                    prop="creator"
+                    label="出题人"
+                    width="70"
+                >
+                    <template slot-scope="scope">
+                        <div>{{ transformUser(scope.row.creator) }}</div>
+                    </template>
+                </el-table-column> -->
+                <el-table-column
+                    prop="createTime"
+                    label="出题时间"
+                    width="150"
+                    sortable
+                />
+                <el-table-column
+                    fixed="right"
+                    label="操作"
+                    width="60"
+                >
+                    <template slot-scope="scope">
+                        <el-button type="text" size="small" @click="handleRowDblclick(scope.row)">修改</el-button>
+                    </template>
+                </el-table-column>
+            </el-table>
+        </div>
         <div slot="footer" class="el-dialog--center">
         <div slot="footer" class="el-dialog--center">
             <ibps-toolbar
             <ibps-toolbar
                 :actions="toolbars"
                 :actions="toolbars"
                 @action-event="handleActionEvent"
                 @action-event="handleActionEvent"
             />
             />
         </div>
         </div>
+        <ques-edit
+            v-if="questionDialogVisible"
+            :id="quesId"
+            :visible.sync="questionDialogVisible"
+            @close="questionDialogVisible = false"
+        />
     </el-dialog>
     </el-dialog>
 </template>
 </template>
 
 
@@ -148,6 +272,9 @@
 import ActionUtils from '@/utils/action'
 import ActionUtils from '@/utils/action'
 import { paperTypeOptions } from '../constants'
 import { paperTypeOptions } from '../constants'
 export default {
 export default {
+    components: {
+        QuesEdit: () => import('../question/edit')
+    },
     props: {
     props: {
         visible: {
         visible: {
             type: Boolean,
             type: Boolean,
@@ -164,11 +291,13 @@ export default {
             userList,
             userList,
             paperTypeOptions,
             paperTypeOptions,
             deptList: deptList.filter(i => i.depth === 4),
             deptList: deptList.filter(i => i.depth === 4),
-            title: '创建题库',
+            title: this.id ? '编辑题库' : '创建题库',
             formLabelWidth: '120px',
             formLabelWidth: '120px',
             dialogVisible: this.visible,
             dialogVisible: this.visible,
             dialogLoading: false,
             dialogLoading: false,
-            filePreviewVisible: false,
+            questionData: [],
+            questionDialogVisible: false,
+            quesId: '',
             form: {
             form: {
                 bian_zhi_bu_men_: '',
                 bian_zhi_bu_men_: '',
                 bian_zhi_ren_: userId,
                 bian_zhi_ren_: userId,
@@ -178,6 +307,7 @@ export default {
                 ti_ku_fen_lei_: paperTypeOptions.length ? paperTypeOptions[0].value : '',
                 ti_ku_fen_lei_: paperTypeOptions.length ? paperTypeOptions[0].value : '',
                 ti_ku_zhuang_tai_: '可用',
                 ti_ku_zhuang_tai_: '可用',
                 xian_kao_ci_shu_: '不限',
                 xian_kao_ci_shu_: '不限',
+                shi_fou_gong_kai_: '是',
                 ping_fen_ren_: '',
                 ping_fen_ren_: '',
                 da_biao_zhan_bi_: 60,
                 da_biao_zhan_bi_: 60,
                 miao_shu_: '',
                 miao_shu_: '',
@@ -203,6 +333,7 @@ export default {
                 suo_shu_fan_wei_: [{ required: true, message: this.$t('validate.required') }],
                 suo_shu_fan_wei_: [{ required: true, message: this.$t('validate.required') }],
                 bian_zhi_bu_men_: [{ required: true, message: this.$t('validate.required') }],
                 bian_zhi_bu_men_: [{ required: true, message: this.$t('validate.required') }],
                 ti_ku_fen_lei_: [{ required: true, message: this.$t('validate.required') }],
                 ti_ku_fen_lei_: [{ required: true, message: this.$t('validate.required') }],
+                shi_fou_gong_kai_: [{ required: true, message: this.$t('validate.required') }],
                 ti_ku_zhuang_tai_: [{ required: true, message: this.$t('validate.required') }],
                 ti_ku_zhuang_tai_: [{ required: true, message: this.$t('validate.required') }],
                 xian_kao_ci_shu_: [{ required: true, message: this.$t('validate.required') }],
                 xian_kao_ci_shu_: [{ required: true, message: this.$t('validate.required') }],
                 kao_shi_shi_chang: [{ required: true, message: this.$t('validate.required') }],
                 kao_shi_shi_chang: [{ required: true, message: this.$t('validate.required') }],
@@ -214,9 +345,6 @@ export default {
     computed: {
     computed: {
         formId () {
         formId () {
             return this.id
             return this.id
-        },
-        formData () {
-            return this.data
         }
         }
     },
     },
     watch: {
     watch: {
@@ -267,6 +395,15 @@ export default {
             ]
             ]
             return this.userList
             return this.userList
         },
         },
+        transformUser (userId) {
+            const { userList = [] } = this.$store.getters
+            const user = userList.find(u => u.userId === userId) || {}
+            return user.userName || '-'
+        },
+        handleRowDblclick (row) {
+            this.quesId = row.quesId
+            this.questionDialogVisible = true
+        },
         handleActionEvent ({ key }) {
         handleActionEvent ({ key }) {
             switch (key) {
             switch (key) {
                 case 'submit':
                 case 'submit':
@@ -284,24 +421,29 @@ export default {
             if (this.$utils.isEmpty(this.formId)) {
             if (this.$utils.isEmpty(this.formId)) {
                 return
                 return
             }
             }
-            const sql = `select id_, bian_zhi_ren_, bian_zhi_bu_men_, bian_zhi_shi_jian, ti_ku_ming_cheng_, ti_ku_fen_lei_, ti_ku_zhuang_tai_, xian_kao_ci_shu_, ping_fen_ren_, miao_shu_, suo_shu_fan_wei_, kao_shi_shi_chang, da_biao_zhan_bi_ from t_question_bank where id_ = '${this.formId}'`
-            this.$common.request('sql', sql).then(res => {
-                const { data = [] } = res.variables || {}
-                if (!data.length) {
+            const sql1 = `select id_, bian_zhi_ren_, bian_zhi_bu_men_, bian_zhi_shi_jian, ti_ku_ming_cheng_, ti_ku_fen_lei_, ti_ku_zhuang_tai_, shi_fou_gong_kai_, xian_kao_ci_shu_, ping_fen_ren_, miao_shu_, suo_shu_fan_wei_, kao_shi_shi_chang, da_biao_zhan_bi_ from t_question_bank where id_ = '${this.formId}'`
+            const sql2 = `select id_ as quesId, chu_ti_ren_ as creator, bu_men_ as createDept, chu_ti_shi_jian_ as createTime, xu_hao_ as sn, ti_gan_ as content, ti_xing_ as quesType, xuan_xiang_lei_xi as optionType, zheng_que_da_an_ as answer, ping_fen_fang_shi as rateType, ping_fen_ren_ as rater, fen_zhi_ as score, biao_qian_ as quesTag, zhuang_tai_ as quesState from t_questions where parent_id_ = '${this.formId}'`
+            Promise.all([this.$common.request('sql', sql1), this.$common.request('sql', sql2)]).then(([res1, res2]) => {
+                const { data: bankData = [] } = res1.variables || {}
+                const { data: questionData = [] } = res2.variables || {}
+                if (!bankData.length) {
                     this.$message.error('数据不存在')
                     this.$message.error('数据不存在')
                     return
                     return
                 }
                 }
-                data[0].isLimit = data[0].xian_kao_ci_shu_ === '不限' ? '0' : '1'
-                if (data[0].kao_shi_shi_chang === '不限') {
-                    data[0].limitTime = '0'
-                    data[0].hours = null
-                    data[0].minutes = null
+                const bank = bankData[0]
+                bank.isLimit = bank.xian_kao_ci_shu_ === '不限' ? '0' : '1'
+                if (bank.kao_shi_shi_chang === '不限') {
+                    bank.limitTime = '0'
+                    bank.hours = null
+                    bank.minutes = null
                 } else {
                 } else {
-                    data[0].limitTime = '1'
-                    data[0].hours = Math.floor(data[0].kao_shi_shi_chang / (1000 * 60 * 60))
-                    data[0].minutes = (data[0].kao_shi_shi_chang % (1000 * 60 * 60)) / (60 * 1000)
+                    bank.limitTime = '1'
+                    bank.hours = Math.floor(bank.kao_shi_shi_chang / (1000 * 60 * 60))
+                    bank.minutes = (bank.kao_shi_shi_chang % (1000 * 60 * 60)) / (60 * 1000)
                 }
                 }
-                this.form = data[0]
+                console.log(questionData)
+                this.questionData = questionData
+                this.form = bank
             })
             })
         },
         },
         handleSubmit () {
         handleSubmit () {
@@ -360,17 +502,28 @@ export default {
 <style lang="scss" scoped>
 <style lang="scss" scoped>
     .paper-dialog {
     .paper-dialog {
         ::v-deep {
         ::v-deep {
+            .el-dialog {
+                min-width: 1080px;
+            }
             .el-dialog__body {
             .el-dialog__body {
                 height: calc(88vh - 200px);
                 height: calc(88vh - 200px);
             }
             }
             .el-form-item {
             .el-form-item {
                 margin-bottom: 14px !important;
                 margin-bottom: 14px !important;
-                padding: 0 20px;
+                &:last-child {
+                    margin-bottom: 0 !important;
+                }
+                .el-form-item__label {
+                    font-size: 14px !important;
+                }
             }
             }
             .el-form-item--small .el-form-item__error {
             .el-form-item--small .el-form-item__error {
                 padding-top: 6px;
                 padding-top: 6px;
             }
             }
         }
         }
+        .paper-form {
+            padding: 20px;
+        }
         .inline-item {
         .inline-item {
             ::v-deep {
             ::v-deep {
                 .el-radio-group {
                 .el-radio-group {
@@ -385,5 +538,40 @@ export default {
             display: inline-block;
             display: inline-block;
             margin: 0 20px 0 5px;
             margin: 0 20px 0 5px;
         }
         }
+        .question-table {
+            margin-bottom: 20px;
+            padding: 0 20px;
+            ::v-deep {
+                .el-table {
+                    th {
+                        font-size: 14px !important;
+                        text-align: center;
+                    }
+                    td {
+                        font-size: 14px !important;
+                    }
+                    .el-table__row {
+                        cursor: pointer;
+                    }
+                }
+            }
+        }
+    }
+    .question-info {
+        .question-info-item {
+            display: flex;
+            margin-bottom: 10px;
+            max-width: 200px;
+            .label {
+                width: 100px;
+                font-size: 14px;
+                color: #606266;
+                text-align: right;
+                margin-right: 10px;
+            }
+            .value {
+                font-weight: 600;
+            }
+        }
     }
     }
 </style>
 </style>

+ 8 - 5
src/views/platform/examine/questionBank/test.vue → src/views/platform/examination/questionBank/test.vue

@@ -100,6 +100,7 @@
 </template>
 </template>
 
 
 <script>
 <script>
+// import Watermark from '@/layout/header-aside/components/header-message/watermark/watermark-cont'
 export default {
 export default {
     components: {
     components: {
         IbpsImage: () => import('@/business/platform/file/image')
         IbpsImage: () => import('@/business/platform/file/image')
@@ -109,7 +110,7 @@ export default {
             type: Boolean,
             type: Boolean,
             default: false
             default: false
         },
         },
-        paperId: {
+        bankId: {
             type: String,
             type: String,
             default: ''
             default: ''
         },
         },
@@ -178,16 +179,18 @@ export default {
     },
     },
     mounted () {
     mounted () {
         this.loadData()
         this.loadData()
+        // Watermark.set(`123`, `123123`)
         // 监听键盘事件
         // 监听键盘事件
         window.addEventListener('keyup', this.handleKeyPress)
         window.addEventListener('keyup', this.handleKeyPress)
     },
     },
     beforeDestroy () {
     beforeDestroy () {
         window.removeEventListener('keyup', this.handleKeyPress)
         window.removeEventListener('keyup', this.handleKeyPress)
+        // Watermark.set('', '')
     },
     },
     methods: {
     methods: {
         // 获取题库数据
         // 获取题库数据
         async loadData () {
         async loadData () {
-            if (!this.paperId) {
+            if (!this.bankId) {
                 this.$message.error('获取题目信息失败,请重试!')
                 this.$message.error('获取题目信息失败,请重试!')
                 this.closeDialog()
                 this.closeDialog()
                 return
                 return
@@ -214,7 +217,7 @@ export default {
             }
             }
         },
         },
         getQuestionData () {
         getQuestionData () {
-            const sql = `select id_ as questionId, ti_gan_ as stem, ti_xing_ as questionType, fu_tu_ as img, xuan_xiang_lei_xi as optionType, da_an_ as options, xuan_xiang_shu_ as optionsLength, fen_zhi_ as score, ping_fen_fang_shi as rateType, ping_fen_ren_ as rater, zheng_que_da_an_ as rightKey from t_questions where parent_id_ = '${this.paperId}' and zhuang_tai_ = '启用' order by field(ti_xing_, '单选题', '多选题', '判断题', '填空题', '简答题')`
+            const sql = `select id_ as questionId, ti_gan_ as stem, ti_xing_ as questionType, fu_tu_ as img, xuan_xiang_lei_xi as optionType, da_an_ as options, xuan_xiang_shu_ as optionsLength, fen_zhi_ as score, ping_fen_fang_shi as rateType, ping_fen_ren_ as rater, zheng_que_da_an_ as rightKey from t_questions where parent_id_ = '${this.bankId}' and zhuang_tai_ = '启用' order by field(ti_xing_, '单选题', '多选题', '判断题', '填空题', '简答题')`
             return new Promise((resolve, reject) => {
             return new Promise((resolve, reject) => {
                 this.$common.request('sql', sql).then(res => {
                 this.$common.request('sql', sql).then(res => {
                     const { data = [] } = res.variables || {}
                     const { data = [] } = res.variables || {}
@@ -225,7 +228,7 @@ export default {
                     }
                     }
                     data.map(item => {
                     data.map(item => {
                         if (item.options) {
                         if (item.options) {
-                            const temp = item.options ? JSON.parse(item.options) : {}
+                            const temp = JSON.parse(item.options) || {}
                             const o = []
                             const o = []
                             Object.keys(temp).forEach(key => {
                             Object.keys(temp).forEach(key => {
                                 o.push({
                                 o.push({
@@ -357,7 +360,7 @@ export default {
                         can_kao_da_an_: item.rightKey,
                         can_kao_da_an_: item.rightKey,
                         ping_fen_fang_shi: item.rateType,
                         ping_fen_fang_shi: item.rateType,
                         ping_fen_ren_: item.rater,
                         ping_fen_ren_: item.rater,
-                        hui_da_: multipleType && item.answer && item.answer.length ? JSON.stringify(item.answer) : item.answer,
+                        hui_da_: multipleType && item.answer ? JSON.stringify(item.answer) : item.answer,
                         shi_fou_yi_yue_: autoType ? '是' : '否',
                         shi_fou_yi_yue_: autoType ? '是' : '否',
                         ping_yue_shi_jian: autoType ? time : '',
                         ping_yue_shi_jian: autoType ? time : '',
                         de_fen_: autoType ? this.getScore(item) : '',
                         de_fen_: autoType ? this.getScore(item) : '',