lion 2 months ago
parent 2a74c56add
commit 2a84e9b92f

@ -15,7 +15,7 @@
<div class="xy-table-item-label" style="font-weight: bold">
<span style="color: red; font-weight: bold; padding-right: 4px"
>*</span
>是否发布
>是否对外展示
</div>
<div class="xy-table-item-content">
<el-select
@ -97,12 +97,25 @@
>具体说明
</div>
<div class="xy-table-item-content">
<el-input
<el-select
v-model="form.introduce"
placeholder="请填写第*模块"
filterable
allow-create
default-first-option
placeholder="请选择或新建模块"
clearable
style="width: 100%"
></el-input>
@change="onModuleChange"
@create="onCreateModule"
>
<el-option
v-for="item in module_options"
:key="item.id"
:label="item.value"
:value="item.value"
>
</el-option>
</el-select>
</div>
</div>
</template>
@ -331,6 +344,18 @@ export default {
course_content_options: [],
course_options: [],
canSelect: false,
module_options: [
{ id: 1, value: '第一模块' },
{ id: 2, value: '第二模块' },
{ id: 3, value: '第三模块' },
{ id: 4, value: '第四模块' },
{ id: 5, value: '第五模块' },
{ id: 6, value: '第六模块' },
{ id: 7, value: '第七模块' },
{ id: 8, value: '第八模块' },
{ id: 9, value: '第九模块' },
{ id: 10, value: '第十模块' }
],
form: {
is_publish:1,
type: "",
@ -483,6 +508,40 @@ export default {
});
}
},
onModuleChange(value) {
//
if (value && this.form.title) {
//
let cleanTitle = this.form.title;
this.module_options.forEach(module => {
if (cleanTitle.includes(' | ' + module.value)) {
cleanTitle = cleanTitle.replace(' | ' + module.value, '');
}
});
//
this.form.title = cleanTitle + ' | ' + value;
}
},
onCreateModule(value) {
//
const newModule = {
id: this.module_options.length + 1,
value: value
};
this.module_options.push(newModule);
this.form.introduce = value;
//
if (this.form.title) {
let cleanTitle = this.form.title;
this.module_options.forEach(module => {
if (cleanTitle.includes(' | ' + module.value)) {
cleanTitle = cleanTitle.replace(' | ' + module.value, '');
}
});
//
this.form.title = cleanTitle + ' | ' + value;
}
},
submit() {
if (this.id) {
this.form.id = this.id;

@ -6,11 +6,17 @@
<lx-header icon="md-apps" :text="$route.meta.title" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<div slot="content">
<div class="searchwrap" style="display: flex;align-items: center;">
<div>
<el-select filterable v-model="select.teacher_id" placeholder="请选择授课老师" clearable style="width: 100%;">
<el-option v-for="(item,index) in teachers" :key="index" :label="item.name" :value="item.id">
</el-option>
</el-select>
<div>
<el-select filterable v-model="select.teacher_id" placeholder="请选择授课老师" clearable style="width: 100%;">
<el-option v-for="(item,index) in teachers" :key="index" :label="item.name" :value="item.id">
</el-option>
</el-select>
</div>
<div>
<el-select filterable v-model="select.direction" placeholder="请选择课程方向" clearable style="width: 100%;">
<el-option v-for="(item,index) in direction_options" :key="index" :label="item.value" :value="item.id">
</el-option>
</el-select>
</div>
<div>
<el-button type="primary" size="small" @click="select.page=1,getList()"></el-button>
@ -28,10 +34,10 @@
</div>
<div>
<xy-table :list="list" :total="total" @pageIndexChange="pageIndexChange" @pageSizeChange="pageSizeChange"
<xy-table :showIndex="false" :list="list" :total="total" @pageIndexChange="pageIndexChange" @pageSizeChange="pageSizeChange"
:table-item="table_item">
<template v-slot:files>
<el-table-column align='left' label="课件" width="240" header-align="center">
<el-table-column align='left' fixed="left" label="课件" width="240" header-align="center">
<template slot-scope="scope">
<div v-for="(item,index) in scope.row.files">
<div>
@ -59,27 +65,36 @@
</div>
</template>
<script>
import {
index as teacherGet
<script>
import {
index as teacherGet
} from "@/api/info/teachers.js"
import {
index
} from '@/api/course/courseContent.js'
import {
getparameteritem
} from "@/api/system/dictionary.js"
export default {
components: {
},
data() {
return {
return {
teachers:[],
direction_options: [], //
select: {
teacher_id: '',
direction: '', //
page: 1,
page_size: 10
},
list: [],
total: 0,
table_item: [{
table_item: [{type:'index',
align: 'center',
width: 80,
fixed: 'left'
},{
prop: 'files',
label: '课件',
align: 'left',
@ -89,11 +104,6 @@
label: '课程名称',
align: 'left',
width: 240,
}, {
prop: 'theme',
label: '授课主题',
align: 'center',
width: 120,
}, {
prop: 'date',
label: '日期',
@ -101,7 +111,7 @@
width: 120,
}, {
prop: 'period',
label: '时间 ',
label: '上课时间 ',
align: 'center',
width: 180,
}, {
@ -110,13 +120,18 @@
align: 'center',
width: 120,
}, {
prop: 'teacher.sex',
label: '性别',
align: 'center',
width: 80
prop: 'teacher.introduce',
label: '老师简介',
align: 'left',
width: 240,
}, {
prop: 'teacher.mobile',
label: '联系方式',
prop: 'theme',
label: '课程主题',
align: 'center',
width: 120,
},{
prop: 'direction_detail.value',
label: '课程方向',
align: 'center',
width: 120,
}, {
@ -124,26 +139,26 @@
label: '上课地点',
align: 'left',
width: 240,
}, {
prop: 'teacher.introduce',
label: '老师简介',
align: 'left',
width: 240,
}],
}
},
created() {
created() {
this.getTeachers()
this.getDirectionOptions()
this.getList()
},
methods: {
async getTeachers(){
const res = await teacherGet({
page:1,
page_size:999
})
this.teachers = res.data
methods: {
async getTeachers(){
const res = await teacherGet({
page:1,
page_size:999
})
this.teachers = res.data
},
async getDirectionOptions() {
const res = await getparameteritem('course_direction')
this.direction_options = res.detail
},
pageIndexChange(e) {
this.select.page = e
@ -156,6 +171,7 @@
},
resetSelect() {
this.select.teacher_id = ''
this.select.direction = ''
this.select.course = ''
this.select.page = 1
this.getList()
@ -164,15 +180,19 @@
const res = await index({
page_size: this.select.page_size,
page: this.select.page,
show_relation: ['course','teacher'],
show_relation: ['course','teacher','directionDetail'],
filter: [{
key: 'file_ids',
op: 'notnull',
value: '1'
},{
key: 'teacher_id',
op: 'eq',
value: this.select.teacher_id?this.select.teacher_id:''
},{
key: 'teacher_id',
op: 'eq',
value: this.select.teacher_id?this.select.teacher_id:''
},{
key: 'direction',
op: 'eq',
value: this.select.direction?this.select.direction:''
}]
})
this.list = res.data
@ -209,4 +229,4 @@
}
}
}
</style>
</style>

@ -1,14 +1,25 @@
<template>
<div>
<xy-dialog ref="dialog" :width="40" :is-show.sync="isShow" :type="'form'"
:title="type === 'add' ? '新增教师信息' : '编辑教师信息'" :form="form" :rules='rules' @submit="submit">
:title="type === 'add' ? '新增授课老师信息' : '编辑授课老师信息'" :form="form" :rules='rules' @submit="submit">
<template v-slot:name>
<div class="xy-table-item">
<div class="xy-table-item-label" style="font-weight: bold">
<span style="color: red;font-weight: bold;padding-right: 4px;">*</span>姓名
<span style="color: red;font-weight: bold;padding-right: 4px;">*</span>授课老师
</div>
<div class="xy-table-item-content">
<el-input v-model="form.name" placeholder="请输入姓名" clearable style="width: 100%;"></el-input>
<el-input v-model="form.name" placeholder="请输入授课老师" clearable style="width: 100%;"></el-input>
</div>
</div>
</template>
<template v-slot:introduce>
<div class="xy-table-item">
<div class="xy-table-item-label" style="font-weight: bold">
<span style="color: red;font-weight: bold;padding-right: 4px;"></span>老师简介
</div>
<div class="xy-table-item-content">
<el-input v-model="form.introduce" type="textarea" placeholder="请输入老师简介" clearable
style="width: 100%;"></el-input>
</div>
</div>
</template>
@ -35,13 +46,14 @@
</div>
</div>
</template>
<template v-slot:introduce>
<template v-slot:remark>
<div class="xy-table-item">
<div class="xy-table-item-label" style="font-weight: bold">
<span style="color: red;font-weight: bold;padding-right: 4px;"></span>介绍
<span style="color: red;font-weight: bold;padding-right: 4px;"></span>备注
</div>
<div class="xy-table-item-content">
<el-input v-model="form.introduce" type="textarea" placeholder="请输入介绍" clearable
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" clearable
style="width: 100%;"></el-input>
</div>
</div>
@ -69,9 +81,10 @@
id: '',
form: {
name: '',
introduce: '',
sex: '',
mobile: '',
introduce: ''
remark: ''
},
sex_options: [{
label: '男',
@ -108,7 +121,7 @@
save(this.form).then(res => {
this.$message({
type: 'success',
message: this.type === 'add' ? '新增教师成功' : '编辑教师成功'
message: this.type === 'add' ? '新增授课老师成功' : '编辑授课老师成功'
})
this.isShow = false
this.$emit('refresh')
@ -133,9 +146,11 @@
this.id = ''
this.form = {
name: '',
introduce: '',
sex: '',
mobile: '',
introduce: ''
remark: ''
}
this.$refs['dialog'].reset()
}
@ -152,4 +167,4 @@
::v-deep .mobile {
flex-basis: 100%;
}
</style>
</style>

@ -7,7 +7,7 @@
<div slot="content">
<div class="searchwrap" style="display: flex;align-items: center;">
<div>
<el-input v-model="select.name" placeholder="请输入姓名"></el-input>
<el-input v-model="select.name" placeholder="请输入授课老师姓名"></el-input>
</div>
<div>
<el-button type="primary" size="small" @click="select.page=1,getList()"></el-button>
@ -39,28 +39,36 @@
<el-table-column prop="course.name" label="课程名称" width="240" align="left">
<template slot-scope="scope">
<div class="cc-item" v-for="(item, index) in scope.row.course_contents" :key="index">
{{ item.course ? item.course.name : '' }}
<el-tooltip :content="item.course ? item.course.name : ''" placement="top" :disabled="!item.course || item.course.name.length <= 20">
<span>{{ item.course ? item.course.name : '' }}</span>
</el-tooltip>
</div>
</template>
</el-table-column>
<el-table-column prop="theme" label="课程主题" width="240" align="left">
<template slot-scope="scope">
<div class="cc-item" v-for="(item, index) in scope.row.course_contents" :key="index">
{{ item.theme || '' }}
<el-tooltip :content="item.theme || ''" placement="top" :disabled="!item.theme || item.theme.length <= 20">
<span>{{ item.theme || '' }}</span>
</el-tooltip>
</div>
</template>
</el-table-column>
<el-table-column prop="direction" label="课程方向" width="240" align="left">
<template slot-scope="scope">
<div class="cc-item" v-for="(item, index) in scope.row.course_contents" :key="index">
{{ item.direction || '' }}
<el-tooltip :content="item.direction_detail ? item.direction_detail.value : ''" placement="top" :disabled="!item.direction_detail || item.direction_detail.value.length <= 20">
<span>{{ item.direction_detail ? item.direction_detail.value : '' }}</span>
</el-tooltip>
</div>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" width="240" align="left">
<template slot-scope="scope">
<div class="cc-item" v-for="(item, index) in scope.row.course_contents" :key="index">
{{ item.remark || '' }}
<el-tooltip :content="item.remark || ''" placement="top" :disabled="!item.remark || item.remark.length <= 20">
<span>{{ item.remark || '' }}</span>
</el-tooltip>
</div>
</template>
</el-table-column>
@ -118,10 +126,15 @@
fixed: 'left'
},{
prop: 'name',
label: '姓名',
label: '授课老师',
align: 'center',
width: 180,
fixed: 'left'
},{
prop: 'introduce',
label: '老师简介',
align: 'left',
width: 240,
}, {
prop: 'sex',
label: '性别',
@ -132,11 +145,6 @@
label: '联系方式',
align: 'center',
width: 180,
},{
prop: 'introduce',
label: '介绍',
align: 'left',
width: 240,
},{
prop: 'course_contents',
label: '排课历史',
@ -180,7 +188,7 @@
},
async exportExcel() {
let sheetName = `${new Date().getTime().toString()}`
let sheetName = `授课老${new Date().getTime().toString()}`
const res = await index({
filter: [{
key: 'name',
@ -260,8 +268,10 @@
padding: 6px 0;
border-bottom: 1px dashed #dcdfe6;
line-height: 1.2;
word-break: break-all;
white-space: normal;
height: 24px; /* 固定每行高度 */
overflow: hidden; /* 隐藏超出部分 */
text-overflow: ellipsis; /* 超出显示省略号 */
white-space: nowrap; /* 不换行 */
}
.cc-item:last-child {
border-bottom: none;

File diff suppressed because it is too large Load Diff

@ -42,11 +42,22 @@
<span style="color: red;font-weight: bold;padding-right: 4px;"></span>授课老师
</div>
<div class="xy-table-item-content">
<el-select v-model="form.teacher_id" @change="changeTeacher" style="width:100%" placeholder="请选择授课老师"
<el-select filterable v-model="form.teacher_id" @change="changeTeacher" style="width:60%" placeholder="请选择授课老师"
clearable>
<el-option v-for="item in teacher_options" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
<el-button type="primary" size="small" @click="addTeacher" style="margin-left: 10px;">新增授课老师</el-button>
</div>
</div>
</template>
<template v-slot:teacher_introduce>
<div class="xy-table-item">
<div class="xy-table-item-label" style="font-weight: bold">
<span style="color: red;font-weight: bold;padding-right: 4px;"></span>授课老师简介
</div>
<div class="xy-table-item-content">
<el-input type="textarea" :rows="3" style="width: 100%;" v-model="form.teacher_introduce" placeholder="请输入授课老师简介" clearable></el-input>
</div>
</div>
</template>
@ -60,36 +71,40 @@
</div>
</div>
</template>
<template v-slot:address>
<template v-slot:direction>
<div class="xy-table-item">
<div class="xy-table-item-label" style="font-weight: bold">
<span style="color: red;font-weight: bold;padding-right: 4px;"></span>上课地点
<span style="color: red;font-weight: bold;padding-right: 4px;"></span>课程方向
</div>
<div class="xy-table-item-content">
<el-input style="width: 100%;" v-model="form.address" placeholder="请输入上课地点" clearable></el-input>
<el-select filterable v-model="form.direction" style="width:100%" placeholder="请选择课程方向" clearable>
<el-option v-for="item in direction_options" :key="item.id" :label="item.value" :value="item.id">
</el-option>
</el-select>
</div>
</div>
</template>
<template v-slot:address_detail>
<template v-slot:address>
<div class="xy-table-item">
<div class="xy-table-item-label" style="font-weight: bold">
<span style="color: red;font-weight: bold;padding-right: 4px;"></span>签到地点
<span style="color: red;font-weight: bold;padding-right: 4px;"></span>上课地点
</div>
<div class="xy-table-item-content">
<avue-input-map v-model="mapform" :params="mapparams" style="width:100%" placeholder="请选择地图" />
<el-input style="width: 100%;" v-model="form.address" placeholder="请输入上课地点" clearable></el-input>
</div>
</div>
</template>
<template v-slot:direction>
<template v-slot:address_detail>
<div class="xy-table-item">
<div class="xy-table-item-label" style="font-weight: bold">
<span style="color: red;font-weight: bold;padding-right: 4px;"></span>课程方向
<span style="color: red;font-weight: bold;padding-right: 4px;"></span>签到地点
</div>
<div class="xy-table-item-content">
<el-input style="width: 100%;" v-model="form.direction" placeholder="请输入课程方向" clearable></el-input>
<avue-input-map v-model="mapform" :params="mapparams" style="width:100%" placeholder="请选择地图" />
</div>
</div>
</template>
<template v-slot:remark>
<div class="xy-table-item">
<div class="xy-table-item-label" style="font-weight: bold">
@ -149,6 +164,7 @@
</div>
</template>
</xy-dialog>
<addTeacher ref="addTeacher" @refresh="refreshTeacherList"></addTeacher>
</div>
</template>
@ -161,9 +177,16 @@
import {
save as saveTeacher
} from "@/api/info/teachers.js"
import { index as teacherIndex } from "@/api/info/teachers.js";
import addTeacher from '@/views/config/components/addTeacher.vue'
import {
getparameteritem
} from "@/api/system/dictionary.js"
export default {
mixins: [myMixins],
components: {},
components: {
addTeacher
},
data() {
return {
isShow: false,
@ -174,19 +197,22 @@
mapparams: {
zoom: 11
},
direction_options:[],
mapform: [],
form: {
date: '',
// timeRange: [],
period:'',
teacher_id: "",
teacher_introduce: '', //
theme: '',
direction: '', //
address: '',
address_detail: '',
latitude: '',
longitude: '',
course_id: '', // ID
direction: '', //
remark: '', //
// introduce: '',
files: [], //
@ -205,22 +231,61 @@
removedFileIds: [], // ID
}
},
created() {},
created() {
this.getAllPara()
},
methods: {
getAllPara() {
getparameteritem('course_direction').then(res => {
console.log("res", res)
this.direction_options = res.detail
})
},
setTeachers(e) {
this.teacher_options = e
},
async getTeachers() {
try {
const res = await teacherIndex({
page: 1,
page_size: 999,
});
this.teacher_options = res.data;
} catch (error) {
console.error('获取授课老师列表失败:', error);
this.$message.error('获取授课老师列表失败');
}
},
changeTeacher(e) {
if (e) {
this.teacher_options.map(item => {
if (e === item.id) {
this.form.teacher_id = item.id
//
this.form.teacher_introduce = item.introduce || ''
// this.form.introduce = item.introduce
}
})
}
console.log("e", e)
},
addTeacher() {
this.$refs.addTeacher.isShow = true
},
refreshTeacherList() {
//
this.getTeachers().then(() => {
//
if (this.teacher_options && this.teacher_options.length > 0) {
//
const latestTeacher = this.teacher_options[0];
if (latestTeacher) {
this.form.teacher_id = latestTeacher.id;
// this.$message.success(`${latestTeacher.name}`);
}
}
});
},
changeTime(e) {
console.log("eeee", e)
if (e) {
@ -251,6 +316,16 @@
return
}
//
let needUpdateTeacher = false
if (this.form.teacher_id && this.form.teacher_introduce !== undefined) {
//
const selectedTeacher = this.teacher_options.find(item => item.id === this.form.teacher_id)
if (selectedTeacher && selectedTeacher.introduce !== this.form.teacher_introduce) {
needUpdateTeacher = true
}
}
// ID
const existingFileIds = this.form.files.map(file => file.id);
const newFileIds = this.newFileList.map(file => {
@ -269,21 +344,34 @@
console.log('提交数据:', submitData) //
save(submitData).then(res => {
//
save(submitData).then(async (res) => {
this.$message({
type: 'success',
message: this.type === 'add' ? '新增课表成功' : '编辑课表成功'
})
// saveTeacher({
// id: this.form.teacher_id
// }).then(res => {
// })
//
if (needUpdateTeacher) {
try {
await saveTeacher({
id: this.form.teacher_id,
introduce: this.form.teacher_introduce
})
this.$message.success('授课老师简介更新成功')
} catch (error) {
console.error('更新授课老师简介失败:', error)
this.$message.warning('课表保存成功,但授课老师简介更新失败')
}
}
this.isShow = false
this.$emit('refresh')
// this.active = 1
}).catch(error => {
console.error('保存课表失败:', error)
this.$message.error('保存课表失败')
})
},
getDetail() {
show({
@ -292,6 +380,8 @@
}).then(res => {
this.form = this.base.requestToForm(res, this.form)
this.form.files = res.files ? res.files : []
//
this.form.teacher_introduce = res.teacher ? res.teacher.introduce || '' : ''
// this.form.timeRange = [this.form.start_time ? this.form.start_time : '', this.form.end_time ? this.form
// .end_time : ''
// ]
@ -352,6 +442,8 @@
watch: {
isShow(newVal) {
if (newVal) {
//
this.getTeachers()
//
if (this.type === 'editor') {
this.getDetail()
@ -366,6 +458,7 @@
// timeRange: [],
period:'',
teacher_id: "",
teacher_introduce: '', //
theme: '',
address: '',
address_detail: '',

@ -649,9 +649,12 @@
clearable
@keyup.enter="searchStudents">
</el-input>
<el-select v-model="selectedCourseType" placeholder="请选择课程" clearable style="width: 200px;" @change="handleCourseTypeChange">
<el-option v-for="item in courseTypesList" :key="item.id" :label="item.name" :value="item.id">
<el-select v-model="selectedCourse" placeholder="请选择具体课程" clearable style="width: 200px;" @change="handleCourseChange">
<el-option v-for="item in courseList" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
<el-select v-model="selectedStatus" placeholder="审核状态" clearable style="width: 160px;">
<el-option v-for="item in apply_status_list" :key="item.id" :label="item.value" :value="item.id"></el-option>
</el-select>
<el-button
type="primary"
@ -673,8 +676,31 @@
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="name" label="姓名" width="120"></el-table-column>
<el-table-column prop="email" label="邮箱" min-width="200"></el-table-column>
<el-table-column prop="courseName" label="课程名称" min-width="150"></el-table-column>
<el-table-column label="课程名称" min-width="200">
<template slot-scope="scope">
<div v-for="(item, index) in scope.row.course_signs" :key="index">
<div v-if="item.course" style="margin-bottom: 5px;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<div>
{{item.course.year?item.course.year:''}}{{item.course.type_detail?item.course.type_detail.name+' | ':''}}{{item.course.name}}
</div>
<template v-for="state in apply_status_list">
<el-tag
v-if="item.status===state.id"
:key="state.id"
:type="state.type"
size="mini"
style="margin-left: 10px;">
{{state.value}}
</el-tag>
</template>
</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="company" label="公司" min-width="150"></el-table-column>
<el-table-column prop="company_position" label="职务" min-width="120"></el-table-column>
</el-table>
<!-- 分页组件 -->
@ -718,10 +744,12 @@
import { saveEmailTemplate, getEmailTemplateList, deleteEmailTemplate } from '@/api/email/index'
import { uploadEmailRecord } from '@/api/email/index'
import { saveEmailRecord, getEmailRecordList, sendEmail } from '@/api/email/index'
import { index as getCourseList } from '@/api/course/index'
import { indexStudy } from '@/api/student/index.js'
export default {
name: 'EmailManagement',
mixins: [require('@/mixin/selectMixin.js').default],
data() {
return {
activeTab: 'templates',
@ -774,8 +802,9 @@ export default {
//
systemStudentSearch: '',
selectedCourseType: '', //
courseTypesList: [], //
selectedCourse: '', //
courseList: [], //
selectedStatus: '', //
selectedSystemStudents: [], //
allSelectedStudents: [], //
studentsLoading: false,
@ -1439,8 +1468,9 @@ export default {
this.selectedSystemStudents = [] //
this.allSelectedStudents = [] //
this.systemStudentSearch = '' //
this.selectedCourseType = '' //
this.loadCourseTypes() //
this.selectedCourse = '' //
this.courseList = [] //
this.loadCourses() //
this.loadStudents() //
},
@ -1487,13 +1517,34 @@ export default {
// Excel
const excelData = [
['姓名', '邮箱', '课程名称', '公司'],
...uniqueSelections.map(student => [
student.name,
student.email,
student.courseName || '',
student.company || ''
])
['姓名', '邮箱', '课程名称', '公司', '职务'],
...uniqueSelections.map(student => {
//
let courseInfo = ''
if (student.course_signs && student.course_signs.length > 0) {
const courseStrings = student.course_signs.map(item => {
if (item.course) {
const courseName = `${item.course.year || ''}${item.course.type_detail ? item.course.type_detail.name + ' | ' : ''}${item.course.name}`
//
const statusItem = this.apply_status_list.find(state => state.id === item.status)
const statusText = statusItem ? statusItem.value : '未知状态'
return `${courseName} (${statusText})`
}
return ''
}).filter(text => text) //
courseInfo = courseStrings.join('\n')
} else {
courseInfo = student.courseName || ''
}
return [
student.name,
student.email,
courseInfo,
student.company || '',
student.company_position || ''
]
})
]
// 簿
@ -1505,7 +1556,8 @@ export default {
{ wch: 15 }, //
{ wch: 25 }, //
{ wch: 20 }, //
{ wch: 20 } //
{ wch: 20 }, //
{ wch: 12 } //
]
worksheet['!cols'] = colWidths
@ -1581,244 +1633,200 @@ export default {
this.$message.success(`已在控制台打印 ${uniqueSelections.length} 条数据(去重后,包含所有分页选择)`)
},
//
loadCourseTypes() {
getCourseList({
page: 1,
page_size: 999,
sort_name: 'id',
sort_type: 'ASC'
}).then(res => {
this.courseTypesList = res.data
}).catch(error => {
console.error('加载课程列表失败:', error)
})
},
//
handleCourseTypeChange(courseId) {
if (courseId) {
//
const selectedCourse = this.courseTypesList.find(course => course.id === courseId)
if (selectedCourse) {
//
this.systemStudentSearch = selectedCourse.name
//
this.selectedSystemStudents = []
//
this.currentPage = 1
// loadStudents
this.loadStudents()
}
} else {
//
this.systemStudentSearch = ''
//
this.selectedSystemStudents = []
//
this.currentPage = 1
//
this.loadStudents()
}
handleCourseChange() {
//
this.selectedSystemStudents = []
this.currentPage = 1
this.loadStudents()
},
//
loadStudents() {
this.studentsLoading = true
// API
import('@/api/student/index').then(({ index }) => {
//
const params = {
has_course: 1,
page: this.currentPage,
page_size: this.pageSize
}
//
if (this.systemStudentSearch && this.systemStudentSearch.trim()) {
params.keyword = this.systemStudentSearch.trim()
}
//
const params = {
page: this.currentPage,
page_size: this.pageSize
}
if (this.systemStudentSearch && this.systemStudentSearch.trim()) {
params.keyword = this.systemStudentSearch.trim()
}
if (this.selectedCourse) {
params.course_id = this.selectedCourse
}
if (this.selectedStatus !== '' && this.selectedStatus !== null) {
params.status = this.selectedStatus
}
indexStudy(params).then(res => {
//
const currentSelection = [...this.selectedSystemStudents]
console.log('保存当前选择状态:', currentSelection.length)
console.log('当前总选择数组:', this.allSelectedStudents)
//
if (this.selectedCourseType) {
params.course_id = this.selectedCourseType
//
if (currentSelection.length > 0) {
currentSelection.forEach(student => {
// ID
const isDuplicate = this.allSelectedStudents.some(existing => Number(existing.id) === Number(student.id))
if (!isDuplicate) {
this.allSelectedStudents.push(student)
console.log(`✅ 新增学员到总选择: ${student.name} (ID: ${student.id})`)
} else {
console.log(`❌ 跳过重复学员: ${student.name} (ID: ${student.id})`)
}
})
}
index(params, false).then(res => {
//
const currentSelection = [...this.selectedSystemStudents]
console.log('保存当前选择状态:', currentSelection.length)
console.log('当前总选择数组:', this.allSelectedStudents)
//
if (currentSelection.length > 0) {
currentSelection.forEach(student => {
// ID
const isDuplicate = this.allSelectedStudents.some(existing => Number(existing.id) === Number(student.id))
if (!isDuplicate) {
this.allSelectedStudents.push(student)
console.log(`✅ 新增学员到总选择: ${student.name} (ID: ${student.id})`)
} else {
console.log(`❌ 跳过重复学员: ${student.name} (ID: ${student.id})`)
}
console.log('去重后的总选择数组:', this.allSelectedStudents)
// API
const listData = res.list && Array.isArray(res.list.data) ? res.list.data : []
if (Array.isArray(listData)) {
// API
console.log('开始处理学员数据,数量:', listData.length)
this.students = listData.map(student => {
//
let courseName = ''
let courseStartDate = ''
let courseEndDate = ''
if (student.course_signs && student.course_signs.length > 0) {
//
const sortedSigns = student.course_signs.sort((a, b) => {
const dateA = new Date(a.created_at || a.createdAt || a.sign_date || 0)
const dateB = new Date(b.created_at || b.createdAt || b.sign_date || 0)
return dateB - dateA //
})
const latestSign = sortedSigns[0]
// course
if (latestSign.course && latestSign.course.name) {
courseName = latestSign.course.name
courseStartDate = latestSign.course.start_date || ''
courseEndDate = latestSign.course.end_date || ''
} else {
// sign
courseName = latestSign.course_name || latestSign.course || latestSign.courseName || ''
}
} else {
// course_signs使
courseName = student.course_name || student.course || ''
}
return {
id: student.id,
name: student.name || student.real_name || '',
email: student.email || '-',
company: student.company_name || student.work_unit || '',
phone: student.phone || student.mobile || '',
department: student.department || '',
courseName: courseName,
courseStartDate: courseStartDate,
courseEndDate: courseEndDate,
course_signs: student.course_signs || [],
company_position: student.company_position || ''
}
})
// res.list
if (res.list) {
this.totalStudents = res.list.total || 0
this.currentPage = res.list.current_page || 1
this.pageSize = res.list.per_page || this.pageSize
}
console.log('数据处理完成this.students长度:', this.students.length)
console.log('分页信息更新:', {
total: this.totalStudents,
currentPage: this.currentPage,
pageSize: this.pageSize
})
}
console.log('去重后的总选择数组:', this.allSelectedStudents)
// API
console.log('API响应数据:', res) //
console.log('res.data类型:', typeof res.data, '长度:', res.data ? res.data.length : 'undefined')
if (res.data) {
// API
console.log('开始处理学员数据,数量:', res.data.length)
this.students = res.data.map(student => {
//
let courseName = ''
let courseStartDate = ''
let courseEndDate = ''
if (student.course_signs && student.course_signs.length > 0) {
//
const sortedSigns = student.course_signs.sort((a, b) => {
const dateA = new Date(a.created_at || a.createdAt || a.sign_date || 0)
const dateB = new Date(b.created_at || b.createdAt || b.sign_date || 0)
return dateB - dateA //
})
const latestSign = sortedSigns[0]
// course
if (latestSign.course && latestSign.course.name) {
courseName = latestSign.course.name
courseStartDate = latestSign.course.start_date || ''
courseEndDate = latestSign.course.end_date || ''
} else {
// sign
courseName = latestSign.course_name || latestSign.course || latestSign.courseName || ''
}
} else {
// course_signs使
courseName = student.course_name || student.course || ''
}
return {
id: student.id,
name: student.name || student.real_name || '',
email: student.email || '-',
company: student.company_name || student.work_unit || '',
phone: student.phone || student.mobile || '',
department: student.department || '',
courseName: courseName,
courseStartDate: courseStartDate,
courseEndDate: courseEndDate
}
})
//
this.$nextTick(() => {
this.selectedSystemStudents = currentSelection
console.log('已恢复选择状态,数量:', this.selectedSystemStudents.length)
//
this.totalStudents = res.total || 0
this.currentPage = res.current_page || 1
this.pageSize = res.per_page || 20
console.log('数据处理完成this.students长度:', this.students.length)
console.log('分页信息更新:', {
total: this.totalStudents,
currentPage: this.currentPage,
pageSize: this.pageSize
})
//
console.log('开始恢复表格勾选状态...')
console.log('当前页学员数据:', this.students.map(s => ({ id: s.id, name: s.name })))
console.log('当前页选择:', currentSelection.map(s => ({ id: s.id, name: s.name })))
console.log('总选择数组:', this.allSelectedStudents.map(s => ({ id: s.id, name: s.name })))
//
this.$nextTick(() => {
this.selectedSystemStudents = currentSelection
console.log('已恢复选择状态,数量:', this.selectedSystemStudents.length)
//
console.log('开始恢复表格勾选状态...')
console.log('当前页学员数据:', this.students.map(s => ({ id: s.id, name: s.name })))
console.log('当前页选择:', currentSelection.map(s => ({ id: s.id, name: s.name })))
console.log('总选择数组:', this.allSelectedStudents.map(s => ({ id: s.id, name: s.name })))
//
if (currentSelection.length > 0) {
currentSelection.forEach(selectedStudent => {
//
const studentInCurrentPage = this.students.find(student => Number(student.id) === Number(selectedStudent.id))
if (studentInCurrentPage) {
// 使 Element UI
this.$refs.systemStudentTable.toggleRowSelection(studentInCurrentPage, true)
console.log(`✅ 已勾选学员: ${studentInCurrentPage.name} (ID: ${studentInCurrentPage.id})`)
} else {
console.log(`❌ 未找到学员: ${selectedStudent.name} (ID: ${selectedStudent.id})`)
}
})
}
//
this.students.forEach(student => {
const isInAllSelected = this.allSelectedStudents.some(selected => Number(selected.id) === Number(student.id))
const isInCurrentSelection = currentSelection.some(selected => Number(selected.id) === Number(student.id))
if (isInAllSelected && !isInCurrentSelection) {
//
this.$refs.systemStudentTable.toggleRowSelection(student, true)
console.log(`✅ 从总选择恢复勾选: ${student.name} (ID: ${student.id})`)
//
if (currentSelection.length > 0) {
currentSelection.forEach(selectedStudent => {
//
const studentInCurrentPage = this.students.find(student => Number(student.id) === Number(selectedStudent.id))
if (studentInCurrentPage) {
// 使 Element UI
this.$refs.systemStudentTable.toggleRowSelection(studentInCurrentPage, true)
console.log(`✅ 已勾选学员: ${studentInCurrentPage.name} (ID: ${studentInCurrentPage.id})`)
} else {
console.log(`❌ 未找到学员: ${selectedStudent.name} (ID: ${selectedStudent.id})`)
}
})
}
//
this.students.forEach(student => {
const isInAllSelected = this.allSelectedStudents.some(selected => Number(selected.id) === Number(student.id))
const isInCurrentSelection = currentSelection.some(selected => Number(selected.id) === Number(student.id))
console.log('表格勾选状态恢复完成')
if (isInAllSelected && !isInCurrentSelection) {
//
this.$refs.systemStudentTable.toggleRowSelection(student, true)
console.log(`✅ 从总选择恢复勾选: ${student.name} (ID: ${student.id})`)
}
})
} else {
this.students = []
// 使
if (res.total !== undefined) {
this.totalStudents = res.total
}
if (res.current_page !== undefined) {
this.currentPage = res.current_page
}
if (res.per_page !== undefined) {
this.pageSize = res.per_page
}
//
if (res.data && res.data.length === 0) {
this.$message.warning('当前页暂无学员数据')
}
console.log('表格勾选状态恢复完成')
})
} else {
this.students = []
if (res.list) {
if (res.list.total !== undefined) this.totalStudents = res.list.total
if (res.list.current_page !== undefined) this.currentPage = res.list.current_page
if (res.list.per_page !== undefined) this.pageSize = res.list.per_page
}
}).catch(error => {
console.error('加载学员数据失败:', error)
this.$message.error('加载学员数据失败')
// 使
this.students = []
}).finally(() => {
this.studentsLoading = false
if (Array.isArray(listData) && listData.length === 0) {
this.$message.warning('当前页暂无学员数据')
}
}
}).catch(error => {
console.error('加载学员数据失败:', error)
this.$message.error('加载学员数据失败')
// 使
this.students = []
}).finally(() => {
this.studentsLoading = false
//
this.$nextTick(() => {
console.log('在finally中恢复选择状态...')
console.log('当前页学员:', this.students.map(s => ({ id: s.id, name: s.name })))
console.log('当前页选择:', this.selectedSystemStudents.map(s => ({ id: s.id, name: s.name })))
console.log('总选择数组:', this.allSelectedStudents.map(s => ({ id: s.id, name: s.name })))
//
this.$nextTick(() => {
console.log('在finally中恢复选择状态...')
console.log('当前页学员:', this.students.map(s => ({ id: s.id, name: s.name })))
console.log('当前页选择:', this.selectedSystemStudents.map(s => ({ id: s.id, name: s.name })))
console.log('总选择数组:', this.allSelectedStudents.map(s => ({ id: s.id, name: s.name })))
//
this.students.forEach(student => {
const isInCurrentSelection = this.selectedSystemStudents.some(selected => Number(selected.id) === Number(student.id))
const isInAllSelected = this.allSelectedStudents.some(selected => Number(selected.id) === Number(student.id))
//
this.students.forEach(student => {
const isInCurrentSelection = this.selectedSystemStudents.some(selected => Number(selected.id) === Number(student.id))
const isInAllSelected = this.allSelectedStudents.some(selected => Number(selected.id) === Number(student.id))
if (isInCurrentSelection || isInAllSelected) {
// 使 Element UI
this.$refs.systemStudentTable.toggleRowSelection(student, true)
if (isInCurrentSelection) {
console.log(`✅ 在finally中恢复当前页勾选: ${student.name} (ID: ${student.id})`)
} else {
console.log(`✅ 在finally中恢复总选择勾选: ${student.name} (ID: ${student.id})`)
}
if (isInCurrentSelection || isInAllSelected) {
// 使 Element UI
this.$refs.systemStudentTable.toggleRowSelection(student, true)
if (isInCurrentSelection) {
console.log(`✅ 在finally中恢复当前页勾选: ${student.name} (ID: ${student.id})`)
} else {
console.log(`✅ 在finally中恢复总选择勾选: ${student.name} (ID: ${student.id})`)
}
})
console.log('finally中已恢复选择状态')
}
})
console.log('finally中已恢复选择状态')
})
}).catch(error => {
console.error('导入API模块失败:', error)
this.$message.error('系统模块加载失败')
this.students = []
this.studentsLoading = false
})
},
@ -1828,6 +1836,7 @@ export default {
this.currentPage = 1 //
this.selectedSystemStudents = [] //
this.allSelectedStudents = [] //
this.selectedCourse = '' //
this.loadStudents() //
},
@ -1861,6 +1870,21 @@ export default {
document.body.removeChild(link)
this.$message.success(`已导出 ${this.recipients.length} 个收件人数据`)
},
//
loadCourses() {
//
import('@/api/course/index').then(({ index }) => {
index({
page: 1,
page_size: 999
}).then(res => {
this.courseList = res.data || []
}).catch(error => {
console.error('加载课程列表失败:', error)
})
})
}
}
}

@ -85,12 +85,6 @@
</el-option>
</el-select>
</div>
<div>
<el-select v-model="select.is_black" placeholder="请选择是否黑名单" clearable>
<el-option v-for="item in is_schoolmate_list" :key="item.id" :label="item.value" :value="item.id">
</el-option>
</el-select>
</div>
<div>
<el-input v-model="select.company_position" placeholder="请输入职务"></el-input>
</div>
@ -161,7 +155,7 @@
<el-button type="primary" size="small" @click="resetSelect"></el-button>
<el-button type="primary" size="small" @click="importTable"></el-button>
<el-button type="primary" size="small" @click="updateSchoolmates(1)"></el-button>
<el-button type="primary" size="small" @click="updateSchoolmates(0)">/</el-button>
<el-button type="primary" size="small" @click="updateSchoolmates(0)"></el-button>
</div>
</div>
@ -231,14 +225,14 @@
</template>
</el-table-column>
</template>
<template v-slot:is_black>
<!-- <template v-slot:is_black>
<el-table-column align='center' label="是否黑名单" width="120" header-align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.is_black===1" type=""></el-tag>
<el-tag v-else type="info"></el-tag>
</template>
</el-table-column>
</template>
</template> -->
<template v-slot:is_vip>
<el-table-column align='center' label="学员身份" width="120" header-align="center">
<template slot-scope="scope">
@ -335,7 +329,6 @@
company_industry: '',
is_vip: '',
is_schoolmate: '',
is_black: '',
courses_end_date: '',
education: '',
type: '',
@ -423,11 +416,6 @@
label: '是否校友库学员',
align: 'center',
width: 120,
}, {
prop: 'is_black',
label: '是否黑名单',
align: 'center',
width: 120,
},{
prop: 'is_vip',
label: '学员身份',
@ -524,7 +512,6 @@
this.select.is_vip = ''
this.select.courses_end_date = ''
this.select.is_schoolmate = ''
this.select.is_black = ''
this.select.education = ''
this.select.type = ''
this.select.status = ''
@ -557,7 +544,6 @@
is_vip: this.select.is_vip,
courses_end_date: this.select.courses_end_date,
is_schoolmate: this.select.is_schoolmate,
is_black: this.select.is_black,
education: this.select.education,
type: this.select.type,
status: this.select.status,
@ -589,7 +575,7 @@
updateSchoolmates(vip) {
if (this.seleSchoolmates.length > 0) {
if (vip == 0) {
// -
//
this.$confirm(
`确定要将选中的 ${this.seleSchoolmates.length} 名学员从校友库移除吗?`,
'提示',
@ -599,24 +585,10 @@
type: 'warning'
}
).then(() => {
//
this.$confirm(
'是否将这些学员加入黑名单?',
'黑名单确认',
{
confirmButtonText: '是',
cancelButtonText: '否',
type: 'warning'
}
).then(() => {
//
this.submitUpdateSchoolmates(vip, 1);
}).catch(() => {
//
this.submitUpdateSchoolmates(vip, 0);
});
//
this.submitUpdateSchoolmates(vip);
}).catch(() => {
//
//
console.log('用户取消了操作');
});
} else {
@ -640,7 +612,7 @@
).then(() => {
//
if (otherUsers.length > 0) {
this.submitUpdateSchoolmates(vip, 0, otherUsers);
this.submitUpdateSchoolmates(vip, otherUsers);
} else {
this.$Message.warning('没有可设置为校友的学员');
}
@ -659,7 +631,7 @@
type: 'warning'
}
).then(() => {
this.submitUpdateSchoolmates(vip, 0);
this.submitUpdateSchoolmates(vip);
}).catch(() => {
console.log('用户取消了操作');
});
@ -671,7 +643,7 @@
}
},
//
submitUpdateSchoolmates(vip, isBlack, users = null) {
submitUpdateSchoolmates(vip, users = null) {
// users使使seleSchoolmates
const targetUsers = users || this.seleSchoolmates;
@ -683,9 +655,8 @@
updateSchoolmate({
is_schoolmate: vip,
ids: ids.join(','),
is_black: isBlack
is_black: 0 //
}).then(res => {
const blackStatus = isBlack === 1 ? '并加入黑名单' : '但不加入黑名单';
const userCount = targetUsers.length;
const operation = vip === 1 ? '加入校友库' : '从校友库移除';
@ -693,7 +664,7 @@
//
this.$Message.success(`批量${operation}成功,共处理 ${userCount} 名学员`)
} else {
this.$Message.success(`批量${operation}成功${blackStatus}`)
this.$Message.success(`批量${operation}成功`)
}
this.getList()

@ -153,7 +153,7 @@
<div>
<el-button type="primary" size="small" @click="select.page=1,getList()"></el-button>
<el-button type="primary" size="small" @click="resetSelect"></el-button>
<el-button type="primary" size="small" @click="updateSchoolmates(0)">/</el-button>
<el-button type="primary" size="small" @click="updateSchoolmates(0)"></el-button>
</div>
</div>
@ -553,7 +553,7 @@
updateSchoolmates(vip) {
if (this.seleSchoolmates.length > 0) {
if (vip == 0) {
// -
//
this.$confirm(
`确定要将选中的 ${this.seleSchoolmates.length} 名学员从校友库移除吗?`,
'提示',
@ -563,24 +563,10 @@
type: 'warning'
}
).then(() => {
//
this.$confirm(
'是否将这些学员加入黑名单?',
'黑名单确认',
{
confirmButtonText: '是',
cancelButtonText: '否',
type: 'warning'
}
).then(() => {
//
this.submitUpdateSchoolmates(vip, 1);
}).catch(() => {
//
this.submitUpdateSchoolmates(vip, 0);
});
//
this.submitUpdateSchoolmates(vip, 0);
}).catch(() => {
//
//
console.log('用户取消了操作');
});
} else {
@ -604,7 +590,7 @@
).then(() => {
//
if (otherUsers.length > 0) {
this.submitUpdateSchoolmates(vip, 0, otherUsers);
this.submitUpdateSchoolmates(vip, otherUsers);
} else {
this.$Message.warning('没有可设置为校友的学员');
}
@ -623,7 +609,7 @@
type: 'warning'
}
).then(() => {
this.submitUpdateSchoolmates(vip, 0);
this.submitUpdateSchoolmates(vip);
}).catch(() => {
console.log('用户取消了操作');
});
@ -635,7 +621,7 @@
}
},
//
submitUpdateSchoolmates(vip, isBlack, users = null) {
submitUpdateSchoolmates(vip, users = null) {
// users使使seleSchoolmates
const targetUsers = users || this.seleSchoolmates;
@ -647,9 +633,8 @@
updateSchoolmate({
is_schoolmate: vip,
ids: ids.join(','),
is_black: isBlack
is_black: 0 //
}).then(res => {
const blackStatus = isBlack === 1 ? '并加入黑名单' : '但不加入黑名单';
const userCount = targetUsers.length;
const operation = vip === 1 ? '加入校友库' : '从校友库移除';
@ -657,7 +642,7 @@
//
this.$Message.success(`批量${operation}成功,共处理 ${userCount} 名学员(已剔除黑名单学员)`)
} else {
this.$Message.success(`批量${operation}成功${blackStatus}`)
this.$Message.success(`批量${operation}成功`)
}
this.getList()

Loading…
Cancel
Save