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 HOME_PAGE_PATH = '/home';
|
||||
export const HOME_PAGE_PATH = '/case-clinical-article/list';
|
||||
|
||||
//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
|
||||
*/
|
||||
import { homeRouters } from './system/home';
|
||||
import { caseClinicalArticleRouters } from './system/case-clinical-article';
|
||||
import { loginRouters } from './system/login';
|
||||
import { helpDocRouters } from './support/help-doc';
|
||||
import NotFound from '/@/views/system/40X/404.vue';
|
||||
@ -15,7 +16,8 @@ import NoPrivilege from '/@/views/system/40X/403.vue';
|
||||
|
||||
export const routerArray = [
|
||||
...loginRouters,
|
||||
...homeRouters,
|
||||
...homeRouters,
|
||||
...caseClinicalArticleRouters,
|
||||
...helpDocRouters,
|
||||
{ path: '/:pathMatch(.*)*', name: '404', component: NotFound },
|
||||
{ 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 },
|
||||
component: SmartLayout,
|
||||
meta: {
|
||||
title: '首页',
|
||||
title: '文章病例库管理',
|
||||
menuType: MENU_TYPE_ENUM.CATALOG.value,
|
||||
icon: 'HomeOutlined',
|
||||
icon: 'FileTextOutlined',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '/home',
|
||||
path: '/case-clinical-article/list',
|
||||
name: HOME_PAGE_NAME,
|
||||
meta: {
|
||||
title: '首页',
|
||||
title: '文章病例库管理',
|
||||
menuType: MENU_TYPE_ENUM.MENU.value,
|
||||
icon: 'HomeOutlined',
|
||||
parentMenuList: [{ name: '_home', title: '首页' }],
|
||||
icon: 'FileTextOutlined',
|
||||
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',
|
||||
|
||||
@ -7,84 +7,116 @@
|
||||
-->
|
||||
<template>
|
||||
<a-modal
|
||||
:title="form.doctorId ? '编辑' : '添加'"
|
||||
:width="1000"
|
||||
:open="visibleFlag"
|
||||
@cancel="onClose"
|
||||
:maskClosable="false"
|
||||
:destroyOnClose="true"
|
||||
:title="form.doctorId ? '编辑医生' : '添加医生'"
|
||||
:width="800"
|
||||
:open="visibleFlag"
|
||||
@cancel="onClose"
|
||||
:maskClosable="false"
|
||||
:destroyOnClose="true"
|
||||
>
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 5 }" >
|
||||
<a-form-item label="用户名称" name="doctorName">
|
||||
<a-input-group compact>
|
||||
<a-input
|
||||
style="calc(100% - 80px)"
|
||||
v-model:value="form.doctorName"
|
||||
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"
|
||||
<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-input
|
||||
v-model:value="form.doctorName"
|
||||
placeholder="请输入医生姓名"
|
||||
:disabled="!!form.doctorId"
|
||||
@focus="onHospitalFocus"
|
||||
@search="onHospitalSearch"
|
||||
show-search
|
||||
allowClear
|
||||
style="width: calc(100% - 80px)"
|
||||
@pressEnter="searchDoctor"
|
||||
/>
|
||||
</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;" />
|
||||
<a-button
|
||||
v-if="!form.doctorId"
|
||||
type="primary"
|
||||
style="width: 80px"
|
||||
@click="searchDoctor"
|
||||
:loading="searchLoading"
|
||||
>
|
||||
搜索
|
||||
</a-button>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 医生搜索结果 -->
|
||||
<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 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>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<template #footer>
|
||||
@ -95,238 +127,332 @@
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import _ from 'lodash';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { caseClinicalDoctorApi } from '/@/api/business/case-clinical-doctor/case-clinical-doctor-api';
|
||||
import { basicHospitalApi } from '/@/api/business/basic-hospital/basic-hospital-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { debounce } from 'lodash';
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { caseClinicalDoctorApi } from '/@/api/business/case-clinical-doctor/case-clinical-doctor-api';
|
||||
import { basicHospitalApi } from '/@/api/business/basic-hospital/basic-hospital-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
// ------------------------ 事件 ------------------------
|
||||
// 事件
|
||||
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);
|
||||
hospitalOptions.value = [];
|
||||
appDoctorInfo.value = null;
|
||||
|
||||
if (rowData && !_.isEmpty(rowData)) {
|
||||
if (rowData.doctorId) {
|
||||
// 编辑模式:获取完整的医生详情信息
|
||||
try {
|
||||
SmartLoading.show();
|
||||
const result = await caseClinicalDoctorApi.getDetail(rowData.doctorId);
|
||||
Object.assign(form, result.data);
|
||||
|
||||
// 如果有医院信息,将当前医院添加到选项中以便正确显示
|
||||
if (result.data.hospitalId && result.data.hospitalName) {
|
||||
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(() => {
|
||||
formRef.value.clearValidate();
|
||||
});
|
||||
}
|
||||
// 搜索状态
|
||||
const searchLoading = ref(false);
|
||||
const showNoResult = ref(false);
|
||||
|
||||
function onClose() {
|
||||
Object.assign(form, formDefault);
|
||||
hospitalOptions.value = [];
|
||||
appDoctorInfo.value = null;
|
||||
searchLoading.value = false;
|
||||
visibleFlag.value = false;
|
||||
}
|
||||
// 是否从APP列表选择了医生,用于控制自动保存
|
||||
const selectedFromApp = ref(false);
|
||||
// 自动保存中标记,避免重复提交
|
||||
const autoSaving = ref(false);
|
||||
|
||||
// ------------------------ 医生名称搜索 ------------------------
|
||||
|
||||
// 搜索APP医生
|
||||
async function searchAppDoctor() {
|
||||
// 编辑模式下不搜索
|
||||
if (form.doctorId || !form.doctorName || form.doctorName.trim() === '') {
|
||||
message.warning('请输入医生姓名');
|
||||
return;
|
||||
}
|
||||
|
||||
searchLoading.value = true;
|
||||
// 医生列表
|
||||
const doctorList = ref([]);
|
||||
|
||||
// 医院相关
|
||||
const hospitalOptions = ref([]);
|
||||
const hospitalLoading = ref(false);
|
||||
const hospitalSearchKeyword = ref('');
|
||||
|
||||
// 表单默认值
|
||||
const formDefault = {
|
||||
doctorId: undefined,
|
||||
doctorName: undefined,
|
||||
doctorIden: undefined,
|
||||
hospitalId: undefined,
|
||||
hospitalUuid: undefined,
|
||||
hospitalName: undefined,
|
||||
status: 1,
|
||||
avatar: undefined,
|
||||
};
|
||||
|
||||
// 表单数据
|
||||
let form = reactive({ ...formDefault });
|
||||
|
||||
// 表单验证规则
|
||||
const rules = {
|
||||
doctorName: [{ required: true, message: '医生姓名必填' }],
|
||||
hospitalId: [{ required: true, message: '所属医院必填' }],
|
||||
};
|
||||
|
||||
// 显示表单
|
||||
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 {
|
||||
const result = await caseClinicalDoctorApi.getAppDoctor(form.doctorName);
|
||||
if (result.data) {
|
||||
// 保存APP医生信息,等待用户确认
|
||||
appDoctorInfo.value = result.data;
|
||||
message.info('找到APP医生信息,请确认是否使用');
|
||||
}
|
||||
} catch (e) {
|
||||
// 没找到医生信息,清空之前的搜索结果
|
||||
appDoctorInfo.value = null;
|
||||
message.info('未找到APP医生信息,请手动选择医院');
|
||||
SmartLoading.show();
|
||||
const result = await caseClinicalDoctorApi.getDetail(rowData.doctorId);
|
||||
Object.assign(form, result.data);
|
||||
|
||||
// 自动加载医院列表供用户选择
|
||||
if (hospitalOptions.value.length === 0) {
|
||||
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;
|
||||
|
||||
// 添加到选项中
|
||||
// 如果有医院信息,添加到选项中
|
||||
if (result.data.hospitalId && result.data.hospitalName) {
|
||||
hospitalOptions.value = [{
|
||||
hospitalId: appDoctorInfo.value.hospitalId,
|
||||
hospitalName: appDoctorInfo.value.hospitalName
|
||||
label: result.data.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) {
|
||||
smartSentry.captureError(e);
|
||||
hospitalOptions.value = [];
|
||||
} 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);
|
||||
Object.assign(form, rowData);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
visibleFlag.value = true;
|
||||
|
||||
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>
|
||||
|
||||
<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 { useDictStore } from '/@/store/modules/system/dict.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);
|
||||
//构建系统的路由
|
||||
buildRoutes();
|
||||
router.push('/home');
|
||||
router.replace(HOME_PAGE_PATH);
|
||||
} catch (e) {
|
||||
if (e.data && e.data.code !== 0) {
|
||||
loginForm.captchaCode = '';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user