Files
railwaysystem/build_ui/src/views/train/plan/index.vue
T

510 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>