<template>
|
<div class="training-management">
|
<!-- 页面头部 -->
|
<div class="page-header">
|
<h2>进修管理</h2>
|
<div class="header-actions">
|
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">
|
新增进修记录
|
</el-button>
|
<el-button icon="el-icon-download" @click="exportData">
|
导出数据
|
</el-button>
|
</div>
|
</div>
|
|
<!-- 搜索筛选区域 -->
|
<el-card class="filter-card">
|
<el-form :model="queryParams" inline>
|
<el-form-item label="姓名">
|
<el-input
|
v-model="queryParams.name"
|
placeholder="请输入姓名"
|
clearable
|
style="width: 120px"
|
/>
|
</el-form-item>
|
<el-form-item label="进修类型">
|
<el-select v-model="queryParams.trainingType" clearable placeholder="请选择">
|
<el-option label="专业技术进修" value="professional" />
|
<el-option label="管理能力进修" value="management" />
|
<el-option label="学历提升进修" value="education" />
|
<el-option label="技能培训" value="skill" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="技术职称">
|
<el-input
|
v-model="queryParams.technicalTitle"
|
placeholder="请输入技术职称"
|
clearable
|
style="width: 140px"
|
/>
|
</el-form-item>
|
<el-form-item label="进修时间">
|
<el-date-picker
|
v-model="queryParams.dateRange"
|
type="daterange"
|
range-separator="至"
|
start-placeholder="开始日期"
|
end-placeholder="结束日期"
|
value-format="yyyy-MM-dd"
|
/>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" @click="handleQuery">查询</el-button>
|
<el-button @click="handleReset">重置</el-button>
|
</el-form-item>
|
</el-form>
|
</el-card>
|
|
<!-- 数据表格 -->
|
<el-card>
|
<el-table
|
:data="tableData"
|
v-loading="loading"
|
border
|
style="width: 100%"
|
@sort-change="handleSortChange"
|
>
|
<el-table-column prop="id" label="ID" width="80" fixed />
|
<el-table-column prop="name" label="姓名" width="100" fixed>
|
<template #default="scope">
|
<el-button type="text" @click="handleView(scope.row)">
|
{{ scope.row.name }}
|
</el-button>
|
</template>
|
</el-table-column>
|
<el-table-column prop="gender" label="性别" width="80">
|
<template #default="scope">
|
<el-tag :type="scope.row.gender === '男' ? 'primary' : 'danger'" size="small">
|
{{ scope.row.gender }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column prop="age" label="年龄" width="80" sortable />
|
<el-table-column prop="education" label="学历" width="100" />
|
<el-table-column prop="trainingType" label="进修类型" width="120">
|
<template #default="scope">
|
<el-tag :type="getTrainingTypeTag(scope.row.trainingType)">
|
{{ getTrainingTypeText(scope.row.trainingType) }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column prop="idCard" label="身份证号" width="180" show-overflow-tooltip />
|
<el-table-column prop="graduateSchool" label="毕业院校" width="150" show-overflow-tooltip />
|
<el-table-column prop="workUnit" label="所在单位" width="150" show-overflow-tooltip />
|
<el-table-column prop="technicalTitle" label="技术职称" width="120" />
|
<el-table-column prop="professionalField" label="从事专业" width="120" />
|
<el-table-column prop="workYears" label="工作年限" width="100" sortable />
|
<el-table-column prop="trainingStartDate" label="进修开始时间" width="120" />
|
<el-table-column prop="trainingEndDate" label="进修结束时间" width="120" />
|
<el-table-column prop="trainingMajor" label="进修专业" width="120" />
|
<el-table-column prop="status" label="状态" width="100" fixed="right">
|
<template #default="scope">
|
<el-tag :type="getStatusTag(scope.row.status)">
|
{{ scope.row.status }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" width="180" fixed="right">
|
<template #default="scope">
|
<el-button size="mini" type="text" @click="handleView(scope.row)">
|
查看
|
</el-button>
|
<el-button size="mini" type="text" @click="handleEdit(scope.row)">
|
编辑
|
</el-button>
|
<el-button
|
size="mini"
|
type="text"
|
@click="handleCopy(scope.row)"
|
style="color: #67C23A;"
|
>
|
复制
|
</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<!-- 分页 -->
|
<div class="pagination-container">
|
<el-pagination
|
:current-page="pagination.currentPage"
|
:page-size="pagination.pageSize"
|
:total="pagination.total"
|
layout="total, sizes, prev, pager, next, jumper"
|
@size-change="handleSizeChange"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
</el-card>
|
|
<!-- 查看详情对话框 -->
|
<el-dialog
|
:title="`进修详情 - ${currentRecord.name || ''}`"
|
:visible.sync="detailDialogVisible"
|
width="900px"
|
:before-close="handleDetailClose"
|
>
|
<el-descriptions :column="2" border v-if="currentRecord">
|
<el-descriptions-item label="姓名">{{ currentRecord.name }}</el-descriptions-item>
|
<el-descriptions-item label="性别">{{ currentRecord.gender }}</el-descriptions-item>
|
<el-descriptions-item label="年龄">{{ currentRecord.age }}</el-descriptions-item>
|
<el-descriptions-item label="学历">{{ currentRecord.education }}</el-descriptions-item>
|
<el-descriptions-item label="进修类型">
|
<el-tag :type="getTrainingTypeTag(currentRecord.trainingType)">
|
{{ getTrainingTypeText(currentRecord.trainingType) }}
|
</el-tag>
|
</el-descriptions-item>
|
<el-descriptions-item label="身份证号">{{ currentRecord.idCard }}</el-descriptions-item>
|
<el-descriptions-item label="毕业院校">{{ currentRecord.graduateSchool }}</el-descriptions-item>
|
<el-descriptions-item label="所在单位">{{ currentRecord.workUnit }}</el-descriptions-item>
|
<el-descriptions-item label="技术职称">{{ currentRecord.technicalTitle }}</el-descriptions-item>
|
<el-descriptions-item label="从事专业">{{ currentRecord.professionalField }}</el-descriptions-item>
|
<el-descriptions-item label="工作年限">{{ currentRecord.workYears }}年</el-descriptions-item>
|
<el-descriptions-item label="进修目标">{{ currentRecord.trainingObjective }}</el-descriptions-item>
|
<el-descriptions-item label="进修开始时间">{{ currentRecord.trainingStartDate }}</el-descriptions-item>
|
<el-descriptions-item label="进修结束时间">{{ currentRecord.trainingEndDate }}</el-descriptions-item>
|
<el-descriptions-item label="进修专业">{{ currentRecord.trainingMajor }}</el-descriptions-item>
|
<el-descriptions-item label="从事工作情况" :span="2">
|
{{ currentRecord.workSituation }}
|
</el-descriptions-item>
|
<el-descriptions-item label="进修科目及目的" :span="2">
|
{{ currentRecord.trainingSubject }}
|
</el-descriptions-item>
|
<el-descriptions-item label="主要学历" :span="2">
|
<div style="white-space: pre-line;">{{ currentRecord.mainEducation }}</div>
|
</el-descriptions-item>
|
<el-descriptions-item label="主要工作经历" :span="2">
|
<div style="white-space: pre-line;">{{ currentRecord.workExperience }}</div>
|
</el-descriptions-item>
|
</el-descriptions>
|
<span slot="footer">
|
<el-button @click="detailDialogVisible = false">关闭</el-button>
|
<el-button type="primary" @click="handleEdit(currentRecord)">编辑</el-button>
|
</span>
|
</el-dialog>
|
|
<!-- 新增/编辑对话框 -->
|
<el-dialog
|
:title="`${isEditing ? '编辑' : '新增'}进修记录`"
|
:visible.sync="editDialogVisible"
|
width="80vw"
|
:before-close="handleEditClose"
|
>
|
<el-form
|
ref="editForm"
|
:model="editForm"
|
:rules="editRules"
|
label-width="120px"
|
label-position="left"
|
>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="姓名" prop="name">
|
<el-input v-model="editForm.name" placeholder="请输入姓名" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="性别" prop="gender">
|
<el-radio-group v-model="editForm.gender">
|
<el-radio label="男">男</el-radio>
|
<el-radio label="女">女</el-radio>
|
</el-radio-group>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="年龄" prop="age">
|
<el-input-number
|
v-model="editForm.age"
|
:min="18"
|
:max="65"
|
controls-position="right"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="学历" prop="education">
|
<el-select v-model="editForm.education" placeholder="请选择学历" style="width: 100%">
|
<el-option label="博士" value="博士" />
|
<el-option label="硕士" value="硕士" />
|
<el-option label="本科" value="本科" />
|
<el-option label="大专" value="大专" />
|
<el-option label="中专" value="中专" />
|
<el-option label="高中" value="高中" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-form-item label="进修类型" prop="trainingType">
|
<el-select v-model="editForm.trainingType" placeholder="请选择进修类型" style="width: 100%">
|
<el-option label="专业技术进修" value="professional" />
|
<el-option label="管理能力进修" value="management" />
|
<el-option label="学历提升进修" value="education" />
|
<el-option label="技能培训" value="skill" />
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="身份证号" prop="idCard">
|
<el-input v-model="editForm.idCard" placeholder="请输入身份证号" />
|
</el-form-item>
|
|
<el-form-item label="毕业院校" prop="graduateSchool">
|
<el-input v-model="editForm.graduateSchool" placeholder="请输入毕业院校" />
|
</el-form-item>
|
|
<el-form-item label="所在单位" prop="workUnit">
|
<el-input v-model="editForm.workUnit" placeholder="请输入所在单位" />
|
</el-form-item>
|
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="技术职称" prop="technicalTitle">
|
<el-input v-model="editForm.technicalTitle" placeholder="请输入技术职称" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="从事专业" prop="professionalField">
|
<el-input v-model="editForm.professionalField" placeholder="请输入从事专业" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-form-item label="工作年限" prop="workYears">
|
<el-input-number
|
v-model="editForm.workYears"
|
:min="0"
|
:max="50"
|
controls-position="right"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
|
<el-form-item label="进修目标" prop="trainingObjective">
|
<el-input
|
v-model="editForm.trainingObjective"
|
type="textarea"
|
:rows="2"
|
placeholder="请输入进修目标"
|
/>
|
</el-form-item>
|
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="进修开始时间" prop="trainingStartDate">
|
<el-date-picker
|
v-model="editForm.trainingStartDate"
|
type="date"
|
placeholder="选择开始日期"
|
value-format="yyyy-MM-dd"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="进修结束时间" prop="trainingEndDate">
|
<el-date-picker
|
v-model="editForm.trainingEndDate"
|
type="date"
|
placeholder="选择结束日期"
|
value-format="yyyy-MM-dd"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-form-item label="进修专业" prop="trainingMajor">
|
<el-input v-model="editForm.trainingMajor" placeholder="请输入进修专业" />
|
</el-form-item>
|
|
<el-form-item label="从事工作情况" prop="workSituation">
|
<el-input
|
v-model="editForm.workSituation"
|
type="textarea"
|
:rows="3"
|
placeholder="请输入从事工作情况"
|
/>
|
</el-form-item>
|
|
<el-form-item label="进修科目及目的" prop="trainingSubject">
|
<el-input
|
v-model="editForm.trainingSubject"
|
type="textarea"
|
:rows="3"
|
placeholder="请输入本次申请进修何种科目及目的要求"
|
/>
|
</el-form-item>
|
|
<el-form-item label="主要学历" prop="mainEducation">
|
<el-input
|
v-model="editForm.mainEducation"
|
type="textarea"
|
:rows="3"
|
placeholder="请输入主要学历(每行一条)"
|
/>
|
</el-form-item>
|
|
<el-form-item label="主要工作经历" prop="workExperience">
|
<el-input
|
v-model="editForm.workExperience"
|
type="textarea"
|
:rows="3"
|
placeholder="请输入主要工作经历(每行一条)"
|
/>
|
</el-form-item>
|
</el-form>
|
|
<span slot="footer">
|
<el-button @click="handleEditClose">取消</el-button>
|
<el-button type="primary" @click="handleSave" :loading="saveLoading">
|
{{ isEditing ? '保存' : '新增' }}
|
</el-button>
|
</span>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script>
|
export default {
|
name: 'TrainingManagement',
|
data() {
|
return {
|
// 查询参数
|
queryParams: {
|
name: '',
|
trainingType: '',
|
technicalTitle: '',
|
dateRange: []
|
},
|
// 分页参数
|
pagination: {
|
currentPage: 1,
|
pageSize: 10,
|
total: 0
|
},
|
// 加载状态
|
loading: false,
|
saveLoading: false,
|
// 对话框显示状态
|
detailDialogVisible: false,
|
editDialogVisible: false,
|
// 当前操作记录
|
currentRecord: {},
|
// 编辑状态
|
isEditing: false,
|
// 表格数据
|
tableData: [],
|
// 编辑表单数据
|
editForm: {
|
name: '',
|
gender: '男',
|
age: 25,
|
education: '',
|
trainingType: '',
|
idCard: '',
|
graduateSchool: '',
|
workUnit: '',
|
technicalTitle: '',
|
professionalField: '',
|
workYears: 0,
|
trainingObjective: '',
|
trainingStartDate: '',
|
trainingEndDate: '',
|
trainingMajor: '',
|
workSituation: '',
|
trainingSubject: '',
|
mainEducation: '',
|
workExperience: ''
|
},
|
// 表单验证规则
|
editRules: {
|
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
|
gender: [{ required: true, message: '请选择性别', trigger: 'change' }],
|
age: [{ required: true, message: '请输入年龄', trigger: 'blur' }],
|
education: [{ required: true, message: '请选择学历', trigger: 'change' }],
|
trainingType: [{ required: true, message: '请选择进修类型', trigger: 'change' }],
|
idCard: [{ required: true, message: '请输入身份证号', trigger: 'blur' }]
|
}
|
}
|
},
|
mounted() {
|
this.loadData()
|
},
|
methods: {
|
// 加载数据
|
async loadData() {
|
this.loading = true
|
try {
|
// 模拟API调用
|
await new Promise(resolve => setTimeout(resolve, 500))
|
|
// 生成模拟数据
|
this.tableData = this.generateMockData()
|
this.pagination.total = this.tableData.length
|
} catch (error) {
|
console.error('加载数据失败:', error)
|
this.$message.error('数据加载失败')
|
} finally {
|
this.loading = false
|
}
|
},
|
// 生成模拟数据
|
generateMockData() {
|
const names = ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十']
|
const trainingTypes = ['professional', 'management', 'education', 'skill']
|
const statuses = ['进行中', '已完成', '待审核', '已取消']
|
|
return Array.from({ length: 10 }, (_, index) => ({
|
id: index + 1,
|
name: names[Math.floor(Math.random() * names.length)],
|
gender: Math.random() > 0.5 ? '男' : '女',
|
age: 25 + Math.floor(Math.random() * 20),
|
education: ['博士', '硕士', '本科', '大专'][Math.floor(Math.random() * 4)],
|
trainingType: trainingTypes[Math.floor(Math.random() * trainingTypes.length)],
|
idCard: '11010119900101' + (1000 + index).toString().slice(-4),
|
graduateSchool: ['北京大学', '清华大学', '复旦大学', '上海交通大学'][Math.floor(Math.random() * 4)],
|
workUnit: ['北京协和医院', '上海瑞金医院', '广州中山医院', '武汉同济医院'][Math.floor(Math.random() * 4)],
|
technicalTitle: ['主任医师', '副主任医师', '主治医师', '住院医师'][Math.floor(Math.random() * 4)],
|
professionalField: ['心血管内科', '神经外科', '儿科', '妇产科'][Math.floor(Math.random() * 4)],
|
workYears: 5 + Math.floor(Math.random() * 20),
|
trainingObjective: '提升专业技术和临床能力',
|
trainingStartDate: '2024-' + (Math.floor(Math.random() * 12) + 1).toString().padStart(2, '0') + '-01',
|
trainingEndDate: '2024-' + (Math.floor(Math.random() * 12) + 1).toString().padStart(2, '0') + '-28',
|
trainingMajor: '临床医学',
|
workSituation: '在临床一线工作,负责患者诊疗',
|
trainingSubject: '高级心血管介入治疗技术',
|
mainEducation: '2005-2009 北京大学医学部 临床医学本科\n2009-2012 北京大学医学部 硕士',
|
workExperience: '2012-2015 北京协和医院 住院医师\n2015-2020 北京协和医院 主治医师',
|
status: statuses[Math.floor(Math.random() * statuses.length)]
|
}))
|
},
|
// 获取进修类型标签样式
|
getTrainingTypeTag(type) {
|
const typeMap = {
|
professional: 'primary',
|
management: 'success',
|
education: 'warning',
|
skill: 'info'
|
}
|
return typeMap[type] || 'info'
|
},
|
// 获取进修类型文本
|
getTrainingTypeText(type) {
|
const textMap = {
|
professional: '专业技术进修',
|
management: '管理能力进修',
|
education: '学历提升进修',
|
skill: '技能培训'
|
}
|
return textMap[type] || type
|
},
|
// 获取状态标签样式
|
getStatusTag(status) {
|
const statusMap = {
|
'进行中': 'primary',
|
'已完成': 'success',
|
'待审核': 'warning',
|
'已取消': 'danger'
|
}
|
return statusMap[status] || 'info'
|
},
|
// 查询处理
|
handleQuery() {
|
this.pagination.currentPage = 1
|
this.loadData()
|
},
|
// 重置查询
|
handleReset() {
|
this.queryParams = {
|
name: '',
|
trainingType: '',
|
technicalTitle: '',
|
dateRange: []
|
}
|
this.pagination.currentPage = 1
|
this.loadData()
|
},
|
// 查看详情
|
handleView(record) {
|
this.currentRecord = { ...record }
|
this.detailDialogVisible = true
|
},
|
// 新增记录
|
handleAdd() {
|
this.isEditing = false
|
this.editForm = this.getDefaultFormData()
|
this.editDialogVisible = true
|
this.$nextTick(() => {
|
this.$refs.editForm && this.$refs.editForm.clearValidate()
|
})
|
},
|
// 编辑记录
|
handleEdit(record) {
|
this.isEditing = true
|
this.currentRecord = record
|
this.editForm = { ...record }
|
this.editDialogVisible = true
|
this.detailDialogVisible = false
|
this.$nextTick(() => {
|
this.$refs.editForm && this.$refs.editForm.clearValidate()
|
})
|
},
|
// 复制记录
|
handleCopy(record) {
|
this.isEditing = false
|
const copiedRecord = { ...record }
|
delete copiedRecord.id
|
copiedRecord.name = copiedRecord.name + '(复制)'
|
this.editForm = copiedRecord
|
this.editDialogVisible = true
|
this.$nextTick(() => {
|
this.$refs.editForm && this.$refs.editForm.clearValidate()
|
})
|
},
|
// 保存记录
|
async handleSave() {
|
try {
|
const valid = await this.$refs.editForm.validate()
|
if (!valid) return
|
|
this.saveLoading = true
|
// 模拟API调用
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
this.$message.success(this.isEditing ? '保存成功' : '新增成功')
|
this.editDialogVisible = false
|
this.loadData()
|
} catch (error) {
|
console.error('保存失败:', error)
|
this.$message.error('操作失败')
|
} finally {
|
this.saveLoading = false
|
}
|
},
|
// 关闭详情对话框
|
handleDetailClose() {
|
this.detailDialogVisible = false
|
this.currentRecord = {}
|
},
|
// 关闭编辑对话框
|
handleEditClose() {
|
this.editDialogVisible = false
|
this.currentRecord = {}
|
this.$nextTick(() => {
|
this.$refs.editForm && this.$refs.editForm.clearValidate()
|
})
|
},
|
// 导出数据
|
exportData() {
|
this.$message.success('导出功能开发中')
|
},
|
// 分页大小变化
|
handleSizeChange(size) {
|
this.pagination.pageSize = size
|
this.pagination.currentPage = 1
|
this.loadData()
|
},
|
// 当前页变化
|
handleCurrentChange(page) {
|
this.pagination.currentPage = page
|
this.loadData()
|
},
|
// 排序变化
|
handleSortChange(sort) {
|
console.log('排序变化:', sort)
|
// 这里可以添加排序逻辑
|
},
|
// 获取默认表单数据
|
getDefaultFormData() {
|
return {
|
name: '',
|
gender: '男',
|
age: 25,
|
education: '',
|
trainingType: '',
|
idCard: '',
|
graduateSchool: '',
|
workUnit: '',
|
technicalTitle: '',
|
professionalField: '',
|
workYears: 0,
|
trainingObjective: '',
|
trainingStartDate: '',
|
trainingEndDate: '',
|
trainingMajor: '',
|
workSituation: '',
|
trainingSubject: '',
|
mainEducation: '',
|
workExperience: ''
|
}
|
}
|
}
|
}
|
</script>
|
|
<style scoped>
|
.training-management {
|
padding: 20px;
|
}
|
|
.page-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 20px;
|
}
|
|
.page-header h2 {
|
margin: 0;
|
color: #303133;
|
}
|
|
.filter-card {
|
margin-bottom: 20px;
|
}
|
|
.pagination-container {
|
margin-top: 20px;
|
display: flex;
|
justify-content: flex-end;
|
}
|
|
/* 响应式设计 */
|
@media (max-width: 768px) {
|
.page-header {
|
flex-direction: column;
|
align-items: flex-start;
|
gap: 10px;
|
}
|
|
.header-actions {
|
width: 100%;
|
justify-content: space-between;
|
}
|
}
|
</style>
|