WXL (wul)
4 天以前 cfa5a3aacd38eab6e89818098a9675456bf52625
src/views/patient/SignAcontract/index.vue
@@ -27,11 +27,12 @@
          <el-col :span="6">
            <el-form-item label="服务套餐" prop="servicePackage">
              <el-select v-model="queryParams.servicePackage" placeholder="请选择套餐" clearable>
                <el-option label="基础健康管理包" value="1" />
                <el-option label="慢性病管理包" value="2" />
                <el-option label="老年人健康包" value="3" />
                <el-option label="孕产妇保健包" value="4" />
                <el-option label="儿童保健包" value="5" />
                <el-option
                  v-for="pkg in packageOptions"
                  :key="pkg.id"
                  :label="pkg.name"
                  :value="pkg.id"
                />
              </el-select>
            </el-form-item>
          </el-col>
@@ -51,7 +52,7 @@
        <el-card class="stats-card" shadow="hover">
          <div class="stats-content">
            <div class="stats-number">{{ stats.total }}</div>
            <div class="stats-label">总签约患者</div>
            <div class="stats-label">总签约儿童</div>
          </div>
        </el-card>
      </el-col>
@@ -91,12 +92,15 @@
        :default-sort="{prop: 'signDate', order: 'descending'}"
      >
        <el-table-column type="selection" width="55" />
        <el-table-column label="患者信息" min-width="180" fixed>
        <el-table-column label="儿童信息" min-width="180" 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>
@@ -190,118 +194,161 @@
      },
      total: 0,
      patientList: [],
      // 服务套餐配置
      // 儿童服务套餐配置 [1,3,5](@ref)
      servicePackages: {
        '1': {
          name: '基础健康管理包',
          services: ['年度健康评估', '在线健康咨询', '健康档案管理', '定期健康提醒'],
          name: '婴幼儿健康基础包',
          description: '为0-3岁婴幼儿提供全面的健康监测与发育指导',
          services: ['新生儿家庭访视', '定期体格检查与发育评估', '血常规检测', '听力筛查', '喂养与护理指导', '预防接种服务', '中医保健指导'],
          price: 0,
          color: 'info'
          color: 'primary',
          applicableAge: '0-3岁'
        },
        '2': {
          name: '慢性病管理包',
          services: ['专属医生服务', '用药指导管理', '定期随访监测', '个性化康复计划', '紧急医疗咨询'],
          price: 299,
          color: 'success'
          name: '学龄前儿童健康包',
          description: '关注3-6岁儿童生长发育、常见病预防及习惯养成',
          services: ['生长发育评估', '视力筛查与口腔保健', '血常规检查', '合理膳食与行为指导', '疾病预防与健康干预', '中医饮食调养指导'],
          price: 0,
          color: 'success',
          applicableAge: '3-6岁'
        },
        '3': {
          name: '老年人健康包',
          services: ['跌倒风险评估', '康复训练指导', '用药安全管理', '定期上门访视', '紧急联系服务', '心理健康关怀'],
          price: 499,
          color: 'warning'
          name: '学龄儿童综合健康包',
          description: '为7-12岁儿童提供学习期健康保障与发展支持',
          services: ['年度健康检查', '心理行为发育评估', '科学用眼与口腔保健', '合理膳食指导', '健康生活方式干预', '专家转诊绿色通道'],
          price: 0,
          color: 'warning',
          applicableAge: '7-12岁'
        },
        '4': {
          name: '孕产妇保健包',
          services: ['孕期健康管理', '产后康复指导', '新生儿护理咨询', '营养膳食建议', '心理情绪支持'],
          price: 399,
          color: 'danger'
          name: '青少年健康支持包',
          description: '针对13-18岁青少年青春期特点的健康管理',
          services: ['青春期健康教育', '年度健康评估', '心理健康支持', '健康风险行为干预', '个性化健康方案', '优先预约检查服务'],
          price: 0,
          color: 'danger',
          applicableAge: '13-18岁'
        },
        '5': {
          name: '儿童保健包',
          services: ['生长发育监测', '疫苗接种管理', '常见病防治', '营养指导', '早期教育咨询'],
          price: 199,
          color: 'primary'
          name: '儿童营养与生长发育增值包',
          description: '针对肥胖、营养不良等问题的专项管理',
          services: ['微量元素测定', '骨密度检测', '个性化膳食方案', '生长发育专项评估', '运动处方指导', '定期营养监测'],
          price: 150,
          color: 'info',
          applicableAge: '3-18岁'
        },
        '6': {
          name: '儿童中医特色保健包',
          description: '运用中医药方法增强儿童体质',
          services: ['中医体质辨识', '三伏贴服务', '小儿推拿', '耳穴治疗', '防感香囊', '食疗指导'],
          price: 200,
          color: 'primary',
          applicableAge: '0-6岁'
        }
      }
      },
      packageOptions: []
    }
  },
  created() {
    this.initPackageOptions()
    this.getList()
    this.calculateStats()
  },
  methods: {
    // 生成更真实的模拟数据
   // 精简后的模拟数据生成方法
// 优化后的模拟数据生成方法
generateMockData() {
  const mockData = []
    // 初始化套餐选项
    initPackageOptions() {
      this.packageOptions = Object.keys(this.servicePackages).map(key => ({
        id: key,
        name: this.servicePackages[key].name
      }))
    },
  // 使用您提供的真实姓名列表
  const patientNames = [
    '李肇芬', '卢木仲', '李成白', '方兆玉', '刘翊惠', '丁汉臻', '吴佳瑞', '舒绿珮',
    '周白芷', '张姿妤', '张虹伦', '周琼玟', '倪怡芳', '郭贵妃', '杨佩芳', '黄文旺',
    '黄盛玫', '郑丽青', '许智云', '张孟涵', '李小爱', '王恩龙', '朱政廷', '邓诗涵',
    '陈政倩', '吴俊伯', '阮馨学', '翁惠珠', '吴思翰', '林佩玲'
  ]
    // 生成模拟数据
    generateMockData() {
      const mockData = []
  const doctors = ['王医生', '李医生', '张医生', '刘医生', '陈医生']
  const cities = ['北京市', '上海市', '广州市', '深圳市', '杭州市', '南京市', '成都市']
  const areas = ['朝阳区', '海淀区', '浦东新区', '黄浦区', '天河区', '福田区', '西湖区']
      // 使用儿童姓名列表
      const patientNames = [
        '李小宝', '张小明', '王雨欣', '刘浩然', '陈思琪', '杨宇航', '黄诗涵', '赵天宇',
        '周小萌', '吴俊杰', '郑雅雯', '孙沐辰', '朱雨萱', '马浩宇', '胡可馨', '林俊熙',
        '郭子轩', '何欣怡', '高天佑', '梁静怡', '罗浩然', '宋雨泽', '唐语嫣', '许博文',
        '谢欣妍', '冯子默', '董雨桐', '萧天乐', '曹心怡', '袁嘉豪'
      ]
  // 生成约20条数据
  for (let i = 0; i < patientNames.length; i++) {
    const packageId = (i % 5) + 1 + ''
    const packageInfo = this.servicePackages[packageId]
      const doctors = ['王医生', '李医生', '张医生', '刘医生', '陈医生']
      const cities = ['北京市', '上海市', '广州市', '深圳市', '杭州市', '南京市', '成都市']
      const areas = ['朝阳区', '海淀区', '浦东新区', '黄浦区', '天河区', '福田区', '西湖区']
    // 生成更合理的签约时间(过去1年内)
    const signDate = this.generateRandomDate('2023-12-01', '2024-11-30')
    const contractPeriod = [1, 2][i % 2] // 1年或2年合同
    const expireDate = this.addYears(signDate, contractPeriod)
    const remainingDays = this.calculateRemainingDays(expireDate)
    const contractStatus = this.getContractStatus(expireDate, remainingDays)
      for (let i = 0; i < patientNames.length; i++) {
        const packageId = (i % 6) + 1 + ''
        const packageInfo = this.servicePackages[packageId]
    // 生成更真实的电话号码和身份证号
    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
        }
    // 生成合理的年龄(20-80岁)
    const age = 20 + (i % 60)
    const birthYear = new Date().getFullYear() - age
    const idCard = `11010${birthYear}${this.padNumber(1 + (i % 12), 2)}${this.padNumber(1 + (i % 28), 2)}${this.padNumber(i % 1000, 3)}X`
        // 生成签约时间(过去1年内)
        const signDate = this.generateRandomDate('2023-12-01', '2024-11-30')
        const contractPeriod = [1, 2][i % 2] // 1年或2年合同
        const expireDate = this.addYears(signDate, contractPeriod)
        const remainingDays = this.calculateRemainingDays(expireDate)
        const contractStatus = this.getContractStatus(expireDate, remainingDays)
    mockData.push({
      id: `P${2024000 + i}`,
      patientName: patientNames[i],
      gender: i % 2 === 0 ? '男' : '女',
      age: age,
      phone: phone,
      idCard: idCard,
      doctorName: doctors[i % doctors.length],
      servicePackageId: packageId,
      servicePackage: packageInfo.name,
      services: packageInfo.services,
      contractPeriod: contractPeriod,
      signDate: signDate,
      expireDate: expireDate,
      remainingDays: remainingDays,
      contractStatus: contractStatus,
      address: `${cities[i % cities.length]}${areas[i % areas.length]}${this.generateStreet(i)}` // 新增地址字段
    })
  }
        // 生成电话号码(使用家长电话)
        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)}`
  return mockData
},
        // 生成儿童身份证号
        const birthYear = new Date().getFullYear() - age
        const idCard = `11010${birthYear}${this.padNumber(1 + (i % 12), 2)}${this.padNumber(1 + (i % 28), 2)}${this.padNumber(i % 1000, 3)}X`
// 新增辅助方法:生成街道地址
generateStreet(index) {
  const streets = [
    '中山路123号', '人民路456号', '解放路789号', '建设路101号', '和平路202号',
    '新华路303号', '光明路404号', '幸福路505号', '团结路606号', '文明路707号'
  ]
  return streets[index % streets.length]
},
        mockData.push({
          id: `C${2024000 + i}`,
          patientName: patientNames[i],
          gender: i % 2 === 0 ? '男' : '女',
          age: age,
          phone: phone,
          idCard: idCard,
          doctorName: doctors[i % doctors.length],
          servicePackageId: packageId,
          servicePackage: packageInfo.name,
          services: packageInfo.services,
          contractPeriod: contractPeriod,
          signDate: signDate,
          expireDate: expireDate,
          remainingDays: remainingDays,
          contractStatus: contractStatus,
          applicableAge: packageInfo.applicableAge,
          address: `${cities[i % cities.length]}${areas[i % areas.length]}${this.generateStreet(i)}`
        })
      }
    // 辅助方法
      return mockData
    },
    // 辅助方法保持不变
    generateStreet(index) {
      const streets = [
        '中山路123号', '人民路456号', '解放路789号', '建设路101号', '和平路202号',
        '新华路303号', '光明路404号', '幸福路505号', '团结路606号', '文明路707号'
      ]
      return streets[index % streets.length]
    },
    generateRandomDate(start, end) {
      const startDate = new Date(start).getTime()
      const endDate = new Date(end).getTime()
@@ -336,11 +383,10 @@
    async getList() {
      this.loading = true
      try {
        // 模拟API调用延迟
        await new Promise(resolve => setTimeout(resolve, 500))
        const allData = this.generateMockData()
        // 简单的本地筛选
        // 筛选逻辑
        let filteredData = allData.filter(item => {
          if (this.queryParams.patientName &&
              !item.patientName.includes(this.queryParams.patientName)) {
@@ -393,7 +439,10 @@
    },
    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'
    },
@@ -425,13 +474,12 @@
    },
    handleView(row) {
      this.$message.info(`查看患者 ${row.patientName} 的详情`)
      this.$message.info(`查看儿童 ${row.patientName} 的详情`)
      // 实际开发中跳转到详情页
      // this.$router.push({ path: '/patient/contract/detail', query: { id: row.id } })
    },
    handleRenew(row) {
      this.$confirm(`确定要为患者 ${row.patientName} 办理续约吗?`, '提示', {
      this.$confirm(`确定要为儿童 ${row.patientName} 办理续约吗?`, '提示', {
        type: 'warning'
      }).then(() => {
        this.$message.success('续约操作成功')
@@ -458,6 +506,10 @@
  .search-card {
    margin-bottom: 20px;
    ::v-deep .el-form-item {
      margin-bottom: 0;
    }
  }
  .stats-row {
@@ -487,11 +539,13 @@
    .patient-name {
      font-weight: 600;
      margin-bottom: 4px;
      color: #2c3e50;
    }
    .patient-detail {
      font-size: 12px;
      color: #666;
      line-height: 1.4;
    }
  }
@@ -509,4 +563,23 @@
    color: #67C23A;
  }
}
// 响应式设计
@media (max-width: 768px) {
  .signed-patient-page {
    padding: 10px;
    .search-card {
      ::v-deep .el-col {
        margin-bottom: 10px;
      }
    }
    .stats-row {
      .el-col {
        margin-bottom: 10px;
      }
    }
  }
}
</style>