Explorar o código

feat(patient): 实现患者端个人中心页面及跳转逻辑

- 新增患者个人中心页面及路由配置
- 实现根据用户角色跳转不同个人中心页面逻辑
- 更新tab-bar点击事件处理,增加登录状态和角色判断
- 修改患者首页功能项点击跳转逻辑
- 调整个人信息完善页面跳转路径
- 移除公共个人中心页面的基础信息和建档信息菜单项
- 增加患者端个人信息提交成功后跳转至患者个人中心首页逻辑
- 删除原公共个人中心基础信息和建档信息页面文件
mcbaiyun hai 1 mes
pai
achega
be1bd366a5

+ 12 - 3
src/components/tab-bar.vue

@@ -56,9 +56,18 @@ const onTabClick = (index: number) => {
       }
       break
     case 2: // 个人中心
-      uni.switchTab({
-        url: '/pages/public/profile/index'
-      })
+      try {
+        const logged = checkLogin()
+        const role = logged ? getRole() : null
+        if (logged && role === 3) {
+          uni.switchTab({ url: '/pages/patient/profile/index' })
+        } else {
+          uni.switchTab({ url: '/pages/public/profile/index' })
+        }
+      } catch (err) {
+        console.error('tab click profile redirect error', err)
+        uni.switchTab({ url: '/pages/public/profile/index' })
+      }
       break
   }
 }

+ 12 - 2
src/pages.json

@@ -62,13 +62,19 @@
 			}
 		},
 		{
-			"path": "pages/public/profile/infos/base-info",
+			"path": "pages/patient/profile/index",
+			"style": {
+				"navigationBarTitleText": "个人中心-患者端"
+			}
+		},
+		{
+			"path": "pages/patient/profile/infos/base-info",
 			"style": {
 				"navigationBarTitleText": "基本信息设定"
 			}
 		},
 		{
-			"path": "pages/public/profile/infos/patient-filing",
+			"path": "pages/patient/profile/infos/patient-filing",
 			"style": {
 				"navigationBarTitleText": "建档信息设定"
 			}
@@ -110,6 +116,10 @@
 			{
 				"pagePath": "pages/public/profile/index",
 				"text": "个人中心"
+			},
+			{
+				"pagePath": "pages/patient/profile/index",
+				"text": "个人中心-患者端"
 			}
 		]
 	}

+ 17 - 5
src/pages/patient/index/index.vue

@@ -18,7 +18,7 @@
 
       <view class="function-container">
         <view class="function-row">
-          <view class="function-item green">
+          <view class="function-item green" @click="onItemClick('我的医生')">
             <view class="item-content">
               <view class="title-row">
                 <view class="item-line"></view>
@@ -27,7 +27,7 @@
               <text class="item-desc">一键预约复诊</text>
             </view>
           </view>
-          <view class="function-item blue">
+          <view class="function-item blue" @click="onItemClick('疑问解答')">
             <view class="item-content">
               <view class="title-row">
                 <view class="item-line"></view>
@@ -39,7 +39,7 @@
 
         </view>
         <view class="function-row">
-          <view class="function-item orange">
+          <view class="function-item orange" @click="onItemClick('提醒管理')">
             <view class="item-content">
               <view class="title-row">
                 <view class="item-line"></view>
@@ -48,7 +48,7 @@
               <text class="item-desc">管理您的健康提醒</text>
             </view>
           </view>
-          <view class="function-item purple">
+          <view class="function-item purple" @click="onItemClick('个人中心')">
             <view class="item-content">
               <view class="title-row">
                 <view class="item-line"></view>
@@ -174,7 +174,7 @@ const fetchUserInfo = async () => {
       user.value = resp.data
       uni.setStorageSync('user_info', resp.data)
       if (!resp.data.nickname || !resp.data.avatar) {
-        uni.navigateTo({ url: '/pages/public/profile/infos/base-info' })
+        uni.navigateTo({ url: '/pages/patient/profile/infos/base-info' })
       }
     }
   } catch (err) {
@@ -202,6 +202,18 @@ function handleScan(res: any) {
   } else {
     uni.showToast({ title: '未识别到有效内容', icon: 'none' })
   }
+}
+
+function onItemClick(type: string) {
+  if (type === '个人中心') {
+    uni.switchTab({ url: '/pages/patient/profile/index' })
+  }
+  if (type === '提醒管理') {
+    uni.navigateTo({ url: '/pages/patient/health/reminder' })
+  }
+  else {
+    uni.showToast({ title: '功能正在开发中', icon: 'none' })
+  }
 }</script>
 
 <style>

+ 3 - 3
src/pages/patient/profile/index.vue

@@ -116,7 +116,7 @@ const fetchUserInfo = async () => {
       uni.setStorageSync('user_info', resp.data)
       // 检查 nickname 和 avatar
       if (!resp.data.nickname || !resp.data.avatar) {
-        uni.navigateTo({ url: '/pages/public/profile/infos/base-info' })
+        uni.navigateTo({ url: '/pages/patient/profile/infos/base-info' })
       }
     }
   } catch (err) {
@@ -140,12 +140,12 @@ const onMenuClick = (type: string) => {
   console.log('Menu clicked:', type)
   if (type === 'base-info') {
     // 跳转到修改个人信息页面
-    uni.navigateTo({ url: '/pages/public/profile/infos/base-info' })
+    uni.navigateTo({ url: '/pages/patient/profile/infos/base-info' })
     return
   }
   if (type === 'patient-filing') {
     // 跳转到建档信息设定页面
-    uni.navigateTo({ url: '/pages/public/profile/infos/patient-filing' })
+    uni.navigateTo({ url: '/pages/patient/profile/infos/patient-filing' })
     return
   }
   uni.showToast({

+ 1 - 1
src/pages/patient/profile/infos/base-info.vue

@@ -309,7 +309,7 @@ const onSubmit = async () => {
     if (resp && resp.code === 200) {
       uni.showToast({ title: '信息更新成功', icon: 'success' })
       setTimeout(() => {
-        uni.navigateBack()
+        uni.switchTab({ url: '/pages/patient/profile/index' })
       }, 1500)
     } else {
       throw new Error('Update failed')

+ 12 - 22
src/pages/public/profile/index.vue

@@ -18,14 +18,6 @@
 
 
     <view class="menu-list">
-      <view class="menu-item" @click="onMenuClick('base-info')">
-        <text class="menu-text">基本信息设定</text>
-        <text class="menu-arrow"></text>
-      </view>
-            <view class="menu-item" @click="onMenuClick('patient-filing')">
-        <text class="menu-text">建档信息设定</text>
-        <text class="menu-arrow"></text>
-      </view>
       <view class="menu-item" @click="onMenuClick('settings')">
         <text class="menu-text">设置</text>
         <text class="menu-arrow"></text>
@@ -49,6 +41,7 @@ import { computed } from 'vue'
 import { onShow } from '@dcloudio/uni-app'
 import CustomNav from '@/components/custom-nav.vue'
 import TabBar from '@/components/tab-bar.vue'
+import { isLoggedIn as checkLogin, getRole } from '@/composables/useAuth'
 
 const title = ref('个人中心')
 
@@ -114,10 +107,6 @@ const fetchUserInfo = async () => {
       user.value = resp.data
       // 保存到本地存储
       uni.setStorageSync('user_info', resp.data)
-      // 检查 nickname 和 avatar
-      if (!resp.data.nickname || !resp.data.avatar) {
-        uni.navigateTo({ url: '/pages/public/profile/infos/base-info' })
-      }
     }
   } catch (err) {
     uni.hideLoading()
@@ -133,21 +122,22 @@ onShow(() => {
     uni.reLaunch({ url: '/pages/public/login/index' })
   } else {
     fetchUserInfo()
+    // 检查角色,如果是患者,跳转到患者个人中心
+    try {
+      const r = getRole()
+      if (r === 3) {
+        console.log('[profile/index] redirecting to patient profile, role=', r)
+        uni.reLaunch({ url: '/pages/patient/profile/index' })
+        return
+      }
+    } catch (err) {
+      console.error('检查角色时出错:', err)
+    }
   }
 })
 
 const onMenuClick = (type: string) => {
   console.log('Menu clicked:', type)
-  if (type === 'base-info') {
-    // 跳转到修改个人信息页面
-    uni.navigateTo({ url: '/pages/public/profile/infos/base-info' })
-    return
-  }
-  if (type === 'patient-filing') {
-    // 跳转到建档信息设定页面
-    uni.navigateTo({ url: '/pages/public/profile/infos/patient-filing' })
-    return
-  }
   uni.showToast({
     title: `${type} 功能开发中`,
     icon: 'none'

+ 0 - 516
src/pages/public/profile/infos/base-info.vue

@@ -1,516 +0,0 @@
-<template>
-  <CustomNav title="完善基本信息" leftType="home" />
-  <view class="complete-container">
-    <view class="form-section">
-      <view class="avatar-section">
-        <view class="avatar">
-          <button
-            class="avatar-wrapper"
-            :class="{ disabled: isChoosing }"
-            :disabled="isChoosing"
-            open-type="chooseAvatar"
-            @tap="startChooseAvatar"
-            @chooseavatar="onChooseAvatar"
-          >
-            <view class="avatar-frame">
-              <image v-if="form.avatar" class="avatar-img" :src="form.avatar" mode="aspectFill" />
-              <text v-else class="avatar-placeholder">点击选择头像</text>
-            </view>
-          </button>
-        </view>
-      </view>
-
-      <view class="form-item">
-        <text class="label">姓名</text>
-        <input class="input" type="nickname" v-model="form.nickname" placeholder="请输入姓名" />
-      </view>
-
-      <view class="form-item">
-        <text class="label">手机号</text>
-        <input class="input" v-model="form.phone" placeholder="请输入手机号" type="number" />
-      </view>
-
-      <view class="form-item">
-        <text class="label">年龄</text>
-        <input class="input" v-model="form.age" placeholder="请输入年龄" type="number" />
-      </view>
-
-      <view class="form-item">
-        <text class="label">性别</text>
-        <view class="radio-group">
-          <label class="radio-item" @click="form.sex = 1">
-            <radio :checked="form.sex === 1" color="#07C160" />
-            <text>男</text>
-          </label>
-          <label class="radio-item" @click="form.sex = 2">
-            <radio :checked="form.sex === 2" color="#07C160" />
-            <text>女</text>
-          </label>
-        </view>
-      </view>
-
-      <view class="form-item">
-        <text class="label">省/市</text>
-        <view class="location-section">
-          <picker mode="region" :value="region" @change="onRegionChange">
-            <view class="picker">{{ region.join(' ') || '请选择省/市' }}</view>
-          </picker>
-          <button class="get-location-btn" @click="getCurrentLocation" :disabled="gettingLocation">
-            {{ gettingLocation ? '获取中...' : '使用当前定位' }}
-          </button>
-        </view>
-      </view>
-
-
-
-      <view class="submit-section">
-        <button class="submit-btn" @click="onSubmit" :disabled="submitting">{{ submitting ? '提交中...' : '提交' }}</button>
-      </view>
-    </view>
-  </view>
-</template>
-
-<script setup lang="ts">
-import { ref } from 'vue'
-import { onShow } from '@dcloudio/uni-app'
-import CustomNav from '@/components/custom-nav.vue'
-
-const form = ref({
-  avatar: '',
-  nickname: '',
-  phone: '',
-  age: '',
-  sex: 0,
-  address: ''
-})
-
-const region = ref<string[]>([])
-const submitting = ref(false)
-const isChoosing = ref(false)
-const gettingLocation = ref(false)
-
-// 从后端拉取已有用户信息并填充表单
-const fetchUserInfo = async () => {
-  try {
-    const token = uni.getStorageSync('token')
-    if (!token) return
-    uni.showLoading({ title: '加载中...' })
-    const response = await uni.request({
-      url: 'https://wx.baiyun.work/user_info',
-      method: 'POST',
-      header: {
-        'Content-Type': 'application/json',
-        'Authorization': `Bearer ${token}`
-      },
-      data: {}
-    })
-    uni.hideLoading()
-    console.log('fetchUserInfo response:', response)
-    if (response.statusCode === 401) {
-      // 未授权,跳转登录
-      uni.removeStorageSync('token')
-      uni.reLaunch({ url: '/pages/public/login/index' })
-      return
-    }
-    const resp = response.data as any
-    if (resp && resp.code === 200 && resp.data) {
-      const d = resp.data
-      // 填充基本字段
-      form.value.avatar = d.avatar || form.value.avatar
-      form.value.nickname = d.nickname || form.value.nickname
-      form.value.phone = d.phone || form.value.phone
-      form.value.age = d.age || form.value.age
-      // sex 可能为 'MALE'/'FEMALE' 或数字/1/2
-      if (d.sex) {
-        if (typeof d.sex === 'string') {
-          const s = d.sex.toUpperCase()
-          form.value.sex = s === 'MALE' ? 1 : s === 'FEMALE' ? 2 : form.value.sex
-        } else if (typeof d.sex === 'number') {
-          form.value.sex = d.sex
-        }
-      }
-      // address 可能为 '重庆市 重庆市' 或包含空格,用空格或中文空格分割
-      if (d.address) {
-        const parts = String(d.address).split(/\s+/).filter(Boolean)
-        region.value = parts
-        form.value.address = parts.join(' ')
-      }
-    }
-  } catch (err) {
-    uni.hideLoading()
-    console.error('fetchUserInfo error:', err)
-  }
-}
-
-// 在页面显示时尝试填充
-onShow(() => {
-  fetchUserInfo()
-})
-
-
-const onChooseAvatar = (e: any) => {
-  console.log('onChooseAvatar called with event:', e)
-  try {
-    const detail = e?.detail
-    console.log('Event detail:', detail)
-    let url = ''
-    if (!detail) {
-      url = typeof e === 'string' ? e : ''
-      console.log('No detail, using event as string:', url)
-    } else if (typeof detail === 'string') {
-      url = detail
-      console.log('Detail is string:', url)
-    } else if (detail.avatarUrl) {
-      url = detail.avatarUrl
-      console.log('Using detail.avatarUrl:', url)
-    } else if (Array.isArray(detail) && detail[0]) {
-      url = detail[0]
-      console.log('Using first element of array:', url)
-    }
-    if (url) {
-      form.value.avatar = url
-      console.log('Avatar URL updated to:', form.value.avatar)
-    }
-    if (detail && detail.nickName && !form.value.nickname) {
-      form.value.nickname = detail.nickName
-      console.log('Nickname updated from detail:', form.value.nickname)
-    }
-  } catch (err) {
-    console.error('Error in onChooseAvatar:', err)
-  } finally {
-    isChoosing.value = false
-    console.log('isChoosing reset to false')
-  }
-}
-
-const startChooseAvatar = () => {
-  console.log('startChooseAvatar called, current isChoosing:', isChoosing.value)
-  if (isChoosing.value) {
-    console.log('Already choosing, ignoring')
-    return
-  }
-  isChoosing.value = true
-  console.log('isChoosing set to true')
-  setTimeout(() => {
-    isChoosing.value = false
-    console.log('Timeout: isChoosing reset to false')
-  }, 3000)
-}
-
-
-
-const onRegionChange = (e: any) => {
-  region.value = e.detail.value
-  form.value.address = region.value.join(' ')
-}
-
-const getCurrentLocation = async () => {
-  if (gettingLocation.value) return
-  gettingLocation.value = true
-  try {
-    // 获取经纬度
-    const locationRes = await uni.getLocation({ type: 'wgs84' })
-    const { latitude, longitude } = locationRes
-    console.log('getLocation success:', locationRes)
-
-    // 调用用户自己的地理编码接口
-    const token = uni.getStorageSync('token')
-    const geocodeRes = await uni.request({
-      url: `https://wx.baiyun.work/geo/nearest?latitude=${latitude}&longitude=${longitude}`,
-      method: 'GET',
-      header: {
-        'Authorization': `Bearer ${token}`
-      }
-    })
-
-    const data = geocodeRes.data as any
-    if (data && data.code === 200 && data.data) {
-      // 解析 data 字段中的 JSON 字符串
-      const addressData = JSON.parse(data.data)
-      if (addressData && addressData.province && addressData.city) {
-        region.value = [addressData.province, addressData.city, addressData.district].filter(Boolean)
-        form.value.address = region.value.join(' ')
-        uni.showToast({ title: '位置获取成功', icon: 'success' })
-      } else {
-        throw new Error('Invalid address data')
-      }
-    } else {
-      throw new Error('Geocode failed')
-    }
-  } catch (err) {
-    console.error('Get location error:', err)
-    uni.showToast({ title: '获取位置失败,请检查定位权限和网络', icon: 'none' })
-  } finally {
-    gettingLocation.value = false
-  }
-}
-
-const onSubmit = async () => {
-  if (submitting.value) return
-
-  // 检查所有必需字段
-  if (!form.value.avatar) {
-    uni.showToast({ title: '请选择头像', icon: 'none' })
-    return
-  }
-  if (!form.value.nickname) {
-    uni.showToast({ title: '请输入姓名', icon: 'none' })
-    return
-  }
-  // 姓名格式校验:2-30 个中文、字母、·或空格
-  const nameRegex = /^[\u4e00-\u9fa5A-Za-z·\s]{2,10}$/
-  if (!nameRegex.test(String(form.value.nickname))) {
-    uni.showToast({ title: '姓名格式不正确,请输入2-10位中文或字母', icon: 'none' })
-    return
-  }
-  if (!form.value.phone) {
-    uni.showToast({ title: '请输入手机号', icon: 'none' })
-    return
-  }
-  // 手机号格式(中国)校验
-  const phoneRegex = /^1[3-9]\d{9}$/
-  if (!phoneRegex.test(String(form.value.phone))) {
-    uni.showToast({ title: '手机号格式不正确', icon: 'none' })
-    return
-  }
-  if (!form.value.age) {
-    uni.showToast({ title: '请输入年龄', icon: 'none' })
-    return
-  }
-  // 年龄为 1-120 的整数
-  const ageNum = Number(form.value.age)
-  if (!Number.isInteger(ageNum) || ageNum < 1 || ageNum > 120) {
-    uni.showToast({ title: '年龄请输入1到120之间的整数', icon: 'none' })
-    return
-  }
-  if (!form.value.sex) {
-    uni.showToast({ title: '请选择性别', icon: 'none' })
-    return
-  }
-  if (!form.value.address) {
-    uni.showToast({ title: '请选择或自动获取省/市', icon: 'none' })
-    return
-  }
-
-  submitting.value = true
-  try {
-    const token = uni.getStorageSync('token')
-    const response = await uni.request({
-      url: 'https://wx.baiyun.work/update_user_info',
-      method: 'POST',
-      header: {
-        'Content-Type': 'application/json',
-        'Authorization': `Bearer ${token}`
-      },
-      data: form.value
-    })
-    console.log('Update response:', response)
-    const resp = response.data as any
-    if (resp && resp.code === 200) {
-      uni.showToast({ title: '信息更新成功', icon: 'success' })
-      setTimeout(() => {
-        uni.navigateBack()
-      }, 1500)
-    } else {
-      throw new Error('Update failed')
-    }
-  } catch (err) {
-    console.error('Update error:', err)
-    uni.showToast({ title: '更新失败', icon: 'error' })
-  } finally {
-    submitting.value = false
-  }
-}
-</script>
-
-<style>
-.complete-container {
-  min-height: 100vh;
-  /* 为固定在顶部的 CustomNav 留出空间(状态栏 + 导航栏 44px) */
-  padding-top: calc(var(--status-bar-height) + 44px + 40rpx);
-  /* 保留侧边与内部间距,使用 border-box 避免计算误差 */
-  padding-right: 40rpx;
-  padding-left: 40rpx;
-  /* 底部安全区:使用项目中声明的 --window-bottom 或 fallback */
-  padding-bottom: calc(var(--window-bottom, 0px) + 40rpx);
-  box-sizing: border-box;
-  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-}
-
-.form-section {
-  background-color: #fff;
-  border-radius: 20rpx;
-  padding: 40rpx;
-  width: 100%;
-  max-width: 600rpx;
-  box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.1);
-}
-
-.avatar-section {
-  display: flex;
-  justify-content: center;
-  margin-bottom: 40rpx;
-}
-
-.avatar {
-  width: 160rpx;
-  height: 160rpx;
-  border-radius: 90rpx;
-  background-color: #eee;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.avatar-wrapper {
-  width: 160rpx;
-  height: 160rpx;
-  border-radius: 90rpx;
-  overflow: hidden;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  padding: 0;
-  border: 2rpx solid #07C160;
-  background: #fff;
-}
-
-.avatar-wrapper.disabled {
-  opacity: 0.5;
-}
-
-.avatar-frame {
-  width: 100%;
-  height: 100%;
-  border-radius: 60rpx;
-  overflow: hidden;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.avatar-img {
-  width: 100%;
-  height: 100%;
-  object-fit: cover;
-}
-
-.avatar-placeholder {
-  color: #999;
-  font-size: 24rpx;
-}
-
-.form-item {
-  margin-bottom: 30rpx;
-}
-
-.label {
-  display: block;
-  font-size: 32rpx;
-  color: #333;
-  margin-bottom: 10rpx;
-}
-
-.input {
-  width: 100%;
-  height: 80rpx;
-  border: 1rpx solid #ddd;
-  border-radius: 8rpx;
-  padding: 0 20rpx;
-  font-size: 32rpx;
-  box-sizing: border-box;
-  max-width: 100%;
-}
-
-.phone-section {
-  display: flex;
-  align-items: center;
-}
-
-.get-phone-btn {
-  flex: 1;
-  height: 80rpx;
-  background: linear-gradient(135deg, #07C160 0%, #00A854 100%);
-  color: #fff;
-  border-radius: 8rpx;
-  font-size: 32rpx;
-  border: none;
-}
-
-.get-phone-btn:disabled {
-  opacity: 0.5;
-}
-
-.radio-group {
-  display: flex;
-  gap: 40rpx;
-}
-
-.radio-item {
-  display: flex;
-  align-items: center;
-  font-size: 32rpx;
-  color: #333;
-}
-
-picker {
-  width: 100%;
-  height: 80rpx;
-  border: 1rpx solid #ddd;
-  border-radius: 8rpx;
-  padding: 0 20rpx;
-  display: flex;
-  align-items: center;
-  font-size: 32rpx;
-  color: hsl(0, 0%, 20%);
-  box-sizing: border-box;
-  max-width: 100%;
-}
-
-.form-item, .picker, .input, .get-location-btn, .submit-btn {
-  box-sizing: border-box;
-}
-
-.location-section {
-  display: flex;
-  align-items: center;
-  gap: 20rpx;
-}
-
-.get-location-btn {
-  flex-shrink: 0;
-  height: 80rpx;
-  background: linear-gradient(135deg, #07C160 0%, #00A854 100%);
-  color: #fff;
-  border-radius: 8rpx;
-  font-size: 28rpx;
-  padding: 0 10rpx;
-  border: none;
-}
-
-.get-location-btn:disabled {
-  opacity: 0.5;
-}
-
-.submit-section {
-  margin-top: 60rpx;
-}
-
-.submit-btn {
-  width: 100%;
-  background: linear-gradient(135deg, #07C160 0%, #00A854 100%);
-  color: #fff;
-  border-radius: 12rpx;
-  font-size: 32rpx;
-  line-height: 80rpx;
-  border: none;
-}
-
-.submit-btn:disabled {
-  opacity: 0.5;
-}
-</style>

+ 0 - 291
src/pages/public/profile/infos/patient-filing.vue

@@ -1,291 +0,0 @@
-<template>
-  <CustomNav title="患者建档信息" leftType="home" />
-  <view class="complete-container">
-    <view class="form-section">
-      <text class="section-title">患者建档信息</text>
-
-      <!-- 吸烟饮酒史 -->
-      <view class="form-item">
-        <text class="label">吸烟史</text>
-        <picker mode="selector" :range="smokingOptions" :value="smokingIndex" range-key="label" @change="onSmokingChange">
-          <view class="picker">{{ smokingSelected ? smokingOptions[smokingIndex]?.label : '请点击选择' }}</view>
-        </picker>
-      </view>
-
-      <view class="form-item">
-        <text class="label">饮酒史</text>
-        <picker mode="selector" :range="drinkingOptions" :value="drinkingIndex" range-key="label" @change="onDrinkingChange">
-          <view class="picker">{{ drinkingSelected ? drinkingOptions[drinkingIndex]?.label : '请点击选择' }}</view>
-        </picker>
-      </view>
-
-      <!-- 疾病诊断 -->
-      <view class="form-item">
-        <text class="label">疾病诊断</text>
-        <view class="disease-list">
-          <view class="disease-item" v-for="disease in diseases" :key="disease.key">
-            <text class="disease-label">{{ disease.label }}</text>
-            <switch :checked="diseaseHistory[disease.key]" @change="(e: any) => toggleDisease(disease.key, e.detail.value)" />
-          </view>
-        </view>
-      </view>
-
-      <!-- 用药情况 -->
-      <view class="form-item">
-        <text class="label">用药情况</text>
-        <textarea
-          v-model="medicationHistory"
-          placeholder="请输入用药情况"
-          class="input"
-        />
-      </view>
-
-      <!-- 过敏史 -->
-      <view class="form-item">
-        <view class="switch-row">
-          <text class="label">过敏史</text>
-          <switch :checked="hasAllergy" @change="(e: any) => hasAllergy = e.detail.value" />
-        </view>
-        <view v-if="hasAllergy" class="input-container">
-          <textarea
-            v-model="allergyHistory"
-            placeholder="请输入过敏史"
-            class="input"
-          />
-        </view>
-      </view>
-
-      <!-- 家族史 -->
-      <view class="form-item">
-        <view class="switch-row">
-          <text class="label">家族史</text>
-          <switch :checked="hasFamilyHistory" @change="(e: any) => hasFamilyHistory = e.detail.value" />
-        </view>
-        <view v-if="hasFamilyHistory" class="input-container">
-          <textarea
-            v-model="familyHistory"
-            placeholder="请输入家族史"
-            class="input"
-          />
-        </view>
-      </view>
-
-      <!-- 提交按钮 -->
-      <view class="submit-section">
-        <button class="submit-btn" @click="submitForm">提交</button>
-      </view>
-    </view>
-  </view>
-</template>
-
-<script setup lang="ts">
-import { ref } from 'vue'
-import CustomNav from '@/components/custom-nav.vue'
-
-// 吸烟选项
-const smokingOptions = [
-  { label: '否', value: 'no' },
-  { label: '偶尔(吸烟<1包/周)', value: 'occasional' },
-  { label: '经常', value: 'frequent' }
-]
-
-// 饮酒选项
-const drinkingOptions = [
-  { label: '否', value: 'no' },
-  { label: '偶尔(饮酒<1次/周)', value: 'occasional' },
-  { label: '经常', value: 'frequent' }
-]
-
-// 疾病列表
-const diseases = [
-  { key: 'diabetes', label: '糖尿病' },
-  { key: 'hypertension', label: '高血压' },
-  { key: 'dyslipidemia', label: '血脂异常' },
-  { key: 'coronaryHeartDisease', label: '冠心病' },
-  { key: 'cerebralInfarction', label: '脑梗塞' }
-]
-
-// 响应式数据
-const smokingHistory = ref('')
-const drinkingHistory = ref('')
-const smokingIndex = ref(0)
-const drinkingIndex = ref(0)
-const smokingSelected = ref(false)
-const drinkingSelected = ref(false)
-const diseaseHistory = ref<Record<string, boolean>>({
-  diabetes: false,
-  hypertension: false,
-  dyslipidemia: false,
-  coronaryHeartDisease: false,
-  cerebralInfarction: false
-})
-const medicationHistory = ref('')
-const allergyHistory = ref('')
-const familyHistory = ref('')
-const hasAllergy = ref(false)
-const hasFamilyHistory = ref(false)
-
-// 切换疾病状态
-const toggleDisease = (key: string, value: boolean) => {
-  diseaseHistory.value[key] = value
-}
-
-// picker change事件处理
-const onSmokingChange = (e: any) => {
-  smokingIndex.value = e.detail.value
-  smokingHistory.value = smokingOptions[smokingIndex.value].value
-  smokingSelected.value = true
-}
-
-const onDrinkingChange = (e: any) => {
-  drinkingIndex.value = e.detail.value
-  drinkingHistory.value = drinkingOptions[drinkingIndex.value].value
-  drinkingSelected.value = true
-}
-
-// 提交表单
-const submitForm = () => {
-  const formData = {
-    smokingHistory: smokingHistory.value,
-    drinkingHistory: drinkingHistory.value,
-    diseaseHistory: diseaseHistory.value,
-    medicationHistory: medicationHistory.value,
-    allergyHistory: hasAllergy.value ? allergyHistory.value : '',
-    familyHistory: hasFamilyHistory.value ? familyHistory.value : ''
-  }
-  console.log('提交的表单数据:', formData)
-  // 这里可以添加提交逻辑,比如调用API
-  uni.showToast({
-    title: '提交成功',
-    icon: 'success'
-  })
-}
-</script>
-
-<style>
-.complete-container {
-  min-height: 100vh;
-  /* 为固定在顶部的 CustomNav 留出空间(状态栏 + 导航栏 44px) */
-  padding-top: calc(var(--status-bar-height) + 44px + 40rpx);
-  /* 保留侧边与内部间距,使用 border-box 避免计算误差 */
-  padding-right: 40rpx;
-  padding-left: 40rpx;
-  /* 底部安全区:使用项目中声明的 --window-bottom 或 fallback */
-  padding-bottom: calc(var(--window-bottom, 0px) + 40rpx);
-  box-sizing: border-box;
-  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-}
-
-.form-section {
-  background-color: #fff;
-  border-radius: 20rpx;
-  padding: 40rpx;
-  width: 100%;
-  max-width: 600rpx;
-  box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.1);
-}
-
-.section-title {
-  font-size: 36rpx;
-  font-weight: bold;
-  color: #333;
-  margin-bottom: 40rpx;
-  display: block;
-  text-align: center;
-}
-
-.form-item {
-  margin-bottom: 30rpx;
-}
-
-.label {
-  display: block;
-  font-size: 32rpx;
-  color: #333;
-  margin-bottom: 10rpx;
-}
-
-.radio-group {
-  display: flex;
-  flex-wrap: wrap;
-  gap: 40rpx;
-  margin-bottom: 20rpx;
-}
-
-.radio-item {
-  display: flex;
-  align-items: center;
-  font-size: 32rpx;
-  color: #333;
-}
-
-.disease-list {
-  display: flex;
-  flex-direction: column;
-  gap: 20rpx;
-}
-
-.disease-item {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  padding: 20rpx;
-  background-color: #f9f9f9;
-  border-radius: 8rpx;
-}
-
-.disease-label {
-  font-size: 32rpx;
-  color: #333;
-}
-
-.input {
-  width: 100%;
-  height: 120rpx;
-  border: 1rpx solid #ddd;
-  border-radius: 8rpx;
-  padding: 20rpx;
-  font-size: 32rpx;
-  box-sizing: border-box;
-  max-width: 100%;
-}
-
-.picker {
-  width: 100%;
-  height: 80rpx;
-  border: 1rpx solid #ddd;
-  border-radius: 8rpx;
-  padding: 0 20rpx;
-  display: flex;
-  align-items: center;
-  font-size: 32rpx;
-  color: #333;
-  box-sizing: border-box;
-  max-width: 100%;
-}
-
-.switch-row {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 10rpx;
-}
-
-.input-container {
-  margin-top: 10rpx;
-}
-
-.submit-btn {
-  width: 100%;
-  background: linear-gradient(135deg, #07C160 0%, #00A854 100%);
-  color: #fff;
-  border-radius: 12rpx;
-  font-size: 32rpx;
-  line-height: 80rpx;
-  border: none;
-}
-</style>