WXL (wul)
4 天以前 cfa5a3aacd38eab6e89818098a9675456bf52625
src/views/patient/SignAcontract/Review.vue
@@ -5,10 +5,10 @@
      <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="100px">
        <el-row :gutter="20">
          <el-col :span="6">
            <el-form-item label="患者姓名" prop="patientName">
            <el-form-item label="儿童姓名" prop="patientName">
              <el-input
                v-model="queryParams.patientName"
                placeholder="请输入患者姓名"
                placeholder="请输入儿童姓名"
                clearable
                @keyup.enter="handleQuery"
              />
@@ -81,12 +81,15 @@
        style="width: 100%"
        :default-sort="{prop: 'applyTime', order: 'descending'}"
      >
        <el-table-column label="患者信息" min-width="200" fixed>
        <el-table-column label="儿童信息" min-width="200" fixed>
          <template slot-scope="scope">
            <div class="patient-info">
              <div class="patient-name">{{ scope.row.patientName }}</div>
              <div class="patient-detail">
                {{ scope.row.gender }} | {{ scope.row.age }}岁 | {{ scope.row.phone }}
                <div style="color: #909399; font-size: 12px; margin-top: 2px;">
                  {{ scope.row.applicableAge }}
                </div>
              </div>
            </div>
          </template>
@@ -110,7 +113,7 @@
        </el-table-column>
        <el-table-column label="申请时间" prop="applyTime" width="160" sortable />
        <el-table-column label="期望医生" prop="expectDoctor" width="120" />
        <el-table-column label="特殊要求" min-width="200">
        <el-table-column label="监护人要求" min-width="200">
          <template slot-scope="scope">
            <span v-if="scope.row.specialRequirements" :title="scope.row.specialRequirements">
              {{ scope.row.specialRequirements.substring(0, 30) }}...
@@ -187,7 +190,7 @@
            type="textarea"
            :rows="3"
            v-model="reviewForm.rejectReason"
            placeholder="请输入驳回的具体原因,便于患者了解情况"
            placeholder="请输入驳回的具体原因,便于监护人了解情况"
            maxlength="200"
            show-word-limit
          />
@@ -255,18 +258,44 @@
        rejected: 0
      },
      availableDoctors: [
        { id: '1', name: '王医生', department: '内科' },
        { id: '2', name: '李医生', department: '老年科' },
        { id: '3', name: '张医生', department: '妇产科' },
        { id: '4', name: '刘医生', department: '儿科' },
        { id: '1', name: '王医生', department: '儿科' },
        { id: '2', name: '李医生', department: '儿童保健科' },
        { id: '3', name: '张医生', department: '儿科' },
        { id: '4', name: '刘医生', department: '儿童营养科' },
        { id: '5', name: '陈医生', department: '全科' }
      ],
      // 儿童服务套餐配置
      servicePackages: {
        '1': { name: '基础健康管理包', color: 'info' },
        '2': { name: '慢性病管理包', color: 'success' },
        '3': { name: '老年人健康包', color: 'warning' },
        '4': { name: '孕产妇保健包', color: 'danger' },
        '5': { name: '儿童保健包', color: 'primary' }
        '1': {
          name: '婴幼儿健康基础包',
          color: 'primary',
          applicableAge: '0-3岁'
        },
        '2': {
          name: '学龄前儿童健康包',
          color: 'success',
          applicableAge: '3-6岁'
        },
        '3': {
          name: '学龄儿童综合健康包',
          color: 'warning',
          applicableAge: '7-12岁'
        },
        '4': {
          name: '青少年健康支持包',
          color: 'danger',
          applicableAge: '13-18岁'
        },
        '5': {
          name: '儿童营养与生长发育增值包',
          color: 'info',
          applicableAge: '3-18岁'
        },
        '6': {
          name: '儿童中医特色保健包',
          color: 'primary',
          applicableAge: '0-6岁'
        }
      },
      rules: {
        rejectReason: [
@@ -283,111 +312,128 @@
    this.calculateStats()
  },
  methods: {
//优化后的模拟数据生成方法
generateMockData() {
  const mockData = []
    // 生成模拟数据
    generateMockData() {
      const mockData = []
  // 使用您提供的真实姓名列表
  const patientNames = [
    '李肇芬', '卢木仲', '李成白', '方兆玉', '刘翊惠', '丁汉臻', '吴佳瑞', '舒绿珮',
    '周白芷', '张姿妤', '张虹伦', '周琼玟', '倪怡芳', '郭贵妃', '杨佩芳', '黄文旺',
    '黄盛玫', '郑丽青', '许智云', '张孟涵', '李小爱', '王恩龙', '朱政廷', '邓诗涵',
    '陈政倩', '吴俊伯', '阮馨学', '翁惠珠', '吴思翰', '林佩玲'
  ]
      // 使用儿童姓名列表
      const patientNames = [
        '李小宝', '张小明', '王雨欣', '刘浩然', '陈思琪', '杨宇航', '黄诗涵', '赵天宇',
        '周小萌', '吴俊杰', '郑雅雯', '孙沐辰', '朱雨萱', '马浩宇', '胡可馨', '林俊熙',
        '郭子轩', '何欣怡', '高天佑', '梁静怡', '罗浩然', '宋雨泽', '唐语嫣', '许博文',
        '谢欣妍', '冯子默', '董雨桐', '萧天乐', '曹心怡', '袁嘉豪'
      ]
  const specialReqs = [
    '希望医生能定期上门检查',
    '需要周末时间段的服务',
    '对药物有过敏史,需特别注意',
    '行动不便,需要上门服务',
    '无特殊要求',
    '需要英语服务支持',
    '有高血压病史,需重点关注',
    '需要定期血糖监测服务',
    '希望有固定的家庭医生',
    '需要心理疏导服务'
  ]
      const specialReqs = [
        '希望医生能定期上门检查',
        '需要周末时间段的服务',
        '对药物有过敏史,需特别注意',
        '行动不便,需要上门服务',
        '无特殊要求',
        '需要英语服务支持',
        '有哮喘病史,需重点关注',
        '需要定期生长发育监测',
        '希望有固定的儿科医生',
        '需要疫苗接种提醒服务'
      ]
  const rejectReasons = [
    '资料不完整,请补充健康档案',
    '不符合当前签约条件',
    '选择的医生档期已满',
    '服务套餐与病情不匹配',
    '年龄不符合套餐要求',
    '请补充完整的病史资料'
  ]
      const rejectReasons = [
        '监护人资料不完整,请补充身份证明',
        '儿童年龄不符合套餐要求',
        '选择的医生专长与儿童需求不匹配',
        '服务套餐与儿童健康状况不匹配',
        '请补充完整的儿童健康档案',
        '疫苗接种记录不完整'
      ]
  // 生成约30条数据(与姓名数量匹配)
  for (let i = 0; i < patientNames.length; i++) {
    const packageId = (i % 5) + 1 + ''
    const reviewStatus = i % 3 // 0:待审核, 1:通过, 2:驳回
    const applyDate = this.generateRandomDate('2024-10-01', '2024-12-08')
      for (let i = 0; i < patientNames.length; i++) {
        const packageId = (i % 6) + 1 + ''
        const packageInfo = this.servicePackages[packageId]
        const reviewStatus = i % 3 // 0:待审核, 1:通过, 2:驳回
        const applyDate = this.generateRandomDate('2024-10-01', '2024-12-08')
    // 生成更真实的电话号码
    const phonePrefix = ['138', '139', '150', '151', '152', '186', '187', '188']
    const phone = `${phonePrefix[i % phonePrefix.length]}${this.padNumber(1000 + i * 37, 4)}${this.padNumber(i % 100, 2)}`
        // 根据套餐适用年龄生成合理的实际年龄
        let age
        switch(packageInfo.applicableAge) {
          case '0-3岁':
            age = Math.floor(Math.random() * 3) + 1
            break
          case '3-6岁':
            age = Math.floor(Math.random() * 3) + 3
            break
          case '7-12岁':
            age = Math.floor(Math.random() * 6) + 7
            break
          case '13-18岁':
            age = Math.floor(Math.random() * 6) + 13
            break
          default:
            age = Math.floor(Math.random() * 18) + 1
        }
    // 生成合理的年龄(0-80岁)
    const age = i % 80
    const gender = i % 2 === 0 ? '男' : '女'
        // 生成监护人电话号码
        const phonePrefix = ['138', '139', '150', '151', '152', '186', '187', '188']
        const phone = `${phonePrefix[i % phonePrefix.length]}${this.padNumber(1000 + i * 37, 4)}${this.padNumber(i % 100, 2)}`
    mockData.push({
      id: `A${2024000 + i}`,
      patientName: patientNames[i],
      gender: gender,
      age: age,
      phone: phone,
      servicePackageId: packageId,
      servicePackage: this.servicePackages[packageId].name,
      services: this.getServicesByPackage(packageId),
      contractPeriod: [1, 2][i % 2],
      applyTime: `${applyDate} ${this.padNumber(8 + (i % 10), 2)}:${this.padNumber(i % 60, 2)}:${this.padNumber(i % 60, 2)}`,
      expectDoctor: ['王医生', '李医生', '张医生', '刘医生', '陈医生'][i % 5],
      specialRequirements: specialReqs[i % specialReqs.length],
      reviewStatus: reviewStatus,
      reviewer: reviewStatus !== 0 ? ['管理员', '系统管理员', '审核专员'][i % 3] : '',
      reviewTime: reviewStatus !== 0 ?
        `${this.addDays(applyDate, 1 + (i % 3))} 14:${this.padNumber(i % 60, 2)}:00` : '',
      rejectReason: reviewStatus === 2 ? rejectReasons[i % rejectReasons.length] : ''
    })
  }
        mockData.push({
          id: `A${2024000 + i}`,
          patientName: patientNames[i],
          gender: i % 2 === 0 ? '男' : '女',
          age: age,
          phone: phone,
          servicePackageId: packageId,
          servicePackage: packageInfo.name,
          services: this.getServicesByPackage(packageId),
          contractPeriod: [1, 2][i % 2],
          applicableAge: packageInfo.applicableAge,
          applyTime: `${applyDate} ${this.padNumber(8 + (i % 10), 2)}:${this.padNumber(i % 60, 2)}:${this.padNumber(i % 60, 2)}`,
          expectDoctor: ['王医生', '李医生', '张医生', '刘医生', '陈医生'][i % 5],
          specialRequirements: specialReqs[i % specialReqs.length],
          reviewStatus: reviewStatus,
          reviewer: reviewStatus !== 0 ? ['管理员', '系统管理员', '审核专员'][i % 3] : '',
          reviewTime: reviewStatus !== 0 ?
            `${this.addDays(applyDate, 1 + (i % 3))} 14:${this.padNumber(i % 60, 2)}:00` : '',
          rejectReason: reviewStatus === 2 ? rejectReasons[i % rejectReasons.length] : ''
        })
      }
  return mockData
},
      return mockData
    },
// 根据套餐获取服务列表
getServicesByPackage(packageId) {
  const servicesMap = {
    '1': ['年度健康评估', '在线健康咨询', '健康档案管理', '定期健康提醒'],
    '2': ['专属医生服务', '用药指导管理', '定期随访监测', '个性化康复计划', '紧急医疗咨询'],
    '3': ['跌倒风险评估', '康复训练指导', '用药安全管理', '定期上门访视', '紧急联系服务', '心理健康关怀'],
    '4': ['孕期健康管理', '产后康复指导', '新生儿护理咨询', '营养膳食建议', '心理情绪支持'],
    '5': ['生长发育监测', '疫苗接种管理', '常见病防治', '营养指导', '早期教育咨询']
  }
  return servicesMap[packageId] || []
},
    // 根据套餐获取服务列表
    getServicesByPackage(packageId) {
      const servicesMap = {
        '1': ['新生儿家庭访视', '定期体格检查与发育评估', '血常规检测', '听力筛查', '喂养与护理指导', '预防接种服务', '中医保健指导'],
        '2': ['生长发育评估', '视力筛查与口腔保健', '血常规检查', '合理膳食与行为指导', '疾病预防与健康干预', '中医饮食调养指导'],
        '3': ['年度健康检查', '心理行为发育评估', '科学用眼与口腔保健', '合理膳食指导', '健康生活方式干预', '专家转诊绿色通道'],
        '4': ['青春期健康教育', '年度健康评估', '心理健康支持', '健康风险行为干预', '个性化健康方案', '优先预约检查服务'],
        '5': ['微量元素测定', '骨密度检测', '个性化膳食方案', '生长发育专项评估', '运动处方指导', '定期营养监测'],
        '6': ['中医体质辨识', '三伏贴服务', '小儿推拿', '耳穴治疗', '防感香囊', '食疗指导']
      }
      return servicesMap[packageId] || []
    },
// 辅助方法:生成随机日期
generateRandomDate(start, end) {
  const startDate = new Date(start).getTime()
  const endDate = new Date(end).getTime()
  const randomTime = startDate + Math.random() * (endDate - startDate)
  return new Date(randomTime).toISOString().split('T')[0]
},
    // 辅助方法:生成随机日期
    generateRandomDate(start, end) {
      const startDate = new Date(start).getTime()
      const endDate = new Date(end).getTime()
      const randomTime = startDate + Math.random() * (endDate - startDate)
      return new Date(randomTime).toISOString().split('T')[0]
    },
// 辅助方法:添加天数
addDays(date, days) {
  const result = new Date(date)
  result.setDate(result.getDate() + days)
  return result.toISOString().split('T')[0]
},
    // 辅助方法:添加天数
    addDays(date, days) {
      const result = new Date(date)
      result.setDate(result.getDate() + days)
      return result.toISOString().split('T')[0]
    },
// 辅助方法:数字补零
padNumber(num, length) {
  return num.toString().padStart(length, '0')
},
    // 辅助方法:数字补零
    padNumber(num, length) {
      return num.toString().padStart(length, '0')
    },
    // 获取审核列表 [1](@ref)
    // 获取审核列表
    async getList() {
      this.loading = true
      try {
@@ -435,7 +481,7 @@
      this.stats.rejected = allData.filter(item => item.reviewStatus === 2).length
    },
    // 获取审核状态文本 [2](@ref)
    // 获取审核状态文本
    getReviewStatusText(status) {
      const statusMap = { 0: '待审核', 1: '审核通过', 2: '审核驳回' }
      return statusMap[status] || '未知'
@@ -449,11 +495,14 @@
    // 获取套餐类型
    getPackageType(packageId) {
      const typeMap = { '1': 'info', '2': 'success', '3': 'warning', '4': 'danger', '5': 'primary' }
      const typeMap = {
        '1': 'primary', '2': 'success', '3': 'warning',
        '4': 'danger', '5': 'info', '6': 'primary'
      }
      return typeMap[packageId] || 'info'
    },
    // 搜索操作 [1](@ref)
    // 搜索操作
    handleQuery() {
      this.queryParams.pageNum = 1
      this.getList()
@@ -471,7 +520,7 @@
      this.handleQuery()
    },
    // 处理审核操作 [2](@ref)
    // 处理审核操作
    handleReview(row, status) {
      this.currentRow = row
      this.reviewForm = {
@@ -483,7 +532,6 @@
      }
      this.reviewDialogVisible = true
      // 清除表单验证
      this.$nextTick(() => {
        if (this.$refs.reviewFormRef) {
          this.$refs.reviewFormRef.clearValidate()
@@ -491,10 +539,9 @@
      })
    },
    // 提交审核 [2,6](@ref)
    // 提交审核
    async submitReview() {
      try {
        // 表单验证
        if (this.reviewForm.reviewStatus === 2) {
          if (!this.reviewForm.rejectReason) {
            this.$message.error('请填写驳回原因')
@@ -507,10 +554,8 @@
          return
        }
        // 模拟API调用
        await new Promise(resolve => setTimeout(resolve, 1000))
        // 更新当前行的状态
        const currentIndex = this.reviewList.findIndex(item => item.id === this.currentRow.id)
        if (currentIndex !== -1) {
          this.reviewList[currentIndex].reviewStatus = this.reviewForm.reviewStatus
@@ -518,7 +563,6 @@
          this.reviewList[currentIndex].reviewTime = new Date().toLocaleString()
          this.reviewList[currentIndex].rejectReason = this.reviewForm.rejectReason
          // 如果审核通过,分配医生
          if (this.reviewForm.reviewStatus === 1) {
            const doctor = this.availableDoctors.find(d => d.id === this.reviewForm.assignDoctor)
            this.reviewList[currentIndex].expectDoctor = doctor ? doctor.name : this.reviewList[currentIndex].expectDoctor
@@ -527,7 +571,7 @@
        this.$message.success(this.reviewForm.reviewStatus === 1 ? '审核通过成功' : '审核驳回成功')
        this.reviewDialogVisible = false
        this.calculateStats() // 重新计算统计信息
        this.calculateStats()
      } catch (error) {
        console.error('审核操作失败:', error)
        this.$message.error('审核操作失败')
@@ -536,54 +580,10 @@
    // 查看详情
    handleView(row) {
      this.$message.info(`查看患者 ${row.patientName} 的申请详情`)
      // 实际开发中跳转到详情页
      // this.$router.push({ path: '/patient/contract/apply-detail', query: { id: row.id } })
    },
    // 批量审核通过
    handleBatchApprove() {
      const pendingItems = this.reviewList.filter(item => item.reviewStatus === 0)
      if (pendingItems.length === 0) {
        this.$message.warning('没有待审核的申请')
        return
      }
      this.$confirm(`确定要批量通过 ${pendingItems.length} 个待审核申请吗?`, '批量审核', {
        type: 'warning'
      }).then(async () => {
        try {
          this.loading = true
          // 模拟批量审核API调用
          await new Promise(resolve => setTimeout(resolve, 2000))
          // 更新所有待审核项的状态
          pendingItems.forEach(item => {
            item.reviewStatus = 1
            item.reviewer = '当前用户'
            item.reviewTime = new Date().toLocaleString()
          })
          this.$message.success(`批量审核通过成功,共处理 ${pendingItems.length} 个申请`)
          this.calculateStats()
        } catch (error) {
          this.$message.error('批量审核失败')
        } finally {
          this.loading = false
        }
      })
    },
    // 导出审核数据
    handleExport() {
      const exportData = this.generateMockData()
      // 实际开发中这里应该调用导出API
      console.log('导出数据:', exportData)
      this.$message.info('导出功能开发中,数据已打印到控制台')
      this.$message.info(`查看儿童 ${row.patientName} 的申请详情`)
    }
  },
  watch: {
    // 监听审核状态变化,动态设置验证规则 [6](@ref)
    'reviewForm.reviewStatus': function(newVal) {
      this.$nextTick(() => {
        if (this.$refs.reviewFormRef) {
@@ -638,53 +638,11 @@
    .patient-detail {
      font-size: 12px;
      color: #909399;
      line-height: 1.4;
    }
  }
  // 审核状态样式
  .review-status {
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 500;
    &.status-pending {
      background: #fdf6ec;
      color: #e6a23c;
    }
    &.status-approved {
      background: #f0f9e8;
      color: #67c23a;
    }
    &.status-rejected {
      background: #fef0f0;
      color: #f56c6c;
    }
  }
  // 特殊要求文本样式
  .special-requirements {
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    &:hover {
      white-space: normal;
      overflow: visible;
      background: white;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      padding: 8px;
      border-radius: 4px;
      position: absolute;
      z-index: 1000;
      max-width: 300px;
    }
  }
  // 表格样式
  // 表格样式优化
  ::v-deep .el-table {
    .el-table__header-wrapper {
      th {
@@ -714,95 +672,6 @@
    }
  }
  // 审核对话框样式
  .review-dialog {
    ::v-deep .el-dialog {
      border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    }
    .dialog-footer {
      text-align: right;
      margin-top: 20px;
    }
  }
  // 操作按钮样式
  .action-buttons {
    display: flex;
    gap: 8px;
    .el-button {
      padding: 7px 12px;
      border-radius: 4px;
      font-size: 12px;
      &.approve-btn {
        background: #67c23a;
        border-color: #67c23a;
        color: white;
        &:hover {
          background: #5daf34;
          border-color: #5daf34;
        }
      }
      &.reject-btn {
        background: #f56c6c;
        border-color: #f56c6c;
        color: white;
        &:hover {
          background: #e65c5c;
          border-color: #e65c5c;
        }
      }
      &.detail-btn {
        color: #409eff;
        border-color: #409eff;
        &:hover {
          background: #ecf5ff;
        }
      }
    }
  }
  // 批量操作栏
  .batch-actions {
    background: #ecf5ff;
    padding: 12px 20px;
    margin-bottom: 16px;
    border-radius: 4px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    .batch-info {
      color: #409eff;
      font-size: 14px;
    }
  }
  // 空状态样式
  .empty-state {
    text-align: center;
    padding: 40px 20px;
    color: #909399;
    .empty-icon {
      font-size: 48px;
      margin-bottom: 16px;
      opacity: 0.5;
    }
    .empty-text {
      font-size: 14px;
    }
  }
  // 响应式设计
  @media (max-width: 768px) {
    padding: 10px;
@@ -811,16 +680,6 @@
      .el-col {
        margin-bottom: 10px;
      }
    }
    .action-buttons {
      flex-direction: column;
    }
    .batch-actions {
      flex-direction: column;
      gap: 10px;
      align-items: stretch;
    }
  }
}