587 lines
17 KiB
Vue
587 lines
17 KiB
Vue
<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> |