编辑 | blame | 历史 | 原始文档

联系人必填和归属机构默认选中功能说明

功能概述

本次优化包含两个功能点:
1. 联系人字段设为必填:确保急救转运任务中联系人信息完整,便于紧急情况下联系
2. 归属机构默认选中当前用户分公司:自动设置用户所属分公司,同时更新地域过滤条件,优化用户体验

实现位置

前端文件: app/pages/task/create-emergency.vue

一、联系人必填功能

1.1 业务背景

急救转运任务中,联系人是关键信息,用于:
- 紧急情况下的沟通联系
- 确认患者身份和情况
- 协调转运过程中的各项事宜
- 后续任务跟进和反馈

因此将联系人字段设为必填,确保信息完整性。

1.2 技术实现

模板修改

将联系人的label添加required类:

<view class="form-item">
  <view class="form-label required">联系人</view>
  <input 
    class="form-input" 
    placeholder="请输入联系人" 
    v-model="taskForm.patient.contact"
  />
</view>

表单验证

validateForm() 方法中添加联系人验证:

validateForm() {
  // ... 其他验证
  
  if (!this.taskForm.patient.contact) {
    this.$modal.showToast('请输入联系人')
    return false
  }
  
  if (!this.taskForm.patient.name) {
    this.$modal.showToast('请输入患者姓名')
    return false
  }
  
  // ... 其他验证
  
  return true
}

验证顺序
1. 任务车辆
2. 任务类型
3. 单据类型
4. ✅ 联系人(新增)
5. 患者姓名
6. 联系电话
7. 转出医院信息
8. 转入医院信息

1.3 样式说明

必填字段标识通过CSS伪元素实现:

.form-label {
  &.required::before {
    content: '*';
    color: #ff4d4f;
    margin-right: 4rpx;
    font-weight: bold;
  }
}

显示效果:* 联系人

二、归属机构默认选中功能

2.1 业务背景

根据项目规范和用户体验:
- 用户创建任务时,归属机构通常就是自己所在的分公司
- 自动选中可以减少用户操作步骤
- 归属机构会影响医院列表的地域过滤,需要自动更新

2.2 技术实现

修改 loadBranchCompanies() 方法

loadBranchCompanies() {
  listBranchCompany().then(response => {
    const list = response.data || []
    // 过滤出 parent_id = 100 的部门(分公司)
    this.organizationOptions = list.filter(dept => dept.parentId === 100)
    // 生成picker的数据源(只显示名称)
    this.organizations = this.organizationOptions.map(dept => dept.deptName)
    
    // 默认设置为当前用户的分公司
    if (this.currentUser.branchCompanyName) {
      const index = this.organizationOptions.findIndex(
        dept => dept.deptName === this.currentUser.branchCompanyName
      )
      if (index !== -1) {
        this.selectedOrganization = this.currentUser.branchCompanyName
        // 提取地域关键词(去除"分公司"后缀)
        this.selectedRegion = this.selectedOrganization.replace(/分公司$/g, '').trim()
        console.log('默认选中归属机构:', this.selectedOrganization, '地域:', this.selectedRegion)
        // 加载医院列表(带地域过滤)
        this.loadDefaultHospitals()
      }
    }
  }).catch(error => {
    console.error('加载分公司数据失败:', error)
    this.organizationOptions = []
    this.organizations = []
  })
}

优化 onLoad() 方法

移除重复的医院列表加载和归属机构设置:

onLoad(options) {
  // 先加载车辆列表,然后加载绑定车辆信息
  this.getAvailableVehicles().then(() => {
    this.getUserBoundVehicleInfo()
  })
  this.initSelectedStaff()
  this.loadDeptStaff()
  // 加载分公司数据(会自动设置默认分公司并加载医院列表)
  this.loadBranchCompanies()
  // 加载科室字典数据
  this.loadDepartments()
  // 加载任务类型数据
  this.loadEmergencyTaskTypes()
  // 加载单据类型数据
  this.loadDocumentTypes()
}

优化说明
- ❌ 移除了独立的 this.selectedOrganization = this.currentUser.branchCompanyName
- ❌ 移除了独立的 this.loadDefaultHospitals()
- ✅ loadBranchCompanies() 内部会完成这两个操作
- ✅ 避免了医院列表的重复加载

2.3 工作流程

页面加载 (onLoad)
    ↓
调用 loadBranchCompanies()
    ↓
从后端加载分公司列表
    ↓
过滤 parent_id = 100 的部门
    ↓
检查当前用户的 branchCompanyName
    ↓
在分公司列表中查找匹配项
    ↓
设置 selectedOrganization = 用户分公司名称
设置 selectedRegion = 提取的地域关键词
    ↓
调用 loadDefaultHospitals() 加载医院列表
    ↓
医院列表按地域过滤
    ↓
UI 更新,显示选中的归属机构

2.4 地域提取逻辑

将分公司名称转换为地域关键词:

// 例如:"广州分公司" → "广州"
this.selectedRegion = this.selectedOrganization.replace(/分公司$/g, '').trim()

示例
- "广州分公司" → "广州"
- "深圳分公司" → "深圳"
- "东莞分公司" → "东莞"

这个地域关键词会用于医院搜索的过滤条件。

三、数据流程图

联系人必填验证流程

用户点击"保存"
    ↓
调用 submitTask()
    ↓
调用 validateForm()
    ↓
检查 taskForm.patient.contact
    ↓
    ├─ 为空 → 提示"请输入联系人" → 阻止提交
    └─ 有值 → 继续其他验证

归属机构默认选中流程

页面加载
    ↓
获取 currentUser.branchCompanyName
    ↓
    ├─ 有值(如"广州分公司")
    │     ↓
    │  在 organizationOptions 中查找
    │     ↓
    │     ├─ 找到
    │     │    ↓
    │     │  设置 selectedOrganization = "广州分公司"
    │     │  设置 selectedRegion = "广州"
    │     │  加载医院列表(地域过滤)
    │     │    ↓
    │     │  UI 显示"广州分公司"
    │     │
    │     └─ 未找到
    │          ↓
    │        不设置默认值
    │        医院列表不过滤
    │
    └─ 无值
         ↓
       不设置默认值
       用户需要手动选择

四、数据结构

用户信息(来自 Vuex state)

currentUser: {
  userId: 1,
  name: "张三",
  nickName: "张三",
  deptId: 101,
  branchCompanyId: 100,
  branchCompanyName: "广州分公司"  // 关键字段
}

归属机构数据

// 原始数据(来自后端)
organizationOptions: [
  {
    deptId: 100,
    deptName: "广州分公司",
    parentId: 100
  },
  {
    deptId: 101,
    deptName: "深圳分公司",
    parentId: 100
  }
]

// picker 显示数据
organizations: ["广州分公司", "深圳分公司"]

// 选中的值
selectedOrganization: "广州分公司"
selectedRegion: "广州"  // 用于医院搜索过滤

表单数据

taskForm: {
  patient: {
    contact: "李四",      // ✅ 必填
    phone: "13800138000", // ✅ 必填
    name: "王五",         // ✅ 必填
    gender: "male",
    idCard: "440106199001011234",
    condition: ""
  },
  // ... 其他字段
}

五、相关接口

获取分公司列表

API: GET /system/dept/list?parentId=100

前端方法: listBranchCompany()

返回数据:
json { "code": 200, "data": [ { "deptId": 100, "deptName": "广州分公司", "parentId": 100, "orderNum": 1, "leader": "张经理", "phone": "020-12345678", "status": "0" }, { "deptId": 101, "deptName": "深圳分公司", "parentId": 100, "orderNum": 2, "leader": "李经理", "phone": "0755-87654321", "status": "0" } ] }

搜索医院(带地域过滤)

API: GET /hospital/search?keyword={keyword}&region={region}

调用示例:
javascript // selectedRegion = "广州" searchHospitals('', '广州').then(response => { // 返回广州地区的医院列表(前100条) })

过滤逻辑(后端SQL):
sql WHERE (HopsProvince LIKE '%广州%' OR HopsCity LIKE '%广州%' OR HopsArea LIKE '%广州%')

六、异常处理

1. 用户未设置分公司

场景: currentUser.branchCompanyName 为空

处理:
- 不设置默认值
- selectedOrganization 保持为空
- picker 显示"请选择归属机构"
- 医院列表不进行地域过滤

2. 用户分公司不在列表中

场景: 数据不一致,用户的分公司不在 parent_id=100 的列表中

处理:
javascript const index = this.organizationOptions.findIndex( dept => dept.deptName === this.currentUser.branchCompanyName ) if (index !== -1) { // 找到了,设置默认值 } else { // 未找到,不设置默认值 // 用户需要手动选择 }

3. 联系人为空提交

场景: 用户未填写联系人就点击保存

处理:
javascript if (!this.taskForm.patient.contact) { this.$modal.showToast('请输入联系人') return false // 阻止提交 }

用户看到: Toast 提示"请输入联系人"

七、测试建议

测试场景1:联系人必填验证

步骤:
1. 打开创建急救转运任务页面
2. 填写其他必填字段(车辆、患者姓名、电话等)
3. 不填写联系人
4. 点击"保存"按钮

预期结果:
- 显示 Toast 提示"请输入联系人"
- 表单不提交
- 用户停留在当前页面

测试场景2:归属机构默认选中

前置条件: 当前用户的 branchCompanyName = "广州分公司"

步骤:
1. 打开创建急救转运任务页面
2. 观察归属机构字段

预期结果:
- 归属机构字段自动显示"广州分公司"
- selectedRegion = "广州"
- 医院列表加载时带地域过滤
- 控制台输出: "默认选中归属机构: 广州分公司 地域: 广州"

测试场景3:归属机构切换

步骤:
1. 页面加载后,归属机构默认显示"广州分公司"
2. 用户点击归属机构选择器
3. 选择"深圳分公司"

预期结果:
- selectedOrganization 更新为"深圳分公司"
- selectedRegion 更新为"深圳"
- 自动重新加载医院列表(带新的地域过滤)
- 医院搜索结果只显示深圳地区的医院

测试场景4:用户无分公司

前置条件: 当前用户的 branchCompanyName 为空或 null

步骤:
1. 打开创建急救转运任务页面
2. 观察归属机构字段

预期结果:
- 归属机构显示"请选择归属机构"
- 没有默认选中项
- 医院列表加载时不进行地域过滤
- 用户可以手动选择归属机构

八、优化建议

1. 联系人智能填充

根据患者姓名或历史记录,智能推荐联系人:

// 监听患者姓名变化
watch: {
  'taskForm.patient.name'(newVal) {
    // 如果联系人为空,可以自动填充为患者姓名
    if (!this.taskForm.patient.contact && newVal) {
      this.taskForm.patient.contact = newVal
    }
  }
}

2. 联系人常用列表

记录用户常用的联系人,提供快速选择:

// 本地存储常用联系人
const frequentContacts = uni.getStorageSync('frequentContacts') || []

// 显示快速选择按钮
<view class="quick-select">
  <text v-for="contact in frequentContacts" @click="selectContact(contact)">
    {{ contact }}
  </text>
</view>

3. 归属机构权限控制

某些用户可能只能看到特定的分公司:

loadBranchCompanies() {
  listBranchCompany().then(response => {
    let list = response.data || []
    
    // 根据用户权限过滤
    if (!this.currentUser.isAdmin) {
      list = list.filter(dept => 
        dept.deptId === this.currentUser.branchCompanyId
      )
    }
    
    this.organizationOptions = list.filter(dept => dept.parentId === 100)
    // ...
  })
}

九、相关规范

根据项目记忆:

  1. 分公司数据加载规范(memory: ba4557cf):
  • ✅ 调用 /system/dept/list 接口
  • ✅ 传入 parentId=100 参数
  • ✅ 获取 parent_id=100 的部门作为分公司列表
  1. 急救转运任务车辆自动填充规则(memory: eec5a112):
  • 车辆选择器必须加载当前用户所在分公司的所有车辆
  • ✅ 本次修改确保了归属机构默认为用户分公司
  • ✅ 地域过滤确保医院列表与分公司地域相关

十、版本历史

  • 2025-01-25 v1: 初始版本
  • ✅ 联系人字段设为必填
  • ✅ 添加联系人必填验证
  • ✅ 归属机构默认选中当前用户分公司
  • ✅ 自动更新 selectedRegion
  • ✅ 优化 onLoad 方法,避免重复加载
  • ✅ 添加调试日志