33333
This commit is contained in:
parent
449bd0c09d
commit
cd6dd3d202
118
HOME_PAGE_CHANGE_README.md
Normal file
118
HOME_PAGE_CHANGE_README.md
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
# 首页修改说明
|
||||||
|
|
||||||
|
## 🎯 修改目标
|
||||||
|
|
||||||
|
将系统首页从原来的"首页"改为"文章病例库管理",用户登录后直接进入文章病例库管理页面。
|
||||||
|
|
||||||
|
## 🔧 修改内容
|
||||||
|
|
||||||
|
### 1. 修改常量配置
|
||||||
|
|
||||||
|
#### `src/constants/system/home-const.js`
|
||||||
|
- **HOME_PAGE_NAME**: 从 `'Home'` 改为 `'CaseClinicalArticleList'`
|
||||||
|
- **HOME_PAGE_PATH**: 从 `'/home'` 改为 `'/case-clinical-article/list'`
|
||||||
|
|
||||||
|
#### `src/constants/common-const.js`
|
||||||
|
- **HOME_PAGE_PATH**: 从 `'/home'` 改为 `'/case-clinical-article/list'`
|
||||||
|
|
||||||
|
### 2. 修改路由配置
|
||||||
|
|
||||||
|
#### `src/router/system/home.js`
|
||||||
|
- **路径**: 从 `/home` 改为 `/case-clinical-article/list`
|
||||||
|
- **标题**: 从"首页"改为"文章病例库管理"
|
||||||
|
- **图标**: 从 `HomeOutlined` 改为 `FileTextOutlined`
|
||||||
|
- **组件**: 从首页组件改为文章病例库列表组件
|
||||||
|
|
||||||
|
#### 新增 `src/router/system/case-clinical-article.js`
|
||||||
|
- 创建完整的文章病例库管理路由配置
|
||||||
|
- 包含列表页和表单页两个子路由
|
||||||
|
|
||||||
|
#### `src/router/routers.js`
|
||||||
|
- 引入文章病例库管理路由配置
|
||||||
|
- 将新路由添加到主路由数组中
|
||||||
|
|
||||||
|
## 📁 文件结构
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── constants/
|
||||||
|
│ ├── system/
|
||||||
|
│ │ └── home-const.js # 首页常量配置
|
||||||
|
│ └── common-const.js # 通用常量配置
|
||||||
|
├── router/
|
||||||
|
│ ├── system/
|
||||||
|
│ │ ├── home.js # 首页路由配置
|
||||||
|
│ │ └── case-clinical-article.js # 文章病例库路由配置
|
||||||
|
│ └── routers.js # 主路由配置
|
||||||
|
└── views/
|
||||||
|
└── business/
|
||||||
|
└── case-clinical-article/
|
||||||
|
├── case-clinical-article-list.vue # 列表页面
|
||||||
|
└── case-clinical-article-form.vue # 表单页面
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 使用方法
|
||||||
|
|
||||||
|
### 1. 用户登录后
|
||||||
|
- 系统自动跳转到 `/case-clinical-article/list`
|
||||||
|
- 显示文章病例库管理列表页面
|
||||||
|
|
||||||
|
### 2. 访问路径
|
||||||
|
- **首页**: `/case-clinical-article/list`
|
||||||
|
- **新增**: `/case-clinical-article/form?type=add`
|
||||||
|
- **编辑**: `/case-clinical-article/form?type=edit&id=xxx`
|
||||||
|
|
||||||
|
### 3. 菜单显示
|
||||||
|
- 主菜单显示"文章病例库管理"
|
||||||
|
- 子菜单显示"文章病例库列表"
|
||||||
|
- 表单页面在菜单中隐藏(hideInMenu: true)
|
||||||
|
|
||||||
|
## 🎨 界面变化
|
||||||
|
|
||||||
|
### 修改前
|
||||||
|
- 首页显示系统概览信息
|
||||||
|
- 图标:🏠 HomeOutlined
|
||||||
|
- 标题:首页
|
||||||
|
|
||||||
|
### 修改后
|
||||||
|
- 首页显示文章病例库管理列表
|
||||||
|
- 图标:📄 FileTextOutlined
|
||||||
|
- 标题:文章病例库管理
|
||||||
|
|
||||||
|
## ⚠️ 注意事项
|
||||||
|
|
||||||
|
1. **路由重定向**: 根路径 `/` 会自动重定向到文章病例库管理页面
|
||||||
|
2. **权限控制**: 确保用户有访问文章病例库管理的权限
|
||||||
|
3. **面包屑导航**: 面包屑会显示"文章病例库管理 > 文章病例库列表"
|
||||||
|
4. **页面缓存**: 如果启用了keepAlive,文章病例库列表页面会被缓存
|
||||||
|
|
||||||
|
## 🔍 验证方法
|
||||||
|
|
||||||
|
### 1. 登录测试
|
||||||
|
- 用户登录后应该直接进入文章病例库管理页面
|
||||||
|
- URL应该是 `/case-clinical-article/list`
|
||||||
|
|
||||||
|
### 2. 菜单测试
|
||||||
|
- 主菜单应该显示"文章病例库管理"
|
||||||
|
- 点击应该能正常跳转
|
||||||
|
|
||||||
|
### 3. 路由测试
|
||||||
|
- 访问根路径 `/` 应该重定向到文章病例库管理
|
||||||
|
- 直接访问 `/case-clinical-article/list` 应该正常显示
|
||||||
|
|
||||||
|
## 📝 后续优化
|
||||||
|
|
||||||
|
1. **添加首页统计**: 在文章病例库列表页面添加统计信息
|
||||||
|
2. **优化加载性能**: 考虑使用懒加载优化页面加载
|
||||||
|
3. **添加快捷操作**: 在首页添加常用的快捷操作按钮
|
||||||
|
4. **个性化配置**: 允许用户自定义首页显示内容
|
||||||
|
|
||||||
|
## ✅ 完成状态
|
||||||
|
|
||||||
|
- [x] 修改首页常量配置
|
||||||
|
- [x] 修改首页路由配置
|
||||||
|
- [x] 创建文章病例库路由配置
|
||||||
|
- [x] 更新主路由配置
|
||||||
|
- [x] 创建说明文档
|
||||||
|
|
||||||
|
**首页修改已完成!** 用户登录后将直接进入文章病例库管理页面。
|
||||||
@ -15,7 +15,7 @@ export const PAGE_SIZE_OPTIONS = ['5', '10', '15', '20', '30', '40', '50', '75',
|
|||||||
//登录页面名字
|
//登录页面名字
|
||||||
export const PAGE_PATH_LOGIN = '/login';
|
export const PAGE_PATH_LOGIN = '/login';
|
||||||
//首页页面名字
|
//首页页面名字
|
||||||
export const HOME_PAGE_PATH = '/home';
|
export const HOME_PAGE_PATH = '/case-clinical-article/list';
|
||||||
|
|
||||||
//404页面名字
|
//404页面名字
|
||||||
export const PAGE_PATH_404 = '/404';
|
export const PAGE_PATH_404 = '/404';
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//首页页面名字
|
//首页页面名字
|
||||||
export const HOME_PAGE_NAME = 'Home';
|
export const HOME_PAGE_NAME = 'CaseClinicalArticleList';
|
||||||
|
|
||||||
//首页页面路径
|
//首页页面路径
|
||||||
export const HOME_PAGE_PATH = '/home';
|
export const HOME_PAGE_PATH = '/case-clinical-article/list';
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||||
*/
|
*/
|
||||||
import { homeRouters } from './system/home';
|
import { homeRouters } from './system/home';
|
||||||
|
import { caseClinicalArticleRouters } from './system/case-clinical-article';
|
||||||
import { loginRouters } from './system/login';
|
import { loginRouters } from './system/login';
|
||||||
import { helpDocRouters } from './support/help-doc';
|
import { helpDocRouters } from './support/help-doc';
|
||||||
import NotFound from '/@/views/system/40X/404.vue';
|
import NotFound from '/@/views/system/40X/404.vue';
|
||||||
@ -15,7 +16,8 @@ import NoPrivilege from '/@/views/system/40X/403.vue';
|
|||||||
|
|
||||||
export const routerArray = [
|
export const routerArray = [
|
||||||
...loginRouters,
|
...loginRouters,
|
||||||
...homeRouters,
|
...homeRouters,
|
||||||
|
...caseClinicalArticleRouters,
|
||||||
...helpDocRouters,
|
...helpDocRouters,
|
||||||
{ path: '/:pathMatch(.*)*', name: '404', component: NotFound },
|
{ path: '/:pathMatch(.*)*', name: '404', component: NotFound },
|
||||||
{ path: '/403', name: '403', component: NoPrivilege }
|
{ path: '/403', name: '403', component: NoPrivilege }
|
||||||
|
|||||||
47
src/router/system/case-clinical-article.js
Normal file
47
src/router/system/case-clinical-article.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 文章病例库管理路由
|
||||||
|
*
|
||||||
|
* @Author: xing
|
||||||
|
* @Date: 2025-01-27
|
||||||
|
* @Copyright gdxz
|
||||||
|
*/
|
||||||
|
import { MENU_TYPE_ENUM } from '/@/constants/system/menu-const';
|
||||||
|
import SmartLayout from '/@/layout/index.vue';
|
||||||
|
|
||||||
|
export const caseClinicalArticleRouters = [
|
||||||
|
{
|
||||||
|
path: '/case-clinical-article',
|
||||||
|
name: 'CaseClinicalArticle',
|
||||||
|
component: SmartLayout,
|
||||||
|
meta: {
|
||||||
|
title: '文章病例库管理',
|
||||||
|
menuType: MENU_TYPE_ENUM.CATALOG.value,
|
||||||
|
icon: 'FileTextOutlined',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/case-clinical-article/list',
|
||||||
|
name: 'CaseClinicalArticleList',
|
||||||
|
meta: {
|
||||||
|
title: '文章病例库列表',
|
||||||
|
menuType: MENU_TYPE_ENUM.MENU.value,
|
||||||
|
icon: 'FileTextOutlined',
|
||||||
|
parentMenuList: [{ name: 'CaseClinicalArticle', title: '文章病例库管理' }],
|
||||||
|
},
|
||||||
|
component: () => import('/@/views/business/case-clinical-article/case-clinical-article-list.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/case-clinical-article/form',
|
||||||
|
name: 'CaseClinicalArticleForm',
|
||||||
|
meta: {
|
||||||
|
title: '文章病例库表单',
|
||||||
|
menuType: MENU_TYPE_ENUM.MENU.value,
|
||||||
|
icon: 'FileTextOutlined',
|
||||||
|
hideInMenu: true,
|
||||||
|
parentMenuList: [{ name: 'CaseClinicalArticle', title: '文章病例库管理' }],
|
||||||
|
},
|
||||||
|
component: () => import('/@/views/business/case-clinical-article/case-clinical-article-form.vue'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
@ -18,21 +18,21 @@ export const homeRouters = [
|
|||||||
redirect: { name: HOME_PAGE_NAME },
|
redirect: { name: HOME_PAGE_NAME },
|
||||||
component: SmartLayout,
|
component: SmartLayout,
|
||||||
meta: {
|
meta: {
|
||||||
title: '首页',
|
title: '文章病例库管理',
|
||||||
menuType: MENU_TYPE_ENUM.CATALOG.value,
|
menuType: MENU_TYPE_ENUM.CATALOG.value,
|
||||||
icon: 'HomeOutlined',
|
icon: 'FileTextOutlined',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/home',
|
path: '/case-clinical-article/list',
|
||||||
name: HOME_PAGE_NAME,
|
name: HOME_PAGE_NAME,
|
||||||
meta: {
|
meta: {
|
||||||
title: '首页',
|
title: '文章病例库管理',
|
||||||
menuType: MENU_TYPE_ENUM.MENU.value,
|
menuType: MENU_TYPE_ENUM.MENU.value,
|
||||||
icon: 'HomeOutlined',
|
icon: 'FileTextOutlined',
|
||||||
parentMenuList: [{ name: '_home', title: '首页' }],
|
parentMenuList: [{ name: '_home', title: '文章病例库管理' }],
|
||||||
},
|
},
|
||||||
component: () => import('/@/views/system/home/index.vue'),
|
component: () => import('/@/views/business/case-clinical-article/case-clinical-article-list.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/account',
|
path: '/account',
|
||||||
|
|||||||
@ -7,84 +7,116 @@
|
|||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<a-modal
|
<a-modal
|
||||||
:title="form.doctorId ? '编辑' : '添加'"
|
:title="form.doctorId ? '编辑医生' : '添加医生'"
|
||||||
:width="1000"
|
:width="800"
|
||||||
:open="visibleFlag"
|
:open="visibleFlag"
|
||||||
@cancel="onClose"
|
@cancel="onClose"
|
||||||
:maskClosable="false"
|
:maskClosable="false"
|
||||||
:destroyOnClose="true"
|
:destroyOnClose="true"
|
||||||
>
|
>
|
||||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 5 }" >
|
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
|
||||||
<a-form-item label="用户名称" name="doctorName">
|
<!-- 医生姓名 -->
|
||||||
<a-input-group compact>
|
<a-form-item label="医生姓名" name="doctorName">
|
||||||
<a-input
|
<a-input-group compact>
|
||||||
style="calc(100% - 80px)"
|
<a-input
|
||||||
v-model:value="form.doctorName"
|
v-model:value="form.doctorName"
|
||||||
placeholder="请输入医生姓名"
|
placeholder="请输入医生姓名"
|
||||||
:disabled="!!form.doctorId"
|
|
||||||
@pressEnter="searchAppDoctor"
|
|
||||||
/>
|
|
||||||
<a-button
|
|
||||||
v-if="!form.doctorId"
|
|
||||||
type="primary"
|
|
||||||
style="width: 80px"
|
|
||||||
@click="searchAppDoctor"
|
|
||||||
:loading="searchLoading"
|
|
||||||
>
|
|
||||||
搜索
|
|
||||||
</a-button>
|
|
||||||
</a-input-group>
|
|
||||||
<!-- 搜索到的APP医生信息提示 -->
|
|
||||||
<div v-if="appDoctorInfo && !form.doctorId" style="margin-top: 8px;">
|
|
||||||
<a-alert
|
|
||||||
:message="`找到APP医生:${appDoctorInfo.doctorName}`"
|
|
||||||
:description="`手机号:${appDoctorInfo.phone || '未知'} | 省份:${appDoctorInfo.province || '未知'}`"
|
|
||||||
type="info"
|
|
||||||
show-icon
|
|
||||||
closable
|
|
||||||
@close="clearAppDoctorInfo"
|
|
||||||
>
|
|
||||||
<template #action>
|
|
||||||
<a-button size="small" type="primary" @click="useAppDoctorInfo">
|
|
||||||
使用此信息
|
|
||||||
</a-button>
|
|
||||||
</template>
|
|
||||||
</a-alert>
|
|
||||||
</div>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="所属医院" name="hospitalId">
|
|
||||||
<a-select
|
|
||||||
v-model:value="form.hospitalId"
|
|
||||||
placeholder="请选择医院"
|
|
||||||
style="width: 100%"
|
|
||||||
:options="hospitalOptions"
|
|
||||||
:field-names="{ label: 'hospitalName', value: 'hospitalId' }"
|
|
||||||
:loading="hospitalLoading"
|
|
||||||
:disabled="!!form.doctorId"
|
:disabled="!!form.doctorId"
|
||||||
@focus="onHospitalFocus"
|
style="width: calc(100% - 80px)"
|
||||||
@search="onHospitalSearch"
|
@pressEnter="searchDoctor"
|
||||||
show-search
|
|
||||||
allowClear
|
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
<a-button
|
||||||
<!-- 编辑时显示状态 -->
|
v-if="!form.doctorId"
|
||||||
<a-form-item v-if="form.doctorId" label="状态" name="status">
|
type="primary"
|
||||||
<a-radio-group v-model:value="form.status">
|
style="width: 80px"
|
||||||
<a-radio :value="1">正常</a-radio>
|
@click="searchDoctor"
|
||||||
<a-radio :value="2">禁用</a-radio>
|
:loading="searchLoading"
|
||||||
</a-radio-group>
|
>
|
||||||
</a-form-item>
|
搜索
|
||||||
<!-- 编辑时显示头像 -->
|
</a-button>
|
||||||
<a-form-item v-if="form.doctorId" label="头像" name="avatar">
|
</a-input-group>
|
||||||
<div v-if="form.avatar && typeof form.avatar === 'string' && form.avatar.trim()" class="avatar-display">
|
</a-form-item>
|
||||||
<img :src="form.avatar" alt="头像" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover;" />
|
|
||||||
|
<!-- 医生搜索结果 -->
|
||||||
|
<a-form-item v-if="doctorList.length > 0 && !form.doctorId" label="搜索结果">
|
||||||
|
<div class="doctor-list">
|
||||||
|
<a-list
|
||||||
|
:data-source="doctorList"
|
||||||
|
item-layout="horizontal"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<template #renderItem="{ item }">
|
||||||
|
<a-list-item>
|
||||||
|
<a-list-item-meta>
|
||||||
|
<template #title>
|
||||||
|
<div class="doctor-info">
|
||||||
|
<span class="doctor-name">{{ item.doctorName }}</span>
|
||||||
|
<span class="doctor-phone" v-if="item.phone">({{ item.phone }})</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #description>
|
||||||
|
<div class="doctor-details">
|
||||||
|
<span v-if="item.province">省份:{{ item.province }}</span>
|
||||||
|
<span v-if="item.hospitalName" style="margin-left: 16px;">医院:{{ item.hospitalName }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-list-item-meta>
|
||||||
|
<template #actions>
|
||||||
|
<a-button type="primary" size="small" @click="selectDoctor(item)">
|
||||||
|
选择此医生
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-list-item>
|
||||||
|
</template>
|
||||||
|
</a-list>
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<!-- 无搜索结果提示 -->
|
||||||
|
<a-form-item v-if="showNoResult && !form.doctorId" label="搜索结果">
|
||||||
|
<a-alert
|
||||||
|
message="未找到医生信息"
|
||||||
|
description="请手动填写医生信息"
|
||||||
|
type="info"
|
||||||
|
show-icon
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<!-- 所属医院 -->
|
||||||
|
<a-form-item label="所属医院" name="hospitalId">
|
||||||
|
<a-select
|
||||||
|
v-model:value="form.hospitalId"
|
||||||
|
placeholder="请选择医院"
|
||||||
|
style="width: 100%"
|
||||||
|
:options="hospitalOptions"
|
||||||
|
:loading="hospitalLoading"
|
||||||
|
@search="onHospitalSearch"
|
||||||
|
@change="onHospitalChange"
|
||||||
|
show-search
|
||||||
|
allowClear
|
||||||
|
:filter-option="false"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<!-- 编辑时显示状态 -->
|
||||||
|
<a-form-item v-if="form.doctorId" label="状态" name="status">
|
||||||
|
<a-radio-group v-model:value="form.status">
|
||||||
|
<a-radio :value="1">正常</a-radio>
|
||||||
|
<a-radio :value="2">禁用</a-radio>
|
||||||
|
</a-radio-group>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<!-- 编辑时显示头像 -->
|
||||||
|
<a-form-item v-if="form.doctorId" label="头像" name="avatar">
|
||||||
|
<div v-if="form.avatar && typeof form.avatar === 'string' && form.avatar.trim()" class="avatar-display">
|
||||||
|
<img :src="form.avatar" alt="头像" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover;" />
|
||||||
|
</div>
|
||||||
|
<div v-else class="avatar-placeholder">
|
||||||
|
<div style="width: 80px; height: 80px; border-radius: 50%; background-color: #f0f0f0; display: flex; align-items: center; justify-content: center; color: #999; font-size: 12px; border: 1px dashed #d9d9d9;">
|
||||||
|
默认头像
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="avatar-placeholder">
|
</div>
|
||||||
<div style="width: 80px; height: 80px; border-radius: 50%; background-color: #f0f0f0; display: flex; align-items: center; justify-content: center; color: #999; font-size: 12px; border: 1px dashed #d9d9d9;">
|
</a-form-item>
|
||||||
默认头像
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
</a-form>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -95,238 +127,332 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref, nextTick } from 'vue';
|
import { reactive, ref, nextTick } from 'vue';
|
||||||
import _ from 'lodash';
|
import { message } from 'ant-design-vue';
|
||||||
import { message } from 'ant-design-vue';
|
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
import { caseClinicalDoctorApi } from '/@/api/business/case-clinical-doctor/case-clinical-doctor-api';
|
||||||
import { caseClinicalDoctorApi } from '/@/api/business/case-clinical-doctor/case-clinical-doctor-api';
|
import { basicHospitalApi } from '/@/api/business/basic-hospital/basic-hospital-api';
|
||||||
import { basicHospitalApi } from '/@/api/business/basic-hospital/basic-hospital-api';
|
import { smartSentry } from '/@/lib/smart-sentry';
|
||||||
import { smartSentry } from '/@/lib/smart-sentry';
|
|
||||||
import { debounce } from 'lodash';
|
|
||||||
|
|
||||||
// ------------------------ 事件 ------------------------
|
// 事件
|
||||||
|
const emits = defineEmits(['reloadList']);
|
||||||
|
|
||||||
const emits = defineEmits(['reloadList']);
|
// 组件引用
|
||||||
|
const formRef = ref();
|
||||||
|
|
||||||
// ------------------------ 显示与隐藏 ------------------------
|
// 显示状态
|
||||||
// 是否显示
|
const visibleFlag = ref(false);
|
||||||
const visibleFlag = ref(false);
|
|
||||||
|
|
||||||
async function show(rowData) {
|
// 搜索状态
|
||||||
Object.assign(form, formDefault);
|
const searchLoading = ref(false);
|
||||||
hospitalOptions.value = [];
|
const showNoResult = ref(false);
|
||||||
appDoctorInfo.value = null;
|
|
||||||
|
|
||||||
if (rowData && !_.isEmpty(rowData)) {
|
// 是否从APP列表选择了医生,用于控制自动保存
|
||||||
if (rowData.doctorId) {
|
const selectedFromApp = ref(false);
|
||||||
// 编辑模式:获取完整的医生详情信息
|
// 自动保存中标记,避免重复提交
|
||||||
try {
|
const autoSaving = ref(false);
|
||||||
SmartLoading.show();
|
|
||||||
const result = await caseClinicalDoctorApi.getDetail(rowData.doctorId);
|
|
||||||
Object.assign(form, result.data);
|
|
||||||
|
|
||||||
// 如果有医院信息,将当前医院添加到选项中以便正确显示
|
// 医生列表
|
||||||
if (result.data.hospitalId && result.data.hospitalName) {
|
const doctorList = ref([]);
|
||||||
hospitalOptions.value = [{
|
|
||||||
hospitalId: result.data.hospitalId,
|
|
||||||
hospitalName: result.data.hospitalName
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
smartSentry.captureError(e);
|
|
||||||
// 如果获取失败,使用传入的数据
|
|
||||||
Object.assign(form, rowData);
|
|
||||||
} finally {
|
|
||||||
SmartLoading.hide();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 新增模式:使用传入的数据
|
|
||||||
Object.assign(form, rowData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
visibleFlag.value = true;
|
// 医院相关
|
||||||
nextTick(() => {
|
const hospitalOptions = ref([]);
|
||||||
formRef.value.clearValidate();
|
const hospitalLoading = ref(false);
|
||||||
});
|
const hospitalSearchKeyword = ref('');
|
||||||
}
|
|
||||||
|
|
||||||
function onClose() {
|
// 表单默认值
|
||||||
Object.assign(form, formDefault);
|
const formDefault = {
|
||||||
hospitalOptions.value = [];
|
doctorId: undefined,
|
||||||
appDoctorInfo.value = null;
|
doctorName: undefined,
|
||||||
searchLoading.value = false;
|
doctorIden: undefined,
|
||||||
visibleFlag.value = false;
|
hospitalId: undefined,
|
||||||
}
|
hospitalUuid: undefined,
|
||||||
|
hospitalName: undefined,
|
||||||
|
status: 1,
|
||||||
|
avatar: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
// ------------------------ 医生名称搜索 ------------------------
|
// 表单数据
|
||||||
|
let form = reactive({ ...formDefault });
|
||||||
|
|
||||||
// 搜索APP医生
|
// 表单验证规则
|
||||||
async function searchAppDoctor() {
|
const rules = {
|
||||||
// 编辑模式下不搜索
|
doctorName: [{ required: true, message: '医生姓名必填' }],
|
||||||
if (form.doctorId || !form.doctorName || form.doctorName.trim() === '') {
|
hospitalId: [{ required: true, message: '所属医院必填' }],
|
||||||
message.warning('请输入医生姓名');
|
};
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
searchLoading.value = true;
|
// 显示表单
|
||||||
|
async function show(rowData) {
|
||||||
|
// 重置表单
|
||||||
|
Object.assign(form, formDefault);
|
||||||
|
doctorList.value = [];
|
||||||
|
hospitalOptions.value = [];
|
||||||
|
showNoResult.value = false;
|
||||||
|
searchLoading.value = false;
|
||||||
|
hospitalLoading.value = false;
|
||||||
|
hospitalSearchKeyword.value = '';
|
||||||
|
selectedFromApp.value = false;
|
||||||
|
autoSaving.value = false;
|
||||||
|
|
||||||
|
// 如果是编辑模式,加载医生详情
|
||||||
|
if (rowData && rowData.doctorId) {
|
||||||
try {
|
try {
|
||||||
const result = await caseClinicalDoctorApi.getAppDoctor(form.doctorName);
|
SmartLoading.show();
|
||||||
if (result.data) {
|
const result = await caseClinicalDoctorApi.getDetail(rowData.doctorId);
|
||||||
// 保存APP医生信息,等待用户确认
|
Object.assign(form, result.data);
|
||||||
appDoctorInfo.value = result.data;
|
|
||||||
message.info('找到APP医生信息,请确认是否使用');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// 没找到医生信息,清空之前的搜索结果
|
|
||||||
appDoctorInfo.value = null;
|
|
||||||
message.info('未找到APP医生信息,请手动选择医院');
|
|
||||||
|
|
||||||
// 自动加载医院列表供用户选择
|
// 如果有医院信息,添加到选项中
|
||||||
if (hospitalOptions.value.length === 0) {
|
if (result.data.hospitalId && result.data.hospitalName) {
|
||||||
loadHospitalOptions();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
searchLoading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用APP医生信息
|
|
||||||
function useAppDoctorInfo() {
|
|
||||||
if (appDoctorInfo.value) {
|
|
||||||
form.doctorName = appDoctorInfo.value.doctorName;
|
|
||||||
form.doctorIden = appDoctorInfo.value.uuid; // 设置app唯一标识
|
|
||||||
form.hospitalUuid = appDoctorInfo.value.hospitalUuid; // 设置医院UUID
|
|
||||||
|
|
||||||
// 如果APP医生有医院信息,直接使用
|
|
||||||
if (appDoctorInfo.value.hospitalId && appDoctorInfo.value.hospitalName) {
|
|
||||||
form.hospitalId = appDoctorInfo.value.hospitalId;
|
|
||||||
form.hospitalName = appDoctorInfo.value.hospitalName;
|
|
||||||
|
|
||||||
// 添加到选项中
|
|
||||||
hospitalOptions.value = [{
|
hospitalOptions.value = [{
|
||||||
hospitalId: appDoctorInfo.value.hospitalId,
|
label: result.data.hospitalName,
|
||||||
hospitalName: appDoctorInfo.value.hospitalName
|
value: result.data.hospitalId,
|
||||||
|
hospitalId: result.data.hospitalId,
|
||||||
|
hospitalName: result.data.hospitalName,
|
||||||
|
hospitalUuid: result.data.hospitalUuid,
|
||||||
}];
|
}];
|
||||||
} else {
|
|
||||||
// 没有医院信息,需要用户手动选择
|
|
||||||
form.hospitalId = undefined;
|
|
||||||
form.hospitalName = undefined;
|
|
||||||
|
|
||||||
// 自动加载医院列表供用户选择
|
|
||||||
if (hospitalOptions.value.length === 0) {
|
|
||||||
loadHospitalOptions();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清空APP医生信息
|
|
||||||
appDoctorInfo.value = null;
|
|
||||||
message.success('已使用APP医生信息');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清空APP医生信息
|
|
||||||
function clearAppDoctorInfo() {
|
|
||||||
appDoctorInfo.value = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------ 医院搜索 ------------------------
|
|
||||||
|
|
||||||
// 加载医院选项
|
|
||||||
async function loadHospitalOptions() {
|
|
||||||
hospitalLoading.value = true;
|
|
||||||
try {
|
|
||||||
const result = await basicHospitalApi.queryList({
|
|
||||||
keywords: hospitalSearchKeyword.value
|
|
||||||
});
|
|
||||||
hospitalOptions.value = result.data || [];
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
smartSentry.captureError(e);
|
smartSentry.captureError(e);
|
||||||
hospitalOptions.value = [];
|
Object.assign(form, rowData);
|
||||||
} finally {
|
|
||||||
hospitalLoading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 医院搜索
|
|
||||||
const debouncedSearch = debounce(() => {
|
|
||||||
loadHospitalOptions();
|
|
||||||
}, 300);
|
|
||||||
|
|
||||||
function onHospitalSearch(value) {
|
|
||||||
hospitalSearchKeyword.value = value;
|
|
||||||
debouncedSearch();
|
|
||||||
}
|
|
||||||
|
|
||||||
function onHospitalFocus() {
|
|
||||||
if (hospitalOptions.value.length === 0) {
|
|
||||||
loadHospitalOptions();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------ 表单 ------------------------
|
|
||||||
|
|
||||||
// 组件ref
|
|
||||||
const formRef = ref();
|
|
||||||
|
|
||||||
// 医院选项
|
|
||||||
const hospitalOptions = ref([]);
|
|
||||||
const hospitalLoading = ref(false);
|
|
||||||
const hospitalSearchKeyword = ref('');
|
|
||||||
|
|
||||||
// APP医生信息
|
|
||||||
const appDoctorInfo = ref(null);
|
|
||||||
const searchLoading = ref(false);
|
|
||||||
|
|
||||||
const formDefault = {
|
|
||||||
doctorId: undefined, //医生ID
|
|
||||||
doctorName: undefined, //用户名称
|
|
||||||
doctorIden: undefined, //app唯一标识
|
|
||||||
hospitalId: undefined, //所属医院
|
|
||||||
hospitalUuid: undefined, //医院UUID
|
|
||||||
hospitalName: undefined, //医院名称
|
|
||||||
status: 1, //状态(1:正常 2:禁用)- 默认为正常
|
|
||||||
avatar: undefined, //头像
|
|
||||||
};
|
|
||||||
|
|
||||||
let form = reactive({ ...formDefault });
|
|
||||||
|
|
||||||
const rules = {
|
|
||||||
doctorName: [{ required: true, message: '用户名称 必填' }],
|
|
||||||
hospitalId: [{ required: true, message: '所属医院 必填' }],
|
|
||||||
};
|
|
||||||
|
|
||||||
// 点击确定,验证表单
|
|
||||||
async function onSubmit() {
|
|
||||||
try {
|
|
||||||
await formRef.value.validateFields();
|
|
||||||
save();
|
|
||||||
} catch (err) {
|
|
||||||
message.error('参数验证错误,请仔细填写表单数据!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新建、编辑API
|
|
||||||
async function save() {
|
|
||||||
SmartLoading.show();
|
|
||||||
try {
|
|
||||||
if (form.doctorId) {
|
|
||||||
await caseClinicalDoctorApi.update(form);
|
|
||||||
} else {
|
|
||||||
await caseClinicalDoctorApi.add(form);
|
|
||||||
}
|
|
||||||
message.success('操作成功');
|
|
||||||
emits('reloadList');
|
|
||||||
onClose();
|
|
||||||
} catch (err) {
|
|
||||||
smartSentry.captureError(err);
|
|
||||||
} finally {
|
} finally {
|
||||||
SmartLoading.hide();
|
SmartLoading.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
visibleFlag.value = true;
|
||||||
show,
|
|
||||||
|
nextTick(() => {
|
||||||
|
formRef.value?.clearValidate();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭表单
|
||||||
|
function onClose() {
|
||||||
|
visibleFlag.value = false;
|
||||||
|
selectedFromApp.value = false;
|
||||||
|
autoSaving.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索医生
|
||||||
|
async function searchDoctor() {
|
||||||
|
if (!form.doctorName || form.doctorName.trim() === '') {
|
||||||
|
message.warning('请输入医生姓名');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchLoading.value = true;
|
||||||
|
showNoResult.value = false;
|
||||||
|
doctorList.value = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await caseClinicalDoctorApi.getAppDoctor(form.doctorName.trim());
|
||||||
|
|
||||||
|
if (result.data && Array.isArray(result.data) && result.data.length > 0) {
|
||||||
|
if (result.data.length === 1) {
|
||||||
|
// 只有一个结果,直接选择
|
||||||
|
selectDoctor(result.data[0]);
|
||||||
|
} else {
|
||||||
|
// 多个结果,显示列表
|
||||||
|
doctorList.value = result.data;
|
||||||
|
message.info(`找到${result.data.length}个医生,请选择其中一个`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 没有结果
|
||||||
|
showNoResult.value = true;
|
||||||
|
message.info('未找到医生信息,请手动填写');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
smartSentry.captureError(e);
|
||||||
|
showNoResult.value = true;
|
||||||
|
message.info('搜索失败,请手动填写');
|
||||||
|
} finally {
|
||||||
|
searchLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择医生
|
||||||
|
function selectDoctor(doctor) {
|
||||||
|
selectedFromApp.value = true;
|
||||||
|
form.doctorName = doctor.doctorName;
|
||||||
|
form.doctorIden = doctor.uuid;
|
||||||
|
form.hospitalUuid = doctor.hospitalUuid;
|
||||||
|
|
||||||
|
// 如果医生有医院信息,自动设置
|
||||||
|
if (doctor.hospitalName) {
|
||||||
|
form.hospitalName = doctor.hospitalName;
|
||||||
|
form.hospitalId = doctor.hospitalId;
|
||||||
|
|
||||||
|
// 添加到医院选项中
|
||||||
|
if (doctor.hospitalId) {
|
||||||
|
hospitalOptions.value = [{
|
||||||
|
label: doctor.hospitalName,
|
||||||
|
value: doctor.hospitalId,
|
||||||
|
hospitalId: doctor.hospitalId,
|
||||||
|
hospitalName: doctor.hospitalName,
|
||||||
|
hospitalUuid: doctor.hospitalUuid,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
message.success(`已选择医生:${doctor.doctorName},医院:${doctor.hospitalName}`);
|
||||||
|
} else {
|
||||||
|
form.hospitalName = undefined;
|
||||||
|
form.hospitalId = undefined;
|
||||||
|
message.success(`已选择医生:${doctor.doctorName},请选择医院`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空搜索结果
|
||||||
|
doctorList.value = [];
|
||||||
|
showNoResult.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载医院选项
|
||||||
|
async function loadHospitalOptions() {
|
||||||
|
hospitalLoading.value = true;
|
||||||
|
try {
|
||||||
|
const result = await basicHospitalApi.queryList({
|
||||||
|
keywords: hospitalSearchKeyword.value || ''
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.data && Array.isArray(result.data)) {
|
||||||
|
// 标准化为 {label, value}
|
||||||
|
const formattedData = result.data.map(item => {
|
||||||
|
const hospitalId = item.hospitalId || item.id;
|
||||||
|
const hospitalName = item.hospitalName || item.name || item.hospital_name;
|
||||||
|
const hospitalUuid = item.hospitalUuid || item.uuid;
|
||||||
|
return {
|
||||||
|
label: hospitalName,
|
||||||
|
value: hospitalId,
|
||||||
|
hospitalId,
|
||||||
|
hospitalName,
|
||||||
|
hospitalUuid,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
hospitalOptions.value = formattedData;
|
||||||
|
} else {
|
||||||
|
hospitalOptions.value = [];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
smartSentry.captureError(e);
|
||||||
|
hospitalOptions.value = [];
|
||||||
|
} finally {
|
||||||
|
hospitalLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 医院搜索
|
||||||
|
function onHospitalSearch(value) {
|
||||||
|
hospitalSearchKeyword.value = value;
|
||||||
|
if (value && value.trim()) {
|
||||||
|
loadHospitalOptions();
|
||||||
|
} else {
|
||||||
|
hospitalOptions.value = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择医院变更
|
||||||
|
async function onHospitalChange(value, option) {
|
||||||
|
if (!value || !option) {
|
||||||
|
form.hospitalId = undefined;
|
||||||
|
form.hospitalName = undefined;
|
||||||
|
form.hospitalUuid = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
form.hospitalId = option.hospitalId ?? value;
|
||||||
|
form.hospitalName = option.hospitalName ?? option.label;
|
||||||
|
form.hospitalUuid = option.hospitalUuid ?? option.uuid;
|
||||||
|
|
||||||
|
// 如果是从APP结果选择了医生,则用户选择医院后自动保存为新增
|
||||||
|
if (selectedFromApp.value && !form.doctorId) {
|
||||||
|
if (autoSaving.value) return;
|
||||||
|
autoSaving.value = true;
|
||||||
|
try {
|
||||||
|
await formRef.value.validateFields();
|
||||||
|
await save();
|
||||||
|
} catch (err) {
|
||||||
|
// 校验失败时不提交
|
||||||
|
} finally {
|
||||||
|
autoSaving.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
async function onSubmit() {
|
||||||
|
try {
|
||||||
|
await formRef.value.validateFields();
|
||||||
|
await save();
|
||||||
|
} catch (err) {
|
||||||
|
message.error('请检查表单填写是否正确');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存数据
|
||||||
|
async function save() {
|
||||||
|
SmartLoading.show();
|
||||||
|
try {
|
||||||
|
if (form.doctorId) {
|
||||||
|
await caseClinicalDoctorApi.update(form);
|
||||||
|
message.success('更新成功');
|
||||||
|
} else {
|
||||||
|
await caseClinicalDoctorApi.add(form);
|
||||||
|
message.success('添加成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
emits('reloadList');
|
||||||
|
onClose();
|
||||||
|
} catch (err) {
|
||||||
|
smartSentry.captureError(err);
|
||||||
|
message.error('操作失败');
|
||||||
|
} finally {
|
||||||
|
SmartLoading.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露方法
|
||||||
|
defineExpose({
|
||||||
|
show,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.doctor-list {
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doctor-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doctor-name {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #262626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doctor-phone {
|
||||||
|
color: #8c8c8c;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doctor-details {
|
||||||
|
color: #595959;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-display img {
|
||||||
|
border: 2px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-placeholder {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -96,6 +96,7 @@
|
|||||||
import LocalStorageKeyConst from '/@/constants/local-storage-key-const.js';
|
import LocalStorageKeyConst from '/@/constants/local-storage-key-const.js';
|
||||||
import { useDictStore } from '/@/store/modules/system/dict.js';
|
import { useDictStore } from '/@/store/modules/system/dict.js';
|
||||||
import { dictApi } from '/@/api/support/dict-api.js';
|
import { dictApi } from '/@/api/support/dict-api.js';
|
||||||
|
import { HOME_PAGE_PATH } from '/@/constants/common-const';
|
||||||
|
|
||||||
//--------------------- 登录表单 ---------------------------------
|
//--------------------- 登录表单 ---------------------------------
|
||||||
|
|
||||||
@ -149,7 +150,7 @@
|
|||||||
useDictStore().initData(dictRes.data);
|
useDictStore().initData(dictRes.data);
|
||||||
//构建系统的路由
|
//构建系统的路由
|
||||||
buildRoutes();
|
buildRoutes();
|
||||||
router.push('/home');
|
router.replace(HOME_PAGE_PATH);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.data && e.data.code !== 0) {
|
if (e.data && e.data.code !== 0) {
|
||||||
loginForm.captchaCode = '';
|
loginForm.captchaCode = '';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user