兰宝车间质量管理系统-前端
LiuHao
2023-06-06 d43ae50abc9461a9b20b3f015ba3679ba699dfa2
update 修改组件 去除无用引用和代码缩进
已修改14个文件
604 ■■■■ 文件已修改
src/components/Breadcrumb/index.vue 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/BuildCode/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/DictTag/index.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Editor/index.vue 202 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/FileUpload/index.vue 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Hamburger/index.vue 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/HeaderSearch/index.vue 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/IconSelect/index.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ImagePreview/index.vue 58 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ImageUpload/index.vue 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/RightToolbar/index.vue 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/SvgIcon/index.vue 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/TreeSelect/index.vue 76 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/iFrame/index.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Breadcrumb/index.vue
@@ -18,34 +18,34 @@
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>
src/components/BuildCode/index.vue
@@ -1,8 +1,6 @@
<!-- 代码构建 -->
<script setup lang="ts">
import { ComponentInternalInstance } from "vue";
const props = defineProps({
  showBtn: {
    type: Boolean,
src/components/DictTag/index.vue
@@ -24,7 +24,7 @@
</template>
<script setup lang="ts">
import { PropType } from 'vue';
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
@@ -36,10 +36,7 @@
  // 当前的值
  value: [Number, String, Array] as PropType<number | string | Array<number | string>>,
  // 当未找到匹配的数据时,显示value
  showValue: {
    type: Boolean as PropType<boolean>,
    default: true,
  },
  showValue: propTypes.bool.def(true),
});
const values = computed(() => {
src/components/Editor/index.vue
@@ -30,152 +30,139 @@
import { QuillEditor, Quill } from '@vueup/vue-quill';
import '@vueup/vue-quill/dist/vue-quill.snow.css';
import { getToken } from "@/utils/auth";
import { ComponentInternalInstance } from "vue";
import { propTypes } from '@/utils/propTypes';
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: propTypes.string,
  /* 高度 */
  height: propTypes.number.def(400),
  /* 最小高度 */
  minHeight: propTypes.number.def(400),
  /* 只读 */
  readOnly: propTypes.bool.def(false),
  /* 上传文件大小限制(MB) */
  fileSize: propTypes.number.def(5),
  /* 类型(base64格式、url格式) */
  type: propTypes.string.def('url')
});
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const upload = reactive<UploadOption>({
    headers: { Authorization: "Bearer " + getToken() },
    url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
  headers: { Authorization: "Bearer " + getToken() },
  url: import.meta.env.VITE_APP_BASE_API + '/resource/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>
<style>
.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: 0;
  content: "保存";
@@ -190,14 +177,17 @@
.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";
@@ -207,26 +197,32 @@
.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";
@@ -236,10 +232,12 @@
.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: "等宽字体";
src/components/FileUpload/index.vue
@@ -45,31 +45,18 @@
<script setup lang="ts">
import { getToken } from "@/utils/auth";
import { listByIds, delOss } from "@/api/system/oss";
import { ComponentInternalInstance } from "vue";
import { ElUpload, UploadFile } from "element-plus";
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
    modelValue: [String, Object, Array],
    // 数量限制
    limit: {
        type: Number,
        default: 5,
    },
    limit: propTypes.number.def(5),
    // 大小限制(MB)
    fileSize: {
        type: Number,
        default: 5,
    },
    fileSize: propTypes.number.def(5),
    // 文件类型, 例如['png', 'jpg', 'jpeg']
    fileType: {
        type: Array,
        default: () => ["doc", "xls", "ppt", "txt", "pdf"],
    },
    fileType: propTypes.array.def(["doc", "xls", "ppt", "txt", "pdf"]),
    // 是否显示提示
    isShowTip: {
        type: Boolean,
        default: true
    }
    isShowTip: propTypes.bool.def(true),
});
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -86,7 +73,7 @@
    () => props.isShowTip && (props.fileType || props.fileSize)
);
const fileUploadRef = ref(ElUpload);
const fileUploadRef = ref<ElUploadInstance>();
watch(() => props.modelValue, async val => {
    if (val) {
@@ -96,7 +83,7 @@
        if (Array.isArray(val)) {
            list = val;
        } else {
            const res =  await listByIds(val as string)
            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;
@@ -104,7 +91,7 @@
        }
        // 然后将数组转为对象数组
        fileList.value = list.map(item => {
            item = {name: item.name, url: item.url, ossId: item.ossId};
            item = { name: item.name, url: item.url, ossId: item.ossId };
            item.uid = item.uid || new Date().getTime() + temp++;
            return item;
        });
@@ -112,7 +99,7 @@
        fileList.value = [];
        return [];
    }
},{ deep: true, immediate: true });
}, { deep: true, immediate: true });
// 上传前校检格式和大小
const handleBeforeUpload = (file: any) => {
@@ -150,7 +137,7 @@
}
// 上传成功回调
const handleUploadSuccess = (res:any, file: UploadFile) => {
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();
@@ -158,7 +145,7 @@
        number.value--;
        proxy?.$modal.closeLoading();
        proxy?.$modal.msgError(res.msg);
        fileUploadRef.value.handleRemove(file);
        fileUploadRef.value?.handleRemove(file);
        uploadedSuccessfully();
    }
}
@@ -172,7 +159,7 @@
}
// 上传结束处理
const uploadedSuccessfully =() => {
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 = [];
@@ -207,21 +194,24 @@
<style scoped lang="scss">
.upload-file-uploader {
  margin-bottom: 5px;
    margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {
  border: 1px solid #e4e7ed;
  line-height: 2;
  margin-bottom: 10px;
  position: relative;
    border: 1px solid #e4e7ed;
    line-height: 2;
    margin-bottom: 10px;
    position: relative;
}
.upload-file-list .ele-upload-list__item-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: inherit;
    display: flex;
    justify-content: space-between;
    align-items: center;
    color: inherit;
}
.ele-upload-list__item-content-action .el-link {
  margin-right: 10px;
    margin-right: 10px;
}
</style>
src/components/Hamburger/index.vue
@@ -1,6 +1,6 @@
<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">
    <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"
      />
@@ -9,16 +9,15 @@
</template>
<script setup lang="ts">
import { propTypes } from '@/utils/propTypes';
defineProps({
    isActive: {
        type: Boolean,
        default: false
    }
  isActive: propTypes.bool.def(false)
})
const emit = defineEmits(['toggleClick'])
const toggleClick = () => {
    emit('toggleClick');
  emit('toggleClick');
}
</script>
src/components/HeaderSearch/index.vue
@@ -23,7 +23,6 @@
import { isHttp } from '@/utils/validate';
import usePermissionStore from '@/store/modules/permission';
import { RouteOption } from 'vue-router';
import { ElSelect } from 'element-plus';
type Router = Array<{
    path: string;
@@ -35,7 +34,7 @@
const searchPool = ref<Router>([]);
const show = ref(false);
const fuse = ref();
const headerSearchSelectRef = ref(ElSelect);
const headerSearchSelectRef = ref<ElSelectInstance>();
const router = useRouter();
const routes = computed(() => usePermissionStore().routes);
@@ -143,40 +142,40 @@
<style lang="scss" scoped>
.header-search {
  font-size: 0 !important;
    font-size: 0 !important;
  .search-icon {
    cursor: pointer;
    font-size: 18px;
    vertical-align: middle;
  }
  .header-search-select {
    font-size: 18px;
    transition: width 0.2s;
    width: 0;
    overflow: hidden;
    background: transparent;
    border-radius: 0;
    display: inline-block;
    vertical-align: middle;
    :deep(.el-input__inner) {
      border-radius: 0;
      border: 0;
      padding-left: 0;
      padding-right: 0;
      box-shadow: none !important;
      border-bottom: 1px solid #d9d9d9;
      vertical-align: middle;
    .search-icon {
        cursor: pointer;
        font-size: 18px;
        vertical-align: middle;
    }
  }
  &.show {
    .header-search-select {
      width: 210px;
      margin-left: 10px;
        font-size: 18px;
        transition: width 0.2s;
        width: 0;
        overflow: hidden;
        background: transparent;
        border-radius: 0;
        display: inline-block;
        vertical-align: middle;
        :deep(.el-input__inner) {
            border-radius: 0;
            border: 0;
            padding-left: 0;
            padding-right: 0;
            box-shadow: none !important;
            border-bottom: 1px solid #d9d9d9;
            vertical-align: middle;
        }
    }
  }
    &.show {
        .header-search-select {
            width: 210px;
            margin-left: 10px;
        }
    }
}
</style>
src/components/IconSelect/index.vue
@@ -31,17 +31,11 @@
<script setup lang="ts">
import icons from '@/components/IconSelect/requireIcons';
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
  modelValue: {
    type: String,
    require: true
  },
  width: {
    type: String,
    require: false,
    default: '400px'
  }
  modelValue: propTypes.string.isRequired,
  width: propTypes.string.def('400px')
});
const emit = defineEmits(['update:modelValue']);
src/components/ImagePreview/index.vue
@@ -9,47 +9,46 @@
</template>
<script setup lang="ts">
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
    src: {
        type: String,
        default: ""
    },
    width: {
        type: [Number, String],
        default: ""
    },
    height: {
        type: [Number, String],
        default: ""
    }
  src: propTypes.string.def(''),
  width: {
    type: [Number, String],
    default: ""
  },
  height: {
    type: [Number, String],
    default: ""
  }
});
const realSrc = computed(() => {
    if (!props.src) {
        return;
    }
    let real_src = props.src.split(",")[0];
    return real_src;
  if (!props.src) {
    return;
  }
  let real_src = props.src.split(",")[0];
  return real_src;
});
const realSrcList = computed(() => {
    if (!props.src) {
        return;
    }
    let real_src_list = props.src.split(",");
    let srcList:string[] = [];
    real_src_list.forEach(item => {
        return srcList.push(item);
    });
    return srcList;
  if (!props.src) {
    return;
  }
  let real_src_list = props.src.split(",");
  let srcList: string[] = [];
  real_src_list.forEach(item => {
    return srcList.push(item);
  });
  return srcList;
});
const realWidth = computed(() =>
    typeof props.width == "string" ? props.width : `${props.width}px`
  typeof props.width == "string" ? props.width : `${props.width}px`
);
const realHeight = computed(() =>
    typeof props.height == "string" ? props.height : `${props.height}px`
  typeof props.height == "string" ? props.height : `${props.height}px`
);
</script>
@@ -58,13 +57,16 @@
  border-radius: 5px;
  background-color: #ebeef5;
  box-shadow: 0 0 5px 1px #ccc;
  :deep(.el-image__inner) {
    transition: all 0.3s;
    cursor: pointer;
    &:hover {
      transform: scale(1.2);
    }
  }
  :deep(.image-slot) {
    display: flex;
    justify-content: center;
src/components/ImageUpload/index.vue
@@ -17,7 +17,9 @@
      :on-preview="handlePictureCardPreview"
      :class="{ hide: fileList.length >= limit }"
    >
      <el-icon class="avatar-uploader-icon"><plus /></el-icon>
      <el-icon class="avatar-uploader-icon">
        <plus />
      </el-icon>
    </el-upload>
    <!-- 上传提示 -->
    <div class="el-upload__tip" v-if="showTip">
@@ -42,25 +44,16 @@
import { listByIds, delOss } from "@/api/system/oss";
import { ComponentInternalInstance, PropType } from "vue";
import { OssVO } from "@/api/system/oss/types";
import { ElUpload, UploadFile } from "element-plus";
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
    modelValue: [String, Object, Array],
    // 图片数量限制
    limit: {
        type: Number,
        default: 5,
    },
    limit: propTypes.number.def(5),
    // 大小限制(MB)
    fileSize: {
        type: Number,
        default: 5,
    },
    fileSize: propTypes.number.def(5),
    // 文件类型, 例如['png', 'jpg', 'jpeg']
    fileType: {
        type: Array as PropType<string[]>,
        default: () => ["png", "jpg", "jpeg"],
    },
    fileType: propTypes.array.def(["png", "jpg", "jpeg"]),
    // 是否显示提示
    isShowTip: {
        type: Boolean,
@@ -84,12 +77,12 @@
    () => props.isShowTip && (props.fileType || props.fileSize)
);
const imageUploadRef = ref(ElUpload);
const imageUploadRef = ref<ElUploadInstance>();
watch(() => props.modelValue, async val => {
    if (val) {
        // 首先将值转为数组
        let list:OssVO[] = [];
        let list: OssVO[] = [];
        if (Array.isArray(val)) {
            list = val as OssVO[];
        } else {
@@ -112,7 +105,7 @@
        fileList.value = [];
        return [];
    }
},{ deep: true, immediate: true });
}, { deep: true, immediate: true });
/** 上传前loading加载 */
const handleBeforeUpload = (file: any) => {
@@ -122,7 +115,7 @@
        if (file.name.lastIndexOf(".") > -1) {
            fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
        }
        isImg = props.fileType.some((type) => {
        isImg = props.fileType.some((type: any) => {
            if (file.type.indexOf(type) > -1) return true;
            if (fileExtension && fileExtension.indexOf(type) > -1) return true;
            return false;
@@ -161,7 +154,7 @@
        number.value--;
        proxy?.$modal.closeLoading();
        proxy?.$modal.msgError(res.msg);
        imageUploadRef.value.handleRemove(file);
        imageUploadRef.value?.handleRemove(file);
        uploadedSuccessfully();
    }
}
@@ -207,7 +200,7 @@
    let strs = "";
    separator = separator || ",";
    for (let i in list) {
        if(undefined !== list[i].ossId && list[i].url.indexOf("blob:") !== 0) {
        if (undefined !== list[i].ossId && list[i].url.indexOf("blob:") !== 0) {
            strs += list[i].ossId + separator;
        }
    }
src/components/RightToolbar/index.vue
@@ -18,25 +18,15 @@
</template>
<script setup lang="ts">
import { TransferKey } from "element-plus";
import { PropType } from "vue";
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
    showSearch: {
        type: Boolean,
        default: true,
    },
    showSearch: propTypes.bool.def(true),
    columns: {
        type: Array as PropType<FieldOption[]>,
    },
    search: {
        type: Boolean,
        default: true,
    },
    gutter: {
        type: Number,
        default: 10,
    },
    search: propTypes.bool.def(true),
    gutter: propTypes.number.def(10),
})
const emits = defineEmits(['update:showSearch', 'queryTable']);
src/components/SvgIcon/index.vue
@@ -5,19 +5,12 @@
</template>
<script setup lang="ts">
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
    iconClass: {
        type: String,
        required: true
    },
    className: {
        type: String,
        default: ''
    },
    color: {
        type: String,
        default: ''
    },
    iconClass: propTypes.string.isRequired,
    className: propTypes.string.def(''),
    color: propTypes.string.def(''),
})
const iconName =  computed(() => `#icon-${props.iconClass}`);
const svgClass = computed(() => {
src/components/TreeSelect/index.vue
@@ -29,94 +29,93 @@
</template>
<script setup lang="ts">
import { ElTreeSelect } from 'element-plus'
const props = defineProps({
  /* 配置项 */
  objMap: {
  type: Object,
  default: () => {
    return {
    value: 'id', // ID字段名
    label: 'label', // 显示名称
    children: 'children' // 子级字段名
    type: Object,
    default: () => {
      return {
        value: 'id', // ID字段名
        label: 'label', // 显示名称
        children: 'children' // 子级字段名
      }
    }
  }
  },
  /* 自动收起 */
  accordion: {
  type: Boolean,
  default: () => {
    return false
  }
    type: Boolean,
    default: () => {
      return false
    }
  },
  /**当前双向数据绑定的值 */
  value: {
  type: [String, Number],
  default: ''
    type: [String, Number],
    default: ''
  },
  /**当前的数据 */
  options: {
  type: Array,
  default: () => []
    type: Array,
    default: () => []
  },
  /**输入框内部的文字 */
  placeholder: {
  type: String,
  default: ''
    type: String,
    default: ''
  }
})
const selectTree = ref(ElTreeSelect);
const selectTree = ref<ElTreeSelectInstance>();
const emit = defineEmits(['update:value']);
const valueId = computed({
  get: () => props.value,
  set: (val) => {
  emit('update:value', val)
    emit('update:value', val)
  }
});
const valueTitle = ref('');
const defaultExpandedKey = ref<any[]>([]);
function initHandle() {
const initHandle = () => {
  nextTick(() => {
  const selectedValue = valueId.value;
  if(selectedValue !== null && typeof (selectedValue) !== 'undefined') {
    const node = selectTree.value.getNode(selectedValue)
    if (node) {
    valueTitle.value = node.data[props.objMap.label]
    selectTree.value.setCurrentKey(selectedValue) // 设置默认选中
    defaultExpandedKey.value = [selectedValue] // 设置默认展开
    const selectedValue = valueId.value;
    if (selectedValue !== null && typeof (selectedValue) !== 'undefined') {
      const node = selectTree.value?.getNode(selectedValue)
      if (node) {
        valueTitle.value = node.data[props.objMap.label]
        selectTree.value?.setCurrentKey(selectedValue) // 设置默认选中
        defaultExpandedKey.value = [selectedValue] // 设置默认展开
      }
    } else {
      clearHandle()
    }
  } else {
    clearHandle()
  }
  })
}
function handleNodeClick(node: any) {
const handleNodeClick = (node: any) => {
  valueTitle.value = node[props.objMap.label]
  valueId.value = node[props.objMap.value];
  defaultExpandedKey.value = [];
  selectTree.value.blur()
  selectTree.value?.blur()
  selectFilterData('')
}
function selectFilterData(val: any) {
  selectTree.value.filter(val)
const selectFilterData = (val: any) => {
  selectTree.value?.filter(val)
}
function filterNode(value: any, data: any) {
const filterNode = (value: any, data: any) => {
  if (!value) return true
  return data[props.objMap['label']].indexOf(value) !== -1
}
function clearHandle() {
const clearHandle = () => {
  valueTitle.value = ''
  valueId.value = ''
  defaultExpandedKey.value = [];
  clearSelected()
}
function clearSelected() {
const clearSelected = () => {
  const allNode = document.querySelectorAll('#tree-option .el-tree-node')
  allNode.forEach((element) => element.classList.remove('is-current'))
}
@@ -132,6 +131,7 @@
<style lang="scss" scoped>
@import "@/assets/styles/variables.module.scss";
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
  padding: 0;
  background-color: #fff;
src/components/iFrame/index.vue
@@ -5,11 +5,10 @@
</template>
<script setup lang="ts">
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
  src: {
    type: String,
    required: true
  }
  src: propTypes.string.isRequired
})
const height = ref(document.documentElement.clientHeight - 94.5 + "px;")