510 lines
19 KiB
Vue
510 lines
19 KiB
Vue
<template>
|
||
<div class="app-container">
|
||
<el-form
|
||
v-show="showSearch"
|
||
ref="queryForm"
|
||
:model="queryParams"
|
||
size="small"
|
||
:inline="true"
|
||
label-width="88px"
|
||
>
|
||
<el-form-item label="培训班名称" prop="planName">
|
||
<el-input v-model="queryParams.planName" placeholder="请输入培训班名称" clearable @keyup.enter.native="handleQuery" />
|
||
</el-form-item>
|
||
<el-form-item label="计划状态" prop="planStatus">
|
||
<el-select v-model="queryParams.planStatus" placeholder="全部状态" clearable>
|
||
<el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="开班时间">
|
||
<el-date-picker
|
||
v-model="startTimeRange"
|
||
type="datetimerange"
|
||
value-format="yyyy-MM-dd HH:mm:ss"
|
||
range-separator="至"
|
||
start-placeholder="开始时间"
|
||
end-placeholder="结束时间"
|
||
clearable
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
|
||
<el-row :gutter="10" class="mb8">
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
v-hasPermi="['train:plan:add']"
|
||
type="primary"
|
||
plain
|
||
icon="el-icon-plus"
|
||
size="mini"
|
||
@click="handleAdd"
|
||
>新增计划</el-button>
|
||
</el-col>
|
||
<right-toolbar :show-search.sync="showSearch" @queryTable="getList" />
|
||
</el-row>
|
||
|
||
<el-table v-loading="loading" :data="planList">
|
||
<el-table-column label="计划编号" align="center" prop="planId" min-width="220" show-overflow-tooltip />
|
||
<el-table-column label="培训班名称" align="left" prop="planName" min-width="230" show-overflow-tooltip />
|
||
<el-table-column label="状态" align="center" prop="planStatus" width="100">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="statusTagType(scope.row.planStatus)">{{ statusLabel(scope.row.planStatus) }}</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="开班时间" align="center" prop="startTime" width="165" />
|
||
<el-table-column label="结束时间" align="center" prop="endTime" width="165" />
|
||
<el-table-column label="报到截止" align="center" prop="reportDeadline" width="165" />
|
||
<el-table-column label="培训地点" align="left" prop="trainAddress" min-width="180" show-overflow-tooltip />
|
||
<el-table-column label="计划人数" align="center" prop="recruitNum" width="90" />
|
||
<el-table-column label="课程数" align="center" prop="courseCount" width="90">
|
||
<template slot-scope="scope">
|
||
<el-button
|
||
v-hasPermi="['train:plan:query']"
|
||
type="text"
|
||
@click="handleCourseConfig(scope.row)"
|
||
>{{ scope.row.courseCount || 0 }}</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="参训人数" align="center" prop="enrolledCount" width="90" />
|
||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="230" fixed="right">
|
||
<template slot-scope="scope">
|
||
<el-button
|
||
v-hasPermi="['train:plan:query']"
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-reading"
|
||
@click="handleCourseConfig(scope.row)"
|
||
>课程配置</el-button>
|
||
<el-button
|
||
v-hasPermi="['train:plan:edit']"
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-edit"
|
||
:disabled="isLocked(scope.row.planStatus)"
|
||
@click="handleUpdate(scope.row)"
|
||
>修改</el-button>
|
||
<el-button
|
||
v-hasPermi="['train:plan:complete']"
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-finished"
|
||
:disabled="isLocked(scope.row.planStatus)"
|
||
@click="handleComplete(scope.row)"
|
||
>结束计划</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<pagination
|
||
v-show="total > 0"
|
||
:total="total"
|
||
:page.sync="queryParams.pageNum"
|
||
:limit.sync="queryParams.pageSize"
|
||
@pagination="getList"
|
||
/>
|
||
|
||
<!-- 创建/编辑培训计划对话框 -->
|
||
<el-dialog :title="title" :visible.sync="open" width="660px" append-to-body>
|
||
<el-form ref="form" :model="form" :rules="rules" label-width="110px">
|
||
<el-form-item label="培训班名称" prop="planName">
|
||
<el-input v-model="form.planName" maxlength="150" show-word-limit placeholder="请输入培训班名称" />
|
||
</el-form-item>
|
||
<el-row :gutter="20">
|
||
<el-col :span="12">
|
||
<el-form-item label="开班时间" prop="startTime">
|
||
<el-date-picker v-model="form.startTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择开班时间" style="width: 100%" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="结束时间" prop="endTime">
|
||
<el-date-picker v-model="form.endTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择结束时间" style="width: 100%" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row :gutter="20">
|
||
<el-col :span="12">
|
||
<el-form-item label="报到截止" prop="reportDeadline">
|
||
<el-date-picker v-model="form.reportDeadline" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择报到截止时间" style="width: 100%" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="计划人数" prop="recruitNum">
|
||
<el-input-number v-model="form.recruitNum" :min="1" :precision="0" style="width: 100%" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-form-item label="培训地点" prop="trainAddress">
|
||
<el-input v-model="form.trainAddress" maxlength="200" show-word-limit placeholder="请输入培训地点" />
|
||
</el-form-item>
|
||
<el-form-item label="报名条件" prop="applyCondition">
|
||
<el-input v-model="form.applyCondition" type="textarea" :rows="3" placeholder="请输入报名条件" />
|
||
</el-form-item>
|
||
<el-form-item label="备注" prop="remark">
|
||
<el-input v-model="form.remark" type="textarea" :rows="2" maxlength="500" show-word-limit placeholder="请输入备注" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||
<el-button @click="cancel">取 消</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<!-- 本期课程配置对话框 -->
|
||
<el-dialog :title="courseDialog.title" :visible.sync="courseDialog.open" width="900px" append-to-body>
|
||
<div style="margin-bottom: 15px; display: flex; justify-content: space-between; align-items: center;">
|
||
<div>
|
||
<span>班级状态:</span>
|
||
<el-tag :type="statusTagType(courseDialog.planStatus)">{{ statusLabel(courseDialog.planStatus) }}</el-tag>
|
||
<span style="margin-left: 15px; color: #909399; font-size: 13px;">已配置课程:{{ courseDialog.list.length }} 门</span>
|
||
</div>
|
||
<div>
|
||
<el-button
|
||
v-hasPermi="['train:plan:edit']"
|
||
type="primary"
|
||
size="mini"
|
||
icon="el-icon-plus"
|
||
:disabled="isLocked(courseDialog.planStatus)"
|
||
@click="handleOpenCourseSelector"
|
||
>引入课程</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<el-table v-loading="courseDialog.loading" :data="courseDialog.list" border style="width: 100%">
|
||
<el-table-column label="序号" type="index" width="55" align="center" />
|
||
<el-table-column label="课程编码" prop="cCode" min-width="120" show-overflow-tooltip />
|
||
<el-table-column label="课程名称" prop="cName" min-width="180" show-overflow-tooltip />
|
||
<el-table-column label="类型" prop="cType" width="80" align="center" />
|
||
<el-table-column label="学时" prop="cDuration" width="70" align="center" />
|
||
<el-table-column label="排序号" prop="sortNo" width="70" align="center" />
|
||
<el-table-column label="配置说明" prop="remark" min-width="120" show-overflow-tooltip />
|
||
<el-table-column label="操作" align="center" width="80" fixed="right">
|
||
<template slot-scope="scope">
|
||
<el-button
|
||
v-hasPermi="['train:plan:edit']"
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-delete"
|
||
style="color: #F56C6C;"
|
||
:disabled="isLocked(courseDialog.planStatus)"
|
||
@click="handleRemoveCourse(scope.row)"
|
||
>移除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button @click="courseDialog.open = false">关 闭</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<!-- 引入公共课程选择器弹窗 -->
|
||
<el-dialog title="引入公共课程" :visible.sync="selectorDialog.open" width="800px" append-to-body>
|
||
<el-form :model="selectorDialog.queryParams" size="small" :inline="true">
|
||
<el-form-item label="课程名称">
|
||
<el-input v-model="selectorDialog.queryParams.cName" placeholder="课程名称" clearable @keyup.enter.native="getCoursePool" />
|
||
</el-form-item>
|
||
<el-form-item label="课程编码">
|
||
<el-input v-model="selectorDialog.queryParams.cCode" placeholder="课程编码" clearable @keyup.enter.native="getCoursePool" />
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" icon="el-icon-search" size="mini" @click="getCoursePool">搜索</el-button>
|
||
<el-button icon="el-icon-refresh" size="mini" @click="resetCoursePool">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
|
||
<el-table
|
||
ref="courseTable"
|
||
v-loading="selectorDialog.loading"
|
||
:data="selectorDialog.list"
|
||
height="320"
|
||
@selection-change="handleCourseSelectionChange"
|
||
>
|
||
<el-table-column type="selection" width="55" align="center" :selectable="checkCourseSelectable" />
|
||
<el-table-column label="课程编码" prop="cCode" min-width="120" show-overflow-tooltip />
|
||
<el-table-column label="课程名称" prop="cName" min-width="180" show-overflow-tooltip />
|
||
<el-table-column label="课程类型" prop="cType" width="80" align="center" />
|
||
<el-table-column label="学时" prop="cDuration" width="70" align="center" />
|
||
<el-table-column label="状态" align="center" width="90">
|
||
<template slot-scope="scope">
|
||
<el-tag v-if="isAlreadyAdded(scope.row.cId)" type="info" size="mini">已配置</el-tag>
|
||
<el-tag v-else-if="scope.row.status === 0" type="danger" size="mini">已停用</el-tag>
|
||
<el-tag v-else type="success" size="mini">可选</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div style="margin-top: 15px;">
|
||
<el-form size="small" label-width="110px">
|
||
<el-form-item label="配置说明 / 备注">
|
||
<el-input v-model="selectorDialog.remark" placeholder="请输入本期课程配置备注(可选)" maxlength="500" show-word-limit />
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button
|
||
type="primary"
|
||
:disabled="selectedCourses.length === 0"
|
||
:loading="selectorDialog.submitting"
|
||
@click="submitCourseSelection"
|
||
>确定引入 ({{ selectedCourses.length }})</el-button>
|
||
<el-button @click="selectorDialog.open = false">取 消</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { addPlan, completePlan, getPlan, listPlan, updatePlan } from '@/api/train/plan'
|
||
import { listPlanCourses, configurePlanCourses, removePlanCourse } from '@/api/train/planCourse'
|
||
import { listCourse } from '@/api/train/course'
|
||
|
||
export default {
|
||
name: 'Plan',
|
||
data() {
|
||
return {
|
||
loading: true,
|
||
showSearch: true,
|
||
total: 0,
|
||
planList: [],
|
||
startTimeRange: [],
|
||
title: '',
|
||
open: false,
|
||
statusOptions: [
|
||
{ value: 0, label: '未开始' },
|
||
{ value: 1, label: '进行中' },
|
||
{ value: 2, label: '已结束' },
|
||
{ value: 3, label: '已取消' }
|
||
],
|
||
queryParams: {
|
||
pageNum: 1,
|
||
pageSize: 10,
|
||
planName: null,
|
||
planStatus: null
|
||
},
|
||
form: {},
|
||
rules: {
|
||
planName: [{ required: true, message: '培训班名称不能为空', trigger: 'blur' }],
|
||
startTime: [{ required: true, message: '开班时间不能为空', trigger: 'change' }],
|
||
endTime: [{ required: true, message: '结束时间不能为空', trigger: 'change' }],
|
||
reportDeadline: [{ required: true, message: '报到截止时间不能为空', trigger: 'change' }],
|
||
recruitNum: [{ required: true, message: '计划人数不能为空', trigger: 'change' }]
|
||
},
|
||
// 本期课程配置对话框
|
||
courseDialog: {
|
||
open: false,
|
||
loading: false,
|
||
title: '',
|
||
planId: null,
|
||
planName: '',
|
||
planStatus: null,
|
||
list: []
|
||
},
|
||
// 公共课程选择器
|
||
selectorDialog: {
|
||
open: false,
|
||
loading: false,
|
||
submitting: false,
|
||
remark: '',
|
||
queryParams: {
|
||
cName: null,
|
||
cCode: null,
|
||
status: 1
|
||
},
|
||
list: []
|
||
},
|
||
selectedCourses: []
|
||
}
|
||
},
|
||
created() {
|
||
this.getList()
|
||
},
|
||
methods: {
|
||
getList() {
|
||
this.loading = true
|
||
const query = { ...this.queryParams }
|
||
if (this.startTimeRange && this.startTimeRange.length === 2) {
|
||
query.startTimeBegin = this.startTimeRange[0]
|
||
query.startTimeEnd = this.startTimeRange[1]
|
||
}
|
||
listPlan(query).then(response => {
|
||
this.planList = response.rows
|
||
this.total = response.total
|
||
}).finally(() => {
|
||
this.loading = false
|
||
})
|
||
},
|
||
statusLabel(status) {
|
||
const option = this.statusOptions.find(item => item.value === status)
|
||
return option ? option.label : '未知'
|
||
},
|
||
statusTagType(status) {
|
||
return { 0: 'info', 1: 'primary', 2: 'success', 3: 'danger' }[status] || 'info'
|
||
},
|
||
isLocked(status) {
|
||
return status === 2 || status === 3
|
||
},
|
||
cancel() {
|
||
this.open = false
|
||
this.reset()
|
||
},
|
||
reset() {
|
||
this.form = {
|
||
planId: null,
|
||
planName: null,
|
||
startTime: null,
|
||
endTime: null,
|
||
reportDeadline: null,
|
||
trainAddress: null,
|
||
recruitNum: 1,
|
||
applyCondition: null,
|
||
remark: null
|
||
}
|
||
this.resetForm('form')
|
||
},
|
||
handleQuery() {
|
||
this.queryParams.pageNum = 1
|
||
this.getList()
|
||
},
|
||
resetQuery() {
|
||
this.startTimeRange = []
|
||
this.resetForm('queryForm')
|
||
this.handleQuery()
|
||
},
|
||
handleAdd() {
|
||
this.reset()
|
||
this.open = true
|
||
this.title = '创建培训计划'
|
||
},
|
||
handleUpdate(row) {
|
||
this.reset()
|
||
getPlan(row.planId).then(response => {
|
||
this.form = response.data
|
||
this.open = true
|
||
this.title = '编辑培训计划'
|
||
})
|
||
},
|
||
submitForm() {
|
||
this.$refs.form.validate(valid => {
|
||
if (!valid) return
|
||
if (this.form.startTime >= this.form.endTime) {
|
||
this.$modal.msgError('结束时间必须晚于开班时间')
|
||
return
|
||
}
|
||
if (this.form.reportDeadline > this.form.startTime) {
|
||
this.$modal.msgError('报到截止时间不得晚于开班时间')
|
||
return
|
||
}
|
||
const request = this.form.planId
|
||
? updatePlan(this.form.planId, this.planPayload())
|
||
: addPlan(this.planPayload())
|
||
request.then(() => {
|
||
this.$modal.msgSuccess(this.form.planId ? '修改成功' : '创建成功')
|
||
this.open = false
|
||
this.getList()
|
||
})
|
||
})
|
||
},
|
||
planPayload() {
|
||
return {
|
||
planName: this.form.planName,
|
||
startTime: this.form.startTime,
|
||
endTime: this.form.endTime,
|
||
reportDeadline: this.form.reportDeadline,
|
||
trainAddress: this.form.trainAddress,
|
||
recruitNum: this.form.recruitNum,
|
||
applyCondition: this.form.applyCondition,
|
||
remark: this.form.remark
|
||
}
|
||
},
|
||
handleComplete(row) {
|
||
this.$modal.confirm('结束计划后将锁定计划信息并保留全部历史记录,是否继续?').then(() => {
|
||
return completePlan(row.planId)
|
||
}).then(() => {
|
||
this.$modal.msgSuccess('计划已结束')
|
||
this.getList()
|
||
}).catch(() => {})
|
||
},
|
||
// ---- ISSUE-02-02 本期课程配置方法 ----
|
||
handleCourseConfig(row) {
|
||
this.courseDialog.planId = row.planId
|
||
this.courseDialog.planName = row.planName
|
||
this.courseDialog.planStatus = row.planStatus
|
||
this.courseDialog.title = `本期课程配置 - ${row.planName}`
|
||
this.courseDialog.open = true
|
||
this.loadPlanCourses(row.planId)
|
||
},
|
||
loadPlanCourses(planId) {
|
||
this.courseDialog.loading = true
|
||
listPlanCourses(planId).then(response => {
|
||
this.courseDialog.list = response.data || []
|
||
}).finally(() => {
|
||
this.courseDialog.loading = false
|
||
})
|
||
},
|
||
handleOpenCourseSelector() {
|
||
this.selectorDialog.remark = ''
|
||
this.selectedCourses = []
|
||
this.selectorDialog.queryParams.cName = null
|
||
this.selectorDialog.queryParams.cCode = null
|
||
this.selectorDialog.open = true
|
||
this.getCoursePool()
|
||
},
|
||
getCoursePool() {
|
||
this.selectorDialog.loading = true
|
||
listCourse(this.selectorDialog.queryParams).then(response => {
|
||
this.selectorDialog.list = response.rows || []
|
||
}).finally(() => {
|
||
this.selectorDialog.loading = false
|
||
})
|
||
},
|
||
resetCoursePool() {
|
||
this.selectorDialog.queryParams.cName = null
|
||
this.selectorDialog.queryParams.cCode = null
|
||
this.getCoursePool()
|
||
},
|
||
isAlreadyAdded(cId) {
|
||
return this.courseDialog.list.some(item => item.cId === cId)
|
||
},
|
||
checkCourseSelectable(row) {
|
||
return !this.isAlreadyAdded(row.cId) && row.status === 1
|
||
},
|
||
handleCourseSelectionChange(selection) {
|
||
this.selectedCourses = selection
|
||
},
|
||
submitCourseSelection() {
|
||
if (this.selectedCourses.length === 0) {
|
||
this.$modal.msgWarning('请选择至少一门课程')
|
||
return
|
||
}
|
||
this.selectorDialog.submitting = true
|
||
const cIds = this.selectedCourses.map(item => item.cId)
|
||
configurePlanCourses(this.courseDialog.planId, {
|
||
cIds: cIds,
|
||
remark: this.selectorDialog.remark
|
||
}).then(() => {
|
||
this.$modal.msgSuccess('成功引入课程')
|
||
this.selectorDialog.open = false
|
||
this.loadPlanCourses(this.courseDialog.planId)
|
||
this.getList()
|
||
}).finally(() => {
|
||
this.selectorDialog.submitting = false
|
||
})
|
||
},
|
||
handleRemoveCourse(row) {
|
||
this.$modal.confirm(`确定要从本期培训计划中移除课程【${row.cName}】吗?`).then(() => {
|
||
return removePlanCourse(this.courseDialog.planId, row.planCourseId)
|
||
}).then(() => {
|
||
this.$modal.msgSuccess('移除成功')
|
||
this.loadPlanCourses(this.courseDialog.planId)
|
||
this.getList()
|
||
}).catch(() => {})
|
||
}
|
||
}
|
||
}
|
||
</script>
|