Selaa lähdekoodia

添加合同到期提醒

unknown 1 kuukausi sitten
vanhempi
commit
f6f89a31af

+ 42 - 0
src/App.vue

@@ -1,4 +1,5 @@
 <script lang="ts" setup>
 <script lang="ts" setup>
+import { h, ref, computed, onMounted, onUnmounted } from 'vue'
 import { isDark } from '@/utils/is'
 import { isDark } from '@/utils/is'
 import { useAppStore } from '@/store/modules/app'
 import { useAppStore } from '@/store/modules/app'
 import { useDesign } from '@/hooks/web/useDesign'
 import { useDesign } from '@/hooks/web/useDesign'
@@ -6,6 +7,7 @@ import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
 import routerSearch from '@/components/RouterSearch/index.vue'
 import routerSearch from '@/components/RouterSearch/index.vue'
 import { useWatermark } from '@/hooks/web/useWatermark'
 import { useWatermark } from '@/hooks/web/useWatermark'
 import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
 import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
+import { Warning } from '@element-plus/icons-vue'
 import { useWebSocket } from '@/utils/useWebSocket'
 import { useWebSocket } from '@/utils/useWebSocket'
 import { amapReverseGeocode } from '@/utils/amapService'
 import { amapReverseGeocode } from '@/utils/amapService'
 import { getAccessToken } from '@/utils/auth'
 import { getAccessToken } from '@/utils/auth'
@@ -98,6 +100,39 @@ const { connect, disconnect, sendMessage } = useWebSocket({
   onOrderAlert: (alertData: any) => showStatsNotification(alertData)
   onOrderAlert: (alertData: any) => showStatsNotification(alertData)
 })
 })
 
 
+// 全局合同过期通知
+const contractNotificationVisible = ref(false)
+const contractNotificationData = ref<ContractNotificationData>({
+  title: '合同过期提醒',
+  message: '',
+  contracts: []
+})
+
+// 显示合同过期通知
+const showContractNotification = (data: ContractNotificationData) => {
+  contractNotificationData.value = {
+    title: data.title || '合同过期提醒',
+    message: data.message || '有合同已经过期,请进行处理',
+    contracts: data.contracts || []
+  }
+  contractNotificationVisible.value = true
+}
+
+// 关闭合同过期通知
+const closeContractNotification = () => {
+  contractNotificationVisible.value = false
+}
+
+// 处理查看合同详情
+const handleContractDetail = () => {
+  closeContractNotification()
+  // 跳转到合同管理页面
+  window.location.href = '/elderly/contract'
+}
+
+// 将通知方法挂载到全局,供其他页面调用
+;(window as any).$showContractNotification = showContractNotification
+
 
 
 
 
 const handleSOSAlert = async (alertData: any) => {
 const handleSOSAlert = async (alertData: any) => {
@@ -248,6 +283,13 @@ onUnmounted(() => {
       :stats="statsData"
       :stats="statsData"
       @close="closeStatsNotification"
       @close="closeStatsNotification"
     />
     />
+    <!-- 合同过期通知弹窗 -->
+    <GlobalWindowConcat
+      :visible="contractNotificationVisible"
+      :data="contractNotificationData"
+      @close="closeContractNotification"
+      @detail="handleContractDetail"
+    />
   </ConfigGlobal>
   </ConfigGlobal>
 </template>
 </template>
 
 

+ 122 - 0
src/api/living-home/elderly/index.ts

@@ -0,0 +1,122 @@
+import request from '@/config/axios'
+
+// ==================== 长者档案管理接口 ====================
+
+// 获取长者详情
+export const getElderDetail = (id: string | number) => {
+  return request.get({
+    url: `elderlyInfo/findDetailById?id=${id}`
+  })
+}
+
+// 新增长者档案
+export const addElder = (data: any) => {
+  return request.post({
+    url: 'elderlyInfo/addElder',
+    data
+  })
+}
+
+// 编辑长者档案
+export const updateElder = (data: any) => {
+  return request.post({
+    url: 'elderlyInfo/update',
+    data
+  })
+}
+
+// 删除长者档案
+export const deleteElder = (id: string | number) => {
+  return request.delete({
+    url: `elderlyInfo/delete?id=${id}`
+  })
+}
+
+// ==================== 服务人员接口 ====================
+
+// 获取服务人员列表(分页)
+export const getServicePersonPage = (params: any) => {
+  return request.get({
+    url: 'living-home/service-person/page',
+    params
+  })
+}
+
+// 获取服务人员列表(全部)
+export const getServicePersonList = (params?: any) => {
+  return request.get({
+    url: 'living-home/service-person/list',
+    params
+  })
+}
+
+// ==================== 应急人员接口 ====================
+
+// 获取应急人员列表(分页)
+export const getEmergencyPersonPage = (params: any) => {
+  return request.get({
+    url: 'living-home/emergency-person/page',
+    params
+  })
+}
+
+// 获取应急人员列表(全部)
+export const getEmergencyPersonList = (params?: any) => {
+  return request.get({
+    url: 'living-home/emergency-person/list',
+    params
+  })
+}
+
+// ==================== 附件接口 ====================
+
+// 上传长者附件
+export const uploadElderFile = (data: any) => {
+  return request.post({
+    url: 'living-home/elder-file/upload',
+    data
+  })
+}
+
+// 获取长者附件列表
+export const getElderFileList = (elderId: string | number) => {
+  return request.get({
+    url: `living-home/elder-file/list?elderId=${elderId}`
+  })
+}
+
+// 删除长者附件
+export const deleteElderFile = (id: string | number) => {
+  return request.delete({
+    url: `living-home/elder-file/delete?id=${id}`
+  })
+}
+
+// ==================== 账户信息接口 ====================
+
+// 获取长者账户信息
+export const getElderAccountInfo = (elderId: string | number) => {
+  return request.get({
+    url: `living-home/elder-account/info?elderId=${elderId}`
+  })
+}
+
+// 获取长者二维码
+export const getElderQrCode = (elderId: string | number) => {
+  return request.get({
+    url: `living-home/elder-account/qr-code?elderId=${elderId}`
+  })
+}
+
+// ==================== 小程序账号接口 ====================
+
+// 修改长者小程序密码
+export const updateElderPassword = (data: { elderId: string | number; password: string }) => {
+  return request.post({
+    url: 'living-home/elder-miniapp/update-password',
+    data
+  })
+}
+
+
+

+ 197 - 0
src/components/GlobalWindowConcat/index.vue

@@ -0,0 +1,197 @@
+<template>
+  <div v-if="visible" class="contract-notification" :class="{ 'show': visible }">
+    <div class="notification-content">
+      <div class="notification-header">
+        <h3 class="notification-title">
+          <el-icon class="warning-icon"><Warning /></el-icon>
+          {{ data.title }}
+        </h3>
+        <button class="close-btn" @click="handleClose">×</button>
+      </div>
+      <div class="notification-body">
+        <p class="notification-message">{{ data.message }}</p>
+        <div v-if="data.contracts && data.contracts.length > 0" class="contract-list">
+          <div v-for="(contract, index) in data.contracts" :key="index" class="contract-item">
+            <span class="contract-name">{{ contract.elderName || contract.name || '未知' }}</span>
+            <span class="contract-date">{{ contract.expireDate || contract.endDate || '' }}</span>
+          </div>
+        </div>
+        <div class="notification-actions">
+          <el-button type="primary" size="small" @click="handleDetail">已知晓</el-button>
+          <el-button size="small" @click="handleClose">稍后处理</el-button>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { Warning } from '@element-plus/icons-vue'
+
+// 合同过期通知数据类型
+export interface ContractNotificationData {
+  title?: string
+  message?: string
+  contracts?: {
+    elderName?: string
+    name?: string
+    expireDate?: string
+    endDate?: string
+  }[]
+}
+
+defineOptions({ name: 'GlobalWindowConcat' })
+
+const props = defineProps<{
+  visible: boolean
+  data: ContractNotificationData
+}>()
+
+const emit = defineEmits<{
+  close: []
+  detail: []
+}>()
+
+// 关闭弹窗
+const handleClose = () => {
+  emit('close')
+}
+
+// 查看详情
+const handleDetail = () => {
+  //emit('detail')
+  emit('close')
+}
+</script>
+
+<style scoped>
+.contract-notification {
+  position: fixed;
+  bottom: 20px;
+  right: 20px;
+  z-index: 9999;
+  opacity: 0;
+  transform: translateY(100px);
+  transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
+}
+
+.contract-notification.show {
+  opacity: 1;
+  transform: translateY(0);
+}
+
+.notification-content {
+  background: #ffffff;
+  border-radius: 8px;
+  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
+  overflow: hidden;
+  width: 360px;
+  animation: slideInUp 0.5s ease-out;
+}
+
+@keyframes slideInUp {
+  0% {
+    transform: translateY(200px);
+    opacity: 0;
+  }
+  100% {
+    transform: translateY(0);
+    opacity: 1;
+  }
+}
+
+.notification-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 12px 16px;
+  background-color: #fdf6ec;
+  border-bottom: 1px solid #f5dab1;
+}
+
+.notification-title {
+  margin: 0;
+  font-size: 16px;
+  font-weight: 600;
+  color: #e6a23c;
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.warning-icon {
+  font-size: 18px;
+}
+
+.close-btn {
+  background: none;
+  border: none;
+  font-size: 20px;
+  color: #909399;
+  cursor: pointer;
+  padding: 0;
+  width: 24px;
+  height: 24px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border-radius: 4px;
+  transition: all 0.2s;
+}
+
+.close-btn:hover {
+  background-color: #f5f7fa;
+  color: #606266;
+}
+
+.notification-body {
+  padding: 16px;
+}
+
+.notification-message {
+  margin: 0 0 12px 0;
+  color: #606266;
+  font-size: 14px;
+  line-height: 1.5;
+}
+
+.contract-list {
+  max-height: 150px;
+  overflow-y: auto;
+  margin-bottom: 12px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+  padding: 8px;
+}
+
+.contract-item {
+  display: flex;
+  justify-content: space-between;
+  padding: 6px 8px;
+  font-size: 13px;
+  border-bottom: 1px solid #ebeef5;
+}
+
+.contract-item:last-child {
+  border-bottom: none;
+}
+
+.contract-name {
+  color: #303133;
+  font-weight: 500;
+}
+
+.contract-date {
+  color: #909399;
+  font-size: 12px;
+}
+
+.notification-actions {
+  display: flex;
+  justify-content: flex-end;
+  gap: 8px;
+  margin-top: 12px;
+  padding-top: 12px;
+  border-top: 1px solid #ebeef5;
+}
+</style>

+ 34 - 0
src/views/Home/Index.vue

@@ -173,6 +173,8 @@ import MessageDrawer from './components/message-drawer.vue'
 import ProcessDetail from '@/views/bpm/task/process-list/detail.vue'
 import ProcessDetail from '@/views/bpm/task/process-list/detail.vue'
 import MyCommon from './MyCommon.vue'
 import MyCommon from './MyCommon.vue'
 import {getInstitutionDashboard} from "@/api/login";
 import {getInstitutionDashboard} from "@/api/login";
+import {getElderlyContract} from "@/api/elderly/elder/contract";
+import {formatTimestampYMD} from "@/utils/dateUtil";
 defineOptions({ name: 'Home' })
 defineOptions({ name: 'Home' })
 const { push } = useRouter()
 const { push } = useRouter()
 const { t } = useI18n()
 const { t } = useI18n()
@@ -586,10 +588,42 @@ const getTodoCount = async () => {
   todoTotal.value = res.todoCount
   todoTotal.value = res.todoCount
 }
 }
 
 
+const queryParamsContract = reactive({
+  pageNo: 1,
+  pageSize: 100,
+  elderName: undefined,
+  type: 0,
+  inStatusType: undefined,
+  tenantIds: userStore.orgTenantId
+})
+//合同过期检测
+const getContractList = async () => {
+  loading.value = true
+  try {
+    const data = await getElderlyContract(queryParamsContract)
+    if (data.list && data.list.length > 0) {
+      // 使用全局通知弹窗
+      if ((window as any).$showContractNotification) {
+        (window as any).$showContractNotification({
+          title: '合同过期提醒',
+          message: `检测到 ${data.list.length} 位长者的合同已过期,请及时处理!`,
+          contracts: data.list.map((item: any) => ({
+            elderName: item.elderName || item.name,
+            expireDate: formatTimestampYMD(item.expireTime)
+          }))
+        })
+      }
+    }
+  } finally {
+    loading.value = false
+  }
+}
+
 onMounted(() => {
 onMounted(() => {
   getTodoList()
   getTodoList()
   getMyList()
   getMyList()
   getTodoCount()
   getTodoCount()
+  getContractList()
   commonList.value = JSON.parse(localStorage.getItem('common-icon')) || []
   commonList.value = JSON.parse(localStorage.getItem('common-icon')) || []
 })
 })
 </script>
 </script>

+ 38 - 0
src/views/elderly/elder/contract/index.vue

@@ -76,6 +76,7 @@ import Form from './Form.vue'
 import Renewal from './Renewal.vue'
 import Renewal from './Renewal.vue'
 import Detail from './Detail.vue'
 import Detail from './Detail.vue'
 import { useUserStore } from '@/store/modules/user'
 import { useUserStore } from '@/store/modules/user'
+import {formatTimestampYMD} from "@/utils/dateUtil";
 defineOptions({ name: 'Contract' })
 defineOptions({ name: 'Contract' })
 const userStore = useUserStore()
 const userStore = useUserStore()
 const message = useMessage() // 消息弹窗
 const message = useMessage() // 消息弹窗
@@ -137,6 +138,38 @@ const openDetail = (row: any = {}) => {
   detailRef.value.open(row.id)
   detailRef.value.open(row.id)
 }
 }
 
 
+
+const queryParamsContract = reactive({
+  pageNo: 1,
+  pageSize: 100,
+  elderName: undefined,
+  type: 0,
+  inStatusType: undefined,
+  tenantIds: userStore.orgTenantId
+})
+//合同过期
+const getContractList = async () => {
+  loading.value = true
+  try {
+    const data = await getElderlyContract(queryParamsContract)
+    if(data.list && data.list.length>0){
+      if ((window as any).$showContractNotification) {
+        (window as any).$showContractNotification({
+          title: '合同过期提醒',
+          message: `检测到 ${data.list.length} 位长者的合同已过期,请及时处理!`,
+          contracts: data.list.map((item: any) => ({
+            elderName: item.elderName || item.name,
+            expireDate: formatTimestampYMD(item.expireTime)
+          }))
+        })
+      }
+    }
+
+  } finally {
+    loading.value = false
+  }
+}
+
 const route = useRoute()
 const route = useRoute()
 /** 初始化 **/
 /** 初始化 **/
 onMounted(() => {
 onMounted(() => {
@@ -145,5 +178,10 @@ onMounted(() => {
     openForm({elderId: route.query.id, tenantId: route.query.tenantId}, 2)
     openForm({elderId: route.query.id, tenantId: route.query.tenantId}, 2)
   }
   }
   getList()
   getList()
+  getContractList()
 })
 })
+
+
+
+
 </script>
 </script>

+ 2051 - 0
src/views/living-home/elderlyManage/elderly-person-file-in/Form.vue

@@ -0,0 +1,2051 @@
+<template>
+  <Dialog
+    v-model="dialogVisible"
+    :title="titleName"
+    width="90%"
+    class="form-tag-dialog elderly-form-dialog"
+    scroll
+    @close="handleClosed"
+  >
+    <el-form
+      ref="formRef"
+      :model="dataForm"
+      :rules="dataRule"
+      label-width="130px"
+      class="elderly-form-content"
+      :disabled="isDetail"
+    >
+      <!-- 账户余额和二维码区域 - 仅在编辑和详情时显示 -->
+      <div class="info-section account-section" v-if="dataForm.id">
+        <el-row :gutter="20">
+          <el-col :xs="24" :sm="16" :md="18">
+            <div class="account-info-wrap">
+              <div class="account-title">
+                <span class="title-line"></span>
+                <span>账户信息</span>
+              </div>
+              <div class="account-balance-list">
+                <div class="balance-item">
+                  <span class="balance-label">账户余额:</span>
+                  <span class="balance-value">{{ dataForm.accountBalance || 0 }}元</span>
+                </div>
+                <div class="balance-item">
+                  <span class="balance-label">代金券:</span>
+                  <span class="balance-value">{{ dataForm.voucherBalance || 0 }}元</span>
+                </div>
+                <div class="balance-item">
+                  <span class="balance-label">现 金:</span>
+                  <span class="balance-value">{{ dataForm.cashBalance || 0 }}元</span>
+                </div>
+              </div>
+            </div>
+          </el-col>
+          <el-col :xs="24" :sm="8" :md="6">
+            <div class="qr-code-wrap">
+              <div class="qr-code-img">
+                <img v-if="dataForm.qrCodeUrl" :src="dataForm.qrCodeUrl" alt="长者码" />
+                <div v-else class="qr-code-placeholder">
+                  <Icon icon="ep:picture" :size="60" />
+                </div>
+              </div>
+              <div class="qr-code-text">长者码</div>
+              <el-button type="primary" link size="small" @click="viewIntro">
+                点击查看介绍>>
+              </el-button>
+            </div>
+          </el-col>
+        </el-row>
+      </div>
+
+      <!-- 基本信息 -->
+      <div class="info-section">
+        <div class="info-title">
+          <span class="title-line"></span>
+          <span>基本信息</span>
+        </div>
+        <div class="info-wrap">
+          <el-row :gutter="24">
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="长者姓名" prop="elderName">
+                <template v-if="isDetail">{{ dataForm.elderName }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.elderName"
+                  placeholder="请输入姓名"
+                  clearable
+                  maxlength="10"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="身份证类型" prop="papersType">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.PAPERS_TYPE, dataForm.papersType) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.papersType"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.PAPERS_TYPE)"
+                >
+                  <el-option
+                    v-for="(item, index) in getIntDictOptions(DICT_TYPE.PAPERS_TYPE)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="身份证号" prop="idCard">
+                <template v-if="isDetail">{{ dataForm.idCard }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.idCard"
+                  placeholder="请输入证件号"
+                  clearable
+                  maxlength="18"
+                  @change="handleIdCardChange"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="手机号码" prop="personalPhone">
+                <template v-if="isDetail">{{ dataForm.personalPhone }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.personalPhone"
+                  placeholder="请输入手机号码"
+                  clearable
+                  maxlength="11"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="现居住区域" prop="currentArea">
+                <template v-if="isDetail">{{ dataForm.currentArea }}</template>
+                <el-cascader
+                  v-else
+                  v-model="dataForm.currentArea"
+                  :options="areaTree"
+                  :props="defaultProps"
+                  class="w-1/1"
+                  clearable
+                  placeholder="请选择地区"
+                  filterable
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="现居住详细地址" prop="currentAddress">
+                <template v-if="isDetail">{{ dataForm.currentAddress }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.currentAddress"
+                  placeholder="请输入详细地址"
+                  clearable
+                  maxlength="100"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="户籍所在区域" prop="householdArea">
+                <template v-if="isDetail">{{ dataForm.householdArea }}</template>
+                <el-cascader
+                  v-else
+                  v-model="dataForm.householdArea"
+                  :options="areaTree"
+                  :props="defaultProps"
+                  class="w-1/1"
+                  clearable
+                  placeholder="请选择地区"
+                  filterable
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="户籍详细地址" prop="householdAddress">
+                <template v-if="isDetail">{{ dataForm.householdAddress }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.householdAddress"
+                  placeholder="请输入户籍详细地址"
+                  clearable
+                  maxlength="100"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 详细信息 -->
+      <div class="info-section">
+        <div class="info-title">
+          <span class="title-line"></span>
+          <span>详细信息</span>
+        </div>
+        <div class="info-wrap">
+          <el-row :gutter="24">
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="出生日期" prop="birthday">
+                <template v-if="isDetail">{{ dataForm.birthday }}</template>
+                <TgDatePicker
+                  v-else
+                  type="date"
+                  v-model="dataForm.birthday"
+                  placeholder="请选择出生日期"
+                  clearable
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="性别" prop="gender">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, dataForm.gender) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.gender"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+                >
+                  <el-option
+                    v-for="(item, index) in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="固定电话" prop="homeTel">
+                <template v-if="isDetail">{{ dataForm.homeTel }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.homeTel"
+                  placeholder="请输入固定电话"
+                  clearable
+                  maxlength="12"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="民族" prop="nationId">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.NATION_ARR, dataForm.nationId) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.nationId"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.NATION_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.NATION_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="婚姻状况" prop="maritalStatus">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.MARITAL_STATUS_ARR, dataForm.maritalStatus) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.maritalStatus"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.MARITAL_STATUS_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getIntDictOptions(DICT_TYPE.MARITAL_STATUS_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="职业" prop="occupation">
+                <template v-if="isDetail">{{ dataForm.occupation }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.occupation"
+                  placeholder="请输入职业"
+                  clearable
+                  maxlength="50"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="自理情况" prop="selfCareStatus">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.ABILITY_LEVEL_ARR, dataForm.selfCareStatus) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.selfCareStatus"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.ABILITY_LEVEL_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.ABILITY_LEVEL_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="文化程度" prop="degreeEducation">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.DEGREE_EDUCATION_ARR, dataForm.degreeEducation) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.degreeEducation"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.DEGREE_EDUCATION_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getIntDictOptions(DICT_TYPE.DEGREE_EDUCATION_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="残疾类型" prop="disabilityType">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.DISABILITY_ARR, dataForm.disabilityType) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.disabilityType"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.DISABILITY_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.DISABILITY_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="居住情况" prop="liveSituation">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.LIVE_ARR, dataForm.liveSituation) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.liveSituation"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.LIVE_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.LIVE_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="居住面积" prop="livingArea">
+                <template v-if="isDetail">{{ dataForm.livingArea }}</template>
+                <el-input
+                  v-else
+                  v-model="dataForm.livingArea"
+                  placeholder="请输入"
+                  clearable
+                  :controls="false"
+                  :precision="2"
+                  :max="9999"
+                >
+                  <template #append>㎡</template>
+                </el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="户籍类别" prop="householdType">
+                <template v-if="isDetail">{{ dataForm.householdType }}</template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.householdType"
+                  placeholder="请选择"
+                  clearable
+                  :list="householdTypeOptions"
+                >
+                  <el-option label="农业户口" value="农业户口" />
+                  <el-option label="非农业户口" value="非农业户口" />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="经济来源" prop="economySource">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.ECONOMY_SOURCE_ARR, dataForm.economySource) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.economySource"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.ECONOMY_SOURCE_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.ECONOMY_SOURCE_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="平均可支配月收入" prop="monthlyIncome">
+                <template v-if="isDetail">{{ dataForm.monthlyIncome }}</template>
+                <TgInputNumber
+                  v-else
+                  v-model="dataForm.monthlyIncome"
+                  placeholder="请输入"
+                  clearable
+                  :controls="false"
+                  :precision="2"
+                  :max="999999"
+                >
+                  <template #append>元</template>
+                </TgInputNumber>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="医疗类型" prop="medicalType">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.MEDICAL_INSURANCE_ARR, dataForm.medicalType) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.medicalType"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.MEDICAL_INSURANCE_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.MEDICAL_INSURANCE_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 意向养老方式 -->
+          <el-row :gutter="24" class="mt-20">
+            <el-col :span="24">
+              <el-form-item label="意向养老方式" prop="pensionWay">
+                <template v-if="isDetail">
+                  {{ dataForm.pensionWay }}
+                </template>
+                <TgRadio v-else v-model="dataForm.pensionWay" clearable>
+                  <el-radio value="机构养老">机构养老</el-radio>
+                  <el-radio value="社区养老">社区养老</el-radio>
+                  <el-radio value="居家养老">居家养老</el-radio>
+                  <el-radio value="老年大学">老年大学</el-radio>
+                  <el-radio value="旅居养老">旅居养老</el-radio>
+                  <el-radio value="其他">其他</el-radio>
+                </TgRadio>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 意向服务 -->
+          <el-row :gutter="24">
+            <el-col :span="24">
+              <el-form-item label="意向服务" prop="intentionService">
+                <template v-if="isDetail">{{ dataForm.intentionService }}</template>
+                <el-input
+                  v-else
+                  v-model="dataForm.intentionService"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入意向服务"
+                  clearable
+                  maxlength="500"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 分组标记 -->
+<!--          <el-row :gutter="24">-->
+<!--            <el-col :span="24">-->
+<!--              <el-form-item label="分组标记" prop="groupTag">-->
+<!--                <template v-if="isDetail">-->
+<!--                  {{ dataForm.groupTag === '1' ? '默认分组' : '其他' }}-->
+<!--                </template>-->
+<!--                <el-checkbox v-else v-model="dataForm.groupTag" true-label="1" false-label="0">-->
+<!--                  默认分组-->
+<!--                </el-checkbox>-->
+<!--              </el-form-item>-->
+<!--            </el-col>-->
+<!--          </el-row>-->
+
+          <!-- 痛点问题 -->
+          <el-row :gutter="24">
+            <el-col :span="24">
+              <el-form-item label="痛点问题" prop="painPoint">
+                <template v-if="isDetail">{{ dataForm.painPoint }}</template>
+                <el-input
+                  v-else
+                  v-model="dataForm.painPoint"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入痛点问题,如:老人长期独居,时常感到孤独抑郁。"
+                  clearable
+                  maxlength="500"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 跟踪记录 -->
+          <el-row :gutter="24">
+            <el-col :span="24">
+              <el-form-item label="跟踪记录" prop="trackRecord">
+                <template v-if="isDetail">{{ dataForm.trackRecord }}</template>
+                <el-input
+                  v-else
+                  v-model="dataForm.trackRecord"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入跟踪记录"
+                  clearable
+                  maxlength="500"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 地图位置 -->
+<!--          <el-row :gutter="24">-->
+<!--            <el-col :span="24">-->
+<!--              <el-form-item label="地图位置" prop="mapLocation">-->
+<!--                <template v-if="isDetail">{{ dataForm.mapLocation }}</template>-->
+<!--                <div v-else class="map-location-wrap">-->
+<!--                  <TgInput-->
+<!--                    v-model="dataForm.mapLocation"-->
+<!--                    placeholder="选择位置"-->
+<!--                    clearable-->
+<!--                    readonly-->
+<!--                    class="map-input"-->
+<!--                  />-->
+<!--                  <el-button type="primary" link @click="selectMapLocation">-->
+<!--                    <Icon icon="ep:location" />-->
+<!--                    选择位置-->
+<!--                  </el-button>-->
+<!--                </div>-->
+<!--              </el-form-item>-->
+<!--            </el-col>-->
+<!--          </el-row>-->
+
+          <!-- 其他选项 -->
+          <el-row :gutter="24">
+            <el-col :xs="24" :sm="8" :md="6">
+              <el-form-item label="外地迁入" prop="isMigrant">
+                <template v-if="isDetail">
+                  {{ dataForm.isMigrant === '1' ? '是' : '否' }}
+                </template>
+                <TgRadio v-else v-model="dataForm.isMigrant" clearable>
+                  <el-radio value="1">是</el-radio>
+                  <el-radio value="0">否</el-radio>
+                </TgRadio>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="8" :md="6">
+              <el-form-item label="是否本市户籍" prop="isLocalHousehold">
+                <template v-if="isDetail">
+                  {{ dataForm.isLocalHousehold === '1' ? '是' : '否' }}
+                </template>
+                <TgRadio v-else v-model="dataForm.isLocalHousehold" clearable>
+                  <el-radio value="1">是</el-radio>
+                  <el-radio value="0">否</el-radio>
+                </TgRadio>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="8" :md="6">
+              <el-form-item label="是否享家服务" prop="isEnjoyService">
+                <template v-if="isDetail">
+                  {{ dataForm.isEnjoyService === '1' ? '是' : '否' }}
+                </template>
+                <TgRadio v-else v-model="dataForm.isEnjoyService" clearable>
+                  <el-radio value="1">是</el-radio>
+                  <el-radio value="0">否</el-radio>
+                </TgRadio>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="8" :md="6">
+              <el-form-item label="年享家服务次数" prop="serviceTimes">
+                <template v-if="isDetail">{{ dataForm.serviceTimes }}</template>
+                <TgInputNumber
+                  v-else
+                  v-model="dataForm.serviceTimes"
+                  placeholder="请输入"
+                  clearable
+                  :controls="false"
+                  :min="0"
+                  :max="999"
+                >
+                  <template #append>次</template>
+                </TgInputNumber>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 健康信息 -->
+      <div class="info-section">
+        <div class="info-title">
+          <span class="title-line"></span>
+          <span>健康信息</span>
+        </div>
+        <div class="info-wrap">
+          <el-row :gutter="24">
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="健康状态" prop="healthStatus">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.ELDERLY_HEALTH_STATUS, dataForm.healthStatus) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.healthStatus"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.ELDERLY_HEALTH_STATUS)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.ELDERLY_HEALTH_STATUS)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="血型" prop="bloodType">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.BLOOD_TYPE, dataForm.bloodType) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.bloodType"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.BLOOD_TYPE)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.BLOOD_TYPE)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="医保卡号" prop="medicalCardNo">
+                <template v-if="isDetail">{{ dataForm.medicalCardNo }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.medicalCardNo"
+                  placeholder="最多只能输入20位"
+                  clearable
+                  maxlength="20"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="视力" prop="vision">
+                <template v-if="isDetail">{{ dataForm.vision }}</template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.vision"
+                  placeholder="请选择"
+                  clearable
+                  :list="visionOptions"
+                >
+                  <el-option label="正常" value="正常" />
+                  <el-option label="轻度障碍" value="轻度障碍" />
+                  <el-option label="中度障碍" value="中度障碍" />
+                  <el-option label="重度障碍" value="重度障碍" />
+                  <el-option label="失明" value="失明" />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="听力" prop="hearing">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.HEARING_ARR, dataForm.hearing) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.hearing"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.HEARING_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.HEARING_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 基础病 -->
+          <el-row :gutter="24">
+            <el-col :span="24">
+              <el-form-item label="基础病" prop="basicIllness">
+                <template v-if="isDetail">{{ dataForm.basicIllness }}</template>
+                <el-checkbox-group v-else v-model="dataForm.basicIllnessList">
+                  <el-checkbox label="高血糖">高血糖</el-checkbox>
+                  <el-checkbox label="高血压">高血压</el-checkbox>
+                  <el-checkbox label="心脏病">心脏病</el-checkbox>
+                  <el-checkbox label="脑血栓">脑血栓</el-checkbox>
+                  <el-checkbox label="冠心病">冠心病</el-checkbox>
+                  <el-checkbox label="关节炎">关节炎</el-checkbox>
+                  <el-checkbox label="风湿">风湿</el-checkbox>
+                  <el-checkbox label="其他">其他</el-checkbox>
+                </el-checkbox-group>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 病史 -->
+          <el-row :gutter="24">
+            <el-col :span="24">
+              <el-form-item label="病史" prop="medicalHistory">
+                <template v-if="isDetail">{{ dataForm.medicalHistory }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.medicalHistory"
+                  type="textarea"
+                  :rows="3"
+                  placeholder="请输入病史"
+                  clearable
+                  maxlength="500"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 紧急联系人信息 -->
+      <div class="info-section">
+        <div class="info-title">
+          <span class="title-line"></span>
+          <span>紧急联系人</span>
+        </div>
+        <div class="info-wrap">
+          <el-row :gutter="24">
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="紧急联系人姓名" prop="emergencyContactName">
+                <template v-if="isDetail">{{ dataForm.emergencyContactName }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.emergencyContactName"
+                  placeholder="请输入"
+                  clearable
+                  maxlength="10"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="身份证号" prop="emergencyContactIdCard">
+                <template v-if="isDetail">{{ dataForm.emergencyContactIdCard }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.emergencyContactIdCard"
+                  placeholder="请输入身份证号码"
+                  clearable
+                  maxlength="18"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="性别" prop="emergencyContactGender">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, dataForm.emergencyContactGender) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.emergencyContactGender"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+                >
+                  <el-option
+                    v-for="(item, index) in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="年龄" prop="emergencyContactAge">
+                <template v-if="isDetail">{{ dataForm.emergencyContactAge }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.emergencyContactAge"
+                  placeholder="由身份证号自动生成"
+                  clearable
+                  disabled
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="手机号码" prop="emergencyContactPhone">
+                <template v-if="isDetail">{{ dataForm.emergencyContactPhone }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.emergencyContactPhone"
+                  placeholder="请输入"
+                  clearable
+                  maxlength="11"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="固定电话" prop="emergencyContactTel">
+                <template v-if="isDetail">{{ dataForm.emergencyContactTel }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.emergencyContactTel"
+                  placeholder="请输入"
+                  clearable
+                  maxlength="12"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="是长者的" prop="emergencyContactRelation">
+                <template v-if="isDetail">{{ dataForm.emergencyContactRelation }}</template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.emergencyContactRelation"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.RELATIONSHIP_TYPES)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.RELATIONSHIP_TYPES)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="是否监护人" prop="emergencyContactIsGuardian">
+                <template v-if="isDetail">
+                  {{ dataForm.emergencyContactIsGuardian === '1' ? '是' : '否' }}
+                </template>
+                <TgRadio v-else v-model="dataForm.emergencyContactIsGuardian" clearable>
+                  <el-radio value="1">是</el-radio>
+                  <el-radio value="0">否</el-radio>
+                </TgRadio>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="16" :lg="12">
+              <el-form-item label="居住地址" prop="emergencyContactAddress">
+                <template v-if="isDetail">{{ dataForm.emergencyContactAddress }}</template>
+                <div v-else class="address-wrap">
+                  <el-cascader
+                    v-model="dataForm.emergencyContactArea"
+                    :options="areaTree"
+                    :props="defaultProps"
+                    clearable
+                    placeholder="请选择省市街道"
+                    filterable
+                    class="area-cascader"
+                  />
+                  <TgInput
+                    v-model="dataForm.emergencyContactAddress"
+                    placeholder="请输入详细地址:如街道、小区、楼栋、单元、房号"
+                    clearable
+                    style="width: 30vw;"
+                    maxlength="100"
+                    class="address-input"
+                  />
+                </div>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 亲属信息 -->
+      <div class="info-section">
+        <div style="display: flex;flex-direction: row;align-items: center">
+          <div class="info-title">
+            <div>
+              <span class="title-line"></span>
+              <span>亲属信息</span>
+            </div>
+          </div>
+          <el-button style="margin-left: 20px;margin-bottom: 16px" v-if="!isDetail" @click="addRelative" type="primary" plain >
+            <Icon icon="ep:plus" class="mr-5px" />添加亲属
+          </el-button>
+        </div>
+
+        <div class="info-wrap">
+          <div v-for="(item, index) in dataForm.relativesList" :key="index" class="relative-item">
+            <div class="relative-header">
+              <span class="relative-title">亲属 {{ index + 1 }}</span>
+              <el-button
+                v-if="!isDetail && dataForm.relativesList.length > 1"
+                @click="deleteRelative(index)"
+                type="danger"
+                link
+                size="small"
+              >
+                <Icon icon="ep:delete" />删除
+              </el-button>
+            </div>
+            <el-row :gutter="24">
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '亲属姓名' : ''" :prop="`relativesList.${index}.name`">
+                  <template v-if="isDetail">{{ item.name }}</template>
+                  <TgInput v-else v-model="item.name" placeholder="请输入" clearable maxlength="10" />
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '身份证号' : ''" :prop="`relativesList.${index}.idCard`">
+                  <template v-if="isDetail">{{ item.idCard }}</template>
+                  <TgInput v-else v-model="item.idCard" placeholder="请输入身份证号码" clearable maxlength="18" />
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '性别' : ''" :prop="`relativesList.${index}.gender`">
+                  <template v-if="isDetail">
+                    {{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, item.gender) }}
+                  </template>
+                  <TgSelect
+                    v-else
+                    v-model="item.gender"
+                    placeholder="请选择"
+                    clearable
+                    :list="getDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+                  >
+                    <el-option
+                      v-for="(opt, idx) in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+                      :key="idx"
+                      :label="opt.label"
+                      :value="opt.value"
+                    />
+                  </TgSelect>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '年龄' : ''" :prop="`relativesList.${index}.age`">
+                  <template v-if="isDetail">{{ item.age }}</template>
+                  <TgInput v-else v-model="item.age" placeholder="由身份证号自动生成" clearable disabled />
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '手机号码' : ''" :prop="`relativesList.${index}.phone`">
+                  <template v-if="isDetail">{{ item.phone }}</template>
+                  <TgInput v-else v-model="item.phone" placeholder="请输入" clearable maxlength="11" />
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '固定电话' : ''" :prop="`relativesList.${index}.tel`">
+                  <template v-if="isDetail">{{ item.tel }}</template>
+                  <TgInput v-else v-model="item.tel" placeholder="请输入" clearable maxlength="12" />
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '是长者的' : ''" :prop="`relativesList.${index}.relation`">
+                  <template v-if="isDetail">{{ item.relation }}</template>
+                  <TgSelect
+                    v-else
+                    v-model="item.relation"
+                    placeholder="请选择"
+                    clearable
+                    :list="getDictOptions(DICT_TYPE.RELATIONSHIP_TYPES)"
+                  >
+                    <el-option
+                      v-for="(opt, idx) in getStrDictOptions(DICT_TYPE.RELATIONSHIP_TYPES)"
+                      :key="idx"
+                      :label="opt.label"
+                      :value="opt.value"
+                    />
+                  </TgSelect>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '是否监护人' : ''" :prop="`relativesList.${index}.isGuardian`">
+                  <template v-if="isDetail">{{ item.isGuardian === '1' ? '是' : '否' }}</template>
+                  <TgRadio v-else v-model="item.isGuardian" clearable>
+                    <el-radio value="1">是</el-radio>
+                    <el-radio value="0">否</el-radio>
+                  </TgRadio>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="24" :md="16" :lg="12">
+                <el-form-item :label="index === 0 ? '居住地址' : ''" :prop="`relativesList.${index}.address`">
+                  <template v-if="isDetail">{{ item.address }}</template>
+                  <div v-else class="address-wrap">
+                    <el-cascader
+                      v-model="item.area"
+                      :options="areaTree"
+                      :props="defaultProps"
+                      clearable
+                      placeholder="请选择省市街道"
+                      filterable
+                      class="area-cascader"
+                    />
+                    <TgInput
+                      v-model="item.address"
+                      placeholder="请输入详细地址:如街道、小区、楼栋、单元、房号"
+                      clearable
+                      maxlength="100"
+                      style="width: 30vw;"
+                      class="address-input"
+                    />
+                  </div>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </div>
+        </div>
+      </div>
+
+      <!-- 服务人员信息 -->
+      <div class="info-section">
+        <div style="display: flex;flex-direction: row;align-items: center">
+          <div class="info-title flex-between">
+            <div>
+              <span class="title-line"></span>
+              <span>服务人员信息</span>
+            </div>
+          </div>
+          <el-button style="margin-bottom: 15px;margin-left: 20px" v-if="!isDetail" @click="openServicePersonDialog" type="primary" plain>
+            <Icon icon="ep:plus" class="mr-5px" />新增服务人员
+          </el-button>
+        </div>
+
+        <div class="info-wrap">
+          <div v-if="dataForm.servicePersonList.length === 0" class="empty-text">
+            尚未添加服务人员
+          </div>
+          <div v-for="(item, index) in dataForm.servicePersonList" :key="index" class="person-item">
+            <div class="person-header">
+              <span class="person-title">服务人员 {{ index + 1 }}</span>
+              <el-button
+                v-if="!isDetail"
+                @click="deleteServicePerson(index)"
+                type="danger"
+                link
+                size="small"
+              >
+                <Icon icon="ep:delete" />删除
+              </el-button>
+            </div>
+            <el-row :gutter="24">
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '姓名' : ''">
+                  <span>{{ item.name }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '性别' : ''">
+                  <span>{{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, item.gender) }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '年龄' : ''">
+                  <span>{{ item.age }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '手机号码' : ''">
+                  <span>{{ item.phone }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '服务区域' : ''">
+                  <span>{{ item.serviceArea }}</span>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </div>
+        </div>
+      </div>
+
+      <!-- 服务人员选择弹窗 -->
+      <el-dialog v-model="servicePersonDialogVisible" title="选择服务人员" width="60%" append-to-body>
+        <div class="search-form">
+          <el-form :inline="true" :model="servicePersonQueryParams" class="demo-form-inline">
+            <el-form-item label="姓名">
+              <el-input v-model="servicePersonQueryParams.name" placeholder="请输入姓名" clearable />
+            </el-form-item>
+            <el-form-item label="手机号码">
+              <el-input v-model="servicePersonQueryParams.phone" placeholder="请输入手机号码" clearable />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="searchServicePerson">查询</el-button>
+              <el-button @click="resetServicePersonQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+        <el-table
+          v-loading="servicePersonLoading"
+          :data="servicePersonList"
+          @selection-change="handleServicePersonSelectionChange"
+          max-height="400"
+        >
+          <el-table-column type="selection" width="55" />
+          <el-table-column prop="name" label="姓名" width="120" />
+          <el-table-column prop="gender" label="性别" width="80">
+            <template #default="scope">
+              {{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, scope.row.gender) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="age" label="年龄" width="80" />
+          <el-table-column prop="phone" label="手机号码" width="150" />
+          <el-table-column prop="serviceArea" label="服务区域" show-overflow-tooltip />
+        </el-table>
+        <template #footer>
+          <span class="dialog-footer">
+            <el-button @click="servicePersonDialogVisible = false">取消</el-button>
+            <el-button type="primary" @click="confirmServicePerson">确定</el-button>
+          </span>
+        </template>
+      </el-dialog>
+
+      <!-- 应急人员信息 -->
+      <div class="info-section">
+        <div style="display: flex;flex-direction: row;align-items: center">
+          <div class="info-title flex-between">
+            <div>
+              <span class="title-line"></span>
+              <span>应急人员信息</span>
+            </div>
+          </div>
+          <el-button style="margin-bottom: 15px;margin-left: 20px" v-if="!isDetail" @click="openEmergencyPersonDialog" type="primary" plain>
+            <Icon icon="ep:plus" class="mr-5px" />新增应急人员
+          </el-button>
+        </div>
+
+        <div class="info-wrap">
+          <div v-if="dataForm.emergencyPersonList.length === 0" class="empty-text">
+            尚未添加应急人员
+          </div>
+          <div v-for="(item, index) in dataForm.emergencyPersonList" :key="index" class="person-item">
+            <div class="person-header">
+              <span class="person-title">应急人员 {{ index + 1 }}</span>
+              <el-button
+                v-if="!isDetail"
+                @click="deleteEmergencyPerson(index)"
+                type="danger"
+                link
+                size="small"
+              >
+                <Icon icon="ep:delete" />删除
+              </el-button>
+            </div>
+            <el-row :gutter="24">
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '姓名' : ''">
+                  <span>{{ item.name }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '性别' : ''">
+                  <span>{{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, item.gender) }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '年龄' : ''">
+                  <span>{{ item.age }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '手机号码' : ''">
+                  <span>{{ item.phone }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '服务区域' : ''">
+                  <span>{{ item.serviceArea }}</span>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </div>
+        </div>
+      </div>
+
+      <!-- 应急人员选择弹窗 -->
+      <el-dialog v-model="emergencyPersonDialogVisible" title="选择应急人员" width="60%" append-to-body>
+        <div class="search-form">
+          <el-form :inline="true" :model="emergencyPersonQueryParams" class="demo-form-inline">
+            <el-form-item label="姓名">
+              <el-input v-model="emergencyPersonQueryParams.name" placeholder="请输入姓名" clearable />
+            </el-form-item>
+            <el-form-item label="手机号码">
+              <el-input v-model="emergencyPersonQueryParams.phone" placeholder="请输入手机号码" clearable />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="searchEmergencyPerson">查询</el-button>
+              <el-button @click="resetEmergencyPersonQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+        <el-table
+          v-loading="emergencyPersonLoading"
+          :data="emergencyPersonList"
+          @selection-change="handleEmergencyPersonSelectionChange"
+          max-height="400"
+        >
+          <el-table-column type="selection" width="55" />
+          <el-table-column prop="name" label="姓名" width="120" />
+          <el-table-column prop="gender" label="性别" width="80">
+            <template #default="scope">
+              {{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, scope.row.gender) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="age" label="年龄" width="80" />
+          <el-table-column prop="phone" label="手机号码" width="150" />
+          <el-table-column prop="serviceArea" label="服务区域" show-overflow-tooltip />
+        </el-table>
+        <template #footer>
+          <span class="dialog-footer">
+            <el-button @click="emergencyPersonDialogVisible = false">取消</el-button>
+            <el-button type="primary" @click="confirmEmergencyPerson">确定</el-button>
+          </span>
+        </template>
+      </el-dialog>
+
+      <!-- 其他信息 -->
+      <div class="info-section">
+        <div class="info-title">
+          <span class="title-line"></span>
+          <span>其他信息</span>
+        </div>
+        <div class="info-wrap">
+          <el-row :gutter="24">
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="登记人" prop="registerPerson" required>
+                <template v-if="isDetail">{{ dataForm.registerPerson }}</template>
+                <TgInput v-else v-model="dataForm.registerPerson" placeholder="请输入" clearable maxlength="10" />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="登记人电话" prop="registerPhone" required>
+                <template v-if="isDetail">{{ dataForm.registerPhone }}</template>
+                <TgInput v-else v-model="dataForm.registerPhone" placeholder="请输入" clearable maxlength="11" />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="登记时间" prop="registerTime" required>
+                <template v-if="isDetail">{{ dataForm.registerTime }}</template>
+                <TgDatePicker
+                  v-else
+                  type="datetime"
+                  v-model="dataForm.registerTime"
+                  placeholder="请选择"
+                  clearable
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="接待人员" prop="receivePerson">
+                <template v-if="isDetail">{{ dataForm.receivePerson }}</template>
+                <TgInput v-else v-model="dataForm.receivePerson" placeholder="请输入" clearable maxlength="10" />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 附件上传 -->
+      <div class="info-section">
+        <div class="info-title">
+          <span class="title-line"></span>
+          <span>附件</span>
+        </div>
+        <div class="info-wrap">
+          <el-form-item label="其他附件" prop="otherFiles">
+            <SelectUpload
+              fun-name="其他附件"
+              v-model="dataForm.otherFiles"
+              :elder="{ elderId: dataForm.id, elderName: dataForm.elderName }"
+              :isDetail="isDetail"
+            />
+          </el-form-item>
+        </div>
+      </div>
+    </el-form>
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button v-loading="formLoading" type="primary" @click="submitForm" v-if="!isDetail">提交</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import {
+  getElderDetail,
+  addElder,
+  updateElder,
+  getServicePersonPage,
+  getEmergencyPersonPage
+} from '@/api/living-home/elderly'
+import { DICT_TYPE, getDictLabel, getDictOptions, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
+import { FormRules } from 'element-plus'
+import { useValidator } from '@/hooks/web/useValidator'
+import { getInfo } from '@/utils'
+import { defaultProps } from '@/utils/tree'
+import * as AreaApi from '@/api/system/area'
+import { formatTime } from '@/utils'
+
+
+defineOptions({ name: 'ElderlyPersonFileForm' })
+const { idCardValidity, validatePhone } = useValidator()
+const message = useMessage()
+const dialogVisible = ref(false)
+const formLoading = ref(false)
+const isDetail = ref(false)
+const titleName = ref('')
+const formRef = ref()
+const areaTree = ref([])
+
+// 视力选项
+const visionOptions = [
+  { label: '正常', value: '正常' },
+  { label: '轻度障碍', value: '轻度障碍' },
+  { label: '中度障碍', value: '中度障碍' },
+  { label: '重度障碍', value: '重度障碍' },
+  { label: '失明', value: '失明' }
+]
+
+// 表单数据
+let dataForm = reactive({
+  id: '',
+  tenantId: undefined,
+  elderName: '',
+  papersType: 1,
+  idCard: '',
+  personalPhone: '',
+  currentArea: '',
+  currentAddress: '',
+  householdArea: '',
+  householdAddress: '',
+  birthday: '',
+  gender: 1,
+  homeTel: '',
+  nationId: '1',
+  maritalStatus: '',
+  occupation: '',
+  selfCareStatus: '',
+  degreeEducation: '',
+  disabilityType: '',
+  liveSituation: '',
+  livingArea: undefined,
+  householdType: '',
+  economySource: '',
+  monthlyIncome: undefined,
+  medicalType: '',
+  pensionWay: '',
+  intentionService: '',
+  groupTag: '1',
+  painPoint: '',
+  trackRecord: '',
+  mapLocation: '',
+  longitude: '',
+  latitude: '',
+  isMigrant: '0',
+  isLocalHousehold: '1',
+  isEnjoyService: '0',
+  serviceTimes: undefined,
+  // 健康信息
+  healthStatus: '',
+  bloodType: '',
+  medicalCardNo: '',
+  vision: '',
+  hearing: '',
+  basicIllness: '',
+  basicIllnessList: [],
+  medicalHistory: '',
+  // 紧急联系人
+  emergencyContactName: '',
+  emergencyContactIdCard: '',
+  emergencyContactGender: '',
+  emergencyContactAge: undefined,
+  emergencyContactPhone: '',
+  emergencyContactTel: '',
+  emergencyContactRelation: '',
+  emergencyContactIsGuardian: '0',
+  emergencyContactArea: '',
+  emergencyContactAddress: '',
+  // 亲属信息
+  relativesList: [{
+    name: '',
+    idCard: '',
+    gender: '',
+    age: undefined,
+    phone: '',
+    tel: '',
+    relation: '',
+    isGuardian: '0',
+    area: '',
+    address: ''
+  }],
+  // 其他信息
+  registerPerson: '',
+  registerPhone: '',
+  registerTime: '',
+  receivePerson: '',
+  // 账户信息(编辑/详情时显示)
+  accountBalance: 0,
+  voucherBalance: 0,
+  cashBalance: 0,
+  qrCodeUrl: '',
+  // 服务人员信息
+  servicePersonList: [],
+  // 应急人员信息
+  emergencyPersonList: [],
+  // 附件
+  otherFiles: []
+})
+
+const resetFormField = reactive({...dataForm})
+
+// 表单验证规则
+const dataRule = reactive<FormRules>({
+  elderName: [
+    { required: true, message: '姓名不能为空', trigger: 'blur' }
+  ],
+  idCard: [
+    { required: true, message: '证件号不能为空', trigger: 'blur' },
+    idCardValidity()
+  ],
+  personalPhone: [
+    { required: true, message: '手机号码不能为空', trigger: 'blur' },
+    validatePhone()
+  ],
+  gender: [
+    { required: true, message: '请选择性别', trigger: 'change' }
+  ],
+  pensionWay: [
+    { required: true, message: '请选择意向养老方式', trigger: 'change' }
+  ],
+  registerPerson: [
+    { required: true, message: '登记人不能为空', trigger: 'blur' }
+  ],
+  registerPhone: [
+    { required: true, message: '登记人电话不能为空', trigger: 'blur' },
+    validatePhone()
+  ],
+  registerTime: [
+    { required: true, message: '登记时间不能为空', trigger: 'change' }
+  ]
+})
+
+// 监听身份证号变化,自动填充性别和出生日期
+watch(
+  () => dataForm.idCard,
+  (val: string) => {
+    const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
+    if (!reg.test(val) && val !== '') {
+      dataForm.birthday = ''
+      dataForm.gender = 1
+    } else {
+      const info = getInfo(val)
+      dataForm.birthday = info.birth
+      dataForm.gender = info.sex
+    }
+  }
+)
+
+// 监听紧急联系人身份证号变化
+watch(
+  () => dataForm.emergencyContactIdCard,
+  (val: string) => {
+    const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
+    if (reg.test(val)) {
+      const info = getInfo(val)
+      dataForm.emergencyContactAge = info.age
+    }
+  }
+)
+
+// 监听亲属身份证号变化
+watch(
+  () => dataForm.relativesList,
+  (list) => {
+    list.forEach((item) => {
+      const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
+      if (reg.test(item.idCard)) {
+        const info = getInfo(item.idCard)
+        item.age = info.age
+      }
+    })
+  },
+  { deep: true }
+)
+
+// 身份证号变化处理
+const handleIdCardChange = () => {
+  // 如果需要处理其他逻辑可以在这里扩展
+}
+
+// 选择地图位置
+const selectMapLocation = () => {
+  message.info('地图选择功能开发中')
+}
+
+// 查看长者码介绍
+const viewIntro = () => {
+  message.info('查看介绍功能开发中')
+}
+
+// 添加亲属
+const addRelative = () => {
+  dataForm.relativesList.push({
+    name: '',
+    idCard: '',
+    gender: '',
+    age: undefined,
+    phone: '',
+    tel: '',
+    relation: '',
+    isGuardian: '0',
+    area: '',
+    address: ''
+  })
+}
+
+// 删除亲属
+const deleteRelative = (index: number) => {
+  if (dataForm.relativesList.length > 1) {
+    dataForm.relativesList.splice(index, 1)
+  }
+}
+
+// 服务人员选择弹窗相关
+const servicePersonDialogVisible = ref(false)
+const servicePersonLoading = ref(false)
+const servicePersonList = ref<any[]>([])
+const selectedServicePersonList = ref<any[]>([])
+const servicePersonQueryParams = reactive({
+  name: '',
+  phone: '',
+  serviceArea: ''
+})
+
+// 打开服务人员选择弹窗
+const openServicePersonDialog = () => {
+  servicePersonDialogVisible.value = true
+  selectedServicePersonList.value = []
+  resetServicePersonQuery()
+  searchServicePerson()
+}
+
+// 查询服务人员
+const searchServicePerson = async () => {
+  servicePersonLoading.value = true
+  try {
+    const res = await getServicePersonPage({
+      pageNo: 1,
+      pageSize: 100,
+      ...servicePersonQueryParams
+    })
+    servicePersonList.value = res.list || []
+  } catch (err) {
+    servicePersonList.value = []
+  } finally {
+    servicePersonLoading.value = false
+  }
+}
+
+// 重置服务人员查询
+const resetServicePersonQuery = () => {
+  servicePersonQueryParams.name = ''
+  servicePersonQueryParams.phone = ''
+  servicePersonQueryParams.serviceArea = ''
+}
+
+// 服务人员选择变化
+const handleServicePersonSelectionChange = (selection: any[]) => {
+  selectedServicePersonList.value = selection
+}
+
+// 确认选择服务人员
+const confirmServicePerson = () => {
+  if (selectedServicePersonList.value.length === 0) {
+    message.warning('请选择至少一个服务人员')
+    return
+  }
+  // 添加到已选列表,过滤重复
+  selectedServicePersonList.value.forEach(person => {
+    const exists = dataForm.servicePersonList.some(p => p.id === person.id)
+    if (!exists) {
+      dataForm.servicePersonList.push({
+        id: person.id,
+        name: person.name,
+        gender: person.gender,
+        age: person.age,
+        phone: person.phone,
+        serviceArea: person.serviceArea
+      })
+    }
+  })
+  servicePersonDialogVisible.value = false
+  message.success('添加成功')
+}
+
+// 删除服务人员
+const deleteServicePerson = (index: number) => {
+  dataForm.servicePersonList.splice(index, 1)
+}
+
+// 应急人员选择弹窗相关
+const emergencyPersonDialogVisible = ref(false)
+const emergencyPersonLoading = ref(false)
+const emergencyPersonList = ref<any[]>([])
+const selectedEmergencyPersonList = ref<any[]>([])
+const emergencyPersonQueryParams = reactive({
+  name: '',
+  phone: ''
+})
+
+// 打开应急人员选择弹窗
+const openEmergencyPersonDialog = () => {
+  emergencyPersonDialogVisible.value = true
+  selectedEmergencyPersonList.value = []
+  resetEmergencyPersonQuery()
+  searchEmergencyPerson()
+}
+
+// 查询应急人员
+const searchEmergencyPerson = async () => {
+  emergencyPersonLoading.value = true
+  try {
+    const res = await getEmergencyPersonPage({
+      pageNo: 1,
+      pageSize: 100,
+      ...emergencyPersonQueryParams
+    })
+    emergencyPersonList.value = res.list || []
+  } catch (err) {
+    emergencyPersonList.value = []
+  } finally {
+    emergencyPersonLoading.value = false
+  }
+}
+
+// 重置应急人员查询
+const resetEmergencyPersonQuery = () => {
+  emergencyPersonQueryParams.name = ''
+  emergencyPersonQueryParams.phone = ''
+}
+
+// 应急人员选择变化
+const handleEmergencyPersonSelectionChange = (selection: any[]) => {
+  selectedEmergencyPersonList.value = selection
+}
+
+// 确认选择应急人员
+const confirmEmergencyPerson = () => {
+  if (selectedEmergencyPersonList.value.length === 0) {
+    message.warning('请选择至少一个应急人员')
+    return
+  }
+  // 添加到已选列表,过滤重复
+  selectedEmergencyPersonList.value.forEach(person => {
+    const exists = dataForm.emergencyPersonList.some(p => p.id === person.id)
+    if (!exists) {
+      dataForm.emergencyPersonList.push({
+        id: person.id,
+        name: person.name,
+        gender: person.gender,
+        age: person.age,
+        phone: person.phone,
+        serviceArea: person.serviceArea
+      })
+    }
+  })
+  emergencyPersonDialogVisible.value = false
+  message.success('添加成功')
+}
+
+// 删除应急人员
+const deleteEmergencyPerson = (index: number) => {
+  dataForm.emergencyPersonList.splice(index, 1)
+}
+
+/** 打开弹窗 */
+const open = async (id?: string | number, detail?: boolean, tId?: number) => {
+  dialogVisible.value = true
+  titleName.value = id ? '编辑长者档案' : '新增长者档案'
+  isDetail.value = detail || false
+  dataForm.id = id || ''
+
+  // 加载区域数据
+  if (areaTree.value.length === 0) {
+    areaTree.value = await AreaApi.getAreaTree()
+  }
+
+  if (id) {
+    try {
+      const res = await getElderDetail(id)
+      Object.assign(dataForm, res)
+      // 处理基础病数组
+      if (res.basicIllness) {
+        dataForm.basicIllnessList = res.basicIllness.split(',')
+      }
+    } catch (err) {}
+  } else {
+    nextTick(() => {
+      dataForm.tenantId = tId
+    })
+  }
+}
+
+defineExpose({ open })
+
+// 获取提交数据
+const getSubmitData = () => {
+  const params = { ...JSON.parse(JSON.stringify(dataForm)) }
+  // 处理基础病数组转字符串
+  if (params.basicIllnessList && params.basicIllnessList.length > 0) {
+    params.basicIllness = params.basicIllnessList.join(',')
+  }
+  delete params.basicIllnessList
+  // 处理区域数据
+  if (Array.isArray(params.currentArea)) {
+    params.currentArea = params.currentArea.join('/')
+  }
+  if (Array.isArray(params.householdArea)) {
+    params.householdArea = params.householdArea.join('/')
+  }
+  // 格式化时间
+  if (params.registerTime && params.registerTime instanceof Date) {
+    params.registerTime = formatTime(params.registerTime, 'yyyy-MM-dd HH:mm:ss')
+  }
+  return params
+}
+
+const emit = defineEmits(['success'])
+
+/** 提交表单 */
+const submitForm = async () => {
+  if (formLoading.value) {
+    return
+  }
+  formLoading.value = true
+  try {
+    if (!formRef.value) return
+    const valid = await formRef.value.validate()
+    if (!valid) return
+
+    const params = getSubmitData()
+    const res = params.id ? await updateElder(params) : await addElder(params)
+    if (res) {
+      message.success(params.id ? '编辑成功' : '新增成功')
+      emit('success')
+      handleClosed()
+    }
+  } finally {
+    setTimeout(() => {
+      formLoading.value = false
+    }, 500)
+  }
+}
+
+// 关闭表单
+const handleClosed = () => {
+  formRef.value?.resetFields()
+  Object.assign(dataForm, resetFormField)
+  dialogVisible.value = false
+}
+</script>
+
+<style lang="scss" scoped>
+.elderly-form-dialog {
+  :deep(.el-dialog__body) {
+    padding: 20px;
+    max-height: 70vh;
+    overflow-y: auto;
+  }
+}
+
+.elderly-form-content {
+  .info-section {
+    margin-bottom: 20px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    &.account-section {
+      .account-info-wrap {
+        background-color: #f5f7fa;
+        border-radius: 8px;
+        padding: 20px;
+        height: 100%;
+
+        .account-title {
+          display: flex;
+          align-items: center;
+          margin-bottom: 15px;
+          font-weight: bold;
+          font-size: 16px;
+          color: #303133;
+
+          .title-line {
+            display: inline-block;
+            width: 4px;
+            height: 16px;
+            background-color: #409eff;
+            margin-right: 8px;
+            border-radius: 2px;
+          }
+        }
+
+        .account-balance-list {
+          .balance-item {
+            display: flex;
+            align-items: center;
+            margin-bottom: 12px;
+            font-size: 14px;
+
+            &:last-child {
+              margin-bottom: 0;
+            }
+
+            .balance-label {
+              color: #606266;
+              width: 80px;
+              text-align: right;
+              margin-right: 8px;
+            }
+
+            .balance-value {
+              color: #303133;
+              font-weight: 500;
+            }
+          }
+        }
+      }
+
+      .qr-code-wrap {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        background-color: #f5f7fa;
+        border-radius: 8px;
+        padding: 15px;
+        height: 100%;
+
+        .qr-code-img {
+          width: 120px;
+          height: 120px;
+          background-color: #fff;
+          border: 1px solid #dcdfe6;
+          border-radius: 4px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          overflow: hidden;
+
+          img {
+            width: 100%;
+            height: 100%;
+            object-fit: contain;
+          }
+
+          .qr-code-placeholder {
+            color: #c0c4cc;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+          }
+        }
+
+        .qr-code-text {
+          margin-top: 8px;
+          font-size: 14px;
+          color: #606266;
+          text-align: center;
+        }
+      }
+    }
+  }
+
+  .info-title {
+    display: flex;
+    align-items: center;
+    margin-bottom: 15px;
+    font-weight: bold;
+    font-size: 16px;
+    color: #303133;
+
+    .title-line {
+      display: inline-block;
+      width: 4px;
+      height: 16px;
+      background-color: #409eff;
+      margin-right: 8px;
+      border-radius: 2px;
+    }
+
+    &.flex-between {
+      justify-content: space-between;
+    }
+  }
+
+  .info-wrap {
+    padding: 20px;
+    background-color: #f5f7fa;
+    border-radius: 8px;
+  }
+
+  .mt-20 {
+    margin-top: 20px;
+  }
+
+  .map-location-wrap {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+
+    .map-input {
+      flex: 1;
+    }
+  }
+
+  .address-wrap {
+    display: flex;
+    gap: 10px;
+
+    .area-cascader {
+      width: 200px;
+    }
+
+    .address-input {
+      flex: 1;
+    }
+  }
+
+  .relative-item {
+    background-color: #fff;
+    padding: 15px;
+    border-radius: 6px;
+    margin-bottom: 15px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    .relative-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 15px;
+      padding-bottom: 10px;
+      border-bottom: 1px solid #ebeef5;
+
+      .relative-title {
+        font-weight: 500;
+        color: #606266;
+      }
+    }
+  }
+
+  .person-item {
+    background-color: #fff;
+    padding: 15px;
+    border-radius: 6px;
+    margin-bottom: 15px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    .person-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 15px;
+      padding-bottom: 10px;
+      border-bottom: 1px solid #ebeef5;
+
+      .person-title {
+        font-weight: 500;
+        color: #606266;
+      }
+    }
+  }
+
+  .empty-text {
+    text-align: center;
+    color: #909399;
+    padding: 30px 0;
+    font-size: 14px;
+  }
+}
+
+// 弹窗搜索表单样式
+.search-form {
+  margin-bottom: 20px;
+  padding: 15px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+}
+
+:deep(.el-form-item__label) {
+  font-weight: 500;
+}
+
+:deep(.el-checkbox-group) {
+  .el-checkbox {
+    margin-right: 20px;
+  }
+}
+</style>

+ 531 - 0
src/views/living-home/elderlyManage/elderly-person-file-in/index.vue

@@ -0,0 +1,531 @@
+<template>
+  <div class="elderly-list-container">
+    <el-card shadow="hover">
+
+
+      <div class="search-form">
+        <el-form :inline="true" :model="queryParams" class="demo-form-inline">
+
+          <el-form-item label="长者姓名" >
+            <el-input @keyup.enter="handleQuery" v-model="queryParams.elderName" placeholder="请输入长者姓名" clearable />
+          </el-form-item>
+          <el-form-item label="身份证号">
+            <el-input @keyup.enter="handleQuery" v-model="queryParams.idCard" placeholder="请输入身份证号" clearable />
+          </el-form-item>
+          <el-form-item label="联系电话">
+            <el-input @keyup.enter="handleQuery" v-model="queryParams.personalPhone" placeholder="请输入联系电话" clearable />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="handleQuery">查询</el-button>
+            <el-button @click="resetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    <el-divider style="margin-top: 0"/>
+      <view>
+<!--        <el-button :disabled="ids.length<=0" :loading="deleteBatchLoading" @click="handleDeleteBatch" type="warning">{{ids.length>0?`批量删除长者(已选:${ids.length})`:'批量删除长者'}}</el-button>-->
+        <el-button type="primary" @click="add">新增</el-button>
+        <el-button type="warning" @click="clickHandler">导入</el-button>
+        <el-button type="success" @click="exportElderly">导出</el-button>
+      </view>
+
+      <el-table
+        v-loading="loading"
+        :data="elderlyList"
+        style="width: 100%;margin-top: 8px"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="elderName" label="姓名" width="150" />
+        <el-table-column prop="gender" label="性别" width="80">
+          <template #default="scope">
+            {{ scope.row.gender === 1 ? '男' : '女' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="age" label="年龄" width="80" />
+        <el-table-column prop="personalPhone" label="手机号" width="180" />
+        <el-table-column prop="homeTel" label="固定电话" width="180" />
+        <el-table-column prop="selfCareStatus" label="自理情况" width="180">
+          <template #default="scope">
+            {{ scope.row.selfCareStatus === '1' ? '自理' : scope.row.selfCareStatus === '2' ? '半自理' : '不能自理' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="liveSituation" label="居住情况" width="180">
+          <template #default="scope">
+            {{ scope.row.liveSituation === '1' ? '独居' : scope.row.liveSituation === '2' ? '与配偶同住' : '与子女同住' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="账户余额" width="150" align="center">
+          <template #default="scope">
+            <div>代金券:{{scope.row.voucherBalance || 0}}元</div>
+            <div>现金:{{scope.row.cashBalance || 0}}元</div>
+          </template>
+        </el-table-column>
+        <el-table-column label="是否享受服务" width="120" align="center">
+          <template #default="scope">
+            <el-switch v-model="scope.row.isEnjoyService" active-value="1" inactive-value="0" disabled />
+          </template>
+        </el-table-column>
+        <el-table-column prop="serviceTimes" label="年享受服务次数" width="120" align="center" />
+        <el-table-column prop="currentAddress" label="居住地址" width="200" show-overflow-tooltip />
+        <el-table-column prop="registerTime" label="登记入住时间" width="180" />
+
+        <el-table-column label="操作" width="150" fixed="right" align="center">
+          <template #default="scope">
+
+            <el-button type="text" @click="handleEdit(scope.row,false)">编辑</el-button>
+            <el-button type="text" @click="handleEdit(scope.row,true)">详情</el-button>
+            <el-button type="text" style="color: #f56c6c" @click="handleDelete(scope.row)">退住</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="pagination-container">
+        <el-pagination
+          v-model:current-page="queryParams.pageNo"
+          v-model:page-size="queryParams.pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="total"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-card>
+
+
+
+
+    <Import
+      ref="importRef"
+      @success="getList"
+      :config="{
+      title: '导入',
+      downloadUrl: 'ykCenter/elderly/downloadExcel',
+      excelTempName: '颐康中心-【导入长者】模板',
+      importUrl: '/ykCenter/elderly/import',
+      failExportUrl: ''
+    }"
+    />
+
+
+    <Form ref="formRef"/>
+
+
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted } from 'vue'
+import { useRouter } from 'vue-router'
+import {getElderlyList, updateElderlyInfo, deleteElderly, deleteElderlyBatch} from '@/api/ykCenter'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import Import from "@/components/ImportFile/index.vue";
+import Form from "./Form.vue";
+import {useUserStore} from "@/store/modules/user";
+const router = useRouter()
+const userStore = useUserStore()
+const importRef = ref() //导入
+const formRef = ref() //导入
+const deleteBatchLoading = ref(false) //
+const message = useMessage() // 消息弹窗
+// 获取本月日期范围
+const getCurrentMonthRange = () => {
+  const now = new Date()
+  const year = now.getFullYear()
+  const month = now.getMonth()
+  const firstDay = new Date(year, month, 1)
+  const lastDay = new Date(year, month + 1, 0) // 下个月的第0天就是本月的最后一天
+
+  // 格式化为 YYYY-MM-DD
+  const formatDate = (date: Date) => {
+    const y = date.getFullYear()
+    const m = String(date.getMonth() + 1).padStart(2, '0')
+    const d = String(date.getDate()).padStart(2, '0')
+    return `${y}-${m}-${d}`
+  }
+
+  return [formatDate(firstDay), formatDate(lastDay)]
+}
+
+
+const ids = ref([])
+const handleSelectionChange = (val) => {
+  ids.value = val.map((item) => item.id)
+}
+
+// 查询参数
+const currentMonthRange = getCurrentMonthRange()
+const queryParams = ref({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  idCard: '',
+  personalPhone: '',
+  //dateRange: currentMonthRange,
+  // startDate: currentMonthRange[0],
+  // endDate: currentMonthRange[1],
+  tenantIds: userStore.orgTenantId
+})
+
+// 列表数据
+const elderlyList = ref([])
+const total = ref(0)
+const loading = ref(false)
+const selectedRows = ref([])
+
+// 详情对话框
+const detailVisible = ref(false)
+const currentElderly = ref(null)
+
+
+
+
+
+
+
+const handleDeleteBatch = async () => {
+
+  let dsc = `确定要删除这些长者吗?`
+  ElMessageBox.confirm(dsc, '提示', {
+    confirmButtonText: '确 认',
+    cancelButtonText: '取 消'
+  }).then(async () => {
+    try {
+      deleteBatchLoading.value=true
+      const res = await deleteElderlyBatch(ids.value)
+      if(res){
+        message.success("删除成功")
+        queryParams.value.pageNo = 1
+        await getList()
+      }
+    }catch (_){}finally {
+      deleteBatchLoading.value=false
+    }
+
+  })
+    .catch(() => console.info('操作取消'))
+}
+
+
+
+// 编辑对话框
+const editVisible = ref(false)
+const editFormRef = ref()
+const editForm = ref({
+  id: '',
+  elderName: '',
+  idCard: '',
+  personalPhone: '',
+  emergencyContact: '',
+  emergencyContactPhone: '',
+  currentAddress: '',
+  status: '已失效',
+  tenantIds: userStore.orgTenantId
+})
+
+// 编辑表单验证规则
+const editRules = {
+  elderName: [
+    { required: true, message: '请输入姓名', trigger: 'blur' }
+  ],
+  gender: [],
+  age: [
+    { type: 'number', min: 1, max: 150, message: '年龄必须在1-150之间', trigger: 'blur' }
+  ],
+  idCard: [
+    { pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, message: '请输入正确的身份证号', trigger: 'blur' }
+  ],
+  personalPhone: [
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+  ],
+  emergencyContactPhone: [
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+  ],
+  status: [
+    { required: true, message: '请选择状态', trigger: 'change' }
+  ]
+}
+
+// 导航到指定页面
+const navigateTo = (path: string) => {
+  router.push(`/ykCenter/${path}`)
+}
+
+const clickHandler = () => {
+  importRef.value.open()
+}
+const add = () => {
+  formRef.value.open(1,false,1,queryParams.value.tenantIds)
+}
+
+// 处理日期范围变化
+const handleDateChange = (value: any) => {
+  if (value && value.length === 2) {
+    queryParams.value.startDate = value[0]
+    queryParams.value.endDate = value[1]
+  } else {
+    queryParams.value.startDate = ''
+    queryParams.value.endDate = ''
+  }
+}
+
+// 默认假数据 - 在住长者
+const defaultElderlyList = [
+  {
+    id: '1',
+    elderName: '张大爷',
+    gender: 1,
+    age: 78,
+    personalPhone: '13800138001',
+    homeTel: '0769-12345678',
+    selfCareStatus: '1',
+    liveSituation: '1',
+    voucherBalance: 500,
+    cashBalance: 1200,
+    isEnjoyService: '1',
+    serviceTimes: 12,
+    currentAddress: '东莞市南城区宏图路1号',
+    registerTime: '2024-01-15 10:30:00'
+  },
+  {
+    id: '2',
+    elderName: '李奶奶',
+    gender: 2,
+    age: 82,
+    personalPhone: '13900139002',
+    homeTel: '0769-87654321',
+    selfCareStatus: '2',
+    liveSituation: '2',
+    voucherBalance: 800,
+    cashBalance: 2500,
+    isEnjoyService: '1',
+    serviceTimes: 24,
+    currentAddress: '东莞市东城区东纵路2号',
+    registerTime: '2023-08-20 14:20:00'
+  },
+  {
+    id: '3',
+    elderName: '王爷爷',
+    gender: 1,
+    age: 75,
+    personalPhone: '13700137003',
+    homeTel: '0769-11223344',
+    selfCareStatus: '1',
+    liveSituation: '1',
+    voucherBalance: 0,
+    cashBalance: 500,
+    isEnjoyService: '0',
+    serviceTimes: 0,
+    currentAddress: '东莞市万江区万道路3号',
+    registerTime: '2024-03-10 09:15:00'
+  }
+]
+
+// 获取长者列表
+const getList = async () => {
+  loading.value = true
+  try {
+    // 构建请求参数
+    const params = {
+      ...queryParams.value
+    }
+    const res = await getElderlyList(params)
+    console.log('获取长者列表成功:', res)
+    // 如果接口返回数据为空,使用默认假数据
+    elderlyList.value = res.list?.length > 0 ? res.list : defaultElderlyList
+    total.value = res.total || elderlyList.value.length
+  } catch (error) {
+    console.error('获取长者列表失败:', error)
+    // 接口失败时使用默认假数据
+    elderlyList.value = defaultElderlyList
+    total.value = defaultElderlyList.length
+    ElMessage.warning('使用默认数据展示')
+  } finally {
+    loading.value = false
+  }
+}
+
+// 查询
+const handleQuery = () => {
+  queryParams.value.pageNo = 1
+  getList()
+}
+
+// 重置查询
+const resetQuery = () => {
+  const range = getCurrentMonthRange()
+  queryParams.value = {
+    pageNo: 1,
+    pageSize: 10,
+    elderName: '',
+    idCard: '',
+    personalPhone: '',
+    // dateRange: range,
+    // startDate: range[0],
+    // endDate: range[1]
+    tenantIds: userStore.orgTenantId
+  }
+  getList()
+}
+
+
+// 每页数量变化
+const handleSizeChange = (val: number) => {
+  queryParams.value.pageSize = val
+  getList()
+}
+
+// 当前页变化
+const handleCurrentChange = (val: number) => {
+  queryParams.value.pageNo = val
+  getList()
+}
+
+// 查看详情
+const handleDetail = async (row: any) => {
+  try {
+    detailVisible.value = true
+    // 使用模拟数据
+    const mockData = (await import('@/api/ykCenter')).mockData
+    const elderly = mockData.elderlyList.list.find(item => item.id === row.id)
+    currentElderly.value = elderly || row
+
+    // 如果实际API可用,取消下面注释并注释掉上面的模拟数据代码
+    // const res = await getElderlyDetail(row.id)
+    // currentElderly.value = res.data
+    detailVisible.value = true
+  } catch (error) {
+    console.error('获取长者详情失败:', error)
+    ElMessage.error('获取长者详情失败')
+  }
+}
+
+
+
+
+
+
+// 导出长者信息
+const exportElderly = async () => {
+  try {
+    // 使用模拟数据导出
+    const mockData = (await import('@/api/ykCenter')).mockData
+    const data = mockData.elderlyList.list.map(item => ({
+      姓名: item.name,
+      性别: item.gender === 1 ? '男' : '女',
+      年龄: item.age,
+      身份证号: item.idCard,
+      联系电话: item.phone,
+      地址: item.address,
+      堂食余额: item.diningBalance,
+      送餐余额: item.deliveryBalance,
+      本月就餐次数: item.mealCount
+    }))
+
+    // 创建CSV内容
+    const csvContent = [
+      Object.keys(data[0]).join(','),
+      ...data.map(row => Object.values(row).join(','))
+    ].join('\n')
+
+    // 创建下载链接
+    const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' })
+    const url = URL.createObjectURL(blob)
+    const link = document.createElement('a')
+    link.href = url
+    link.download = '长者信息.csv'
+    link.click()
+    URL.revokeObjectURL(url)
+
+    ElMessage.success('导出成功')
+
+    // 如果实际API可用,取消下面注释并注释掉上面的模拟数据代码
+    // await exportElderlyInfo(queryParams.value)
+    // ElMessage.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    ElMessage.error('导出失败')
+  }
+}
+
+// 编辑长者信息
+const handleEdit = async (row: any,detail:boolean) => {
+  formRef.value.open(row.id,detail,1,queryParams.value.tenantIds)
+}
+
+
+
+// 删除长者
+const handleDelete = async (row: any) => {
+  try {
+    await ElMessageBox.confirm(
+      `确定要退住长者 "${row.elderName}" 吗?`,
+      '删除确认',
+      {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }
+    )
+    await deleteElderly(row.id)
+
+    ElMessage.success('删除成功')
+    await getList()
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('删除长者失败:', error)
+      ElMessage.error('删除长者失败')
+    }
+  }
+}
+
+onMounted(() => {
+  getList()
+})
+</script>
+
+<style scoped>
+.elderly-list-container {
+
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.header-actions {
+  display: flex;
+  gap: 10px;
+}
+
+.search-form {
+  margin-bottom: 2px;
+}
+
+.pagination-container {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.elderly-detail {
+  padding: 10px 0;
+}
+
+.balance-info {
+  padding: 0 20px;
+}
+
+.balance-records {
+  margin-top: 20px;
+}
+
+.balance-records h3 {
+  margin-bottom: 15px;
+  font-size: 16px;
+  color: #333;
+}
+</style>

+ 123 - 0
src/views/living-home/elderlyManage/elderly-person-file-miniapp/Form.vue

@@ -0,0 +1,123 @@
+<template>
+  <!-- 修改密码弹窗 -->
+  <el-dialog
+    v-model="passwordDialogVisible"
+    title="修改密码"
+    width="500px"
+    append-to-body
+    :close-on-click-modal="false"
+  >
+    <el-form
+      ref="passwordFormRef"
+      :model="passwordForm"
+      :rules="passwordRules"
+      label-width="100px"
+    >
+      <el-form-item label="新密码" prop="newPassword">
+        <el-input
+          v-model="passwordForm.newPassword"
+          type="password"
+          placeholder="请输入新密码"
+          show-password
+          clearable
+        />
+      </el-form-item>
+      <el-form-item label="确认密码" prop="confirmPassword">
+        <el-input
+          v-model="passwordForm.confirmPassword"
+          type="password"
+          placeholder="请输入确认密码"
+          show-password
+          clearable
+        />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="passwordDialogVisible = false">取消</el-button>
+      <el-button type="primary" @click="submitPassword" :loading="passwordLoading">保存</el-button>
+    </template>
+  </el-dialog>
+</template>
+<script setup lang="ts">
+import {
+  updateElderPassword
+} from '@/api/living-home/elderly'
+import type { FormRules } from 'element-plus'
+
+defineOptions({ name: 'ElderlyPersonFileMiniappForm' })
+const message = useMessage()
+
+// 修改密码弹窗相关
+const passwordDialogVisible = ref(false)
+const passwordLoading = ref(false)
+const passwordFormRef = ref()
+const currentElderId = ref('')
+
+// 密码表单数据
+const passwordForm = reactive({
+  newPassword: '',
+  confirmPassword: ''
+})
+
+// 密码表单验证规则
+const passwordRules = reactive<FormRules>({
+  newPassword: [
+    { required: true, message: '请输入新密码', trigger: 'blur' },
+    { min: 6, message: '密码长度不能少于6位', trigger: 'blur' }
+  ],
+  confirmPassword: [
+    { required: true, message: '请输入确认密码', trigger: 'blur' },
+    {
+      validator: (rule: any, value: string, callback: Function) => {
+        if (value !== passwordForm.newPassword) {
+          callback(new Error('两次输入的密码不一致'))
+        } else {
+          callback()
+        }
+      },
+      trigger: 'blur'
+    }
+  ]
+})
+
+/** 打开修改密码弹窗 */
+const openPasswordDialog = (row: any) => {
+  currentElderId.value = row.id
+  passwordDialogVisible.value = true
+  passwordForm.newPassword = ''
+  passwordForm.confirmPassword = ''
+  nextTick(() => {
+    passwordFormRef.value?.resetFields()
+  })
+}
+
+/** 提交密码修改 */
+const submitPassword = async () => {
+  if (passwordLoading.value) return
+  
+  try {
+    await passwordFormRef.value.validate()
+    passwordLoading.value = true
+    
+    await updateElderPassword({
+      elderId: currentElderId.value,
+      password: passwordForm.newPassword
+    })
+    
+    message.success('密码修改成功')
+    passwordDialogVisible.value = false
+  } catch (err) {
+    // 验证失败或接口调用失败
+  } finally {
+    passwordLoading.value = false
+  }
+}
+
+defineExpose({ openPasswordDialog })
+</script>
+
+<style lang="scss" scoped>
+:deep(.el-form-item__label) {
+  font-weight: 500;
+}
+</style>

+ 497 - 0
src/views/living-home/elderlyManage/elderly-person-file-miniapp/index.vue

@@ -0,0 +1,497 @@
+<template>
+  <div class="elderly-list-container">
+    <el-card shadow="hover">
+
+
+      <div class="search-form">
+        <el-form :inline="true" :model="queryParams" class="demo-form-inline">
+
+          <el-form-item label="长者姓名" >
+            <el-input @keyup.enter="handleQuery" v-model="queryParams.elderName" placeholder="请输入长者姓名" clearable />
+          </el-form-item>
+          <el-form-item label="身份证号">
+            <el-input @keyup.enter="handleQuery" v-model="queryParams.idCard" placeholder="请输入身份证号" clearable />
+          </el-form-item>
+          <el-form-item label="联系电话">
+            <el-input @keyup.enter="handleQuery" v-model="queryParams.personalPhone" placeholder="请输入联系电话" clearable />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="handleQuery">查询</el-button>
+            <el-button @click="resetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    <el-divider style="margin-top: 0"/>
+      <view>
+<!--        <el-button :disabled="ids.length<=0" :loading="deleteBatchLoading" @click="handleDeleteBatch" type="warning">{{ids.length>0?`批量删除长者(已选:${ids.length})`:'批量删除长者'}}</el-button>-->
+
+        <el-button type="warning" @click="clickHandler">导入</el-button>
+        <el-button type="success" @click="exportElderly">导出</el-button>
+      </view>
+
+      <el-table
+        v-loading="loading"
+        :data="elderlyList"
+        style="width: 100%;margin-top: 8px"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="elderName" label="姓名" width="250" />
+        <el-table-column prop="personalPhone" label="手机号" width="250" />
+        <el-table-column prop="miniappAccount" label="小程序账号" width="250" />
+        <el-table-column prop="createTime" label="创建时间" width="250" />
+
+        <el-table-column label="是否启用" width="250" align="center">
+          <template #default="scope">
+            <el-switch v-model="scope.row.isEnabled" />
+          </template>
+        </el-table-column>
+
+<!--        <el-table-column label="操作" width="200" fixed="right" align="center">-->
+<!--          <template #default="scope">-->
+
+<!--            <el-button type="text" @click="handleEdit(scope.row,false)">修改密码</el-button>-->
+
+<!--          </template>-->
+<!--        </el-table-column>-->
+      </el-table>
+
+      <div class="pagination-container">
+        <el-pagination
+          v-model:current-page="queryParams.pageNo"
+          v-model:page-size="queryParams.pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="total"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-card>
+
+
+
+
+    <Import
+      ref="importRef"
+      @success="getList"
+      :config="{
+      title: '导入',
+      downloadUrl: 'ykCenter/elderly/downloadExcel',
+      excelTempName: '颐康中心-【导入长者】模板',
+      importUrl: '/ykCenter/elderly/import',
+      failExportUrl: ''
+    }"
+    />
+
+
+    <Form ref="formRef"/>
+
+
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted } from 'vue'
+import { useRouter } from 'vue-router'
+import {getElderlyList, updateElderlyInfo, deleteElderly, deleteElderlyBatch} from '@/api/ykCenter'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import Import from "@/components/ImportFile/index.vue";
+import Form from "./Form.vue";
+import {useUserStore} from "@/store/modules/user";
+const router = useRouter()
+const userStore = useUserStore()
+const importRef = ref() //导入
+const formRef = ref() //导入
+const deleteBatchLoading = ref(false) //
+const message = useMessage() // 消息弹窗
+// 获取本月日期范围
+const getCurrentMonthRange = () => {
+  const now = new Date()
+  const year = now.getFullYear()
+  const month = now.getMonth()
+  const firstDay = new Date(year, month, 1)
+  const lastDay = new Date(year, month + 1, 0) // 下个月的第0天就是本月的最后一天
+
+  // 格式化为 YYYY-MM-DD
+  const formatDate = (date: Date) => {
+    const y = date.getFullYear()
+    const m = String(date.getMonth() + 1).padStart(2, '0')
+    const d = String(date.getDate()).padStart(2, '0')
+    return `${y}-${m}-${d}`
+  }
+
+  return [formatDate(firstDay), formatDate(lastDay)]
+}
+
+
+const ids = ref([])
+const handleSelectionChange = (val) => {
+  ids.value = val.map((item) => item.id)
+}
+
+// 查询参数
+const currentMonthRange = getCurrentMonthRange()
+const queryParams = ref({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  idCard: '',
+  personalPhone: '',
+  //dateRange: currentMonthRange,
+  // startDate: currentMonthRange[0],
+  // endDate: currentMonthRange[1],
+  tenantIds: userStore.orgTenantId
+})
+
+// 列表数据
+const elderlyList = ref([])
+const total = ref(0)
+const loading = ref(false)
+const selectedRows = ref([])
+
+// 详情对话框
+const detailVisible = ref(false)
+const currentElderly = ref(null)
+
+
+
+// 表单验证规则
+const balanceRules = {
+  paymentType: [
+    { required: true, message: '请选择支付类型', trigger: 'change' }
+  ],
+  diningBalance: [
+    { required: true, message: '请输入堂食余额', trigger: 'blur' }
+  ],
+  deliveryBalance: [
+    { required: true, message: '请输入送餐余额', trigger: 'blur' }
+  ],
+  reason: [
+    { required: true, message: '请输入更新原因', trigger: 'blur' }
+  ]
+}
+
+
+
+const handleDeleteBatch = async () => {
+
+  let dsc = `确定要删除这些长者吗?`
+  ElMessageBox.confirm(dsc, '提示', {
+    confirmButtonText: '确 认',
+    cancelButtonText: '取 消'
+  }).then(async () => {
+    try {
+      deleteBatchLoading.value=true
+      const res = await deleteElderlyBatch(ids.value)
+      if(res){
+        message.success("删除成功")
+        queryParams.value.pageNo = 1
+        await getList()
+      }
+    }catch (_){}finally {
+      deleteBatchLoading.value=false
+    }
+
+  })
+    .catch(() => console.info('操作取消'))
+}
+
+
+
+// 编辑对话框
+const editVisible = ref(false)
+const editFormRef = ref()
+const editForm = ref({
+  id: '',
+  elderName: '',
+  idCard: '',
+  personalPhone: '',
+  emergencyContact: '',
+  emergencyContactPhone: '',
+  currentAddress: '',
+  status: '已失效',
+  tenantIds: userStore.orgTenantId
+})
+
+// 编辑表单验证规则
+const editRules = {
+  elderName: [
+    { required: true, message: '请输入姓名', trigger: 'blur' }
+  ],
+  gender: [],
+  age: [
+    { type: 'number', min: 1, max: 150, message: '年龄必须在1-150之间', trigger: 'blur' }
+  ],
+  idCard: [
+    { pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, message: '请输入正确的身份证号', trigger: 'blur' }
+  ],
+  personalPhone: [
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+  ],
+  emergencyContactPhone: [
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+  ],
+  status: [
+    { required: true, message: '请选择状态', trigger: 'change' }
+  ]
+}
+
+// 导航到指定页面
+const navigateTo = (path: string) => {
+  router.push(`/ykCenter/${path}`)
+}
+
+const clickHandler = () => {
+  importRef.value.open()
+}
+const add = () => {
+  formRef.value.open(1,false,1,queryParams.value.tenantIds)
+}
+
+// 处理日期范围变化
+const handleDateChange = (value: any) => {
+  if (value && value.length === 2) {
+    queryParams.value.startDate = value[0]
+    queryParams.value.endDate = value[1]
+  } else {
+    queryParams.value.startDate = ''
+    queryParams.value.endDate = ''
+  }
+}
+
+// 默认假数据 - 小程序账号
+const defaultElderlyList = [
+  {
+    id: '1',
+    elderName: '张大爷',
+    personalPhone: '13800138001',
+    miniappAccount: 'zhang_daye_001',
+    createTime: '2024-01-15 10:30:00',
+    isEnabled: true
+  },
+  {
+    id: '2',
+    elderName: '李奶奶',
+    personalPhone: '13900139002',
+    miniappAccount: 'li_nainai_002',
+    createTime: '2023-08-20 14:20:00',
+    isEnabled: true
+  },
+  {
+    id: '3',
+    elderName: '王爷爷',
+    personalPhone: '13700137003',
+    miniappAccount: 'wang_yeye_003',
+    createTime: '2024-03-10 09:15:00',
+    isEnabled: false
+  }
+]
+
+// 获取长者列表
+const getList = async () => {
+  loading.value = true
+  try {
+    // 构建请求参数
+    const params = {
+      ...queryParams.value
+    }
+    const res = await getElderlyList(params)
+    console.log('获取长者列表成功:', res)
+    // 如果接口返回数据为空,使用默认假数据
+    elderlyList.value = res.list?.length > 0 ? res.list : defaultElderlyList
+    total.value = res.total || elderlyList.value.length
+  } catch (error) {
+    console.error('获取长者列表失败:', error)
+    // 接口失败时使用默认假数据
+    elderlyList.value = defaultElderlyList
+    total.value = defaultElderlyList.length
+    ElMessage.warning('使用默认数据展示')
+  } finally {
+    loading.value = false
+  }
+}
+
+// 查询
+const handleQuery = () => {
+  queryParams.value.pageNo = 1
+  getList()
+}
+
+// 重置查询
+const resetQuery = () => {
+  const range = getCurrentMonthRange()
+  queryParams.value = {
+    pageNo: 1,
+    pageSize: 10,
+    elderName: '',
+    idCard: '',
+    personalPhone: '',
+    // dateRange: range,
+    // startDate: range[0],
+    // endDate: range[1]
+    tenantIds: userStore.orgTenantId
+  }
+  getList()
+}
+
+
+// 每页数量变化
+const handleSizeChange = (val: number) => {
+  queryParams.value.pageSize = val
+  getList()
+}
+
+// 当前页变化
+const handleCurrentChange = (val: number) => {
+  queryParams.value.pageNo = val
+  getList()
+}
+
+// 查看详情
+const handleDetail = async (row: any) => {
+  try {
+    detailVisible.value = true
+    // 使用模拟数据
+    const mockData = (await import('@/api/ykCenter')).mockData
+    const elderly = mockData.elderlyList.list.find(item => item.id === row.id)
+    currentElderly.value = elderly || row
+
+    // 如果实际API可用,取消下面注释并注释掉上面的模拟数据代码
+    // const res = await getElderlyDetail(row.id)
+    // currentElderly.value = res.data
+    detailVisible.value = true
+  } catch (error) {
+    console.error('获取长者详情失败:', error)
+    ElMessage.error('获取长者详情失败')
+  }
+}
+
+
+
+
+
+
+// 导出长者信息
+const exportElderly = async () => {
+  try {
+    // 使用模拟数据导出
+    const mockData = (await import('@/api/ykCenter')).mockData
+    const data = mockData.elderlyList.list.map(item => ({
+      姓名: item.name,
+      性别: item.gender === 1 ? '男' : '女',
+      年龄: item.age,
+      身份证号: item.idCard,
+      联系电话: item.phone,
+      地址: item.address,
+      堂食余额: item.diningBalance,
+      送餐余额: item.deliveryBalance,
+      本月就餐次数: item.mealCount
+    }))
+
+    // 创建CSV内容
+    const csvContent = [
+      Object.keys(data[0]).join(','),
+      ...data.map(row => Object.values(row).join(','))
+    ].join('\n')
+
+    // 创建下载链接
+    const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' })
+    const url = URL.createObjectURL(blob)
+    const link = document.createElement('a')
+    link.href = url
+    link.download = '长者信息.csv'
+    link.click()
+    URL.revokeObjectURL(url)
+
+    ElMessage.success('导出成功')
+
+    // 如果实际API可用,取消下面注释并注释掉上面的模拟数据代码
+    // await exportElderlyInfo(queryParams.value)
+    // ElMessage.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    ElMessage.error('导出失败')
+  }
+}
+
+// 修改密码
+const handleEdit = async (row: any) => {
+  formRef.value.openPasswordDialog(row)
+}
+
+
+
+// 删除长者
+const handleDelete = async (row: any) => {
+  try {
+    await ElMessageBox.confirm(
+      `确定要删除长者 "${row.elderName}" 吗?此操作不可恢复!`,
+      '删除确认',
+      {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }
+    )
+    await deleteElderly(row.id)
+
+    ElMessage.success('删除成功')
+    await getList()
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('删除长者失败:', error)
+      ElMessage.error('删除长者失败')
+    }
+  }
+}
+
+onMounted(() => {
+  getList()
+})
+</script>
+
+<style scoped>
+.elderly-list-container {
+
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.header-actions {
+  display: flex;
+  gap: 10px;
+}
+
+.search-form {
+  margin-bottom: 2px;
+}
+
+.pagination-container {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.elderly-detail {
+  padding: 10px 0;
+}
+
+.balance-info {
+  padding: 0 20px;
+}
+
+.balance-records {
+  margin-top: 20px;
+}
+
+.balance-records h3 {
+  margin-bottom: 15px;
+  font-size: 16px;
+  color: #333;
+}
+</style>

+ 2051 - 0
src/views/living-home/elderlyManage/elderly-person-file-out/Form.vue

@@ -0,0 +1,2051 @@
+<template>
+  <Dialog
+    v-model="dialogVisible"
+    :title="titleName"
+    width="90%"
+    class="form-tag-dialog elderly-form-dialog"
+    scroll
+    @close="handleClosed"
+  >
+    <el-form
+      ref="formRef"
+      :model="dataForm"
+      :rules="dataRule"
+      label-width="130px"
+      class="elderly-form-content"
+      :disabled="isDetail"
+    >
+      <!-- 账户余额和二维码区域 - 仅在编辑和详情时显示 -->
+      <div class="info-section account-section" v-if="dataForm.id">
+        <el-row :gutter="20">
+          <el-col :xs="24" :sm="16" :md="18">
+            <div class="account-info-wrap">
+              <div class="account-title">
+                <span class="title-line"></span>
+                <span>账户信息</span>
+              </div>
+              <div class="account-balance-list">
+                <div class="balance-item">
+                  <span class="balance-label">账户余额:</span>
+                  <span class="balance-value">{{ dataForm.accountBalance || 0 }}元</span>
+                </div>
+                <div class="balance-item">
+                  <span class="balance-label">代金券:</span>
+                  <span class="balance-value">{{ dataForm.voucherBalance || 0 }}元</span>
+                </div>
+                <div class="balance-item">
+                  <span class="balance-label">现 金:</span>
+                  <span class="balance-value">{{ dataForm.cashBalance || 0 }}元</span>
+                </div>
+              </div>
+            </div>
+          </el-col>
+          <el-col :xs="24" :sm="8" :md="6">
+            <div class="qr-code-wrap">
+              <div class="qr-code-img">
+                <img v-if="dataForm.qrCodeUrl" :src="dataForm.qrCodeUrl" alt="长者码" />
+                <div v-else class="qr-code-placeholder">
+                  <Icon icon="ep:picture" :size="60" />
+                </div>
+              </div>
+              <div class="qr-code-text">长者码</div>
+              <el-button type="primary" link size="small" @click="viewIntro">
+                点击查看介绍>>
+              </el-button>
+            </div>
+          </el-col>
+        </el-row>
+      </div>
+
+      <!-- 基本信息 -->
+      <div class="info-section">
+        <div class="info-title">
+          <span class="title-line"></span>
+          <span>基本信息</span>
+        </div>
+        <div class="info-wrap">
+          <el-row :gutter="24">
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="长者姓名" prop="elderName">
+                <template v-if="isDetail">{{ dataForm.elderName }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.elderName"
+                  placeholder="请输入姓名"
+                  clearable
+                  maxlength="10"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="身份证类型" prop="papersType">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.PAPERS_TYPE, dataForm.papersType) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.papersType"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.PAPERS_TYPE)"
+                >
+                  <el-option
+                    v-for="(item, index) in getIntDictOptions(DICT_TYPE.PAPERS_TYPE)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="身份证号" prop="idCard">
+                <template v-if="isDetail">{{ dataForm.idCard }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.idCard"
+                  placeholder="请输入证件号"
+                  clearable
+                  maxlength="18"
+                  @change="handleIdCardChange"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="手机号码" prop="personalPhone">
+                <template v-if="isDetail">{{ dataForm.personalPhone }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.personalPhone"
+                  placeholder="请输入手机号码"
+                  clearable
+                  maxlength="11"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="现居住区域" prop="currentArea">
+                <template v-if="isDetail">{{ dataForm.currentArea }}</template>
+                <el-cascader
+                  v-else
+                  v-model="dataForm.currentArea"
+                  :options="areaTree"
+                  :props="defaultProps"
+                  class="w-1/1"
+                  clearable
+                  placeholder="请选择地区"
+                  filterable
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="现居住详细地址" prop="currentAddress">
+                <template v-if="isDetail">{{ dataForm.currentAddress }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.currentAddress"
+                  placeholder="请输入详细地址"
+                  clearable
+                  maxlength="100"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="户籍所在区域" prop="householdArea">
+                <template v-if="isDetail">{{ dataForm.householdArea }}</template>
+                <el-cascader
+                  v-else
+                  v-model="dataForm.householdArea"
+                  :options="areaTree"
+                  :props="defaultProps"
+                  class="w-1/1"
+                  clearable
+                  placeholder="请选择地区"
+                  filterable
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="户籍详细地址" prop="householdAddress">
+                <template v-if="isDetail">{{ dataForm.householdAddress }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.householdAddress"
+                  placeholder="请输入户籍详细地址"
+                  clearable
+                  maxlength="100"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 详细信息 -->
+      <div class="info-section">
+        <div class="info-title">
+          <span class="title-line"></span>
+          <span>详细信息</span>
+        </div>
+        <div class="info-wrap">
+          <el-row :gutter="24">
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="出生日期" prop="birthday">
+                <template v-if="isDetail">{{ dataForm.birthday }}</template>
+                <TgDatePicker
+                  v-else
+                  type="date"
+                  v-model="dataForm.birthday"
+                  placeholder="请选择出生日期"
+                  clearable
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="性别" prop="gender">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, dataForm.gender) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.gender"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+                >
+                  <el-option
+                    v-for="(item, index) in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="固定电话" prop="homeTel">
+                <template v-if="isDetail">{{ dataForm.homeTel }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.homeTel"
+                  placeholder="请输入固定电话"
+                  clearable
+                  maxlength="12"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="民族" prop="nationId">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.NATION_ARR, dataForm.nationId) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.nationId"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.NATION_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.NATION_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="婚姻状况" prop="maritalStatus">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.MARITAL_STATUS_ARR, dataForm.maritalStatus) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.maritalStatus"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.MARITAL_STATUS_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getIntDictOptions(DICT_TYPE.MARITAL_STATUS_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="职业" prop="occupation">
+                <template v-if="isDetail">{{ dataForm.occupation }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.occupation"
+                  placeholder="请输入职业"
+                  clearable
+                  maxlength="50"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="自理情况" prop="selfCareStatus">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.ABILITY_LEVEL_ARR, dataForm.selfCareStatus) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.selfCareStatus"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.ABILITY_LEVEL_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.ABILITY_LEVEL_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="文化程度" prop="degreeEducation">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.DEGREE_EDUCATION_ARR, dataForm.degreeEducation) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.degreeEducation"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.DEGREE_EDUCATION_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getIntDictOptions(DICT_TYPE.DEGREE_EDUCATION_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="残疾类型" prop="disabilityType">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.DISABILITY_ARR, dataForm.disabilityType) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.disabilityType"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.DISABILITY_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.DISABILITY_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="居住情况" prop="liveSituation">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.LIVE_ARR, dataForm.liveSituation) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.liveSituation"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.LIVE_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.LIVE_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="居住面积" prop="livingArea">
+                <template v-if="isDetail">{{ dataForm.livingArea }}</template>
+                <el-input
+                  v-else
+                  v-model="dataForm.livingArea"
+                  placeholder="请输入"
+                  clearable
+                  :controls="false"
+                  :precision="2"
+                  :max="9999"
+                >
+                  <template #append>㎡</template>
+                </el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="户籍类别" prop="householdType">
+                <template v-if="isDetail">{{ dataForm.householdType }}</template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.householdType"
+                  placeholder="请选择"
+                  clearable
+                  :list="householdTypeOptions"
+                >
+                  <el-option label="农业户口" value="农业户口" />
+                  <el-option label="非农业户口" value="非农业户口" />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="经济来源" prop="economySource">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.ECONOMY_SOURCE_ARR, dataForm.economySource) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.economySource"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.ECONOMY_SOURCE_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.ECONOMY_SOURCE_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="平均可支配月收入" prop="monthlyIncome">
+                <template v-if="isDetail">{{ dataForm.monthlyIncome }}</template>
+                <TgInputNumber
+                  v-else
+                  v-model="dataForm.monthlyIncome"
+                  placeholder="请输入"
+                  clearable
+                  :controls="false"
+                  :precision="2"
+                  :max="999999"
+                >
+                  <template #append>元</template>
+                </TgInputNumber>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="医疗类型" prop="medicalType">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.MEDICAL_INSURANCE_ARR, dataForm.medicalType) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.medicalType"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.MEDICAL_INSURANCE_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.MEDICAL_INSURANCE_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 意向养老方式 -->
+          <el-row :gutter="24" class="mt-20">
+            <el-col :span="24">
+              <el-form-item label="意向养老方式" prop="pensionWay">
+                <template v-if="isDetail">
+                  {{ dataForm.pensionWay }}
+                </template>
+                <TgRadio v-else v-model="dataForm.pensionWay" clearable>
+                  <el-radio value="机构养老">机构养老</el-radio>
+                  <el-radio value="社区养老">社区养老</el-radio>
+                  <el-radio value="居家养老">居家养老</el-radio>
+                  <el-radio value="老年大学">老年大学</el-radio>
+                  <el-radio value="旅居养老">旅居养老</el-radio>
+                  <el-radio value="其他">其他</el-radio>
+                </TgRadio>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 意向服务 -->
+          <el-row :gutter="24">
+            <el-col :span="24">
+              <el-form-item label="意向服务" prop="intentionService">
+                <template v-if="isDetail">{{ dataForm.intentionService }}</template>
+                <el-input
+                  v-else
+                  v-model="dataForm.intentionService"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入意向服务"
+                  clearable
+                  maxlength="500"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 分组标记 -->
+<!--          <el-row :gutter="24">-->
+<!--            <el-col :span="24">-->
+<!--              <el-form-item label="分组标记" prop="groupTag">-->
+<!--                <template v-if="isDetail">-->
+<!--                  {{ dataForm.groupTag === '1' ? '默认分组' : '其他' }}-->
+<!--                </template>-->
+<!--                <el-checkbox v-else v-model="dataForm.groupTag" true-label="1" false-label="0">-->
+<!--                  默认分组-->
+<!--                </el-checkbox>-->
+<!--              </el-form-item>-->
+<!--            </el-col>-->
+<!--          </el-row>-->
+
+          <!-- 痛点问题 -->
+          <el-row :gutter="24">
+            <el-col :span="24">
+              <el-form-item label="痛点问题" prop="painPoint">
+                <template v-if="isDetail">{{ dataForm.painPoint }}</template>
+                <el-input
+                  v-else
+                  v-model="dataForm.painPoint"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入痛点问题,如:老人长期独居,时常感到孤独抑郁。"
+                  clearable
+                  maxlength="500"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 跟踪记录 -->
+          <el-row :gutter="24">
+            <el-col :span="24">
+              <el-form-item label="跟踪记录" prop="trackRecord">
+                <template v-if="isDetail">{{ dataForm.trackRecord }}</template>
+                <el-input
+                  v-else
+                  v-model="dataForm.trackRecord"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入跟踪记录"
+                  clearable
+                  maxlength="500"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 地图位置 -->
+<!--          <el-row :gutter="24">-->
+<!--            <el-col :span="24">-->
+<!--              <el-form-item label="地图位置" prop="mapLocation">-->
+<!--                <template v-if="isDetail">{{ dataForm.mapLocation }}</template>-->
+<!--                <div v-else class="map-location-wrap">-->
+<!--                  <TgInput-->
+<!--                    v-model="dataForm.mapLocation"-->
+<!--                    placeholder="选择位置"-->
+<!--                    clearable-->
+<!--                    readonly-->
+<!--                    class="map-input"-->
+<!--                  />-->
+<!--                  <el-button type="primary" link @click="selectMapLocation">-->
+<!--                    <Icon icon="ep:location" />-->
+<!--                    选择位置-->
+<!--                  </el-button>-->
+<!--                </div>-->
+<!--              </el-form-item>-->
+<!--            </el-col>-->
+<!--          </el-row>-->
+
+          <!-- 其他选项 -->
+          <el-row :gutter="24">
+            <el-col :xs="24" :sm="8" :md="6">
+              <el-form-item label="外地迁入" prop="isMigrant">
+                <template v-if="isDetail">
+                  {{ dataForm.isMigrant === '1' ? '是' : '否' }}
+                </template>
+                <TgRadio v-else v-model="dataForm.isMigrant" clearable>
+                  <el-radio value="1">是</el-radio>
+                  <el-radio value="0">否</el-radio>
+                </TgRadio>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="8" :md="6">
+              <el-form-item label="是否本市户籍" prop="isLocalHousehold">
+                <template v-if="isDetail">
+                  {{ dataForm.isLocalHousehold === '1' ? '是' : '否' }}
+                </template>
+                <TgRadio v-else v-model="dataForm.isLocalHousehold" clearable>
+                  <el-radio value="1">是</el-radio>
+                  <el-radio value="0">否</el-radio>
+                </TgRadio>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="8" :md="6">
+              <el-form-item label="是否享家服务" prop="isEnjoyService">
+                <template v-if="isDetail">
+                  {{ dataForm.isEnjoyService === '1' ? '是' : '否' }}
+                </template>
+                <TgRadio v-else v-model="dataForm.isEnjoyService" clearable>
+                  <el-radio value="1">是</el-radio>
+                  <el-radio value="0">否</el-radio>
+                </TgRadio>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="8" :md="6">
+              <el-form-item label="年享家服务次数" prop="serviceTimes">
+                <template v-if="isDetail">{{ dataForm.serviceTimes }}</template>
+                <TgInputNumber
+                  v-else
+                  v-model="dataForm.serviceTimes"
+                  placeholder="请输入"
+                  clearable
+                  :controls="false"
+                  :min="0"
+                  :max="999"
+                >
+                  <template #append>次</template>
+                </TgInputNumber>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 健康信息 -->
+      <div class="info-section">
+        <div class="info-title">
+          <span class="title-line"></span>
+          <span>健康信息</span>
+        </div>
+        <div class="info-wrap">
+          <el-row :gutter="24">
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="健康状态" prop="healthStatus">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.ELDERLY_HEALTH_STATUS, dataForm.healthStatus) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.healthStatus"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.ELDERLY_HEALTH_STATUS)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.ELDERLY_HEALTH_STATUS)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="血型" prop="bloodType">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.BLOOD_TYPE, dataForm.bloodType) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.bloodType"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.BLOOD_TYPE)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.BLOOD_TYPE)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="医保卡号" prop="medicalCardNo">
+                <template v-if="isDetail">{{ dataForm.medicalCardNo }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.medicalCardNo"
+                  placeholder="最多只能输入20位"
+                  clearable
+                  maxlength="20"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="视力" prop="vision">
+                <template v-if="isDetail">{{ dataForm.vision }}</template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.vision"
+                  placeholder="请选择"
+                  clearable
+                  :list="visionOptions"
+                >
+                  <el-option label="正常" value="正常" />
+                  <el-option label="轻度障碍" value="轻度障碍" />
+                  <el-option label="中度障碍" value="中度障碍" />
+                  <el-option label="重度障碍" value="重度障碍" />
+                  <el-option label="失明" value="失明" />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="听力" prop="hearing">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.HEARING_ARR, dataForm.hearing) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.hearing"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.HEARING_ARR)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.HEARING_ARR)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 基础病 -->
+          <el-row :gutter="24">
+            <el-col :span="24">
+              <el-form-item label="基础病" prop="basicIllness">
+                <template v-if="isDetail">{{ dataForm.basicIllness }}</template>
+                <el-checkbox-group v-else v-model="dataForm.basicIllnessList">
+                  <el-checkbox label="高血糖">高血糖</el-checkbox>
+                  <el-checkbox label="高血压">高血压</el-checkbox>
+                  <el-checkbox label="心脏病">心脏病</el-checkbox>
+                  <el-checkbox label="脑血栓">脑血栓</el-checkbox>
+                  <el-checkbox label="冠心病">冠心病</el-checkbox>
+                  <el-checkbox label="关节炎">关节炎</el-checkbox>
+                  <el-checkbox label="风湿">风湿</el-checkbox>
+                  <el-checkbox label="其他">其他</el-checkbox>
+                </el-checkbox-group>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 病史 -->
+          <el-row :gutter="24">
+            <el-col :span="24">
+              <el-form-item label="病史" prop="medicalHistory">
+                <template v-if="isDetail">{{ dataForm.medicalHistory }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.medicalHistory"
+                  type="textarea"
+                  :rows="3"
+                  placeholder="请输入病史"
+                  clearable
+                  maxlength="500"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 紧急联系人信息 -->
+      <div class="info-section">
+        <div class="info-title">
+          <span class="title-line"></span>
+          <span>紧急联系人</span>
+        </div>
+        <div class="info-wrap">
+          <el-row :gutter="24">
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="紧急联系人姓名" prop="emergencyContactName">
+                <template v-if="isDetail">{{ dataForm.emergencyContactName }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.emergencyContactName"
+                  placeholder="请输入"
+                  clearable
+                  maxlength="10"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="身份证号" prop="emergencyContactIdCard">
+                <template v-if="isDetail">{{ dataForm.emergencyContactIdCard }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.emergencyContactIdCard"
+                  placeholder="请输入身份证号码"
+                  clearable
+                  maxlength="18"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="性别" prop="emergencyContactGender">
+                <template v-if="isDetail">
+                  {{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, dataForm.emergencyContactGender) }}
+                </template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.emergencyContactGender"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+                >
+                  <el-option
+                    v-for="(item, index) in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="年龄" prop="emergencyContactAge">
+                <template v-if="isDetail">{{ dataForm.emergencyContactAge }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.emergencyContactAge"
+                  placeholder="由身份证号自动生成"
+                  clearable
+                  disabled
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="手机号码" prop="emergencyContactPhone">
+                <template v-if="isDetail">{{ dataForm.emergencyContactPhone }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.emergencyContactPhone"
+                  placeholder="请输入"
+                  clearable
+                  maxlength="11"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="固定电话" prop="emergencyContactTel">
+                <template v-if="isDetail">{{ dataForm.emergencyContactTel }}</template>
+                <TgInput
+                  v-else
+                  v-model="dataForm.emergencyContactTel"
+                  placeholder="请输入"
+                  clearable
+                  maxlength="12"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="是长者的" prop="emergencyContactRelation">
+                <template v-if="isDetail">{{ dataForm.emergencyContactRelation }}</template>
+                <TgSelect
+                  v-else
+                  v-model="dataForm.emergencyContactRelation"
+                  placeholder="请选择"
+                  clearable
+                  :list="getDictOptions(DICT_TYPE.RELATIONSHIP_TYPES)"
+                >
+                  <el-option
+                    v-for="(item, index) in getStrDictOptions(DICT_TYPE.RELATIONSHIP_TYPES)"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </TgSelect>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="是否监护人" prop="emergencyContactIsGuardian">
+                <template v-if="isDetail">
+                  {{ dataForm.emergencyContactIsGuardian === '1' ? '是' : '否' }}
+                </template>
+                <TgRadio v-else v-model="dataForm.emergencyContactIsGuardian" clearable>
+                  <el-radio value="1">是</el-radio>
+                  <el-radio value="0">否</el-radio>
+                </TgRadio>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="16" :lg="12">
+              <el-form-item label="居住地址" prop="emergencyContactAddress">
+                <template v-if="isDetail">{{ dataForm.emergencyContactAddress }}</template>
+                <div v-else class="address-wrap">
+                  <el-cascader
+                    v-model="dataForm.emergencyContactArea"
+                    :options="areaTree"
+                    :props="defaultProps"
+                    clearable
+                    placeholder="请选择省市街道"
+                    filterable
+                    class="area-cascader"
+                  />
+                  <TgInput
+                    v-model="dataForm.emergencyContactAddress"
+                    placeholder="请输入详细地址:如街道、小区、楼栋、单元、房号"
+                    clearable
+                    style="width: 30vw;"
+                    maxlength="100"
+                    class="address-input"
+                  />
+                </div>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 亲属信息 -->
+      <div class="info-section">
+        <div style="display: flex;flex-direction: row;align-items: center">
+          <div class="info-title">
+            <div>
+              <span class="title-line"></span>
+              <span>亲属信息</span>
+            </div>
+          </div>
+          <el-button style="margin-left: 20px;margin-bottom: 16px" v-if="!isDetail" @click="addRelative" type="primary" plain >
+            <Icon icon="ep:plus" class="mr-5px" />添加亲属
+          </el-button>
+        </div>
+
+        <div class="info-wrap">
+          <div v-for="(item, index) in dataForm.relativesList" :key="index" class="relative-item">
+            <div class="relative-header">
+              <span class="relative-title">亲属 {{ index + 1 }}</span>
+              <el-button
+                v-if="!isDetail && dataForm.relativesList.length > 1"
+                @click="deleteRelative(index)"
+                type="danger"
+                link
+                size="small"
+              >
+                <Icon icon="ep:delete" />删除
+              </el-button>
+            </div>
+            <el-row :gutter="24">
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '亲属姓名' : ''" :prop="`relativesList.${index}.name`">
+                  <template v-if="isDetail">{{ item.name }}</template>
+                  <TgInput v-else v-model="item.name" placeholder="请输入" clearable maxlength="10" />
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '身份证号' : ''" :prop="`relativesList.${index}.idCard`">
+                  <template v-if="isDetail">{{ item.idCard }}</template>
+                  <TgInput v-else v-model="item.idCard" placeholder="请输入身份证号码" clearable maxlength="18" />
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '性别' : ''" :prop="`relativesList.${index}.gender`">
+                  <template v-if="isDetail">
+                    {{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, item.gender) }}
+                  </template>
+                  <TgSelect
+                    v-else
+                    v-model="item.gender"
+                    placeholder="请选择"
+                    clearable
+                    :list="getDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+                  >
+                    <el-option
+                      v-for="(opt, idx) in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+                      :key="idx"
+                      :label="opt.label"
+                      :value="opt.value"
+                    />
+                  </TgSelect>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '年龄' : ''" :prop="`relativesList.${index}.age`">
+                  <template v-if="isDetail">{{ item.age }}</template>
+                  <TgInput v-else v-model="item.age" placeholder="由身份证号自动生成" clearable disabled />
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '手机号码' : ''" :prop="`relativesList.${index}.phone`">
+                  <template v-if="isDetail">{{ item.phone }}</template>
+                  <TgInput v-else v-model="item.phone" placeholder="请输入" clearable maxlength="11" />
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '固定电话' : ''" :prop="`relativesList.${index}.tel`">
+                  <template v-if="isDetail">{{ item.tel }}</template>
+                  <TgInput v-else v-model="item.tel" placeholder="请输入" clearable maxlength="12" />
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '是长者的' : ''" :prop="`relativesList.${index}.relation`">
+                  <template v-if="isDetail">{{ item.relation }}</template>
+                  <TgSelect
+                    v-else
+                    v-model="item.relation"
+                    placeholder="请选择"
+                    clearable
+                    :list="getDictOptions(DICT_TYPE.RELATIONSHIP_TYPES)"
+                  >
+                    <el-option
+                      v-for="(opt, idx) in getStrDictOptions(DICT_TYPE.RELATIONSHIP_TYPES)"
+                      :key="idx"
+                      :label="opt.label"
+                      :value="opt.value"
+                    />
+                  </TgSelect>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '是否监护人' : ''" :prop="`relativesList.${index}.isGuardian`">
+                  <template v-if="isDetail">{{ item.isGuardian === '1' ? '是' : '否' }}</template>
+                  <TgRadio v-else v-model="item.isGuardian" clearable>
+                    <el-radio value="1">是</el-radio>
+                    <el-radio value="0">否</el-radio>
+                  </TgRadio>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="24" :md="16" :lg="12">
+                <el-form-item :label="index === 0 ? '居住地址' : ''" :prop="`relativesList.${index}.address`">
+                  <template v-if="isDetail">{{ item.address }}</template>
+                  <div v-else class="address-wrap">
+                    <el-cascader
+                      v-model="item.area"
+                      :options="areaTree"
+                      :props="defaultProps"
+                      clearable
+                      placeholder="请选择省市街道"
+                      filterable
+                      class="area-cascader"
+                    />
+                    <TgInput
+                      v-model="item.address"
+                      placeholder="请输入详细地址:如街道、小区、楼栋、单元、房号"
+                      clearable
+                      maxlength="100"
+                      style="width: 30vw;"
+                      class="address-input"
+                    />
+                  </div>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </div>
+        </div>
+      </div>
+
+      <!-- 服务人员信息 -->
+      <div class="info-section">
+        <div style="display: flex;flex-direction: row;align-items: center">
+          <div class="info-title flex-between">
+            <div>
+              <span class="title-line"></span>
+              <span>服务人员信息</span>
+            </div>
+          </div>
+          <el-button style="margin-bottom: 15px;margin-left: 20px" v-if="!isDetail" @click="openServicePersonDialog" type="primary" plain>
+            <Icon icon="ep:plus" class="mr-5px" />新增服务人员
+          </el-button>
+        </div>
+
+        <div class="info-wrap">
+          <div v-if="dataForm.servicePersonList.length === 0" class="empty-text">
+            尚未添加服务人员
+          </div>
+          <div v-for="(item, index) in dataForm.servicePersonList" :key="index" class="person-item">
+            <div class="person-header">
+              <span class="person-title">服务人员 {{ index + 1 }}</span>
+              <el-button
+                v-if="!isDetail"
+                @click="deleteServicePerson(index)"
+                type="danger"
+                link
+                size="small"
+              >
+                <Icon icon="ep:delete" />删除
+              </el-button>
+            </div>
+            <el-row :gutter="24">
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '姓名' : ''">
+                  <span>{{ item.name }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '性别' : ''">
+                  <span>{{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, item.gender) }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '年龄' : ''">
+                  <span>{{ item.age }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '手机号码' : ''">
+                  <span>{{ item.phone }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '服务区域' : ''">
+                  <span>{{ item.serviceArea }}</span>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </div>
+        </div>
+      </div>
+
+      <!-- 服务人员选择弹窗 -->
+      <el-dialog v-model="servicePersonDialogVisible" title="选择服务人员" width="60%" append-to-body>
+        <div class="search-form">
+          <el-form :inline="true" :model="servicePersonQueryParams" class="demo-form-inline">
+            <el-form-item label="姓名">
+              <el-input v-model="servicePersonQueryParams.name" placeholder="请输入姓名" clearable />
+            </el-form-item>
+            <el-form-item label="手机号码">
+              <el-input v-model="servicePersonQueryParams.phone" placeholder="请输入手机号码" clearable />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="searchServicePerson">查询</el-button>
+              <el-button @click="resetServicePersonQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+        <el-table
+          v-loading="servicePersonLoading"
+          :data="servicePersonList"
+          @selection-change="handleServicePersonSelectionChange"
+          max-height="400"
+        >
+          <el-table-column type="selection" width="55" />
+          <el-table-column prop="name" label="姓名" width="120" />
+          <el-table-column prop="gender" label="性别" width="80">
+            <template #default="scope">
+              {{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, scope.row.gender) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="age" label="年龄" width="80" />
+          <el-table-column prop="phone" label="手机号码" width="150" />
+          <el-table-column prop="serviceArea" label="服务区域" show-overflow-tooltip />
+        </el-table>
+        <template #footer>
+          <span class="dialog-footer">
+            <el-button @click="servicePersonDialogVisible = false">取消</el-button>
+            <el-button type="primary" @click="confirmServicePerson">确定</el-button>
+          </span>
+        </template>
+      </el-dialog>
+
+      <!-- 应急人员信息 -->
+      <div class="info-section">
+        <div style="display: flex;flex-direction: row;align-items: center">
+          <div class="info-title flex-between">
+            <div>
+              <span class="title-line"></span>
+              <span>应急人员信息</span>
+            </div>
+          </div>
+          <el-button style="margin-bottom: 15px;margin-left: 20px" v-if="!isDetail" @click="openEmergencyPersonDialog" type="primary" plain>
+            <Icon icon="ep:plus" class="mr-5px" />新增应急人员
+          </el-button>
+        </div>
+
+        <div class="info-wrap">
+          <div v-if="dataForm.emergencyPersonList.length === 0" class="empty-text">
+            尚未添加应急人员
+          </div>
+          <div v-for="(item, index) in dataForm.emergencyPersonList" :key="index" class="person-item">
+            <div class="person-header">
+              <span class="person-title">应急人员 {{ index + 1 }}</span>
+              <el-button
+                v-if="!isDetail"
+                @click="deleteEmergencyPerson(index)"
+                type="danger"
+                link
+                size="small"
+              >
+                <Icon icon="ep:delete" />删除
+              </el-button>
+            </div>
+            <el-row :gutter="24">
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '姓名' : ''">
+                  <span>{{ item.name }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '性别' : ''">
+                  <span>{{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, item.gender) }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '年龄' : ''">
+                  <span>{{ item.age }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '手机号码' : ''">
+                  <span>{{ item.phone }}</span>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6">
+                <el-form-item :label="index === 0 ? '服务区域' : ''">
+                  <span>{{ item.serviceArea }}</span>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </div>
+        </div>
+      </div>
+
+      <!-- 应急人员选择弹窗 -->
+      <el-dialog v-model="emergencyPersonDialogVisible" title="选择应急人员" width="60%" append-to-body>
+        <div class="search-form">
+          <el-form :inline="true" :model="emergencyPersonQueryParams" class="demo-form-inline">
+            <el-form-item label="姓名">
+              <el-input v-model="emergencyPersonQueryParams.name" placeholder="请输入姓名" clearable />
+            </el-form-item>
+            <el-form-item label="手机号码">
+              <el-input v-model="emergencyPersonQueryParams.phone" placeholder="请输入手机号码" clearable />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="searchEmergencyPerson">查询</el-button>
+              <el-button @click="resetEmergencyPersonQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+        <el-table
+          v-loading="emergencyPersonLoading"
+          :data="emergencyPersonList"
+          @selection-change="handleEmergencyPersonSelectionChange"
+          max-height="400"
+        >
+          <el-table-column type="selection" width="55" />
+          <el-table-column prop="name" label="姓名" width="120" />
+          <el-table-column prop="gender" label="性别" width="80">
+            <template #default="scope">
+              {{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, scope.row.gender) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="age" label="年龄" width="80" />
+          <el-table-column prop="phone" label="手机号码" width="150" />
+          <el-table-column prop="serviceArea" label="服务区域" show-overflow-tooltip />
+        </el-table>
+        <template #footer>
+          <span class="dialog-footer">
+            <el-button @click="emergencyPersonDialogVisible = false">取消</el-button>
+            <el-button type="primary" @click="confirmEmergencyPerson">确定</el-button>
+          </span>
+        </template>
+      </el-dialog>
+
+      <!-- 其他信息 -->
+      <div class="info-section">
+        <div class="info-title">
+          <span class="title-line"></span>
+          <span>其他信息</span>
+        </div>
+        <div class="info-wrap">
+          <el-row :gutter="24">
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="登记人" prop="registerPerson" required>
+                <template v-if="isDetail">{{ dataForm.registerPerson }}</template>
+                <TgInput v-else v-model="dataForm.registerPerson" placeholder="请输入" clearable maxlength="10" />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="登记人电话" prop="registerPhone" required>
+                <template v-if="isDetail">{{ dataForm.registerPhone }}</template>
+                <TgInput v-else v-model="dataForm.registerPhone" placeholder="请输入" clearable maxlength="11" />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="登记时间" prop="registerTime" required>
+                <template v-if="isDetail">{{ dataForm.registerTime }}</template>
+                <TgDatePicker
+                  v-else
+                  type="datetime"
+                  v-model="dataForm.registerTime"
+                  placeholder="请选择"
+                  clearable
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6">
+              <el-form-item label="接待人员" prop="receivePerson">
+                <template v-if="isDetail">{{ dataForm.receivePerson }}</template>
+                <TgInput v-else v-model="dataForm.receivePerson" placeholder="请输入" clearable maxlength="10" />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 附件上传 -->
+      <div class="info-section">
+        <div class="info-title">
+          <span class="title-line"></span>
+          <span>附件</span>
+        </div>
+        <div class="info-wrap">
+          <el-form-item label="其他附件" prop="otherFiles">
+            <SelectUpload
+              fun-name="其他附件"
+              v-model="dataForm.otherFiles"
+              :elder="{ elderId: dataForm.id, elderName: dataForm.elderName }"
+              :isDetail="isDetail"
+            />
+          </el-form-item>
+        </div>
+      </div>
+    </el-form>
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button v-loading="formLoading" type="primary" @click="submitForm" v-if="!isDetail">提交</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import {
+  getElderDetail,
+  addElder,
+  updateElder,
+  getServicePersonPage,
+  getEmergencyPersonPage
+} from '@/api/living-home/elderly'
+import { DICT_TYPE, getDictLabel, getDictOptions, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
+import { FormRules } from 'element-plus'
+import { useValidator } from '@/hooks/web/useValidator'
+import { getInfo } from '@/utils'
+import { defaultProps } from '@/utils/tree'
+import * as AreaApi from '@/api/system/area'
+import { formatTime } from '@/utils'
+
+
+defineOptions({ name: 'ElderlyPersonFileForm' })
+const { idCardValidity, validatePhone } = useValidator()
+const message = useMessage()
+const dialogVisible = ref(false)
+const formLoading = ref(false)
+const isDetail = ref(false)
+const titleName = ref('')
+const formRef = ref()
+const areaTree = ref([])
+
+// 视力选项
+const visionOptions = [
+  { label: '正常', value: '正常' },
+  { label: '轻度障碍', value: '轻度障碍' },
+  { label: '中度障碍', value: '中度障碍' },
+  { label: '重度障碍', value: '重度障碍' },
+  { label: '失明', value: '失明' }
+]
+
+// 表单数据
+let dataForm = reactive({
+  id: '',
+  tenantId: undefined,
+  elderName: '',
+  papersType: 1,
+  idCard: '',
+  personalPhone: '',
+  currentArea: '',
+  currentAddress: '',
+  householdArea: '',
+  householdAddress: '',
+  birthday: '',
+  gender: 1,
+  homeTel: '',
+  nationId: '1',
+  maritalStatus: '',
+  occupation: '',
+  selfCareStatus: '',
+  degreeEducation: '',
+  disabilityType: '',
+  liveSituation: '',
+  livingArea: undefined,
+  householdType: '',
+  economySource: '',
+  monthlyIncome: undefined,
+  medicalType: '',
+  pensionWay: '',
+  intentionService: '',
+  groupTag: '1',
+  painPoint: '',
+  trackRecord: '',
+  mapLocation: '',
+  longitude: '',
+  latitude: '',
+  isMigrant: '0',
+  isLocalHousehold: '1',
+  isEnjoyService: '0',
+  serviceTimes: undefined,
+  // 健康信息
+  healthStatus: '',
+  bloodType: '',
+  medicalCardNo: '',
+  vision: '',
+  hearing: '',
+  basicIllness: '',
+  basicIllnessList: [],
+  medicalHistory: '',
+  // 紧急联系人
+  emergencyContactName: '',
+  emergencyContactIdCard: '',
+  emergencyContactGender: '',
+  emergencyContactAge: undefined,
+  emergencyContactPhone: '',
+  emergencyContactTel: '',
+  emergencyContactRelation: '',
+  emergencyContactIsGuardian: '0',
+  emergencyContactArea: '',
+  emergencyContactAddress: '',
+  // 亲属信息
+  relativesList: [{
+    name: '',
+    idCard: '',
+    gender: '',
+    age: undefined,
+    phone: '',
+    tel: '',
+    relation: '',
+    isGuardian: '0',
+    area: '',
+    address: ''
+  }],
+  // 其他信息
+  registerPerson: '',
+  registerPhone: '',
+  registerTime: '',
+  receivePerson: '',
+  // 账户信息(编辑/详情时显示)
+  accountBalance: 0,
+  voucherBalance: 0,
+  cashBalance: 0,
+  qrCodeUrl: '',
+  // 服务人员信息
+  servicePersonList: [],
+  // 应急人员信息
+  emergencyPersonList: [],
+  // 附件
+  otherFiles: []
+})
+
+const resetFormField = reactive({...dataForm})
+
+// 表单验证规则
+const dataRule = reactive<FormRules>({
+  elderName: [
+    { required: true, message: '姓名不能为空', trigger: 'blur' }
+  ],
+  idCard: [
+    { required: true, message: '证件号不能为空', trigger: 'blur' },
+    idCardValidity()
+  ],
+  personalPhone: [
+    { required: true, message: '手机号码不能为空', trigger: 'blur' },
+    validatePhone()
+  ],
+  gender: [
+    { required: true, message: '请选择性别', trigger: 'change' }
+  ],
+  pensionWay: [
+    { required: true, message: '请选择意向养老方式', trigger: 'change' }
+  ],
+  registerPerson: [
+    { required: true, message: '登记人不能为空', trigger: 'blur' }
+  ],
+  registerPhone: [
+    { required: true, message: '登记人电话不能为空', trigger: 'blur' },
+    validatePhone()
+  ],
+  registerTime: [
+    { required: true, message: '登记时间不能为空', trigger: 'change' }
+  ]
+})
+
+// 监听身份证号变化,自动填充性别和出生日期
+watch(
+  () => dataForm.idCard,
+  (val: string) => {
+    const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
+    if (!reg.test(val) && val !== '') {
+      dataForm.birthday = ''
+      dataForm.gender = 1
+    } else {
+      const info = getInfo(val)
+      dataForm.birthday = info.birth
+      dataForm.gender = info.sex
+    }
+  }
+)
+
+// 监听紧急联系人身份证号变化
+watch(
+  () => dataForm.emergencyContactIdCard,
+  (val: string) => {
+    const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
+    if (reg.test(val)) {
+      const info = getInfo(val)
+      dataForm.emergencyContactAge = info.age
+    }
+  }
+)
+
+// 监听亲属身份证号变化
+watch(
+  () => dataForm.relativesList,
+  (list) => {
+    list.forEach((item) => {
+      const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
+      if (reg.test(item.idCard)) {
+        const info = getInfo(item.idCard)
+        item.age = info.age
+      }
+    })
+  },
+  { deep: true }
+)
+
+// 身份证号变化处理
+const handleIdCardChange = () => {
+  // 如果需要处理其他逻辑可以在这里扩展
+}
+
+// 选择地图位置
+const selectMapLocation = () => {
+  message.info('地图选择功能开发中')
+}
+
+// 查看长者码介绍
+const viewIntro = () => {
+  message.info('查看介绍功能开发中')
+}
+
+// 添加亲属
+const addRelative = () => {
+  dataForm.relativesList.push({
+    name: '',
+    idCard: '',
+    gender: '',
+    age: undefined,
+    phone: '',
+    tel: '',
+    relation: '',
+    isGuardian: '0',
+    area: '',
+    address: ''
+  })
+}
+
+// 删除亲属
+const deleteRelative = (index: number) => {
+  if (dataForm.relativesList.length > 1) {
+    dataForm.relativesList.splice(index, 1)
+  }
+}
+
+// 服务人员选择弹窗相关
+const servicePersonDialogVisible = ref(false)
+const servicePersonLoading = ref(false)
+const servicePersonList = ref<any[]>([])
+const selectedServicePersonList = ref<any[]>([])
+const servicePersonQueryParams = reactive({
+  name: '',
+  phone: '',
+  serviceArea: ''
+})
+
+// 打开服务人员选择弹窗
+const openServicePersonDialog = () => {
+  servicePersonDialogVisible.value = true
+  selectedServicePersonList.value = []
+  resetServicePersonQuery()
+  searchServicePerson()
+}
+
+// 查询服务人员
+const searchServicePerson = async () => {
+  servicePersonLoading.value = true
+  try {
+    const res = await getServicePersonPage({
+      pageNo: 1,
+      pageSize: 100,
+      ...servicePersonQueryParams
+    })
+    servicePersonList.value = res.list || []
+  } catch (err) {
+    servicePersonList.value = []
+  } finally {
+    servicePersonLoading.value = false
+  }
+}
+
+// 重置服务人员查询
+const resetServicePersonQuery = () => {
+  servicePersonQueryParams.name = ''
+  servicePersonQueryParams.phone = ''
+  servicePersonQueryParams.serviceArea = ''
+}
+
+// 服务人员选择变化
+const handleServicePersonSelectionChange = (selection: any[]) => {
+  selectedServicePersonList.value = selection
+}
+
+// 确认选择服务人员
+const confirmServicePerson = () => {
+  if (selectedServicePersonList.value.length === 0) {
+    message.warning('请选择至少一个服务人员')
+    return
+  }
+  // 添加到已选列表,过滤重复
+  selectedServicePersonList.value.forEach(person => {
+    const exists = dataForm.servicePersonList.some(p => p.id === person.id)
+    if (!exists) {
+      dataForm.servicePersonList.push({
+        id: person.id,
+        name: person.name,
+        gender: person.gender,
+        age: person.age,
+        phone: person.phone,
+        serviceArea: person.serviceArea
+      })
+    }
+  })
+  servicePersonDialogVisible.value = false
+  message.success('添加成功')
+}
+
+// 删除服务人员
+const deleteServicePerson = (index: number) => {
+  dataForm.servicePersonList.splice(index, 1)
+}
+
+// 应急人员选择弹窗相关
+const emergencyPersonDialogVisible = ref(false)
+const emergencyPersonLoading = ref(false)
+const emergencyPersonList = ref<any[]>([])
+const selectedEmergencyPersonList = ref<any[]>([])
+const emergencyPersonQueryParams = reactive({
+  name: '',
+  phone: ''
+})
+
+// 打开应急人员选择弹窗
+const openEmergencyPersonDialog = () => {
+  emergencyPersonDialogVisible.value = true
+  selectedEmergencyPersonList.value = []
+  resetEmergencyPersonQuery()
+  searchEmergencyPerson()
+}
+
+// 查询应急人员
+const searchEmergencyPerson = async () => {
+  emergencyPersonLoading.value = true
+  try {
+    const res = await getEmergencyPersonPage({
+      pageNo: 1,
+      pageSize: 100,
+      ...emergencyPersonQueryParams
+    })
+    emergencyPersonList.value = res.list || []
+  } catch (err) {
+    emergencyPersonList.value = []
+  } finally {
+    emergencyPersonLoading.value = false
+  }
+}
+
+// 重置应急人员查询
+const resetEmergencyPersonQuery = () => {
+  emergencyPersonQueryParams.name = ''
+  emergencyPersonQueryParams.phone = ''
+}
+
+// 应急人员选择变化
+const handleEmergencyPersonSelectionChange = (selection: any[]) => {
+  selectedEmergencyPersonList.value = selection
+}
+
+// 确认选择应急人员
+const confirmEmergencyPerson = () => {
+  if (selectedEmergencyPersonList.value.length === 0) {
+    message.warning('请选择至少一个应急人员')
+    return
+  }
+  // 添加到已选列表,过滤重复
+  selectedEmergencyPersonList.value.forEach(person => {
+    const exists = dataForm.emergencyPersonList.some(p => p.id === person.id)
+    if (!exists) {
+      dataForm.emergencyPersonList.push({
+        id: person.id,
+        name: person.name,
+        gender: person.gender,
+        age: person.age,
+        phone: person.phone,
+        serviceArea: person.serviceArea
+      })
+    }
+  })
+  emergencyPersonDialogVisible.value = false
+  message.success('添加成功')
+}
+
+// 删除应急人员
+const deleteEmergencyPerson = (index: number) => {
+  dataForm.emergencyPersonList.splice(index, 1)
+}
+
+/** 打开弹窗 */
+const open = async (id?: string | number, detail?: boolean, tId?: number) => {
+  dialogVisible.value = true
+  titleName.value = id ? '编辑长者档案' : '新增长者档案'
+  isDetail.value = detail || false
+  dataForm.id = id || ''
+
+  // 加载区域数据
+  if (areaTree.value.length === 0) {
+    areaTree.value = await AreaApi.getAreaTree()
+  }
+
+  if (id) {
+    try {
+      const res = await getElderDetail(id)
+      Object.assign(dataForm, res)
+      // 处理基础病数组
+      if (res.basicIllness) {
+        dataForm.basicIllnessList = res.basicIllness.split(',')
+      }
+    } catch (err) {}
+  } else {
+    nextTick(() => {
+      dataForm.tenantId = tId
+    })
+  }
+}
+
+defineExpose({ open })
+
+// 获取提交数据
+const getSubmitData = () => {
+  const params = { ...JSON.parse(JSON.stringify(dataForm)) }
+  // 处理基础病数组转字符串
+  if (params.basicIllnessList && params.basicIllnessList.length > 0) {
+    params.basicIllness = params.basicIllnessList.join(',')
+  }
+  delete params.basicIllnessList
+  // 处理区域数据
+  if (Array.isArray(params.currentArea)) {
+    params.currentArea = params.currentArea.join('/')
+  }
+  if (Array.isArray(params.householdArea)) {
+    params.householdArea = params.householdArea.join('/')
+  }
+  // 格式化时间
+  if (params.registerTime && params.registerTime instanceof Date) {
+    params.registerTime = formatTime(params.registerTime, 'yyyy-MM-dd HH:mm:ss')
+  }
+  return params
+}
+
+const emit = defineEmits(['success'])
+
+/** 提交表单 */
+const submitForm = async () => {
+  if (formLoading.value) {
+    return
+  }
+  formLoading.value = true
+  try {
+    if (!formRef.value) return
+    const valid = await formRef.value.validate()
+    if (!valid) return
+
+    const params = getSubmitData()
+    const res = params.id ? await updateElder(params) : await addElder(params)
+    if (res) {
+      message.success(params.id ? '编辑成功' : '新增成功')
+      emit('success')
+      handleClosed()
+    }
+  } finally {
+    setTimeout(() => {
+      formLoading.value = false
+    }, 500)
+  }
+}
+
+// 关闭表单
+const handleClosed = () => {
+  formRef.value?.resetFields()
+  Object.assign(dataForm, resetFormField)
+  dialogVisible.value = false
+}
+</script>
+
+<style lang="scss" scoped>
+.elderly-form-dialog {
+  :deep(.el-dialog__body) {
+    padding: 20px;
+    max-height: 70vh;
+    overflow-y: auto;
+  }
+}
+
+.elderly-form-content {
+  .info-section {
+    margin-bottom: 20px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    &.account-section {
+      .account-info-wrap {
+        background-color: #f5f7fa;
+        border-radius: 8px;
+        padding: 20px;
+        height: 100%;
+
+        .account-title {
+          display: flex;
+          align-items: center;
+          margin-bottom: 15px;
+          font-weight: bold;
+          font-size: 16px;
+          color: #303133;
+
+          .title-line {
+            display: inline-block;
+            width: 4px;
+            height: 16px;
+            background-color: #409eff;
+            margin-right: 8px;
+            border-radius: 2px;
+          }
+        }
+
+        .account-balance-list {
+          .balance-item {
+            display: flex;
+            align-items: center;
+            margin-bottom: 12px;
+            font-size: 14px;
+
+            &:last-child {
+              margin-bottom: 0;
+            }
+
+            .balance-label {
+              color: #606266;
+              width: 80px;
+              text-align: right;
+              margin-right: 8px;
+            }
+
+            .balance-value {
+              color: #303133;
+              font-weight: 500;
+            }
+          }
+        }
+      }
+
+      .qr-code-wrap {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        background-color: #f5f7fa;
+        border-radius: 8px;
+        padding: 15px;
+        height: 100%;
+
+        .qr-code-img {
+          width: 120px;
+          height: 120px;
+          background-color: #fff;
+          border: 1px solid #dcdfe6;
+          border-radius: 4px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          overflow: hidden;
+
+          img {
+            width: 100%;
+            height: 100%;
+            object-fit: contain;
+          }
+
+          .qr-code-placeholder {
+            color: #c0c4cc;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+          }
+        }
+
+        .qr-code-text {
+          margin-top: 8px;
+          font-size: 14px;
+          color: #606266;
+          text-align: center;
+        }
+      }
+    }
+  }
+
+  .info-title {
+    display: flex;
+    align-items: center;
+    margin-bottom: 15px;
+    font-weight: bold;
+    font-size: 16px;
+    color: #303133;
+
+    .title-line {
+      display: inline-block;
+      width: 4px;
+      height: 16px;
+      background-color: #409eff;
+      margin-right: 8px;
+      border-radius: 2px;
+    }
+
+    &.flex-between {
+      justify-content: space-between;
+    }
+  }
+
+  .info-wrap {
+    padding: 20px;
+    background-color: #f5f7fa;
+    border-radius: 8px;
+  }
+
+  .mt-20 {
+    margin-top: 20px;
+  }
+
+  .map-location-wrap {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+
+    .map-input {
+      flex: 1;
+    }
+  }
+
+  .address-wrap {
+    display: flex;
+    gap: 10px;
+
+    .area-cascader {
+      width: 200px;
+    }
+
+    .address-input {
+      flex: 1;
+    }
+  }
+
+  .relative-item {
+    background-color: #fff;
+    padding: 15px;
+    border-radius: 6px;
+    margin-bottom: 15px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    .relative-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 15px;
+      padding-bottom: 10px;
+      border-bottom: 1px solid #ebeef5;
+
+      .relative-title {
+        font-weight: 500;
+        color: #606266;
+      }
+    }
+  }
+
+  .person-item {
+    background-color: #fff;
+    padding: 15px;
+    border-radius: 6px;
+    margin-bottom: 15px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    .person-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 15px;
+      padding-bottom: 10px;
+      border-bottom: 1px solid #ebeef5;
+
+      .person-title {
+        font-weight: 500;
+        color: #606266;
+      }
+    }
+  }
+
+  .empty-text {
+    text-align: center;
+    color: #909399;
+    padding: 30px 0;
+    font-size: 14px;
+  }
+}
+
+// 弹窗搜索表单样式
+.search-form {
+  margin-bottom: 20px;
+  padding: 15px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+}
+
+:deep(.el-form-item__label) {
+  font-weight: 500;
+}
+
+:deep(.el-checkbox-group) {
+  .el-checkbox {
+    margin-right: 20px;
+  }
+}
+</style>

+ 571 - 0
src/views/living-home/elderlyManage/elderly-person-file-out/index.vue

@@ -0,0 +1,571 @@
+<template>
+  <div class="elderly-list-container">
+    <el-card shadow="hover">
+
+
+      <div class="search-form">
+        <el-form :inline="true" :model="queryParams" class="demo-form-inline">
+
+          <el-form-item label="长者姓名" >
+            <el-input @keyup.enter="handleQuery" v-model="queryParams.elderName" placeholder="请输入长者姓名" clearable />
+          </el-form-item>
+          <el-form-item label="身份证号">
+            <el-input @keyup.enter="handleQuery" v-model="queryParams.idCard" placeholder="请输入身份证号" clearable />
+          </el-form-item>
+          <el-form-item label="联系电话">
+            <el-input @keyup.enter="handleQuery" v-model="queryParams.personalPhone" placeholder="请输入联系电话" clearable />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="handleQuery">查询</el-button>
+            <el-button @click="resetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    <el-divider style="margin-top: 0"/>
+      <view>
+<!--        <el-button :disabled="ids.length<=0" :loading="deleteBatchLoading" @click="handleDeleteBatch" type="warning">{{ids.length>0?`批量删除长者(已选:${ids.length})`:'批量删除长者'}}</el-button>-->
+
+        <el-button type="warning" @click="clickHandler">导入</el-button>
+        <el-button type="success" @click="exportElderly">导出</el-button>
+      </view>
+
+      <el-table
+        v-loading="loading"
+        :data="elderlyList"
+        style="width: 100%;margin-top: 8px"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="elderName" label="姓名" width="150" />
+        <el-table-column prop="gender" label="性别" width="80">
+          <template #default="scope">
+            {{ scope.row.gender === 1 ? '男' : '女' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="age" label="年龄" width="80" />
+        <el-table-column prop="personalPhone" label="手机号" width="180" />
+        <el-table-column prop="homeTel" label="固定电话" width="180" />
+        <el-table-column prop="selfCareStatus" label="自理情况" width="180">
+          <template #default="scope">
+            {{ scope.row.selfCareStatus === '1' ? '自理' : scope.row.selfCareStatus === '2' ? '半自理' : '不能自理' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="liveSituation" label="居住情况" width="180">
+          <template #default="scope">
+            {{ scope.row.liveSituation === '1' ? '独居' : scope.row.liveSituation === '2' ? '与配偶同住' : '与子女同住' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="账户余额" width="150" align="center">
+          <template #default="scope">
+            <div>代金券:{{scope.row.voucherBalance || 0}}元</div>
+            <div>现金:{{scope.row.cashBalance || 0}}元</div>
+          </template>
+        </el-table-column>
+        <el-table-column label="是否享受服务" width="120" align="center">
+          <template #default="scope">
+            <el-switch v-model="scope.row.isEnjoyService" active-value="1" inactive-value="0" disabled />
+          </template>
+        </el-table-column>
+        <el-table-column prop="serviceTimes" label="年享受服务次数" width="120" align="center" />
+        <el-table-column prop="currentAddress" label="居住地址" width="200" show-overflow-tooltip />
+        <el-table-column prop="registerTime" label="登记入住时间" width="180" />
+        <el-table-column prop="checkoutTime" label="退住时间" width="180" />
+        <el-table-column prop="checkoutReason" label="退住原因" width="200" show-overflow-tooltip />
+
+        <el-table-column label="操作" width="220" fixed="right" align="center">
+          <template #default="scope">
+
+            <el-button type="text" @click="handleEdit(scope.row,false)">编辑</el-button>
+            <el-button type="text" @click="handleEdit(scope.row,true)">详情</el-button>
+            <el-button type="text" style="color: #f56c6c" @click="handleDelete(scope.row)">恢复入住</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="pagination-container">
+        <el-pagination
+          v-model:current-page="queryParams.pageNo"
+          v-model:page-size="queryParams.pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="total"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-card>
+
+
+
+
+    <Import
+      ref="importRef"
+      @success="getList"
+      :config="{
+      title: '导入',
+      downloadUrl: 'ykCenter/elderly/downloadExcel',
+      excelTempName: '颐康中心-【导入长者】模板',
+      importUrl: '/ykCenter/elderly/import',
+      failExportUrl: ''
+    }"
+    />
+
+
+    <Form ref="formRef"/>
+
+
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted } from 'vue'
+import { useRouter } from 'vue-router'
+import {getElderlyList, updateElderlyInfo, deleteElderly, deleteElderlyBatch} from '@/api/ykCenter'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import Import from "@/components/ImportFile/index.vue";
+import Form from "./Form.vue";
+import {useUserStore} from "@/store/modules/user";
+const router = useRouter()
+const userStore = useUserStore()
+const importRef = ref() //导入
+const formRef = ref() //导入
+const deleteBatchLoading = ref(false) //
+const message = useMessage() // 消息弹窗
+// 获取本月日期范围
+const getCurrentMonthRange = () => {
+  const now = new Date()
+  const year = now.getFullYear()
+  const month = now.getMonth()
+  const firstDay = new Date(year, month, 1)
+  const lastDay = new Date(year, month + 1, 0) // 下个月的第0天就是本月的最后一天
+
+  // 格式化为 YYYY-MM-DD
+  const formatDate = (date: Date) => {
+    const y = date.getFullYear()
+    const m = String(date.getMonth() + 1).padStart(2, '0')
+    const d = String(date.getDate()).padStart(2, '0')
+    return `${y}-${m}-${d}`
+  }
+
+  return [formatDate(firstDay), formatDate(lastDay)]
+}
+
+
+const ids = ref([])
+const handleSelectionChange = (val) => {
+  ids.value = val.map((item) => item.id)
+}
+
+// 查询参数
+const currentMonthRange = getCurrentMonthRange()
+const queryParams = ref({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  idCard: '',
+  personalPhone: '',
+  //dateRange: currentMonthRange,
+  // startDate: currentMonthRange[0],
+  // endDate: currentMonthRange[1],
+  tenantIds: userStore.orgTenantId
+})
+
+// 列表数据
+const elderlyList = ref([])
+const total = ref(0)
+const loading = ref(false)
+const selectedRows = ref([])
+
+// 详情对话框
+const detailVisible = ref(false)
+const currentElderly = ref(null)
+
+
+
+// 表单验证规则
+const balanceRules = {
+  paymentType: [
+    { required: true, message: '请选择支付类型', trigger: 'change' }
+  ],
+  diningBalance: [
+    { required: true, message: '请输入堂食余额', trigger: 'blur' }
+  ],
+  deliveryBalance: [
+    { required: true, message: '请输入送餐余额', trigger: 'blur' }
+  ],
+  reason: [
+    { required: true, message: '请输入更新原因', trigger: 'blur' }
+  ]
+}
+
+
+
+const handleDeleteBatch = async () => {
+
+  let dsc = `确定要删除这些长者吗?`
+  ElMessageBox.confirm(dsc, '提示', {
+    confirmButtonText: '确 认',
+    cancelButtonText: '取 消'
+  }).then(async () => {
+    try {
+      deleteBatchLoading.value=true
+      const res = await deleteElderlyBatch(ids.value)
+      if(res){
+        message.success("删除成功")
+        queryParams.value.pageNo = 1
+        await getList()
+      }
+    }catch (_){}finally {
+      deleteBatchLoading.value=false
+    }
+
+  })
+    .catch(() => console.info('操作取消'))
+}
+
+
+
+// 编辑对话框
+const editVisible = ref(false)
+const editFormRef = ref()
+const editForm = ref({
+  id: '',
+  elderName: '',
+  idCard: '',
+  personalPhone: '',
+  emergencyContact: '',
+  emergencyContactPhone: '',
+  currentAddress: '',
+  status: '已失效',
+  tenantIds: userStore.orgTenantId
+})
+
+// 编辑表单验证规则
+const editRules = {
+  elderName: [
+    { required: true, message: '请输入姓名', trigger: 'blur' }
+  ],
+  gender: [],
+  age: [
+    { type: 'number', min: 1, max: 150, message: '年龄必须在1-150之间', trigger: 'blur' }
+  ],
+  idCard: [
+    { pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, message: '请输入正确的身份证号', trigger: 'blur' }
+  ],
+  personalPhone: [
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+  ],
+  emergencyContactPhone: [
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+  ],
+  status: [
+    { required: true, message: '请选择状态', trigger: 'change' }
+  ]
+}
+
+// 导航到指定页面
+const navigateTo = (path: string) => {
+  router.push(`/ykCenter/${path}`)
+}
+
+const clickHandler = () => {
+  importRef.value.open()
+}
+const add = () => {
+  formRef.value.open(1,false,1,queryParams.value.tenantIds)
+}
+
+// 处理日期范围变化
+const handleDateChange = (value: any) => {
+  if (value && value.length === 2) {
+    queryParams.value.startDate = value[0]
+    queryParams.value.endDate = value[1]
+  } else {
+    queryParams.value.startDate = ''
+    queryParams.value.endDate = ''
+  }
+}
+
+// 默认假数据 - 退住长者
+const defaultElderlyList = [
+  {
+    id: '1',
+    elderName: '陈大爷',
+    gender: 1,
+    age: 80,
+    personalPhone: '13600136001',
+    homeTel: '0769-11112222',
+    selfCareStatus: '3',
+    liveSituation: '2',
+    voucherBalance: 200,
+    cashBalance: 800,
+    isEnjoyService: '1',
+    serviceTimes: 36,
+    currentAddress: '东莞市莞城区莞太路10号',
+    registerTime: '2022-05-15 10:30:00',
+    checkoutTime: '2024-06-20 15:00:00',
+    checkoutReason: '家属接回居家养老'
+  },
+  {
+    id: '2',
+    elderName: '刘奶奶',
+    gender: 2,
+    age: 85,
+    personalPhone: '13500135002',
+    homeTel: '0769-33334444',
+    selfCareStatus: '4',
+    liveSituation: '3',
+    voucherBalance: 0,
+    cashBalance: 300,
+    isEnjoyService: '0',
+    serviceTimes: 48,
+    currentAddress: '东莞市厚街镇厚街大道20号',
+    registerTime: '2021-03-10 09:00:00',
+    checkoutTime: '2024-05-18 11:30:00',
+    checkoutReason: '转院至医疗机构'
+  },
+  {
+    id: '3',
+    elderName: '赵爷爷',
+    gender: 1,
+    age: 77,
+    personalPhone: '13300133003',
+    homeTel: '0769-55556666',
+    selfCareStatus: '2',
+    liveSituation: '1',
+    voucherBalance: 100,
+    cashBalance: 600,
+    isEnjoyService: '1',
+    serviceTimes: 18,
+    currentAddress: '东莞市寮步镇寮步大道30号',
+    registerTime: '2023-01-20 14:00:00',
+    checkoutTime: '2024-04-25 16:45:00',
+    checkoutReason: '个人原因申请退住'
+  }
+]
+
+// 获取长者列表
+const getList = async () => {
+  loading.value = true
+  try {
+    // 构建请求参数
+    const params = {
+      ...queryParams.value
+    }
+    const res = await getElderlyList(params)
+    console.log('获取长者列表成功:', res)
+    // 如果接口返回数据为空,使用默认假数据
+    elderlyList.value = res.list?.length > 0 ? res.list : defaultElderlyList
+    total.value = res.total || elderlyList.value.length
+  } catch (error) {
+    console.error('获取长者列表失败:', error)
+    // 接口失败时使用默认假数据
+    elderlyList.value = defaultElderlyList
+    total.value = defaultElderlyList.length
+    ElMessage.warning('使用默认数据展示')
+  } finally {
+    loading.value = false
+  }
+}
+
+// 查询
+const handleQuery = () => {
+  queryParams.value.pageNo = 1
+  getList()
+}
+
+// 重置查询
+const resetQuery = () => {
+  const range = getCurrentMonthRange()
+  queryParams.value = {
+    pageNo: 1,
+    pageSize: 10,
+    elderName: '',
+    idCard: '',
+    personalPhone: '',
+    // dateRange: range,
+    // startDate: range[0],
+    // endDate: range[1]
+    tenantIds: userStore.orgTenantId
+  }
+  getList()
+}
+
+
+// 每页数量变化
+const handleSizeChange = (val: number) => {
+  queryParams.value.pageSize = val
+  getList()
+}
+
+// 当前页变化
+const handleCurrentChange = (val: number) => {
+  queryParams.value.pageNo = val
+  getList()
+}
+
+// 查看详情
+const handleDetail = async (row: any) => {
+  try {
+    detailVisible.value = true
+    // 使用模拟数据
+    const mockData = (await import('@/api/ykCenter')).mockData
+    const elderly = mockData.elderlyList.list.find(item => item.id === row.id)
+    currentElderly.value = elderly || row
+
+    // 如果实际API可用,取消下面注释并注释掉上面的模拟数据代码
+    // const res = await getElderlyDetail(row.id)
+    // currentElderly.value = res.data
+    detailVisible.value = true
+  } catch (error) {
+    console.error('获取长者详情失败:', error)
+    ElMessage.error('获取长者详情失败')
+  }
+}
+
+
+
+
+
+
+// 导出长者信息
+const exportElderly = async () => {
+  try {
+    // 使用模拟数据导出
+    const mockData = (await import('@/api/ykCenter')).mockData
+    const data = mockData.elderlyList.list.map(item => ({
+      姓名: item.name,
+      性别: item.gender === 1 ? '男' : '女',
+      年龄: item.age,
+      身份证号: item.idCard,
+      联系电话: item.phone,
+      地址: item.address,
+      堂食余额: item.diningBalance,
+      送餐余额: item.deliveryBalance,
+      本月就餐次数: item.mealCount
+    }))
+
+    // 创建CSV内容
+    const csvContent = [
+      Object.keys(data[0]).join(','),
+      ...data.map(row => Object.values(row).join(','))
+    ].join('\n')
+
+    // 创建下载链接
+    const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' })
+    const url = URL.createObjectURL(blob)
+    const link = document.createElement('a')
+    link.href = url
+    link.download = '长者信息.csv'
+    link.click()
+    URL.revokeObjectURL(url)
+
+    ElMessage.success('导出成功')
+
+    // 如果实际API可用,取消下面注释并注释掉上面的模拟数据代码
+    // await exportElderlyInfo(queryParams.value)
+    // ElMessage.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    ElMessage.error('导出失败')
+  }
+}
+
+// 编辑长者信息
+const handleEdit = async (row: any,detail:boolean) => {
+  formRef.value.open(row.id,detail,1,queryParams.value.tenantIds)
+}
+
+// 提交编辑
+const submitEdit = async () => {
+  if (!editFormRef.value) return
+
+  await editFormRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      try {
+
+        await updateElderlyInfo(editForm.value)
+        ElMessage.success('长者信息更新成功')
+        editVisible.value = false
+        await getList()
+      } catch (error) {
+        console.error('更新长者信息失败:', error)
+        ElMessage.error('更新长者信息失败')
+      }
+    }
+  })
+}
+
+// 删除长者
+const handleDelete = async (row: any) => {
+  try {
+    await ElMessageBox.confirm(
+      `确定要恢复入住长者 "${row.elderName}" 吗?`,
+      '删除确认',
+      {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }
+    )
+    await deleteElderly(row.id)
+
+    ElMessage.success('删除成功')
+    await getList()
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('删除长者失败:', error)
+      ElMessage.error('删除长者失败')
+    }
+  }
+}
+
+onMounted(() => {
+  getList()
+})
+</script>
+
+<style scoped>
+.elderly-list-container {
+
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.header-actions {
+  display: flex;
+  gap: 10px;
+}
+
+.search-form {
+  margin-bottom: 2px;
+}
+
+.pagination-container {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.elderly-detail {
+  padding: 10px 0;
+}
+
+.balance-info {
+  padding: 0 20px;
+}
+
+.balance-records {
+  margin-top: 20px;
+}
+
+.balance-records h3 {
+  margin-bottom: 15px;
+  font-size: 16px;
+  color: #333;
+}
+</style>