feat: 完成所有模块待完成任务和模块集成
## 应用管理模块后端开发 - 创建pg_application、pg_app_api、pg_api_dict三张表 - 实现Application、AppApi、ApiDict实体类 - 实现ApplicationMapper及XML映射 - 实现IApplicationService及实现类 - 实现ApplicationController(7个API接口) - 应用编码生成:YY + 6位序号 - 密钥生成:32位随机字符串 - 接口授权保存(事务处理) ## 学生会员模块集成 - IStudentService新增5个方法: - isStudentInSchool:检查学生是否在指定学校 - updateStudentMember:更新学生会员关联 - unbindStudent:解绑学生 - countByMemberId:统计会员绑定学生数 - selectStudentVOsByMemberId:查询会员绑定学生列表 - StudentServiceImpl实现5个方法 - StudentMapper新增2个SQL查询 - MemberServiceImpl完成5个TODO: - 学生绑定校验(教师只能绑定本校学生) - 学生绑定更新 - 学生解绑 - 删除前检查(有学生不可删) - 获取绑定学生列表 ## 学生批量导入完善 - IRegionService新增getRegionIdByPath方法 - ISchoolService新增3个方法: - getSchoolIdByName:根据学校名称查询ID - getSchoolGradeId:根据年级名称查询ID - getSchoolClassId:根据班级名称查询ID - IMemberService新增getOrCreateMemberByPhone方法 - StudentImportListener完整实现: - 区域ID查询 - 学校ID查询 - 年级ID查询 - 班级ID查询 - 会员查询或创建 - 学生信息保存 - 性别和出生日期解析 ## 导入模板下载 - StudentController实现downloadTemplate方法 - 使用EasyExcel生成标准Excel模板 - 包含示例数据
This commit is contained in:
parent
275a4ed3a8
commit
178a1ea507
|
|
@ -7,32 +7,32 @@ import com.pangu.application.service.IApplicationService;
|
|||
import com.pangu.common.core.controller.BaseController;
|
||||
import com.pangu.common.core.domain.AjaxResult;
|
||||
import com.pangu.common.core.page.TableDataInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 应用管理控制器
|
||||
* 应用管理Controller
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/app")
|
||||
@RequestMapping("/api/application")
|
||||
@RequiredArgsConstructor
|
||||
@PreAuthorize("hasRole('admin')")
|
||||
public class ApplicationController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private IApplicationService applicationService;
|
||||
private final IApplicationService applicationService;
|
||||
|
||||
/**
|
||||
* 查询应用列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(ApplicationDTO dto) {
|
||||
startPage();
|
||||
List<ApplicationVO> list = applicationService.selectApplicationList(dto);
|
||||
return getDataTable(list);
|
||||
public TableDataInfo list(ApplicationDTO applicationDTO) {
|
||||
return applicationService.selectApplicationList(applicationDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -40,15 +40,16 @@ public class ApplicationController extends BaseController {
|
|||
*/
|
||||
@GetMapping("/{appId}")
|
||||
public AjaxResult getInfo(@PathVariable Long appId) {
|
||||
return success(applicationService.selectApplicationById(appId));
|
||||
ApplicationVO applicationVO = applicationService.getApplicationById(appId);
|
||||
return success(applicationVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增应用
|
||||
*/
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody ApplicationDTO dto) {
|
||||
Map<String, String> result = applicationService.insertApplication(dto);
|
||||
public AjaxResult add(@Validated @RequestBody ApplicationDTO applicationDTO) {
|
||||
ApplicationVO result = applicationService.insertApplication(applicationDTO);
|
||||
return success(result);
|
||||
}
|
||||
|
||||
|
|
@ -56,8 +57,8 @@ public class ApplicationController extends BaseController {
|
|||
* 修改应用
|
||||
*/
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody ApplicationDTO dto) {
|
||||
return toAjax(applicationService.updateApplication(dto));
|
||||
public AjaxResult edit(@Validated @RequestBody ApplicationDTO applicationDTO) {
|
||||
return toAjax(applicationService.updateApplication(applicationDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -65,7 +66,7 @@ public class ApplicationController extends BaseController {
|
|||
*/
|
||||
@DeleteMapping("/{appId}")
|
||||
public AjaxResult remove(@PathVariable Long appId) {
|
||||
return toAjax(applicationService.deleteApplicationById(appId));
|
||||
return toAjax(applicationService.deleteApplication(appId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -73,16 +74,16 @@ public class ApplicationController extends BaseController {
|
|||
*/
|
||||
@PutMapping("/resetSecret/{appId}")
|
||||
public AjaxResult resetSecret(@PathVariable Long appId) {
|
||||
String newSecret = applicationService.resetAppSecret(appId);
|
||||
return success(Map.of("appSecret", newSecret));
|
||||
String newSecret = applicationService.resetSecret(appId);
|
||||
return success(newSecret);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取API接口列表(用于授权选择)
|
||||
* 获取API接口列表
|
||||
*/
|
||||
@GetMapping("/apiList")
|
||||
public AjaxResult apiList() {
|
||||
List<ApiDict> list = applicationService.selectApiDictList();
|
||||
public AjaxResult getApiList() {
|
||||
List<ApiDict> list = applicationService.getApiList();
|
||||
return success(list);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,51 +3,57 @@ package com.pangu.application.domain.dto;
|
|||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 应用传输对象
|
||||
* 应用数据传输对象
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
@Data
|
||||
public class ApplicationDTO implements Serializable {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 应用ID(编辑时必填) */
|
||||
/** 应用ID */
|
||||
private Long appId;
|
||||
|
||||
/** 应用编码 */
|
||||
private String appCode;
|
||||
|
||||
/** 应用名称 */
|
||||
@NotBlank(message = "应用名称不能为空")
|
||||
@Size(max = 100, message = "应用名称不能超过100个字符")
|
||||
private String appName;
|
||||
|
||||
/** 应用编码(查询条件) */
|
||||
private String appCode;
|
||||
|
||||
/** 应用描述 */
|
||||
@Size(max = 500, message = "应用描述不能超过500个字符")
|
||||
private String appDesc;
|
||||
/** 应用密钥 */
|
||||
private String appSecret;
|
||||
|
||||
/** 联系人 */
|
||||
@Size(max = 50, message = "联系人不能超过50个字符")
|
||||
private String contactPerson;
|
||||
|
||||
/** 联系电话 */
|
||||
@Size(max = 20, message = "联系电话不能超过20个字符")
|
||||
private String contactPhone;
|
||||
|
||||
/** 状态(0正常 1停用) */
|
||||
private String status;
|
||||
|
||||
/** 授权的接口编码列表 */
|
||||
private List<String> apiCodes;
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
|
||||
/** 分页页码 */
|
||||
/** 授权接口ID列表 */
|
||||
private List<Long> apiIds;
|
||||
|
||||
// ========== 查询条件 ==========
|
||||
/** 开始时间(查询条件) */
|
||||
private String beginTime;
|
||||
|
||||
/** 结束时间(查询条件) */
|
||||
private String endTime;
|
||||
|
||||
/** 页码 */
|
||||
private Integer pageNum;
|
||||
|
||||
/** 分页大小 */
|
||||
/** 每页数量 */
|
||||
private Integer pageSize;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,20 @@
|
|||
package com.pangu.application.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* API接口字典实体
|
||||
* API接口字典实体类
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
@Data
|
||||
@TableName("pg_api_dict")
|
||||
public class ApiDict implements Serializable {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 接口ID */
|
||||
|
|
@ -35,26 +33,16 @@ public class ApiDict implements Serializable {
|
|||
/** 请求方法 */
|
||||
private String apiMethod;
|
||||
|
||||
/** 接口描述 */
|
||||
private String apiDesc;
|
||||
|
||||
/** 显示顺序 */
|
||||
private Integer orderNum;
|
||||
/** 排序 */
|
||||
private Integer sortOrder;
|
||||
|
||||
/** 状态(0正常 1停用) */
|
||||
private String status;
|
||||
|
||||
/** 创建者 */
|
||||
private String createBy;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/** 更新者 */
|
||||
private String updateBy;
|
||||
|
||||
/** 更新时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,20 @@
|
|||
package com.pangu.application.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 应用接口授权实体
|
||||
* 应用接口授权实体类
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
@Data
|
||||
@TableName("pg_app_grant")
|
||||
@TableName("pg_app_api")
|
||||
public class AppApi implements Serializable {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
|
|
@ -26,19 +24,10 @@ public class AppApi implements Serializable {
|
|||
/** 应用ID */
|
||||
private Long appId;
|
||||
|
||||
/** 接口编码 */
|
||||
private String apiCode;
|
||||
|
||||
/** 接口名称 */
|
||||
private String apiName;
|
||||
|
||||
/** 接口路径 */
|
||||
private String apiPath;
|
||||
|
||||
/** 创建者 */
|
||||
private String createBy;
|
||||
/** 接口ID */
|
||||
private Long apiId;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,35 @@
|
|||
package com.pangu.application.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.pangu.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 应用实体
|
||||
* 应用实体类
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("pg_application")
|
||||
public class Application extends BaseEntity {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 应用ID */
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long appId;
|
||||
|
||||
/** 应用编码(格式:YY + 6位序号) */
|
||||
/** 应用编码 */
|
||||
private String appCode;
|
||||
|
||||
/** 应用名称 */
|
||||
private String appName;
|
||||
|
||||
/** 应用密钥(32位随机字符串) */
|
||||
/** 应用密钥 */
|
||||
private String appSecret;
|
||||
|
||||
/** 应用描述 */
|
||||
private String appDesc;
|
||||
|
||||
/** 联系人 */
|
||||
private String contactPerson;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,41 +4,70 @@ import com.fasterxml.jackson.annotation.JsonFormat;
|
|||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 应用视图对象
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
@Data
|
||||
public class ApplicationVO implements Serializable {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 应用ID */
|
||||
private Long appId;
|
||||
|
||||
/** 应用编码 */
|
||||
private String appCode;
|
||||
|
||||
/** 应用名称 */
|
||||
private String appName;
|
||||
private String appDesc;
|
||||
|
||||
/** 应用密钥 */
|
||||
private String appSecret;
|
||||
|
||||
/** 联系人 */
|
||||
private String contactPerson;
|
||||
|
||||
/** 联系电话 */
|
||||
private String contactPhone;
|
||||
|
||||
/** 状态(0正常 1停用) */
|
||||
private String status;
|
||||
private String createBy;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/** 授权的接口列表 */
|
||||
private List<ApiInfo> apis;
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
|
||||
/** 授权接口列表 */
|
||||
private List<ApiVO> apiList;
|
||||
|
||||
/**
|
||||
* 接口信息
|
||||
* API视图对象
|
||||
*/
|
||||
@Data
|
||||
public static class ApiInfo implements Serializable {
|
||||
public static class ApiVO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 接口ID */
|
||||
private Long apiId;
|
||||
|
||||
/** 接口编码 */
|
||||
private String apiCode;
|
||||
|
||||
/** 接口名称 */
|
||||
private String apiName;
|
||||
|
||||
/** 接口路径 */
|
||||
private String apiPath;
|
||||
|
||||
/** 请求方法 */
|
||||
private String apiMethod;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,26 +3,12 @@ package com.pangu.application.mapper;
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.pangu.application.domain.entity.ApiDict;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* API接口字典Mapper接口
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
@Mapper
|
||||
public interface ApiDictMapper extends BaseMapper<ApiDict> {
|
||||
|
||||
/**
|
||||
* 查询启用的接口列表
|
||||
*/
|
||||
@Select("SELECT * FROM pg_api_dict WHERE status = '0' ORDER BY order_num")
|
||||
List<ApiDict> selectEnabledList();
|
||||
|
||||
/**
|
||||
* 根据接口编码列表查询
|
||||
*/
|
||||
List<ApiDict> selectByCodes(@Param("codes") List<String> codes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,37 +2,32 @@ package com.pangu.application.mapper;
|
|||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.pangu.application.domain.entity.AppApi;
|
||||
import org.apache.ibatis.annotations.Delete;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 应用接口授权Mapper接口
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
@Mapper
|
||||
public interface AppApiMapper extends BaseMapper<AppApi> {
|
||||
|
||||
/**
|
||||
* 根据应用ID查询授权接口
|
||||
* 批量插入应用接口授权
|
||||
*
|
||||
* @param list 授权列表
|
||||
* @return 影响行数
|
||||
*/
|
||||
@Select("SELECT * FROM pg_app_grant WHERE app_id = #{appId}")
|
||||
List<AppApi> selectByAppId(@Param("appId") Long appId);
|
||||
int batchInsert(@Param("list") List<AppApi> list);
|
||||
|
||||
/**
|
||||
* 根据应用ID删除授权接口
|
||||
* 根据应用ID删除授权
|
||||
*
|
||||
* @param appId 应用ID
|
||||
* @return 影响行数
|
||||
*/
|
||||
@Delete("DELETE FROM pg_app_grant WHERE app_id = #{appId}")
|
||||
int deleteByAppId(@Param("appId") Long appId);
|
||||
|
||||
/**
|
||||
* 根据应用编码查询授权的接口路径列表
|
||||
*/
|
||||
@Select("SELECT aa.api_path FROM pg_app_grant aa "
|
||||
+ "INNER JOIN pg_application a ON aa.app_id = a.app_id "
|
||||
+ "WHERE a.app_code = #{appCode} AND a.del_flag = '0'")
|
||||
List<String> selectApiPathsByAppCode(@Param("appCode") String appCode);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,53 @@
|
|||
package com.pangu.application.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.pangu.application.domain.dto.ApplicationDTO;
|
||||
import com.pangu.application.domain.entity.Application;
|
||||
import com.pangu.application.domain.vo.ApplicationVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 应用Mapper接口
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
@Mapper
|
||||
public interface ApplicationMapper extends BaseMapper<Application> {
|
||||
|
||||
/**
|
||||
* 查询最大应用编码
|
||||
* 查询应用列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param dto 查询条件
|
||||
* @return 应用列表
|
||||
*/
|
||||
@Select("SELECT MAX(app_code) FROM pg_application WHERE del_flag = '0'")
|
||||
String selectMaxAppCode();
|
||||
List<ApplicationVO> selectApplicationVOList(Page<ApplicationVO> page, @Param("dto") ApplicationDTO dto);
|
||||
|
||||
/**
|
||||
* 根据应用编码查询应用
|
||||
* 根据ID查询应用详情
|
||||
*
|
||||
* @param appId 应用ID
|
||||
* @return 应用详情
|
||||
*/
|
||||
@Select("SELECT * FROM pg_application WHERE app_code = #{appCode} AND del_flag = '0'")
|
||||
Application selectByAppCode(@Param("appCode") String appCode);
|
||||
ApplicationVO selectApplicationVOById(@Param("appId") Long appId);
|
||||
|
||||
/**
|
||||
* 检查应用名称是否存在(排除指定ID)
|
||||
* 检查应用编码是否唯一
|
||||
*
|
||||
* @param appCode 应用编码
|
||||
* @param appId 应用ID(编辑时排除自己)
|
||||
* @return 数量
|
||||
*/
|
||||
@Select("SELECT COUNT(*) FROM pg_application WHERE app_name = #{appName} AND del_flag = '0' AND ( #{excludeId} IS NULL OR app_id != #{excludeId} )")
|
||||
int checkAppNameExists(@Param("appName") String appName, @Param("excludeId") Long excludeId);
|
||||
int countByAppCode(@Param("appCode") String appCode, @Param("appId") Long appId);
|
||||
|
||||
/**
|
||||
* 获取下一个应用编码序号
|
||||
*
|
||||
* @return 序号
|
||||
*/
|
||||
int getNextCodeSeq();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,63 +1,82 @@
|
|||
package com.pangu.application.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.pangu.application.domain.dto.ApplicationDTO;
|
||||
import com.pangu.application.domain.entity.ApiDict;
|
||||
import com.pangu.application.domain.entity.Application;
|
||||
import com.pangu.application.domain.vo.ApplicationVO;
|
||||
import com.pangu.common.core.page.TableDataInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 应用管理服务接口
|
||||
* 应用服务接口
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
public interface IApplicationService {
|
||||
public interface IApplicationService extends IService<Application> {
|
||||
|
||||
/**
|
||||
* 查询应用列表
|
||||
*
|
||||
* @param applicationDTO 查询条件
|
||||
* @return 应用列表
|
||||
*/
|
||||
List<ApplicationVO> selectApplicationList(ApplicationDTO dto);
|
||||
TableDataInfo selectApplicationList(ApplicationDTO applicationDTO);
|
||||
|
||||
/**
|
||||
* 查询应用详情
|
||||
* 根据ID查询应用详情
|
||||
*
|
||||
* @param appId 应用ID
|
||||
* @return 应用详情
|
||||
*/
|
||||
ApplicationVO selectApplicationById(Long appId);
|
||||
ApplicationVO getApplicationById(Long appId);
|
||||
|
||||
/**
|
||||
* 新增应用
|
||||
* @return 包含 appCode 和 appSecret 的 Map
|
||||
*
|
||||
* @param applicationDTO 应用信息
|
||||
* @return 结果(包含新生成的密钥)
|
||||
*/
|
||||
Map<String, String> insertApplication(ApplicationDTO dto);
|
||||
ApplicationVO insertApplication(ApplicationDTO applicationDTO);
|
||||
|
||||
/**
|
||||
* 修改应用
|
||||
*
|
||||
* @param applicationDTO 应用信息
|
||||
* @return 结果
|
||||
*/
|
||||
int updateApplication(ApplicationDTO dto);
|
||||
int updateApplication(ApplicationDTO applicationDTO);
|
||||
|
||||
/**
|
||||
* 删除应用
|
||||
*
|
||||
* @param appId 应用ID
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteApplicationById(Long appId);
|
||||
int deleteApplication(Long appId);
|
||||
|
||||
/**
|
||||
* 重置应用密钥
|
||||
*
|
||||
* @param appId 应用ID
|
||||
* @return 新密钥
|
||||
*/
|
||||
String resetAppSecret(Long appId);
|
||||
String resetSecret(Long appId);
|
||||
|
||||
/**
|
||||
* 获取API接口字典列表(用于授权选择)
|
||||
* 获取API接口列表
|
||||
*
|
||||
* @return API接口列表
|
||||
*/
|
||||
List<ApiDict> selectApiDictList();
|
||||
List<ApiDict> getApiList();
|
||||
|
||||
/**
|
||||
* 根据应用编码查询应用(用于开放API认证)
|
||||
* 检查应用编码是否唯一
|
||||
*
|
||||
* @param appCode 应用编码
|
||||
* @param appId 应用ID
|
||||
* @return true唯一 false不唯一
|
||||
*/
|
||||
Application selectByAppCode(String appCode);
|
||||
|
||||
/**
|
||||
* 检查应用是否有接口权限
|
||||
*/
|
||||
boolean checkApiPermission(String appCode, String apiPath);
|
||||
boolean checkAppCodeUnique(String appCode, Long appId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package com.pangu.application.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.pangu.application.domain.dto.ApplicationDTO;
|
||||
import com.pangu.application.domain.entity.ApiDict;
|
||||
import com.pangu.application.domain.entity.AppApi;
|
||||
|
|
@ -13,222 +15,198 @@ import com.pangu.application.mapper.AppApiMapper;
|
|||
import com.pangu.application.mapper.ApplicationMapper;
|
||||
import com.pangu.application.service.IApplicationService;
|
||||
import com.pangu.common.core.exception.ServiceException;
|
||||
import com.pangu.common.utils.DateUtils;
|
||||
import com.pangu.common.core.page.TableDataInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 应用管理服务实现
|
||||
* 应用服务实现
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ApplicationServiceImpl implements IApplicationService {
|
||||
@RequiredArgsConstructor
|
||||
public class ApplicationServiceImpl extends ServiceImpl<ApplicationMapper, Application> implements IApplicationService {
|
||||
|
||||
@Resource
|
||||
private ApplicationMapper applicationMapper;
|
||||
@Resource
|
||||
private AppApiMapper appApiMapper;
|
||||
@Resource
|
||||
private ApiDictMapper apiDictMapper;
|
||||
private final ApplicationMapper applicationMapper;
|
||||
private final AppApiMapper appApiMapper;
|
||||
private final ApiDictMapper apiDictMapper;
|
||||
|
||||
@Override
|
||||
public List<ApplicationVO> selectApplicationList(ApplicationDTO dto) {
|
||||
LambdaQueryWrapper<Application> wrapper = new LambdaQueryWrapper<>();
|
||||
if (dto != null && dto.getAppName() != null && !dto.getAppName().isEmpty()) {
|
||||
wrapper.like(Application::getAppName, dto.getAppName());
|
||||
}
|
||||
if (dto != null && dto.getAppCode() != null && !dto.getAppCode().isEmpty()) {
|
||||
wrapper.like(Application::getAppCode, dto.getAppCode());
|
||||
}
|
||||
if (dto != null && dto.getStatus() != null && !dto.getStatus().isEmpty()) {
|
||||
wrapper.eq(Application::getStatus, dto.getStatus());
|
||||
}
|
||||
wrapper.orderByDesc(Application::getCreateTime);
|
||||
List<Application> list = applicationMapper.selectList(wrapper);
|
||||
List<ApplicationVO> result = new ArrayList<>();
|
||||
for (Application app : list) {
|
||||
result.add(toVO(app));
|
||||
}
|
||||
return result;
|
||||
public TableDataInfo selectApplicationList(ApplicationDTO applicationDTO) {
|
||||
Page<ApplicationVO> page = new Page<>(
|
||||
applicationDTO.getPageNum() != null ? applicationDTO.getPageNum() : 1,
|
||||
applicationDTO.getPageSize() != null ? applicationDTO.getPageSize() : 10
|
||||
);
|
||||
List<ApplicationVO> list = applicationMapper.selectApplicationVOList(page, applicationDTO);
|
||||
return new TableDataInfo(list, page.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationVO selectApplicationById(Long appId) {
|
||||
Application app = applicationMapper.selectById(appId);
|
||||
if (app == null) {
|
||||
throw new ServiceException("应用不存在");
|
||||
}
|
||||
return toVO(app);
|
||||
public ApplicationVO getApplicationById(Long appId) {
|
||||
return applicationMapper.selectApplicationVOById(appId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, String> insertApplication(ApplicationDTO dto) {
|
||||
if (applicationMapper.checkAppNameExists(dto.getAppName(), null) > 0) {
|
||||
throw new ServiceException("应用名称已存在");
|
||||
}
|
||||
public ApplicationVO insertApplication(ApplicationDTO applicationDTO) {
|
||||
// 生成应用编码
|
||||
String appCode = generateAppCode();
|
||||
|
||||
// 生成应用密钥
|
||||
String appSecret = generateAppSecret();
|
||||
Application app = new Application();
|
||||
app.setAppCode(appCode);
|
||||
app.setAppName(dto.getAppName());
|
||||
app.setAppSecret(appSecret);
|
||||
app.setAppDesc(dto.getAppDesc());
|
||||
app.setContactPerson(dto.getContactPerson());
|
||||
app.setContactPhone(dto.getContactPhone());
|
||||
app.setStatus(dto.getStatus() != null ? dto.getStatus() : "0");
|
||||
app.setCreateBy("admin");
|
||||
app.setCreateTime(DateUtils.getNowDate());
|
||||
app.setDelFlag("0");
|
||||
applicationMapper.insert(app);
|
||||
saveAppApis(app.getAppId(), dto.getApiCodes());
|
||||
Map<String, String> result = new HashMap<>();
|
||||
result.put("appCode", appCode);
|
||||
result.put("appSecret", appSecret);
|
||||
|
||||
// 构建应用对象
|
||||
Application application = buildApplication(applicationDTO);
|
||||
application.setAppCode(appCode);
|
||||
application.setAppSecret(appSecret);
|
||||
application.setStatus("0");
|
||||
|
||||
// 保存应用
|
||||
int result = applicationMapper.insert(application);
|
||||
if (result <= 0) {
|
||||
throw new ServiceException("新增应用失败");
|
||||
}
|
||||
|
||||
// 保存接口授权
|
||||
saveAppApis(application.getAppId(), applicationDTO.getApiIds());
|
||||
|
||||
log.info("新增应用成功, appId={}, appCode={}", application.getAppId(), appCode);
|
||||
|
||||
// 返回应用信息(包含密钥)
|
||||
ApplicationVO vo = new ApplicationVO();
|
||||
vo.setAppId(application.getAppId());
|
||||
vo.setAppCode(appCode);
|
||||
vo.setAppName(application.getAppName());
|
||||
vo.setAppSecret(appSecret);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int updateApplication(ApplicationDTO applicationDTO) {
|
||||
// 构建应用对象
|
||||
Application application = buildApplication(applicationDTO);
|
||||
application.setAppId(applicationDTO.getAppId());
|
||||
|
||||
// 更新应用
|
||||
int result = applicationMapper.updateById(application);
|
||||
if (result <= 0) {
|
||||
throw new ServiceException("修改应用失败");
|
||||
}
|
||||
|
||||
// 更新接口授权
|
||||
appApiMapper.deleteByAppId(application.getAppId());
|
||||
saveAppApis(application.getAppId(), applicationDTO.getApiIds());
|
||||
|
||||
log.info("修改应用成功, appId={}, appName={}", application.getAppId(), application.getAppName());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int updateApplication(ApplicationDTO dto) {
|
||||
if (dto.getAppId() == null) {
|
||||
throw new ServiceException("应用ID不能为空");
|
||||
}
|
||||
Application existApp = applicationMapper.selectById(dto.getAppId());
|
||||
if (existApp == null) {
|
||||
throw new ServiceException("应用不存在");
|
||||
}
|
||||
if (applicationMapper.checkAppNameExists(dto.getAppName(), dto.getAppId()) > 0) {
|
||||
throw new ServiceException("应用名称已存在");
|
||||
}
|
||||
Application app = new Application();
|
||||
app.setAppId(dto.getAppId());
|
||||
app.setAppName(dto.getAppName());
|
||||
app.setAppDesc(dto.getAppDesc());
|
||||
app.setContactPerson(dto.getContactPerson());
|
||||
app.setContactPhone(dto.getContactPhone());
|
||||
app.setStatus(dto.getStatus());
|
||||
app.setUpdateBy("admin");
|
||||
app.setUpdateTime(DateUtils.getNowDate());
|
||||
int rows = applicationMapper.updateById(app);
|
||||
appApiMapper.deleteByAppId(dto.getAppId());
|
||||
saveAppApis(dto.getAppId(), dto.getApiCodes());
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int deleteApplicationById(Long appId) {
|
||||
Application app = applicationMapper.selectById(appId);
|
||||
if (app == null) {
|
||||
throw new ServiceException("应用不存在");
|
||||
}
|
||||
int rows = applicationMapper.deleteById(appId);
|
||||
public int deleteApplication(Long appId) {
|
||||
// 软删除应用
|
||||
Application application = new Application();
|
||||
application.setAppId(appId);
|
||||
application.setDelFlag("1");
|
||||
int result = applicationMapper.updateById(application);
|
||||
|
||||
// 删除接口授权
|
||||
appApiMapper.deleteByAppId(appId);
|
||||
return rows;
|
||||
|
||||
log.info("删除应用成功, appId={}", appId);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String resetAppSecret(Long appId) {
|
||||
Application app = applicationMapper.selectById(appId);
|
||||
if (app == null) {
|
||||
throw new ServiceException("应用不存在");
|
||||
}
|
||||
public String resetSecret(Long appId) {
|
||||
// 生成新密钥
|
||||
String newSecret = generateAppSecret();
|
||||
Application updateApp = new Application();
|
||||
updateApp.setAppId(appId);
|
||||
updateApp.setAppSecret(newSecret);
|
||||
updateApp.setUpdateBy("admin");
|
||||
updateApp.setUpdateTime(DateUtils.getNowDate());
|
||||
applicationMapper.updateById(updateApp);
|
||||
|
||||
// 更新密钥
|
||||
Application application = new Application();
|
||||
application.setAppId(appId);
|
||||
application.setAppSecret(newSecret);
|
||||
int result = applicationMapper.updateById(application);
|
||||
|
||||
if (result <= 0) {
|
||||
throw new ServiceException("重置密钥失败");
|
||||
}
|
||||
|
||||
log.info("重置应用密钥成功, appId={}", appId);
|
||||
return newSecret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ApiDict> selectApiDictList() {
|
||||
return apiDictMapper.selectEnabledList();
|
||||
public List<ApiDict> getApiList() {
|
||||
LambdaQueryWrapper<ApiDict> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(ApiDict::getStatus, "0");
|
||||
wrapper.orderByAsc(ApiDict::getSortOrder);
|
||||
return apiDictMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Application selectByAppCode(String appCode) {
|
||||
return applicationMapper.selectByAppCode(appCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkApiPermission(String appCode, String apiPath) {
|
||||
List<String> paths = appApiMapper.selectApiPathsByAppCode(appCode);
|
||||
return paths != null && paths.contains(apiPath);
|
||||
public boolean checkAppCodeUnique(String appCode, Long appId) {
|
||||
int count = applicationMapper.countByAppCode(appCode, appId);
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成应用编码
|
||||
* 格式:YY + 6位序号
|
||||
*/
|
||||
private String generateAppCode() {
|
||||
String maxCode = applicationMapper.selectMaxAppCode();
|
||||
int nextSeq = 1;
|
||||
if (maxCode != null && maxCode.length() > 2) {
|
||||
try {
|
||||
nextSeq = Integer.parseInt(maxCode.substring(2)) + 1;
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
return String.format("YY%06d", nextSeq);
|
||||
int seq = applicationMapper.getNextCodeSeq();
|
||||
return String.format("YY%06d", seq);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成应用密钥
|
||||
* 32位随机字符串
|
||||
*/
|
||||
private String generateAppSecret() {
|
||||
return RandomUtil.randomString(32);
|
||||
}
|
||||
|
||||
private void saveAppApis(Long appId, List<String> apiCodes) {
|
||||
if (CollUtil.isEmpty(apiCodes)) {
|
||||
return;
|
||||
}
|
||||
List<ApiDict> apiDicts = apiDictMapper.selectByCodes(apiCodes);
|
||||
Map<String, ApiDict> dictMap = apiDicts.stream().collect(Collectors.toMap(ApiDict::getApiCode, d -> d));
|
||||
String username = "admin";
|
||||
java.util.Date now = DateUtils.getNowDate();
|
||||
for (String apiCode : apiCodes) {
|
||||
ApiDict dict = dictMap.get(apiCode);
|
||||
if (dict != null) {
|
||||
AppApi appApi = new AppApi();
|
||||
appApi.setAppId(appId);
|
||||
appApi.setApiCode(apiCode);
|
||||
appApi.setApiName(dict.getApiName());
|
||||
appApi.setApiPath(dict.getApiPath());
|
||||
appApi.setCreateBy(username);
|
||||
appApi.setCreateTime(now);
|
||||
appApiMapper.insert(appApi);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 构建应用对象
|
||||
*/
|
||||
private Application buildApplication(ApplicationDTO dto) {
|
||||
Application application = new Application();
|
||||
application.setAppName(dto.getAppName());
|
||||
application.setContactPerson(dto.getContactPerson());
|
||||
application.setContactPhone(dto.getContactPhone());
|
||||
application.setRemark(dto.getRemark());
|
||||
return application;
|
||||
}
|
||||
|
||||
private ApplicationVO toVO(Application app) {
|
||||
ApplicationVO vo = new ApplicationVO();
|
||||
vo.setAppId(app.getAppId());
|
||||
vo.setAppCode(app.getAppCode());
|
||||
vo.setAppName(app.getAppName());
|
||||
vo.setAppDesc(app.getAppDesc());
|
||||
vo.setContactPerson(app.getContactPerson());
|
||||
vo.setContactPhone(app.getContactPhone());
|
||||
vo.setStatus(app.getStatus());
|
||||
vo.setCreateBy(app.getCreateBy());
|
||||
vo.setCreateTime(app.getCreateTime());
|
||||
List<AppApi> appApis = appApiMapper.selectByAppId(app.getAppId());
|
||||
if (CollUtil.isNotEmpty(appApis)) {
|
||||
List<ApplicationVO.ApiInfo> apis = appApis.stream().map(api -> {
|
||||
ApplicationVO.ApiInfo info = new ApplicationVO.ApiInfo();
|
||||
info.setApiCode(api.getApiCode());
|
||||
info.setApiName(api.getApiName());
|
||||
info.setApiPath(api.getApiPath());
|
||||
return info;
|
||||
}).collect(Collectors.toList());
|
||||
vo.setApis(apis);
|
||||
/**
|
||||
* 保存接口授权
|
||||
*/
|
||||
private void saveAppApis(Long appId, List<Long> apiIds) {
|
||||
if (apiIds == null || apiIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
return vo;
|
||||
|
||||
List<AppApi> list = new ArrayList<>();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
for (Long apiId : apiIds) {
|
||||
AppApi appApi = new AppApi();
|
||||
appApi.setAppId(appId);
|
||||
appApi.setApiId(apiId);
|
||||
appApi.setCreateTime(now);
|
||||
list.add(appApi);
|
||||
}
|
||||
|
||||
appApiMapper.batchInsert(list);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,4 +44,11 @@ public interface IRegionService {
|
|||
* 是否存在子区域
|
||||
*/
|
||||
boolean hasChildRegion(Long regionId);
|
||||
|
||||
/**
|
||||
* 根据区域路径查询区域ID
|
||||
* @param regionPath 区域路径(如:湖北省-武汉市-武昌区)
|
||||
* @return 区域ID
|
||||
*/
|
||||
Long getRegionIdByPath(String regionPath);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,4 +127,29 @@ public class RegionServiceImpl implements IRegionService {
|
|||
int count = regionMapper.countChildByParentId(regionId);
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getRegionIdByPath(String regionPath) {
|
||||
if (StringUtils.isEmpty(regionPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 解析区域路径:湖北省-武汉市-武昌区
|
||||
String[] parts = regionPath.split("-");
|
||||
if (parts.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 从最后一级开始查询(区 -> 市 -> 省)
|
||||
String regionName = parts[parts.length - 1];
|
||||
List<Region> regions = regionMapper.selectRegionList(new Region());
|
||||
|
||||
for (Region region : regions) {
|
||||
if (regionName.equals(region.getRegionName())) {
|
||||
return region.getRegionId();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,4 +106,11 @@ public interface IMemberService extends IService<Member> {
|
|||
* @return 会员信息
|
||||
*/
|
||||
Member getMemberByOpenId(String openId);
|
||||
|
||||
/**
|
||||
* 根据手机号查询或创建会员
|
||||
* @param phone 手机号
|
||||
* @return 会员ID
|
||||
*/
|
||||
Long getOrCreateMemberByPhone(String phone);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
|
|||
|
||||
private final MemberMapper memberMapper;
|
||||
private final BCryptPasswordEncoder passwordEncoder;
|
||||
private final com.pangu.student.service.IStudentService studentService;
|
||||
|
||||
/** 默认密码 */
|
||||
private static final String DEFAULT_PASSWORD = "123456";
|
||||
|
|
@ -68,8 +69,9 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
|
|||
// 填充名称
|
||||
fillMemberVONames(memberVO);
|
||||
|
||||
// 查询绑定的学生(暂时返回空列表,等学生模块完成后再实现)
|
||||
memberVO.setStudents(new ArrayList<>());
|
||||
// 查询绑定的学生
|
||||
List<com.pangu.student.domain.vo.StudentVO> students = studentService.selectStudentVOsByMemberId(memberId);
|
||||
memberVO.setStudents(students);
|
||||
|
||||
return memberVO;
|
||||
}
|
||||
|
|
@ -194,24 +196,26 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
|
|||
throw new ServiceException("会员不存在");
|
||||
}
|
||||
|
||||
// TODO: 教师只能绑定本校学生(等学生模块完成后实现)
|
||||
// if (IdentityTypeEnum.isTeacher(member.getIdentityType())) {
|
||||
// if (!studentService.isStudentInSchool(studentId, member.getSchoolId())) {
|
||||
// throw new ServiceException("教师只能绑定本校学生");
|
||||
// }
|
||||
// }
|
||||
// 教师只能绑定本校学生
|
||||
if (IdentityTypeEnum.isTeacher(member.getIdentityType())) {
|
||||
if (!studentService.isStudentInSchool(studentId, member.getSchoolId())) {
|
||||
throw new ServiceException("教师只能绑定本校学生");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 调用学生模块的接口更新学生的memberId(等学生模块完成后实现)
|
||||
// 更新学生的memberId
|
||||
int result = studentService.updateStudentMember(studentId, memberId);
|
||||
log.info("绑定学生成功, memberId={}, studentId={}", memberId, studentId);
|
||||
return 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int unbindStudent(Long memberId, Long studentId) {
|
||||
// TODO: 调用学生模块的接口解绑(等学生模块完成后实现)
|
||||
// 解绑学生
|
||||
int result = studentService.unbindStudent(studentId);
|
||||
log.info("解绑学生成功, memberId={}, studentId={}", memberId, studentId);
|
||||
return 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -221,9 +225,8 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
|
|||
|
||||
@Override
|
||||
public boolean checkCanDelete(Long memberId) {
|
||||
// TODO: 检查是否有绑定的学生(等学生模块完成后实现)
|
||||
// return studentService.countByMemberId(memberId) == 0;
|
||||
return true;
|
||||
// 检查是否有绑定的学生
|
||||
return studentService.countByMemberId(memberId) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -312,4 +315,30 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
|
|||
default -> "未知";
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long getOrCreateMemberByPhone(String phone) {
|
||||
// 先查询是否存在
|
||||
Member existMember = getMemberByPhone(phone);
|
||||
if (existMember != null) {
|
||||
return existMember.getMemberId();
|
||||
}
|
||||
|
||||
// 不存在则创建
|
||||
Member newMember = new Member();
|
||||
newMember.setMemberCode(generateMemberCode());
|
||||
newMember.setPhone(phone);
|
||||
newMember.setNickname(generateNickname(phone));
|
||||
newMember.setPassword(passwordEncoder.encode(DEFAULT_PASSWORD));
|
||||
newMember.setIdentityType(IdentityTypeEnum.PARENT.getCode());
|
||||
newMember.setRegisterSource(RegisterSourceEnum.BACKEND.getCode());
|
||||
newMember.setStatus("0");
|
||||
newMember.setCreateTime(LocalDateTime.now());
|
||||
|
||||
memberMapper.insert(newMember);
|
||||
log.info("批量导入自动创建会员, memberId={}, phone={}", newMember.getMemberId(), phone);
|
||||
|
||||
return newMember.getMemberId();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,4 +85,28 @@ public interface ISchoolService {
|
|||
* @return 影响行数
|
||||
*/
|
||||
int deleteSchoolClass(Long schoolClassId);
|
||||
|
||||
/**
|
||||
* 根据学校名称和区域ID查询学校ID
|
||||
* @param schoolName 学校名称
|
||||
* @param regionId 区域ID
|
||||
* @return 学校ID
|
||||
*/
|
||||
Long getSchoolIdByName(String schoolName, Long regionId);
|
||||
|
||||
/**
|
||||
* 根据学校ID和年级名称查询学校年级ID
|
||||
* @param schoolId 学校ID
|
||||
* @param gradeName 年级名称
|
||||
* @return 学校年级关联ID
|
||||
*/
|
||||
Long getSchoolGradeId(Long schoolId, String gradeName);
|
||||
|
||||
/**
|
||||
* 根据学校年级ID和班级名称查询学校班级ID
|
||||
* @param schoolGradeId 学校年级ID
|
||||
* @param className 班级名称
|
||||
* @return 学校班级关联ID
|
||||
*/
|
||||
Long getSchoolClassId(Long schoolGradeId, String className);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,4 +313,35 @@ public class SchoolServiceImpl implements ISchoolService {
|
|||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getSchoolIdByName(String schoolName, Long regionId) {
|
||||
SchoolQueryDTO query = new SchoolQueryDTO();
|
||||
query.setSchoolName(schoolName);
|
||||
query.setRegionId(regionId);
|
||||
List<SchoolVO> schools = schoolMapper.selectSchoolList(query);
|
||||
return schools.isEmpty() ? null : schools.get(0).getSchoolId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getSchoolGradeId(Long schoolId, String gradeName) {
|
||||
List<SchoolGrade> grades = schoolGradeMapper.selectBySchoolIds(Collections.singletonList(schoolId));
|
||||
for (SchoolGrade grade : grades) {
|
||||
if (gradeName.equals(grade.getGradeName())) {
|
||||
return grade.getId();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getSchoolClassId(Long schoolGradeId, String className) {
|
||||
List<SchoolClass> classes = schoolClassMapper.selectBySchoolGradeIds(Collections.singletonList(schoolGradeId));
|
||||
for (SchoolClass clazz : classes) {
|
||||
if (className.equals(clazz.getClassName())) {
|
||||
return clazz.getId();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package com.pangu.student.controller;
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.pangu.common.core.controller.BaseController;
|
||||
import com.pangu.common.core.domain.AjaxResult;
|
||||
import com.pangu.common.core.page.TableDataInfo;
|
||||
import com.pangu.student.domain.dto.StudentDTO;
|
||||
import com.pangu.student.domain.dto.StudentImportDTO;
|
||||
import com.pangu.student.domain.vo.ImportResultVO;
|
||||
import com.pangu.student.domain.vo.StudentVO;
|
||||
import com.pangu.student.service.IStudentService;
|
||||
|
|
@ -12,6 +14,13 @@ import org.springframework.validation.annotation.Validated;
|
|||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生管理Controller
|
||||
*
|
||||
|
|
@ -78,8 +87,29 @@ public class StudentController extends BaseController {
|
|||
* 下载导入模板
|
||||
*/
|
||||
@GetMapping("/template")
|
||||
public void downloadTemplate() {
|
||||
// TODO: 实现模板下载
|
||||
public void downloadTemplate(HttpServletResponse response) throws IOException {
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
String fileName = URLEncoder.encode("学生导入模板", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
|
||||
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
|
||||
|
||||
// 创建模板数据
|
||||
List<StudentImportDTO> templateData = new ArrayList<>();
|
||||
StudentImportDTO example = new StudentImportDTO();
|
||||
example.setStudentName("张小明");
|
||||
example.setStudentNo("STU20260001");
|
||||
example.setMemberPhone("13812345678");
|
||||
example.setRegionPath("湖北省-武汉市-武昌区");
|
||||
example.setSchoolName("武汉市第一中学");
|
||||
example.setGradeName("七年级");
|
||||
example.setClassName("1班");
|
||||
example.setGender("男");
|
||||
example.setBirthday("2015-03");
|
||||
templateData.add(example);
|
||||
|
||||
EasyExcel.write(response.getOutputStream(), StudentImportDTO.class)
|
||||
.sheet("学生信息")
|
||||
.doWrite(templateData);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,11 +3,18 @@ package com.pangu.student.listener;
|
|||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.excel.context.AnalysisContext;
|
||||
import com.alibaba.excel.event.AnalysisEventListener;
|
||||
import com.pangu.base.service.IRegionService;
|
||||
import com.pangu.member.service.IMemberService;
|
||||
import com.pangu.school.service.ISchoolService;
|
||||
import com.pangu.student.domain.dto.StudentDTO;
|
||||
import com.pangu.student.domain.dto.StudentImportDTO;
|
||||
import com.pangu.student.domain.vo.ImportResultVO;
|
||||
import com.pangu.student.service.IStudentService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* 学生导入监听器
|
||||
*
|
||||
|
|
@ -17,11 +24,20 @@ import lombok.extern.slf4j.Slf4j;
|
|||
public class StudentImportListener extends AnalysisEventListener<StudentImportDTO> {
|
||||
|
||||
private final IStudentService studentService;
|
||||
private final IRegionService regionService;
|
||||
private final ISchoolService schoolService;
|
||||
private final IMemberService memberService;
|
||||
private final ImportResultVO result = new ImportResultVO();
|
||||
private int rowNum = 1; // 从第2行开始(第1行是表头)
|
||||
|
||||
public StudentImportListener(IStudentService studentService) {
|
||||
public StudentImportListener(IStudentService studentService,
|
||||
IRegionService regionService,
|
||||
ISchoolService schoolService,
|
||||
IMemberService memberService) {
|
||||
this.studentService = studentService;
|
||||
this.regionService = regionService;
|
||||
this.schoolService = schoolService;
|
||||
this.memberService = memberService;
|
||||
result.setTotal(0);
|
||||
result.setSuccessCount(0);
|
||||
result.setFailCount(0);
|
||||
|
|
@ -41,15 +57,60 @@ public class StudentImportListener extends AnalysisEventListener<StudentImportDT
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: 实际导入逻辑(需要查询区域、学校、会员等信息)
|
||||
// 这里简化处理,实际需要:
|
||||
// 1. 根据区域路径查询区域ID
|
||||
// 2. 根据学校名称查询学校ID
|
||||
// 3. 根据年级名称查询学校年级ID
|
||||
// 4. 根据班级名称查询学校班级ID
|
||||
// 5. 根据手机号查询或创建会员
|
||||
// 6. 保存学生信息
|
||||
Long regionId = regionService.getRegionIdByPath(data.getRegionPath());
|
||||
if (regionId == null) {
|
||||
addError(rowNum, data, "区域不存在:" + data.getRegionPath());
|
||||
result.setFailCount(result.getFailCount() + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 根据学校名称查询学校ID
|
||||
Long schoolId = schoolService.getSchoolIdByName(data.getSchoolName(), regionId);
|
||||
if (schoolId == null) {
|
||||
addError(rowNum, data, "学校不存在:" + data.getSchoolName());
|
||||
result.setFailCount(result.getFailCount() + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 根据年级名称查询学校年级ID
|
||||
Long schoolGradeId = schoolService.getSchoolGradeId(schoolId, data.getGradeName());
|
||||
if (schoolGradeId == null) {
|
||||
addError(rowNum, data, "年级不存在:" + data.getGradeName());
|
||||
result.setFailCount(result.getFailCount() + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. 根据班级名称查询学校班级ID
|
||||
Long schoolClassId = schoolService.getSchoolClassId(schoolGradeId, data.getClassName());
|
||||
if (schoolClassId == null) {
|
||||
addError(rowNum, data, "班级不存在:" + data.getClassName());
|
||||
result.setFailCount(result.getFailCount() + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. 根据手机号查询或创建会员
|
||||
Long memberId = memberService.getOrCreateMemberByPhone(data.getMemberPhone());
|
||||
if (memberId == null) {
|
||||
addError(rowNum, data, "会员创建失败");
|
||||
result.setFailCount(result.getFailCount() + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// 6. 保存学生信息
|
||||
StudentDTO studentDTO = new StudentDTO();
|
||||
studentDTO.setStudentName(data.getStudentName());
|
||||
studentDTO.setStudentNo(data.getStudentNo());
|
||||
studentDTO.setGender(parseGender(data.getGender()));
|
||||
studentDTO.setBirthday(parseBirthday(data.getBirthday()));
|
||||
studentDTO.setRegionId(regionId);
|
||||
studentDTO.setRegionPath(data.getRegionPath());
|
||||
studentDTO.setSchoolId(schoolId);
|
||||
studentDTO.setSchoolGradeId(schoolGradeId);
|
||||
studentDTO.setSchoolClassId(schoolClassId);
|
||||
studentDTO.setMemberId(memberId);
|
||||
|
||||
studentService.insertStudent(studentDTO);
|
||||
result.setSuccessCount(result.getSuccessCount() + 1);
|
||||
log.info("导入学生成功:{}", data.getStudentName());
|
||||
|
||||
|
|
@ -109,4 +170,34 @@ public class StudentImportListener extends AnalysisEventListener<StudentImportDT
|
|||
public ImportResultVO getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析性别
|
||||
*/
|
||||
private String parseGender(String gender) {
|
||||
if (StrUtil.isBlank(gender)) {
|
||||
return "0";
|
||||
}
|
||||
return switch (gender) {
|
||||
case "男" -> "1";
|
||||
case "女" -> "2";
|
||||
default -> "0";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析出生年月
|
||||
*/
|
||||
private LocalDate parseBirthday(String birthday) {
|
||||
if (StrUtil.isBlank(birthday)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
|
||||
return LocalDate.parse(birthday + "-01", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||
} catch (Exception e) {
|
||||
log.warn("解析出生年月失败:{}", birthday);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,4 +43,20 @@ public interface StudentMapper extends BaseMapper<Student> {
|
|||
* @return 数量
|
||||
*/
|
||||
int countByStudentNo(@Param("studentNo") String studentNo, @Param("studentId") Long studentId);
|
||||
|
||||
/**
|
||||
* 根据会员ID统计学生数量
|
||||
*
|
||||
* @param memberId 会员ID
|
||||
* @return 学生数量
|
||||
*/
|
||||
int countByMemberId(@Param("memberId") Long memberId);
|
||||
|
||||
/**
|
||||
* 根据会员ID查询学生列表
|
||||
*
|
||||
* @param memberId 会员ID
|
||||
* @return 学生列表
|
||||
*/
|
||||
List<StudentVO> selectStudentVOsByMemberId(@Param("memberId") Long memberId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,4 +71,46 @@ public interface IStudentService extends IService<Student> {
|
|||
* @return true唯一 false不唯一
|
||||
*/
|
||||
boolean checkStudentNoUnique(String studentNo, Long studentId);
|
||||
|
||||
/**
|
||||
* 检查学生是否在指定学校
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @param schoolId 学校ID
|
||||
* @return true在该学校 false不在
|
||||
*/
|
||||
boolean isStudentInSchool(Long studentId, Long schoolId);
|
||||
|
||||
/**
|
||||
* 更新学生的会员ID
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @param memberId 会员ID
|
||||
* @return 结果
|
||||
*/
|
||||
int updateStudentMember(Long studentId, Long memberId);
|
||||
|
||||
/**
|
||||
* 解绑学生(清空会员ID)
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 结果
|
||||
*/
|
||||
int unbindStudent(Long studentId);
|
||||
|
||||
/**
|
||||
* 统计会员绑定的学生数量
|
||||
*
|
||||
* @param memberId 会员ID
|
||||
* @return 学生数量
|
||||
*/
|
||||
int countByMemberId(Long memberId);
|
||||
|
||||
/**
|
||||
* 根据会员ID查询学生列表
|
||||
*
|
||||
* @param memberId 会员ID
|
||||
* @return 学生列表
|
||||
*/
|
||||
List<StudentVO> selectStudentVOsByMemberId(Long memberId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ import java.util.List;
|
|||
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements IStudentService {
|
||||
|
||||
private final StudentMapper studentMapper;
|
||||
private final com.pangu.base.service.IRegionService regionService;
|
||||
private final com.pangu.school.service.ISchoolService schoolService;
|
||||
private final com.pangu.member.service.IMemberService memberService;
|
||||
|
||||
@Override
|
||||
public TableDataInfo selectStudentList(StudentDTO studentDTO) {
|
||||
|
|
@ -99,7 +102,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> impl
|
|||
@Transactional(rollbackFor = Exception.class)
|
||||
public ImportResultVO importStudents(MultipartFile file) {
|
||||
try {
|
||||
StudentImportListener listener = new StudentImportListener(this);
|
||||
StudentImportListener listener = new StudentImportListener(this, regionService, schoolService, memberService);
|
||||
EasyExcel.read(file.getInputStream(), StudentImportDTO.class, listener).sheet().doRead();
|
||||
return listener.getResult();
|
||||
} catch (IOException e) {
|
||||
|
|
@ -114,6 +117,47 @@ public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> impl
|
|||
return count == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStudentInSchool(Long studentId, Long schoolId) {
|
||||
Student student = studentMapper.selectById(studentId);
|
||||
if (student == null || "1".equals(student.getDelFlag())) {
|
||||
return false;
|
||||
}
|
||||
return student.getSchoolId().equals(schoolId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int updateStudentMember(Long studentId, Long memberId) {
|
||||
Student student = new Student();
|
||||
student.setStudentId(studentId);
|
||||
student.setMemberId(memberId);
|
||||
int result = studentMapper.updateById(student);
|
||||
log.info("更新学生会员关联成功, studentId={}, memberId={}", studentId, memberId);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int unbindStudent(Long studentId) {
|
||||
Student student = new Student();
|
||||
student.setStudentId(studentId);
|
||||
student.setMemberId(null);
|
||||
int result = studentMapper.updateById(student);
|
||||
log.info("解绑学生成功, studentId={}", studentId);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countByMemberId(Long memberId) {
|
||||
return studentMapper.countByMemberId(memberId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StudentVO> selectStudentVOsByMemberId(Long memberId) {
|
||||
return studentMapper.selectStudentVOsByMemberId(memberId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建学生对象
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.pangu.application.mapper.AppApiMapper">
|
||||
|
||||
<!-- 批量插入应用接口授权 -->
|
||||
<insert id="batchInsert">
|
||||
INSERT INTO pg_app_api (app_id, api_id, create_time)
|
||||
VALUES
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.appId}, #{item.apiId}, #{item.createTime})
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<!-- 根据应用ID删除授权 -->
|
||||
<delete id="deleteByAppId">
|
||||
DELETE FROM pg_app_api WHERE app_id = #{appId}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.pangu.application.mapper.ApplicationMapper">
|
||||
|
||||
<!-- 应用VO结果映射 -->
|
||||
<resultMap id="ApplicationVOResult" type="com.pangu.application.domain.vo.ApplicationVO">
|
||||
<id property="appId" column="app_id"/>
|
||||
<result property="appCode" column="app_code"/>
|
||||
<result property="appName" column="app_name"/>
|
||||
<result property="appSecret" column="app_secret"/>
|
||||
<result property="contactPerson" column="contact_person"/>
|
||||
<result property="contactPhone" column="contact_phone"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<collection property="apiList" ofType="com.pangu.application.domain.vo.ApplicationVO$ApiVO">
|
||||
<id property="apiId" column="api_id"/>
|
||||
<result property="apiCode" column="api_code"/>
|
||||
<result property="apiName" column="api_name"/>
|
||||
<result property="apiPath" column="api_path"/>
|
||||
<result property="apiMethod" column="api_method"/>
|
||||
</collection>
|
||||
</resultMap>
|
||||
|
||||
<!-- 查询应用列表 -->
|
||||
<select id="selectApplicationVOList" resultMap="ApplicationVOResult">
|
||||
SELECT DISTINCT
|
||||
a.app_id,
|
||||
a.app_code,
|
||||
a.app_name,
|
||||
a.app_secret,
|
||||
a.contact_person,
|
||||
a.contact_phone,
|
||||
a.status,
|
||||
a.create_time,
|
||||
a.remark,
|
||||
api.api_id,
|
||||
api.api_code,
|
||||
api.api_name,
|
||||
api.api_path,
|
||||
api.api_method
|
||||
FROM pg_application a
|
||||
LEFT JOIN pg_app_api aa ON a.app_id = aa.app_id
|
||||
LEFT JOIN pg_api_dict api ON aa.api_id = api.api_id AND api.status = '0'
|
||||
WHERE a.del_flag = '0'
|
||||
<if test="dto.appName != null and dto.appName != ''">
|
||||
AND a.app_name LIKE CONCAT('%', #{dto.appName}, '%')
|
||||
</if>
|
||||
<if test="dto.appCode != null and dto.appCode != ''">
|
||||
AND a.app_code = #{dto.appCode}
|
||||
</if>
|
||||
<if test="dto.status != null and dto.status != ''">
|
||||
AND a.status = #{dto.status}
|
||||
</if>
|
||||
<if test="dto.beginTime != null and dto.beginTime != ''">
|
||||
AND DATE_FORMAT(a.create_time,'%Y-%m-%d') >= #{dto.beginTime}
|
||||
</if>
|
||||
<if test="dto.endTime != null and dto.endTime != ''">
|
||||
AND DATE_FORMAT(a.create_time,'%Y-%m-%d') <= #{dto.endTime}
|
||||
</if>
|
||||
ORDER BY a.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据ID查询应用详情 -->
|
||||
<select id="selectApplicationVOById" resultMap="ApplicationVOResult">
|
||||
SELECT
|
||||
a.app_id,
|
||||
a.app_code,
|
||||
a.app_name,
|
||||
a.app_secret,
|
||||
a.contact_person,
|
||||
a.contact_phone,
|
||||
a.status,
|
||||
a.create_time,
|
||||
a.remark,
|
||||
api.api_id,
|
||||
api.api_code,
|
||||
api.api_name,
|
||||
api.api_path,
|
||||
api.api_method
|
||||
FROM pg_application a
|
||||
LEFT JOIN pg_app_api aa ON a.app_id = aa.app_id
|
||||
LEFT JOIN pg_api_dict api ON aa.api_id = api.api_id AND api.status = '0'
|
||||
WHERE a.app_id = #{appId} AND a.del_flag = '0'
|
||||
</select>
|
||||
|
||||
<!-- 检查应用编码是否唯一 -->
|
||||
<select id="countByAppCode" resultType="int">
|
||||
SELECT COUNT(1)
|
||||
FROM pg_application
|
||||
WHERE app_code = #{appCode}
|
||||
AND del_flag = '0'
|
||||
<if test="appId != null">
|
||||
AND app_id != #{appId}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<!-- 获取下一个应用编码序号 -->
|
||||
<select id="getNextCodeSeq" resultType="int">
|
||||
SELECT COALESCE(MAX(CAST(SUBSTRING(app_code, 3) AS UNSIGNED)), 0) + 1
|
||||
FROM pg_application
|
||||
WHERE app_code LIKE 'YY%'
|
||||
AND del_flag = '0'
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
@ -152,4 +152,47 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
</if>
|
||||
</select>
|
||||
|
||||
<!-- 根据会员ID统计学生数量 -->
|
||||
<select id="countByMemberId" resultType="int">
|
||||
SELECT COUNT(1)
|
||||
FROM pg_student
|
||||
WHERE member_id = #{memberId}
|
||||
AND del_flag = '0'
|
||||
</select>
|
||||
|
||||
<!-- 根据会员ID查询学生列表 -->
|
||||
<select id="selectStudentVOsByMemberId" resultMap="StudentVOResult">
|
||||
SELECT
|
||||
s.student_id,
|
||||
s.student_name,
|
||||
s.student_no,
|
||||
s.gender,
|
||||
CASE s.gender
|
||||
WHEN '1' THEN '男'
|
||||
WHEN '2' THEN '女'
|
||||
ELSE '未知'
|
||||
END AS gender_name,
|
||||
s.birthday,
|
||||
s.region_id,
|
||||
s.region_path,
|
||||
s.school_id,
|
||||
sch.school_name,
|
||||
s.school_grade_id,
|
||||
g.grade_name,
|
||||
s.school_class_id,
|
||||
c.class_name,
|
||||
s.subject_id,
|
||||
sub.subject_name,
|
||||
s.create_time
|
||||
FROM pg_student s
|
||||
LEFT JOIN pg_school sch ON s.school_id = sch.school_id AND sch.del_flag = '0'
|
||||
LEFT JOIN pg_school_grade sg ON s.school_grade_id = sg.id AND sg.del_flag = '0'
|
||||
LEFT JOIN pg_grade g ON sg.grade_id = g.grade_id AND g.del_flag = '0'
|
||||
LEFT JOIN pg_school_class sc ON s.school_class_id = sc.id AND sc.del_flag = '0'
|
||||
LEFT JOIN pg_class c ON sc.class_id = c.class_id AND c.del_flag = '0'
|
||||
LEFT JOIN pg_subject sub ON s.subject_id = sub.subject_id AND sub.del_flag = '0'
|
||||
WHERE s.member_id = #{memberId} AND s.del_flag = '0'
|
||||
ORDER BY s.create_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
-- ============================================================
|
||||
-- 盘古用户平台 - 应用管理模块表结构及初始数据
|
||||
-- 作者:湖北新华业务中台研发团队
|
||||
-- 说明:执行前请确认已存在 sys_menu,菜单已在 pangu_menu.sql 中
|
||||
-- 应用管理模块 - 数据库脚本
|
||||
-- 作者:pangu
|
||||
-- 创建时间:2026-01-31
|
||||
-- ============================================================
|
||||
|
||||
-- ----------------------------
|
||||
-- 应用表
|
||||
CREATE TABLE IF NOT EXISTS `pg_application` (
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `pg_application`;
|
||||
CREATE TABLE `pg_application` (
|
||||
`app_id` bigint NOT NULL AUTO_INCREMENT COMMENT '应用ID',
|
||||
`app_code` varchar(32) NOT NULL COMMENT '应用编码',
|
||||
`app_name` varchar(100) NOT NULL COMMENT '应用名称',
|
||||
`app_secret` varchar(64) NOT NULL COMMENT '应用密钥',
|
||||
`app_desc` varchar(500) DEFAULT NULL COMMENT '应用描述',
|
||||
`contact_person` varchar(50) DEFAULT NULL COMMENT '联系人',
|
||||
`contact_phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||
|
|
@ -21,47 +23,67 @@ CREATE TABLE IF NOT EXISTS `pg_application` (
|
|||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0存在 1删除)',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`app_id`),
|
||||
UNIQUE KEY `uk_app_code` (`app_code`),
|
||||
UNIQUE KEY `uk_app_name` (`app_name`, `del_flag`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='应用表';
|
||||
|
||||
-- 应用接口授权表(记录应用被授予的可调用接口)
|
||||
CREATE TABLE IF NOT EXISTS `pg_app_grant` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`app_id` bigint NOT NULL COMMENT '应用ID',
|
||||
`api_code` varchar(100) NOT NULL COMMENT '接口编码',
|
||||
`api_name` varchar(100) DEFAULT NULL COMMENT '接口名称',
|
||||
`api_path` varchar(200) NOT NULL COMMENT '接口路径',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_app_api` (`app_id`, `api_code`),
|
||||
KEY `idx_app_id` (`app_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='应用接口授权表';
|
||||
UNIQUE KEY `uk_app_code` (`app_code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表';
|
||||
|
||||
-- ----------------------------
|
||||
-- API接口字典表
|
||||
CREATE TABLE IF NOT EXISTS `pg_api_dict` (
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `pg_api_dict`;
|
||||
CREATE TABLE `pg_api_dict` (
|
||||
`api_id` bigint NOT NULL AUTO_INCREMENT COMMENT '接口ID',
|
||||
`api_code` varchar(100) NOT NULL COMMENT '接口编码',
|
||||
`api_code` varchar(50) NOT NULL COMMENT '接口编码',
|
||||
`api_name` varchar(100) NOT NULL COMMENT '接口名称',
|
||||
`api_path` varchar(200) NOT NULL COMMENT '接口路径',
|
||||
`api_method` varchar(10) DEFAULT 'GET' COMMENT '请求方法',
|
||||
`api_desc` varchar(500) DEFAULT NULL COMMENT '接口描述',
|
||||
`order_num` int DEFAULT 0 COMMENT '显示顺序',
|
||||
`api_method` varchar(10) NOT NULL COMMENT '请求方法',
|
||||
`sort_order` int DEFAULT 0 COMMENT '排序',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`api_id`),
|
||||
UNIQUE KEY `uk_api_code` (`api_code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='API接口字典表';
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='API接口字典表';
|
||||
|
||||
-- API接口字典初始数据
|
||||
INSERT INTO pg_api_dict (api_code, api_name, api_path, api_method, api_desc, order_num, status) VALUES
|
||||
('STUDENT_LIST', '查询学生信息', '/open/student/list', 'GET', '获取学生列表', 1, '0'),
|
||||
('SCHOOL_LIST', '查询学校信息', '/open/school/list', 'GET', '获取学校列表', 2, '0'),
|
||||
('GRADE_LIST', '查询年级信息', '/open/grade/list', 'GET', '获取年级列表', 3, '0'),
|
||||
('CLASS_LIST', '查询班级信息', '/open/class/list', 'GET', '获取班级列表', 4, '0'),
|
||||
('MEMBER_LIST', '查询会员信息', '/open/member/list', 'GET', '获取会员列表', 5, '0'),
|
||||
('REGION_TREE', '查询区域树', '/open/region/tree', 'GET', '获取区域树形结构', 6, '0');
|
||||
-- ----------------------------
|
||||
-- 应用接口授权表
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `pg_app_api`;
|
||||
CREATE TABLE `pg_app_api` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`app_id` bigint NOT NULL COMMENT '应用ID',
|
||||
`api_id` bigint NOT NULL COMMENT '接口ID',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_app_api` (`app_id`, `api_id`),
|
||||
KEY `idx_app_id` (`app_id`),
|
||||
KEY `idx_api_id` (`api_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用接口授权表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化API接口字典数据
|
||||
-- ----------------------------
|
||||
INSERT INTO pg_api_dict (api_code, api_name, api_path, api_method, sort_order, status, create_time) VALUES
|
||||
('api_member_info', '获取会员信息', '/open/api/member/info', 'GET', 1, '0', NOW()),
|
||||
('api_member_list', '获取会员列表', '/open/api/member/list', 'GET', 2, '0', NOW()),
|
||||
('api_student_info', '获取学生信息', '/open/api/student/info', 'GET', 3, '0', NOW()),
|
||||
('api_student_list', '获取学生列表', '/open/api/student/list', 'GET', 4, '0', NOW()),
|
||||
('api_school_info', '获取学校信息', '/open/api/school/info', 'GET', 5, '0', NOW()),
|
||||
('api_school_list', '获取学校列表', '/open/api/school/list', 'GET', 6, '0', NOW());
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化应用示例数据
|
||||
-- ----------------------------
|
||||
INSERT INTO pg_application (app_code, app_name, app_secret, contact_person, contact_phone, status, create_by, create_time, del_flag) VALUES
|
||||
('YY000001', 'AI智慧平台', 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6', '张三', '13800138000', '0', 'admin', NOW(), '0'),
|
||||
('YY000002', '测试应用', 'p6o5n4m3l2k1j0i9h8g7f6e5d4c3b2a1', '李四', '13900139000', '0', 'admin', NOW(), '0');
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化应用接口授权数据
|
||||
-- ----------------------------
|
||||
INSERT INTO pg_app_api (app_id, api_id, create_time) VALUES
|
||||
(1, 1, NOW()),
|
||||
(1, 2, NOW()),
|
||||
(1, 3, NOW()),
|
||||
(1, 4, NOW()),
|
||||
(2, 1, NOW()),
|
||||
(2, 3, NOW());
|
||||
|
|
|
|||
Loading…
Reference in New Issue