更新
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
# 医生字段安装说明
|
||||
|
||||
## 概述
|
||||
此文档说明如何为医生管理功能添加必要的数据库字段。
|
||||
|
||||
## 新增字段列表
|
||||
|
||||
### 基本信息
|
||||
- `gender` - 性别(1=男,2=女)
|
||||
- `age` - 年龄
|
||||
- `phone` - 手机号
|
||||
|
||||
### 专业信息
|
||||
- `title` - 职称(如:主任医师、副主任医师)
|
||||
- `department` - 所属科室(如:中医科、内科)
|
||||
- `specialty` - 擅长领域(文本)
|
||||
|
||||
### 履历信息
|
||||
- `education` - 教育背景(文本)
|
||||
- `experience` - 工作经历(文本)
|
||||
- `honors` - 荣誉资质(文本)
|
||||
|
||||
## 安装步骤
|
||||
|
||||
### 1. 备份数据库
|
||||
在执行任何数据库修改之前,请先备份数据库:
|
||||
|
||||
```bash
|
||||
mysqldump -u root -p zyt > zyt_backup_$(date +%Y%m%d_%H%M%S).sql
|
||||
```
|
||||
|
||||
### 2. 执行迁移脚本
|
||||
|
||||
#### 方法一:使用MySQL命令行
|
||||
```bash
|
||||
mysql -u root -p zyt < server/database/migrations/add_doctor_fields_to_admin.sql
|
||||
```
|
||||
|
||||
#### 方法二:使用数据库管理工具
|
||||
1. 打开 Navicat、phpMyAdmin 或其他数据库管理工具
|
||||
2. 连接到数据库
|
||||
3. 打开 `server/database/migrations/add_doctor_fields_to_admin.sql` 文件
|
||||
4. 执行SQL脚本
|
||||
|
||||
### 3. 验证安装
|
||||
|
||||
执行以下SQL查询验证字段是否添加成功:
|
||||
|
||||
```sql
|
||||
DESCRIBE zyt_admin;
|
||||
```
|
||||
|
||||
应该能看到新增的字段:
|
||||
- gender
|
||||
- age
|
||||
- phone
|
||||
- title
|
||||
- department
|
||||
- specialty
|
||||
- education
|
||||
- experience
|
||||
- honors
|
||||
|
||||
### 4. 测试功能
|
||||
|
||||
1. 登录管理后台
|
||||
2. 进入"医生管理"页面
|
||||
3. 点击"新增医生"
|
||||
4. 填写所有字段并保存
|
||||
5. 验证数据是否正确保存
|
||||
|
||||
## 回滚说明
|
||||
|
||||
如果需要撤销这些更改,可以执行回滚脚本:
|
||||
|
||||
```bash
|
||||
mysql -u root -p zyt < server/database/migrations/rollback_doctor_fields_from_admin.sql
|
||||
```
|
||||
|
||||
**警告:** 回滚操作将删除这些字段的所有数据,请谨慎操作!
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **数据兼容性**:现有的管理员记录不会受到影响,新字段默认为NULL
|
||||
2. **索引优化**:为`phone`和`gender`字段添加了索引以提高查询性能
|
||||
3. **字段长度**:
|
||||
- `phone`: varchar(20) - 支持国际号码格式
|
||||
- `title`: varchar(50) - 职称名称
|
||||
- `department`: varchar(100) - 科室名称
|
||||
- `specialty`, `education`, `experience`, `honors`: text - 支持长文本
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 执行脚本时报错"字段已存在"
|
||||
A: 说明字段已经添加过了,可以跳过此步骤或先执行回滚脚本。
|
||||
|
||||
### Q: 现有管理员数据会丢失吗?
|
||||
A: 不会,新增字段不会影响现有数据。
|
||||
|
||||
### Q: 如何批量更新现有医生的信息?
|
||||
A: 可以通过管理后台逐个编辑,或编写SQL脚本批量更新。
|
||||
|
||||
## 相关文件
|
||||
|
||||
- 迁移脚本:`server/database/migrations/add_doctor_fields_to_admin.sql`
|
||||
- 回滚脚本:`server/database/migrations/rollback_doctor_fields_from_admin.sql`
|
||||
- 前端页面:`admin/src/views/consumer/doctor/edit.vue`
|
||||
|
||||
## 技术支持
|
||||
|
||||
如有问题,请检查:
|
||||
1. 数据库连接是否正常
|
||||
2. 用户是否有ALTER TABLE权限
|
||||
3. 表名是否正确(默认为`zyt_admin`)
|
||||
@@ -126,11 +126,11 @@ const callInfo = ref<CallInfo>({
|
||||
// 窗口位置和大小
|
||||
const windowRef = ref<HTMLElement>()
|
||||
const windowPosition = ref({ x: 100, y: 100 })
|
||||
const windowSize = ref({ width: 800, height: 600 })
|
||||
const windowSize = ref({ width: 300, height: 750 })
|
||||
|
||||
// 拖拽相关
|
||||
const isDragging = ref(false)
|
||||
const dragStart = ref({ x: 0, y: 0 })
|
||||
const dragStart = ref({ x: 10, y: 0 })
|
||||
|
||||
// 调整大小相关
|
||||
const isResizing = ref(false)
|
||||
|
||||
@@ -0,0 +1,434 @@
|
||||
<template>
|
||||
<div class="edit-drawer">
|
||||
<el-drawer
|
||||
v-model="visible"
|
||||
:title="drawerTitle"
|
||||
direction="rtl"
|
||||
size="780px"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<el-form ref="formRef" :model="formData" label-width="100px" :rules="formRules">
|
||||
<el-divider content-position="left">基本信息</el-divider>
|
||||
|
||||
<!-- 账号输入框 -->
|
||||
<el-form-item label="账号" prop="account">
|
||||
<el-input
|
||||
v-model="formData.account"
|
||||
placeholder="请输入账号"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 医生头像 -->
|
||||
<el-form-item label="头像">
|
||||
<div>
|
||||
<div>
|
||||
<material-picker v-model="formData.avatar" :limit="1" />
|
||||
</div>
|
||||
<div class="form-tips">建议尺寸:100*100px,支持jpg,jpeg,png格式</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 姓名输入框 -->
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入姓名" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 性别 -->
|
||||
<el-form-item label="性别" prop="gender">
|
||||
<el-radio-group v-model="formData.gender">
|
||||
<el-radio :label="1">男</el-radio>
|
||||
<el-radio :label="2">女</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 年龄 -->
|
||||
<el-form-item label="年龄" prop="age">
|
||||
<el-input-number v-model="formData.age" :min="18" :max="100" placeholder="请输入年龄" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 手机号输入框 -->
|
||||
<el-form-item label="手机号" prop="phone">
|
||||
<el-input v-model="formData.phone" placeholder="请输入手机号" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-divider content-position="left">组织信息</el-divider>
|
||||
|
||||
<!-- 归属部门 -->
|
||||
<el-form-item label="归属部门" prop="dept_id">
|
||||
<el-tree-select
|
||||
class="flex-1"
|
||||
v-model="formData.dept_id"
|
||||
:data="optionsData.dept"
|
||||
clearable
|
||||
multiple
|
||||
node-key="id"
|
||||
:props="{
|
||||
label: 'name',
|
||||
disabled(data: any) {
|
||||
return data.status !== 1
|
||||
}
|
||||
}"
|
||||
check-strictly
|
||||
:default-expand-all="true"
|
||||
placeholder="请选择归属部门"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 岗位 -->
|
||||
<el-form-item label="岗位" prop="jobs_id">
|
||||
<el-select
|
||||
class="flex-1"
|
||||
v-model="formData.jobs_id"
|
||||
clearable
|
||||
multiple
|
||||
placeholder="请选择岗位"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, index) in optionsData.jobs"
|
||||
:key="index"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider content-position="left">专业信息</el-divider>
|
||||
|
||||
<!-- 职称 -->
|
||||
<el-form-item label="职称" prop="title">
|
||||
<el-input v-model="formData.title" placeholder="如:主任医师、副主任医师" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 所属科室 -->
|
||||
<el-form-item label="所属科室" prop="department">
|
||||
<el-input v-model="formData.department" placeholder="如:中医科、内科" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 擅长领域 -->
|
||||
<el-form-item label="擅长领域" prop="specialty">
|
||||
<el-input
|
||||
v-model="formData.specialty"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入擅长领域"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider content-position="left">履历信息</el-divider>
|
||||
|
||||
<!-- 教育背景 -->
|
||||
<el-form-item label="教育背景" prop="education">
|
||||
<el-input
|
||||
v-model="formData.education"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入教育背景,如:北京中医药大学 中医学博士"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 工作经历 -->
|
||||
<el-form-item label="工作经历" prop="experience">
|
||||
<el-input
|
||||
v-model="formData.experience"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入工作经历"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 荣誉资质 -->
|
||||
<el-form-item label="荣誉资质" prop="honors">
|
||||
<el-input
|
||||
v-model="formData.honors"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入荣誉资质"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider content-position="left">账号设置</el-divider>
|
||||
|
||||
<!-- 密码输入框 -->
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input
|
||||
v-model="formData.password"
|
||||
show-password
|
||||
clearable
|
||||
:placeholder="mode === 'edit' ? '不修改请留空' : '请输入密码'"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 确认密码输入框 -->
|
||||
<el-form-item label="确认密码" prop="password_confirm">
|
||||
<el-input
|
||||
v-model="formData.password_confirm"
|
||||
show-password
|
||||
clearable
|
||||
:placeholder="mode === 'edit' ? '不修改请留空' : '请输入确认密码'"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 医生状态 -->
|
||||
<el-form-item label="医生状态">
|
||||
<el-switch v-model="formData.disable" :active-value="0" :inactive-value="1" />
|
||||
<span class="ml-2 text-gray-500">{{ formData.disable === 0 ? '启用' : '禁用' }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 多处登录 -->
|
||||
<el-form-item label="多处登录">
|
||||
<div>
|
||||
<el-switch
|
||||
v-model="formData.multipoint_login"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
/>
|
||||
<div class="form-tips">允许多人同时在线登录</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="flex justify-end">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="loading">确定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { adminAdd, adminDetail, adminEdit } from '@/api/perms/admin'
|
||||
import { deptAll } from '@/api/org/department'
|
||||
import { jobsAll } from '@/api/org/post'
|
||||
import { useDictOptions } from '@/hooks/useDictOptions'
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
const emit = defineEmits(['success', 'close'])
|
||||
const formRef = shallowRef<FormInstance>()
|
||||
const visible = ref(false)
|
||||
const mode = ref('add')
|
||||
const loading = ref(false)
|
||||
|
||||
const drawerTitle = computed(() => {
|
||||
return mode.value == 'edit' ? '编辑医生' : '新增医生'
|
||||
})
|
||||
|
||||
const formData = reactive({
|
||||
id: '',
|
||||
account: '',
|
||||
name: '',
|
||||
gender: 1,
|
||||
age: null as number | null,
|
||||
phone: '',
|
||||
role_id: [1], // 固定为医生角色
|
||||
dept_id: [],
|
||||
jobs_id: [],
|
||||
avatar: '',
|
||||
title: '', // 职称
|
||||
department: '', // 所属科室
|
||||
specialty: '', // 擅长领域
|
||||
education: '', // 教育背景
|
||||
experience: '', // 工作经历
|
||||
honors: '', // 荣誉资质
|
||||
password: '',
|
||||
password_confirm: '',
|
||||
disable: 0,
|
||||
multipoint_login: 1
|
||||
})
|
||||
|
||||
// 获取部门和岗位选项
|
||||
const { optionsData } = useDictOptions<{
|
||||
jobs: any[]
|
||||
dept: any[]
|
||||
}>({
|
||||
jobs: {
|
||||
api: jobsAll
|
||||
},
|
||||
dept: {
|
||||
api: deptAll
|
||||
}
|
||||
})
|
||||
|
||||
// 密码确认验证
|
||||
const passwordConfirmValidator = (rule: object, value: string, callback: any) => {
|
||||
if (formData.password) {
|
||||
if (!value) callback(new Error('请再次输入密码'))
|
||||
if (value !== formData.password) callback(new Error('两次输入密码不一致!'))
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
// 手机号验证
|
||||
const phoneValidator = (rule: object, value: string, callback: any) => {
|
||||
if (value && !/^1[3-9]\d{9}$/.test(value)) {
|
||||
callback(new Error('请输入正确的手机号'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
const formRules = reactive({
|
||||
account: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入账号',
|
||||
trigger: ['blur']
|
||||
}
|
||||
],
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入姓名',
|
||||
trigger: ['blur']
|
||||
}
|
||||
],
|
||||
gender: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择性别',
|
||||
trigger: ['change']
|
||||
}
|
||||
],
|
||||
phone: [
|
||||
{
|
||||
validator: phoneValidator,
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入密码',
|
||||
trigger: ['blur']
|
||||
}
|
||||
] as any[],
|
||||
password_confirm: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入确认密码',
|
||||
trigger: ['blur']
|
||||
},
|
||||
{
|
||||
validator: passwordConfirmValidator,
|
||||
trigger: 'blur'
|
||||
}
|
||||
] as any[]
|
||||
})
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
await formRef.value?.validate()
|
||||
loading.value = true
|
||||
|
||||
mode.value == 'edit' ? await adminEdit(formData) : await adminAdd(formData)
|
||||
|
||||
feedback.msgSuccess(mode.value == 'edit' ? '编辑成功' : '新增成功')
|
||||
visible.value = false
|
||||
emit('success')
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const open = (type = 'add') => {
|
||||
mode.value = type
|
||||
visible.value = true
|
||||
|
||||
// 重置表单
|
||||
if (type === 'add') {
|
||||
Object.assign(formData, {
|
||||
id: '',
|
||||
account: '',
|
||||
name: '',
|
||||
gender: 1,
|
||||
age: null,
|
||||
phone: '',
|
||||
role_id: [1],
|
||||
dept_id: [],
|
||||
jobs_id: [],
|
||||
avatar: '',
|
||||
title: '',
|
||||
department: '',
|
||||
specialty: '',
|
||||
education: '',
|
||||
experience: '',
|
||||
honors: '',
|
||||
password: '',
|
||||
password_confirm: '',
|
||||
disable: 0,
|
||||
multipoint_login: 1
|
||||
})
|
||||
|
||||
// 新增时密码必填
|
||||
formRules.password = [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入密码',
|
||||
trigger: ['blur']
|
||||
}
|
||||
]
|
||||
formRules.password_confirm = [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入确认密码',
|
||||
trigger: ['blur']
|
||||
},
|
||||
{
|
||||
validator: passwordConfirmValidator,
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
const setFormData = async (row: any) => {
|
||||
// 编辑时密码不是必填
|
||||
formRules.password = []
|
||||
formRules.password_confirm = [
|
||||
{
|
||||
validator: passwordConfirmValidator,
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
|
||||
const data = await adminDetail({
|
||||
id: row.id
|
||||
})
|
||||
|
||||
for (const key in formData) {
|
||||
if (data[key] != null && data[key] != undefined) {
|
||||
//@ts-ignore
|
||||
formData[key] = data[key]
|
||||
}
|
||||
}
|
||||
|
||||
// 确保role_id包含医生角色
|
||||
if (!formData.role_id.includes(1)) {
|
||||
formData.role_id.push(1)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
visible.value = false
|
||||
emit('close')
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
setFormData
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.form-tips {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,164 @@
|
||||
<!-- 医生列表 -->
|
||||
<template>
|
||||
<div class="doctor-list">
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<el-form class="mb-[-16px]" :model="formData" inline>
|
||||
<el-form-item class="w-[280px]" label="医生账号">
|
||||
<el-input
|
||||
v-model="formData.account"
|
||||
placeholder="请输入医生账号"
|
||||
clearable
|
||||
@keyup.enter="resetPage"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="w-[280px]" label="医生名称">
|
||||
<el-input
|
||||
v-model="formData.name"
|
||||
placeholder="请输入医生名称"
|
||||
clearable
|
||||
@keyup.enter="resetPage"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="resetPage">查询</el-button>
|
||||
<el-button @click="resetParams">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card v-loading="pager.loading" class="mt-4 !border-none" shadow="never">
|
||||
<el-button v-perms="['auth.admin/add']" type="primary" @click="handleAdd">
|
||||
<template #icon>
|
||||
<icon name="el-icon-Plus" />
|
||||
</template>
|
||||
新增医生
|
||||
</el-button>
|
||||
|
||||
<div class="mt-4">
|
||||
<el-table :data="pager.lists" size="large">
|
||||
<el-table-column label="ID" prop="id" min-width="60" />
|
||||
<el-table-column label="头像" min-width="100">
|
||||
<template #default="{ row }">
|
||||
<el-avatar :size="50" :src="row.avatar"></el-avatar>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="账号" prop="account" min-width="120" />
|
||||
<el-table-column label="姓名" prop="name" min-width="100" />
|
||||
<el-table-column label="手机号" prop="phone" min-width="120" />
|
||||
<el-table-column label="创建时间" prop="create_time" min-width="180" />
|
||||
<el-table-column label="最近登录时间" prop="login_time" min-width="180" />
|
||||
<el-table-column label="最近登录IP" prop="login_ip" min-width="120" />
|
||||
<el-table-column label="状态" min-width="100" v-perms="['auth.admin/edit']">
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
v-model="row.disable"
|
||||
:active-value="0"
|
||||
:inactive-value="1"
|
||||
@change="changeStatus(row)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-perms="['auth.admin/edit']"
|
||||
type="primary"
|
||||
link
|
||||
@click="handleEdit(row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
v-perms="['auth.admin/delete']"
|
||||
type="danger"
|
||||
link
|
||||
@click="handleDelete(row.id)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<div class="flex mt-4 justify-end">
|
||||
<pagination v-model="pager" @change="getLists" />
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="doctorList">
|
||||
import { adminDelete, adminEdit, adminLists } from '@/api/perms/admin'
|
||||
import { usePaging } from '@/hooks/usePaging'
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
import EditPopup from './edit.vue'
|
||||
|
||||
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
|
||||
|
||||
// 表单数据 - 固定role_id=1查询医生
|
||||
const formData = reactive({
|
||||
account: '',
|
||||
name: '',
|
||||
role_id: 1 // 固定为医生角色
|
||||
})
|
||||
|
||||
const showEdit = ref(false)
|
||||
|
||||
const { pager, getLists, resetParams, resetPage } = usePaging({
|
||||
fetchFun: adminLists,
|
||||
params: formData
|
||||
})
|
||||
|
||||
// 修改状态
|
||||
const changeStatus = (data: any) => {
|
||||
adminEdit({
|
||||
id: data.id,
|
||||
avatar: data.avatar,
|
||||
account: data.account,
|
||||
name: data.name,
|
||||
role_id: data.role_id,
|
||||
jobs_id: data.jobs_id,
|
||||
dept_id: data.dept_id,
|
||||
disable: data.disable,
|
||||
multipoint_login: data.multipoint_login
|
||||
}).finally(() => {
|
||||
getLists()
|
||||
})
|
||||
}
|
||||
|
||||
// 新增医生
|
||||
const handleAdd = async () => {
|
||||
showEdit.value = true
|
||||
await nextTick()
|
||||
editRef.value?.open('add')
|
||||
}
|
||||
|
||||
// 编辑医生
|
||||
const handleEdit = async (data: any) => {
|
||||
showEdit.value = true
|
||||
await nextTick()
|
||||
editRef.value?.open('edit')
|
||||
editRef.value?.setFormData(data)
|
||||
}
|
||||
|
||||
// 删除医生
|
||||
const handleDelete = async (id: number) => {
|
||||
await feedback.confirm('确定要删除该医生吗?')
|
||||
await adminDelete({ id })
|
||||
getLists()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getLists()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.doctor-list {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,255 @@
|
||||
<template>
|
||||
<el-drawer
|
||||
v-model="visible"
|
||||
title="创建处方单"
|
||||
size="800px"
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose"
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
label-width="100px"
|
||||
class="prescription-form"
|
||||
>
|
||||
<!-- 患者基本信息 -->
|
||||
<div class="info-section">
|
||||
<div class="section-title">患者信息</div>
|
||||
<el-form-item label="姓名">
|
||||
<span>{{ formData.patient_name }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别">
|
||||
<span>{{ formData.gender }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="年龄">
|
||||
<span>{{ formData.age }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="诊号">
|
||||
<span>{{ formData.diagnosis_no }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="日期">
|
||||
<span>{{ formData.date }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="科室">
|
||||
<span>{{ formData.department }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="费别">
|
||||
<span>{{ formData.fee_type }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号">
|
||||
<span>{{ formData.phone }}</span>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 诊断信息 -->
|
||||
<div class="info-section">
|
||||
<div class="section-title">诊断信息</div>
|
||||
<el-form-item label="诊断" prop="diagnosis">
|
||||
<el-input
|
||||
v-model="formData.diagnosis"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入诊断信息"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 药品信息 -->
|
||||
<div class="info-section">
|
||||
<div class="section-title">
|
||||
药品信息
|
||||
<el-button type="primary" size="small" @click="handleAddMedicine">
|
||||
添加药品
|
||||
</el-button>
|
||||
</div>
|
||||
<div
|
||||
v-for="(medicine, index) in formData.medicines"
|
||||
:key="index"
|
||||
class="medicine-item"
|
||||
>
|
||||
<el-form-item :label="`药品${index + 1}`">
|
||||
<el-input
|
||||
v-model="medicine.name"
|
||||
placeholder="药品名称"
|
||||
class="mb-2"
|
||||
/>
|
||||
<el-input
|
||||
v-model="medicine.usage"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="用法用量"
|
||||
/>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
link
|
||||
@click="handleRemoveMedicine(index)"
|
||||
class="mt-2"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" @click="handleSave">保存</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
interface Medicine {
|
||||
name: string
|
||||
usage: string
|
||||
}
|
||||
|
||||
interface PrescriptionForm {
|
||||
appointment_id: number
|
||||
patient_name: string
|
||||
gender: string
|
||||
age: string
|
||||
diagnosis_no: string
|
||||
date: string
|
||||
department: string
|
||||
fee_type: string
|
||||
phone: string
|
||||
diagnosis: string
|
||||
medicines: Medicine[]
|
||||
}
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
const visible = ref(false)
|
||||
const formRef = ref()
|
||||
const formData = reactive<PrescriptionForm>({
|
||||
appointment_id: 0,
|
||||
patient_name: '',
|
||||
gender: '',
|
||||
age: '',
|
||||
diagnosis_no: '',
|
||||
date: '',
|
||||
department: '',
|
||||
fee_type: '',
|
||||
phone: '',
|
||||
diagnosis: '',
|
||||
medicines: []
|
||||
})
|
||||
|
||||
// 打开抽屉
|
||||
const open = (data: any) => {
|
||||
formData.appointment_id = data.id
|
||||
formData.patient_name = data.patient_name || ''
|
||||
formData.gender = data.patient_gender || ''
|
||||
formData.age = data.patient_age || ''
|
||||
formData.diagnosis_no = data.id.toString()
|
||||
formData.date = data.appointment_date || ''
|
||||
formData.department = '中医科'
|
||||
formData.fee_type = data.appointment_type_desc || ''
|
||||
formData.phone = data.patient_phone || ''
|
||||
formData.diagnosis = ''
|
||||
formData.medicines = []
|
||||
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
// 关闭抽屉
|
||||
const handleClose = () => {
|
||||
visible.value = false
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
|
||||
// 添加药品
|
||||
const handleAddMedicine = () => {
|
||||
formData.medicines.push({
|
||||
name: '',
|
||||
usage: ''
|
||||
})
|
||||
}
|
||||
|
||||
// 删除药品
|
||||
const handleRemoveMedicine = (index: number) => {
|
||||
formData.medicines.splice(index, 1)
|
||||
}
|
||||
|
||||
// 保存处方单
|
||||
const handleSave = async () => {
|
||||
if (!formData.diagnosis) {
|
||||
feedback.msgWarning('请输入诊断信息')
|
||||
return
|
||||
}
|
||||
|
||||
if (formData.medicines.length === 0) {
|
||||
feedback.msgWarning('请至少添加一个药品')
|
||||
return
|
||||
}
|
||||
|
||||
// 验证药品信息
|
||||
for (const medicine of formData.medicines) {
|
||||
if (!medicine.name || !medicine.usage) {
|
||||
feedback.msgWarning('请完善药品信息')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO: 调用保存处方单的API
|
||||
// await savePrescription(formData)
|
||||
|
||||
feedback.msgSuccess('处方单创建成功')
|
||||
handleClose()
|
||||
emit('success')
|
||||
} catch (error) {
|
||||
feedback.msgError('保存失败')
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.prescription-form {
|
||||
.info-section {
|
||||
margin-bottom: 24px;
|
||||
padding: 16px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
color: #303133;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 12px;
|
||||
|
||||
span {
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.medicine-item {
|
||||
margin-bottom: 16px;
|
||||
padding: 12px;
|
||||
background: #fff;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -8,16 +8,16 @@
|
||||
v-model="formData.patient_name"
|
||||
placeholder="请输入患者姓名"
|
||||
clearable
|
||||
@keyup.enter="resetPage"
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item class="w-[280px]" label="医生姓名">
|
||||
<el-form-item class="w-[280px]" label="医生姓名" v-if="isAdmin">
|
||||
<el-input
|
||||
v-model="formData.doctor_name"
|
||||
placeholder="请输入医生姓名"
|
||||
clearable
|
||||
@keyup.enter="resetPage"
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
<el-option label="已预约" :value="1" />
|
||||
<el-option label="已取消" :value="2" />
|
||||
<el-option label="已完成" :value="3" />
|
||||
<el-option label="已过号" :value="4" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
@@ -37,14 +38,43 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="resetPage">查询</el-button>
|
||||
<el-button @click="resetParams">重置</el-button>
|
||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<!-- tab选项卡 -->
|
||||
<el-tabs v-model="activeTab" @tab-change="handleTabChange" class="mb-4">
|
||||
<el-tab-pane label="全部" name="all" />
|
||||
<el-tab-pane name="1">
|
||||
<template #label>
|
||||
<span>已预约</span>
|
||||
<el-badge v-if="statusCount[1]" :value="statusCount[1]" class="ml-2" type="success" />
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="4">
|
||||
<template #label>
|
||||
<span>已过号</span>
|
||||
<el-badge v-if="statusCount[4]" :value="statusCount[4]" class="ml-2" type="danger" />
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="2">
|
||||
<template #label>
|
||||
<span>已取消</span>
|
||||
<el-badge v-if="statusCount[2]" :value="statusCount[2]" class="ml-2" type="info" />
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="3">
|
||||
<template #label>
|
||||
<span>已完成</span>
|
||||
<el-badge v-if="statusCount[3]" :value="statusCount[3]" class="ml-2" type="primary" />
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<el-table
|
||||
v-loading="pager.loading"
|
||||
:data="pager.lists"
|
||||
@@ -87,10 +117,10 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="状态" width="80">
|
||||
<el-table-column label="状态" width="90">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:type="row.status === 1 ? 'success' : row.status === 2 ? 'info' : 'primary'"
|
||||
:type="row.status === 1 ? 'success' : row.status === 2 ? 'info' : row.status === 3 ? 'primary' : 'danger'"
|
||||
size="small"
|
||||
>
|
||||
{{ row.status_desc }}
|
||||
@@ -106,7 +136,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="180" fixed="right">
|
||||
<el-table-column label="操作" width="360" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-perms="['doctor.appointment/detail']"
|
||||
@@ -116,6 +146,30 @@
|
||||
>
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
v-perms="['tcm.diagnosis/edit']"
|
||||
type="primary"
|
||||
link
|
||||
@click="handleEditPatient(row)"
|
||||
>
|
||||
编辑患者
|
||||
</el-button>
|
||||
<el-button
|
||||
v-perms="['tcm.diagnosis/video-call']"
|
||||
type="success"
|
||||
link
|
||||
@click="handleVideoCall(row)"
|
||||
>
|
||||
1V1通话
|
||||
</el-button>
|
||||
<el-button
|
||||
v-perms="['tcm.diagnosis/video-group']"
|
||||
type="success"
|
||||
link
|
||||
@click="handleGroupVideoCall(row)"
|
||||
>
|
||||
群通话
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 1"
|
||||
v-perms="['doctor.appointment/cancel']"
|
||||
@@ -123,7 +177,7 @@
|
||||
link
|
||||
@click="handleCancel(row)"
|
||||
>
|
||||
取消
|
||||
取消挂号
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 1"
|
||||
@@ -132,8 +186,17 @@
|
||||
link
|
||||
@click="handleComplete(row)"
|
||||
>
|
||||
完成
|
||||
完成视频面诊
|
||||
</el-button>
|
||||
<!-- <el-button
|
||||
v-if="row.status === 1"
|
||||
v-perms="['doctor.appointment/prescription']"
|
||||
type="success"
|
||||
link
|
||||
@click="handleCreatePrescription(row)"
|
||||
>
|
||||
创建处方单
|
||||
</el-button> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -155,7 +218,7 @@
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag
|
||||
:type="detailData.status === 1 ? 'success' : detailData.status === 2 ? 'info' : 'primary'"
|
||||
:type="detailData.status === 1 ? 'success' : detailData.status === 2 ? 'info' : detailData.status === 3 ? 'primary' : 'danger'"
|
||||
size="small"
|
||||
>
|
||||
{{ detailData.status_desc }}
|
||||
@@ -190,6 +253,15 @@
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 编辑患者弹窗 -->
|
||||
<edit-popup ref="editRef" @success="getLists" />
|
||||
|
||||
<!-- 视频通话组件 -->
|
||||
<video-call ref="videoCallRef" />
|
||||
|
||||
<!-- 处方单抽屉 -->
|
||||
<prescription-drawer ref="prescriptionDrawerRef" @success="loadData" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -197,22 +269,101 @@
|
||||
import { usePaging } from '@/hooks/usePaging'
|
||||
import { appointmentLists, cancelAppointment, completeAppointment, appointmentDetail } from '@/api/doctor'
|
||||
import feedback from '@/utils/feedback'
|
||||
import EditPopup from '../diagnosis/edit.vue'
|
||||
import VideoCall from '@/components/video-call/index.vue'
|
||||
import PrescriptionDrawer from './components/prescription-drawer.vue'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const userInfo = computed(() => userStore.userInfo)
|
||||
|
||||
// 判断是否为管理员(非医生、非医助)
|
||||
const isAdmin = computed(() => {
|
||||
const roleId = userInfo.value.role_id
|
||||
// 如果role_id是数组,检查是否包含医生(1)或医助(2)
|
||||
if (Array.isArray(roleId)) {
|
||||
return !roleId.includes(1) && !roleId.includes(2)
|
||||
}
|
||||
// 如果role_id是单个值,检查是否不是医生或医助
|
||||
return roleId !== 1 && roleId !== 2
|
||||
})
|
||||
|
||||
const formData = reactive({
|
||||
patient_name: '',
|
||||
doctor_name: '',
|
||||
status: '',
|
||||
status: '' as string | number,
|
||||
start_date: '',
|
||||
end_date: ''
|
||||
})
|
||||
|
||||
const activeTab = ref('all')
|
||||
const statusCount = ref<Record<number, number>>({
|
||||
1: 0,
|
||||
2: 0,
|
||||
3: 0,
|
||||
4: 0
|
||||
})
|
||||
|
||||
const { pager, getLists, resetPage, resetParams } = usePaging({
|
||||
fetchFun: appointmentLists,
|
||||
params: formData
|
||||
})
|
||||
|
||||
// 获取各状态数量
|
||||
const getStatusCount = async () => {
|
||||
try {
|
||||
// 获取各状态的数量
|
||||
const promises = [1, 2, 3, 4].map(async (status) => {
|
||||
const res = await appointmentLists({
|
||||
...formData,
|
||||
status,
|
||||
page_no: 1,
|
||||
page_size: 1
|
||||
})
|
||||
return { status, count: res.count || 0 }
|
||||
})
|
||||
|
||||
const results = await Promise.all(promises)
|
||||
results.forEach(({ status, count }) => {
|
||||
statusCount.value[status] = count
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('获取状态数量失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 切换选项卡
|
||||
const handleTabChange = (tabName: string | number) => {
|
||||
if (tabName === 'all') {
|
||||
formData.status = ''
|
||||
} else {
|
||||
formData.status = Number(tabName)
|
||||
}
|
||||
resetPage()
|
||||
}
|
||||
|
||||
// 重写getLists,同时更新状态数量
|
||||
const loadData = async () => {
|
||||
await getLists()
|
||||
await getStatusCount()
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
resetPage()
|
||||
}
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
activeTab.value = 'all'
|
||||
resetParams()
|
||||
}
|
||||
|
||||
const detailVisible = ref(false)
|
||||
const detailData = ref<any>(null)
|
||||
const editRef = ref()
|
||||
const videoCallRef = ref()
|
||||
const prescriptionDrawerRef = ref()
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = async (row: any) => {
|
||||
@@ -231,7 +382,7 @@ const handleCancel = async (row: any) => {
|
||||
await feedback.confirm('确定要取消该挂号吗?')
|
||||
await cancelAppointment({ id: row.id })
|
||||
feedback.msgSuccess('取消成功')
|
||||
getLists()
|
||||
loadData()
|
||||
} catch (error) {
|
||||
// 用户取消操作
|
||||
}
|
||||
@@ -243,13 +394,78 @@ const handleComplete = async (row: any) => {
|
||||
await feedback.confirm('确认患者已就诊完成?')
|
||||
await completeAppointment({ id: row.id })
|
||||
feedback.msgSuccess('操作成功')
|
||||
getLists()
|
||||
loadData()
|
||||
} catch (error) {
|
||||
// 用户取消操作
|
||||
}
|
||||
}
|
||||
|
||||
getLists()
|
||||
// 编辑患者资料
|
||||
const handleEditPatient = (row: any) => {
|
||||
console.log()
|
||||
if (!row.patient_id) {
|
||||
feedback.msgWarning('该预约没有关联诊单信息')
|
||||
return
|
||||
}
|
||||
editRef.value?.open('edit', row.patient_id)
|
||||
}
|
||||
|
||||
// 1v1视频通话
|
||||
const handleVideoCall = (row: any) => {
|
||||
if (!row.patient_id) {
|
||||
feedback.msgWarning('患者信息不完整')
|
||||
return
|
||||
}
|
||||
|
||||
videoCallRef.value?.open({
|
||||
diagnosisId: row.diagnosis_id || row.id,
|
||||
patientId: row.patient_id,
|
||||
patientName: row.patient_name,
|
||||
userId: `patient_${row.patient_id}`,
|
||||
isGroup: false
|
||||
})
|
||||
}
|
||||
|
||||
// 群组视频通话
|
||||
const handleGroupVideoCall = (row: any) => {
|
||||
if (!row.patient_id) {
|
||||
feedback.msgWarning('患者信息不完整')
|
||||
return
|
||||
}
|
||||
|
||||
if (!row.doctor_id) {
|
||||
feedback.msgWarning('该预约没有医生信息,无法发起群组通话')
|
||||
return
|
||||
}
|
||||
|
||||
// 群组通话参与者:患者和医生
|
||||
const userIds = [
|
||||
`patient_${row.patient_id}`,
|
||||
`doctor_${row.doctor_id}`
|
||||
]
|
||||
|
||||
videoCallRef.value?.open({
|
||||
diagnosisId: row.diagnosis_id || row.id,
|
||||
patientId: row.patient_id,
|
||||
patientName: row.patient_name,
|
||||
doctorId: row.doctor_id,
|
||||
userIds: userIds,
|
||||
isGroup: true
|
||||
})
|
||||
}
|
||||
|
||||
// 创建处方单
|
||||
const handleCreatePrescription = async (row: any) => {
|
||||
try {
|
||||
// 获取详细信息
|
||||
const detail = await appointmentDetail({ id: row.id })
|
||||
prescriptionDrawerRef.value?.open(detail)
|
||||
} catch (error) {
|
||||
feedback.msgError('获取患者信息失败')
|
||||
}
|
||||
}
|
||||
|
||||
loadData()
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
<el-drawer
|
||||
v-model="visible"
|
||||
:title="drawerTitle"
|
||||
size="60%"
|
||||
size="70%"
|
||||
:before-close="handleClose"
|
||||
:z-index="1500"
|
||||
:modal="true"
|
||||
class="diagnosis-drawer"
|
||||
>
|
||||
<el-tabs v-model="activeTab" class="px-4">
|
||||
<el-tabs v-model="activeTab" class="diagnosis-tabs">
|
||||
<!-- 基本信息标签页 -->
|
||||
<el-tab-pane label="基本信息" name="basic">
|
||||
<el-form
|
||||
@@ -133,7 +134,25 @@
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="糖尿病期数" prop="diabetes_type">
|
||||
<el-select
|
||||
v-model="formData.diabetes_type"
|
||||
placeholder="请选择糖尿病期数"
|
||||
class="w-full"
|
||||
:popper-options="{ strategy: 'fixed' }"
|
||||
popper-class="high-z-index"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in diabetesTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.name + (item.remark ? ' (' + item.remark + ')' : '')"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio :label="1">启用</el-radio>
|
||||
@@ -148,7 +167,7 @@
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="口腔感觉">
|
||||
<el-form-item label="口腔感觉" class="compact-form-item">
|
||||
<el-radio-group v-model="formData.appetite">
|
||||
<el-radio v-for="item in appetiteOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
@@ -157,7 +176,7 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="每日饮水量">
|
||||
<el-form-item label="每日饮水量" class="compact-form-item">
|
||||
<el-radio-group v-model="formData.water_intake">
|
||||
<el-radio v-for="item in waterIntakeOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
@@ -167,7 +186,28 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item label="饮食情况">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="体重变化" class="compact-form-item">
|
||||
<el-radio-group v-model="formData.weight_change">
|
||||
<el-radio v-for="item in weightChangeOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="脂肪肝程度" class="compact-form-item">
|
||||
<el-radio-group v-model="formData.fatty_liver_degree">
|
||||
<el-radio v-for="item in fattyLiverDegreeOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item label="饮食情况" class="checkbox-form-item">
|
||||
<el-checkbox-group v-model="formData.diet_condition">
|
||||
<el-checkbox v-for="item in dietConditionOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
@@ -175,15 +215,7 @@
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="体重变化">
|
||||
<el-radio-group v-model="formData.weight_change">
|
||||
<el-radio v-for="item in weightChangeOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="肢体感觉">
|
||||
<el-form-item label="肢体感觉" class="checkbox-form-item">
|
||||
<el-checkbox-group v-model="formData.body_feeling">
|
||||
<el-checkbox v-for="item in bodyFeelingOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
@@ -191,7 +223,7 @@
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="睡眠情况">
|
||||
<el-form-item label="睡眠情况" class="checkbox-form-item">
|
||||
<el-checkbox-group v-model="formData.sleep_condition">
|
||||
<el-checkbox v-for="item in sleepConditionOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
@@ -199,7 +231,7 @@
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="眼睛情况">
|
||||
<el-form-item label="眼睛情况" class="checkbox-form-item">
|
||||
<el-checkbox-group v-model="formData.eye_condition">
|
||||
<el-checkbox v-for="item in eyeConditionOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
@@ -207,7 +239,7 @@
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="头部感觉">
|
||||
<el-form-item label="头部感觉" class="checkbox-form-item">
|
||||
<el-checkbox-group v-model="formData.head_feeling">
|
||||
<el-checkbox v-for="item in headFeelingOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
@@ -215,7 +247,7 @@
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="出汗情况">
|
||||
<el-form-item label="出汗情况" class="checkbox-form-item">
|
||||
<el-checkbox-group v-model="formData.sweat_condition">
|
||||
<el-checkbox v-for="item in sweatConditionOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
@@ -223,7 +255,7 @@
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="皮肤情况">
|
||||
<el-form-item label="皮肤情况" class="checkbox-form-item">
|
||||
<el-checkbox-group v-model="formData.skin_condition">
|
||||
<el-checkbox v-for="item in skinConditionOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
@@ -231,7 +263,7 @@
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="小便情况">
|
||||
<el-form-item label="小便情况" class="checkbox-form-item">
|
||||
<el-checkbox-group v-model="formData.urine_condition">
|
||||
<el-checkbox v-for="item in urineConditionOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
@@ -239,7 +271,7 @@
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="大便情况">
|
||||
<el-form-item label="大便情况" class="checkbox-form-item">
|
||||
<el-checkbox-group v-model="formData.stool_condition">
|
||||
<el-checkbox v-for="item in stoolConditionOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
@@ -247,7 +279,7 @@
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="腰肾情况">
|
||||
<el-form-item label="腰肾情况" class="checkbox-form-item">
|
||||
<el-checkbox-group v-model="formData.kidney_condition">
|
||||
<el-checkbox v-for="item in kidneyConditionOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
@@ -255,14 +287,6 @@
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="脂肪肝程度">
|
||||
<el-radio-group v-model="formData.fatty_liver_degree">
|
||||
<el-radio v-for="item in fattyLiverDegreeOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 既往史 -->
|
||||
<el-divider content-position="left">既往史</el-divider>
|
||||
|
||||
@@ -469,6 +493,7 @@ const formData = ref({
|
||||
diagnosis_date: '',
|
||||
diagnosis_type: '',
|
||||
syndrome_type: '',
|
||||
diabetes_type: '',
|
||||
// 现病史字段
|
||||
appetite: '',
|
||||
water_intake: '',
|
||||
@@ -535,12 +560,14 @@ const formRules = {
|
||||
age: [{ required: true, message: '请输入年龄', trigger: 'blur' }],
|
||||
diagnosis_date: [{ required: true, message: '请选择诊断日期', trigger: 'change' }],
|
||||
diagnosis_type: [{ required: true, message: '请选择诊断类型', trigger: 'change' }],
|
||||
syndrome_type: [{ required: true, message: '请选择证型', trigger: 'change' }]
|
||||
syndrome_type: [{ required: true, message: '请选择证型', trigger: 'change' }],
|
||||
diabetes_type: [{ required: true, message: '请选择糖尿病期数', trigger: 'change' }]
|
||||
}
|
||||
|
||||
// 获取字典选项
|
||||
const diagnosisTypeOptions = ref<any[]>([])
|
||||
const syndromeTypeOptions = ref<any[]>([])
|
||||
const diabetesTypeOptions = ref<any[]>([])
|
||||
const pastHistoryOptions = ref<any[]>([])
|
||||
// 现病史字典选项
|
||||
const appetiteOptions = ref<any[]>([])
|
||||
@@ -562,7 +589,8 @@ const getDictOptions = async () => {
|
||||
try {
|
||||
const [
|
||||
diagnosisType,
|
||||
syndromeType,
|
||||
syndromeType,
|
||||
diabetesType,
|
||||
pastHistory,
|
||||
appetite,
|
||||
waterIntake,
|
||||
@@ -581,6 +609,7 @@ const getDictOptions = async () => {
|
||||
] = await Promise.all([
|
||||
getDictData({ type: 'diagnosis_type' }),
|
||||
getDictData({ type: 'syndrome_type' }),
|
||||
getDictData({ type: 'diabetes_type' }),
|
||||
getDictData({ type: 'past_history' }),
|
||||
getDictData({ type: 'appetite' }),
|
||||
getDictData({ type: 'water_intake' }),
|
||||
@@ -600,6 +629,7 @@ const getDictOptions = async () => {
|
||||
|
||||
diagnosisTypeOptions.value = diagnosisType?.diagnosis_type || []
|
||||
syndromeTypeOptions.value = syndromeType?.syndrome_type || []
|
||||
diabetesTypeOptions.value = diabetesType?.diabetes_type || []
|
||||
pastHistoryOptions.value = pastHistory?.past_history || []
|
||||
appetiteOptions.value = appetite?.appetite || []
|
||||
waterIntakeOptions.value = waterIntake?.water_intake || []
|
||||
@@ -720,6 +750,7 @@ const handleClose = () => {
|
||||
diagnosis_date: '',
|
||||
diagnosis_type: '',
|
||||
syndrome_type: '',
|
||||
diabetes_type: '',
|
||||
appetite: '',
|
||||
water_intake: '',
|
||||
diet_condition: [],
|
||||
@@ -761,24 +792,104 @@ defineExpose({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.edit-drawer {
|
||||
:deep(.el-checkbox-group) {
|
||||
.el-checkbox {
|
||||
margin-right: 20px;
|
||||
margin-bottom: 10px;
|
||||
:deep(.el-form) {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
:deep(.el-divider) {
|
||||
margin: 24px 0 20px;
|
||||
|
||||
.el-divider__text {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
background: #f5f7fa;
|
||||
padding: 0 16px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
// 紧凑型表单项(单选框)
|
||||
.compact-form-item {
|
||||
:deep(.el-radio-group) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
|
||||
.el-radio {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 复选框表单项
|
||||
.checkbox-form-item {
|
||||
:deep(.el-checkbox-group) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px 16px;
|
||||
|
||||
.el-checkbox {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通用单选框样式
|
||||
:deep(.el-radio-group) {
|
||||
.el-radio {
|
||||
margin-right: 20px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 16px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通用复选框样式
|
||||
:deep(.el-checkbox-group) {
|
||||
.el-checkbox {
|
||||
margin-right: 16px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-tips {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 5px;
|
||||
color: #909399;
|
||||
margin-top: 4px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
// 输入框样式优化
|
||||
:deep(.el-input__inner),
|
||||
:deep(.el-textarea__inner) {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
// 选择器样式优化
|
||||
:deep(.el-select) {
|
||||
.el-input__inner {
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
// 日期选择器样式优化
|
||||
:deep(.el-date-editor) {
|
||||
.el-input__inner {
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
REM 医生字段安装脚本 (Windows版本)
|
||||
REM 用法: install_doctor_fields.bat
|
||||
|
||||
echo ==========================================
|
||||
echo 医生字段安装脚本
|
||||
echo ==========================================
|
||||
echo.
|
||||
|
||||
REM 数据库配置
|
||||
set DB_HOST=localhost
|
||||
set DB_PORT=3306
|
||||
set DB_NAME=zyt
|
||||
set DB_USER=root
|
||||
|
||||
REM 提示输入数据库密码
|
||||
set /p DB_PASS=请输入数据库密码:
|
||||
echo.
|
||||
|
||||
REM 检查MySQL是否可用
|
||||
echo 检查MySQL连接...
|
||||
mysql -h%DB_HOST% -P%DB_PORT% -u%DB_USER% -p%DB_PASS% -e "SELECT 1;" >nul 2>&1
|
||||
|
||||
if errorlevel 1 (
|
||||
echo [错误] 无法连接到MySQL数据库
|
||||
echo 请检查数据库配置和密码是否正确
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [成功] 数据库连接成功
|
||||
echo.
|
||||
|
||||
REM 备份数据库
|
||||
set BACKUP_FILE=zyt_backup_%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%.sql
|
||||
set BACKUP_FILE=%BACKUP_FILE: =0%
|
||||
echo 正在备份数据库到: %BACKUP_FILE%
|
||||
mysqldump -h%DB_HOST% -P%DB_PORT% -u%DB_USER% -p%DB_PASS% %DB_NAME% > %BACKUP_FILE% 2>nul
|
||||
|
||||
if errorlevel 1 (
|
||||
echo [警告] 数据库备份失败
|
||||
set /p continue=是否继续安装? (y/n):
|
||||
if /i not "!continue!"=="y" exit /b 1
|
||||
) else (
|
||||
echo [成功] 数据库备份成功
|
||||
)
|
||||
echo.
|
||||
|
||||
REM 执行迁移脚本
|
||||
echo 正在执行数据库迁移...
|
||||
mysql -h%DB_HOST% -P%DB_PORT% -u%DB_USER% -p%DB_PASS% %DB_NAME% < server\database\migrations\add_doctor_fields_to_admin.sql 2>&1
|
||||
|
||||
if errorlevel 1 (
|
||||
echo [错误] 数据库迁移失败
|
||||
echo 请检查错误信息,可能字段已经存在
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [成功] 数据库迁移成功
|
||||
echo.
|
||||
|
||||
REM 验证安装
|
||||
echo 验证字段是否添加成功...
|
||||
mysql -h%DB_HOST% -P%DB_PORT% -u%DB_USER% -p%DB_PASS% %DB_NAME% -e "SHOW COLUMNS FROM zyt_admin LIKE 'gender';" 2>nul | find "gender" >nul
|
||||
|
||||
if errorlevel 1 (
|
||||
echo [错误] 字段验证失败
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [成功] 字段验证成功
|
||||
echo.
|
||||
|
||||
echo ==========================================
|
||||
echo 安装完成!
|
||||
echo ==========================================
|
||||
echo.
|
||||
echo 新增字段列表:
|
||||
echo - gender (性别)
|
||||
echo - age (年龄)
|
||||
echo - phone (手机号)
|
||||
echo - title (职称)
|
||||
echo - department (所属科室)
|
||||
echo - specialty (擅长领域)
|
||||
echo - education (教育背景)
|
||||
echo - experience (工作经历)
|
||||
echo - honors (荣誉资质)
|
||||
echo.
|
||||
echo 备份文件: %BACKUP_FILE%
|
||||
echo.
|
||||
echo 现在可以使用医生管理功能了!
|
||||
echo.
|
||||
pause
|
||||
@@ -0,0 +1,100 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 医生字段安装脚本
|
||||
# 用法: ./install_doctor_fields.sh
|
||||
|
||||
echo "=========================================="
|
||||
echo "医生字段安装脚本"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 数据库配置
|
||||
DB_HOST="localhost"
|
||||
DB_PORT="3306"
|
||||
DB_NAME="zyt"
|
||||
DB_USER="root"
|
||||
|
||||
# 提示输入数据库密码
|
||||
echo -e "${YELLOW}请输入数据库密码:${NC}"
|
||||
read -s DB_PASS
|
||||
echo ""
|
||||
|
||||
# 检查MySQL是否可用
|
||||
echo "检查MySQL连接..."
|
||||
mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -e "SELECT 1;" > /dev/null 2>&1
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}错误: 无法连接到MySQL数据库${NC}"
|
||||
echo "请检查数据库配置和密码是否正确"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✓ 数据库连接成功${NC}"
|
||||
echo ""
|
||||
|
||||
# 备份数据库
|
||||
BACKUP_FILE="zyt_backup_$(date +%Y%m%d_%H%M%S).sql"
|
||||
echo "正在备份数据库到: $BACKUP_FILE"
|
||||
mysqldump -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" > "$BACKUP_FILE" 2>/dev/null
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN}✓ 数据库备份成功${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ 数据库备份失败${NC}"
|
||||
echo "是否继续安装? (y/n)"
|
||||
read -r response
|
||||
if [[ ! "$response" =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 执行迁移脚本
|
||||
echo "正在执行数据库迁移..."
|
||||
mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < server/database/migrations/add_doctor_fields_to_admin.sql 2>&1
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN}✓ 数据库迁移成功${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ 数据库迁移失败${NC}"
|
||||
echo "请检查错误信息,可能字段已经存在"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 验证安装
|
||||
echo "验证字段是否添加成功..."
|
||||
RESULT=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SHOW COLUMNS FROM zyt_admin LIKE 'gender';" 2>/dev/null | grep -c "gender")
|
||||
|
||||
if [ "$RESULT" -eq 1 ]; then
|
||||
echo -e "${GREEN}✓ 字段验证成功${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ 字段验证失败${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=========================================="
|
||||
echo -e "${GREEN}安装完成!${NC}"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "新增字段列表:"
|
||||
echo " - gender (性别)"
|
||||
echo " - age (年龄)"
|
||||
echo " - phone (手机号)"
|
||||
echo " - title (职称)"
|
||||
echo " - department (所属科室)"
|
||||
echo " - specialty (擅长领域)"
|
||||
echo " - education (教育背景)"
|
||||
echo " - experience (工作经历)"
|
||||
echo " - honors (荣誉资质)"
|
||||
echo ""
|
||||
echo "备份文件: $BACKUP_FILE"
|
||||
echo ""
|
||||
echo "现在可以使用医生管理功能了!"
|
||||
+5
-1
@@ -6,4 +6,8 @@ admin Zyt123456
|
||||
外网面板地址: https://139.196.37.14:30296/2a7ef99b
|
||||
内网面板地址: https://172.27.15.98:30296/2a7ef99b
|
||||
username: i6rjat7k
|
||||
password: 0ccb31ec
|
||||
password: 0ccb31ec
|
||||
|
||||
http://%E6%88%91%E6%8A%8A%E7%BB%84%E4%BB%B6%E6%94%B9%E6%88%90%E8%BF%99%E4%B8%AA%E4%BA%86@tencentcloud/call-uikit-vue%22:%20%22%5E4.0.12%22,
|
||||
|
||||
我把视频组件从"@tencentcloud/call-uikit-vue": "^4.0.12", 改成了最新版,现在需要你更新所有视频通话组件逻辑代码
|
||||
@@ -135,7 +135,9 @@ class AdminLists extends BaseAdminDataLists implements ListsExtendInterface, Lis
|
||||
{
|
||||
$field = [
|
||||
'id', 'name', 'account', 'create_time', 'disable', 'root',
|
||||
'login_time', 'login_ip', 'multipoint_login', 'avatar'
|
||||
'login_time', 'login_ip', 'multipoint_login', 'avatar',
|
||||
'gender', 'age', 'phone', 'title', 'department',
|
||||
'specialty', 'education', 'experience', 'honors'
|
||||
];
|
||||
|
||||
$adminLists = Admin::field($field)
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace app\adminapi\lists\doctor;
|
||||
|
||||
use app\adminapi\lists\BaseAdminDataLists;
|
||||
use app\common\model\doctor\Appointment;
|
||||
use app\common\model\auth\AdminRole;
|
||||
use app\common\lists\ListsSearchInterface;
|
||||
|
||||
/**
|
||||
@@ -19,15 +20,18 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
|
||||
*/
|
||||
public function setSearch(): array
|
||||
{
|
||||
$allowSearch = [
|
||||
'=' => ['a.patient_id', 'a.doctor_id', 'a.status', 'a.appointment_date'],
|
||||
];
|
||||
|
||||
// 处理日期范围搜索
|
||||
if (!empty($this->params['start_date']) && !empty($this->params['end_date'])) {
|
||||
$this->searchWhere[] = ['a.appointment_date', 'between', [$this->params['start_date'], $this->params['end_date']]];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 获取列表
|
||||
* @return array
|
||||
*/
|
||||
public function lists(): array
|
||||
{
|
||||
// 获取当前管理员的角色ID
|
||||
$roleIds = AdminRole::where('admin_id', $this->adminId)->column('role_id');
|
||||
|
||||
// 处理患者姓名搜索
|
||||
if (!empty($this->params['patient_name'])) {
|
||||
$this->searchWhere[] = ['u.patient_name', 'like', '%' . $this->params['patient_name'] . '%'];
|
||||
@@ -38,22 +42,41 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
|
||||
$this->searchWhere[] = ['ad.name', 'like', '%' . $this->params['doctor_name'] . '%'];
|
||||
}
|
||||
|
||||
return $allowSearch;
|
||||
}
|
||||
// 处理状态搜索
|
||||
if (isset($this->params['status']) && $this->params['status'] !== '') {
|
||||
$this->searchWhere[] = ['a.status', '=', $this->params['status']];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 获取列表
|
||||
* @return array
|
||||
*/
|
||||
public function lists(): array
|
||||
{
|
||||
|
||||
$lists = Appointment::alias('a')
|
||||
// 处理日期范围搜索
|
||||
if (!empty($this->params['start_date']) && !empty($this->params['end_date'])) {
|
||||
$this->searchWhere[] = ['a.appointment_date', 'between', [$this->params['start_date'], $this->params['end_date']]];
|
||||
} elseif (!empty($this->params['start_date'])) {
|
||||
$this->searchWhere[] = ['a.appointment_date', '>=', $this->params['start_date']];
|
||||
} elseif (!empty($this->params['end_date'])) {
|
||||
$this->searchWhere[] = ['a.appointment_date', '<=', $this->params['end_date']];
|
||||
}
|
||||
|
||||
// 构建查询
|
||||
$query = Appointment::alias('a')
|
||||
->leftJoin('tcm_diagnosis u', 'a.patient_id = u.id')
|
||||
->leftJoin('admin ad', 'a.doctor_id = ad.id')
|
||||
->field('a.*, u.patient_name as patient_name, u.phone as patient_phone, ad.name as doctor_name')
|
||||
->where($this->searchWhere)
|
||||
->order('a.id', 'desc')
|
||||
->field('a.*, u.patient_name as patient_name, u.phone as patient_phone, ad.name as doctor_name, u.id as diagnosis_id')
|
||||
->where($this->searchWhere);
|
||||
|
||||
// 如果是医生角色(role_id=1),只显示挂自己号的预约
|
||||
if (in_array(1, $roleIds)) {
|
||||
$query->where('a.doctor_id', $this->adminId);
|
||||
}
|
||||
|
||||
// 如果是医助角色(role_id=2),只显示自己添加的患者的预约
|
||||
if (in_array(2, $roleIds)) {
|
||||
$query->where('u.assistant_id', $this->adminId);
|
||||
}
|
||||
|
||||
$lists = $query
|
||||
->order('a.status', 'asc')
|
||||
->order('a.appointment_date', 'asc')
|
||||
->order('a.appointment_time', 'asc')
|
||||
->limit($this->limitOffset, $this->limitLength)
|
||||
->select()
|
||||
->toArray();
|
||||
@@ -64,6 +87,7 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
|
||||
1 => '已预约',
|
||||
2 => '已取消',
|
||||
3 => '已完成',
|
||||
4 => '已过号',
|
||||
];
|
||||
$item['status_desc'] = $statusMap[$item['status']] ?? '未知';
|
||||
|
||||
@@ -92,10 +116,48 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
// 获取当前管理员的角色ID
|
||||
$roleIds = AdminRole::where('admin_id', $this->adminId)->column('role_id');
|
||||
|
||||
// 处理患者姓名搜索
|
||||
if (!empty($this->params['patient_name'])) {
|
||||
$this->searchWhere[] = ['u.patient_name', 'like', '%' . $this->params['patient_name'] . '%'];
|
||||
}
|
||||
|
||||
// 处理医生姓名搜索
|
||||
if (!empty($this->params['doctor_name'])) {
|
||||
$this->searchWhere[] = ['ad.name', 'like', '%' . $this->params['doctor_name'] . '%'];
|
||||
}
|
||||
|
||||
// 处理状态搜索
|
||||
if (isset($this->params['status']) && $this->params['status'] !== '') {
|
||||
$this->searchWhere[] = ['a.status', '=', $this->params['status']];
|
||||
}
|
||||
|
||||
// 处理日期范围搜索
|
||||
if (!empty($this->params['start_date']) && !empty($this->params['end_date'])) {
|
||||
$this->searchWhere[] = ['a.appointment_date', 'between', [$this->params['start_date'], $this->params['end_date']]];
|
||||
} elseif (!empty($this->params['start_date'])) {
|
||||
$this->searchWhere[] = ['a.appointment_date', '>=', $this->params['start_date']];
|
||||
} elseif (!empty($this->params['end_date'])) {
|
||||
$this->searchWhere[] = ['a.appointment_date', '<=', $this->params['end_date']];
|
||||
}
|
||||
|
||||
// 构建查询
|
||||
$query = Appointment::alias('a')
|
||||
->leftJoin('tcm_diagnosis u', 'a.patient_id = u.id')
|
||||
->leftJoin('admin ad', 'a.doctor_id = ad.id')
|
||||
->where($this->searchWhere);
|
||||
|
||||
// 如果是医生角色(role_id=1),只显示挂自己号的预约
|
||||
if (in_array(1, $roleIds)) {
|
||||
$query->where('a.doctor_id', $this->adminId);
|
||||
}
|
||||
|
||||
// 如果是医助角色(role_id=2),只显示自己添加的患者的预约
|
||||
if (in_array(2, $roleIds)) {
|
||||
$query->where('u.assistant_id', $this->adminId);
|
||||
}
|
||||
|
||||
return $query->count();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace app\adminapi\lists\tcm;
|
||||
|
||||
use app\adminapi\lists\BaseAdminDataLists;
|
||||
use app\common\model\tcm\Diagnosis;
|
||||
use app\common\model\auth\AdminRole;
|
||||
use app\common\lists\ListsSearchInterface;
|
||||
|
||||
/**
|
||||
@@ -47,7 +48,18 @@ class DiagnosisLists extends BaseAdminDataLists implements ListsSearchInterface
|
||||
*/
|
||||
public function lists(): array
|
||||
{
|
||||
$lists = Diagnosis::where($this->searchWhere)
|
||||
// 获取当前管理员的角色ID
|
||||
$roleIds = AdminRole::where('admin_id', $this->adminId)->column('role_id');
|
||||
|
||||
// 构建查询
|
||||
$query = Diagnosis::where($this->searchWhere);
|
||||
|
||||
// 如果是医助角色(role_id=2),只显示自己添加的患者
|
||||
if (in_array(2, $roleIds)) {
|
||||
$query->where('assistant_id', $this->adminId);
|
||||
}
|
||||
|
||||
$lists = $query
|
||||
->field(['id', 'patient_id', 'patient_name', 'id_card', 'phone', 'gender', 'age', 'diagnosis_date', 'diagnosis_type', 'syndrome_type', 'assistant_id', 'status', 'create_time', 'update_time'])
|
||||
->append(['gender_desc', 'status_desc', 'diagnosis_date_text'])
|
||||
->order(['id' => 'desc'])
|
||||
@@ -64,6 +76,17 @@ class DiagnosisLists extends BaseAdminDataLists implements ListsSearchInterface
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return Diagnosis::where($this->searchWhere)->count();
|
||||
// 获取当前管理员的角色ID
|
||||
$roleIds = AdminRole::where('admin_id', $this->adminId)->column('role_id');
|
||||
|
||||
// 构建查询
|
||||
$query = Diagnosis::where($this->searchWhere);
|
||||
|
||||
// 如果是医助角色(role_id=2),只显示自己添加的患者
|
||||
if (in_array(2, $roleIds)) {
|
||||
$query->where('assistant_id', $this->adminId);
|
||||
}
|
||||
|
||||
return $query->count();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,16 @@ class AdminLogic extends BaseLogic
|
||||
'create_time' => time(),
|
||||
'disable' => $params['disable'],
|
||||
'multipoint_login' => $params['multipoint_login'],
|
||||
// 新增字段
|
||||
'gender' => $params['gender'] ?? 1,
|
||||
'age' => $params['age'] ?? null,
|
||||
'phone' => $params['phone'] ?? null,
|
||||
'title' => $params['title'] ?? null,
|
||||
'department' => $params['department'] ?? null,
|
||||
'specialty' => $params['specialty'] ?? null,
|
||||
'education' => $params['education'] ?? null,
|
||||
'experience' => $params['experience'] ?? null,
|
||||
'honors' => $params['honors'] ?? null,
|
||||
]);
|
||||
|
||||
// 角色
|
||||
@@ -99,7 +109,17 @@ class AdminLogic extends BaseLogic
|
||||
'name' => $params['name'],
|
||||
'account' => $params['account'],
|
||||
'disable' => $params['disable'],
|
||||
'multipoint_login' => $params['multipoint_login']
|
||||
'multipoint_login' => $params['multipoint_login'],
|
||||
// 新增字段
|
||||
'gender' => $params['gender'] ?? 1,
|
||||
'age' => $params['age'] ?? null,
|
||||
'phone' => $params['phone'] ?? null,
|
||||
'title' => $params['title'] ?? null,
|
||||
'department' => $params['department'] ?? null,
|
||||
'specialty' => $params['specialty'] ?? null,
|
||||
'education' => $params['education'] ?? null,
|
||||
'experience' => $params['experience'] ?? null,
|
||||
'honors' => $params['honors'] ?? null,
|
||||
];
|
||||
|
||||
// 头像
|
||||
@@ -232,6 +252,8 @@ class AdminLogic extends BaseLogic
|
||||
$admin = Admin::field([
|
||||
'id', 'account', 'name', 'disable', 'root',
|
||||
'multipoint_login', 'avatar',
|
||||
'gender', 'age', 'phone', 'title', 'department',
|
||||
'specialty', 'education', 'experience', 'honors'
|
||||
])->findOrEmpty($params['id'])->toArray();
|
||||
|
||||
if ($action == 'detail') {
|
||||
|
||||
@@ -290,9 +290,9 @@ class AppointmentLogic extends BaseLogic
|
||||
public static function detail(array $params)
|
||||
{
|
||||
$appointment = Appointment::alias('a')
|
||||
->leftJoin('la_user u', 'a.patient_id = u.id')
|
||||
->leftJoin('la_admin ad', 'a.doctor_id = ad.id')
|
||||
->field('a.*, u.nickname as patient_name, u.mobile as patient_phone, ad.name as doctor_name')
|
||||
->leftJoin('zyt_tcm_diagnosis u', 'a.patient_id = u.id')
|
||||
->leftJoin('zyt_admin ad', 'a.doctor_id = ad.id')
|
||||
->field('a.*, u.patient_name as patient_name, u.phone as patient_phone, ad.name as doctor_name')
|
||||
->where('a.id', $params['id'])
|
||||
->findOrEmpty()
|
||||
->toArray();
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
-- 为管理员表添加医生相关字段
|
||||
-- 执行时间:请根据实际情况修改
|
||||
|
||||
-- 添加基本信息字段
|
||||
ALTER TABLE `zyt_admin`
|
||||
ADD COLUMN `gender` tinyint(1) DEFAULT 1 COMMENT '性别:1=男,2=女' AFTER `name`,
|
||||
ADD COLUMN `age` int(3) DEFAULT NULL COMMENT '年龄' AFTER `gender`,
|
||||
ADD COLUMN `phone` varchar(20) DEFAULT NULL COMMENT '手机号' AFTER `age`;
|
||||
|
||||
-- 添加专业信息字段
|
||||
ALTER TABLE `zyt_admin`
|
||||
ADD COLUMN `title` varchar(50) DEFAULT NULL COMMENT '职称' AFTER `phone`,
|
||||
ADD COLUMN `department` varchar(100) DEFAULT NULL COMMENT '所属科室' AFTER `title`,
|
||||
ADD COLUMN `specialty` text DEFAULT NULL COMMENT '擅长领域' AFTER `department`;
|
||||
|
||||
-- 添加履历信息字段
|
||||
ALTER TABLE `zyt_admin`
|
||||
ADD COLUMN `education` text DEFAULT NULL COMMENT '教育背景' AFTER `specialty`,
|
||||
ADD COLUMN `experience` text DEFAULT NULL COMMENT '工作经历' AFTER `education`,
|
||||
ADD COLUMN `honors` text DEFAULT NULL COMMENT '荣誉资质' AFTER `experience`;
|
||||
|
||||
-- 添加索引
|
||||
ALTER TABLE `zyt_admin` ADD INDEX `idx_phone` (`phone`);
|
||||
ALTER TABLE `zyt_admin` ADD INDEX `idx_gender` (`gender`);
|
||||
@@ -0,0 +1,18 @@
|
||||
-- 回滚:删除管理员表的医生相关字段
|
||||
-- 警告:执行此脚本将删除这些字段的所有数据
|
||||
|
||||
-- 删除索引
|
||||
ALTER TABLE `zyt_admin` DROP INDEX `idx_phone`;
|
||||
ALTER TABLE `zyt_admin` DROP INDEX `idx_gender`;
|
||||
|
||||
-- 删除字段
|
||||
ALTER TABLE `zyt_admin`
|
||||
DROP COLUMN `gender`,
|
||||
DROP COLUMN `age`,
|
||||
DROP COLUMN `phone`,
|
||||
DROP COLUMN `title`,
|
||||
DROP COLUMN `department`,
|
||||
DROP COLUMN `specialty`,
|
||||
DROP COLUMN `education`,
|
||||
DROP COLUMN `experience`,
|
||||
DROP COLUMN `honors`;
|
||||
Reference in New Issue
Block a user