update 调整代码格式
This commit is contained in:
@ -1,3 +1,15 @@
|
||||
<template>
|
||||
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
|
||||
<span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{
|
||||
item.meta?.title }}</span>
|
||||
<a v-else @click.prevent="handleLink(item)">{{ item.meta?.title }}</a>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { RouteLocationMatched } from 'vue-router'
|
||||
|
||||
@ -6,49 +18,37 @@ const router = useRouter();
|
||||
const levelList = ref<RouteLocationMatched[]>([])
|
||||
|
||||
const getBreadcrumb = () => {
|
||||
// only show routes with meta.title
|
||||
let matched = route.matched.filter(item => item.meta && item.meta.title);
|
||||
const first = matched[0]
|
||||
// 判断是否为首页
|
||||
if (!isDashboard(first)) {
|
||||
matched = ([{ path: '/index', meta: { title: '首页' } }] as any).concat(matched)
|
||||
}
|
||||
levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
|
||||
// only show routes with meta.title
|
||||
let matched = route.matched.filter(item => item.meta && item.meta.title);
|
||||
const first = matched[0]
|
||||
// 判断是否为首页
|
||||
if (!isDashboard(first)) {
|
||||
matched = ([{ path: '/index', meta: { title: '首页' } }] as any).concat(matched)
|
||||
}
|
||||
levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
|
||||
}
|
||||
const isDashboard = (route: RouteLocationMatched) => {
|
||||
const name = route && route.name as string
|
||||
if (!name) {
|
||||
return false
|
||||
}
|
||||
return name.trim() === 'Index'
|
||||
const name = route && route.name as string
|
||||
if (!name) {
|
||||
return false
|
||||
}
|
||||
return name.trim() === 'Index'
|
||||
}
|
||||
const handleLink = (item: RouteLocationMatched) => {
|
||||
const { redirect, path } = item
|
||||
redirect ? router.push(redirect as string) : router.push(path)
|
||||
const { redirect, path } = item
|
||||
redirect ? router.push(redirect as string) : router.push(path)
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
// if you go to the redirect page, do not update the breadcrumbs
|
||||
if (route.path.startsWith('/redirect/')) return
|
||||
getBreadcrumb()
|
||||
// if you go to the redirect page, do not update the breadcrumbs
|
||||
if (route.path.startsWith('/redirect/')) return
|
||||
getBreadcrumb()
|
||||
})
|
||||
onMounted(() => {
|
||||
getBreadcrumb();
|
||||
getBreadcrumb();
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
|
||||
<span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{
|
||||
item.meta?.title }}</span>
|
||||
<a v-else @click.prevent="handleLink(item)">{{ item.meta?.title }}</a>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-breadcrumb.el-breadcrumb {
|
||||
display: inline-block;
|
||||
|
@ -1,50 +1,50 @@
|
||||
<template>
|
||||
<div>
|
||||
<template v-for="(item, index) in options">
|
||||
<template v-if="values.includes(item.value)">
|
||||
<span
|
||||
v-if="item.elTagType == 'default' || item.elTagType == ''"
|
||||
:key="item.value"
|
||||
:index="index"
|
||||
:class="item.elTagClass"
|
||||
>{{ item.label }}</span
|
||||
>
|
||||
<el-tag
|
||||
v-else
|
||||
:disable-transitions="true"
|
||||
:key="item.value + ''"
|
||||
:index="index"
|
||||
:type="item.elTagType === 'primary' ? '' : item.elTagType"
|
||||
:class="item.elTagClass"
|
||||
>{{ item.label }}</el-tag
|
||||
>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PropType } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
// 数据
|
||||
options: {
|
||||
type: Array as PropType<DictDataOption[]>,
|
||||
default: null,
|
||||
},
|
||||
// 当前的值
|
||||
value: [Number, String, Array],
|
||||
// 数据
|
||||
options: {
|
||||
type: Array as PropType<DictDataOption[]>,
|
||||
default: null,
|
||||
},
|
||||
// 当前的值
|
||||
value: [Number, String, Array],
|
||||
})
|
||||
|
||||
const values = computed(() => {
|
||||
if (props.value !== null && typeof props.value !== 'undefined') {
|
||||
return Array.isArray(props.value) ? props.value : [String(props.value)];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
if (props.value !== null && typeof props.value !== 'undefined') {
|
||||
return Array.isArray(props.value) ? props.value : [String(props.value)];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<template v-for="(item, index) in options">
|
||||
<template v-if="values.includes(item.value)">
|
||||
<span
|
||||
v-if="item.elTagType == 'default' || item.elTagType == ''"
|
||||
:key="item.value"
|
||||
:index="index"
|
||||
:class="item.elTagClass"
|
||||
>{{ item.label }}</span
|
||||
>
|
||||
<el-tag
|
||||
v-else
|
||||
:disable-transitions="true"
|
||||
:key="item.value + ''"
|
||||
:index="index"
|
||||
:type="item.elTagType === 'primary' ? '' : item.elTagType"
|
||||
:class="item.elTagClass"
|
||||
>{{ item.label }}</el-tag
|
||||
>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.el-tag + .el-tag {
|
||||
margin-left: 10px;
|
||||
|
@ -1,3 +1,31 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-upload
|
||||
:action="upload.url"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:on-success="handleUploadSuccess"
|
||||
:on-error="handleUploadError"
|
||||
class="editor-img-uploader"
|
||||
name="file"
|
||||
:show-file-list="false"
|
||||
:headers="upload.headers"
|
||||
style="display: none"
|
||||
v-if="type === 'url'"
|
||||
>
|
||||
</el-upload>
|
||||
<div class="editor">
|
||||
<quill-editor
|
||||
ref="myQuillEditor"
|
||||
v-model:content="content"
|
||||
contentType="html"
|
||||
@textChange="(e: any) => $emit('update:modelValue', content)"
|
||||
:options="options"
|
||||
:style="styles"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { QuillEditor, Quill } from '@vueup/vue-quill';
|
||||
import '@vueup/vue-quill/dist/vue-quill.snow.css';
|
||||
@ -5,166 +33,138 @@ import { getToken } from "@/utils/auth";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
/* 编辑器的内容 */
|
||||
modelValue: {
|
||||
type: String,
|
||||
},
|
||||
/* 高度 */
|
||||
height: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
/* 最小高度 */
|
||||
minHeight: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
/* 只读 */
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/* 上传文件大小限制(MB) */
|
||||
fileSize: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
/* 类型(base64格式、url格式) */
|
||||
type: {
|
||||
type: String,
|
||||
default: "url",
|
||||
}
|
||||
/* 编辑器的内容 */
|
||||
modelValue: {
|
||||
type: String,
|
||||
},
|
||||
/* 高度 */
|
||||
height: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
/* 最小高度 */
|
||||
minHeight: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
/* 只读 */
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/* 上传文件大小限制(MB) */
|
||||
fileSize: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
/* 类型(base64格式、url格式) */
|
||||
type: {
|
||||
type: String,
|
||||
default: "url",
|
||||
}
|
||||
});
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
const upload = reactive<UploadOption>({
|
||||
headers: { Authorization: "Bearer " + getToken() },
|
||||
url: import.meta.env.VITE_APP_BASE_API + '/system/oss/upload'
|
||||
headers: { Authorization: "Bearer " + getToken() },
|
||||
url: import.meta.env.VITE_APP_BASE_API + '/system/oss/upload'
|
||||
})
|
||||
const myQuillEditor = ref();
|
||||
|
||||
const options = ref({
|
||||
theme: "snow",
|
||||
bounds: document.body,
|
||||
debug: "warn",
|
||||
modules: {
|
||||
// 工具栏配置
|
||||
toolbar: {
|
||||
container: [
|
||||
["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
|
||||
["blockquote", "code-block"], // 引用 代码块
|
||||
[{ list: "ordered" }, { list: "bullet"} ], // 有序、无序列表
|
||||
[{ indent: "-1" }, { indent: "+1" }], // 缩进
|
||||
[{ size: ["small", false, "large", "huge"] }], // 字体大小
|
||||
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
|
||||
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
|
||||
[{ align: [] }], // 对齐方式
|
||||
["clean"], // 清除文本格式
|
||||
["link", "image", "video"] // 链接、图片、视频
|
||||
],
|
||||
handlers: {
|
||||
image: function (value: any) {
|
||||
if (value) {
|
||||
// 调用element图片上传
|
||||
(document.querySelector(".editor-img-uploader>.el-upload") as HTMLDivElement)?.click();
|
||||
} else {
|
||||
Quill.format("image", true);
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
placeholder: '请输入内容',
|
||||
readOnly: props.readOnly,
|
||||
theme: "snow",
|
||||
bounds: document.body,
|
||||
debug: "warn",
|
||||
modules: {
|
||||
// 工具栏配置
|
||||
toolbar: {
|
||||
container: [
|
||||
["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
|
||||
["blockquote", "code-block"], // 引用 代码块
|
||||
[{ list: "ordered" }, { list: "bullet"} ], // 有序、无序列表
|
||||
[{ indent: "-1" }, { indent: "+1" }], // 缩进
|
||||
[{ size: ["small", false, "large", "huge"] }], // 字体大小
|
||||
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
|
||||
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
|
||||
[{ align: [] }], // 对齐方式
|
||||
["clean"], // 清除文本格式
|
||||
["link", "image", "video"] // 链接、图片、视频
|
||||
],
|
||||
handlers: {
|
||||
image: function (value: any) {
|
||||
if (value) {
|
||||
// 调用element图片上传
|
||||
(document.querySelector(".editor-img-uploader>.el-upload") as HTMLDivElement)?.click();
|
||||
} else {
|
||||
Quill.format("image", true);
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
placeholder: '请输入内容',
|
||||
readOnly: props.readOnly,
|
||||
});
|
||||
|
||||
const styles = computed(() => {
|
||||
let style: any = {};
|
||||
if (props.minHeight) {
|
||||
style.minHeight = `${props.minHeight}px`;
|
||||
}
|
||||
if (props.height) {
|
||||
style.height = `${props.height}px`;
|
||||
}
|
||||
return style;
|
||||
let style: any = {};
|
||||
if (props.minHeight) {
|
||||
style.minHeight = `${props.minHeight}px`;
|
||||
}
|
||||
if (props.height) {
|
||||
style.height = `${props.height}px`;
|
||||
}
|
||||
return style;
|
||||
})
|
||||
|
||||
const content = ref("");
|
||||
watch(() => props.modelValue, (v) => {
|
||||
if (v !== content.value) {
|
||||
content.value = v === undefined ? "<p></p>" : v;
|
||||
}
|
||||
if (v !== content.value) {
|
||||
content.value = v === undefined ? "<p></p>" : v;
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
// 图片上传成功返回图片地址
|
||||
const handleUploadSuccess = (res: any) => {
|
||||
// 获取富文本实例
|
||||
let quill = toRaw(myQuillEditor.value).getQuill();
|
||||
// 如果上传成功
|
||||
if (res.code === 200) {
|
||||
// 获取光标位置
|
||||
let length = quill.selection.savedRange.index;
|
||||
// 插入图片,res为服务器返回的图片链接地址
|
||||
quill.insertEmbed(length, "image", res.data.url);
|
||||
// 调整光标到最后
|
||||
quill.setSelection(length + 1);
|
||||
proxy?.$modal.closeLoading();
|
||||
} else {
|
||||
proxy?.$modal.loading(res.msg);
|
||||
proxy?.$modal.closeLoading();
|
||||
}
|
||||
// 获取富文本实例
|
||||
let quill = toRaw(myQuillEditor.value).getQuill();
|
||||
// 如果上传成功
|
||||
if (res.code === 200) {
|
||||
// 获取光标位置
|
||||
let length = quill.selection.savedRange.index;
|
||||
// 插入图片,res为服务器返回的图片链接地址
|
||||
quill.insertEmbed(length, "image", res.data.url);
|
||||
// 调整光标到最后
|
||||
quill.setSelection(length + 1);
|
||||
proxy?.$modal.closeLoading();
|
||||
} else {
|
||||
proxy?.$modal.loading(res.msg);
|
||||
proxy?.$modal.closeLoading();
|
||||
}
|
||||
}
|
||||
|
||||
// 图片上传前拦截
|
||||
const handleBeforeUpload = (file: any) => {
|
||||
// 校检文件大小
|
||||
if (props.fileSize) {
|
||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||
if (!isLt) {
|
||||
proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
|
||||
return false;
|
||||
// 校检文件大小
|
||||
if (props.fileSize) {
|
||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||
if (!isLt) {
|
||||
proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
proxy?.$modal.loading('正在上传文件,请稍候...');
|
||||
return true;
|
||||
proxy?.$modal.loading('正在上传文件,请稍候...');
|
||||
return true;
|
||||
}
|
||||
|
||||
// 图片失败拦截
|
||||
const handleUploadError = (err: any) => {
|
||||
console.error(err);
|
||||
proxy?.$modal.msgError('上传文件失败');
|
||||
console.error(err);
|
||||
proxy?.$modal.msgError('上传文件失败');
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<el-upload
|
||||
:action="upload.url"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:on-success="handleUploadSuccess"
|
||||
:on-error="handleUploadError"
|
||||
class="editor-img-uploader"
|
||||
name="file"
|
||||
:show-file-list="false"
|
||||
:headers="upload.headers"
|
||||
style="display: none"
|
||||
v-if="type === 'url'"
|
||||
>
|
||||
</el-upload>
|
||||
<div class="editor">
|
||||
<quill-editor
|
||||
ref="myQuillEditor"
|
||||
v-model:content="content"
|
||||
contentType="html"
|
||||
@textChange="(e: any) => $emit('update:modelValue', content)"
|
||||
:options="options"
|
||||
:style="styles"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.editor, .ql-toolbar {
|
||||
white-space: pre-wrap !important;
|
||||
|
@ -1,3 +1,47 @@
|
||||
<template>
|
||||
<div class="upload-file">
|
||||
<el-upload
|
||||
multiple
|
||||
:action="uploadFileUrl"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:file-list="fileList"
|
||||
:limit="limit"
|
||||
:on-error="handleUploadError"
|
||||
:on-exceed="handleExceed"
|
||||
:on-success="handleUploadSuccess"
|
||||
:show-file-list="false"
|
||||
:headers="headers"
|
||||
class="upload-file-uploader"
|
||||
ref="fileUploadRef"
|
||||
>
|
||||
<!-- 上传按钮 -->
|
||||
<el-button type="primary">选取文件</el-button>
|
||||
</el-upload>
|
||||
<!-- 上传提示 -->
|
||||
<div class="el-upload__tip" v-if="showTip">
|
||||
请上传
|
||||
<template v-if="fileSize">
|
||||
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
|
||||
</template>
|
||||
<template v-if="fileType">
|
||||
格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
|
||||
</template>
|
||||
的文件
|
||||
</div>
|
||||
<!-- 文件列表 -->
|
||||
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
|
||||
<li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
|
||||
<el-link :href="`${file.url}`" :underline="false" target="_blank">
|
||||
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
|
||||
</el-link>
|
||||
<div class="ele-upload-list__item-content-action">
|
||||
<el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
|
||||
</div>
|
||||
</li>
|
||||
</transition-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { listByIds, delOss } from "@/api/system/oss";
|
||||
@ -5,27 +49,27 @@ import { ComponentInternalInstance } from "vue";
|
||||
import { ElUpload, UploadFile } from "element-plus";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: [String, Object, Array],
|
||||
// 数量限制
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
// 大小限制(MB)
|
||||
fileSize: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
// 文件类型, 例如['png', 'jpg', 'jpeg']
|
||||
fileType: {
|
||||
type: Array,
|
||||
default: () => ["doc", "xls", "ppt", "txt", "pdf"],
|
||||
},
|
||||
// 是否显示提示
|
||||
isShowTip: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
modelValue: [String, Object, Array],
|
||||
// 数量限制
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
// 大小限制(MB)
|
||||
fileSize: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
// 文件类型, 例如['png', 'jpg', 'jpeg']
|
||||
fileType: {
|
||||
type: Array,
|
||||
default: () => ["doc", "xls", "ppt", "txt", "pdf"],
|
||||
},
|
||||
// 是否显示提示
|
||||
isShowTip: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
});
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@ -39,172 +83,128 @@ const headers = ref({ Authorization: "Bearer " + getToken() });
|
||||
|
||||
const fileList = ref<any[]>([]);
|
||||
const showTip = computed(
|
||||
() => props.isShowTip && (props.fileType || props.fileSize)
|
||||
() => props.isShowTip && (props.fileType || props.fileSize)
|
||||
);
|
||||
|
||||
const fileUploadRef = ref(ElUpload);
|
||||
|
||||
watch(() => props.modelValue, async val => {
|
||||
if (val) {
|
||||
let temp = 1;
|
||||
// 首先将值转为数组
|
||||
let list = [];
|
||||
if (Array.isArray(val)) {
|
||||
list = val;
|
||||
} else {
|
||||
const res = await listByIds(val as string)
|
||||
list = res.data.map((oss) => {
|
||||
const data = { name: oss.originalName, url: oss.url, ossId: oss.ossId };
|
||||
return data;
|
||||
if (val) {
|
||||
let temp = 1;
|
||||
// 首先将值转为数组
|
||||
let list = [];
|
||||
if (Array.isArray(val)) {
|
||||
list = val;
|
||||
} else {
|
||||
const res = await listByIds(val as string)
|
||||
list = res.data.map((oss) => {
|
||||
const data = { name: oss.originalName, url: oss.url, ossId: oss.ossId };
|
||||
return data;
|
||||
});
|
||||
}
|
||||
// 然后将数组转为对象数组
|
||||
fileList.value = list.map(item => {
|
||||
item = {name: item.name, url: item.url, ossId: item.ossId};
|
||||
item.uid = item.uid || new Date().getTime() + temp++;
|
||||
return item;
|
||||
});
|
||||
} else {
|
||||
fileList.value = [];
|
||||
return [];
|
||||
}
|
||||
// 然后将数组转为对象数组
|
||||
fileList.value = list.map(item => {
|
||||
item = {name: item.name, url: item.url, ossId: item.ossId};
|
||||
item.uid = item.uid || new Date().getTime() + temp++;
|
||||
return item;
|
||||
});
|
||||
} else {
|
||||
fileList.value = [];
|
||||
return [];
|
||||
}
|
||||
},{ deep: true, immediate: true });
|
||||
|
||||
// 上传前校检格式和大小
|
||||
const handleBeforeUpload = (file: any) => {
|
||||
// 校检文件类型
|
||||
if (props.fileType.length) {
|
||||
const fileName = file.name.split('.');
|
||||
const fileExt = fileName[fileName.length - 1];
|
||||
const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
|
||||
if (!isTypeOk) {
|
||||
proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`);
|
||||
return false;
|
||||
// 校检文件类型
|
||||
if (props.fileType.length) {
|
||||
const fileName = file.name.split('.');
|
||||
const fileExt = fileName[fileName.length - 1];
|
||||
const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
|
||||
if (!isTypeOk) {
|
||||
proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 校检文件大小
|
||||
if (props.fileSize) {
|
||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||
if (!isLt) {
|
||||
proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
|
||||
return false;
|
||||
// 校检文件大小
|
||||
if (props.fileSize) {
|
||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||
if (!isLt) {
|
||||
proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
proxy?.$modal.loading("正在上传文件,请稍候...");
|
||||
number.value++;
|
||||
return true;
|
||||
proxy?.$modal.loading("正在上传文件,请稍候...");
|
||||
number.value++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 文件个数超出
|
||||
const handleExceed = () => {
|
||||
proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
|
||||
proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
|
||||
}
|
||||
|
||||
// 上传失败
|
||||
const handleUploadError = () => {
|
||||
proxy?.$modal.msgError("上传文件失败");
|
||||
proxy?.$modal.msgError("上传文件失败");
|
||||
}
|
||||
|
||||
// 上传成功回调
|
||||
const handleUploadSuccess = (res:any, file: UploadFile) => {
|
||||
if (res.code === 200) {
|
||||
uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
|
||||
uploadedSuccessfully();
|
||||
} else {
|
||||
number.value--;
|
||||
proxy?.$modal.closeLoading();
|
||||
proxy?.$modal.msgError(res.msg);
|
||||
fileUploadRef.value.handleRemove(file);
|
||||
uploadedSuccessfully();
|
||||
}
|
||||
if (res.code === 200) {
|
||||
uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
|
||||
uploadedSuccessfully();
|
||||
} else {
|
||||
number.value--;
|
||||
proxy?.$modal.closeLoading();
|
||||
proxy?.$modal.msgError(res.msg);
|
||||
fileUploadRef.value.handleRemove(file);
|
||||
uploadedSuccessfully();
|
||||
}
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
const handleDelete = (index: number) => {
|
||||
let ossId = fileList.value[index].ossId;
|
||||
delOss(ossId);
|
||||
fileList.value.splice(index, 1);
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
let ossId = fileList.value[index].ossId;
|
||||
delOss(ossId);
|
||||
fileList.value.splice(index, 1);
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
}
|
||||
|
||||
// 上传结束处理
|
||||
const uploadedSuccessfully =() => {
|
||||
if (number.value > 0 && uploadList.value.length === number.value) {
|
||||
fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
|
||||
uploadList.value = [];
|
||||
number.value = 0;
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
proxy?.$modal.closeLoading();
|
||||
}
|
||||
if (number.value > 0 && uploadList.value.length === number.value) {
|
||||
fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
|
||||
uploadList.value = [];
|
||||
number.value = 0;
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
proxy?.$modal.closeLoading();
|
||||
}
|
||||
}
|
||||
|
||||
// 获取文件名称
|
||||
const getFileName = (name: string) => {
|
||||
// 如果是url那么取最后的名字 如果不是直接返回
|
||||
if (name.lastIndexOf("/") > -1) {
|
||||
return name.slice(name.lastIndexOf("/") + 1);
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
// 如果是url那么取最后的名字 如果不是直接返回
|
||||
if (name.lastIndexOf("/") > -1) {
|
||||
return name.slice(name.lastIndexOf("/") + 1);
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// 对象转成指定字符串分隔
|
||||
const listToString = (list: any[], separator?: string) => {
|
||||
let strs = "";
|
||||
separator = separator || ",";
|
||||
list.forEach(item => {
|
||||
if (item.ossId) {
|
||||
strs += item.ossId + separator;
|
||||
}
|
||||
})
|
||||
return strs != "" ? strs.substring(0, strs.length - 1) : "";
|
||||
let strs = "";
|
||||
separator = separator || ",";
|
||||
list.forEach(item => {
|
||||
if (item.ossId) {
|
||||
strs += item.ossId + separator;
|
||||
}
|
||||
})
|
||||
return strs != "" ? strs.substring(0, strs.length - 1) : "";
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="upload-file">
|
||||
<el-upload
|
||||
multiple
|
||||
:action="uploadFileUrl"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:file-list="fileList"
|
||||
:limit="limit"
|
||||
:on-error="handleUploadError"
|
||||
:on-exceed="handleExceed"
|
||||
:on-success="handleUploadSuccess"
|
||||
:show-file-list="false"
|
||||
:headers="headers"
|
||||
class="upload-file-uploader"
|
||||
ref="fileUploadRef"
|
||||
>
|
||||
<!-- 上传按钮 -->
|
||||
<el-button type="primary">选取文件</el-button>
|
||||
</el-upload>
|
||||
<!-- 上传提示 -->
|
||||
<div class="el-upload__tip" v-if="showTip">
|
||||
请上传
|
||||
<template v-if="fileSize">
|
||||
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
|
||||
</template>
|
||||
<template v-if="fileType">
|
||||
格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
|
||||
</template>
|
||||
的文件
|
||||
</div>
|
||||
<!-- 文件列表 -->
|
||||
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
|
||||
<li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
|
||||
<el-link :href="`${file.url}`" :underline="false" target="_blank">
|
||||
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
|
||||
</el-link>
|
||||
<div class="ele-upload-list__item-content-action">
|
||||
<el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
|
||||
</div>
|
||||
</li>
|
||||
</transition-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.upload-file-uploader {
|
||||
margin-bottom: 5px;
|
||||
|
@ -13,13 +13,13 @@ const toggleClick = () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div style="padding: 0 15px;" @click="toggleClick">
|
||||
<svg :class="{'is-active':isActive}" class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
|
||||
<path
|
||||
d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div style="padding: 0 15px;" @click="toggleClick">
|
||||
<svg :class="{'is-active':isActive}" class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
|
||||
<path
|
||||
d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
@ -122,22 +122,22 @@ watch(searchPool, (list) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="{ 'show': show }" class="header-search">
|
||||
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
|
||||
<el-select
|
||||
ref="headerSearchSelectRef"
|
||||
v-model="search"
|
||||
:remote-method="querySearch"
|
||||
filterable
|
||||
default-first-option
|
||||
remote
|
||||
placeholder="Search"
|
||||
class="header-search-select"
|
||||
@change="change"
|
||||
>
|
||||
<el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div :class="{ 'show': show }" class="header-search">
|
||||
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
|
||||
<el-select
|
||||
ref="headerSearchSelectRef"
|
||||
v-model="search"
|
||||
:remote-method="querySearch"
|
||||
filterable
|
||||
default-first-option
|
||||
remote
|
||||
placeholder="Search"
|
||||
class="header-search-select"
|
||||
@change="change"
|
||||
>
|
||||
<el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -44,34 +44,34 @@ const selectedIcon = (iconName: string) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative" :style="{ width: width }">
|
||||
<el-input v-model="modelValue" readonly @click="visible = !visible" placeholder="点击选择图标">
|
||||
<template #prepend>
|
||||
<svg-icon :icon-class="modelValue as string"></svg-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
<div class="relative" :style="{ width: width }">
|
||||
<el-input v-model="modelValue" readonly @click="visible = !visible" placeholder="点击选择图标">
|
||||
<template #prepend>
|
||||
<svg-icon :icon-class="modelValue as string"></svg-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-popover shadow="none" :visible="visible" placement="bottom-end" trigger="click" :width="450">
|
||||
<template #reference>
|
||||
<div @click="visible = !visible" class="cursor-pointer text-[#999] absolute right-[10px] top-0 height-[32px] leading-[32px]">
|
||||
<i-ep-caret-top v-show="visible"></i-ep-caret-top>
|
||||
<i-ep-caret-bottom v-show="!visible"></i-ep-caret-bottom>
|
||||
</div>
|
||||
</template>
|
||||
<el-popover shadow="none" :visible="visible" placement="bottom-end" trigger="click" :width="450">
|
||||
<template #reference>
|
||||
<div @click="visible = !visible" class="cursor-pointer text-[#999] absolute right-[10px] top-0 height-[32px] leading-[32px]">
|
||||
<i-ep-caret-top v-show="visible"></i-ep-caret-top>
|
||||
<i-ep-caret-bottom v-show="!visible"></i-ep-caret-bottom>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-input class="p-2" v-model="filterValue" placeholder="搜索图标" clearable @input="filterIcons" />
|
||||
<el-input class="p-2" v-model="filterValue" placeholder="搜索图标" clearable @input="filterIcons" />
|
||||
|
||||
<el-scrollbar height="w-[200px]">
|
||||
<ul class="icon-list">
|
||||
<el-tooltip v-for="(iconName, index) in iconNames" :key="index" :content="iconName" placement="bottom" effect="light">
|
||||
<li class="icon-item" @click="selectedIcon(iconName)">
|
||||
<svg-icon color="var(--el-text-color-regular)" :icon-class="iconName" />
|
||||
</li>
|
||||
</el-tooltip>
|
||||
</ul>
|
||||
</el-scrollbar>
|
||||
</el-popover>
|
||||
</div>
|
||||
<el-scrollbar height="w-[200px]">
|
||||
<ul class="icon-list">
|
||||
<el-tooltip v-for="(iconName, index) in iconNames" :key="index" :content="iconName" placement="bottom" effect="light">
|
||||
<li class="icon-item" @click="selectedIcon(iconName)">
|
||||
<svg-icon color="var(--el-text-color-regular)" :icon-class="iconName" />
|
||||
</li>
|
||||
</el-tooltip>
|
||||
</ul>
|
||||
</el-scrollbar>
|
||||
</el-popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
@ -1,7 +1,7 @@
|
||||
const icons: string[] = [];
|
||||
const modules = import.meta.glob('./../../assets/icons/svg/*.svg');
|
||||
for (const path in modules) {
|
||||
const p = path.split('assets/icons/svg/')[1].split('.svg')[0];
|
||||
icons.push(p);
|
||||
const p = path.split('assets/icons/svg/')[1].split('.svg')[0];
|
||||
icons.push(p);
|
||||
}
|
||||
export default icons;
|
||||
|
@ -44,13 +44,13 @@ const realHeight = computed(() =>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-image :src="`${realSrc}`" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="realSrcList" preview-teleported>
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<el-icon><picture-filled /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
<el-image :src="`${realSrc}`" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="realSrcList" preview-teleported>
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<el-icon><picture-filled /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -1,3 +1,42 @@
|
||||
<template>
|
||||
<div class="component-upload-image">
|
||||
<el-upload
|
||||
multiple
|
||||
:action="uploadImgUrl"
|
||||
list-type="picture-card"
|
||||
:on-success="handleUploadSuccess"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:limit="limit"
|
||||
:on-error="handleUploadError"
|
||||
:on-exceed="handleExceed"
|
||||
ref="imageUpload"
|
||||
:before-remove="handleDelete"
|
||||
:show-file-list="true"
|
||||
:headers="headers"
|
||||
:file-list="fileList"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:class="{ hide: fileList.length >= limit }"
|
||||
>
|
||||
<el-icon class="avatar-uploader-icon"><plus /></el-icon>
|
||||
</el-upload>
|
||||
<!-- 上传提示 -->
|
||||
<div class="el-upload__tip" v-if="showTip">
|
||||
请上传
|
||||
<template v-if="fileSize">
|
||||
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
|
||||
</template>
|
||||
<template v-if="fileType">
|
||||
格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
|
||||
</template>
|
||||
的文件
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="dialogVisible" title="预览" width="800px" append-to-body>
|
||||
<img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { listByIds, delOss } from "@/api/system/oss";
|
||||
@ -6,27 +45,27 @@ import { OssVO } from "@/api/system/oss/types";
|
||||
import { ElUpload, UploadFile } from "element-plus";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: [String, Object, Array],
|
||||
// 图片数量限制
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
// 大小限制(MB)
|
||||
fileSize: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
// 文件类型, 例如['png', 'jpg', 'jpeg']
|
||||
fileType: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => ["png", "jpg", "jpeg"],
|
||||
},
|
||||
// 是否显示提示
|
||||
isShowTip: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
modelValue: [String, Object, Array],
|
||||
// 图片数量限制
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
// 大小限制(MB)
|
||||
fileSize: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
// 文件类型, 例如['png', 'jpg', 'jpeg']
|
||||
fileType: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => ["png", "jpg", "jpeg"],
|
||||
},
|
||||
// 是否显示提示
|
||||
isShowTip: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
});
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@ -42,179 +81,140 @@ const headers = ref({ Authorization: "Bearer " + getToken() });
|
||||
|
||||
const fileList = ref<any[]>([]);
|
||||
const showTip = computed(
|
||||
() => props.isShowTip && (props.fileType || props.fileSize)
|
||||
() => props.isShowTip && (props.fileType || props.fileSize)
|
||||
);
|
||||
|
||||
const imageUploadRef = ref(ElUpload);
|
||||
|
||||
watch(() => props.modelValue, async val => {
|
||||
if (val) {
|
||||
// 首先将值转为数组
|
||||
let list:OssVO[] = [];
|
||||
if (Array.isArray(val)) {
|
||||
list = val as OssVO[];
|
||||
if (val) {
|
||||
// 首先将值转为数组
|
||||
let list:OssVO[] = [];
|
||||
if (Array.isArray(val)) {
|
||||
list = val as OssVO[];
|
||||
} else {
|
||||
const res = await listByIds(val as string)
|
||||
list = res.data
|
||||
}
|
||||
// 然后将数组转为对象数组
|
||||
fileList.value = list.map(item => {
|
||||
// 字符串回显处理 如果此处存的是url可直接回显 如果存的是id需要调用接口查出来
|
||||
let itemData;
|
||||
if (typeof item === "string") {
|
||||
itemData = { name: item, url: item };
|
||||
} else {
|
||||
// 此处name使用ossId 防止删除出现重名
|
||||
itemData = { name: item.ossId, url: item.url, ossId: item.ossId };
|
||||
}
|
||||
return itemData;
|
||||
});
|
||||
} else {
|
||||
const res = await listByIds(val as string)
|
||||
list = res.data
|
||||
fileList.value = [];
|
||||
return [];
|
||||
}
|
||||
// 然后将数组转为对象数组
|
||||
fileList.value = list.map(item => {
|
||||
// 字符串回显处理 如果此处存的是url可直接回显 如果存的是id需要调用接口查出来
|
||||
let itemData;
|
||||
if (typeof item === "string") {
|
||||
itemData = { name: item, url: item };
|
||||
} else {
|
||||
// 此处name使用ossId 防止删除出现重名
|
||||
itemData = { name: item.ossId, url: item.url, ossId: item.ossId };
|
||||
}
|
||||
return itemData;
|
||||
});
|
||||
} else {
|
||||
fileList.value = [];
|
||||
return [];
|
||||
}
|
||||
},{ deep: true, immediate: true });
|
||||
|
||||
/** 上传前loading加载 */
|
||||
const handleBeforeUpload = (file: any) => {
|
||||
let isImg = false;
|
||||
if (props.fileType.length) {
|
||||
let fileExtension = "";
|
||||
if (file.name.lastIndexOf(".") > -1) {
|
||||
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
|
||||
let isImg = false;
|
||||
if (props.fileType.length) {
|
||||
let fileExtension = "";
|
||||
if (file.name.lastIndexOf(".") > -1) {
|
||||
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
|
||||
}
|
||||
isImg = props.fileType.some((type) => {
|
||||
if (file.type.indexOf(type) > -1) return true;
|
||||
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
|
||||
return false;
|
||||
});
|
||||
} else {
|
||||
isImg = file.type.indexOf("image") > -1;
|
||||
}
|
||||
isImg = props.fileType.some((type) => {
|
||||
if (file.type.indexOf(type) > -1) return true;
|
||||
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
|
||||
return false;
|
||||
});
|
||||
} else {
|
||||
isImg = file.type.indexOf("image") > -1;
|
||||
}
|
||||
if (!isImg) {
|
||||
proxy?.$modal.msgError(
|
||||
`文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (props.fileSize) {
|
||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||
if (!isLt) {
|
||||
proxy?.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
|
||||
return false;
|
||||
if (!isImg) {
|
||||
proxy?.$modal.msgError(
|
||||
`文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
proxy?.$modal.loading("正在上传图片,请稍候...");
|
||||
number.value++;
|
||||
if (props.fileSize) {
|
||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||
if (!isLt) {
|
||||
proxy?.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
proxy?.$modal.loading("正在上传图片,请稍候...");
|
||||
number.value++;
|
||||
}
|
||||
|
||||
// 文件个数超出
|
||||
const handleExceed = () => {
|
||||
proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
|
||||
proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
|
||||
}
|
||||
|
||||
// 上传成功回调
|
||||
const handleUploadSuccess = (res: any, file: UploadFile) => {
|
||||
if (res.code === 200) {
|
||||
uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
|
||||
uploadedSuccessfully();
|
||||
} else {
|
||||
number.value--;
|
||||
proxy?.$modal.closeLoading();
|
||||
proxy?.$modal.msgError(res.msg);
|
||||
imageUploadRef.value.handleRemove(file);
|
||||
uploadedSuccessfully();
|
||||
}
|
||||
if (res.code === 200) {
|
||||
uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
|
||||
uploadedSuccessfully();
|
||||
} else {
|
||||
number.value--;
|
||||
proxy?.$modal.closeLoading();
|
||||
proxy?.$modal.msgError(res.msg);
|
||||
imageUploadRef.value.handleRemove(file);
|
||||
uploadedSuccessfully();
|
||||
}
|
||||
}
|
||||
|
||||
// 删除图片
|
||||
const handleDelete = (file: UploadFile): boolean => {
|
||||
const findex = fileList.value.map(f => f.name).indexOf(file.name);
|
||||
if (findex > -1 && uploadList.value.length === number.value) {
|
||||
let ossId = fileList.value[findex].ossId;
|
||||
delOss(ossId);
|
||||
fileList.value.splice(findex, 1);
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
const findex = fileList.value.map(f => f.name).indexOf(file.name);
|
||||
if (findex > -1 && uploadList.value.length === number.value) {
|
||||
let ossId = fileList.value[findex].ossId;
|
||||
delOss(ossId);
|
||||
fileList.value.splice(findex, 1);
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 上传结束处理
|
||||
const uploadedSuccessfully = () => {
|
||||
if (number.value > 0 && uploadList.value.length === number.value) {
|
||||
fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
|
||||
uploadList.value = [];
|
||||
number.value = 0;
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
proxy?.$modal.closeLoading();
|
||||
}
|
||||
if (number.value > 0 && uploadList.value.length === number.value) {
|
||||
fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
|
||||
uploadList.value = [];
|
||||
number.value = 0;
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
proxy?.$modal.closeLoading();
|
||||
}
|
||||
}
|
||||
|
||||
// 上传失败
|
||||
const handleUploadError = () => {
|
||||
proxy?.$modal.msgError("上传图片失败");
|
||||
proxy?.$modal.closeLoading();
|
||||
proxy?.$modal.msgError("上传图片失败");
|
||||
proxy?.$modal.closeLoading();
|
||||
}
|
||||
|
||||
// 预览
|
||||
const handlePictureCardPreview = (file: any) => {
|
||||
dialogImageUrl.value = file.url;
|
||||
dialogVisible.value = true;
|
||||
dialogImageUrl.value = file.url;
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
|
||||
// 对象转成指定字符串分隔
|
||||
const listToString = (list: any[], separator?: string) => {
|
||||
let strs = "";
|
||||
separator = separator || ",";
|
||||
for (let i in list) {
|
||||
if(undefined !== list[i].ossId && list[i].url.indexOf("blob:") !== 0) {
|
||||
strs += list[i].ossId + separator;
|
||||
let strs = "";
|
||||
separator = separator || ",";
|
||||
for (let i in list) {
|
||||
if(undefined !== list[i].ossId && list[i].url.indexOf("blob:") !== 0) {
|
||||
strs += list[i].ossId + separator;
|
||||
}
|
||||
}
|
||||
}
|
||||
return strs != "" ? strs.substring(0, strs.length - 1) : "";
|
||||
return strs != "" ? strs.substring(0, strs.length - 1) : "";
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="component-upload-image">
|
||||
<el-upload
|
||||
multiple
|
||||
:action="uploadImgUrl"
|
||||
list-type="picture-card"
|
||||
:on-success="handleUploadSuccess"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:limit="limit"
|
||||
:on-error="handleUploadError"
|
||||
:on-exceed="handleExceed"
|
||||
ref="imageUpload"
|
||||
:before-remove="handleDelete"
|
||||
:show-file-list="true"
|
||||
:headers="headers"
|
||||
:file-list="fileList"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:class="{ hide: fileList.length >= limit }"
|
||||
>
|
||||
<el-icon class="avatar-uploader-icon"><plus /></el-icon>
|
||||
</el-upload>
|
||||
<!-- 上传提示 -->
|
||||
<div class="el-upload__tip" v-if="showTip">
|
||||
请上传
|
||||
<template v-if="fileSize">
|
||||
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
|
||||
</template>
|
||||
<template v-if="fileType">
|
||||
格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
|
||||
</template>
|
||||
的文件
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="dialogVisible" title="预览" width="800px" append-to-body>
|
||||
<img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
// .el-upload--picture-card 控制加号部分
|
||||
:deep(.hide .el-upload--picture-card) {
|
||||
|
@ -1,6 +1,22 @@
|
||||
<template>
|
||||
<div :class="{ 'hidden': hidden }" class="pagination-container">
|
||||
<el-pagination
|
||||
:background="background"
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:layout="layout"
|
||||
:page-sizes="pageSizes"
|
||||
:pager-count="pagerCount"
|
||||
:total="total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'Pagination'
|
||||
name: 'Pagination'
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -9,101 +25,85 @@ import { scrollTo } from '@/utils/scroll-to'
|
||||
import { PropType } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
total: {
|
||||
required: true,
|
||||
type: Number
|
||||
},
|
||||
page: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
pageSizes: {
|
||||
type: Array as PropType<number[]>,
|
||||
default() {
|
||||
return [10, 20, 30, 50]
|
||||
total: {
|
||||
required: true,
|
||||
type: Number
|
||||
},
|
||||
page: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
pageSizes: {
|
||||
type: Array as PropType<number[]>,
|
||||
default() {
|
||||
return [10, 20, 30, 50]
|
||||
}
|
||||
},
|
||||
// 移动端页码按钮的数量端默认值5
|
||||
pagerCount: {
|
||||
type: Number,
|
||||
default: document.body.clientWidth < 992 ? 5 : 7
|
||||
},
|
||||
layout: {
|
||||
type: String,
|
||||
default: 'total, sizes, prev, pager, next, jumper'
|
||||
},
|
||||
background: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
autoScroll: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hidden: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
float: {
|
||||
type: String,
|
||||
default: 'right'
|
||||
}
|
||||
},
|
||||
// 移动端页码按钮的数量端默认值5
|
||||
pagerCount: {
|
||||
type: Number,
|
||||
default: document.body.clientWidth < 992 ? 5 : 7
|
||||
},
|
||||
layout: {
|
||||
type: String,
|
||||
default: 'total, sizes, prev, pager, next, jumper'
|
||||
},
|
||||
background: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
autoScroll: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hidden: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
float: {
|
||||
type: String,
|
||||
default: 'right'
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:page', 'update:limit', 'pagination']);
|
||||
const currentPage = computed({
|
||||
get() {
|
||||
return props.page
|
||||
},
|
||||
set(val) {
|
||||
emit('update:page', val)
|
||||
}
|
||||
get() {
|
||||
return props.page
|
||||
},
|
||||
set(val) {
|
||||
emit('update:page', val)
|
||||
}
|
||||
})
|
||||
const pageSize = computed({
|
||||
get() {
|
||||
return props.limit
|
||||
},
|
||||
set(val){
|
||||
emit('update:limit', val)
|
||||
}
|
||||
get() {
|
||||
return props.limit
|
||||
},
|
||||
set(val){
|
||||
emit('update:limit', val)
|
||||
}
|
||||
})
|
||||
function handleSizeChange(val: number) {
|
||||
if (currentPage.value * val > props.total) {
|
||||
currentPage.value = 1
|
||||
}
|
||||
emit('pagination', { page: currentPage.value, limit: val })
|
||||
if (props.autoScroll) {
|
||||
scrollTo(0, 800)
|
||||
}
|
||||
if (currentPage.value * val > props.total) {
|
||||
currentPage.value = 1
|
||||
}
|
||||
emit('pagination', { page: currentPage.value, limit: val })
|
||||
if (props.autoScroll) {
|
||||
scrollTo(0, 800)
|
||||
}
|
||||
}
|
||||
function handleCurrentChange(val: number) {
|
||||
emit('pagination', { page: val, limit: pageSize.value })
|
||||
if (props.autoScroll) {
|
||||
scrollTo(0, 800)
|
||||
}
|
||||
emit('pagination', { page: val, limit: pageSize.value })
|
||||
if (props.autoScroll) {
|
||||
scrollTo(0, 800)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="{ 'hidden': hidden }" class="pagination-container">
|
||||
<el-pagination
|
||||
:background="background"
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:layout="layout"
|
||||
:page-sizes="pageSizes"
|
||||
:pager-count="pagerCount"
|
||||
:total="total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pagination-container {
|
||||
background: #fff;
|
||||
|
@ -1,3 +1,3 @@
|
||||
<template>
|
||||
<router-view />
|
||||
<router-view />
|
||||
</template>
|
||||
|
@ -1,23 +1,42 @@
|
||||
<template>
|
||||
<div class="top-right-btn" :style="style">
|
||||
<el-row>
|
||||
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top" v-if="search">
|
||||
<el-button circle icon="Search" @click="toggleSearch()" />
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
|
||||
<el-button circle icon="Refresh" @click="refresh()" />
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="columns">
|
||||
<el-button circle icon="Menu" @click="showColumn()" />
|
||||
</el-tooltip>
|
||||
</el-row>
|
||||
<el-dialog :title="title" v-model="open" append-to-body>
|
||||
<el-transfer :titles="['显示', '隐藏']" v-model="value" :data="columns" @change="dataChange"></el-transfer>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { TransferKey } from "element-plus";
|
||||
import { PropType } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
showSearch: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
columns: {
|
||||
type: Array as PropType<FieldOption[]>,
|
||||
},
|
||||
search: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
gutter: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
},
|
||||
showSearch: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
columns: {
|
||||
type: Array as PropType<FieldOption[]>,
|
||||
},
|
||||
search: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
gutter: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
},
|
||||
})
|
||||
|
||||
const emits = defineEmits(['update:showSearch', 'queryTable']);
|
||||
@ -30,64 +49,45 @@ const title = ref("显示/隐藏");
|
||||
const open = ref(false);
|
||||
|
||||
const style = computed(() => {
|
||||
const ret: any = {};
|
||||
if (props.gutter) {
|
||||
ret.marginRight = `${props.gutter / 2}px`;
|
||||
}
|
||||
return ret;
|
||||
const ret: any = {};
|
||||
if (props.gutter) {
|
||||
ret.marginRight = `${props.gutter / 2}px`;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
|
||||
// 搜索
|
||||
function toggleSearch() {
|
||||
emits("update:showSearch", !props.showSearch);
|
||||
emits("update:showSearch", !props.showSearch);
|
||||
}
|
||||
|
||||
// 刷新
|
||||
function refresh() {
|
||||
emits("queryTable");
|
||||
emits("queryTable");
|
||||
}
|
||||
|
||||
// 右侧列表元素变化
|
||||
function dataChange(data: TransferKey[]) {
|
||||
props.columns?.forEach((item) => {
|
||||
item.visible = !data.includes(item.key);
|
||||
})
|
||||
props.columns?.forEach((item) => {
|
||||
item.visible = !data.includes(item.key);
|
||||
})
|
||||
}
|
||||
|
||||
// 打开显隐列dialog
|
||||
const showColumn = () => {
|
||||
open.value = true;
|
||||
open.value = true;
|
||||
}
|
||||
|
||||
// 显隐列初始默认隐藏列
|
||||
onMounted(() => {
|
||||
props.columns?.forEach((item) => {
|
||||
if (!item.visible) {
|
||||
value.value.push(item.key);
|
||||
}
|
||||
})
|
||||
props.columns?.forEach((item) => {
|
||||
if (!item.visible) {
|
||||
value.value.push(item.key);
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="top-right-btn" :style="style">
|
||||
<el-row>
|
||||
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top" v-if="search">
|
||||
<el-button circle icon="Search" @click="toggleSearch()" />
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
|
||||
<el-button circle icon="Refresh" @click="refresh()" />
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="columns">
|
||||
<el-button circle icon="Menu" @click="showColumn()" />
|
||||
</el-tooltip>
|
||||
</el-row>
|
||||
<el-dialog :title="title" v-model="open" append-to-body>
|
||||
<el-transfer :titles="['显示', '隐藏']" v-model="value" :data="columns" @change="dataChange"></el-transfer>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-transfer__button) {
|
||||
border-radius: 50%;
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<svg-icon icon-class="question" @click="goto" />
|
||||
</div>
|
||||
<div>
|
||||
<svg-icon icon-class="question" @click="goto" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<svg-icon icon-class="github" @click="goto" />
|
||||
</div>
|
||||
<div>
|
||||
<svg-icon icon-class="github" @click="goto" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<svg-icon :icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'" @click="toggle" />
|
||||
</div>
|
||||
<div>
|
||||
<svg-icon :icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'" @click="toggle" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -16,20 +16,20 @@ const handleSetSize = (size: string) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<el-dropdown trigger="click" @command="handleSetSize">
|
||||
<div class="size-icon--style">
|
||||
<svg-icon class-name="size-icon" icon-class="size" />
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size === item.value" :command="item.value">
|
||||
{{ item.label }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<div>
|
||||
<el-dropdown trigger="click" @command="handleSetSize">
|
||||
<div class="size-icon--style">
|
||||
<svg-icon class-name="size-icon" icon-class="size" />
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size === item.value" :command="item.value">
|
||||
{{ item.label }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -23,9 +23,9 @@ const svgClass = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<svg :class="svgClass" aria-hidden="true">
|
||||
<use :xlink:href="iconName" :fill="color" />
|
||||
</svg>
|
||||
<svg :class="svgClass" aria-hidden="true">
|
||||
<use :xlink:href="iconName" :fill="color" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<style scope lang="scss">
|
||||
|
@ -1,3 +1,23 @@
|
||||
<template>
|
||||
<el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false">
|
||||
<template v-for="(item, index) in topMenus">
|
||||
<el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
|
||||
><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
|
||||
>
|
||||
</template>
|
||||
|
||||
<!-- 顶部菜单超出数量折叠 -->
|
||||
<el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
|
||||
<template #title>更多菜单</template>
|
||||
<template v-for="(item, index) in topMenus">
|
||||
<el-menu-item :index="item.path" :key="index" v-if="index >= visibleNumber"
|
||||
><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
|
||||
>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { constantRoutes } from '@/router';
|
||||
import { isHttp } from '@/utils/validate';
|
||||
@ -130,26 +150,6 @@ onMounted(() => {
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false">
|
||||
<template v-for="(item, index) in topMenus">
|
||||
<el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
|
||||
><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
|
||||
>
|
||||
</template>
|
||||
|
||||
<!-- 顶部菜单超出数量折叠 -->
|
||||
<el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
|
||||
<template #title>更多菜单</template>
|
||||
<template v-for="(item, index) in topMenus">
|
||||
<el-menu-item :index="item.path" :key="index" v-if="index >= visibleNumber"
|
||||
><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
|
||||
>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.topmenu-container.el-menu--horizontal > .el-menu-item {
|
||||
float: left;
|
||||
|
@ -128,31 +128,31 @@ ul li .el-tree .el-tree-node__content {
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="el-tree-select">
|
||||
<el-select
|
||||
style="width: 100%"
|
||||
v-model="valueId"
|
||||
ref="treeSelect"
|
||||
:filterable="true"
|
||||
:clearable="true"
|
||||
@clear="clearHandle"
|
||||
:filter-method="selectFilterData"
|
||||
:placeholder="placeholder"
|
||||
>
|
||||
<el-option :value="valueId" :label="valueTitle">
|
||||
<el-tree
|
||||
id="tree-option"
|
||||
ref="selectTree"
|
||||
:accordion="accordion"
|
||||
:data="options"
|
||||
:props="objMap"
|
||||
:node-key="objMap.value"
|
||||
:expand-on-click-node="false"
|
||||
:default-expanded-keys="defaultExpandedKey"
|
||||
:filter-node-method="filterNode"
|
||||
@node-click="handleNodeClick"
|
||||
></el-tree>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="el-tree-select">
|
||||
<el-select
|
||||
style="width: 100%"
|
||||
v-model="valueId"
|
||||
ref="treeSelect"
|
||||
:filterable="true"
|
||||
:clearable="true"
|
||||
@clear="clearHandle"
|
||||
:filter-method="selectFilterData"
|
||||
:placeholder="placeholder"
|
||||
>
|
||||
<el-option :value="valueId" :label="valueTitle">
|
||||
<el-tree
|
||||
id="tree-option"
|
||||
ref="selectTree"
|
||||
:accordion="accordion"
|
||||
:data="options"
|
||||
:props="objMap"
|
||||
:node-key="objMap.value"
|
||||
:expand-on-click-node="false"
|
||||
:default-expanded-keys="defaultExpandedKey"
|
||||
:filter-node-method="filterNode"
|
||||
@node-click="handleNodeClick"
|
||||
></el-tree>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -21,7 +21,7 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-loading="loading" :style="'height:' + height">
|
||||
<iframe :src="url" frameborder="no" style="width: 100%; height: 100%" scrolling="auto" />
|
||||
</div>
|
||||
<div v-loading="loading" :style="'height:' + height">
|
||||
<iframe :src="url" frameborder="no" style="width: 100%; height: 100%" scrolling="auto" />
|
||||
</div>
|
||||
</template>
|
||||
|
Reference in New Issue
Block a user