pangu-user-platform/docs/05-模块技术方案/会员区域字段需求技术方案.md

16 KiB
Raw Permalink Blame History

会员区域字段需求技术方案

版本: v1.0
编制人: pangu
编制日期: 2026-02-05
状态: 待审核


一、需求概述

1.1 需求背景

当前会员管理系统中,会员数据缺少区域归属信息。在添加教育关系和亲子关系时,需要用户从头开始选择区域,用户体验不佳。

1.2 需求内容

序号 需求项 描述
1 会员增加区域字段 在会员数据中记录所属区域
2 H5注册时选择区域 用户注册时必须选择所在区域
3 弹窗区域默认值 添加教育关系/亲子关系时,区域默认选择会员所在区域,但允许修改

二、现状分析

2.1 数据库现状

-- pg_member 表已有 region_id 字段
CREATE TABLE `pg_member` (
  ...
  `region_id` bigint DEFAULT NULL COMMENT '区域ID',
  ...
);

结论: 数据库表已具备 region_id 字段,无需修改表结构。

2.2 后端实体现状

// PgMember.java 中缺少 regionId 字段
public class PgMember extends BaseEntity {
    private Long memberId;
    private String memberCode;
    private String phone;
    // ... 无 regionId 字段
}

结论: 实体类需要添加 regionId 字段。

2.3 H5注册现状

当前H5注册表单字段

  • 手机号码 (phone)
  • 图形验证码 (imageCaptcha)
  • 短信验证码 (verificationCode)
  • 密码 (password)
  • 同意协议 (agreed)

结论: 注册流程无区域选择,需要新增。

2.4 弹窗组件现状

管理后台前端:

组件 区域选择 默认值
EducationDialog (教育关系) 无默认值
StudentSelectDialog (亲子关系) -

H5前端:

组件 区域选择 默认值
TeacherIdentityForm (教育身份) 无默认值
ParentChildrenForm (绑定学生) 无默认值

结论:

  • 管理后台EducationDialog 已有区域选择需添加默认值逻辑StudentSelectDialog 需添加区域筛选功能
  • H5前端两个弹窗均已有区域选择只需添加默认区域逻辑

三、技术方案

3.1 总体架构

┌─────────────────────────────────────────────────────────────┐
│                        H5前端                                │
├─────────────────┬───────────────────────────────────────────┤
│   注册页面      │  添加区域选择器注册时提交regionId         │
└────────┬────────┴───────────────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────────────────────────┐
│                        后端API                               │
├─────────────────┬───────────────────────────────────────────┤
│ H5AuthController│  register接口接收regionId                  │
│ PgMember实体    │  新增regionId字段                          │
└────────┬────────┴───────────────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────────────────────────┐
│                     管理后台前端                             │
├─────────────────┬───────────────────────────────────────────┤
│ EducationDialog │  open时传入会员regionId作为默认值          │
│ StudentSelectDialog │  新增区域筛选默认使用会员regionId    │
│ MemberDialog    │  向子组件传递会员regionId                  │
└─────────────────┴───────────────────────────────────────────┘

3.2 详细设计

3.2.1 后端修改

文件: PgMember.java

// 新增字段
/**
 * 区域ID
 */
private Long regionId;

文件: H5AuthServiceImpl.java - register方法

// 修改注册逻辑接收并保存regionId
public R<LoginVo> register(RegisterDto dto) {
    // ... 原有验证逻辑
    
    PgMember member = new PgMember();
    member.setPhone(dto.getPhone());
    member.setPassword(encryptPassword(dto.getPassword()));
    member.setRegionId(dto.getRegionId()); // 新增保存区域ID
    member.setRegisterSource("2"); // H5注册
    member.setRegisterTime(new Date());
    // ... 保存会员
}

文件: RegisterDto.java (如不存在需创建)

// 新增区域ID字段
private Long regionId;

3.2.2 H5前端修改

3.2.2.1 注册页面新增区域选择

文件: user-front/src/views/register/index.vue

<!-- 新增区域选择器使用el-cascader与现有弹窗风格一致 -->
<el-form-item label="所在区域" prop="regionPath" required>
  <el-cascader
    v-model="registerForm.regionPath"
    :options="regionsData"
    :props="{ value: 'regionId', label: 'regionName', children: 'children' }"
    placeholder="请选择省市区"
    clearable
    style="width: 100%"
  />
</el-form-item>
// 表单数据新增
registerForm = {
  phone: '',
  imageCaptcha: '',
  verificationCode: '',
  password: '',
  agreed: false,
  regionPath: []    // 新增:区域路径 [provinceId, cityId, districtId]
}

// 获取区域树(复用已有逻辑)
const regionsData = ref([])
const loadRegionsData = async () => {
  const res = await request.get('/h5/region/tree')
  regionsData.value = res.data || []
}

// 提交注册时传递regionId取数组最后一个元素
register({
  // ... 原有字段
  regionId: registerForm.regionPath[registerForm.regionPath.length - 1]
})

文件: user-front/src/api/user.js

// 修改register函数添加regionId参数
export function register(data) {
  return request({
    url: '/h5/auth/register',
    method: 'post',
    data: {
      phone: data.consumerName,
      password: data.password,
      smsCode: data.verifyCode,
      captchaCode: data.captchaValue,
      uuid: data.captchaUuid,
      regionId: data.regionId  // 新增
    }
  })
}
3.2.2.2 弹窗默认区域

文件: user-front/src/components/TeacherIdentityForm.vue

// 新增props接收默认区域
props: {
  // ... 原有props
  defaultRegionPath: {    // 新增:默认区域路径
    type: Array,
    default: () => []
  }
}

// 组件挂载或打开时设置默认值
watch(() => props.defaultRegionPath, (val) => {
  if (val && val.length > 0 && formData.regionPath.length === 0) {
    formData.regionPath = [...val]
    // 触发学校加载
    loadSchoolsByRegion(val[val.length - 1])
  }
}, { immediate: true })

文件: user-front/src/components/ParentChildrenForm.vue

// 新增props接收默认区域同上
props: {
  // ... 原有props
  defaultRegionPath: {
    type: Array,
    default: () => []
  }
}

文件: user-front/src/views/userCenter/index.vue

// 获取会员区域信息
const memberRegionPath = ref([])

// 加载会员信息时获取区域路径
const loadMemberInfo = async () => {
  // ... 原有逻辑
  if (memberInfo.regionId) {
    memberRegionPath.value = await getRegionPath(memberInfo.regionId)
  }
}

// 向弹窗组件传递默认区域
<teacher-identity-form
  :default-region-path="memberRegionPath"
  // ... 其他props
/>

<parent-children-form
  :default-region-path="memberRegionPath"
  // ... 其他props
/>

3.2.3 管理后台前端修改

文件: MemberDialog.vue

// 向子组件传递会员区域ID
const memberRegionId = ref(null)

// 编辑会员时获取区域ID
const open = async (row) => {
  if (row) {
    // ... 加载会员数据
    memberRegionId.value = row.regionId
  }
}

// 打开教育关系弹窗时传递默认区域
const handleAddEducation = () => {
  educationDialogRef.value?.open(memberId.value, null, null, memberRegionId.value)
}

// 打开亲子关系弹窗时传递默认区域
const handleAddStudent = () => {
  studentSelectDialogRef.value?.open({
    memberId: memberId.value,
    defaultRegionId: memberRegionId.value
  })
}

文件: EducationDialog.vue

// 修改open方法签名增加默认区域参数
const open = async (mId, row, index, defaultRegionId) => {
  resetForm()
  memberId.value = mId
  isEdit.value = !!row
  localIndex.value = index ?? null
  visible.value = true

  await Promise.all([loadRegionTree(), loadSubjectList()])

  if (row) {
    // 编辑模式:使用已有数据
    // ... 原有逻辑
  } else if (defaultRegionId) {
    // 新增模式:使用会员默认区域
    regionIds.value = await getRegionPath(defaultRegionId)
    form.regionId = defaultRegionId
    await loadSchoolList(defaultRegionId)
  }
}

文件: StudentSelectDialog.vue

<!-- 新增区域筛选 -->
<el-form-item label="区域">
  <el-cascader
    v-model="queryParams.regionIds"
    :options="regionTree"
    :props="{ value: 'regionId', label: 'regionName', checkStrictly: true }"
    placeholder="请选择区域"
    clearable
    style="width: 180px"
    @change="handleRegionChange"
  />
</el-form-item>
// 新增区域相关变量
const regionTree = ref([])
const defaultRegionId = ref(null)

// 修改查询参数
const queryParams = reactive({
  pageNum: 1,
  pageSize: 10,
  studentName: '',
  studentNo: '',
  regionIds: [],    // 新增
  regionId: null    // 新增
})

// 修改open方法
const open = async (options = {}) => {
  memberId.value = options.memberId || null
  defaultRegionId.value = options.defaultRegionId || null
  excludeStudentIds.value = options.excludeIds || []
  
  resetQuery()
  
  // 加载区域树
  await loadRegionTree()
  
  // 设置默认区域
  if (defaultRegionId.value) {
    queryParams.regionIds = await getRegionPath(defaultRegionId.value)
    queryParams.regionId = defaultRegionId.value
  }
  
  visible.value = true
  getList()
}

// 区域变更处理
const handleRegionChange = (val) => {
  queryParams.regionId = val && val.length ? val[val.length - 1] : null
  handleQuery()
}

// 修改getList添加regionId参数
const getList = async () => {
  const params = {
    // ... 原有参数
    regionId: queryParams.regionId || undefined  // 新增
  }
  // ...
}

四、接口变更

4.1 H5注册接口

路径: POST /h5/auth/register

请求体变更:

字段 类型 必填 说明
phone String 手机号
password String 密码
smsCode String 短信验证码
captchaCode String 图形验证码
uuid String 验证码UUID
regionId Long 区域ID新增

4.2 区域树接口H5端

路径: GET /h5/region/tree

说明: 如不存在需新增返回区域树结构供H5选择。

响应体:

{
  "code": 200,
  "data": [
    {
      "regionId": 42,
      "regionName": "湖北省",
      "children": [
        {
          "regionId": 4201,
          "regionName": "武汉市",
          "children": [...]
        }
      ]
    }
  ]
}

4.3 学生列表接口

路径: GET /business/student/available

请求参数变更:

参数 类型 必填 说明
pageNum Integer 页码
pageSize Integer 每页数量
studentName String 学生姓名
studentNo String 学号
regionId Long 区域ID新增

五、数据库变更

5.1 表结构

无变更 - pg_member 表已有 region_id 字段。

5.2 数据迁移

无需迁移 - 新注册用户将自动填充区域ID历史用户区域ID保持为NULL。


六、影响范围

6.1 后端文件清单

文件 修改类型 说明
PgMember.java 修改 新增regionId字段
H5AuthServiceImpl.java 修改 register方法接收regionId
RegisterDto.java 新增/修改 新增regionId字段
H5RegionController.java 新增 提供区域树接口
PgStudentServiceImpl.java 修改 available方法支持regionId筛选

6.2 H5前端文件清单

文件 修改类型 说明
views/register/index.vue 修改 新增区域选择器
api/user.js 修改 register函数添加regionId
components/TeacherIdentityForm.vue 修改 新增defaultRegionPath prop
components/ParentChildrenForm.vue 修改 新增defaultRegionPath prop
views/userCenter/index.vue 修改 获取会员区域并传递给弹窗

6.3 管理后台前端文件清单

文件 修改类型 说明
MemberDialog.vue 修改 传递memberRegionId给子组件
EducationDialog.vue 修改 open方法增加defaultRegionId参数
StudentSelectDialog.vue 修改 新增区域筛选功能

七、测试要点

7.1 功能测试

测试项 测试步骤 预期结果
H5注册-区域必填 不选区域直接注册 提示"请选择所在区域"
H5注册-区域保存 选择区域后注册 会员数据包含正确的regionId
H5教育身份-默认区域 有区域的会员打开"添加教育身份"弹窗 区域字段自动选中会员所在区域
H5教育身份-可修改 修改默认选中的区域 可正常切换到其他区域,学校列表刷新
H5绑定学生-默认区域 有区域的会员打开"绑定学生"弹窗 区域字段自动选中会员所在区域
H5绑定学生-可修改 修改默认选中的区域 可正常切换到其他区域,学校列表刷新
管理后台-教育关系默认区域 为有区域的会员添加任教信息 区域字段自动选中会员所在区域
管理后台-亲子关系区域筛选 为有区域的会员添加亲子关系 区域筛选默认选中会员所在区域

7.2 兼容性测试

测试项 测试步骤 预期结果
历史会员-无区域(H5) 无区域会员打开"添加教育身份"弹窗 区域字段为空,需手动选择
历史会员-无区域(管理后台) 为无区域的会员添加任教信息 区域字段为空,需手动选择
历史会员-弹窗正常 打开历史会员的各类弹窗 弹窗正常显示,无报错

八、风险评估

风险项 风险等级 应对措施
H5注册流程变更 🟡 充分测试,确保注册流程顺畅
历史数据无区域 🟢 兼容处理,无区域时默认值为空
弹窗组件改动 🟢 保持向后兼容,参数可选

九、工作量估算

模块 工作项 估算
后端 PgMember实体修改 0.5h
后端 注册接口修改 1h
后端 区域树接口H5端如不存在 1h
后端 学生列表接口修改 0.5h
H5前端 注册页面区域选择 1.5h
H5前端 TeacherIdentityForm默认区域 1h
H5前端 ParentChildrenForm默认区域 1h
H5前端 userCenter传递区域 0.5h
管理后台 MemberDialog修改 0.5h
管理后台 EducationDialog修改 1h
管理后台 StudentSelectDialog修改 2h
测试 功能测试 2h
合计 12.5h

十、审批记录

角色 姓名 意见 日期
技术负责人
产品负责人

文档生成时间: 2026-02-05