fix(login): 修复获取用户绑定租户列表时用户名为空导致的URL错误
确保username参数存在,避免因为空值造成接口调用失败 feat(editor): 重构富文本编辑器组件并优化图片上传逻辑 - 使用 Composition API 重构代码结构,提升可维护性 - 改进图片上传功能,增强对 quill 实例的安全访问 - 更新样式排版,提高组件可读性和一致性 refactor(file-upload): 移除旧代理引用,使用 modern Vue API 替换 `proxy` 调用为 `modal` 插件直接调用,提升代码清晰度与健壮性 refactor(image-upload): 替换旧实例调用方式,强化错误提示机制 统一使用 `modal` 进行消息提示和加载状态控制,改善用户体验 refactor(tree-select): 引入 Composition API 优化节点操作逻辑 移除 `getCurrentInstance` 的不必要使用,改为明确的模板引用管理 chore(main): 添加 util._extend 补丁以消除 Node.js 环境警告 解决开发环境下由于 Node.js 内建模块缺失造成的运行时警告问题 feat(template): 完善跌倒/坠床评估护理记录单模板 - 增加详细注释说明各部分作用,便于后续维护 - 明确组件名称为中文,利于业务识别 - 丰富表单交互细节及数据处理逻辑,支持动态打分、措施选择等功能 refactor(template-index): 加强模板组件自动注册逻辑 增加组件 name 属性校验,防止无效或匿名组件被注册到全局
This commit is contained in:
@@ -1,28 +1,16 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-upload
|
||||
:action="uploadUrl"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:on-success="handleUploadSuccess"
|
||||
:on-error="handleUploadError"
|
||||
name="file"
|
||||
:show-file-list="false"
|
||||
:headers="headers"
|
||||
class="editor-img-uploader"
|
||||
v-if="type == 'url'"
|
||||
>
|
||||
<i ref="uploadRef" class="editor-img-uploader"></i>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div class="editor">
|
||||
<quill-editor
|
||||
ref="quillEditorRef"
|
||||
v-model:content="content"
|
||||
contentType="html"
|
||||
@textChange="(e) => $emit('update:modelValue', content)"
|
||||
:options="options"
|
||||
:style="styles"
|
||||
/>
|
||||
<div class="editor-container">
|
||||
<div>
|
||||
<el-upload :action="uploadUrl" :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess"
|
||||
:on-error="handleUploadError" name="file" :show-file-list="false" :headers="headers" class="editor-img-uploader"
|
||||
v-if="type == 'url'">
|
||||
<i ref="uploadRef" class="editor-img-uploader"></i>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div class="editor">
|
||||
<quill-editor ref="quillEditorRef" :content="content" @update:content="content = $event" contentType="html"
|
||||
@textChange="(e) => $emit('update:modelValue', content)" :options="options" :style="styles" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -30,10 +18,11 @@
|
||||
import { QuillEditor } from "@vueup/vue-quill";
|
||||
import "@vueup/vue-quill/dist/vue-quill.snow.css";
|
||||
import { getToken } from "@/utils/auth";
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
import { ref, computed, watch, onMounted } from 'vue';
|
||||
import modal from '@/plugins/modal';
|
||||
|
||||
const quillEditorRef = ref();
|
||||
const uploadRef = ref();
|
||||
const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传的图片服务器地址
|
||||
const headers = ref({
|
||||
Authorization: "Bearer " + getToken()
|
||||
@@ -115,32 +104,34 @@ watch(() => props.modelValue, (v) => {
|
||||
// 如果设置了上传地址则自定义图片上传事件
|
||||
onMounted(() => {
|
||||
if (props.type == 'url') {
|
||||
let quill = quillEditorRef.value.getQuill();
|
||||
let toolbar = quill.getModule("toolbar");
|
||||
toolbar.addHandler("image", (value) => {
|
||||
if (value) {
|
||||
proxy.$refs.uploadRef.click();
|
||||
} else {
|
||||
quill.format("image", false);
|
||||
}
|
||||
});
|
||||
let quill = quillEditorRef.value?.getQuill();
|
||||
if (quill) {
|
||||
let toolbar = quill.getModule("toolbar");
|
||||
toolbar.addHandler("image", (value) => {
|
||||
if (value && uploadRef.value) {
|
||||
uploadRef.value.click();
|
||||
} else {
|
||||
quill.format("image", false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 上传前校检格式和大小
|
||||
function handleBeforeUpload(file) {
|
||||
const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"];
|
||||
const type = ["image/jpeg", "image/jpg", "image/png", "image/svg+xml"];
|
||||
const isJPG = type.includes(file.type);
|
||||
//检验文件格式
|
||||
if (!isJPG) {
|
||||
proxy.$modal.msgError(`图片格式错误!`);
|
||||
modal.msgError(`图片格式错误!`);
|
||||
return false;
|
||||
}
|
||||
// 校检文件大小
|
||||
if (props.fileSize) {
|
||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||
if (!isLt) {
|
||||
proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
|
||||
modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -152,21 +143,24 @@ function handleUploadSuccess(res, file) {
|
||||
// 如果上传成功
|
||||
if (res.code == 200) {
|
||||
// 获取富文本实例
|
||||
let quill = toRaw(quillEditorRef.value).getQuill();
|
||||
// 获取光标位置
|
||||
let length = quill.selection.savedRange.index;
|
||||
// 插入图片,res.url为服务器返回的图片链接地址
|
||||
quill.insertEmbed(length, "image", import.meta.env.VITE_APP_BASE_API + res.fileName);
|
||||
// 调整光标到最后
|
||||
quill.setSelection(length + 1);
|
||||
let quill = quillEditorRef.value?.getQuill();
|
||||
if (quill) {
|
||||
// 获取光标位置
|
||||
let range = quill.selection?.savedRange || quill.getSelection();
|
||||
let length = range?.index || 0;
|
||||
// 插入图片,res.url为服务器返回的图片链接地址
|
||||
quill.insertEmbed(length, "image", import.meta.env.VITE_APP_BASE_API + res.fileName);
|
||||
// 调整光标到最后
|
||||
quill.setSelection(length + 1);
|
||||
}
|
||||
} else {
|
||||
proxy.$modal.msgError("图片插入失败");
|
||||
modal.msgError("图片插入失败");
|
||||
}
|
||||
}
|
||||
|
||||
// 上传失败处理
|
||||
function handleUploadError() {
|
||||
proxy.$modal.msgError("图片插入失败");
|
||||
modal.msgError("图片插入失败");
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -174,78 +168,98 @@ function handleUploadError() {
|
||||
.editor-img-uploader {
|
||||
display: none;
|
||||
}
|
||||
.editor, .ql-toolbar {
|
||||
|
||||
.editor,
|
||||
.ql-toolbar {
|
||||
white-space: pre-wrap !important;
|
||||
line-height: normal !important;
|
||||
}
|
||||
|
||||
.quill-img {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ql-snow .ql-tooltip[data-mode="link"]::before {
|
||||
content: "请输入链接地址:";
|
||||
}
|
||||
|
||||
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
|
||||
border-right: 0px;
|
||||
content: "保存";
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.ql-snow .ql-tooltip[data-mode="video"]::before {
|
||||
content: "请输入视频地址:";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
|
||||
content: "14px";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
|
||||
content: "10px";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
|
||||
content: "18px";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
|
||||
content: "32px";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
|
||||
content: "文本";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
|
||||
content: "标题1";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
|
||||
content: "标题2";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
|
||||
content: "标题3";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
|
||||
content: "标题4";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
|
||||
content: "标题5";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
|
||||
content: "标题6";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
|
||||
content: "标准字体";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
|
||||
content: "衬线字体";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
|
||||
content: "等宽字体";
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
@@ -39,7 +39,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { getToken } from "@/utils/auth";
|
||||
import modal from '@/plugins/modal';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: [String, Object, Array],
|
||||
@@ -65,7 +67,7 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const fileUpload = ref(null);
|
||||
const emit = defineEmits();
|
||||
const number = ref(0);
|
||||
const uploadList = ref([]);
|
||||
@@ -104,7 +106,7 @@ function handleBeforeUpload(file) {
|
||||
const fileExt = fileName[fileName.length - 1];
|
||||
const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
|
||||
if (!isTypeOk) {
|
||||
proxy.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`);
|
||||
modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -112,23 +114,23 @@ function handleBeforeUpload(file) {
|
||||
if (props.fileSize) {
|
||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||
if (!isLt) {
|
||||
proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
|
||||
modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
proxy.$modal.loading("正在上传文件,请稍候...");
|
||||
modal.loading("正在上传文件,请稍候...");
|
||||
number.value++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 文件个数超出
|
||||
function handleExceed() {
|
||||
proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
|
||||
modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
|
||||
}
|
||||
|
||||
// 上传失败
|
||||
function handleUploadError(err) {
|
||||
proxy.$modal.msgError("上传文件失败");
|
||||
modal.msgError("上传文件失败");
|
||||
}
|
||||
|
||||
// 上传成功回调
|
||||
@@ -138,9 +140,9 @@ function handleUploadSuccess(res, file) {
|
||||
uploadedSuccessfully();
|
||||
} else {
|
||||
number.value--;
|
||||
proxy.$modal.closeLoading();
|
||||
proxy.$modal.msgError(res.msg);
|
||||
proxy.$refs.fileUpload.handleRemove(file);
|
||||
modal.closeLoading();
|
||||
modal.msgError(res.msg);
|
||||
fileUpload.value.handleRemove(file);
|
||||
uploadedSuccessfully();
|
||||
}
|
||||
}
|
||||
@@ -158,7 +160,7 @@ function uploadedSuccessfully() {
|
||||
uploadList.value = [];
|
||||
number.value = 0;
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
proxy.$modal.closeLoading();
|
||||
modal.closeLoading();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,4 +206,4 @@ function listToString(list, separator) {
|
||||
.ele-upload-list__item-content-action .el-link {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
@@ -47,6 +47,8 @@
|
||||
|
||||
<script setup>
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { ref, computed, watch, getCurrentInstance } from 'vue';
|
||||
import modal from '@/plugins/modal';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: [String, Object, Array],
|
||||
@@ -72,7 +74,6 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const emit = defineEmits();
|
||||
const number = ref(0);
|
||||
const uploadList = ref([]);
|
||||
@@ -82,6 +83,7 @@ const baseUrl = import.meta.env.VITE_APP_BASE_API;
|
||||
const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传的图片服务器地址
|
||||
const headers = ref({ Authorization: "Bearer " + getToken() });
|
||||
const fileList = ref([]);
|
||||
const imageUpload = ref(null);
|
||||
const showTip = computed(
|
||||
() => props.isShowTip && (props.fileType || props.fileSize)
|
||||
);
|
||||
@@ -124,7 +126,7 @@ function handleBeforeUpload(file) {
|
||||
isImg = file.type.indexOf("image") > -1;
|
||||
}
|
||||
if (!isImg) {
|
||||
proxy.$modal.msgError(
|
||||
modal.msgError(
|
||||
`文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
|
||||
);
|
||||
return false;
|
||||
@@ -132,17 +134,17 @@ function handleBeforeUpload(file) {
|
||||
if (props.fileSize) {
|
||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||
if (!isLt) {
|
||||
proxy.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
|
||||
modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
proxy.$modal.loading("正在上传图片,请稍候...");
|
||||
modal.loading("正在上传图片,请稍候...");
|
||||
number.value++;
|
||||
}
|
||||
|
||||
// 文件个数超出
|
||||
function handleExceed() {
|
||||
proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
|
||||
modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
|
||||
}
|
||||
|
||||
// 上传成功回调
|
||||
@@ -152,9 +154,9 @@ function handleUploadSuccess(res, file) {
|
||||
uploadedSuccessfully();
|
||||
} else {
|
||||
number.value--;
|
||||
proxy.$modal.closeLoading();
|
||||
proxy.$modal.msgError(res.msg);
|
||||
proxy.$refs.imageUpload.handleRemove(file);
|
||||
modal.closeLoading();
|
||||
modal.msgError(res.msg);
|
||||
imageUpload.value.handleRemove(file);
|
||||
uploadedSuccessfully();
|
||||
}
|
||||
}
|
||||
@@ -176,14 +178,14 @@ function uploadedSuccessfully() {
|
||||
uploadList.value = [];
|
||||
number.value = 0;
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
proxy.$modal.closeLoading();
|
||||
modal.closeLoading();
|
||||
}
|
||||
}
|
||||
|
||||
// 上传失败
|
||||
function handleUploadError() {
|
||||
proxy.$modal.msgError("上传图片失败");
|
||||
proxy.$modal.closeLoading();
|
||||
modal.msgError("上传图片失败");
|
||||
modal.closeLoading();
|
||||
}
|
||||
|
||||
// 预览
|
||||
|
||||
@@ -29,8 +29,11 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, onMounted, nextTick } from 'vue';
|
||||
import { getCurrentInstance } from 'vue';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const selectTree = ref(null);
|
||||
const treeSelect = ref(null);
|
||||
|
||||
const props = defineProps({
|
||||
/* 配置项 */
|
||||
@@ -83,10 +86,10 @@ function initHandle() {
|
||||
nextTick(() => {
|
||||
const selectedValue = valueId.value;
|
||||
if(selectedValue !== null && typeof (selectedValue) !== 'undefined') {
|
||||
const node = proxy.$refs.selectTree.getNode(selectedValue)
|
||||
const node = selectTree.value.getNode(selectedValue)
|
||||
if (node) {
|
||||
valueTitle.value = node.data[props.objMap.label]
|
||||
proxy.$refs.selectTree.setCurrentKey(selectedValue) // 设置默认选中
|
||||
selectTree.value.setCurrentKey(selectedValue) // 设置默认选中
|
||||
defaultExpandedKey.value = [selectedValue] // 设置默认展开
|
||||
}
|
||||
} else {
|
||||
@@ -98,11 +101,11 @@ function handleNodeClick(node) {
|
||||
valueTitle.value = node[props.objMap.label]
|
||||
valueId.value = node[props.objMap.value];
|
||||
defaultExpandedKey.value = [];
|
||||
proxy.$refs.treeSelect.blur()
|
||||
treeSelect.value.blur()
|
||||
selectFilterData('')
|
||||
}
|
||||
function selectFilterData(val) {
|
||||
proxy.$refs.selectTree.filter(val)
|
||||
selectTree.value.filter(val)
|
||||
}
|
||||
function filterNode(value, data) {
|
||||
if (!value) return true
|
||||
|
||||
Reference in New Issue
Block a user