用户模块展示
添加底部tab栏
路由配置
routes: [
{ path: '/login', component: () => import('@/views/Login/index.vue') },
{
path: '/',
component: () => import('@/views/Layout/index.vue'),
redirect: '/home',
children: [
{ path: '/home', component: () => import('@/views/Home/index.vue') },
{ path: '/article', component: () => import('@/views/Article/index.vue') },
{ path: '/notify', component: () => import('@/views/Notify/index.vue') },
{ path: '/user', component: () => import('@/views/User/index.vue') }
]
}
]
布局容器
src\views\layout
<script setup lang="ts"></script>
<template>
<div class="layout-page">
<router-view></router-view>
<van-tabbar route>
<van-tabbar-item to="/home">
首页
<template #icon="{ active }">
<cp-icon :name="`home-index-${active ? 'active' : 'default'}`" />
</template>
</van-tabbar-item>
<van-tabbar-item to="/article">
健康百科
<template #icon="{ active }">
<cp-icon :name="`home-article-${active ? 'active' : 'default'}`" />
</template>
</van-tabbar-item>
<van-tabbar-item to="/notify">
消息中心
<template #icon="{ active }">
<cp-icon :name="`home-notice-${active ? 'active' : 'default'}`" />
</template>
</van-tabbar-item>
<van-tabbar-item to="/user">
我的
<template #icon="{ active }">
<cp-icon :name="`home-mine-${active ? 'active' : 'default'}`" />
</template>
</van-tabbar-item>
</van-tabbar>
</div>
</template>
<style lang="scss" scoped>
.layout-page {
:deep() {
.van-tabbar-item {
&__icon {
font-size: 21px;
}
&__text {
font-size: 11px;
}
&:not(.van-tabbar-item--active) {
color: var(--cp-text3);
}
}
}
}
</style>
设置访问权限控制
vue3不需要next函数,改成return
router/index.ts
// 访问权限控制
router.beforeEach((to) => {
// 用户仓库
const store = useUserStore()
// 不需要登录的页面,白名单
const wihteList = ['/login']
// 如果没有登录且不在白名单内,去登录
if (!store.user?.token && !wihteList.includes(to.path)) return '/login'
// 否则不做任何处理
})
设置页面标题
给每一个路由添加meta数据
router/index.ts
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{ path: '/login', component: () => import('@/views/Login/index.vue'), meta: { title: '登录' } },
{
path: '/',
component: () => import('@/views/Layout/index.vue'),
redirect: '/home',
children: [
{
path: '/home',
component: () => import('@/views/Home/index.vue'),
meta: { title: '首页' }
},
{
path: '/article',
component: () => import('@/views/Article/index.vue'),
meta: { title: '健康百科' }
},
{
path: '/notify',
component: () => import('@/views/Notify/index.vue'),
meta: { title: '消息通知' }
},
{
path: '/user',
component: () => import('@/views/User/index.vue'),
meta: { title: '个人中心' }
}
]
}
]
})
router.afterEach切换路由设置标题
router/index.ts
router.afterEach((to) => {
// 切换路由完成后修改标题
document.title = `在线问诊-${to.meta.title || ''}`
})
为了更好的路由提示,RouteMeta类型会合并
types/vue-router.d.ts
import 'vue-router'
declare module 'vue-router' {
// 扩展 元信息类型
interface RouteMeta {
// 标题
title?: string
}
}
为了提高用户体验,加上进度条
- 安装插件
pnpm add nprogress
pnpm add @types/nprogress -D
- 切换路由前开启
+ import NProgress from 'nprogress'
+ import 'nprogress/nprogress.css'
router.beforeEach((to) => {
+ NProgress.start()
- 路由切换完毕后关闭
router.afterEach((to) => {
// 修改标题
document.title = `在线问诊-${to.meta.title || ''}`
+ NProgress.done()
})
- 插件配置,颜色修改
+ NProgress.configure({
+ showSpinner: false
+ })
修改进度条颜色
main.scss
#nprogress .bar {
background-color: var(--cp-primary) !important;
}
个人中心
基础结构
<script setup lang="ts"></script>
<template>
<div class="user-page">
<div class="user-page-head">
<div class="top">
<van-image
round
fit="cover"
src="https://yanxuan-item.nosdn.127.net/ef302fbf967ea8f439209bd747738aba.png"
/>
<div class="name">
<p>用户907456</p>
<p><van-icon name="edit" /></p>
</div>
</div>
<van-row>
<van-col span="6">
<p>150</p>
<p>收藏</p>
</van-col>
<van-col span="6">
<p>23</p>
<p>关注</p>
</van-col>
<van-col span="6">
<p>270</p>
<p>积分</p>
</van-col>
<van-col span="6">
<p>3</p>
<p>优惠券</p>
</van-col>
</van-row>
</div>
<div class="user-page-order">
<div class="head">
<h3>药品订单</h3>
<router-link to="/order">全部订单 <van-icon name="arrow" /></router-link>
</div>
<van-row>
<van-col span="6">
<cp-icon name="user-paid" />
<p>待付款</p>
</van-col>
<van-col span="6">
<cp-icon name="user-shipped" />
<p>待发货</p>
</van-col>
<van-col span="6">
<cp-icon name="user-received" />
<p>待收货</p>
</van-col>
<van-col span="6">
<cp-icon name="user-finished" />
<p>已完成</p>
</van-col>
</van-row>
</div>
</div>
</template>
<style lang="scss" scoped>
.user-page {
background-color: var(--cp-bg);
min-height: calc(100vh - 50px);
padding: 0 15px 65px;
// 头部
&-head {
height: 200px;
background: linear-gradient(180deg, rgba(44, 181, 165, 0.46), rgba(44, 181, 165, 0));
margin: 0 -15px;
padding: 0 15px;
.top {
display: flex;
padding-top: 50px;
align-items: center;
.van-image {
width: 70px;
height: 70px;
}
.name {
padding-left: 10px;
p {
&:first-child {
font-size: 18px;
font-weight: 500;
}
&:last-child {
margin-top: 10px;
color: var(--cp-primary);
font-size: 16px;
}
}
}
}
.van-row {
margin: 0 -15px;
padding-top: 15px;
p {
text-align: center;
&:first-child {
font-size: 18px;
font-weight: 500;
}
&:last-child {
color: var(--cp-dark);
font-size: 12px;
padding-top: 4px;
}
}
}
}
// 订单
&-order {
background-color: #fff;
border-radius: 8px;
margin-bottom: 15px;
padding-bottom: 15px;
.head {
display: flex;
justify-content: space-between;
line-height: 50px;
padding: 0 15px;
a {
color: var(--cp-tip);
}
}
.van-col {
text-align: center;
.cp-icon {
font-size: 28px;
}
p {
font-size: 12px;
padding-top: 4px;
}
}
}
// 分组
&-group {
background-color: #fff;
border-radius: 8px;
overflow: hidden;
h3 {
padding-left: 16px;
line-height: 44px;
}
.van-cell {
align-items: center;
}
.cp-icon {
font-size: 17px;
margin-right: 10px;
}
}
.logout {
display: block;
margin: 20px auto;
width: 100px;
text-align: center;
color: var(--cp-price);
}
}
</style>
获取个人信息接口
import type { CodeType, User, UserInfo } from '@/types/user'
// ... 省略 ...
// 获取个人信息
export const getUserInfo = () => request<UserInfo>('/patient/myUser')
获取数据进行渲染
import { getUserInfo } from '@/api/user'
import type { UserInfo } from '@/types/user'
import { onMounted, ref } from 'vue'
const user = ref<UserInfo>()
onMounted(async () => {
const res = await getUserInfo()
user.value = res.data
})
+<div class="user-page" v-if="user">
<div class="user-page-head">
<div class="top">
+ <van-image round fit="cover" :src="user.avatar" />
<div class="name">
+ <p>{{ user.account }}</p>
<p><van-icon name="edit" /></p>
</div>
</div>
<van-row>
<van-col span="6">
+ <p>{{ user.collectionNumber }}</p>
<p>收藏</p>
</van-col>
<van-col span="6">
+ <p>{{ user.likeNumber }}</p>
<p>关注</p>
</van-col>
<van-col span="6">
+ <p>{{ user.score }}</p>
<p>积分</p>
</van-col>
<van-col span="6">
+ <p>{{ user.couponNumber }}</p>
<p>优惠券</p>
</van-col>
</van-row>
</div>
<div class="user-page-order">
<div class="head">
<h3>药品订单</h3>
<router-link to="/order">全部订单 <van-icon name="arrow" /></router-link>
</div>
<van-row>
<van-col span="6">
+ <van-badge :content="user.orderInfo.paidNumber || ''">
<cp-icon name="user-paid" />
+ </van-badge>
<p>待付款</p>
</van-col>
<van-col span="6">
+ <van-badge :content="user.orderInfo.shippedNumber || ''">
<cp-icon name="user-shipped" />
+ </van-badge>
<p>待发货</p>
</van-col>
<van-col span="6">
+ <van-badge :content="user.orderInfo.receivedNumber || ''">
<cp-icon name="user-received" />
+ </van-badge>
<p>待收货</p>
</van-col>
<van-col span="6">
+ <van-badge :content="user.orderInfo.finishedNumber || ''">
<cp-icon name="user-finished" />
+ </van-badge>
<p>已完成</p>
</van-col>
</van-row>
</div>
</div>
快捷工具栏目渲染
<div class="user-page-group">
<h3>快捷工具</h3>
<van-cell
v-for="(item, i) in tools"
:key="item.label"
:title="item.label"
:to="item.path"
is-link
:border="false"
>
<template #icon><cp-icon :name="`user-tool-0${i + 1}`" /></template>
</van-cell>
</div>
const tools = [
{ label: '我的问诊', path: '/user/consult' },
{ label: '我的处方', path: '/' },
{ label: '家庭档案', path: '/user/patient' },
{ label: '地址管理', path: '/user/address' },
{ label: '我的评价', path: '/' },
{ label: '官方客服', path: '/' },
{ label: '设置', path: '/' }
]
退出登录
按钮结构
<van-button
type="danger"
size="large"
@click="logout"
class="logout"
>
退出登录
</van-button>
import { useUserStore } from '@/stores/index'
// ... 省略 ...
const store = useUserStore()
const router = useRouter()
const logout = () => {
showConfirmDialog({
title: '温馨提示',
message: '您确认要退出优医问诊吗?'
})
.then(() => {
// 删除本地用户信息
store.delUser()
// 跳转到登录页
router.push('/login')
})
.catch(() => {
// on cancel
})
}
家庭档案详情页
配置路由信息,因为家庭档案详情页不需要导航栏,所以是一级路由,
{
path: '/user/patient',
component: () => import('@/views/User/PatientPage.vue'),
meta: { title: '家庭档案' }
}
基础结构
<script setup lang="ts"></script>
<template>
<div class="patient-page">
<cp-nav-bar title="家庭档案"></cp-nav-bar>
<div class="patient-list">
<div class="patient-item">
<div class="info">
<span class="name">李富贵</span>
<span class="id">321111********6164</span>
<span>男</span>
<span>32岁</span>
</div>
<div class="icon"><cp-icon name="user-edit" /></div>
<div class="tag">默认</div>
</div>
<div class="patient-item">
<div class="info">
<span class="name">李富贵</span>
<span class="id">321333********6164</span>
<span>男</span>
<span>32岁</span>
</div>
<div class="icon"><cp-icon name="user-edit" /></div>
</div>
<div class="patient-add">
<cp-icon name="user-add" />
<p>添加患者</p>
</div>
<div class="patient-tip">最多可添加 6 人</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.patient-page {
padding: 46px 0 80px;
}
.patient-list {
padding: 15px;
}
.patient-item {
display: flex;
align-items: center;
padding: 15px;
background-color: var(--cp-bg);
border-radius: 8px;
margin-bottom: 15px;
position: relative;
border: 1px solid var(--cp-bg);
transition: all 0.3s;
overflow: hidden;
.info {
display: flex;
flex-wrap: wrap;
flex: 1;
span {
color: var(--cp-tip);
margin-right: 20px;
line-height: 30px;
&.name {
font-size: 16px;
color: var(--cp-text1);
width: 80px;
margin-right: 0;
}
&.id {
color: var(--cp-text2);
width: 180px;
}
}
}
.icon {
color: var(--cp-tag);
width: 20px;
text-align: center;
}
.tag {
position: absolute;
right: 60px;
top: 21px;
width: 30px;
height: 16px;
font-size: 10px;
color: #fff;
background-color: var(--cp-primary);
border-radius: 2px;
display: flex;
justify-content: center;
align-items: center;
}
&.selected {
border-color: var(--cp-primary);
background-color: var(--cp-plain);
.icon {
color: var(--cp-primary);
}
}
}
.patient-add {
background-color: var(--cp-bg);
color: var(--cp-primary);
text-align: center;
padding: 15px 0;
border-radius: 8px;
.cp-icon {
font-size: 24px;
}
}
.patient-tip {
color: var(--cp-tag);
padding: 12px 0;
}
.pb4 {
padding-bottom: 4px;
}
</style>
定义接口类型类型
types/user.d.ts
// 家庭档案-患者信息
export type Patient = {
/** 患者ID */
id?: string
/** 患者名称 */
name: string
/** 身份证号 */
idCard: string
/** 0不默认 1默认 */
defaultFlag: 0 | 1
/** 0 女 1 男 */
gender: 0 | 1
/** 性别文字 */
genderValue?: string
/** 年龄 */
age?: number
}
// 家庭档案-患者信息列表
export type PatientList = Patient[]
定义接口
api/user.ts
import type { CodeType, PatientList, User, UserInfo } from '@/types/user'
// ... 省略 ...
// 获患者信息列表
export const getPatientList = () => request<PatientList>('/patient/mylist')
实现查询患者业务
User/PatientPage.vue
import { getPatientList } from '@/api/user'
import type { PatientList } from '@/types/user'
import { onMounted, ref } from 'vue'
// 1. 页面初始化加载数据
const list = ref<PatientList>([])
const loadList = async () => {
try {
const res = await getPatientList()
list.value = res.data
} catch (error) {
console.log(error)
}
}
onMounted(() => {
loadList()
})
数据渲染
<div class="patient-item" v-for="item in list" :key="item.id">
<div class="info">
<span class="name">{{ item.name }}</span>
<!-- 身份证脱敏处理 -->
<!-- 匹配第一个$1 `^(.{6})` -->
<!-- `.+` 匹配中间字符 -->
<!-- 匹配第二个$2 `(.{4})$` -->
<span class="id">{{ item.idCard.replace(/^(.{6}).+(.{4})$/, '\$1********\$2') }}</span>
<span>{{ item.genderValue }}</span>
<span>{{ item.age }}岁</span>
</div>
<div class="icon"><cp-icon name="user-edit" /></div>
<div class="tag" v-if="item.defaultFlag === 1">默认</div>
</div>
<div class="patient-add" v-if="list.length < 6">
按钮组单选框组件封装
基础结构
<script setup lang="ts"></script>
<template>
<div class="cp-radio-btn">
<a class="item" href="javascript:;">男</a>
<a class="item" href="javascript:;">女</a>
</div>
</template>
<style lang="scss" scoped>
.cp-radio-btn {
display: flex;
flex-wrap: wrap;
.item {
height: 32px;
min-width: 60px;
line-height: 30px;
padding: 0 14px;
text-align: center;
border: 1px solid var(--cp-bg);
background-color: var(--cp-bg);
margin-right: 10px;
box-sizing: border-box;
color: var(--cp-text2);
margin-bottom: 10px;
border-radius: 4px;
transition: all 0.3s;
&.active {
border-color: var(--cp-primary);
background-color: var(--cp-plain);
}
}
}
</style>
添加组件类型提示
import CpNavBar from '@/components/cp-nav-bar.vue'
import CpIcon from '@/components/cp-icon.vue'
+import CpRadioBtn from '@/components/cp-radio-btn.vue'
declare module 'vue' {
interface GlobalComponents {
CpNavBar: typeof CpNavBar
CpIcon: typeof CpIcon
+ CpRadioBtn: typeof CpRadioBtn
}
}
使用传入数组方式动态展示需要显示的按钮
<script setup lang="ts">
defineProps<{
options: {
label: string
value: string | number
}[]
}>()
</script>
<template>
<div class="cp-radio-btn">
<a class="item" href="javascript:;" v-for="item in options" :key="item.value">
{{ item.label }}
</a>
</div>
</template>
User/PatientPage.vue
const options = [
{ label: '男', value: 1 },
{ label: '女', value: 0 }
]
<cp-radio-btn :options="options"></cp-radio-btn>
实现默认选中
User/PatientPage.vue
const gender = ref(1)
<cp-radio-btn
:options="options"
v-model="gender"
></cp-radio-btn>
判读当前value与选中value是否一致,一致就添加active类名
src\components\cp-radio-btn.vue
<script setup lang="ts">
defineProps<{
options: {
label: string
value: string | number
}[]
+ modelValue?: string | number
}>()
</script>
<template>
<div class="cp-radio-btn">
<a
class="item"
href="javascript:;"
v-for="item in options"
:key="item.value"
+ :class="{ active: modelValue === item.value }"
>
{{ item.label }}
</a>
</div>
</template>
添加切换效果
const emit = defineEmits<{
(e: 'update:modelValue', value: string | number): void
}>()
const toggleItem = (value: string | number) => {
// 触发自定义事件把数据给父组件
emit('update:modelValue', value)
}
<a
class="item"
href="javascript:;"
v-for="item in options"
:key="item.value"
:class="{ active: modelValue === item.value }"
+ @click="toggleItem(item.value)"
>
{{ item.label }}
</a>
侧滑层表单显示隐藏
使用van-popup完成侧边栏效果
User/PatientPage.vue
给新增按钮添加事件
<div class="patient-add" v-if="list.length < 6" @click="showPopup()">
// 2. 打开侧滑栏
const show = ref(false)
const showPopup = () => {
show.value = true
}
<!-- 侧边栏 -->
<van-popup v-model:show="show" position="right">
<cp-nav-bar title="添加患者" right-text="保存"></cp-nav-bar>
</van-popup>
扩展cp-nav-bar组件,支持自定义返回,扩展 back 属性,如果有就执行 back 对应的函数。
const router = useRouter()
const onClickLeft = () => {
+ if (props.back) {
+ return props.back()
+ }
// 判断历史记录中是否有回退
if (history.state?.back) {
router.back()
} else {
router.push('/')
}
}
// 2. 使用组件时候才能确定的功能:标题,右侧文字,点击右侧文字行为(props传入)
+const props = defineProps<{
title?: string
rightText?: string
+ back?: () => void
}>()
User/PatientPage.vue
<cp-nav-bar :back="() => (show = false)" title="添加患者" right-text="保存"></cp-nav-bar>
绘制表单
<van-form autocomplete="off" ref="form">
<van-field label="真实姓名" placeholder="请输入真实姓名" />
<van-field label="身份证号" placeholder="请输入身份证号" />
<van-field label="性别" class="pb4">
<!-- 单选按钮组件 -->
<template #input>
<cp-radio-btn :options="options"></cp-radio-btn>
</template>
</van-field>
<van-field label="默认就诊人">
<template #input>
<van-checkbox :icon-size="18" round />
</template>
</van-field>
</van-form>
表单数据绑定
User/PatientPage.vue
定义表单数据
import type { Patient, PatientList } from '@/types/user'
import { computed, onMounted, ref } from 'vue'
// 新增、编辑公用初始值
const initPatient = ref<Patient>({
name: '',
idCard: '',
gender: 1,
defaultFlag: 0
})
// 克隆一份新数据,要不然是同一个对象
const patient = ref<Patient>({ ...initPatient })
// van-checkbox的v-model绑定的是boolean值,需要转换
const defaultFlag = computed({
get() {
return patient.value.defaultFlag === 1 ? true : false
},
set(value) {
patient.value.defaultFlag = value ? 1 : 0
}
})
<van-field
+ v-model="patient.name"
label="真实姓名"
placeholder="请输入真实姓名"
/>
<van-field
+ v-model="patient.idCard"
label="身份证号"
placeholder="请输入身份证号"
/>
<van-field label="性别" class="pb4">
<!-- 单选按钮组件 -->
<template #input>
<cp-radio-btn
+ v-model="patient.gender"
:options="options"
></cp-radio-btn>
</template>
</van-field>
<van-field label="默认就诊人">
<template #input>
+ <van-checkbox v-model="defaultFlag" :icon-size="18" round />
</template>
</van-field>
// 2. 打开侧滑栏
const show = ref(false)
const showPopup = () => {
+ patient.value = { ...initPatient }
show.value = true
}
表单校验
姓名,非空,2-16字符 身份证,非空,格式校验
rules.ts
const nameRules: FieldRule[] = [
{ required: true, message: '请输入姓名' },
{ pattern: /^(?:[\u4e00-\u9fa5·]{2,16})$/, message: '中文2-16个字符' }
]
const idCardRules: FieldRule[] = [
{ required: true, message: '请输入身份证号' },
{
pattern:
/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/,
message: '身份证号不正确'
}
]
export { mobileRules, passwordRules, codeRules, nameRules, idCardRules }
PatientPage.vue
<van-field
v-model="patient.name"
label="真实姓名"
placeholder="请输入真实姓名"
+ :rules="nameRules"
/>
<van-field
v-model="patient.idCard"
label="身份证号"
placeholder="请输入身份证号"
+ :rules="idCardRules"
/>
保存的时候校验,整体校验
const onSubmit = async () => {
await form.value?.validate()
// 身份证倒数第二位,单数是男,双数是女
const gender = +patient.value.idCard.slice(-2, -1) % 2
if (gender !== patient.value.gender) {
await showConfirmDialog({
title: '温馨提示',
message: '填写的性别和身份证号中的不一致\n您确认提交吗?'
})
}
console.log('通过校验')
}
添加患者
定义接口
import type { CodeType, Patient, PatientList, User, UserInfo } from '@/types/user'
// 添加患者信息
export const addPatient = (patient: Patient) => request('/patient/add', 'POST', patient)
PatientPage.vue
+import { addPatient, getPatientList } from '@/api/user'
const submit = async () => {
await form.value?.validate()
// 身份证倒数第二位,单数是男,双数是女
const gender = +patient.value.idCard.slice(-2, -1) % 2
if (gender !== patient.value.gender) {
await showConfirmDialog({
title: '温馨提示',
message: '填写的性别和身份证号中的不一致\n您确认提交吗?'
})
}
+ // 添加
+ await addPatient(patient.value)
+ show.value = false
+ loadList()
+ showSuccessToast('添加成功')
}
编辑患者
编辑按钮添加事件
PatientPage.vue
<div @click="showPopup(item)" class="icon"><cp-icon name="user-edit" /></div>
const showPopup = (item?: Patient) => {
if (item) {
// 如果点的是编辑,解构出后台需要的数据
const { id, gender, name, idCard, defaultFlag } = item
patient.value = { id, gender, name, idCard, defaultFlag }
} else {
patient.value = { ...initPatient }
}
show.value = true
}
修改nav-bar头部文案
<cp-nav-bar
:back="() => (show = false)"
+ :title="patient.id ? '编辑患者' : '添加患者'"
right-text="保存"
@click-right="submit"
></cp-nav-bar>
定义编辑接口
// 编辑患者信息
export const editPatient = (patient: Patient) => request('/patient/update', 'PUT', patient)
合并编辑患者请求
import { addPatient, getPatientList, editPatient } from '@/api/user'
const onSubmit = async () => {
try {
await form.value?.validate()
// 身份证倒数第二位,单数是男,双数是女
const gender = +patient.value.idCard.slice(-2, -1) % 2
if (gender !== patient.value.gender) {
await showConfirmDialog({
title: '温馨提示',
message: '填写的性别和身份证号中的不一致\n您确认提交吗?'
})
}
// 添加 & 修改
patient.value.id
? await editPatient(patient.value)
: await addPatient(patient.value)
show.value = false
loadList()
showSuccessToast(patient.value.id ? '编辑成功' : '添加成功')
} catch (error) {
console.log(error)
}
}
删除患者
在表单下方定义删除按钮结构
</van-form>
+ <van-action-bar>
+ <van-action-bar-button>删除</van-action-bar-button>
+ </van-action-bar>
</van-popup>
定义删除接口
// 删除患者信息
export const delPatient = (id: string) => request(`/patient/del/${id}`, 'DELETE')
点击删除,弹出确认框,确认删除
<van-action-bar v-if="patient.id">
<van-action-bar-button @click="remove">删除</van-action-bar-button>
</van-action-bar>
const remove = async () => {
if (patient.value.id) {
try {
await showConfirmDialog({
title: '温馨提示',
message: `您确认要删除 ${patient.value.name} 患者信息吗 ?`
})
await delPatient(patient.value.id)
show.value = false
loadList()
showSuccessToast('删除成功')
} catch (error) {
console.log(error)
}
}
}