fix: 修复学生管理模块问题
1. 后端修复: - 添加 StudentVo 视图类,包含学校名、年级名、班级名、学科名、会员昵称等关联数据 - Service 返回 StudentVo,关联查询各表数据 2. 前端修复: - StudentDialog 改为自获取 schoolTree 和 subjectList - 修复字段名适配(studentId/studentName) - 编辑时完整回显学校/年级/班级三级路径 - 添加 MemberSelectDialog 会员选择弹窗 3. ImportDialog 完善: - 修复 token 获取方式适配 RuoYi 框架 - 完善上传进度显示 4. index.vue 修复: - 表格列字段名适配后端返回数据 - 添加日期格式化函数
This commit is contained in:
parent
9883fddb67
commit
6784e32e1e
|
|
@ -12,6 +12,7 @@ import org.dromara.pangu.school.domain.PgSchool;
|
|||
import org.dromara.pangu.school.domain.vo.SchoolTreeNode;
|
||||
import org.dromara.pangu.school.service.IPgSchoolService;
|
||||
import org.dromara.pangu.student.domain.PgStudent;
|
||||
import org.dromara.pangu.student.domain.vo.StudentVo;
|
||||
import org.dromara.pangu.student.service.IPgStudentService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
|
@ -34,7 +35,7 @@ public class PgStudentController extends BaseController {
|
|||
|
||||
@SaCheckPermission("business:student:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<PgStudent> list(PgStudent student, PageQuery pageQuery) {
|
||||
public TableDataInfo<StudentVo> list(PgStudent student, PageQuery pageQuery) {
|
||||
return studentService.selectPageList(student, pageQuery);
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ public class PgStudentController extends BaseController {
|
|||
|
||||
@SaCheckPermission("business:student:query")
|
||||
@GetMapping("/{studentId}")
|
||||
public R<PgStudent> getInfo(@PathVariable Long studentId) {
|
||||
public R<StudentVo> getInfo(@PathVariable Long studentId) {
|
||||
return R.ok(studentService.selectById(studentId));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
package org.dromara.pangu.student.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 学生视图对象(包含关联数据)
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
@Data
|
||||
public class StudentVo {
|
||||
|
||||
private Long studentId;
|
||||
|
||||
private String studentName;
|
||||
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 性别(0未知 1男 2女)
|
||||
*/
|
||||
private String gender;
|
||||
|
||||
private Date birthday;
|
||||
|
||||
private Long regionId;
|
||||
|
||||
private String regionPath;
|
||||
|
||||
private Long schoolId;
|
||||
|
||||
/**
|
||||
* 学校名称
|
||||
*/
|
||||
private String schoolName;
|
||||
|
||||
private Long schoolGradeId;
|
||||
|
||||
/**
|
||||
* 年级名称
|
||||
*/
|
||||
private String gradeName;
|
||||
|
||||
private Long schoolClassId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
private Long subjectId;
|
||||
|
||||
/**
|
||||
* 学科名称
|
||||
*/
|
||||
private String subjectName;
|
||||
|
||||
private Long memberId;
|
||||
|
||||
/**
|
||||
* 会员昵称
|
||||
*/
|
||||
private String memberNickname;
|
||||
|
||||
/**
|
||||
* 会员手机号
|
||||
*/
|
||||
private String memberPhone;
|
||||
|
||||
private String status;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package org.dromara.pangu.student.service;
|
|||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.pangu.student.domain.PgStudent;
|
||||
import org.dromara.pangu.student.domain.vo.StudentVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -12,9 +13,9 @@ import java.util.List;
|
|||
* @author pangu
|
||||
*/
|
||||
public interface IPgStudentService {
|
||||
TableDataInfo<PgStudent> selectPageList(PgStudent student, PageQuery pageQuery);
|
||||
TableDataInfo<StudentVo> selectPageList(PgStudent student, PageQuery pageQuery);
|
||||
List<PgStudent> selectList(PgStudent student);
|
||||
PgStudent selectById(Long studentId);
|
||||
StudentVo selectById(Long studentId);
|
||||
int insert(PgStudent student);
|
||||
int update(PgStudent student);
|
||||
int deleteByIds(Long[] studentIds);
|
||||
|
|
|
|||
|
|
@ -1,18 +1,36 @@
|
|||
package org.dromara.pangu.student.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.pangu.base.domain.PgClass;
|
||||
import org.dromara.pangu.base.domain.PgGrade;
|
||||
import org.dromara.pangu.base.mapper.PgClassMapper;
|
||||
import org.dromara.pangu.base.mapper.PgGradeMapper;
|
||||
import org.dromara.pangu.member.domain.PgMember;
|
||||
import org.dromara.pangu.member.mapper.PgMemberMapper;
|
||||
import org.dromara.pangu.school.domain.PgSchool;
|
||||
import org.dromara.pangu.school.domain.PgSchoolClass;
|
||||
import org.dromara.pangu.school.domain.PgSchoolGrade;
|
||||
import org.dromara.pangu.school.mapper.PgSchoolClassMapper;
|
||||
import org.dromara.pangu.school.mapper.PgSchoolGradeMapper;
|
||||
import org.dromara.pangu.school.mapper.PgSchoolMapper;
|
||||
import org.dromara.pangu.base.domain.PgSubject;
|
||||
import org.dromara.pangu.base.mapper.PgSubjectMapper;
|
||||
import org.dromara.pangu.student.domain.PgStudent;
|
||||
import org.dromara.pangu.student.domain.vo.StudentVo;
|
||||
import org.dromara.pangu.student.mapper.PgStudentMapper;
|
||||
import org.dromara.pangu.student.service.IPgStudentService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 学生 Service 实现
|
||||
|
|
@ -24,12 +42,25 @@ import java.util.List;
|
|||
public class PgStudentServiceImpl implements IPgStudentService {
|
||||
|
||||
private final PgStudentMapper baseMapper;
|
||||
private final PgSchoolMapper schoolMapper;
|
||||
private final PgSchoolGradeMapper schoolGradeMapper;
|
||||
private final PgSchoolClassMapper schoolClassMapper;
|
||||
private final PgGradeMapper gradeMapper;
|
||||
private final PgClassMapper classMapper;
|
||||
private final PgSubjectMapper subjectMapper;
|
||||
private final PgMemberMapper memberMapper;
|
||||
|
||||
@Override
|
||||
public TableDataInfo<PgStudent> selectPageList(PgStudent student, PageQuery pageQuery) {
|
||||
public TableDataInfo<StudentVo> selectPageList(PgStudent student, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<PgStudent> lqw = buildQueryWrapper(student);
|
||||
Page<PgStudent> page = baseMapper.selectPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(page);
|
||||
|
||||
// 转换为 VO 并填充关联数据
|
||||
List<StudentVo> voList = convertToVoList(page.getRecords());
|
||||
|
||||
Page<StudentVo> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
|
||||
voPage.setRecords(voList);
|
||||
return TableDataInfo.build(voPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -38,8 +69,12 @@ public class PgStudentServiceImpl implements IPgStudentService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PgStudent selectById(Long studentId) {
|
||||
return baseMapper.selectById(studentId);
|
||||
public StudentVo selectById(Long studentId) {
|
||||
PgStudent student = baseMapper.selectById(studentId);
|
||||
if (student == null) {
|
||||
return null;
|
||||
}
|
||||
return convertToVo(student);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -61,6 +96,7 @@ public class PgStudentServiceImpl implements IPgStudentService {
|
|||
LambdaQueryWrapper<PgStudent> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.like(StrUtil.isNotBlank(student.getStudentName()), PgStudent::getStudentName, student.getStudentName());
|
||||
lqw.like(StrUtil.isNotBlank(student.getStudentNo()), PgStudent::getStudentNo, student.getStudentNo());
|
||||
lqw.eq(StrUtil.isNotBlank(student.getGender()), PgStudent::getGender, student.getGender());
|
||||
lqw.eq(student.getSchoolId() != null, PgStudent::getSchoolId, student.getSchoolId());
|
||||
lqw.eq(student.getSchoolGradeId() != null, PgStudent::getSchoolGradeId, student.getSchoolGradeId());
|
||||
lqw.eq(student.getSchoolClassId() != null, PgStudent::getSchoolClassId, student.getSchoolClassId());
|
||||
|
|
@ -69,20 +105,130 @@ public class PgStudentServiceImpl implements IPgStudentService {
|
|||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量转换为 VO 并填充关联数据
|
||||
*/
|
||||
private List<StudentVo> convertToVoList(List<PgStudent> students) {
|
||||
if (students == null || students.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 收集所有需要查询的 ID
|
||||
Set<Long> schoolIds = new HashSet<>();
|
||||
Set<Long> schoolGradeIds = new HashSet<>();
|
||||
Set<Long> schoolClassIds = new HashSet<>();
|
||||
Set<Long> subjectIds = new HashSet<>();
|
||||
Set<Long> memberIds = new HashSet<>();
|
||||
|
||||
for (PgStudent s : students) {
|
||||
if (s.getSchoolId() != null) schoolIds.add(s.getSchoolId());
|
||||
if (s.getSchoolGradeId() != null) schoolGradeIds.add(s.getSchoolGradeId());
|
||||
if (s.getSchoolClassId() != null) schoolClassIds.add(s.getSchoolClassId());
|
||||
if (s.getSubjectId() != null) subjectIds.add(s.getSubjectId());
|
||||
if (s.getMemberId() != null) memberIds.add(s.getMemberId());
|
||||
}
|
||||
|
||||
// 批量查询关联数据
|
||||
Map<Long, PgSchool> schoolMap = schoolIds.isEmpty() ? Collections.emptyMap() :
|
||||
schoolMapper.selectByIds(schoolIds).stream()
|
||||
.collect(Collectors.toMap(PgSchool::getSchoolId, Function.identity()));
|
||||
|
||||
Map<Long, PgSchoolGrade> schoolGradeMap = schoolGradeIds.isEmpty() ? Collections.emptyMap() :
|
||||
schoolGradeMapper.selectByIds(schoolGradeIds).stream()
|
||||
.collect(Collectors.toMap(PgSchoolGrade::getId, Function.identity()));
|
||||
|
||||
Map<Long, PgSchoolClass> schoolClassMap = schoolClassIds.isEmpty() ? Collections.emptyMap() :
|
||||
schoolClassMapper.selectByIds(schoolClassIds).stream()
|
||||
.collect(Collectors.toMap(PgSchoolClass::getId, Function.identity()));
|
||||
|
||||
Map<Long, PgSubject> subjectMap = subjectIds.isEmpty() ? Collections.emptyMap() :
|
||||
subjectMapper.selectByIds(subjectIds).stream()
|
||||
.collect(Collectors.toMap(PgSubject::getSubjectId, Function.identity()));
|
||||
|
||||
Map<Long, PgMember> memberMap = memberIds.isEmpty() ? Collections.emptyMap() :
|
||||
memberMapper.selectByIds(memberIds).stream()
|
||||
.collect(Collectors.toMap(PgMember::getMemberId, Function.identity()));
|
||||
|
||||
// 收集基础年级和班级 ID
|
||||
Set<Long> baseGradeIds = schoolGradeMap.values().stream()
|
||||
.map(PgSchoolGrade::getGradeId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
Set<Long> baseClassIds = schoolClassMap.values().stream()
|
||||
.map(PgSchoolClass::getClassId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 查询基础年级和班级名称
|
||||
Map<Long, String> gradeNameMap = baseGradeIds.isEmpty() ? Collections.emptyMap() :
|
||||
gradeMapper.selectByIds(baseGradeIds).stream()
|
||||
.collect(Collectors.toMap(PgGrade::getGradeId, PgGrade::getGradeName));
|
||||
|
||||
Map<Long, String> classNameMap = baseClassIds.isEmpty() ? Collections.emptyMap() :
|
||||
classMapper.selectByIds(baseClassIds).stream()
|
||||
.collect(Collectors.toMap(PgClass::getClassId, PgClass::getClassName));
|
||||
|
||||
// 转换为 VO
|
||||
List<StudentVo> voList = new ArrayList<>();
|
||||
for (PgStudent s : students) {
|
||||
StudentVo vo = new StudentVo();
|
||||
BeanUtil.copyProperties(s, vo);
|
||||
|
||||
// 填充学校名称
|
||||
PgSchool school = schoolMap.get(s.getSchoolId());
|
||||
if (school != null) {
|
||||
vo.setSchoolName(school.getSchoolName());
|
||||
}
|
||||
|
||||
// 填充年级名称
|
||||
PgSchoolGrade schoolGrade = schoolGradeMap.get(s.getSchoolGradeId());
|
||||
if (schoolGrade != null && schoolGrade.getGradeId() != null) {
|
||||
vo.setGradeName(gradeNameMap.get(schoolGrade.getGradeId()));
|
||||
}
|
||||
|
||||
// 填充班级名称
|
||||
PgSchoolClass schoolClass = schoolClassMap.get(s.getSchoolClassId());
|
||||
if (schoolClass != null && schoolClass.getClassId() != null) {
|
||||
vo.setClassName(classNameMap.get(schoolClass.getClassId()));
|
||||
}
|
||||
|
||||
// 填充学科名称
|
||||
PgSubject subject = subjectMap.get(s.getSubjectId());
|
||||
if (subject != null) {
|
||||
vo.setSubjectName(subject.getSubjectName());
|
||||
}
|
||||
|
||||
// 填充会员信息
|
||||
PgMember member = memberMap.get(s.getMemberId());
|
||||
if (member != null) {
|
||||
vo.setMemberNickname(member.getNickname());
|
||||
vo.setMemberPhone(member.getPhone());
|
||||
}
|
||||
|
||||
voList.add(vo);
|
||||
}
|
||||
|
||||
return voList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个转换为 VO
|
||||
*/
|
||||
private StudentVo convertToVo(PgStudent student) {
|
||||
List<StudentVo> voList = convertToVoList(Collections.singletonList(student));
|
||||
return voList.isEmpty() ? null : voList.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<PgStudent> selectAvailableStudents(String studentName, String studentNo, Long memberId, Long schoolId, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<PgStudent> lqw = new LambdaQueryWrapper<>();
|
||||
// 姓名模糊查询
|
||||
lqw.like(StrUtil.isNotBlank(studentName), PgStudent::getStudentName, studentName);
|
||||
// 学号模糊查询
|
||||
lqw.like(StrUtil.isNotBlank(studentNo), PgStudent::getStudentNo, studentNo);
|
||||
// 可绑定条件:未被绑定 或 已绑定当前会员
|
||||
lqw.and(wrapper -> wrapper
|
||||
.isNull(PgStudent::getMemberId)
|
||||
.or()
|
||||
.eq(memberId != null, PgStudent::getMemberId, memberId)
|
||||
);
|
||||
// 教师身份限制:只能选本校学生
|
||||
lqw.eq(schoolId != null, PgStudent::getSchoolId, schoolId);
|
||||
lqw.orderByDesc(PgStudent::getCreateTime);
|
||||
|
||||
|
|
@ -122,9 +268,8 @@ public class PgStudentServiceImpl implements IPgStudentService {
|
|||
if (studentId == null) {
|
||||
return 0;
|
||||
}
|
||||
// 使用原生SQL更新memberId为null
|
||||
return baseMapper.update(null,
|
||||
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<PgStudent>()
|
||||
new LambdaUpdateWrapper<PgStudent>()
|
||||
.eq(PgStudent::getStudentId, studentId)
|
||||
.set(PgStudent::getMemberId, null)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<el-dialog
|
||||
v-model="visible"
|
||||
title="批量导入学生"
|
||||
width="500px"
|
||||
width="550px"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
>
|
||||
|
|
@ -16,13 +16,16 @@
|
|||
<div style="line-height: 1.8">
|
||||
1. 请先下载导入模板,按模板格式填写数据<br>
|
||||
2. 支持 xlsx、xls 格式文件,单次最多导入500条<br>
|
||||
3. 必填字段:姓名、学校、年级、班级
|
||||
3. 必填字段:姓名、学号、用户手机号、区域、学校、年级、班级<br>
|
||||
4. 若用户手机号已存在则挂载到已有用户,否则自动创建家长账号
|
||||
</div>
|
||||
</template>
|
||||
</el-alert>
|
||||
|
||||
<div style="margin-bottom: 16px;">
|
||||
<el-button type="primary" :icon="Download" @click="handleDownloadTemplate">下载模板</el-button>
|
||||
<el-button type="primary" :icon="Download" @click="handleDownloadTemplate" :loading="downloadLoading">
|
||||
下载模板
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-upload
|
||||
|
|
@ -32,18 +35,27 @@
|
|||
:before-upload="beforeUpload"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
:on-progress="handleProgress"
|
||||
:show-file-list="true"
|
||||
:limit="1"
|
||||
accept=".xlsx,.xls"
|
||||
drag
|
||||
>
|
||||
<el-icon class="el-icon--upload"><Upload /></el-icon>
|
||||
<el-icon class="el-icon--upload"><UploadFilled /></el-icon>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">只能上传 xlsx/xls 文件</div>
|
||||
<div class="el-upload__tip">只能上传 xlsx/xls 文件,文件大小不超过 10MB</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
|
||||
<!-- 上传进度 -->
|
||||
<div v-if="uploading" style="margin-top: 16px;">
|
||||
<el-progress :percentage="uploadProgress" :status="uploadProgress === 100 ? 'success' : ''" />
|
||||
<div style="margin-top: 8px; color: #909399; font-size: 12px;">
|
||||
{{ uploadProgress === 100 ? '上传完成,正在处理数据...' : '正在上传...' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 导入结果 -->
|
||||
<div v-if="importResult" style="margin-top: 16px;">
|
||||
<el-alert
|
||||
|
|
@ -52,15 +64,16 @@
|
|||
:closable="false"
|
||||
/>
|
||||
<div v-if="importResult.failList && importResult.failList.length > 0" style="margin-top: 12px;">
|
||||
<div style="margin-bottom: 8px; font-size: 14px; color: #606266;">失败明细:</div>
|
||||
<el-table :data="importResult.failList" border size="small" max-height="200">
|
||||
<el-table-column prop="row" label="行号" width="80" />
|
||||
<el-table-column prop="reason" label="失败原因" min-width="200" />
|
||||
<el-table-column prop="row" label="行号" width="80" align="center" />
|
||||
<el-table-column prop="reason" label="失败原因" min-width="200" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">关闭</el-button>
|
||||
<el-button @click="handleClose">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
|
@ -70,40 +83,45 @@
|
|||
* 学生批量导入弹窗
|
||||
* @author pangu
|
||||
*/
|
||||
import { Download, Upload } from '@element-plus/icons-vue'
|
||||
import { Download, UploadFilled } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { computed, ref } from 'vue'
|
||||
import { getToken } from '@/utils/auth'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'success'])
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (val) => emit('update:modelValue', val)
|
||||
})
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
const visible = ref(false)
|
||||
const uploadRef = ref(null)
|
||||
const importResult = ref(null)
|
||||
const downloadLoading = ref(false)
|
||||
const uploading = ref(false)
|
||||
const uploadProgress = ref(0)
|
||||
|
||||
// 上传地址
|
||||
const uploadUrl = '/business/student/import'
|
||||
// 上传地址(使用完整路径)
|
||||
const uploadUrl = computed(() => {
|
||||
return import.meta.env.VITE_APP_BASE_API + '/business/student/import'
|
||||
})
|
||||
|
||||
// 上传请求头
|
||||
const uploadHeaders = computed(() => {
|
||||
const token = localStorage.getItem('token')
|
||||
const token = getToken()
|
||||
return token ? { Authorization: 'Bearer ' + token } : {}
|
||||
})
|
||||
|
||||
// 下载模板
|
||||
const handleDownloadTemplate = () => {
|
||||
// 实际应该调用后端接口下载模板
|
||||
ElMessage.info('模板下载功能需要对接后端下载接口')
|
||||
const handleDownloadTemplate = async () => {
|
||||
downloadLoading.value = true
|
||||
try {
|
||||
// 使用 window.open 直接下载
|
||||
const baseApi = import.meta.env.VITE_APP_BASE_API || ''
|
||||
const token = getToken()
|
||||
const url = `${baseApi}/business/student/template?token=${encodeURIComponent(token)}`
|
||||
window.open(url, '_blank')
|
||||
} catch (e) {
|
||||
ElMessage.error('下载模板失败')
|
||||
} finally {
|
||||
downloadLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 上传前校验
|
||||
|
|
@ -119,15 +137,25 @@ const beforeUpload = (file) => {
|
|||
return false
|
||||
}
|
||||
importResult.value = null
|
||||
uploading.value = true
|
||||
uploadProgress.value = 0
|
||||
return true
|
||||
}
|
||||
|
||||
// 上传进度
|
||||
const handleProgress = (event) => {
|
||||
uploadProgress.value = Math.round(event.percent)
|
||||
}
|
||||
|
||||
// 上传成功
|
||||
const handleSuccess = (response) => {
|
||||
uploading.value = false
|
||||
uploadProgress.value = 0
|
||||
|
||||
if (response.code === 200) {
|
||||
importResult.value = response.data
|
||||
if (response.data.failCount === 0) {
|
||||
ElMessage.success('导入成功')
|
||||
ElMessage.success(`导入成功,共导入 ${response.data.successCount} 条数据`)
|
||||
emit('success')
|
||||
} else {
|
||||
ElMessage.warning('部分数据导入失败,请查看失败原因')
|
||||
|
|
@ -138,9 +166,31 @@ const handleSuccess = (response) => {
|
|||
}
|
||||
|
||||
// 上传失败
|
||||
const handleError = () => {
|
||||
const handleError = (error) => {
|
||||
uploading.value = false
|
||||
uploadProgress.value = 0
|
||||
console.error('上传失败:', error)
|
||||
ElMessage.error('文件上传失败,请重试')
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
const handleClose = () => {
|
||||
visible.value = false
|
||||
// 清理状态
|
||||
importResult.value = null
|
||||
uploading.value = false
|
||||
uploadProgress.value = 0
|
||||
}
|
||||
|
||||
// 打开弹窗
|
||||
const open = () => {
|
||||
visible.value = true
|
||||
importResult.value = null
|
||||
uploading.value = false
|
||||
uploadProgress.value = 0
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,156 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="选择归属用户"
|
||||
width="700px"
|
||||
:close-on-click-modal="false"
|
||||
append-to-body
|
||||
>
|
||||
<!-- 搜索区域 -->
|
||||
<el-form :inline="true" style="margin-bottom: 16px">
|
||||
<el-form-item label="手机号">
|
||||
<el-input v-model="queryParams.phone" placeholder="请输入手机号" clearable style="width: 150px" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="昵称">
|
||||
<el-input v-model="queryParams.nickname" placeholder="请输入昵称" clearable style="width: 150px" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
border
|
||||
stripe
|
||||
highlight-current-row
|
||||
@current-change="handleCurrentChange"
|
||||
style="width: 100%"
|
||||
max-height="400"
|
||||
>
|
||||
<el-table-column prop="phone" label="手机号" width="130" />
|
||||
<el-table-column prop="nickname" label="昵称" width="120" />
|
||||
<el-table-column prop="identityType" label="身份" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.identityType === '1' ? 'success' : 'primary'" size="small">
|
||||
{{ row.identityType === '1' ? '家长' : '教师' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="gender" label="性别" width="60" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.gender === '1' ? '男' : row.gender === '2' ? '女' : '未知' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="注册时间" width="160" />
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<el-pagination
|
||||
v-model:current-page="queryParams.pageNum"
|
||||
v-model:page-size="queryParams.pageSize"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
style="margin-top: 16px; justify-content: flex-end"
|
||||
@size-change="getList"
|
||||
@current-change="getList"
|
||||
/>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleConfirm" :disabled="!selectedRow">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* 会员选择弹窗
|
||||
* @author pangu
|
||||
*/
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
import request from '@/utils/request'
|
||||
|
||||
const emit = defineEmits(['select'])
|
||||
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const tableData = ref([])
|
||||
const total = ref(0)
|
||||
const selectedRow = ref(null)
|
||||
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
phone: '',
|
||||
nickname: ''
|
||||
})
|
||||
|
||||
// 获取会员列表
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await request.get('/business/member/list', { params: queryParams.value })
|
||||
if (res.code === 200) {
|
||||
tableData.value = res.rows || []
|
||||
total.value = res.total || 0
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取会员列表失败:', e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
// 重置
|
||||
const resetQuery = () => {
|
||||
queryParams.value = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
phone: '',
|
||||
nickname: ''
|
||||
}
|
||||
getList()
|
||||
}
|
||||
|
||||
// 选中行变化
|
||||
const handleCurrentChange = (row) => {
|
||||
selectedRow.value = row
|
||||
}
|
||||
|
||||
// 确认选择
|
||||
const handleConfirm = () => {
|
||||
if (!selectedRow.value) {
|
||||
ElMessage.warning('请选择一个会员')
|
||||
return
|
||||
}
|
||||
emit('select', selectedRow.value)
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
// 打开弹窗
|
||||
const open = () => {
|
||||
visible.value = true
|
||||
selectedRow.value = null
|
||||
queryParams.value = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
phone: '',
|
||||
nickname: ''
|
||||
}
|
||||
getList()
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
|
@ -5,19 +5,19 @@
|
|||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
@open="handleOpen"
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
v-loading="formLoading"
|
||||
>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入学生姓名" maxlength="20" />
|
||||
<el-form-item label="姓名" prop="studentName">
|
||||
<el-input v-model="form.studentName" placeholder="请输入学生姓名" maxlength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="学号" prop="studentNo">
|
||||
<el-input v-model="form.studentNo" placeholder="请输入学号" maxlength="30" />
|
||||
<el-input v-model="form.studentNo" placeholder="请输入学号(选填)" maxlength="30" />
|
||||
</el-form-item>
|
||||
<el-form-item label="性别" prop="gender">
|
||||
<el-radio-group v-model="form.gender">
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
<el-radio value="0">未知</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="出生日期" prop="birthday">
|
||||
<el-form-item label="出生年月" prop="birthday">
|
||||
<el-date-picker
|
||||
v-model="form.birthday"
|
||||
type="month"
|
||||
|
|
@ -36,38 +36,48 @@
|
|||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="学校信息" prop="schoolPath" required>
|
||||
<el-form-item label="学校信息" prop="schoolClassId" required>
|
||||
<el-cascader
|
||||
v-model="form.schoolPath"
|
||||
:options="schoolTree"
|
||||
:options="schoolTreeData"
|
||||
:props="{
|
||||
value: 'id',
|
||||
label: 'label',
|
||||
label: 'name',
|
||||
children: 'children',
|
||||
checkStrictly: false
|
||||
}"
|
||||
placeholder="请选择学校/年级/班级"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%"
|
||||
@change="handleSchoolChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="学科" prop="subject">
|
||||
<el-select v-model="form.subject" placeholder="请选择学科" clearable style="width: 100%">
|
||||
<el-option v-for="item in subjectList" :key="item.id" :label="item.name" :value="item.name" />
|
||||
<el-form-item label="学科" prop="subjectId">
|
||||
<el-select v-model="form.subjectId" placeholder="请选择学科(选填)" clearable style="width: 100%">
|
||||
<el-option v-for="item in subjectList" :key="item.subjectId" :label="item.subjectName" :value="item.subjectId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="归属用户" prop="userId">
|
||||
<el-input v-model="form.userNickname" placeholder="请输入用户昵称搜索" readonly>
|
||||
<template #append>
|
||||
<el-button @click="handleSelectUser">选择</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-form-item label="归属用户" prop="memberId">
|
||||
<div style="display: flex; gap: 8px; width: 100%">
|
||||
<el-input
|
||||
v-model="form.memberDisplay"
|
||||
placeholder="点击选择归属用户"
|
||||
readonly
|
||||
style="flex: 1"
|
||||
/>
|
||||
<el-button @click="handleSelectMember">选择</el-button>
|
||||
<el-button v-if="form.memberId" @click="handleClearMember">清除</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 会员选择弹窗 -->
|
||||
<MemberSelectDialog ref="memberSelectRef" @select="handleMemberSelected" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
|
|
@ -76,95 +86,157 @@
|
|||
* 学生新增/编辑弹窗
|
||||
* @author pangu
|
||||
*/
|
||||
import { addStudent, getStudent, updateStudent } from '@/api/pangu/student'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
import request from '@/utils/request'
|
||||
import MemberSelectDialog from './MemberSelectDialog.vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
studentId: {
|
||||
type: [Number, null],
|
||||
default: null
|
||||
},
|
||||
schoolTree: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
subjectList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'success'])
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (val) => emit('update:modelValue', val)
|
||||
})
|
||||
|
||||
const isEdit = computed(() => !!props.studentId)
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
const visible = ref(false)
|
||||
const isEdit = ref(false)
|
||||
const formRef = ref(null)
|
||||
const formLoading = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
const memberSelectRef = ref()
|
||||
|
||||
// 学校树数据
|
||||
const schoolTreeData = ref([])
|
||||
// 学科列表
|
||||
const subjectList = ref([])
|
||||
|
||||
const initialForm = {
|
||||
id: null,
|
||||
name: '',
|
||||
studentId: null,
|
||||
studentName: '',
|
||||
studentNo: '',
|
||||
gender: '1',
|
||||
birthday: '',
|
||||
schoolPath: [],
|
||||
subject: '',
|
||||
userId: null,
|
||||
userNickname: ''
|
||||
schoolId: null,
|
||||
schoolGradeId: null,
|
||||
schoolClassId: null,
|
||||
subjectId: null,
|
||||
memberId: null,
|
||||
memberDisplay: ''
|
||||
}
|
||||
|
||||
const form = reactive({ ...initialForm })
|
||||
|
||||
const rules = {
|
||||
name: [
|
||||
studentName: [
|
||||
{ required: true, message: '请输入学生姓名', trigger: 'blur' }
|
||||
],
|
||||
schoolPath: [
|
||||
schoolClassId: [
|
||||
{ required: true, message: '请选择学校/年级/班级', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
|
||||
// 弹窗打开时
|
||||
const handleOpen = async () => {
|
||||
Object.assign(form, initialForm)
|
||||
formRef.value?.clearValidate()
|
||||
// 获取学校树数据
|
||||
const getSchoolTree = async () => {
|
||||
try {
|
||||
const res = await request.get('/business/student/schoolTree')
|
||||
if (res.code === 200) {
|
||||
schoolTreeData.value = res.data || []
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取学校树失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
if (props.studentId) {
|
||||
// 获取学科列表
|
||||
const getSubjectList = async () => {
|
||||
try {
|
||||
const res = await request.get('/business/subject/list', { params: { status: '0' } })
|
||||
if (res.code === 200) {
|
||||
subjectList.value = res.rows || []
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取学科列表失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化出生日期
|
||||
const formatBirthday = (date) => {
|
||||
if (!date) return ''
|
||||
const d = new Date(date)
|
||||
const year = d.getFullYear()
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0')
|
||||
return `${year}-${month}`
|
||||
}
|
||||
|
||||
// 学校选择变化
|
||||
const handleSchoolChange = (value) => {
|
||||
if (value && value.length === 3) {
|
||||
form.schoolId = value[0]
|
||||
form.schoolGradeId = value[1]
|
||||
form.schoolClassId = value[2]
|
||||
} else {
|
||||
form.schoolId = null
|
||||
form.schoolGradeId = null
|
||||
form.schoolClassId = null
|
||||
}
|
||||
}
|
||||
|
||||
// 打开弹窗
|
||||
const open = async (row = null) => {
|
||||
visible.value = true
|
||||
isEdit.value = !!row
|
||||
formLoading.value = true
|
||||
|
||||
// 重置表单
|
||||
Object.assign(form, initialForm)
|
||||
form.schoolPath = []
|
||||
formRef.value?.clearValidate()
|
||||
|
||||
// 获取基础数据
|
||||
await Promise.all([getSchoolTree(), getSubjectList()])
|
||||
|
||||
// 编辑模式:加载学生详情
|
||||
if (row) {
|
||||
try {
|
||||
const res = await getStudent(props.studentId)
|
||||
if (res.data) {
|
||||
const res = await request.get(`/business/student/${row.studentId}`)
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data
|
||||
form.id = data.id
|
||||
form.name = data.name
|
||||
form.studentId = data.studentId
|
||||
form.studentName = data.studentName
|
||||
form.studentNo = data.studentNo
|
||||
form.gender = data.gender
|
||||
form.birthday = data.birthday
|
||||
form.subject = data.subject
|
||||
form.userId = data.userId
|
||||
form.userNickname = data.userNickname
|
||||
// 需要根据实际数据结构构建 schoolPath
|
||||
form.schoolPath = [data.schoolId]
|
||||
form.gender = data.gender || '0'
|
||||
form.birthday = data.birthday ? formatBirthday(data.birthday) : ''
|
||||
form.subjectId = data.subjectId
|
||||
form.memberId = data.memberId
|
||||
form.memberDisplay = data.memberNickname ? `${data.memberNickname}(${data.memberPhone || ''})` : ''
|
||||
|
||||
// 构建学校路径用于级联选择器回显
|
||||
if (data.schoolId && data.schoolGradeId && data.schoolClassId) {
|
||||
form.schoolPath = [data.schoolId, data.schoolGradeId, data.schoolClassId]
|
||||
form.schoolId = data.schoolId
|
||||
form.schoolGradeId = data.schoolGradeId
|
||||
form.schoolClassId = data.schoolClassId
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取学生详情失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
formLoading.value = false
|
||||
}
|
||||
|
||||
// 选择用户
|
||||
const handleSelectUser = () => {
|
||||
// 简化处理,实际应该弹出用户选择器
|
||||
ElMessage.info('用户选择功能需要对接会员管理模块')
|
||||
// 选择会员
|
||||
const handleSelectMember = () => {
|
||||
memberSelectRef.value?.open()
|
||||
}
|
||||
|
||||
// 会员选择回调
|
||||
const handleMemberSelected = (member) => {
|
||||
form.memberId = member.memberId
|
||||
form.memberDisplay = `${member.nickname || '未设置昵称'}(${member.phone})`
|
||||
}
|
||||
|
||||
// 清除会员
|
||||
const handleClearMember = () => {
|
||||
form.memberId = null
|
||||
form.memberDisplay = ''
|
||||
}
|
||||
|
||||
// 提交
|
||||
|
|
@ -174,22 +246,33 @@ const handleSubmit = async () => {
|
|||
} catch (e) {
|
||||
return
|
||||
}
|
||||
|
||||
// 校验学校信息
|
||||
if (!form.schoolClassId) {
|
||||
ElMessage.warning('请选择完整的学校/年级/班级信息')
|
||||
return
|
||||
}
|
||||
|
||||
submitLoading.value = true
|
||||
try {
|
||||
const submitData = {
|
||||
...form,
|
||||
schoolId: form.schoolPath[0],
|
||||
gradeId: form.schoolPath[1],
|
||||
classId: form.schoolPath[2]
|
||||
studentId: form.studentId,
|
||||
studentName: form.studentName,
|
||||
studentNo: form.studentNo,
|
||||
gender: form.gender,
|
||||
birthday: form.birthday,
|
||||
schoolId: form.schoolId,
|
||||
schoolGradeId: form.schoolGradeId,
|
||||
schoolClassId: form.schoolClassId,
|
||||
subjectId: form.subjectId,
|
||||
memberId: form.memberId
|
||||
}
|
||||
delete submitData.schoolPath
|
||||
|
||||
if (isEdit.value) {
|
||||
await updateStudent(submitData)
|
||||
await request.put('/business/student', submitData)
|
||||
ElMessage.success('修改成功')
|
||||
} else {
|
||||
await addStudent(submitData)
|
||||
await request.post('/business/student', submitData)
|
||||
ElMessage.success('新增成功')
|
||||
}
|
||||
visible.value = false
|
||||
|
|
@ -200,4 +283,6 @@ const handleSubmit = async () => {
|
|||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -59,18 +59,28 @@
|
|||
|
||||
<el-table v-loading="loading" :data="tableData" border stripe :header-cell-style="{ background: '#f5f7fa', color: '#606266' }" style="width: 100%">
|
||||
<el-table-column prop="studentNo" label="学号" width="130" />
|
||||
<el-table-column prop="name" label="姓名" width="100" />
|
||||
<el-table-column prop="studentName" label="姓名" width="100" />
|
||||
<el-table-column prop="gender" label="性别" width="60" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.gender === '1' ? '男' : row.gender === '2' ? '女' : '未知' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="birthday" label="出生年月" width="100" />
|
||||
<el-table-column prop="birthday" label="出生年月" width="100">
|
||||
<template #default="{ row }">
|
||||
{{ row.birthday ? formatDate(row.birthday) : '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="schoolName" label="学校" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="gradeName" label="年级" width="80" />
|
||||
<el-table-column prop="className" label="班级" width="80" />
|
||||
<el-table-column prop="subject" label="学科" width="80" />
|
||||
<el-table-column prop="userNickname" label="归属用户" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="subjectName" label="学科" width="80" />
|
||||
<el-table-column prop="memberNickname" label="归属用户" width="120" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.memberNickname">{{ row.memberNickname }}</span>
|
||||
<span v-else-if="row.memberPhone">{{ row.memberPhone }}</span>
|
||||
<span v-else style="color: #909399">未绑定</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="160" />
|
||||
<el-table-column label="操作" width="150" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
|
|
@ -228,14 +238,23 @@ const handleImport = () => {
|
|||
importDialogRef.value?.open()
|
||||
}
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (date) => {
|
||||
if (!date) return ''
|
||||
const d = new Date(date)
|
||||
const year = d.getFullYear()
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0')
|
||||
return `${year}-${month}`
|
||||
}
|
||||
|
||||
// 删除
|
||||
const handleDelete = (row) => {
|
||||
ElMessageBox.confirm(`确定要删除学生"${row.name}"吗?`, '提示', {
|
||||
ElMessageBox.confirm(`确定要删除学生"${row.studentName}"吗?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
const res = await request.delete(`/business/student/${row.id}`)
|
||||
const res = await request.delete(`/business/student/${row.studentId}`)
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('删除成功')
|
||||
getList()
|
||||
|
|
|
|||
Loading…
Reference in New Issue