feat: H5教育身份接口增加省市区信息返回

- 修改 H5EducationVo 添加省市区字段
- 修改 H5MemberServiceImpl 的 buildEducationVo 方法,从学校的regionId解析省市区信息
- 保存教育身份时自动从学校获取regionId保存到会员表
- 添加日志记录省市区信息便于调试
- 更新 pangu-project.mdc 文档,添加 build.sh 工具使用说明
- 优化管理后台会员和学生相关组件
This commit is contained in:
神码-方晓辉 2026-02-03 11:53:55 +08:00
parent e35b4098e6
commit f0d8a6c571
6 changed files with 121 additions and 7 deletions

View File

@ -221,6 +221,46 @@ return dataInfo;
} }
``` ```
## 构建工具build.sh
后端项目提供了快速编译打包脚本,位于 `backend/build.sh`,支持多种编译模式。
### 常用命令
| 命令 | 说明 | 耗时 |
|------|------|------|
| `./build.sh -q` | 快速编译,仅检查语法错误 | ~4秒 |
| `./build.sh -p` | 增量打包(默认) | ~4秒 |
| `./build.sh -f` | 全量编译clean + package | ~30秒 |
| `./build.sh -m pangu-business` | 仅编译业务模块 | 更快 |
| `./build.sh -r` | 增量打包并重启后端 | ~27秒 |
| `./build.sh -m pangu-business -r` | 编译业务模块并重启 | ~27秒 |
| `./build.sh -c` | 仅清理 target 目录 | - |
| `./build.sh -h` | 显示帮助信息 | - |
### 开发建议
1. **日常开发**:修改代码后用 `-q` 快速检查语法错误
2. **本地测试**:用 `-r` 编译并重启服务
3. **仅改某模块**:用 `-m` 指定模块,加快编译速度
4. **部署前**:用 `-f` 全量编译确保干净
### 示例
```bash
# 进入后端目录
cd backend
# 快速检查语法
./build.sh -q
# 修改 pangu-business 模块后编译并重启
./build.sh -m pangu-business -r
# 全量编译
./build.sh -f
```
## 业务模块 ## 业务模块
| 模块 | 路径 | 说明 | | 模块 | 路径 | 说明 |

View File

@ -114,11 +114,16 @@ public class H5BaseDataController {
content = @Content(schema = @Schema(implementation = List.class))) content = @Content(schema = @Schema(implementation = List.class)))
}) })
@Parameters({ @Parameters({
@Parameter(name = "regionId", description = "区域ID", required = true, in = ParameterIn.QUERY, @Parameter(name = "regionId", description = "区域ID(不传则返回空列表)", required = false, in = ParameterIn.QUERY,
schema = @Schema(type = "integer", format = "int64"), example = "420100") schema = @Schema(type = "integer", format = "int64"), example = "420100")
}) })
@GetMapping("/schools") @GetMapping("/schools")
public R<List<Map<String, Object>>> getSchools(@RequestParam Long regionId) { public R<List<Map<String, Object>>> getSchools(@RequestParam(required = false) Long regionId) {
// 如果没传regionId返回空列表
if (regionId == null) {
return R.ok(new ArrayList<>());
}
List<PgSchool> schools = schoolMapper.selectList( List<PgSchool> schools = schoolMapper.selectList(
new LambdaQueryWrapper<PgSchool>() new LambdaQueryWrapper<PgSchool>()
.eq(PgSchool::getRegionId, regionId) .eq(PgSchool::getRegionId, regionId)

View File

@ -12,6 +12,24 @@ import lombok.Data;
@Schema(description = "教育身份信息(教师)") @Schema(description = "教育身份信息(教师)")
public class H5EducationVo { public class H5EducationVo {
@Schema(description = "省份ID", example = "420000")
private Long provinceId;
@Schema(description = "省份名称", example = "湖北省")
private String provinceName;
@Schema(description = "城市ID", example = "420100")
private Long cityId;
@Schema(description = "城市名称", example = "武汉市")
private String cityName;
@Schema(description = "区县ID", example = "420102")
private Long districtId;
@Schema(description = "区县名称", example = "江岸区")
private String districtName;
@Schema(description = "学校ID", example = "1") @Schema(description = "学校ID", example = "1")
private Long schoolId; private Long schoolId;

View File

@ -10,9 +10,11 @@ import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.pangu.base.domain.PgClass; import org.dromara.pangu.base.domain.PgClass;
import org.dromara.pangu.base.domain.PgGrade; import org.dromara.pangu.base.domain.PgGrade;
import org.dromara.pangu.base.domain.PgRegion;
import org.dromara.pangu.base.domain.PgSubject; import org.dromara.pangu.base.domain.PgSubject;
import org.dromara.pangu.base.mapper.PgClassMapper; import org.dromara.pangu.base.mapper.PgClassMapper;
import org.dromara.pangu.base.mapper.PgGradeMapper; import org.dromara.pangu.base.mapper.PgGradeMapper;
import org.dromara.pangu.base.mapper.PgRegionMapper;
import org.dromara.pangu.base.mapper.PgSubjectMapper; import org.dromara.pangu.base.mapper.PgSubjectMapper;
import org.dromara.pangu.h5.domain.dto.H5EducationDto; import org.dromara.pangu.h5.domain.dto.H5EducationDto;
import org.dromara.pangu.h5.domain.dto.H5MemberUpdateDto; import org.dromara.pangu.h5.domain.dto.H5MemberUpdateDto;
@ -56,6 +58,7 @@ public class H5MemberServiceImpl implements H5MemberService {
private final PgGradeMapper gradeMapper; private final PgGradeMapper gradeMapper;
private final PgClassMapper classMapper; private final PgClassMapper classMapper;
private final PgSubjectMapper subjectMapper; private final PgSubjectMapper subjectMapper;
private final PgRegionMapper regionMapper;
@Override @Override
public H5MemberInfoVo getMemberInfo() { public H5MemberInfoVo getMemberInfo() {
@ -169,6 +172,10 @@ public class H5MemberServiceImpl implements H5MemberService {
member.setSchoolId(dto.getSchoolId()); member.setSchoolId(dto.getSchoolId());
member.setSchoolGradeId(dto.getSchoolGradeId()); member.setSchoolGradeId(dto.getSchoolGradeId());
member.setSchoolClassId(dto.getSchoolClassId()); member.setSchoolClassId(dto.getSchoolClassId());
// 从学校获取区域信息并保存
if (school.getRegionId() != null) {
member.setRegionId(school.getRegionId());
}
// 学科信息需要在member表添加字段这里先用remark暂存 // 学科信息需要在member表添加字段这里先用remark暂存
member.setRemark("subjectId:" + dto.getSubjectId()); member.setRemark("subjectId:" + dto.getSubjectId());
memberMapper.updateById(member); memberMapper.updateById(member);
@ -188,7 +195,10 @@ public class H5MemberServiceImpl implements H5MemberService {
return null; return null;
} }
return buildEducationVo(member); H5EducationVo vo = buildEducationVo(member);
log.info("H5获取教育身份: memberId={}, provinceId={}, cityId={}, districtId={}, schoolId={}",
memberId, vo.getProvinceId(), vo.getCityId(), vo.getDistrictId(), vo.getSchoolId());
return vo;
} }
@Override @Override
@ -344,10 +354,51 @@ public class H5MemberServiceImpl implements H5MemberService {
vo.setSchoolGradeId(member.getSchoolGradeId()); vo.setSchoolGradeId(member.getSchoolGradeId());
vo.setSchoolClassId(member.getSchoolClassId()); vo.setSchoolClassId(member.getSchoolClassId());
// 获取学校名称 // 获取学校名称和区域信息
PgSchool school = schoolMapper.selectById(member.getSchoolId()); PgSchool school = schoolMapper.selectById(member.getSchoolId());
if (school != null) { if (school != null) {
vo.setSchoolName(school.getSchoolName()); vo.setSchoolName(school.getSchoolName());
// 根据学校的regionId获取区域信息区县级别
if (school.getRegionId() != null) {
PgRegion district = regionMapper.selectById(school.getRegionId());
if (district != null) {
vo.setDistrictId(district.getRegionId());
vo.setDistrictName(district.getRegionName());
// 根据ancestors获取省市信息格式如 "0,42,4201"
if (StringUtils.isNotBlank(district.getAncestors())) {
String[] ancestorIds = district.getAncestors().split(",");
// ancestorIds[0] = "0" (根节点)
// ancestorIds[1] = 省份ID
// ancestorIds[2] = 城市ID
if (ancestorIds.length >= 2 && !"0".equals(ancestorIds[1])) {
try {
Long provinceId = Long.parseLong(ancestorIds[1].trim());
PgRegion province = regionMapper.selectById(provinceId);
if (province != null) {
vo.setProvinceId(province.getRegionId());
vo.setProvinceName(province.getRegionName());
}
} catch (NumberFormatException e) {
log.warn("解析省份ID失败: {}", ancestorIds[1]);
}
}
if (ancestorIds.length >= 3) {
try {
Long cityId = Long.parseLong(ancestorIds[2].trim());
PgRegion city = regionMapper.selectById(cityId);
if (city != null) {
vo.setCityId(city.getRegionId());
vo.setCityName(city.getRegionName());
}
} catch (NumberFormatException e) {
log.warn("解析城市ID失败: {}", ancestorIds[2]);
}
}
}
}
}
} }
// 获取年级名称 // 获取年级名称

View File

@ -161,10 +161,10 @@
</template> </template>
<script setup> <script setup>
import request from '@/utils/request'
import { Plus } from '@element-plus/icons-vue' import { Plus } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import request from '@/utils/request'
import StudentSelectDialog from './StudentSelectDialog.vue' import StudentSelectDialog from './StudentSelectDialog.vue'
const emit = defineEmits(['success']) const emit = defineEmits(['success'])

View File

@ -81,10 +81,10 @@
</template> </template>
<script setup> <script setup>
import { Search, Refresh } from '@element-plus/icons-vue' import request from '@/utils/request'
import { Refresh, Search } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import request from '@/utils/request'
const emit = defineEmits(['success']) const emit = defineEmits(['success'])