Files
his/openhis-ui-vue3/src/views/doctorstation/doctorphrase/index.vue

587 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="doctor-phrase-container">
<!-- 搜索栏 -->
<div class="search-bar">
<el-select v-model="searchScope" placeholder="范围" style="width: 120px;">
<el-option label="个人" :value="1"></el-option>
<el-option label="科室" :value="2"></el-option>
<el-option label="全院" :value="3"></el-option>
</el-select>
<el-input
v-model="searchKeyword"
placeholder="请输入名称"
style="width: 240px; margin-left: 10px;"
@keyup.enter="handleSearch"
></el-input>
<el-button style="margin-left: 10px;" @click="handleSearch"><el-icon><Search /></el-icon> 查询</el-button>
<el-button style="margin-left: 10px;" @click="handleReset"><el-icon><Refresh /></el-icon> 重置</el-button>
<el-button type="primary" style="margin-left: 10px;" @click="showAddDialog"><el-icon><Plus /></el-icon> 增加</el-button>
</div>
<!-- 表格 -->
<el-table :data="tableData" style="width: 100%; margin-top: 20px;">
<el-table-column prop="sortNo" label="排序号" width="200">
<template #default="scope">
<el-input-number
v-if="editingId === scope.row.id"
v-model="editForm.sortNo"
:min="1"
:step="1"
style="width: 100%"
/>
<span v-else>{{ scope.row.sortNo }}</span>
</template>
</el-table-column>
<el-table-column prop="phraseName" label="名称" width="250">
<template #default="scope">
<el-input
v-if="editingId === scope.row.id"
v-model="editForm.phraseName"
placeholder="请输入名称(不超过50字)"
maxlength="50"
show-word-limit
style="width: 100%"
/>
<span v-else>{{ scope.row.phraseName }}</span>
</template>
</el-table-column>
<el-table-column prop="phraseContent" label="内容">
<template #default="scope">
<el-input
v-if="editingId === scope.row.id"
v-model="editForm.phraseContent"
placeholder="请输入内容"
type="textarea"
:rows="3"
style="width: 100%"
/>
<span v-else>{{ scope.row.phraseContent }}</span>
</template>
</el-table-column>
<el-table-column label="范围" width="250">
<template #default="scope">
<el-select
v-if="editingId === scope.row.id"
v-model="editForm.phraseType"
placeholder="请选择范围"
style="width: 100%"
>
<el-option label="个人" :value="1"></el-option>
<el-option label="科室" :value="2"></el-option>
<el-option label="全院" :value="3"></el-option>
</el-select>
<span v-else>{{ getScopeName(scope.row.phraseType) }}</span>
</template>
</el-table-column>
<el-table-column label="业务分类" width="200">
<template #default="scope">
<el-select
v-if="editingId === scope.row.id"
v-model="editForm.phraseCategory"
placeholder="请选择业务分类"
style="width: 100%"
>
<el-option label="病愈" value="12"></el-option>
<el-option
v-for="item in businessclassification"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
<span v-else>{{ getBusinessTypeName(scope.row.phraseCategory) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="scope">
<!-- 编辑状态 -->
<template v-if="editingId === scope.row.id">
<el-button
type="success"
size="small"
@click="handleSave"
>
<el-icon><Check /></el-icon> 保存
</el-button>
<el-button
type="warning"
size="small"
style="margin-left: 5px;"
@click="handleCancel"
>
<el-icon><Close /></el-icon> 取消
</el-button>
</template>
<!-- 非编辑状态 -->
<template v-else>
<el-button
type="primary"
size="small"
@click="handleEdit(scope.row)"
>
编辑
</el-button>
<el-button
type="danger"
size="small"
style="margin-left: 5px;"
@click="handleDelete(scope.row)"
>
删除
</el-button>
</template>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[15, 30, 50]"
:page-size="pageSize"
layout="total, prev, pager, next, jumper, sizes"
:total="total"
></el-pagination>
</div>
<!-- 新增模态框 -->
<el-dialog
v-model="addDialogVisible"
title="新增医生常用语"
width="600px"
center
>
<el-form ref="addFormRef" :model="addForm" :rules="rules" label-width="100px" class="add-form">
<el-form-item label="名称" prop="phraseName" required>
<el-input v-model="addForm.phraseName" placeholder="请输入常用语名称(不超过50字)" maxlength="50" show-word-limit style="width: 100%;"></el-input>
</el-form-item>
<el-form-item label="内容" prop="phraseContent" required>
<el-input
v-model="addForm.phraseContent"
placeholder="请输入常用语内容"
type="textarea"
:rows="4"
style="width: 100%;"
></el-input>
</el-form-item>
<el-form-item label="排序号">
<el-input-number v-model="addForm.sortNo" :min="1" :step="1" style="width: 100%;"></el-input-number>
</el-form-item>
<el-form-item label="业务分类">
<el-select v-model="addForm.phraseCategory" placeholder="请选择业务分类" style="width: 100%;">
<!-- 默认添加"病愈"选项 -->
<el-option label="病愈" value="12"></el-option>
<!-- 从数据字典获取其他选项 -->
<el-option
v-for="item in businessclassification"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="范围">
<el-select v-model="addForm.phraseType" placeholder="请选择范围" style="width: 100%;">
<el-option label="个人" :value="1"></el-option>
<el-option label="科室" :value="2"></el-option>
<el-option label="全院" :value="3"></el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="addDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleAdd">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import {onMounted, ref} from 'vue'
import {Check, Close, Plus, Refresh, Search} from '@element-plus/icons-vue'
import {
addDoctorPhrase,
deleteDoctorPhrase,
getDoctorPhraseList,
searchDoctorPhraseList,
updateDoctorPhrase
} from './api'
import {ElMessage, ElMessageBox} from 'element-plus'
import {useDict} from '@/utils/dict'
// 搜索条件
const searchScope = ref(null) // null表示未选择数字类型1=个人2=科室3=全院
const searchKeyword = ref('')
// 表格数据
const tableData = ref([])
// 分页
const currentPage = ref(1)
const pageSize = ref(15)
const total = ref(0)
// 新增模态框相关
const addDialogVisible = ref(false)
const addFormRef = ref()
const addForm = ref({
phraseName: '',
phraseContent: '',
sortNo: 1,
phraseType: 1,
phraseCategory: '病愈'
})
// 表单验证规则
const rules = {
phraseName: [
{ required: true, message: '请输入常用语名称', trigger: 'blur' }
],
phraseContent: [
{ required: true, message: '请输入常用语内容', trigger: 'blur' }
],
phraseType: [
{ required: true, message: '请选择范围', trigger: 'change' }
]
}
// 编辑状态管理
const editingId = ref(null)
const editForm = ref({})
const editRules = {
phraseName: [
{ required: true, message: '请输入常用语名称', trigger: 'blur' }
],
phraseContent: [
{ required: true, message: '请输入常用语内容', trigger: 'blur' }
]
}
// 获取业务分类数据字典
const { businessclassification } = useDict('businessclassification')
// 获取业务分类名称
const getBusinessTypeName = (category) => {
// 直接返回后端返回的phrase_category字段值
// 从数据库截图看phrase_category已经是中文名称"主诉"、"现病史"、"术后"等
if (category) {
return category
}
return '未知类型'
}
// 获取范围名称
const getScopeName = (scope) => {
const scopeMap = {
1: '个人',
2: '科室',
3: '全院'
}
return scopeMap[scope] || '未知范围'
}
// 名称唯一性校验函数
const validatePhraseName = (phraseName, excludeId = null) => {
if (!phraseName || !phraseName.trim()) {
return { valid: false, message: '请输入常用语名称' }
}
// 检查字数限制
if (phraseName.trim().length > 50) {
return { valid: false, message: '常用语名称不能超过50字' }
}
// 检查名称是否已存在
const existingPhrase = allData.value.find(item => {
// 排除自身(更新时)
if (excludeId && item.id === excludeId) {
return false
}
return item.phraseName === phraseName.trim()
})
if (existingPhrase) {
return { valid: false, message: '常用语名称已存在,请输入不同的名称' }
}
return { valid: true, message: '' }
}
// 所有数据(用于客户端分页)
const allData = ref([])
// 获取医生常用语列表
const fetchDoctorPhraseList = async () => {
try {
const response = await getDoctorPhraseList()
// 处理后端返回的数据结构data.data
if (response.code === 200 && response.data && response.data.data) {
// 按照sortNo由小到大排序
allData.value = response.data.data.sort((a, b) => a.sortNo - b.sortNo)
total.value = response.data.data.length
// 执行客户端分页
applyPagination()
} else {
ElMessage.error('获取数据失败: ' + (response.msg || '未知错误'))
allData.value = []
total.value = 0
}
} catch (error) {
ElMessage.error('获取数据失败: 网络请求错误')
allData.value = []
total.value = 0
}
}
// 重置功能
const handleReset = () => {
// 重置搜索条件
searchScope.value = null
searchKeyword.value = ''
// 重新加载所有数据
fetchDoctorPhraseList()
}
// 客户端分页处理
const applyPagination = () => {
const start = (currentPage.value - 1) * pageSize.value
const end = start + pageSize.value
tableData.value = allData.value.slice(start, end)
}
// 分页处理
const handleSizeChange = (val) => {
pageSize.value = val
applyPagination()
}
const handleCurrentChange = (val) => {
currentPage.value = val
applyPagination()
}
// 搜索功能
const handleSearch = async () => {
try {
// searchScope可能是null未选择、1=个人2=科室3=全院
const searchScopeValue = searchScope.value
const phraseType = searchScopeValue === null ? undefined : searchScopeValue
// 调用搜索接口phraseName, phraseType
// 如果phraseType为undefined则后端不会按范围过滤查询所有数据
const response = await searchDoctorPhraseList(searchKeyword.value, phraseType)
// 处理后端返回的数据结构data.data
if (response.code === 200 && response.data && response.data.data) {
// 按照sortNo由小到大排序
allData.value = response.data.data.sort((a, b) => a.sortNo - b.sortNo)
total.value = response.data.data.length
currentPage.value = 1 // 搜索后重置到第一页
applyPagination() // 应用分页
} else {
ElMessage.error('搜索失败: ' + (response.msg || '未知错误'))
allData.value = []
total.value = 0
}
} catch (error) {
ElMessage.error('搜索失败: 网络请求错误')
allData.value = []
total.value = 0
}
}
// 打开新增模态框
const showAddDialog = () => {
// 重置表单
addForm.value = {
phraseName: '',
phraseContent: '',
sortNo: 1,
phraseType: 1,
phraseCategory: '病愈'
}
// 打开模态框
addDialogVisible.value = true
}
// 提交新增表单
const handleAdd = async () => {
try {
// 验证表单
await addFormRef.value.validate()
// 名称唯一性校验
const nameValidation = validatePhraseName(addForm.value.phraseName)
if (!nameValidation.valid) {
ElMessage.error(nameValidation.message)
return
}
// 添加数据库要求的必填默认字段
const formData = {
...addForm.value,
phraseCode: 'PHR000',
enableFlag: 1,
staffId: 1001,
deptCode: 'DEPT001',
creatorId: 1001
}
// 调用新增接口
const response = await addDoctorPhrase(formData)
// 处理新增结果
if (response.code === 200) {
ElMessage.success('新增成功')
// 关闭模态框
addDialogVisible.value = false
// 将新数据添加到数组开头,使新增的数据在表格最上方显示
const newData = {
...formData,
id: response.data.id || Date.now() // 使用后端返回的id或当前时间戳作为临时id
}
allData.value.unshift(newData)
total.value = allData.value.length
// 重新应用分页
applyPagination()
} else {
ElMessage.error('新增失败: ' + (response.msg || '未知错误'))
}
} catch (error) {
// 表单验证失败或其他错误
if (error instanceof Error) {
ElMessage.error('请填写完整信息或网络请求错误')
} else {
// 表单验证失败的情况
ElMessage.error('请填写完整信息')
}
}
}
// 删除功能
const handleDelete = async (row) => {
try {
// 弹出确认对话框
await ElMessageBox.confirm('确定要删除该常用语吗?', '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
// 调用删除接口
const response = await deleteDoctorPhrase(row.id)
// 处理删除结果
if (response.code === 200) {
ElMessage.success('删除成功')
// 重新获取数据以更新界面
fetchDoctorPhraseList()
} else {
ElMessage.error('删除失败: ' + (response.msg || '未知错误'))
}
} catch (error) {
// 如果用户取消删除,不显示错误信息
if (error !== 'cancel' && error !== undefined) {
if (error.msg) {
ElMessage.error('删除操作失败: ' + error.msg)
} else if (error instanceof Error) {
ElMessage.error('删除操作失败: 网络请求错误')
} else {
ElMessage.error('删除操作失败: 未知错误')
}
}
}
}
// 编辑按钮点击事件
const handleEdit = (row) => {
// 进入编辑状态
editingId.value = row.id
// 复制当前行数据到编辑表单
editForm.value = {
...row,
// 确保phraseCategory和phraseType类型正确
phraseCategory: row.phraseCategory,
phraseType: row.phraseType
}
}
// 取消编辑
const handleCancel = () => {
// 退出编辑状态
editingId.value = null
// 清空编辑表单
editForm.value = {}
}
// 保存编辑
const handleSave = async () => {
try {
// 验证表单数据
if (!editForm.value.phraseName || !editForm.value.phraseContent) {
ElMessage.error('请填写完整信息')
return
}
// 名称唯一性校验(排除当前记录)
const nameValidation = validatePhraseName(editForm.value.phraseName, editingId.value)
if (!nameValidation.valid) {
ElMessage.error(nameValidation.message)
return
}
// 准备更新数据
const updateData = {
...editForm.value,
enableFlag: 1 // 确保启用状态
}
// 调用更新接口
const response = await updateDoctorPhrase(updateData)
// 处理更新结果
if (response.code === 200) {
ElMessage.success('更新成功')
// 退出编辑状态
editingId.value = null
// 清空编辑表单
editForm.value = {}
// 重新获取数据以更新界面
fetchDoctorPhraseList()
} else {
ElMessage.error('更新失败: ' + (response.msg || '未知错误'))
}
} catch (error) {
ElMessage.error('更新操作失败: 网络请求错误')
}
}
// 组件挂载时获取数据
onMounted(() => {
fetchDoctorPhraseList()
})
</script>
<style scoped>
.doctor-phrase-container {
padding: 20px;
}
.search-bar {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.pagination-container {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
</style>