<template>
|
<div class="batch-process">
|
<!-- 页面标题 -->
|
<div class="page-header">
|
<div class="header-content">
|
<h2 class="page-title">异常批量处理</h2>
|
<p class="page-description">批量处理选中的异常反馈</p>
|
<div class="header-actions">
|
<el-button
|
type="primary"
|
icon="el-icon-check"
|
@click="handleBatchSubmit"
|
:loading="batchProcessing"
|
>
|
批量提交处理
|
</el-button>
|
<el-button type="warning" icon="el-icon-back" @click="handleGoBack">
|
返回异常列表
|
</el-button>
|
</div>
|
</div>
|
</div>
|
|
<!-- 异常列表 -->
|
<div class="list-section">
|
<el-card shadow="never">
|
<div class="filter-section">
|
<el-form
|
:model="filterParams"
|
:inline="true"
|
size="medium"
|
class="filter-form"
|
>
|
<el-form-item label="负责科室">
|
<el-select
|
v-model="filterParams.deptId"
|
placeholder="请选择科室"
|
clearable
|
style="width: 200px"
|
>
|
<el-option
|
v-for="dept in deptList"
|
:key="dept.id"
|
:label="dept.name"
|
:value="dept.id"
|
/>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="处理状态">
|
<el-select
|
v-model="filterParams.status"
|
placeholder="请选择状态"
|
clearable
|
style="width: 200px"
|
>
|
<el-option label="待处理" :value="0" />
|
<el-option label="处理中" :value="1" />
|
<el-option label="已处理" :value="2" />
|
</el-select>
|
</el-form-item>
|
<el-form-item>
|
<el-button
|
type="primary"
|
icon="el-icon-search"
|
@click="handleFilter"
|
>
|
筛选
|
</el-button>
|
<el-button icon="el-icon-refresh" @click="handleResetFilter">
|
重置
|
</el-button>
|
</el-form-item>
|
</el-form>
|
</div>
|
|
<el-table
|
v-loading="loading"
|
:data="exceptionList"
|
:border="true"
|
style="width: 100%"
|
@selection-change="handleSelectionChange"
|
class="exception-table"
|
>
|
<el-table-column type="selection" width="55" align="center" />
|
|
<el-table-column
|
label="序号"
|
type="index"
|
width="60"
|
align="center"
|
/>
|
|
<el-table-column
|
label="负责科室"
|
prop="responsibilityDept"
|
width="120"
|
align="center"
|
>
|
<template slot-scope="{ row }">
|
<el-tag type="primary">{{ row.responsibilityDept }}</el-tag>
|
</template>
|
</el-table-column>
|
|
<el-table-column
|
label="不满意详情"
|
prop="unsatisfactoryDetail"
|
min-width="200"
|
align="center"
|
>
|
<template slot-scope="{ row }">
|
<div class="detail-content">
|
{{ row.unsatisfactoryDetail }}
|
</div>
|
</template>
|
</el-table-column>
|
|
<el-table-column label="患者信息" width="300" align="center">
|
<template slot-scope="{ row }">
|
<div class="patient-info">
|
<div class="patient-item">
|
<span class="label">姓名:</span>
|
<span class="value">{{ row.patientName }}</span>
|
</div>
|
<div class="patient-item">
|
<span class="label">性别:</span>
|
<span class="value">{{
|
row.gender === 1 ? "男" : "女"
|
}}</span>
|
</div>
|
<div class="patient-item">
|
<span class="label">年龄:</span>
|
<span class="value">{{ row.age }}岁</span>
|
</div>
|
<div class="patient-item">
|
<span class="label">电话:</span>
|
<span class="value">{{ row.phone }}</span>
|
</div>
|
</div>
|
</template>
|
</el-table-column>
|
|
<el-table-column label="出院信息" width="250" align="center">
|
<template slot-scope="{ row }">
|
<div class="discharge-info">
|
<div class="info-item">
|
<span class="label">科室:</span>
|
<span class="value">{{ row.dischargeDept }}</span>
|
</div>
|
<div class="info-item">
|
<span class="label">病区:</span>
|
<span class="value">{{ row.dischargeWard }}</span>
|
</div>
|
<div class="info-item">
|
<span class="label">填写时间:</span>
|
<span class="value time">{{ row.fillTime }}</span>
|
</div>
|
</div>
|
</template>
|
</el-table-column>
|
|
<el-table-column
|
label="处理状态"
|
prop="processStatus"
|
width="100"
|
align="center"
|
>
|
<template slot-scope="{ row }">
|
<el-tag :type="getStatusTagType(row.processStatus)" effect="dark">
|
{{ getStatusText(row.processStatus) }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
|
<el-table-column
|
label="操作"
|
width="210"
|
align="center"
|
fixed="right"
|
>
|
<template slot-scope="{ row }">
|
<el-button
|
type="primary"
|
size="small"
|
icon="el-icon-view"
|
@click="handleViewDetail(row)"
|
>
|
查看详情
|
</el-button>
|
<el-button
|
type="warning"
|
size="small"
|
icon="el-icon-edit"
|
@click="handleProcess(row)"
|
:disabled="row.processStatus === 2"
|
>
|
处理
|
</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<!-- 分页 -->
|
<div class="pagination-section">
|
<el-pagination
|
background
|
layout="total, sizes, prev, pager, next, jumper"
|
:current-page="filterParams.pageNum"
|
:page-size="filterParams.pageSize"
|
:page-sizes="[10, 20, 30, 50]"
|
:total="total"
|
@size-change="handleSizeChange"
|
@current-change="handlePageChange"
|
/>
|
</div>
|
</el-card>
|
</div>
|
|
<!-- 处理对话框 -->
|
<el-dialog
|
title="处理异常反馈"
|
:visible.sync="processDialogVisible"
|
width="600px"
|
center
|
>
|
<el-form
|
:model="processForm"
|
:rules="processRules"
|
ref="processForm"
|
label-width="100px"
|
size="medium"
|
>
|
<el-form-item label="处理状态" prop="status">
|
<el-select
|
v-model="processForm.status"
|
placeholder="请选择处理状态"
|
style="width: 100%"
|
>
|
<el-option label="处理中" :value="1" />
|
<el-option label="已处理" :value="2" />
|
<el-option label="已驳回" :value="3" />
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="报备科室" prop="reportDepts">
|
<el-select
|
v-model="processForm.reportDepts"
|
placeholder="请选择报备科室"
|
multiple
|
filterable
|
collapse-tags
|
style="width: 100%"
|
>
|
<el-option
|
v-for="dept in deptList"
|
:key="dept.id"
|
:label="dept.name"
|
:value="dept.id"
|
/>
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="处理备注" prop="remark">
|
<el-input
|
v-model="processForm.remark"
|
type="textarea"
|
:rows="4"
|
placeholder="请输入处理备注(最多500字)"
|
maxlength="500"
|
show-word-limit
|
/>
|
</el-form-item>
|
|
<el-form-item label="附件上传">
|
<el-upload
|
class="upload-demo"
|
action="#"
|
:on-preview="handlePreview"
|
:on-remove="handleRemove"
|
:before-remove="beforeRemove"
|
:limit="3"
|
:on-exceed="handleExceed"
|
:file-list="fileList"
|
>
|
<el-button size="small" type="primary">点击上传</el-button>
|
<div slot="tip" class="el-upload__tip">
|
支持上传图片、文档等附件,单个文件不超过10MB
|
</div>
|
</el-upload>
|
</el-form-item>
|
</el-form>
|
<span slot="footer" class="dialog-footer">
|
<el-button @click="processDialogVisible = false">取消</el-button>
|
<el-button type="primary" @click="submitProcess" :loading="processing">
|
提交处理
|
</el-button>
|
</span>
|
</el-dialog>
|
|
<!-- 批量处理对话框 -->
|
<el-dialog
|
title="批量处理异常反馈"
|
:visible.sync="batchDialogVisible"
|
width="600px"
|
center
|
>
|
<el-form
|
:model="batchProcessForm"
|
:rules="processRules"
|
ref="batchProcessForm"
|
label-width="100px"
|
size="medium"
|
>
|
<el-form-item label="处理状态" prop="status">
|
<el-select
|
v-model="batchProcessForm.status"
|
placeholder="请选择处理状态"
|
style="width: 100%"
|
>
|
<el-option label="处理中" :value="1" />
|
<el-option label="已处理" :value="2" />
|
<el-option label="已驳回" :value="3" />
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="报备科室" prop="reportDepts">
|
<el-select
|
v-model="batchProcessForm.reportDepts"
|
placeholder="请选择报备科室"
|
multiple
|
filterable
|
collapse-tags
|
style="width: 100%"
|
>
|
<el-option
|
v-for="dept in deptList"
|
:key="dept.id"
|
:label="dept.name"
|
:value="dept.id"
|
/>
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="处理备注" prop="remark">
|
<el-input
|
v-model="batchProcessForm.remark"
|
type="textarea"
|
:rows="4"
|
placeholder="请输入处理备注(最多500字)"
|
maxlength="500"
|
show-word-limit
|
/>
|
</el-form-item>
|
</el-form>
|
<span slot="footer" class="dialog-footer">
|
<el-button @click="batchDialogVisible = false">取消</el-button>
|
<el-button
|
type="primary"
|
@click="submitBatchProcess"
|
:loading="batchProcessing"
|
>
|
批量提交
|
</el-button>
|
</span>
|
</el-dialog>
|
<!-- 异常详情弹框 -->
|
<Details-anomaly
|
:visible="detailDialogVisible"
|
:record-id="selectedRecordId"
|
:title="detailDialogTitle"
|
@update:visible="handleDetailDialogClose"
|
@processed="handleProcessed"
|
@close="handleDetailDialogClose"
|
/>
|
</div>
|
</template>
|
|
<script>
|
import DetailsAnomaly from "./components/DetailsAnomaly.vue";
|
export default {
|
name: "BatchProcess",
|
components: {
|
DetailsAnomaly,
|
},
|
data() {
|
return {
|
// 添加以下数据
|
detailDialogVisible: false,
|
selectedRecordId: null,
|
detailDialogTitle: "异常反馈详情",
|
// 当前处理的异常ID
|
currentExceptionId: null,
|
|
// 批量选中的异常ID
|
selectedExceptionIds: [],
|
|
// 过滤参数
|
filterParams: {
|
deptId: "",
|
status: "",
|
pageNum: 1,
|
pageSize: 10,
|
},
|
|
// 加载状态
|
loading: false,
|
processing: false,
|
batchProcessing: false,
|
|
// 科室列表
|
deptList: [
|
{ id: 1, name: "心血管内科" },
|
{ id: 2, name: "神经内科" },
|
{ id: 3, name: "普外科" },
|
{ id: 4, name: "骨科" },
|
{ id: 5, name: "妇产科" },
|
{ id: 6, name: "儿科" },
|
{ id: 7, name: "急诊科" },
|
{ id: 8, name: "呼吸内科" },
|
{ id: 9, name: "消化内科" },
|
{ id: 10, name: "内分泌科" },
|
],
|
|
// 异常列表数据
|
exceptionList: [],
|
total: 0,
|
|
// 处理对话框
|
processDialogVisible: false,
|
processForm: {
|
status: "",
|
reportDepts: [],
|
remark: "",
|
},
|
processRules: {
|
status: [
|
{ required: true, message: "请选择处理状态", trigger: "change" },
|
],
|
remark: [
|
{ required: true, message: "请输入处理备注", trigger: "blur" },
|
{
|
min: 5,
|
max: 500,
|
message: "备注长度在 5 到 500 个字符",
|
trigger: "blur",
|
},
|
],
|
},
|
fileList: [],
|
|
// 批量处理对话框
|
batchDialogVisible: false,
|
batchProcessForm: {
|
status: "",
|
reportDepts: [],
|
remark: "",
|
},
|
};
|
},
|
|
mounted() {
|
this.loadExceptionList();
|
},
|
|
methods: {
|
// 加载异常列表
|
async loadExceptionList() {
|
this.loading = true;
|
try {
|
// Mock 数据
|
await new Promise((resolve) => {
|
setTimeout(() => {
|
this.exceptionList = [
|
{
|
id: 1,
|
responsibilityDept: "心血管内科",
|
unsatisfactoryDetail:
|
"医生查房时间太短,沟通不够充分,对病情解释不够详细",
|
patientName: "张先生",
|
gender: 1,
|
age: 45,
|
phone: "138****1234",
|
dischargeDept: "心血管内科",
|
dischargeWard: "内科一病区",
|
fillTime: "2024-01-15 10:30:25",
|
processStatus: 0,
|
questionnaireId: 1001,
|
},
|
{
|
id: 2,
|
responsibilityDept: "神经内科",
|
unsatisfactoryDetail:
|
"护士打针技术不佳,扎了三次才成功,且态度不够耐心",
|
patientName: "李女士",
|
gender: 0,
|
age: 38,
|
phone: "139****5678",
|
dischargeDept: "神经内科",
|
dischargeWard: "内科二病区",
|
fillTime: "2024-01-14 16:20:10",
|
processStatus: 0,
|
questionnaireId: 1002,
|
},
|
{
|
id: 3,
|
responsibilityDept: "普外科",
|
unsatisfactoryDetail: "术后换药不及时,伤口疼痛时没有及时处理",
|
patientName: "王先生",
|
gender: 1,
|
age: 52,
|
phone: "137****9012",
|
dischargeDept: "普外科",
|
dischargeWard: "外科一病区",
|
fillTime: "2024-01-13 09:15:45",
|
processStatus: 1,
|
questionnaireId: 1003,
|
},
|
{
|
id: 4,
|
responsibilityDept: "骨科",
|
unsatisfactoryDetail: "康复指导不够专业,对恢复过程描述不清楚",
|
patientName: "刘女士",
|
gender: 0,
|
age: 65,
|
phone: "136****3456",
|
dischargeDept: "骨科",
|
dischargeWard: "外科二病区",
|
fillTime: "2024-01-12 14:40:30",
|
processStatus: 0,
|
questionnaireId: 1004,
|
},
|
{
|
id: 5,
|
responsibilityDept: "妇产科",
|
unsatisfactoryDetail:
|
"产前检查排队时间过长,等待期间没有休息座位",
|
patientName: "陈女士",
|
gender: 0,
|
age: 28,
|
phone: "135****7890",
|
dischargeDept: "妇产科",
|
dischargeWard: "妇产科病区",
|
fillTime: "2024-01-11 11:25:15",
|
processStatus: 2,
|
questionnaireId: 1005,
|
},
|
{
|
id: 6,
|
responsibilityDept: "儿科",
|
unsatisfactoryDetail:
|
"儿童用药剂量交代不清晰,用药注意事项没有说明",
|
patientName: "赵宝宝",
|
gender: 1,
|
age: 5,
|
phone: "134****1234",
|
dischargeDept: "儿科",
|
dischargeWard: "儿科病区",
|
fillTime: "2024-01-10 15:50:20",
|
processStatus: 0,
|
questionnaireId: 1006,
|
},
|
{
|
id: 7,
|
responsibilityDept: "急诊科",
|
unsatisfactoryDetail: "急诊等待时间过长,病情没有得到及时评估",
|
patientName: "孙先生",
|
gender: 1,
|
age: 40,
|
phone: "133****5678",
|
dischargeDept: "急诊科",
|
dischargeWard: "急诊病区",
|
fillTime: "2024-01-09 10:15:40",
|
processStatus: 0,
|
questionnaireId: 1007,
|
},
|
{
|
id: 8,
|
responsibilityDept: "呼吸内科",
|
unsatisfactoryDetail: "医生开药较多,费用较高,没有说明必要性",
|
patientName: "周女士",
|
gender: 0,
|
age: 55,
|
phone: "132****9012",
|
dischargeDept: "呼吸内科",
|
dischargeWard: "内科一病区",
|
fillTime: "2024-01-08 13:30:55",
|
processStatus: 1,
|
questionnaireId: 1008,
|
},
|
];
|
this.total = this.exceptionList.length;
|
resolve();
|
}, 500);
|
});
|
} finally {
|
this.loading = false;
|
}
|
},
|
|
// 获取状态标签类型
|
getStatusTagType(status) {
|
switch (status) {
|
case 0:
|
return "warning"; // 待处理
|
case 1:
|
return "primary"; // 处理中
|
case 2:
|
return "success"; // 已处理
|
default:
|
return "info";
|
}
|
},
|
|
// 获取状态文本
|
getStatusText(status) {
|
switch (status) {
|
case 0:
|
return "待处理";
|
case 1:
|
return "处理中";
|
case 2:
|
return "已处理";
|
default:
|
return "未知";
|
}
|
},
|
|
// 处理筛选
|
handleFilter() {
|
this.filterParams.pageNum = 1;
|
this.loadExceptionList();
|
},
|
|
// 重置筛选
|
handleResetFilter() {
|
this.filterParams = {
|
deptId: "",
|
status: "",
|
pageNum: 1,
|
pageSize: 10,
|
};
|
this.loadExceptionList();
|
},
|
|
// 处理选择变化
|
handleSelectionChange(selection) {
|
this.selectedExceptionIds = selection.map((item) => item.id);
|
},
|
|
// 处理批量提交
|
handleBatchSubmit() {
|
if (this.selectedExceptionIds.length === 0) {
|
this.$message.warning("请先选择要处理的异常反馈");
|
return;
|
}
|
this.batchDialogVisible = true;
|
},
|
|
// 返回异常列表
|
handleGoBack() {
|
this.$router.push("/satisfaction/exception/list");
|
},
|
|
// 查看详情
|
handleViewDetail(row) {
|
this.selectedRecordId = row.id;
|
this.detailDialogTitle = `${row.patientName} - 异常反馈详情`;
|
this.detailDialogVisible = true;
|
},
|
// 处理详情弹框关闭
|
handleDetailDialogClose() {
|
this.detailDialogVisible = false;
|
this.selectedRecordId = null;
|
}, // 处理完成后的回调
|
handleProcessed() {
|
// 重新加载数据
|
this.loadExceptionList();
|
},
|
// 处理单个异常
|
handleProcess(row) {
|
this.currentExceptionId = row.id;
|
this.processForm = {
|
status: row.processStatus === 0 ? 1 : row.processStatus,
|
reportDepts: [],
|
remark: "",
|
};
|
this.processDialogVisible = true;
|
},
|
|
// 提交处理
|
async submitProcess() {
|
this.$refs.processForm.validate(async (valid) => {
|
if (valid) {
|
this.processing = true;
|
try {
|
// Mock API调用
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
this.$message.success("处理提交成功");
|
this.processDialogVisible = false;
|
this.loadExceptionList();
|
} finally {
|
this.processing = false;
|
}
|
}
|
});
|
},
|
|
// 提交批量处理
|
async submitBatchProcess() {
|
this.$refs.batchProcessForm.validate(async (valid) => {
|
if (valid) {
|
this.batchProcessing = true;
|
try {
|
// Mock API调用
|
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
this.$message.success(
|
`已批量处理 ${this.selectedExceptionIds.length} 条异常反馈`
|
);
|
this.batchDialogVisible = false;
|
this.selectedExceptionIds = [];
|
this.loadExceptionList();
|
} finally {
|
this.batchProcessing = false;
|
}
|
}
|
});
|
},
|
|
// 分页大小变化
|
handleSizeChange(size) {
|
this.filterParams.pageSize = size;
|
this.filterParams.pageNum = 1;
|
this.loadExceptionList();
|
},
|
|
// 页码变化
|
handlePageChange(page) {
|
this.filterParams.pageNum = page;
|
this.loadExceptionList();
|
},
|
|
// 文件上传相关方法
|
handlePreview(file) {
|
console.log("预览文件:", file);
|
},
|
|
handleRemove(file, fileList) {
|
console.log("移除文件:", file, fileList);
|
},
|
|
beforeRemove(file) {
|
return this.$confirm(`确定移除 ${file.name}?`);
|
},
|
|
handleExceed(files, fileList) {
|
this.$message.warning(
|
`当前限制选择 3 个文件,本次选择了 ${files.length} 个文件,共选择了 ${
|
files.length + fileList.length
|
} 个文件`
|
);
|
},
|
},
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
.batch-process {
|
padding: 20px;
|
background-color: #f5f7fa;
|
min-height: 100vh;
|
|
.page-header {
|
margin-bottom: 20px;
|
padding: 20px;
|
background: linear-gradient(135deg, #5788fe 0%, #66b1ff 100%);
|
border-radius: 8px;
|
color: white;
|
|
.header-content {
|
.page-title {
|
margin: 0 0 8px 0;
|
font-size: 20px;
|
font-weight: 600;
|
}
|
|
.page-description {
|
margin: 0 0 20px 0;
|
opacity: 0.9;
|
font-size: 14px;
|
}
|
|
.header-actions {
|
display: flex;
|
gap: 10px;
|
}
|
}
|
}
|
|
.list-section {
|
.filter-section {
|
margin-bottom: 20px;
|
|
.filter-form {
|
display: flex;
|
flex-wrap: wrap;
|
align-items: center;
|
|
::v-deep .el-form-item {
|
margin-bottom: 0;
|
margin-right: 20px;
|
|
&:last-child {
|
margin-right: 0;
|
}
|
}
|
}
|
}
|
|
.exception-table {
|
::v-deep .el-table__header-wrapper {
|
th {
|
background-color: #f8f9fa;
|
font-weight: 600;
|
color: #333;
|
}
|
}
|
|
.detail-content {
|
font-size: 13px;
|
color: #606266;
|
line-height: 1.5;
|
text-align: left;
|
}
|
|
.patient-info {
|
.patient-item {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 5px;
|
padding: 2px 0;
|
|
.label {
|
font-size: 12px;
|
color: #606266;
|
min-width: 40px;
|
}
|
|
.value {
|
font-size: 13px;
|
color: #333;
|
font-weight: 500;
|
text-align: right;
|
flex: 1;
|
}
|
}
|
}
|
|
.discharge-info {
|
.info-item {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 5px;
|
padding: 2px 0;
|
|
.label {
|
font-size: 12px;
|
color: #606266;
|
min-width: 50px;
|
}
|
|
.value {
|
font-size: 13px;
|
color: #333;
|
font-weight: 500;
|
text-align: right;
|
flex: 1;
|
|
&.time {
|
font-size: 12px;
|
color: #909399;
|
}
|
}
|
}
|
}
|
}
|
|
.pagination-section {
|
display: flex;
|
justify-content: center;
|
padding: 20px 0 0 0;
|
}
|
}
|
}
|
|
@media (max-width: 768px) {
|
.batch-process {
|
padding: 10px;
|
|
.page-header {
|
.header-actions {
|
flex-direction: column;
|
align-items: stretch;
|
}
|
}
|
|
.list-section {
|
.filter-section {
|
.filter-form {
|
::v-deep .el-form-item {
|
width: 100%;
|
margin-right: 0;
|
margin-bottom: 10px;
|
}
|
}
|
}
|
}
|
}
|
}
|
</style>
|