|
@@ -0,0 +1,362 @@
|
|
|
+<template>
|
|
|
+ <section>
|
|
|
+ <!--工具条-->
|
|
|
+ <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
|
|
|
+ <el-form :inline="true" @submit.native.prevent>
|
|
|
+ <el-form-item label="讲师名称">
|
|
|
+ <el-input v-model="keyword" placeholder="请输入讲师名称" clearable @change="searchList"
|
|
|
+ size="small"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" @click="addLecturer" size="small">添加讲师</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <!--列表-->
|
|
|
+ <el-table :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;" @selection-change="handleSelectionChange">
|
|
|
+ <el-table-column type="selection" width="55" align="center"></el-table-column>
|
|
|
+ <el-table-column prop="name" label="讲师名称" min-width="180" align="center"></el-table-column>
|
|
|
+ <el-table-column prop="introduction" label="讲师介绍" min-width="300" align="center"></el-table-column>
|
|
|
+ <el-table-column label="讲师照片" width="120" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <img v-if="scope.row.photo" :src="scope.row.photo" class="lecturer-photo" />
|
|
|
+ <span v-else>无照片</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="180" class-name="btns" header-align="center" fixed="right">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-button size="small" type="primary" @click="editLecturer(scope.row)">编辑</el-button>
|
|
|
+ <el-button size="small" type="danger" @click="deleteLecturer(scope.row)">删除</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!--工具条-->
|
|
|
+ <el-col :span="24" class="toolbar">
|
|
|
+ <el-button type="danger" @click="batchDelete" :disabled="selectedIds.length===0" size="small">批量删除</el-button>
|
|
|
+ <el-pagination
|
|
|
+ @size-change="handleSizeChange"
|
|
|
+ @current-change="handleCurrentChange"
|
|
|
+ :page-sizes="[10, 20, 50, 100]"
|
|
|
+ :page-size="size"
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ :total="total"
|
|
|
+ style="float:right;"
|
|
|
+ ></el-pagination>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <!-- 添加/编辑讲师对话框 -->
|
|
|
+ <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="800px">
|
|
|
+ <el-form :model="lecturerForm" :rules="rules" ref="lecturerForm" label-width="100px">
|
|
|
+ <el-form-item label="讲师名称" prop="name">
|
|
|
+ <el-input v-model="lecturerForm.name" placeholder="请输入讲师名称"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="讲师介绍">
|
|
|
+ <el-input type="textarea" v-model="lecturerForm.introduction" placeholder="请输入讲师介绍"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="讲师照片">
|
|
|
+ <el-upload
|
|
|
+ class="lecturer-uploader"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :on-change="handlePhotoChange"
|
|
|
+ :auto-upload="false"
|
|
|
+ :before-upload="beforePhotoUpload">
|
|
|
+ <img v-if="photoUrl" :src="photoUrl" class="lecturer-image" />
|
|
|
+ <i v-else class="el-icon-plus lecturer-uploader-icon"></i>
|
|
|
+ </el-upload>
|
|
|
+ <div class="upload-tip">建议上传1:1比例的头像照片</div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <span slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="dialogVisible = false">取 消</el-button>
|
|
|
+ <el-button type="primary" @click="saveLecturer">确 定</el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
+ </section>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ // 搜索条件
|
|
|
+ keyword: null,
|
|
|
+
|
|
|
+ // 表格相关
|
|
|
+ tableHeight: 0,
|
|
|
+ listLoading: false,
|
|
|
+ total: 0,
|
|
|
+ page: 1,
|
|
|
+ size: 20,
|
|
|
+ list: [],
|
|
|
+ selectedIds: [],
|
|
|
+
|
|
|
+ // 对话框控制
|
|
|
+ dialogVisible: false,
|
|
|
+ dialogTitle: '添加讲师',
|
|
|
+ currentLecturerId: null,
|
|
|
+ photoUrl: '',
|
|
|
+ photoFile: null,
|
|
|
+
|
|
|
+ // 表单数据
|
|
|
+ lecturerForm: {
|
|
|
+ name: '',
|
|
|
+ introduction: '',
|
|
|
+ photo: ''
|
|
|
+ },
|
|
|
+
|
|
|
+ // 表单验证规则
|
|
|
+ rules: {
|
|
|
+ name: [
|
|
|
+ { required: true, message: '请输入讲师名称', trigger: 'blur' }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ checkAndAddUpload(str) {
|
|
|
+ if (str.includes('/upload/')) {
|
|
|
+ return str;
|
|
|
+ } else {
|
|
|
+ return '/upload/' + str;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 搜索讲师列表
|
|
|
+ searchList() {
|
|
|
+ this.page = 1;
|
|
|
+ this.getList();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取讲师列表
|
|
|
+ getList() {
|
|
|
+ this.listLoading = true;
|
|
|
+ // 这里应该是调用API获取讲师列表
|
|
|
+ // 模拟数据
|
|
|
+ setTimeout(() => {
|
|
|
+ this.list = [
|
|
|
+ { id: 1, name: '张老师', introduction: '资深前端开发工程师', photo: '' },
|
|
|
+ { id: 2, name: '李老师', introduction: '后端架构师', photo: '' },
|
|
|
+ { id: 3, name: '王老师', introduction: '全栈开发工程师', photo: '' }
|
|
|
+ ];
|
|
|
+ this.total = 3;
|
|
|
+ this.listLoading = false;
|
|
|
+ }, 500);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 分页相关
|
|
|
+ handleCurrentChange(val) {
|
|
|
+ this.page = val;
|
|
|
+ this.getList();
|
|
|
+ },
|
|
|
+ handleSizeChange(val) {
|
|
|
+ this.page = 1;
|
|
|
+ this.size = val;
|
|
|
+ this.getList();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 选择变化
|
|
|
+ handleSelectionChange(val) {
|
|
|
+ this.selectedIds = val.map(item => item.id);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 添加讲师
|
|
|
+ addLecturer() {
|
|
|
+ this.dialogTitle = '添加讲师';
|
|
|
+ this.currentLecturerId = null;
|
|
|
+ this.lecturerForm = {
|
|
|
+ name: '',
|
|
|
+ introduction: '',
|
|
|
+ photo: ''
|
|
|
+ };
|
|
|
+ this.photoUrl = '';
|
|
|
+ this.dialogVisible = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 编辑讲师
|
|
|
+ editLecturer(row) {
|
|
|
+ this.dialogTitle = '编辑讲师';
|
|
|
+ this.currentLecturerId = row.id;
|
|
|
+ this.lecturerForm = {
|
|
|
+ name: row.name,
|
|
|
+ introduction: row.introduction,
|
|
|
+ photo: row.photo
|
|
|
+ };
|
|
|
+ this.photoUrl = row.photo || '';
|
|
|
+ this.dialogVisible = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 删除讲师
|
|
|
+ deleteLecturer(row) {
|
|
|
+ this.$confirm('确认删除该讲师?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ // 这里应该是调用API删除讲师
|
|
|
+ this.$message({
|
|
|
+ type: 'success',
|
|
|
+ message: '删除成功!'
|
|
|
+ });
|
|
|
+ this.getList();
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 批量删除
|
|
|
+ batchDelete() {
|
|
|
+ if (this.selectedIds.length === 0) {
|
|
|
+ this.$message.warning('请选择要删除的讲师');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.$confirm(`确认删除选中的${this.selectedIds.length}位讲师?`, '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ // 这里应该是调用API批量删除讲师
|
|
|
+ this.$message({
|
|
|
+ type: 'success',
|
|
|
+ message: '批量删除成功!'
|
|
|
+ });
|
|
|
+ this.getList();
|
|
|
+ this.selectedIds = [];
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 保存讲师
|
|
|
+ saveLecturer() {
|
|
|
+ this.$refs.lecturerForm.validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ // 这里应该是调用API保存讲师信息
|
|
|
+ if (this.photoFile) {
|
|
|
+ // 如果有上传照片,先上传照片
|
|
|
+ // 模拟上传照片
|
|
|
+ setTimeout(() => {
|
|
|
+ this.lecturerForm.photo = this.photoUrl;
|
|
|
+ this.saveLecturerInfo();
|
|
|
+ }, 500);
|
|
|
+ } else {
|
|
|
+ this.saveLecturerInfo();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 保存讲师信息
|
|
|
+ saveLecturerInfo() {
|
|
|
+ // 模拟保存
|
|
|
+ setTimeout(() => {
|
|
|
+ this.$message({
|
|
|
+ type: 'success',
|
|
|
+ message: '保存成功!'
|
|
|
+ });
|
|
|
+ this.dialogVisible = false;
|
|
|
+ this.getList();
|
|
|
+ }, 500);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 处理照片变更
|
|
|
+ handlePhotoChange(file) {
|
|
|
+ const row = file.raw
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append('multipartFile', row);
|
|
|
+ this.http.uploadFile('/common/uploadFile', formData, res => {
|
|
|
+ if (res.code == "ok") {
|
|
|
+ this.photoUrl = this.checkAndAddUpload(res.data)
|
|
|
+ } else {
|
|
|
+ this.$message({
|
|
|
+ message: res.msg || '图片上传失败',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 处理照片上传前的验证
|
|
|
+ beforePhotoUpload(file) {
|
|
|
+ const isImage = file.type.indexOf('image/') === 0;
|
|
|
+ const isLt2M = file.size / 1024 / 1024 < 5;
|
|
|
+
|
|
|
+ if (!isImage) {
|
|
|
+ this.$message.error('上传文件只能是图片格式!');
|
|
|
+ }
|
|
|
+ if (!isLt2M) {
|
|
|
+ this.$message.error('上传图片大小不能超过 2MB!');
|
|
|
+ }
|
|
|
+
|
|
|
+ return isImage && isLt2M;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ created() {
|
|
|
+ let height = window.innerHeight;
|
|
|
+ this.tableHeight = height - 195;
|
|
|
+ const that = this;
|
|
|
+ window.onresize = function temp() {
|
|
|
+ that.tableHeight = window.innerHeight - 195;
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ mounted() {
|
|
|
+ this.getList();
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.toolbar {
|
|
|
+ padding-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.btns .el-button {
|
|
|
+ margin-left: 10px;
|
|
|
+ margin-bottom: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.lecturer-photo {
|
|
|
+ width: 80px;
|
|
|
+ height: 80px;
|
|
|
+ object-fit: cover;
|
|
|
+ border-radius: 50%;
|
|
|
+}
|
|
|
+
|
|
|
+.lecturer-uploader {
|
|
|
+ border: 1px dashed #d9d9d9;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+ width: 100px;
|
|
|
+ height: 100px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.lecturer-uploader:hover {
|
|
|
+ border-color: #409EFF;
|
|
|
+}
|
|
|
+
|
|
|
+.lecturer-uploader-icon {
|
|
|
+ font-size: 28px;
|
|
|
+ color: #8c939d;
|
|
|
+ width: 100px;
|
|
|
+ height: 100px;
|
|
|
+ line-height: 100px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.lecturer-image {
|
|
|
+ width: 100px;
|
|
|
+ height: 100px;
|
|
|
+ display: block;
|
|
|
+ object-fit: cover;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-tip {
|
|
|
+ color: #909399;
|
|
|
+ font-size: 12px;
|
|
|
+ margin-top: 5px;
|
|
|
+}
|
|
|
+</style>
|