<template>
|
<div class="advice-blocks">
|
<!-- 类型 Tab 展示 -->
|
<el-tabs v-model="activeType">
|
<el-tab-pane
|
v-for="type in adviceTypes"
|
:key="type.value"
|
:name="type.value"
|
>
|
<span slot="label">
|
<span class="tab-icon">{{ type.icon }}</span> {{ type.label }}
|
</span>
|
|
<!-- 有记录 -->
|
<div v-if="getAdviceByType(type.value)" class="advice-content" :class="type.className">
|
<div class="advice-head">
|
<span class="advice-label">{{ type.label }}内容</span>
|
<el-button size="mini" type="primary" plain icon="el-icon-edit" @click="handleEdit(type.value)">修改</el-button>
|
</div>
|
<div class="advice-text">{{ getAdviceByType(type.value).content }}</div>
|
<div class="advice-meta" v-if="getAdviceByType(type.value).deptCodes || getAdviceByType(type.value).wardCodes">
|
<span v-if="getAdviceByType(type.value).deptCodes" class="meta-item">
|
<i class="el-icon-office-building"></i>{{ getDeptNames(getAdviceByType(type.value).deptCodes) }}
|
</span>
|
<span v-if="getAdviceByType(type.value).wardCodes" class="meta-item">
|
<i class="el-icon-s-home"></i>{{ getWardNames(getAdviceByType(type.value).wardCodes) }}
|
</span>
|
</div>
|
<div class="advice-meta" v-if="getAdviceByType(type.value).involvedUsers">
|
<span class="meta-item"><i class="el-icon-user"></i>涉及人员:{{ getAdviceByType(type.value).involvedUsers }}</span>
|
</div>
|
<div class="advice-meta" v-if="getAdviceByType(type.value).remark">
|
<span class="meta-item">备注:{{ getAdviceByType(type.value).remark }}</span>
|
</div>
|
<div class="advice-foot">
|
<span>{{ getAdviceByType(type.value).createBy || "-" }}</span>
|
<span>{{ getAdviceByType(type.value).createTime || "-" }}</span>
|
</div>
|
</div>
|
|
<!-- 空态 -->
|
<div v-else class="advice-empty">
|
<span class="empty-icon">{{ type.icon }}</span>
|
<p>暂无{{ type.label }}记录</p>
|
<el-button size="small" type="primary" plain icon="el-icon-plus" @click="handleAdd(type.value)">新增{{ type.label }}</el-button>
|
</div>
|
</el-tab-pane>
|
</el-tabs>
|
|
<!-- 新增/编辑弹窗 -->
|
<el-dialog
|
:title="dialogTitle"
|
:visible.sync="open"
|
width="560px"
|
append-to-body
|
:close-on-click-modal="false"
|
>
|
<el-form ref="form" :model="form" :rules="rules" label-width="90px">
|
<el-form-item label="类型">
|
<el-tag :type="currentTypeTag" size="small">{{ currentTypeText }}</el-tag>
|
</el-form-item>
|
<el-form-item label="涉及科室" prop="deptCodes">
|
<el-select v-model="form.deptCodes" multiple filterable clearable placeholder="请选择涉及科室(可多选)" style="width: 100%">
|
<el-option v-for="d in deptOptions" :key="d.value" :label="d.label" :value="d.value" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="涉及病区" prop="wardCodes">
|
<el-select v-model="form.wardCodes" multiple filterable clearable placeholder="请选择涉及病区(可多选)" style="width: 100%">
|
<el-option v-for="w in wardOptions" :key="w.value" :label="w.label" :value="w.value" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="涉及人员" prop="involvedUsers">
|
<el-input v-model="form.involvedUsers" placeholder="涉及人员代码,多个用逗号分隔" />
|
</el-form-item>
|
<el-form-item label="内容" prop="content">
|
<el-input type="textarea" :rows="4" v-model="form.content" :placeholder="'请输入' + currentTypeText + '内容'" />
|
</el-form-item>
|
<el-form-item label="备注" prop="remark">
|
<el-input type="textarea" :rows="2" v-model="form.remark" placeholder="请输入备注" />
|
</el-form-item>
|
</el-form>
|
<div slot="footer" class="dialog-footer">
|
<el-button @click="open = false">取 消</el-button>
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
</div>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script>
|
import { listAdvice, getAdvice, addAdvice, updateAdvice } from "@/api/followvisit/advice";
|
import store from "@/store";
|
|
export default {
|
name: "AdviceList",
|
props: {
|
// 任务ID(实体 subid)
|
subid: { type: [Number, String], default: null },
|
// 服务ID(实体 taskid)
|
taskid: { type: [Number, String], default: null },
|
// 病人ID
|
patid: { type: [Number, String], default: null }
|
},
|
data() {
|
return {
|
loading: false,
|
adviceList: [],
|
activeType: "1",
|
open: false,
|
dialogTitle: "",
|
currentType: "1",
|
form: {},
|
rules: {
|
content: [{ required: true, message: "请输入内容", trigger: "blur" }]
|
},
|
adviceTypes: [
|
{ value: "1", label: "投诉", icon: "⚠️", className: "type-complaint", tagType: "danger" },
|
{ value: "2", label: "建议", icon: "💡", className: "type-suggest", tagType: "primary" },
|
{ value: "3", label: "表扬", icon: "👍", className: "type-praise", tagType: "success" }
|
]
|
};
|
},
|
computed: {
|
deptOptions() {
|
return (store.getters.belongDepts || []).map(d => ({ label: d.deptName, value: d.deptCode }));
|
},
|
wardOptions() {
|
return (store.getters.belongWards || []).map(w => ({ label: w.districtName, value: w.districtCode }));
|
},
|
currentTypeText() {
|
const t = this.adviceTypes.find(x => x.value === this.currentType);
|
return t ? t.label : "";
|
},
|
currentTypeTag() {
|
const t = this.adviceTypes.find(x => x.value === this.currentType);
|
return t ? t.tagType : "info";
|
}
|
},
|
created() {
|
this.getList();
|
},
|
methods: {
|
getAdviceByType(type) {
|
return this.adviceList.find(item => String(item.adviceType) === String(type));
|
},
|
getDeptNames(codes) {
|
if (!codes) return "";
|
return codes.split(",").filter(Boolean).map(c => {
|
const found = this.deptOptions.find(d => d.value == c);
|
return found ? found.label : c;
|
}).join("、");
|
},
|
getWardNames(codes) {
|
if (!codes) return "";
|
return codes.split(",").filter(Boolean).map(c => {
|
const found = this.wardOptions.find(w => w.value == c);
|
return found ? found.label : c;
|
}).join("、");
|
},
|
|
getList() {
|
this.loading = true;
|
const body = {
|
subid: this.subid || undefined,
|
taskid: this.taskid || undefined,
|
patid: this.patid || undefined
|
};
|
const query = { pageNum: 1, pageSize: 100 };
|
listAdvice(body, query).then(res => {
|
this.adviceList = res.rows || [];
|
this.loading = false;
|
}).catch(() => { this.loading = false; });
|
},
|
|
resetForm() {
|
this.form = {
|
id: undefined,
|
adviceType: this.currentType,
|
deptCodes: [],
|
wardCodes: [],
|
involvedUsers: "",
|
content: "",
|
remark: ""
|
};
|
},
|
|
handleAdd(type) {
|
this.currentType = type;
|
this.resetForm();
|
this.dialogTitle = "新增" + this.currentTypeText;
|
this.open = true;
|
},
|
|
handleEdit(type) {
|
this.currentType = type;
|
const existing = this.getAdviceByType(type);
|
if (existing) {
|
getAdvice(existing.id).then(res => {
|
const data = res.data || existing;
|
this.form = {
|
id: data.id,
|
adviceType: data.adviceType || type,
|
deptCodes: data.deptCodes ? data.deptCodes.split(",").filter(Boolean) : [],
|
wardCodes: data.wardCodes ? data.wardCodes.split(",").filter(Boolean) : [],
|
involvedUsers: data.involvedUsers || "",
|
content: data.content || "",
|
remark: data.remark || ""
|
};
|
this.dialogTitle = "修改" + this.currentTypeText;
|
this.open = true;
|
});
|
}
|
},
|
|
submitForm() {
|
this.$refs["form"].validate(valid => {
|
if (!valid) return;
|
const data = {
|
id: this.form.id,
|
subid: this.subid,
|
taskid: this.taskid,
|
patid: this.patid,
|
adviceType: this.form.adviceType,
|
deptCodes: this.form.deptCodes.join(","),
|
wardCodes: this.form.wardCodes.join(","),
|
involvedUsers: this.form.involvedUsers,
|
content: this.form.content,
|
remark: this.form.remark,
|
delFlag: "0"
|
};
|
const api = this.form.id ? updateAdvice(data) : addAdvice(data);
|
api.then(res => {
|
if (res.code === 200) {
|
this.$modal.msgSuccess(this.form.id ? "修改成功" : "新增成功");
|
this.open = false;
|
this.getList();
|
} else {
|
this.$modal.msgError(res.msg || "操作失败");
|
}
|
});
|
});
|
}
|
}
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
.advice-blocks {
|
padding: 0;
|
|
::v-deep .el-tabs__item {
|
.tab-icon {
|
margin-right: 4px;
|
}
|
}
|
}
|
|
.advice-content {
|
padding: 16px 20px;
|
border-radius: 6px;
|
border-left: 4px solid transparent;
|
background: #fafafa;
|
|
&.type-complaint { border-left-color: #f56c6c; }
|
&.type-suggest { border-left-color: #409eff; }
|
&.type-praise { border-left-color: #67c23a; }
|
|
.advice-head {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 10px;
|
.advice-label {
|
font-size: 14px;
|
font-weight: 600;
|
color: #303133;
|
}
|
}
|
|
.advice-text {
|
font-size: 14px;
|
color: #303133;
|
line-height: 1.7;
|
margin-bottom: 10px;
|
word-break: break-all;
|
}
|
|
.advice-meta {
|
font-size: 13px;
|
color: #909399;
|
margin-bottom: 6px;
|
.meta-item {
|
display: inline-block;
|
margin-right: 16px;
|
i { margin-right: 4px; color: #606266; }
|
}
|
}
|
|
.advice-foot {
|
display: flex;
|
justify-content: space-between;
|
font-size: 12px;
|
color: #c0c4cc;
|
padding-top: 10px;
|
border-top: 1px solid #ebeef5;
|
}
|
}
|
|
.advice-empty {
|
padding: 50px 0;
|
text-align: center;
|
.empty-icon { font-size: 36px; display: block; margin-bottom: 12px; }
|
p { color: #c0c4cc; font-size: 14px; margin-bottom: 16px; }
|
}
|
</style>
|