<template>
|
<div class="app-container">
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
<el-form-item label="院区名称" prop="hospAreaName">
|
<el-input style="width: 160px" v-model="queryParams.hospAreaName" placeholder="请输入院区名称" clearable
|
@keyup.enter.native="handleQuery" />
|
</el-form-item>
|
<el-form-item label="机构名称" prop="hospName">
|
<el-input v-model="queryParams.hospName" style="width: 160px" placeholder="请输入机构名称" clearable
|
@keyup.enter.native="handleQuery" />
|
</el-form-item>
|
<el-form-item label="区划名称" prop="areaName">
|
<el-input v-model="queryParams.areaName" placeholder="请输入区划名称" clearable @keyup.enter.native="handleQuery"
|
style="width: 180px" />
|
</el-form-item>
|
<el-form-item label="主院区" prop="mainHospArea">
|
<el-select v-model="queryParams.mainHospArea" placeholder="是否主院区" clearable style="width: 110px">
|
<el-option v-for="dict in dict.type.sys_yes_no" :key="dict.value" :label="dict.label" :value="dict.value" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="负责人" prop="principal">
|
<el-input v-model="queryParams.principal" placeholder="请输入负责人" clearable @keyup.enter.native="handleQuery"
|
style="width: 140px" />
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
</el-form-item>
|
</el-form>
|
|
<el-row :gutter="10" class="mb8">
|
<el-col :span="1.5">
|
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd"
|
v-hasPermi="['hosp:hosp:add']">新增</el-button>
|
</el-col>
|
<el-col :span="1.5">
|
<el-button type="primary" icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
|
v-hasPermi="['hosp:hosp:edit']">修改</el-button>
|
</el-col>
|
<el-col :span="1.5">
|
<el-button type="primary" icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete"
|
v-hasPermi="['hosp:hosp:remove']">删除</el-button>
|
</el-col>
|
<el-col :span="1.5">
|
<el-button type="primary" icon="el-icon-download" size="mini" @click="handleExport"
|
v-hasPermi="['hosp:hosp:export']">导出</el-button>
|
</el-col>
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
</el-row>
|
|
<el-table v-loading="loading" :data="hospList" @selection-change="handleSelectionChange" border>
|
<el-table-column type="selection" width="55" align="center" fixed />
|
<el-table-column label="序号" align="center" prop="newID" width="50px" fixed="left" />
|
<el-table-column label="院区名称" align="center" prop="hospAreaName" width="120px" :show-overflow-tooltip="true"
|
fixed="left" />
|
<el-table-column label="院区编码" align="center" prop="code" :show-overflow-tooltip="true" />
|
<el-table-column label="五笔简码" align="center" prop="wbm" :show-overflow-tooltip="true" />
|
<el-table-column label="拼音简码" align="center" prop="spell" :show-overflow-tooltip="true" />
|
<el-table-column label="主院区" align="center" prop="mainHospArea" :show-overflow-tooltip="true">
|
<template slot-scope="scope">
|
<dict-tag :options="dict.type.sys_yes_no" :value="scope.row.mainHospArea" />
|
</template>
|
</el-table-column>
|
<el-table-column label="负责人" align="center" prop="principal" :show-overflow-tooltip="true" />
|
<el-table-column label="负责人电话" align="center" prop="phone" :show-overflow-tooltip="true" width="120px" />
|
<el-table-column label="编制床位" align="center" prop="plaitBed" :show-overflow-tooltip="true" />
|
<el-table-column label="开放床位" align="center" prop="openBed" :show-overflow-tooltip="true" />
|
<el-table-column label="成立日期" align="center" prop="buildDate" width="120px" :show-overflow-tooltip="true">
|
<template slot-scope="scope">
|
<span>{{ parseTime(scope.row.buildDate, "{y}-{m}-{d}") }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
<el-table-column label="排序" align="center" prop="orderNum" width="50px" :show-overflow-tooltip="true" />
|
<el-table-column label="数据状态" align="center" prop="effective" :show-overflow-tooltip="true">
|
<template slot-scope="scope">
|
<dict-tag :options="dict.type.dict_data_status" :value="scope.row.effective" />
|
</template>
|
</el-table-column>
|
<el-table-column fixed="right" label="操作" align="center" class-name="small-padding fixed-width" width="80px">
|
<template slot-scope="scope">
|
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
v-hasPermi="['hosp:hosp:edit']" title="修改"></el-button>
|
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
v-hasPermi="['hosp:hosp:remove']" title="删除"></el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<div class="pag">
|
<div class="pag1">
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
|
:limit.sync="queryParams.pageSize" @pagination="getList" />
|
</div>
|
</div>
|
|
<!-- 添加或修改院区信息对话框 -->
|
<el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
|
<el-form ref="form" :model="form" :rules="rules" label-width="100px" :inline="true">
|
<el-form-item label="院区名称" prop="hospAreaName">
|
<el-input v-model="form.hospAreaName" placeholder="请输入院区名称" />
|
</el-form-item>
|
<el-form-item label="院区编码" prop="code">
|
<el-input v-model="form.code" placeholder="请输入院区编码" />
|
</el-form-item>
|
<el-form-item label="主院区" prop="mainHospArea">
|
<el-select v-model="form.mainHospArea" placeholder="请选择是否主院区 0-不是 1-是" style="width: 130px">
|
<el-option v-for="dict in dict.type.sys_yes_no" :key="dict.value" :label="dict.label"
|
:value="dict.value"></el-option>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="机构名称" prop="hospName">
|
<el-select v-model="form.hospid" placeholder="请选择所在机构" clearable style="width: 200px" filterable>
|
<el-option v-for="dict in orgList" :key="dict.orgCnName" :label="dict.orgCnName" :value="dict.orgId" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="区划名称" prop="areaid">
|
<el-select style="width: 200px" v-model="form.areaid" placeholder="请选择区划名称" filterable>
|
<el-option v-for="dict in dict.type.dict_qhdm" :key="dict.value" :label="dict.label" :value="dict.value" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="负责人" prop="principal">
|
<el-input v-model="form.principal" placeholder="请输入负责人" style="width: 135px" />
|
</el-form-item>
|
<el-form-item label="院区地址" prop="areaName">
|
<el-input v-model="form.areaName" placeholder="请输入院区地址" style="width: 510px" />
|
</el-form-item>
|
<el-form-item label="负责人电话" prop="phone">
|
<el-input v-model="form.phone" placeholder="请输入负责人电话" style="width: 135px" />
|
</el-form-item>
|
<el-form-item label="成立日期" prop="buildDate">
|
<el-date-picker clearable v-model="form.buildDate" type="date" value-format="yyyy-MM-dd" placeholder="请选择成立日期"
|
style="width: 200px">
|
</el-date-picker>
|
</el-form-item>
|
<el-form-item label="编制床位数" prop="plaitBed">
|
<el-input v-model="form.plaitBed" placeholder="请输入编制床位数" style="width: 200px" />
|
</el-form-item>
|
<el-form-item label="开放床位数" prop="openBed">
|
<el-input v-model="form.openBed" placeholder="请输入开放床位数" style="width: 200px" />
|
</el-form-item>
|
<el-form-item label="排序" prop="orderNum">
|
<el-input v-model="form.orderNum" placeholder="请输入排序" style="width: 145px" />
|
</el-form-item>
|
<el-form-item label="备注" prop="remark">
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" :rows="2" style="width: 820px" resize="none"></el-input>
|
</el-form-item>
|
<el-form-item label="医院简介" prop="introduction">
|
<editor v-model="form.introduction" :init="editorInit" :api-key="apiKey" style="width: 820px"></editor>
|
</el-form-item>
|
<el-form-item label="图片">
|
<image-upload v-model="form.imgbase64" />
|
</el-form-item>
|
</el-form>
|
<div slot="footer" class="dialog-footer">
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
<el-button @click="cancel">取 消</el-button>
|
</div>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script>
|
import { listHosp, getHosp, delHosp, addHosp, updateHosp } from "@/api/hosp/hosp";
|
import { listOrg } from "@/api/hosp/org";
|
import Editor from '@tinymce/tinymce-vue';
|
|
export default {
|
name: "Hosp",
|
dicts: ["sys_yes_no", "dict_data_status", "dict_qhdm"],
|
components: { Editor },
|
data() {
|
let checkPhoneNum = (rule, value, callback) => {
|
const pattern = /^1[3-9]\d{9}$/;
|
if (!value) {
|
return callback(new Error("请输入负责人电话"));
|
}
|
if (!pattern.test(value)) {
|
return callback(new Error("请输入正确的手机号"));
|
}
|
return callback();
|
};
|
|
return {
|
loading: true,
|
ids: [],
|
single: true,
|
multiple: true,
|
showSearch: true,
|
total: 0,
|
hospList: [],
|
orgList: [],
|
title: "",
|
open: false,
|
apiKey: '3ceaxd5ckw4te35xj38vj3p5rmmeyv0x8pq2yrr92rwdiqzp', // 替换为您的 TinyMCE API 密钥
|
editorInit: {
|
height: 200,
|
menubar: false,
|
plugins: [
|
'advlist autolink lists link image charmap',
|
'searchreplace visualblocks code fullscreen',
|
'insertdatetime media table paste wordcount'
|
],
|
toolbar:
|
'undo redo | formatselect | bold italic underline | alignleft aligncenter alignright | bullist numlist | link image table | removeformat',
|
images_upload_handler: (blobInfo, success, failure) => {
|
const reader = new FileReader();
|
reader.onload = () => success(reader.result);
|
reader.onerror = () => failure('图片上传失败');
|
reader.readAsDataURL(blobInfo.blob());
|
},
|
content_style: 'body { font-family: Arial, sans-serif; font-size: 14px; }',
|
table_default_attributes: { border: 1 },
|
language: 'zh_CN',
|
dialog_zindex: 9999,
|
fixed_toolbar_container: true,
|
inline: false,
|
relative_urls: false,
|
remove_script_host: false,
|
convert_urls: false,
|
valid_elements: '*[*]', // 允许所有 HTML 元素和属性
|
extended_valid_elements: 'p,div,span,b,strong,i,em,u,strike,sup,sub,table,tr,td,th,ul,ol,li,h1,h2,h3,h4,h5,h6,br,hr,img[*],a[*]', // 扩展允许的元素
|
},
|
queryParams: {
|
pageNum: 1,
|
pageSize: 10,
|
hospAreaName: null,
|
hospid: null,
|
hospName: null,
|
code: null,
|
areaid: null,
|
areaName: null,
|
mainHospArea: null,
|
principal: null,
|
plaitBed: null,
|
openBed: null,
|
orderNum: null,
|
},
|
form: {
|
introduction: '<p>请输入医院简介...</p>', // 默认值
|
},
|
rules: {
|
hospAreaName: [
|
{ required: true, message: "请输入院区名称", trigger: "blur" },
|
],
|
code: [{ required: true, message: "请输入院区编码", trigger: "blur" }],
|
mainHospArea: [
|
{ required: true, message: "请选择是否主院区", trigger: "change" },
|
],
|
principal: [
|
{ required: true, message: "请输入负责人", trigger: "blur" },
|
],
|
areaName: [
|
{ required: true, message: "请输入院区地址", trigger: "blur" },
|
],
|
phone: [
|
{ required: true, validator: checkPhoneNum, trigger: "blur" },
|
],
|
introduction: [
|
{ required: true, message: "请输入医院简介", trigger: "blur" },
|
{ validator: (rule, value, callback) => {
|
if (!value || value === '<p>请输入医院简介...</p>') {
|
callback(new Error("医院简介不能为空"));
|
} else {
|
callback();
|
}
|
}, trigger: "blur" }
|
],
|
},
|
};
|
},
|
created() {
|
this.getList();
|
this.getListOrg();
|
},
|
methods: {
|
// 检测字符串是否为有效的 Base64 编码
|
isBase64(str) {
|
if (!str || typeof str !== 'string') return false;
|
// Base64 字符串只包含 A-Z, a-z, 0-9, +, /, =,且长度通常为 4 的倍数
|
const base64Regex = /^[A-Za-z0-9+/=]+$/;
|
if (!base64Regex.test(str)) return false;
|
// 进一步验证是否可以解码
|
try {
|
// 检查长度是否为 4 的倍数(考虑填充字符 =)
|
if (str.length % 4 !== 0) return false;
|
// 尝试解码
|
const decoded = atob(str);
|
// 验证解码后是否可以重新编码为原字符串
|
return btoa(decoded) === str;
|
} catch (e) {
|
return false;
|
}
|
},
|
// 解码 Base64,处理 Unicode 字符
|
decodeBase64(str) {
|
try {
|
// 替换 URL-safe Base64 字符(如果后端使用了 URL-safe 编码)
|
str = str.replace(/-/g, '+').replace(/_/g, '/');
|
// 使用 atob 解码
|
const decoded = atob(str);
|
// 将 Latin1 字符串转换为 UTF-8
|
return decodeURIComponent(escape(decoded));
|
} catch (e) {
|
console.error("Base64 解码失败:", e);
|
return null;
|
}
|
},
|
// 编码为 Base64,处理 Unicode 字符
|
encodeBase64(str) {
|
try {
|
// 将 UTF-8 字符串转换为 Latin1 编码
|
return btoa(unescape(encodeURIComponent(str)));
|
} catch (e) {
|
console.error("Base64 编码失败:", e);
|
return null;
|
}
|
},
|
getList() {
|
this.loading = true;
|
listHosp(this.queryParams).then((response) => {
|
response.rows.forEach((item, index) => {
|
item.newID =
|
(this.queryParams.pageNum - 1) * this.queryParams.pageSize +
|
index +
|
1;
|
});
|
this.hospList = response.rows;
|
this.total = response.total;
|
this.loading = false;
|
});
|
},
|
getListOrg() {
|
listOrg(this.queryParams).then((response) => {
|
this.orgList = response.rows;
|
});
|
},
|
cancel() {
|
this.open = false;
|
this.reset();
|
},
|
reset() {
|
this.form = {
|
hospAreaId: null,
|
hospAreaName: null,
|
hospid: null,
|
hospName: null,
|
code: null,
|
wbm: null,
|
spell: null,
|
areaid: null,
|
areaName: null,
|
mainHospArea: null,
|
principal: null,
|
phone: null,
|
plaitBed: null,
|
openBed: null,
|
buildDate: null,
|
remark: null,
|
createBy: null,
|
createTime: null,
|
updateBy: null,
|
updateTime: null,
|
orderNum: null,
|
effective: null,
|
createByName: null,
|
updateByName: null,
|
imgbase64: null,
|
deleted: null,
|
introduction: '<p>请输入医院简介...</p>', // 重置时恢复默认值
|
};
|
this.resetForm("form");
|
},
|
handleQuery() {
|
this.queryParams.pageNum = 1;
|
this.getList();
|
},
|
resetQuery() {
|
this.resetForm("queryForm");
|
this.handleQuery();
|
},
|
handleSelectionChange(selection) {
|
this.ids = selection.map((item) => item.hospAreaId);
|
this.single = selection.length !== 1;
|
this.multiple = !selection.length;
|
},
|
handleAdd() {
|
this.reset();
|
this.open = true;
|
this.title = "分院信息维护";
|
},
|
handleUpdate(row) {
|
this.reset();
|
const hospAreaId = row.hospAreaId || this.ids;
|
getHosp(hospAreaId).then((response) => {
|
this.form = response.data;
|
console.log("原始 introduction:", response.data.introduction); // 调试输出
|
if (this.form.introduction) {
|
// 检测是否为 Base64 编码
|
if (this.isBase64(this.form.introduction)) {
|
const decoded = this.decodeBase64(this.form.introduction);
|
if (decoded) {
|
this.form.introduction = decoded;
|
console.log("解码后的 introduction:", this.form.introduction); // 调试输出
|
} else {
|
this.form.introduction = '<p>无法解码医院简介,请检查数据</p>';
|
}
|
} else {
|
// 如果不是 Base64,假设是 HTML 或纯文本,直接使用
|
this.form.introduction = this.form.introduction;
|
}
|
} else {
|
this.form.introduction = '<p>请输入医院简介...</p>';
|
}
|
this.open = true;
|
this.title = "分院信息维护";
|
});
|
},
|
submitForm() {
|
this.$refs["form"].validate((valid) => {
|
if (valid) {
|
const formData = { ...this.form };
|
// 如果后端要求 Base64 编码
|
if (formData.introduction) {
|
const encoded = this.encodeBase64(formData.introduction);
|
if (encoded) {
|
formData.introduction = encoded;
|
} else {
|
this.$modal.msgError("医院简介编码失败,请检查内容");
|
return;
|
}
|
}
|
if (formData.hospAreaId != null) {
|
updateHosp(formData).then((response) => {
|
this.$modal.msgSuccess("修改成功");
|
this.open = false;
|
this.getList();
|
});
|
} else {
|
addHosp(formData).then((response) => {
|
this.$modal.msgSuccess("新增成功");
|
this.open = false;
|
this.getList();
|
});
|
}
|
}
|
});
|
},
|
handleDelete(row) {
|
const hospAreaIds = row.hospAreaId || this.ids;
|
this.$modal
|
.confirm('是否确认删除院区信息编号为"' + hospAreaIds + '"的数据项?')
|
.then(function () {
|
return delHosp(hospAreaIds);
|
})
|
.then(() => {
|
this.getList();
|
this.$modal.msgSuccess("删除成功");
|
})
|
.catch(() => {});
|
},
|
handleExport() {
|
this.download(
|
"hosp/hosp/export",
|
{
|
...this.queryParams,
|
},
|
`hosp_${new Date().getTime()}.xlsx`
|
);
|
},
|
},
|
};
|
</script>
|
|
<style lang="scss">
|
.pag {
|
width: 100%;
|
display: flex;
|
justify-content: center;
|
}
|
|
.pag1 {
|
width: 30%;
|
}
|
|
.app-container {
|
padding: 20px;
|
}
|
|
.el-form-item {
|
margin-bottom: 10px;
|
}
|
|
/* 调整 TinyMCE 编辑器样式 */
|
.tox-tinymce {
|
border: 1px solid #dcdfe6;
|
border-radius: 4px;
|
}
|
|
/* 提高 TinyMCE 子对话框的 z-index */
|
.tox-dialog-wrap {
|
z-index: 9999 !important; /* 确保高于 el-dialog 的默认 z-index */
|
}
|
|
/* 提高 TinyMCE 下拉菜单的 z-index */
|
.tox-menu {
|
z-index: 9999 !important;
|
}
|
|
/* 提高 TinyMCE 工具栏的 z-index */
|
.tox-toolbar {
|
z-index: 9999 !important;
|
}
|
|
/* 提高 TinyMCE 状态栏的 z-index */
|
.tox-statusbar {
|
z-index: 9999 !important;
|
}
|
|
/* 确保所有 TinyMCE 相关元素都有足够高的 z-index */
|
.tox-tinymce-aux {
|
z-index: 9999 !important;
|
}
|
</style>
|