jgy-public-component 0.0.19 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/JButton/JButton.d.ts +1 -1
- package/dist/components/JSearchHeader/JSearchHeader.d.ts +2 -2
- package/dist/components/JUploadImg/JUploadImg.d.ts +2 -2
- package/dist/index.js +886 -897
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +1 -1
- package/dist/index.umd.cjs.map +1 -1
- package/dist/router/guards copy.d.ts +6 -0
- package/dist/style.css +1 -1
- package/package.json +73 -73
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/components/JButton/JButton.vue","../src/components/JUploadImg/JUploadImg.vue","../src/components/JIconRender/JIconRender.vue","../src/components/JSearchHeader/JSearchHeader.vue","../src/components/JImportExcel/JImportExcel.vue","../src/components/JSidebar/JSideMenuItem.vue","../src/components/JSidebar/JSidebar.vue","../src/components/JAdminLayout/JAdminLayout.vue","../src/utils/transform.ts","../src/router/helpers.ts","../src/router/guards.ts","../src/index.ts"],"sourcesContent":["<template>\r\n <button\r\n class=\"j-button\"\r\n :class=\"[\r\n `j-button--${type}`,\r\n `j-button--${size}`,\r\n {\r\n 'j-button--plain': plain,\r\n 'j-button--round': round,\r\n 'j-button--disabled': disabled,\r\n 'j-button--loading': loading,\r\n },\r\n ]\"\r\n :disabled=\"disabled || loading\"\r\n @click=\"handleClick\"\r\n >\r\n <span v-if=\"loading\" class=\"j-button__loading-icon\" />\r\n <span v-if=\"$slots.default\" class=\"j-button__text\">\r\n <slot />\r\n </span>\r\n </button>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport type { ButtonType, ButtonSize } from './types'\r\n\r\ninterface Props {\r\n type?: ButtonType\r\n size?: ButtonSize\r\n plain?: boolean\r\n round?: boolean\r\n disabled?: boolean\r\n loading?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n type: 'default',\r\n size: 'medium',\r\n plain: false,\r\n round: false,\r\n disabled: false,\r\n loading: false,\r\n})\r\n\r\nconst emit = defineEmits<{\r\n click: [event: MouseEvent]\r\n}>()\r\n\r\nfunction handleClick(event: MouseEvent) {\r\n if (!props.disabled && !props.loading) {\r\n emit('click', event)\r\n }\r\n}\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.j-button {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: $spacing-xs;\r\n padding: 8px 16px;\r\n font-size: $font-size-base;\r\n font-weight: 400;\r\n line-height: 1;\r\n white-space: nowrap;\r\n cursor: pointer;\r\n border: 1px solid $color-border;\r\n border-radius: $border-radius-base;\r\n background-color: $color-white;\r\n color: $color-text-regular;\r\n transition: $transition-fast;\r\n outline: none;\r\n user-select: none;\r\n\r\n &:hover {\r\n color: $color-primary;\r\n border-color: $color-primary;\r\n background-color: color.adjust($color-primary, $lightness: 40%);\r\n }\r\n\r\n // 尺寸\r\n &--small {\r\n padding: 5px 12px;\r\n font-size: $font-size-xs;\r\n }\r\n\r\n &--medium {\r\n padding: 8px 16px;\r\n font-size: $font-size-base;\r\n }\r\n\r\n &--large {\r\n padding: 12px 20px;\r\n font-size: $font-size-md;\r\n }\r\n\r\n // 类型\r\n &--primary {\r\n background-color: $color-primary;\r\n border-color: $color-primary;\r\n color: $color-white;\r\n &:hover {\r\n background-color: color.adjust($color-primary, $lightness: 10%);\r\n border-color: color.adjust($color-primary, $lightness: 10%);\r\n color: $color-white;\r\n }\r\n }\r\n\r\n &--success {\r\n background-color: $color-success;\r\n border-color: $color-success;\r\n color: $color-white;\r\n &:hover {\r\n background-color: color.adjust($color-success, $lightness: 10%);\r\n border-color: color.adjust($color-success, $lightness: 10%);\r\n color: $color-white;\r\n }\r\n }\r\n\r\n &--danger {\r\n background-color: $color-danger;\r\n border-color: $color-danger;\r\n color: $color-white;\r\n &:hover {\r\n background-color: color.adjust($color-danger, $lightness: 10%);\r\n border-color: color.adjust($color-danger, $lightness: 10%);\r\n color: $color-white;\r\n }\r\n }\r\n\r\n &--warning {\r\n background-color: $color-warning;\r\n border-color: $color-warning;\r\n color: $color-white;\r\n &:hover {\r\n background-color: color.adjust($color-warning, $lightness: 10%);\r\n border-color: color.adjust($color-warning, $lightness: 10%);\r\n color: $color-white;\r\n }\r\n }\r\n\r\n // 朴素按钮\r\n &--plain {\r\n &.j-button--primary {\r\n background-color: color.adjust($color-primary, $lightness: 40%);\r\n color: $color-primary;\r\n &:hover {\r\n background-color: $color-primary;\r\n color: $color-white;\r\n }\r\n }\r\n }\r\n\r\n // 圆角\r\n &--round {\r\n border-radius: $border-radius-round;\r\n }\r\n\r\n // 禁用\r\n &--disabled {\r\n opacity: 0.5;\r\n cursor: not-allowed;\r\n pointer-events: none;\r\n }\r\n\r\n // 加载\r\n &--loading {\r\n opacity: 0.7;\r\n cursor: not-allowed;\r\n pointer-events: none;\r\n }\r\n\r\n &__loading-icon {\r\n display: inline-block;\r\n width: 14px;\r\n height: 14px;\r\n border: 2px solid currentColor;\r\n border-top-color: transparent;\r\n border-radius: 50%;\r\n animation: j-spin 0.6s linear infinite;\r\n }\r\n\r\n @keyframes j-spin {\r\n to {\r\n transform: rotate(360deg);\r\n }\r\n }\r\n}\r\n</style>\r\n","<template>\r\n <div class=\"j-upload-img-container\">\r\n <!-- 多图模式 -->\r\n <template v-if=\"multiple\">\r\n <div class=\"images-wrapper\">\r\n <draggable\r\n v-model=\"imageList\"\r\n class=\"images-list\"\r\n item-key=\"uid\"\r\n :animation=\"200\"\r\n :disabled=\"disabled\"\r\n @end=\"handleDragEnd\"\r\n >\r\n <template #item=\"{ element, index }\">\r\n <div class=\"image-item\">\r\n <el-image\r\n :src=\"element.url\"\r\n :preview-src-list=\"imageList.map(img => img.url)\"\r\n :initial-index=\"index\"\r\n fit=\"cover\"\r\n class=\"image-preview\"\r\n :preview-teleported=\"true\"\r\n :hide-on-click-modal=\"true\"\r\n />\r\n <div v-if=\"!disabled\" class=\"delete-btn\" @click.stop=\"handleRemove(index)\">\r\n <el-icon class=\"icon-delete\">\r\n <Delete />\r\n </el-icon>\r\n </div>\r\n </div>\r\n </template>\r\n </draggable>\r\n\r\n <!-- 多图上传按钮 -->\r\n <el-upload\r\n v-if=\"!disabled && (!limit || imageList.length < limit)\"\r\n class=\"image-uploader\"\r\n :auto-upload=\"false\"\r\n :show-file-list=\"false\"\r\n :on-change=\"handleFileChange\"\r\n :disabled=\"uploading\"\r\n list-type=\"picture-card\"\r\n :accept=\"accept\"\r\n >\r\n <el-icon v-if=\"!uploading\" class=\"uploader-icon\">\r\n <Plus />\r\n </el-icon>\r\n <el-icon v-else class=\"uploader-icon is-loading\">\r\n <Loading />\r\n </el-icon>\r\n </el-upload>\r\n </div>\r\n </template>\r\n\r\n <!-- 单图模式 -->\r\n <template v-else>\r\n <!-- 已有图片:独立展示,hover 显示操作遮罩 -->\r\n <div v-if=\"imageUrl\" class=\"image-item single-image-item\">\r\n <el-image\r\n :src=\"imageUrl\"\r\n fit=\"cover\"\r\n class=\"image-preview\"\r\n />\r\n <div class=\"image-actions\">\r\n <el-icon class=\"action-icon\" @click.stop=\"handlePreviewSingle\">\r\n <ZoomIn />\r\n </el-icon>\r\n <el-icon v-if=\"!disabled\" class=\"action-icon\" @click.stop=\"handleRemoveSingle\">\r\n <Delete />\r\n </el-icon>\r\n </div>\r\n </div>\r\n\r\n <!-- 无图片:显示上传按钮 -->\r\n <el-upload\r\n v-else\r\n class=\"image-uploader\"\r\n :auto-upload=\"false\"\r\n :show-file-list=\"false\"\r\n :on-change=\"handleFileChange\"\r\n :disabled=\"disabled || uploading\"\r\n :accept=\"accept\"\r\n list-type=\"picture-card\"\r\n >\r\n <el-icon class=\"uploader-icon\">\r\n <Plus v-if=\"!uploading\" />\r\n <Loading v-else class=\"is-loading\" />\r\n </el-icon>\r\n </el-upload>\r\n\r\n <!-- 大图预览 -->\r\n <el-image-viewer\r\n v-if=\"showPreview\"\r\n :url-list=\"[imageUrl]\"\r\n :teleported=\"true\"\r\n @close=\"showPreview = false\"\r\n />\r\n </template>\r\n\r\n <div v-if=\"showTipText\" class=\"upload-tip\">\r\n <span>{{ tip }}</span>\r\n <span v-if=\"multiple && limit\"> (最多 {{ limit }} 张)</span>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, watch } from 'vue'\r\nimport { ElMessage } from 'element-plus'\r\nimport type { UploadFile } from 'element-plus'\r\nimport { Plus, Loading, Delete, ZoomIn } from '@element-plus/icons-vue'\r\nimport draggable from 'vuedraggable'\r\nimport type { ImageItem } from './types'\r\n\r\ndefineOptions({\r\n name: 'JUploadImg'\r\n})\r\n\r\nconst props = withDefaults(defineProps<{\r\n modelValue?: string | string[]\r\n disabled?: boolean\r\n multiple?: boolean\r\n limit?: number\r\n maxSize?: number\r\n accept?: string\r\n tip?: string\r\n showTip?: boolean\r\n /** 自定义上传函数,接收 File 返回图片 URL */\r\n uploadFn?: (file: File) => Promise<string>\r\n}>(), {\r\n modelValue: '',\r\n disabled: false,\r\n multiple: false,\r\n limit: 9,\r\n maxSize: 2,\r\n accept: 'image/jpeg,image/png,image/jpg,image/gif',\r\n tip: '只能上传jpg/png/gif格式的图片,且不超过2MB',\r\n showTip: true,\r\n uploadFn: undefined\r\n})\r\n\r\nconst emit = defineEmits<{\r\n (e: 'update:modelValue', value: string | string[]): void\r\n (e: 'success', url: string): void\r\n (e: 'error', error: any): void\r\n}>()\r\n\r\n// 单图模式\r\nconst imageUrl = ref<string>('')\r\nconst showPreview = ref(false)\r\nconst showTipText = props.showTip\r\n\r\nconst handlePreviewSingle = () => {\r\n showPreview.value = true\r\n}\r\n\r\nconst handleRemoveSingle = () => {\r\n imageUrl.value = ''\r\n emit('update:modelValue', '')\r\n ElMessage.success('删除成功')\r\n}\r\n\r\n// 多图模式\r\nconst imageList = ref<ImageItem[]>([])\r\nconst uploading = ref(false)\r\n\r\n// 初始化图片列表(多图模式)\r\nconst initImageList = (urls: string[]) => {\r\n imageList.value = urls.map((url, index) => ({\r\n uid: Date.now() + index,\r\n url\r\n }))\r\n}\r\n\r\n// 监听外部值变化\r\nwatch(() => props.modelValue, (val) => {\r\n if (props.multiple) {\r\n if (Array.isArray(val) && val.length > 0) {\r\n initImageList(val)\r\n } else {\r\n imageList.value = []\r\n }\r\n } else {\r\n if (typeof val === 'string') {\r\n imageUrl.value = val\r\n } else {\r\n imageUrl.value = ''\r\n }\r\n }\r\n}, { immediate: true })\r\n\r\n// 拖拽结束(多图模式)\r\nconst handleDragEnd = () => {\r\n emitMultipleUpdate()\r\n}\r\n\r\n// 删除图片(多图模式)\r\nconst handleRemove = (index: number) => {\r\n imageList.value.splice(index, 1)\r\n emitMultipleUpdate()\r\n ElMessage.success('删除成功')\r\n}\r\n\r\n// 文件改变时触发\r\nconst handleFileChange = async (uploadFile: UploadFile) => {\r\n const file = uploadFile.raw as File\r\n\r\n if (!file) {\r\n ElMessage.error('文件不存在,请重试')\r\n return\r\n }\r\n\r\n if (file.size > props.maxSize * 1024 * 1024) {\r\n ElMessage.error(`图片大小不能超过 ${props.maxSize}MB`)\r\n return\r\n }\r\n\r\n if (!props.uploadFn) {\r\n ElMessage.error('未配置上传函数 (uploadFn)')\r\n return\r\n }\r\n\r\n try {\r\n uploading.value = true\r\n const url = await props.uploadFn(file)\r\n\r\n if (props.multiple) {\r\n imageList.value.push({ uid: Date.now(), url })\r\n emitMultipleUpdate()\r\n } else {\r\n imageUrl.value = url\r\n emit('update:modelValue', url)\r\n }\r\n\r\n emit('success', url)\r\n ElMessage.success('上传成功')\r\n } catch (error) {\r\n console.error('上传出错:', error)\r\n ElMessage.error('上传失败,请重试')\r\n emit('error', error)\r\n } finally {\r\n uploading.value = false\r\n }\r\n}\r\n\r\n// 触发多图更新\r\nconst emitMultipleUpdate = () => {\r\n const urls = imageList.value.map(item => item.url)\r\n emit('update:modelValue', urls)\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n.j-upload-img-container {\r\n display: inline-block;\r\n}\r\n\r\n/* 多图模式样式 */\r\n.images-wrapper {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 8px;\r\n align-items: flex-start;\r\n}\r\n\r\n.images-list {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 8px;\r\n}\r\n\r\n.image-item {\r\n position: relative;\r\n width: 74px;\r\n height: 74px;\r\n border: 1px solid var(--el-border-color);\r\n border-radius: 6px;\r\n overflow: hidden;\r\n cursor: move;\r\n}\r\n\r\n.image-preview {\r\n width: 100%;\r\n height: 100%;\r\n}\r\n\r\n.delete-btn {\r\n position: absolute;\r\n top: 2px;\r\n right: 2px;\r\n width: 20px;\r\n height: 20px;\r\n background-color: rgba(0, 0, 0, 0.6);\r\n border-radius: 50%;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n opacity: 0;\r\n transition: opacity 0.3s;\r\n cursor: pointer;\r\n z-index: 1;\r\n}\r\n\r\n.image-item:hover .delete-btn {\r\n opacity: 1;\r\n}\r\n\r\n.delete-btn:hover {\r\n background-color: rgba(0, 0, 0, 0.8);\r\n}\r\n\r\n.icon-delete {\r\n font-size: 12px;\r\n color: #fff;\r\n}\r\n\r\n/* 单图和多图共用样式 */\r\n.image-uploader {\r\n display: inline-block;\r\n vertical-align: top;\r\n}\r\n\r\n.image-uploader :deep(.el-upload) {\r\n border: 1px dashed var(--el-border-color);\r\n border-radius: 6px;\r\n cursor: pointer;\r\n position: relative;\r\n overflow: hidden;\r\n transition: var(--el-transition-duration-fast);\r\n width: 74px !important;\r\n height: 74px !important;\r\n}\r\n\r\n.image-uploader :deep(.el-upload:hover) {\r\n border-color: var(--el-color-primary);\r\n}\r\n\r\n.uploader-icon {\r\n font-size: 20px;\r\n color: #8c939d;\r\n width: 74px;\r\n height: 74px;\r\n text-align: center;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.single-image-item {\r\n cursor: default;\r\n}\r\n\r\n.image-actions {\r\n position: absolute;\r\n inset: 0;\r\n background-color: rgba(0, 0, 0, 0.5);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 12px;\r\n opacity: 0;\r\n transition: opacity 0.3s;\r\n}\r\n\r\n.single-image-item:hover .image-actions,\r\n.image-item:hover .image-actions {\r\n opacity: 1;\r\n}\r\n\r\n.action-icon {\r\n font-size: 18px;\r\n color: #fff;\r\n cursor: pointer;\r\n transition: transform 0.2s;\r\n}\r\n\r\n.action-icon:hover {\r\n transform: scale(1.2);\r\n}\r\n\r\n.upload-tip {\r\n margin-top: 8px;\r\n font-size: 12px;\r\n color: #909399;\r\n line-height: 1.5;\r\n}\r\n</style>\r\n","<template>\r\n <Icon v-if=\"icon\" :icon=\"icon\" :width=\"size\" :height=\"size\" v-bind=\"$attrs\" />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { Icon } from '@iconify/vue'\r\n\r\ndefineOptions({\r\n name: 'JIconRender'\r\n})\r\n\r\nwithDefaults(defineProps<{\r\n icon: string\r\n size?: string | number\r\n}>(), {\r\n size: 24,\r\n})\r\n</script>\r\n","<template>\r\n <el-card shadow=\"never\" class=\"j-search-header-card\">\r\n <el-form inline class=\"search-form\">\r\n <div\r\n ref=\"formItemsRef\"\r\n class=\"form-items-wrapper\"\r\n :class=\"{ 'is-animated': isAnimated }\"\r\n >\r\n <slot />\r\n </div>\r\n </el-form>\r\n\r\n <div class=\"action-bar\" :style=\"{ marginTop: expanded ? '0px' : '10px' }\">\r\n <div class=\"action-left\">\r\n <el-button v-if=\"showAdd\" type=\"primary\" :icon=\"Plus\" @click=\"emit('add')\">\r\n {{ addText }}\r\n </el-button>\r\n <el-button\r\n v-if=\"showBatchDelete\"\r\n type=\"danger\"\r\n :icon=\"Delete\"\r\n :disabled=\"selectedCount === 0\"\r\n @click=\"emit('batchDelete')\"\r\n >\r\n 批量删除{{ selectedCount ? `(${selectedCount})` : '' }}\r\n </el-button>\r\n <el-button v-if=\"showSearch\" type=\"primary\" :icon=\"Search\" @click=\"emit('search')\">搜索</el-button>\r\n <el-button v-if=\"showReset\" :icon=\"Refresh\" @click=\"emit('reset')\">重置</el-button>\r\n <slot name=\"actions\" />\r\n </div>\r\n <el-button\r\n v-if=\"shouldCollapse\"\r\n link\r\n type=\"primary\"\r\n @click=\"toggleExpand\"\r\n >\r\n {{ expanded ? '收起' : '展开' }}\r\n <el-icon class=\"toggle-icon\" :class=\"{ 'is-expanded': expanded }\">\r\n <ArrowDown />\r\n </el-icon>\r\n </el-button>\r\n </div>\r\n </el-card>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted, onBeforeUnmount } from 'vue'\r\nimport { Search, Refresh, Plus, Delete, ArrowDown } from '@element-plus/icons-vue'\r\n\r\ndefineOptions({\r\n name: 'JSearchHeader'\r\n})\r\n\r\nconst props = withDefaults(defineProps<{\r\n selectedCount?: number\r\n addText?: string\r\n defaultVisible?: number\r\n showAdd?: boolean\r\n showBatchDelete?: boolean\r\n showSearch?: boolean\r\n showReset?: boolean\r\n}>(), {\r\n selectedCount: 0,\r\n addText: '新增',\r\n defaultVisible: 5,\r\n showAdd: true,\r\n showBatchDelete: true,\r\n showSearch: true,\r\n showReset: true\r\n})\r\n\r\nconst emit = defineEmits<{\r\n search: []\r\n reset: []\r\n add: []\r\n batchDelete: []\r\n}>()\r\n\r\nconst formItemsRef = ref<HTMLElement>()\r\nconst expanded = ref(false)\r\nconst isAnimated = ref(false)\r\nconst itemCount = ref(0)\r\nconst collapsedHeight = ref(0)\r\n\r\nconst shouldCollapse = computed(() => itemCount.value > props.defaultVisible)\r\n\r\nconst measureItems = () => {\r\n if (!formItemsRef.value) return\r\n const items = Array.from(formItemsRef.value.children) as HTMLElement[]\r\n itemCount.value = items.length\r\n\r\n const lastVisibleItem = items[props.defaultVisible - 1]\r\n if (lastVisibleItem && formItemsRef.value) {\r\n const wrapperRect = formItemsRef.value.getBoundingClientRect()\r\n const lastVisibleRect = lastVisibleItem.getBoundingClientRect()\r\n collapsedHeight.value = lastVisibleRect.bottom - wrapperRect.top\r\n }\r\n}\r\n\r\nconst toggleExpand = () => {\r\n const el = formItemsRef.value\r\n if (!el) return\r\n\r\n if (!expanded.value) {\r\n expanded.value = true\r\n el.style.maxHeight = el.scrollHeight + 'px'\r\n const onEnd = () => {\r\n el.style.maxHeight = 'none'\r\n el.removeEventListener('transitionend', onEnd)\r\n }\r\n el.addEventListener('transitionend', onEnd)\r\n } else {\r\n measureItems()\r\n expanded.value = false\r\n el.style.maxHeight = el.scrollHeight + 'px'\r\n el.offsetHeight\r\n el.style.maxHeight = collapsedHeight.value + 'px'\r\n }\r\n}\r\n\r\nlet observer: MutationObserver | null = null\r\n\r\nonMounted(() => {\r\n measureItems()\r\n if (shouldCollapse.value && formItemsRef.value) {\r\n formItemsRef.value.style.maxHeight = collapsedHeight.value + 'px'\r\n }\r\n requestAnimationFrame(() => {\r\n requestAnimationFrame(() => {\r\n isAnimated.value = true\r\n })\r\n })\r\n if (formItemsRef.value) {\r\n observer = new MutationObserver(() => {\r\n measureItems()\r\n if (shouldCollapse.value && !expanded.value && formItemsRef.value) {\r\n formItemsRef.value.style.maxHeight = collapsedHeight.value + 'px'\r\n }\r\n })\r\n observer.observe(formItemsRef.value, { childList: true })\r\n }\r\n})\r\n\r\nonBeforeUnmount(() => {\r\n observer?.disconnect()\r\n})\r\n</script>\r\n\r\n<style scoped>\r\n.j-search-header-card :deep(.el-card__body) {\r\n padding: 16px 20px 12px;\r\n}\r\n\r\n.search-form {\r\n display: flex;\r\n flex-wrap: wrap;\r\n align-items: center;\r\n gap: 0;\r\n}\r\n\r\n.form-items-wrapper {\r\n display: flex;\r\n flex-wrap: wrap;\r\n align-items: center;\r\n overflow: hidden;\r\n}\r\n\r\n.form-items-wrapper.is-animated {\r\n transition: max-height 0.3s ease-in-out;\r\n}\r\n\r\n.form-items-wrapper :deep(.el-form-item) {\r\n margin-bottom: 10px;\r\n margin-right: 16px;\r\n}\r\n\r\n.action-bar {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding-top: 10px;\r\n border-top: 1px solid #ebeef5;\r\n}\r\n\r\n.action-left {\r\n display: flex;\r\n gap: 8px;\r\n}\r\n\r\n.toggle-icon {\r\n margin-left: 2px;\r\n transition: transform 0.25s;\r\n}\r\n\r\n.toggle-icon.is-expanded {\r\n transform: rotate(180deg);\r\n}\r\n</style>\r\n","<template>\r\n <el-dialog\r\n v-model=\"visible\"\r\n :title=\"props.title\"\r\n width=\"900px\"\r\n :close-on-click-modal=\"false\"\r\n @open=\"handleOpen\"\r\n @close=\"handleClose\"\r\n >\r\n <!-- 上传区域 -->\r\n <el-card shadow=\"never\" class=\"j-import-upload-card\">\r\n <div class=\"j-import-upload-card-title\">导入 EXCEL</div>\r\n <el-divider style=\"margin: 10px 0\" />\r\n <div class=\"j-import-upload-row\">\r\n <el-upload\r\n accept=\".xlsx,.xls\"\r\n :auto-upload=\"false\"\r\n :show-file-list=\"false\"\r\n :on-change=\"handleFileChange\"\r\n >\r\n <el-button size=\"small\">点击上传</el-button>\r\n </el-upload>\r\n <el-link\r\n v-if=\"dataColumns.length\"\r\n type=\"primary\"\r\n class=\"j-import-no-wrap\"\r\n @click=\"handleDownloadTemplate\"\r\n >\r\n 下载导入模板.xlsx\r\n </el-link>\r\n </div>\r\n </el-card>\r\n\r\n <!-- 统计信息 + 确认导入 -->\r\n <el-row class=\"j-import-stats-row\" :gutter=\"20\" align=\"middle\">\r\n <el-col :span=\"18\">\r\n <el-row class=\"j-import-stats-cols\">\r\n <el-col :span=\"4\" class=\"j-import-stat-item\">\r\n <div class=\"j-import-stat-num\">{{ stats.total }}</div>\r\n <div class=\"j-import-stat-label\">导入数量</div>\r\n </el-col>\r\n <el-col :span=\"4\" class=\"j-import-stat-item\">\r\n <div class=\"j-import-stat-num\">{{ stats.fail }}</div>\r\n <div class=\"j-import-stat-label\">失败数量</div>\r\n </el-col>\r\n <el-col :span=\"4\" class=\"j-import-stat-item\">\r\n <div class=\"j-import-stat-num\">{{ stats.success }}</div>\r\n <div class=\"j-import-stat-label\">成功数量</div>\r\n </el-col>\r\n </el-row>\r\n </el-col>\r\n <el-col :span=\"6\" class=\"j-import-confirm-col\">\r\n <el-button\r\n type=\"primary\"\r\n size=\"small\"\r\n :loading=\"submitting\"\r\n :disabled=\"!renderData.length\"\r\n @click=\"handleConfirm\"\r\n >\r\n 确认导入\r\n </el-button>\r\n </el-col>\r\n </el-row>\r\n\r\n <!-- 数据表格 -->\r\n <el-table :data=\"renderData\" border size=\"small\" max-height=\"360\" class=\"j-import-data-table\">\r\n <el-table-column\r\n v-for=\"col in dataColumns\"\r\n :key=\"col.prop\"\r\n :prop=\"col.prop\"\r\n :label=\"col.label\"\r\n :min-width=\"120\"\r\n show-overflow-tooltip\r\n />\r\n <el-table-column label=\"状态\" width=\"110\" align=\"center\" fixed=\"right\">\r\n <template #default=\"{ row }\">\r\n <span v-if=\"row._status === -1\" class=\"j-import-status-fail\">\r\n {{ row._error || '创建失败' }}\r\n </span>\r\n <span v-else>{{ statusMap[row._status] }}</span>\r\n </template>\r\n </el-table-column>\r\n <el-table-column label=\"操作\" width=\"80\" align=\"center\" fixed=\"right\">\r\n <template #default=\"{ $index, row }\">\r\n <el-button\r\n v-if=\"row._status === 0\"\r\n size=\"small\"\r\n @click=\"handleDel($index)\"\r\n >\r\n 删除\r\n </el-button>\r\n </template>\r\n </el-table-column>\r\n </el-table>\r\n\r\n <template #footer>\r\n <el-button @click=\"handleClose\">关闭</el-button>\r\n </template>\r\n </el-dialog>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed } from 'vue'\r\nimport { ElMessage } from 'element-plus'\r\nimport type { UploadFile } from 'element-plus'\r\nimport * as XLSX from 'xlsx'\r\nimport type { JImportExcelProps } from './types'\r\n\r\ndefineOptions({ name: 'JImportExcel' })\r\n\r\nconst props = withDefaults(defineProps<JImportExcelProps>(), {\r\n excludeFields: () => ['id', 'ctime', 'mtime'],\r\n title: 'Excel 批量导入',\r\n})\r\n\r\nconst emit = defineEmits<{\r\n success: []\r\n}>()\r\n\r\nconst visible = defineModel<boolean>({ default: false })\r\nconst submitting = ref(false)\r\nconst fieldMap = ref<Record<string, string>>({})\r\nconst renderData = ref<Record<string, any>[]>([])\r\nconst stats = ref({ total: 0, success: 0, fail: 0 })\r\n\r\nconst statusMap: Record<number, string> = {\r\n 0: '待创建',\r\n 1: '创建成功',\r\n 2: '创建中',\r\n [-1]: '创建失败',\r\n}\r\n\r\n/** 过滤后的表头列 */\r\nconst dataColumns = computed(() => {\r\n return Object.entries(fieldMap.value)\r\n .filter(([key]) => !props.excludeFields.includes(key))\r\n .map(([key, label]) => ({ id: key, label, prop: key }))\r\n})\r\n\r\n/** 弹窗打开时获取字段列表 */\r\nconst handleOpen = async () => {\r\n try {\r\n const res = await props.getFieldListApi()\r\n fieldMap.value = res.data.tableFieldsInfo ?? {}\r\n } catch {\r\n ElMessage.error('获取字段列表失败')\r\n }\r\n}\r\n\r\n/** 文件上传解析 */\r\nconst handleFileChange = (uploadFile: UploadFile) => {\r\n const raw = uploadFile.raw\r\n if (!raw) return\r\n\r\n const validTypes = [\r\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\r\n 'application/vnd.ms-excel',\r\n ]\r\n if (!validTypes.includes(raw.type) && !raw.name.match(/\\.xlsx?$/i)) {\r\n ElMessage.warning('请上传 .xlsx 或 .xls 格式文件')\r\n return\r\n }\r\n\r\n const reader = new FileReader()\r\n reader.onload = (e) => {\r\n try {\r\n const workbook = XLSX.read(e.target!.result, { type: 'binary' })\r\n const wsName = workbook.SheetNames[0] as string\r\n const ws = workbook.Sheets[wsName]!\r\n const jsonData = XLSX.utils.sheet_to_json(ws) as Record<string, any>[]\r\n\r\n if (!jsonData.length) {\r\n ElMessage.warning('文件内容为空')\r\n return\r\n }\r\n\r\n // 将 Excel 每行按表头 prop 顺序映射\r\n const propList = dataColumns.value.map((col) => col.prop)\r\n const list: Record<string, any>[] = jsonData.map((row) => {\r\n const values = Object.values(row)\r\n const item: Record<string, any> = { _status: 0, _error: '' }\r\n propList.forEach((prop, index) => {\r\n item[prop] = values[index]\r\n })\r\n return item\r\n })\r\n\r\n renderData.value = list\r\n stats.value = { total: list.length, success: 0, fail: 0 }\r\n } catch {\r\n ElMessage.error('解析文件失败,请检查文件格式')\r\n }\r\n }\r\n reader.readAsBinaryString(raw)\r\n}\r\n\r\n/** 删除行 */\r\nconst handleDel = (idx: number) => {\r\n renderData.value.splice(idx, 1)\r\n stats.value.total = renderData.value.length\r\n}\r\n\r\n/** 确认导入 */\r\nconst handleConfirm = async () => {\r\n const data = renderData.value\r\n .filter((row) => row._status === 0)\r\n .map(({ _status, _error, ...rest }) => rest)\r\n\r\n if (!data.length) {\r\n ElMessage.warning('没有可导入的数据')\r\n return\r\n }\r\n\r\n submitting.value = true\r\n try {\r\n const res = await props.importApi(data)\r\n if (res.code === 1) {\r\n // 全部成功\r\n renderData.value.forEach((row) => {\r\n if (row._status === 0) row._status = 1\r\n })\r\n stats.value.success = renderData.value.filter((r) => r._status === 1).length\r\n ElMessage.success('导入成功')\r\n emit('success')\r\n } else {\r\n ElMessage.error(res.msg || '导入失败')\r\n }\r\n } catch {\r\n ElMessage.error('导入失败,请重试')\r\n } finally {\r\n submitting.value = false\r\n }\r\n}\r\n\r\n/** 下载导入模板 */\r\nconst handleDownloadTemplate = () => {\r\n try {\r\n const wb = XLSX.utils.book_new()\r\n const headers = dataColumns.value.map((col) => col.label)\r\n const tr: Record<string, string> = {}\r\n headers.forEach((h) => (tr[h] = ''))\r\n const ws = XLSX.utils.json_to_sheet([tr])\r\n XLSX.utils.book_append_sheet(wb, ws, '模板')\r\n XLSX.writeFile(wb, '导入模板.xlsx')\r\n } catch {\r\n ElMessage.error('模板下载失败')\r\n }\r\n}\r\n\r\nconst handleClose = () => {\r\n if (!submitting.value) {\r\n visible.value = false\r\n renderData.value = []\r\n stats.value = { total: 0, success: 0, fail: 0 }\r\n }\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n.j-import-upload-card {\r\n margin-bottom: 16px;\r\n}\r\n.j-import-upload-card-title {\r\n font-size: 14px;\r\n color: #606266;\r\n}\r\n.j-import-upload-row {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n}\r\n.j-import-no-wrap {\r\n white-space: nowrap;\r\n}\r\n.j-import-stats-row {\r\n margin: 12px 0;\r\n}\r\n.j-import-stats-cols {\r\n text-align: center;\r\n line-height: 1.5;\r\n}\r\n.j-import-stat-item {\r\n padding: 0 8px;\r\n}\r\n.j-import-stat-num {\r\n font-size: 20px;\r\n}\r\n.j-import-stat-label {\r\n font-size: 12px;\r\n color: #909399;\r\n}\r\n.j-import-confirm-col {\r\n text-align: right;\r\n padding-top: 10px;\r\n}\r\n.j-import-data-table {\r\n margin-top: 10px;\r\n}\r\n.j-import-status-fail {\r\n color: #f56c6c;\r\n font-size: 12px;\r\n}\r\n</style>\r\n","<template>\r\n <!-- 有子菜单:渲染 el-sub-menu -->\r\n <el-sub-menu\r\n v-if=\"menuItem.children && menuItem.children.length > 0\"\r\n :index=\"menuItem.path\"\r\n :class=\"[`j-sidebar__depth-${depth}`]\"\r\n >\r\n <template #title>\r\n <JIconRender v-if=\"menuItem.icon && depth === 0\" :icon=\"menuItem.icon\" />\r\n <span class=\"j-sidebar__menu-item-title\">{{ menuItem.title || menuItem.name }}</span>\r\n </template>\r\n <!-- 递归渲染子菜单 -->\r\n <JSideMenuItem\r\n v-for=\"child in menuItem.children\"\r\n :key=\"child.path\"\r\n :menu-item=\"child\"\r\n :is-collapse=\"isCollapse\"\r\n :depth=\"depth + 1\"\r\n @menu-click=\"(item) => emit('menu-click', item)\"\r\n />\r\n </el-sub-menu>\r\n\r\n <!-- 无子菜单:渲染 el-menu-item -->\r\n <el-menu-item\r\n v-else\r\n :index=\"menuItem.path\"\r\n :class=\"[`j-sidebar__depth-${depth}`]\"\r\n @click=\"handleClick\"\r\n >\r\n <JIconRender v-if=\"menuItem.icon && depth === 0\" :icon=\"menuItem.icon\" />\r\n <template #title>\r\n <span>{{ menuItem.title || menuItem.name }}</span>\r\n </template>\r\n </el-menu-item>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport type { SidebarMenuItem } from './types'\r\nimport { JIconRender } from '../JIconRender'\r\n\r\ndefineOptions({\r\n name: 'JSideMenuItem'\r\n})\r\n\r\ninterface Props {\r\n menuItem: SidebarMenuItem\r\n isCollapse?: boolean\r\n depth?: number\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), { depth: 0 })\r\n\r\nconst emit = defineEmits<{\r\n 'menu-click': [item: SidebarMenuItem]\r\n}>()\r\n\r\nconst handleClick = () => {\r\n emit('menu-click', props.menuItem)\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n.j-sidebar__menu-item-title {\r\n padding: 0 10px;\r\n}\r\n\r\n/* 二级菜单:灰色标题,作为分类标签 */\r\n.j-sidebar__depth-1 > :deep(.el-sub-menu__title) {\r\n color: #909399;\r\n font-size: 13px;\r\n}\r\n\r\n/* 二级叶子菜单(无子项)也用灰色 */\r\n:deep(.j-sidebar__depth-1.el-menu-item) {\r\n color: #909399;\r\n font-size: 13px;\r\n}\r\n\r\n/* 三级菜单:文字稍大 */\r\n:deep(.j-sidebar__depth-2.el-menu-item) {\r\n font-size: 15px;\r\n}\r\n</style>\r\n","<template>\r\n <div\r\n :class=\"['j-sidebar', innerCollapsed ? 'j-sidebar--collapsed' : 'j-sidebar--expanded']\"\r\n :style=\"{ width: innerCollapsed ? `${collapsedWidth}px` : `${expandedWidth}px` }\"\r\n >\r\n <!-- Logo 区域 -->\r\n <div class=\"j-sidebar__logo\">\r\n <slot name=\"logo\" :collapsed=\"innerCollapsed\">\r\n <h2 class=\"j-sidebar__title\">\r\n {{ innerCollapsed ? (collapsedTitle || title?.charAt(0) || '') : title }}\r\n </h2>\r\n </slot>\r\n </div>\r\n\r\n <!-- 菜单区域 -->\r\n <div class=\"j-sidebar__menu-wrapper\">\r\n <el-menu\r\n :default-active=\"activeMenu\"\r\n class=\"j-sidebar__menu\"\r\n :router=\"router\"\r\n :collapse=\"innerCollapsed\"\r\n :collapse-transition=\"false\"\r\n >\r\n <JSideMenuItem\r\n v-for=\"route in menus\"\r\n :key=\"route.path\"\r\n :menu-item=\"route\"\r\n :is-collapse=\"innerCollapsed\"\r\n @menu-click=\"(item) => emit('menu-click', item)\"\r\n />\r\n </el-menu>\r\n </div>\r\n\r\n <!-- 底部折叠按钮 -->\r\n <div class=\"j-sidebar__footer\">\r\n <slot name=\"footer\" :collapsed=\"innerCollapsed\" :toggle=\"toggleCollapse\">\r\n <button\r\n class=\"j-sidebar__collapse-btn\"\r\n @click=\"toggleCollapse\"\r\n >\r\n <JIconRender :icon=\"innerCollapsed ? 'mdi:chevron-right' : 'mdi:chevron-left'\" />\r\n </button>\r\n </slot>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, watch } from 'vue'\r\nimport type { SidebarMenuItem } from './types'\r\nimport JSideMenuItem from './JSideMenuItem.vue'\r\nimport { JIconRender } from '../JIconRender'\r\n\r\ndefineOptions({\r\n name: 'JSidebar'\r\n})\r\n\r\ninterface Props {\r\n menus: SidebarMenuItem[]\r\n activeMenu?: string\r\n title?: string\r\n collapsedTitle?: string\r\n collapsed?: boolean\r\n collapsedWidth?: number\r\n expandedWidth?: number\r\n router?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n activeMenu: '',\r\n title: '',\r\n collapsedTitle: '',\r\n collapsed: false,\r\n collapsedWidth: 80,\r\n expandedWidth: 200,\r\n router: true,\r\n})\r\n\r\nconst emit = defineEmits<{\r\n 'update:collapsed': [value: boolean]\r\n 'menu-click': [item: SidebarMenuItem]\r\n}>()\r\n\r\nconst innerCollapsed = ref(props.collapsed)\r\n\r\nwatch(() => props.collapsed, (val) => {\r\n innerCollapsed.value = val\r\n})\r\n\r\nconst toggleCollapse = () => {\r\n innerCollapsed.value = !innerCollapsed.value\r\n emit('update:collapsed', innerCollapsed.value)\r\n}\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.j-sidebar {\r\n position: relative;\r\n background-color: $color-white;\r\n box-shadow: 2px 0 6px rgba(0, 21, 41, 0.08);\r\n overflow-x: hidden;\r\n transition: width 0.3s ease-in-out;\r\n flex-shrink: 0;\r\n display: flex;\r\n flex-direction: column;\r\n height: 100%;\r\n}\r\n\r\n.j-sidebar__logo {\r\n padding: 0 $spacing-md;\r\n display: flex;\r\n align-items: center;\r\n height: 50px;\r\n flex-shrink: 0;\r\n}\r\n\r\n\r\n.j-sidebar__title {\r\n margin: 0;\r\n font-size: $font-size-lg;\r\n font-weight: bold;\r\n color: $color-primary;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n}\r\n\r\n.j-sidebar__menu-wrapper {\r\n flex: 1;\r\n overflow-y: auto;\r\n overflow-x: hidden;\r\n}\r\n\r\n.j-sidebar__menu {\r\n border: none;\r\n width: 100%;\r\n}\r\n\r\n.j-sidebar__footer {\r\n flex-shrink: 0;\r\n padding: $spacing-sm;\r\n display: flex;\r\n}\r\n\r\n// 折叠状态:覆盖 el-menu 样式,图标+文字上下排列\r\n.j-sidebar--collapsed {\r\n :deep(.el-menu--collapse) {\r\n width: 100%;\r\n\r\n .el-menu-item,\r\n .el-sub-menu__title {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n height: auto;\r\n line-height: normal;\r\n padding: $spacing-sm 0 !important;\r\n\r\n .el-icon,\r\n .iconify {\r\n margin: 0;\r\n }\r\n\r\n span {\r\n display: block !important;\r\n visibility: visible !important;\r\n overflow: visible !important;\r\n width: auto !important;\r\n height: auto !important;\r\n font-size: $font-size-xs;\r\n margin-top: $spacing-xs;\r\n }\r\n }\r\n\r\n // 隐藏子菜单展开箭头\r\n .el-sub-menu__icon-arrow {\r\n display: none;\r\n }\r\n }\r\n}\r\n\r\n.j-sidebar__collapse-btn {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: $spacing-sm;\r\n border: none;\r\n border-radius: $border-radius-base;\r\n background-color: transparent;\r\n color: $color-text-secondary;\r\n cursor: pointer;\r\n transition: $transition-fast;\r\n\r\n &:hover {\r\n background-color: $color-bg-base;\r\n color: $color-primary;\r\n }\r\n\r\n}\r\n</style>\r\n","<template>\n <div class=\"j-admin-layout\" :style=\"layoutStyle\">\n <JSidebar\n v-if=\"sideMenus.length > 0\"\n v-model:collapsed=\"innerCollapsed\"\n :menus=\"sideMenus\"\n :active-menu=\"activeMenu\"\n :title=\"title\"\n :collapsed-title=\"collapsedTitle\"\n :collapsed-width=\"sidebarCollapsedWidth\"\n :expanded-width=\"sidebarExpandedWidth\"\n @menu-click=\"handleSideMenuClick\"\n >\n <template v-if=\"$slots.sidebarFooter\" #footer=\"{ collapsed: sidebarCollapsed, toggle }\">\n <slot name=\"sidebarFooter\" :collapsed=\"sidebarCollapsed\" :toggle=\"toggle\" />\n </template>\n </JSidebar>\n\n <div class=\"j-admin-layout__right-panel\">\n <div class=\"j-admin-layout__header\">\n <div class=\"j-admin-layout__header-left\">\n <div v-if=\"sideMenus.length === 0\" class=\"j-admin-layout__logo\">\n <slot name=\"logo\">\n <h2>{{ logoTitle || title }}</h2>\n </slot>\n </div>\n\n <el-menu\n mode=\"horizontal\"\n :default-active=\"activeTopMenu\"\n class=\"j-admin-layout__top-menu\"\n @select=\"handleTopMenuSelect\"\n >\n <el-menu-item\n v-for=\"menu in topMenus\"\n :key=\"menu.path\"\n :index=\"menu.path\"\n >\n <JIconRender :icon=\"menu.icon || 'ep:menu'\" class=\"j-admin-layout__top-menu-icon\" />\n <span>{{ menu.title || menu.name }}</span>\n </el-menu-item>\n </el-menu>\n </div>\n\n <div class=\"j-admin-layout__header-right\">\n <slot name=\"headerRight\" :username=\"username\">\n <el-dropdown v-if=\"showProfile || showLogout\">\n <span class=\"j-admin-layout__user\">\n {{ username }}\n <el-icon>\n <ArrowDown />\n </el-icon>\n </span>\n <template #dropdown>\n <el-dropdown-menu>\n <el-dropdown-item v-if=\"showProfile\" @click=\"emit('profile')\">\n {{ profileText }}\n </el-dropdown-item>\n <el-dropdown-item v-if=\"showLogout\" @click=\"emit('logout')\">\n {{ logoutText }}\n </el-dropdown-item>\n </el-dropdown-menu>\n </template>\n </el-dropdown>\n </slot>\n </div>\n </div>\n\n <div class=\"j-admin-layout__content-container\">\n <slot name=\"tabs\" />\n <div\n :class=\"[\n 'j-admin-layout__content',\n { 'j-admin-layout__content--scrollbar-hidden': hideContentScrollbar }\n ]\"\n >\n <slot />\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { ArrowDown } from '@element-plus/icons-vue'\nimport { JSidebar, type SidebarMenuItem } from '../JSidebar'\nimport { JIconRender } from '../JIconRender'\nimport type { AdminLayoutMenuItem } from './types'\n\ndefineOptions({\n name: 'JAdminLayout'\n})\n\ninterface Props {\n topMenus: AdminLayoutMenuItem[]\n sideMenus: AdminLayoutMenuItem[]\n activeTopMenu?: string\n activeMenu?: string\n title?: string\n logoTitle?: string\n collapsedTitle?: string\n collapsed?: boolean\n username?: string\n profileText?: string\n logoutText?: string\n sidebarCollapsedWidth?: number\n sidebarExpandedWidth?: number\n headerHeight?: string\n contentPadding?: string\n contentBackground?: string\n headerBackground?: string\n showProfile?: boolean\n showLogout?: boolean\n hideContentScrollbar?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n activeTopMenu: '',\n activeMenu: '',\n title: '',\n logoTitle: '',\n collapsedTitle: '',\n collapsed: false,\n username: '',\n profileText: '个人资料',\n logoutText: '退出登录',\n sidebarCollapsedWidth: 80,\n sidebarExpandedWidth: 200,\n headerHeight: '50px',\n contentPadding: '10px',\n contentBackground: '#f0f2f5',\n headerBackground: '#ffffff',\n showProfile: true,\n showLogout: true,\n hideContentScrollbar: false,\n})\n\nconst emit = defineEmits<{\n 'update:collapsed': [value: boolean]\n 'top-menu-select': [path: string]\n 'side-menu-click': [item: SidebarMenuItem]\n profile: []\n logout: []\n}>()\n\nconst innerCollapsed = computed({\n get: () => props.collapsed,\n set: value => emit('update:collapsed', value),\n})\n\nconst layoutStyle = computed(() => ({\n '--j-admin-layout-header-height': props.headerHeight,\n '--j-admin-layout-content-padding': props.contentPadding,\n '--j-admin-layout-content-bg': props.contentBackground,\n '--j-admin-layout-header-bg': props.headerBackground,\n}))\n\nconst handleTopMenuSelect = (path: string) => {\n emit('top-menu-select', path)\n}\n\nconst handleSideMenuClick = (item: SidebarMenuItem) => {\n emit('side-menu-click', item)\n}\n</script>\n\n<style scoped lang=\"scss\">\n.j-admin-layout {\n width: 100vw;\n height: 100vh;\n display: flex;\n flex-direction: row;\n overflow: hidden;\n}\n\n.j-admin-layout__right-panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background-color: var(--j-admin-layout-content-bg);\n}\n\n.j-admin-layout__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n background-color: var(--j-admin-layout-header-bg);\n box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);\n height: var(--j-admin-layout-header-height);\n flex-shrink: 0;\n z-index: 100;\n}\n\n.j-admin-layout__header-left {\n display: flex;\n align-items: center;\n flex: 1;\n height: 100%;\n min-width: 0;\n}\n\n.j-admin-layout__logo {\n padding: 0 $spacing-md;\n display: flex;\n align-items: center;\n height: var(--j-admin-layout-header-height);\n flex-shrink: 0;\n}\n\n.j-admin-layout__logo h2 {\n margin: 0;\n font-size: $font-size-lg;\n font-weight: bold;\n color: $color-primary;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.j-admin-layout__top-menu {\n flex: 1;\n height: var(--j-admin-layout-header-height);\n border-bottom: none;\n min-width: 0;\n}\n\n.j-admin-layout__top-menu-icon {\n margin-right: $spacing-xs;\n}\n\n.j-admin-layout__header-right {\n display: flex;\n align-items: center;\n gap: $spacing-md;\n padding-right: $spacing-md;\n flex-shrink: 0;\n}\n\n.j-admin-layout__user {\n cursor: pointer;\n display: flex;\n align-items: center;\n color: $color-text-regular;\n}\n\n.j-admin-layout__user:hover {\n color: $color-primary;\n}\n\n.j-admin-layout__content-container {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n background-color: var(--j-admin-layout-content-bg);\n}\n\n.j-admin-layout__content {\n padding: var(--j-admin-layout-content-padding);\n flex: 1;\n overflow: auto;\n}\n\n.j-admin-layout__content--scrollbar-hidden {\n scrollbar-width: none;\n -ms-overflow-style: none;\n\n &::-webkit-scrollbar {\n display: none;\n }\n}\n</style>\n","/**\r\n * 递归转换值(处理嵌套对象和数组)\r\n */\r\nfunction deepTransformValue(value: any, transformer: (obj: Record<string, any>) => Record<string, any>): any {\r\n if (Array.isArray(value)) {\r\n return value.map((item) => deepTransformValue(item, transformer))\r\n }\r\n if (value !== null && typeof value === 'object' && !(value instanceof Date)) {\r\n return transformer(value)\r\n }\r\n return value\r\n}\r\n\r\n/**\r\n * 将对象的 key 从小驼峰转为下划线格式(支持深度嵌套)\r\n * @param obj 需要转换的对象\r\n * @param excludeKeys 不需要转换的 key 数组(可选)\r\n */\r\nexport function toSnakeCase<T extends Record<string, any>>(\r\n obj: T,\r\n excludeKeys: string[] = []\r\n): Record<string, any> {\r\n return Object.fromEntries(\r\n Object.entries(obj).map(([key, value]) => {\r\n const newValue = deepTransformValue(value, (v) => toSnakeCase(v, excludeKeys))\r\n if (excludeKeys.includes(key)) {\r\n return [key, newValue]\r\n }\r\n const snakeKey = key.replace(/([A-Z])/g, '_$1').toLowerCase()\r\n return [snakeKey, newValue]\r\n })\r\n )\r\n}\r\n\r\n/**\r\n * 将对象的 key 从下划线格式转为小驼峰(支持深度嵌套)\r\n * @param obj 需要转换的对象\r\n * @param excludeKeys 不需要转换的 key 数组(可选)\r\n */\r\nexport function toCamelCase<T extends Record<string, any>>(\r\n obj: T,\r\n excludeKeys: string[] = []\r\n): Record<string, any> {\r\n return Object.fromEntries(\r\n Object.entries(obj).map(([key, value]) => {\r\n const newValue = deepTransformValue(value, (v) => toCamelCase(v, excludeKeys))\r\n if (excludeKeys.includes(key)) {\r\n return [key, newValue]\r\n }\r\n const camelKey = key.replace(/_([a-z])/g, (_, char) => char.toUpperCase())\r\n return [camelKey, newValue]\r\n })\r\n )\r\n}\r\n\r\n/**\r\n * 从对象中提取指定的 key\r\n * @param obj 源对象\r\n * @param keys 要提取的 key 数组\r\n */\r\nexport function pick<T extends Record<string, any>, K extends keyof T>(\r\n obj: T,\r\n keys: K[]\r\n): Pick<T, K> {\r\n const result = {} as Pick<T, K>\r\n for (const key of keys) {\r\n if (key in obj) {\r\n result[key] = obj[key]\r\n }\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * 从对象中排除指定的 key\r\n * @param obj 源对象\r\n * @param keys 要排除的 key 数组\r\n */\r\nexport function omit<T extends Record<string, any>, K extends keyof T>(\r\n obj: T,\r\n keys: K[]\r\n): Omit<T, K> {\r\n const result = { ...obj }\r\n for (const key of keys) {\r\n delete result[key]\r\n }\r\n return result as Omit<T, K>\r\n}\r\n\r\n/**\r\n * 深拷贝对象\r\n * @param obj 需要拷贝的对象\r\n */\r\nexport function deepClone<T>(obj: T): T {\r\n if (obj === null || typeof obj !== 'object') return obj\r\n if (obj instanceof Date) return new Date(obj.getTime()) as unknown as T\r\n if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags) as unknown as T\r\n if (Array.isArray(obj)) return obj.map((item) => deepClone(item)) as unknown as T\r\n const cloned = {} as Record<string, any>\r\n for (const key of Object.keys(obj)) {\r\n cloned[key] = deepClone((obj as Record<string, any>)[key])\r\n }\r\n return cloned as T\r\n}\r\n\r\n/**\r\n * 过滤对象中的空值(null、undefined、空字符串)\r\n * @param obj 需要过滤的对象\r\n * @param deep 是否递归过滤嵌套对象,默认 false\r\n */\r\nexport function filterEmpty<T extends Record<string, any>>(\r\n obj: T,\r\n deep = false\r\n): Partial<T> {\r\n const result = {} as Record<string, any>\r\n for (const [key, value] of Object.entries(obj)) {\r\n if (value === null || value === undefined || value === '') continue\r\n if (deep && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date)) {\r\n const filtered = filterEmpty(value, true)\r\n if (Object.keys(filtered).length > 0) {\r\n result[key] = filtered\r\n }\r\n } else {\r\n result[key] = value\r\n }\r\n }\r\n return result as Partial<T>\r\n}\r\n\r\n/**\r\n * 将嵌套对象扁平化为单层对象\r\n * @param obj 需要扁平化的对象\r\n * @param prefix key 前缀,默认为空\r\n * @param separator 分隔符,默认为 '.'\r\n * @example flatten({ a: { b: 1, c: { d: 2 } } }) => { 'a.b': 1, 'a.c.d': 2 }\r\n */\r\nexport function flatten(\r\n obj: Record<string, any>,\r\n prefix = '',\r\n separator = '.'\r\n): Record<string, any> {\r\n const result: Record<string, any> = {}\r\n for (const [key, value] of Object.entries(obj)) {\r\n const newKey = prefix ? `${prefix}${separator}${key}` : key\r\n if (value !== null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date)) {\r\n Object.assign(result, flatten(value, newKey, separator))\r\n } else {\r\n result[newKey] = value\r\n }\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * 将扁平化的对象还原为嵌套对象\r\n * @param obj 扁平化的对象\r\n * @param separator 分隔符,默认为 '.'\r\n * @example unflatten({ 'a.b': 1, 'a.c.d': 2 }) => { a: { b: 1, c: { d: 2 } } }\r\n */\r\nexport function unflatten(\r\n obj: Record<string, any>,\r\n separator = '.'\r\n): Record<string, any> {\r\n const result: Record<string, any> = {}\r\n for (const [key, value] of Object.entries(obj)) {\r\n const parts = key.split(separator)\r\n let current = result\r\n for (let i = 0; i < parts.length - 1; i++) {\r\n const k = parts[i] as string\r\n if (!(k in current)) {\r\n current[k] = {}\r\n }\r\n current = current[k]\r\n }\r\n current[parts[parts.length - 1] as string] = value\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * 将 { key: label } 对象转换为 el-table-column 所需的表头数组\r\n * @param fieldMap 字段映射对象\r\n * @example toTableColumns({ id: '主键', name: '名称' }) => [{ id: 'id', label: '主键', prop: 'id' }, ...]\r\n */\r\nexport function toTableColumns(fieldMap: Record<string, string>) {\r\n return Object.entries(fieldMap).map(([key, label]) => ({\r\n id: key,\r\n label,\r\n prop: key,\r\n }))\r\n}\r\n","import type { RouteRecordRaw } from 'vue-router'\r\nimport type { BackendRoute } from './types'\r\n\r\ntype ViewModules = Record<string, () => Promise<unknown>>\r\n\r\ninterface RouteTreeNode extends BackendRoute {\r\n children?: RouteTreeNode[]\r\n}\r\n\r\nexport function getComponentImport(componentPath: string, viewModules: ViewModules): (() => Promise<unknown>) | null {\r\n if (!componentPath) return null\r\n\r\n let normalizedPath = componentPath.replace(/^@\\//, '')\r\n if (!normalizedPath.startsWith('views/')) normalizedPath = `views/${normalizedPath}`\r\n if (!normalizedPath.endsWith('.vue')) normalizedPath = `${normalizedPath}.vue`\r\n\r\n const fullPath = `/src/${normalizedPath}`\r\n\r\n return (viewModules[fullPath] ?? viewModules['/src/views/common/NotFound.vue'] ?? null) as (() => Promise<unknown>) | null\r\n}\r\n\r\nexport function buildRouteTree(routes: BackendRoute[]): RouteTreeNode[] {\r\n const routeMap = new Map<string, RouteTreeNode>()\r\n const rootRoutes: RouteTreeNode[] = []\r\n\r\n routes.forEach(route => routeMap.set(route.name, { ...route, children: [] }))\r\n\r\n routes.forEach(route => {\r\n const currentRoute = routeMap.get(route.name)!\r\n if (!route.parent_name) {\r\n rootRoutes.push(currentRoute)\r\n } else {\r\n const parentRoute = routeMap.get(route.parent_name)\r\n if (parentRoute) {\r\n parentRoute.children ??= []\r\n parentRoute.children.push(currentRoute)\r\n } else {\r\n rootRoutes.push(currentRoute)\r\n }\r\n }\r\n })\r\n return rootRoutes\r\n}\r\n\r\nexport function transformBackendRoutes(\r\n backendRoutes: RouteTreeNode[],\r\n viewModules: ViewModules,\r\n projectName?: string\r\n): RouteRecordRaw[] {\r\n return backendRoutes\r\n .filter(route => !projectName || !route.project || route.project === projectName)\r\n .map(route => {\r\n const routeConfig: Partial<RouteRecordRaw> = {\r\n path: route.path,\r\n name: route.name,\r\n meta: {\r\n requiresAuth: route.requiresAuth === 1,\r\n title: route.title,\r\n permissions: route.permissions\r\n ? route.permissions.split(',').map(p => p.trim()).filter(Boolean)\r\n : [],\r\n params: route.params\r\n ? route.params.split('&').map(p => p.trim()).filter(Boolean)\r\n : [],\r\n },\r\n }\r\n\r\n const component = getComponentImport(route.component, viewModules)\r\n if (component) routeConfig.component = component as RouteRecordRaw['component']\r\n\r\n if (route.redirect) routeConfig.redirect = route.redirect\r\n\r\n if (route.children?.length) {\r\n routeConfig.children = transformBackendRoutes(route.children, viewModules, projectName)\r\n }\r\n\r\n return routeConfig as RouteRecordRaw\r\n })\r\n}\r\n\r\nexport function findFirstAllowedRoute(\n backendRoutes: BackendRoute[],\n routePermissions: string[],\n layoutRouteName: string,\n projectName?: string\n): BackendRoute | undefined {\n const routeMap = new Map<string, BackendRoute>()\n backendRoutes.forEach(route => routeMap.set(route.name, route))\n\n const isDescendantOfLayout = (route: BackendRoute): boolean => {\n let parentName = route.parent_name\n const visited = new Set<string>()\n\n while (parentName) {\n if (parentName === layoutRouteName) return true\n if (visited.has(parentName)) return false\n\n visited.add(parentName)\n const parentRoute = routeMap.get(parentName)\n if (!parentRoute) return false\n parentName = parentRoute.parent_name\n }\n\n return false\n }\n\n return backendRoutes\n .filter(route =>\n route.name !== layoutRouteName &&\n route.is_show === 1 &&\n route.component &&\n routePermissions.includes(route.code) &&\n isDescendantOfLayout(route) &&\n (!projectName || !route.project || route.project === projectName)\n )\n .sort((a, b) => a.sorts - b.sorts)[0]\n}\n","import type { NavigationGuardNext, Router } from 'vue-router'\nimport NProgress from 'nprogress'\nimport 'nprogress/nprogress.css'\nimport { ElMessage } from 'element-plus'\nimport type { RouterGuardOptions } from './types'\nimport { buildRouteTree, transformBackendRoutes } from './helpers'\n\nNProgress.configure({ showSpinner: false })\n\nconst isDev = import.meta.env.DEV\nconst log = (...args: unknown[]) => { if (isDev) console.log('[Router]', ...args) }\nconst warn = (...args: unknown[]) => { if (isDev) console.warn('[Router]', ...args) }\nconst logError = (...args: unknown[]) => { console.error('[Router]', ...args) }\n\nexport function createRouterGuard(router: Router, options: RouterGuardOptions) {\n const {\n getRouteStore,\n getPermissionStore,\n getUserStore,\n isAuthenticated,\n viewModules,\n homeComponent,\n notFoundComponent,\n projectName,\n layoutRouteName = 'Layout',\n publicPaths = ['/login', '/register'],\n loginRouteName = 'login',\n forbiddenRouteName = 'Forbidden',\n homeRouteName = 'Home',\n homeRoutePath = 'home',\n homeTitle = '\\u9996\\u9875',\n noPermissionMessage = '\\u6682\\u65e0\\u6743\\u9650',\n } = options\n\n let hasAddedRoutes = false\n\n function addDynamicRoutes(backendRoutes: ReturnType<typeof getRouteStore>['backendRoutes']) {\n const treeRoutes = buildRouteTree(backendRoutes)\n const layoutRoute = treeRoutes.find(route => route.name === layoutRouteName)\n const childRoutes = layoutRoute?.children\n ? transformBackendRoutes(layoutRoute.children, viewModules, projectName)\n : []\n\n childRoutes.forEach(route => {\n if (route.name && router.hasRoute(route.name)) return\n router.addRoute(layoutRouteName, route)\n log(`Add route: ${String(route.name)} -> ${route.path}`)\n })\n\n if (!router.hasRoute(homeRouteName)) {\n router.addRoute(layoutRouteName, {\n path: homeRoutePath,\n name: homeRouteName,\n component: homeComponent as never,\n meta: { title: homeTitle },\n })\n }\n\n if (!router.hasRoute('NotFound')) {\n router.addRoute({\n path: '/:pathMatch(.*)*',\n name: 'NotFound',\n component: notFoundComponent as never,\n })\n }\n\n log(`Dynamic routes added: ${childRoutes.length}`)\n }\n\n function redirectToHomeOrContinue(\n toName: ReturnType<Router['resolve']>['name'],\n next: NavigationGuardNext\n ) {\n if (toName === homeRouteName) {\n next()\n return\n }\n\n if (router.hasRoute(homeRouteName)) {\n next({ name: homeRouteName, replace: true })\n } else {\n next()\n }\n }\n\n router.beforeEach(async (to, _from, next) => {\n NProgress.start()\n\n if (isAuthenticated() && !hasAddedRoutes) {\n try {\n const routeStore = getRouteStore()\n const permissionStore = getPermissionStore()\n\n await routeStore.initRoutes()\n await permissionStore.loadUserPermissions()\n\n addDynamicRoutes(routeStore.backendRoutes)\n hasAddedRoutes = true\n\n if (to.path === '/' || to.path === '') {\n redirectToHomeOrContinue(to.name, next)\n return\n }\n\n if (to.name === layoutRouteName) {\n redirectToHomeOrContinue(to.name, next)\n return\n }\n\n const currentRoute = routeStore.backendRoutes.find(route => route.name === to.name)\n if (currentRoute && !permissionStore.routePermissions.includes(currentRoute.code)) {\n warn('No route permission:', to.path)\n next({ name: forbiddenRouteName, replace: true })\n return\n }\n\n next({\n path: to.path,\n query: to.query,\n hash: to.hash,\n replace: true,\n })\n return\n } catch (err) {\n logError('Failed to load route permissions:', err)\n hasAddedRoutes = false\n await getUserStore().logout()\n next({ name: loginRouteName, replace: true })\n return\n }\n }\n\n if (publicPaths.includes(to.path)) {\n if (isAuthenticated()) {\n next({ path: '/', replace: true })\n } else {\n next()\n }\n return\n }\n\n if (!isAuthenticated()) {\n next({ name: loginRouteName, replace: true })\n return\n }\n\n const permissionStore = getPermissionStore()\n const routeStore = getRouteStore()\n\n if (to.name === homeRouteName) {\n next()\n return\n }\n\n if (permissionStore.routePermissions.length === 0) {\n if (to.path !== '/') {\n ElMessage.warning(noPermissionMessage)\n next({ path: '/', replace: true })\n } else {\n redirectToHomeOrContinue(to.name, next)\n }\n return\n }\n\n if (to.path === '/') {\n redirectToHomeOrContinue(to.name, next)\n return\n }\n\n if (to.name === layoutRouteName) {\n redirectToHomeOrContinue(to.name, next)\n return\n }\n\n const currentRoute = routeStore.backendRoutes.find(route => route.name === to.name)\n if (currentRoute && !permissionStore.routePermissions.includes(currentRoute.code)) {\n warn('No route permission:', to.path)\n next({ name: forbiddenRouteName, replace: true })\n return\n }\n\n next()\n })\n\n router.afterEach(() => NProgress.done())\n\n return {\n resetRouterState: () => { hasAddedRoutes = false },\n }\n}\n","import type { App } from 'vue'\r\nimport { JButton } from './components/JButton'\r\nimport { JUploadImg } from './components/JUploadImg'\r\nimport { JIconRender } from './components/JIconRender'\r\nimport { JSearchHeader } from './components/JSearchHeader'\nimport { JImportExcel } from './components/JImportExcel'\nimport { JSidebar, JSideMenuItem } from './components/JSidebar'\nimport { JAdminLayout } from './components/JAdminLayout'\n\r\n// 组件列表,新增组件后在此处注册\r\nconst components = [JButton, JUploadImg, JIconRender, JSearchHeader, JImportExcel, JSidebar, JSideMenuItem, JAdminLayout]\n\r\n// 全量安装插件(app.use(JgyComponents))\r\nconst install = (app: App) => {\r\n components.forEach((component) => {\r\n app.component(component.name ?? component.__name ?? '', component)\r\n })\r\n}\r\n\r\n// 默认导出插件对象\r\nexport default { install }\r\n\r\n// 按需导出各组件\r\nexport { JButton, JUploadImg, JIconRender, JSearchHeader, JImportExcel, JSidebar, JSideMenuItem, JAdminLayout }\n\r\n// 导出工具方法\r\nexport { toSnakeCase, toCamelCase, pick, omit, deepClone, filterEmpty, flatten, unflatten, toTableColumns } from './utils'\r\n\r\n// 导出路由工具\r\nexport { createRouterGuard, buildRouteTree, transformBackendRoutes, findFirstAllowedRoute, getComponentImport } from './router'\r\nexport type { BackendRoute, RouteStoreAdapter, PermissionStoreAdapter, UserStoreAdapter, RouterGuardOptions } from './router'\r\n\r\n// 导出类型\r\nexport type { ButtonType, ButtonSize } from './components/JButton'\r\nexport type { JUploadImgProps, JUploadImgEmits, ImageItem } from './components/JUploadImg'\r\nexport type { JIconRenderProps } from './components/JIconRender'\r\nexport type { JSearchHeaderProps } from './components/JSearchHeader'\r\nexport type { JImportExcelProps, ApiFn } from './components/JImportExcel'\nexport type { SidebarMenuItem, JSidebarProps, JSideMenuItemProps } from './components/JSidebar'\nexport type { AdminLayoutMenuItem, JAdminLayoutProps } from './components/JAdminLayout'\n"],"names":["props","__props","emit","__emit","handleClick","event","_createElementBlock","_openBlock","_hoisted_2","$slots","_hoisted_3","_renderSlot","_ctx","imageUrl","ref","showPreview","showTipText","handlePreviewSingle","handleRemoveSingle","ElMessage","imageList","uploading","initImageList","urls","url","index","watch","val","handleDragEnd","emitMultipleUpdate","handleRemove","handleFileChange","uploadFile","file","error","item","_hoisted_1","_createVNode","_unref","draggable","$event","_withCtx","element","_createElementVNode","_component_el_image","img","_withModifiers","_component_el_icon","Delete","_createBlock","_component_el_upload","Loading","Plus","_Fragment","_hoisted_5","_hoisted_6","ZoomIn","_component_el_image_viewer","_hoisted_7","_hoisted_8","_toDisplayString","_mergeProps","$attrs","formItemsRef","expanded","isAnimated","itemCount","collapsedHeight","shouldCollapse","computed","measureItems","items","lastVisibleItem","wrapperRect","lastVisibleRect","toggleExpand","el","onEnd","observer","onMounted","onBeforeUnmount","_component_el_card","_component_el_form","_normalizeClass","_component_el_button","Search","_cache","Refresh","_createTextVNode","ArrowDown","visible","_useModel","submitting","fieldMap","renderData","stats","statusMap","dataColumns","key","label","handleOpen","res","raw","reader","e","workbook","XLSX","wsName","ws","jsonData","propList","col","list","row","values","prop","handleDel","idx","handleConfirm","data","_status","_error","rest","r","handleDownloadTemplate","wb","headers","tr","h","handleClose","_component_el_dialog","_component_el_divider","_component_el_link","_component_el_row","_component_el_col","_hoisted_4","_component_el_table","_renderList","_component_el_table_column","$index","_component_el_sub_menu","JIconRender","child","_component_JSideMenuItem","_component_el_menu_item","innerCollapsed","toggleCollapse","_normalizeStyle","_a","_component_el_menu","route","JSideMenuItem","value","layoutStyle","handleTopMenuSelect","path","handleSideMenuClick","JSidebar","sidebarCollapsed","toggle","menu","_component_el_dropdown","_component_el_dropdown_menu","_component_el_dropdown_item","deepTransformValue","transformer","toSnakeCase","obj","excludeKeys","newValue","v","toCamelCase","_","char","pick","keys","result","omit","deepClone","cloned","filterEmpty","deep","filtered","flatten","prefix","separator","newKey","unflatten","parts","current","i","k","toTableColumns","getComponentImport","componentPath","viewModules","normalizedPath","fullPath","buildRouteTree","routes","routeMap","rootRoutes","currentRoute","parentRoute","transformBackendRoutes","backendRoutes","projectName","routeConfig","p","component","findFirstAllowedRoute","routePermissions","layoutRouteName","isDescendantOfLayout","parentName","visited","a","b","NProgress","log","args","warn","logError","createRouterGuard","router","options","getRouteStore","getPermissionStore","getUserStore","isAuthenticated","homeComponent","notFoundComponent","publicPaths","loginRouteName","forbiddenRouteName","homeRouteName","homeRoutePath","homeTitle","noPermissionMessage","hasAddedRoutes","addDynamicRoutes","layoutRoute","childRoutes","redirectToHomeOrContinue","toName","next","to","_from","routeStore","permissionStore","err","components","JButton","JUploadImg","JSearchHeader","JImportExcel","JAdminLayout","install","app"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/components/JButton/JButton.vue","../src/components/JUploadImg/JUploadImg.vue","../src/components/JIconRender/JIconRender.vue","../src/components/JSearchHeader/JSearchHeader.vue","../src/components/JImportExcel/JImportExcel.vue","../src/components/JSidebar/JSideMenuItem.vue","../src/components/JSidebar/JSidebar.vue","../src/components/JAdminLayout/JAdminLayout.vue","../src/utils/transform.ts","../src/router/helpers.ts","../src/router/guards.ts","../src/index.ts"],"sourcesContent":["<template>\r\n <button\r\n class=\"j-button\"\r\n :class=\"[\r\n `j-button--${type}`,\r\n `j-button--${size}`,\r\n {\r\n 'j-button--plain': plain,\r\n 'j-button--round': round,\r\n 'j-button--disabled': disabled,\r\n 'j-button--loading': loading,\r\n },\r\n ]\"\r\n :disabled=\"disabled || loading\"\r\n @click=\"handleClick\"\r\n >\r\n <span v-if=\"loading\" class=\"j-button__loading-icon\" />\r\n <span v-if=\"$slots.default\" class=\"j-button__text\">\r\n <slot />\r\n </span>\r\n </button>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport type { ButtonType, ButtonSize } from './types'\r\n\r\ninterface Props {\r\n type?: ButtonType\r\n size?: ButtonSize\r\n plain?: boolean\r\n round?: boolean\r\n disabled?: boolean\r\n loading?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n type: 'default',\r\n size: 'medium',\r\n plain: false,\r\n round: false,\r\n disabled: false,\r\n loading: false,\r\n})\r\n\r\nconst emit = defineEmits<{\r\n click: [event: MouseEvent]\r\n}>()\r\n\r\nfunction handleClick(event: MouseEvent) {\r\n if (!props.disabled && !props.loading) {\r\n emit('click', event)\r\n }\r\n}\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.j-button {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: $spacing-xs;\r\n padding: 8px 16px;\r\n font-size: $font-size-base;\r\n font-weight: 400;\r\n line-height: 1;\r\n white-space: nowrap;\r\n cursor: pointer;\r\n border: 1px solid $color-border;\r\n border-radius: $border-radius-base;\r\n background-color: $color-white;\r\n color: $color-text-regular;\r\n transition: $transition-fast;\r\n outline: none;\r\n user-select: none;\r\n\r\n &:hover {\r\n color: $color-primary;\r\n border-color: $color-primary;\r\n background-color: color.adjust($color-primary, $lightness: 40%);\r\n }\r\n\r\n // 尺寸\r\n &--small {\r\n padding: 5px 12px;\r\n font-size: $font-size-xs;\r\n }\r\n\r\n &--medium {\r\n padding: 8px 16px;\r\n font-size: $font-size-base;\r\n }\r\n\r\n &--large {\r\n padding: 12px 20px;\r\n font-size: $font-size-md;\r\n }\r\n\r\n // 类型\r\n &--primary {\r\n background-color: $color-primary;\r\n border-color: $color-primary;\r\n color: $color-white;\r\n &:hover {\r\n background-color: color.adjust($color-primary, $lightness: 10%);\r\n border-color: color.adjust($color-primary, $lightness: 10%);\r\n color: $color-white;\r\n }\r\n }\r\n\r\n &--success {\r\n background-color: $color-success;\r\n border-color: $color-success;\r\n color: $color-white;\r\n &:hover {\r\n background-color: color.adjust($color-success, $lightness: 10%);\r\n border-color: color.adjust($color-success, $lightness: 10%);\r\n color: $color-white;\r\n }\r\n }\r\n\r\n &--danger {\r\n background-color: $color-danger;\r\n border-color: $color-danger;\r\n color: $color-white;\r\n &:hover {\r\n background-color: color.adjust($color-danger, $lightness: 10%);\r\n border-color: color.adjust($color-danger, $lightness: 10%);\r\n color: $color-white;\r\n }\r\n }\r\n\r\n &--warning {\r\n background-color: $color-warning;\r\n border-color: $color-warning;\r\n color: $color-white;\r\n &:hover {\r\n background-color: color.adjust($color-warning, $lightness: 10%);\r\n border-color: color.adjust($color-warning, $lightness: 10%);\r\n color: $color-white;\r\n }\r\n }\r\n\r\n // 朴素按钮\r\n &--plain {\r\n &.j-button--primary {\r\n background-color: color.adjust($color-primary, $lightness: 40%);\r\n color: $color-primary;\r\n &:hover {\r\n background-color: $color-primary;\r\n color: $color-white;\r\n }\r\n }\r\n }\r\n\r\n // 圆角\r\n &--round {\r\n border-radius: $border-radius-round;\r\n }\r\n\r\n // 禁用\r\n &--disabled {\r\n opacity: 0.5;\r\n cursor: not-allowed;\r\n pointer-events: none;\r\n }\r\n\r\n // 加载\r\n &--loading {\r\n opacity: 0.7;\r\n cursor: not-allowed;\r\n pointer-events: none;\r\n }\r\n\r\n &__loading-icon {\r\n display: inline-block;\r\n width: 14px;\r\n height: 14px;\r\n border: 2px solid currentColor;\r\n border-top-color: transparent;\r\n border-radius: 50%;\r\n animation: j-spin 0.6s linear infinite;\r\n }\r\n\r\n @keyframes j-spin {\r\n to {\r\n transform: rotate(360deg);\r\n }\r\n }\r\n}\r\n</style>\r\n","<template>\r\n <div class=\"j-upload-img-container\">\r\n <!-- 多图模式 -->\r\n <template v-if=\"multiple\">\r\n <div class=\"images-wrapper\">\r\n <draggable\r\n v-model=\"imageList\"\r\n class=\"images-list\"\r\n item-key=\"uid\"\r\n :animation=\"200\"\r\n :disabled=\"disabled\"\r\n @end=\"handleDragEnd\"\r\n >\r\n <template #item=\"{ element, index }\">\r\n <div class=\"image-item\">\r\n <el-image\r\n :src=\"element.url\"\r\n :preview-src-list=\"imageList.map(img => img.url)\"\r\n :initial-index=\"index\"\r\n fit=\"cover\"\r\n class=\"image-preview\"\r\n :preview-teleported=\"true\"\r\n :hide-on-click-modal=\"true\"\r\n />\r\n <div v-if=\"!disabled\" class=\"delete-btn\" @click.stop=\"handleRemove(index)\">\r\n <el-icon class=\"icon-delete\">\r\n <Delete />\r\n </el-icon>\r\n </div>\r\n </div>\r\n </template>\r\n </draggable>\r\n\r\n <!-- 多图上传按钮 -->\r\n <el-upload\r\n v-if=\"!disabled && (!limit || imageList.length < limit)\"\r\n class=\"image-uploader\"\r\n :auto-upload=\"false\"\r\n :show-file-list=\"false\"\r\n :on-change=\"handleFileChange\"\r\n :disabled=\"uploading\"\r\n list-type=\"picture-card\"\r\n :accept=\"accept\"\r\n >\r\n <el-icon v-if=\"!uploading\" class=\"uploader-icon\">\r\n <Plus />\r\n </el-icon>\r\n <el-icon v-else class=\"uploader-icon is-loading\">\r\n <Loading />\r\n </el-icon>\r\n </el-upload>\r\n </div>\r\n </template>\r\n\r\n <!-- 单图模式 -->\r\n <template v-else>\r\n <!-- 已有图片:独立展示,hover 显示操作遮罩 -->\r\n <div v-if=\"imageUrl\" class=\"image-item single-image-item\">\r\n <el-image\r\n :src=\"imageUrl\"\r\n fit=\"cover\"\r\n class=\"image-preview\"\r\n />\r\n <div class=\"image-actions\">\r\n <el-icon class=\"action-icon\" @click.stop=\"handlePreviewSingle\">\r\n <ZoomIn />\r\n </el-icon>\r\n <el-icon v-if=\"!disabled\" class=\"action-icon\" @click.stop=\"handleRemoveSingle\">\r\n <Delete />\r\n </el-icon>\r\n </div>\r\n </div>\r\n\r\n <!-- 无图片:显示上传按钮 -->\r\n <el-upload\r\n v-else\r\n class=\"image-uploader\"\r\n :auto-upload=\"false\"\r\n :show-file-list=\"false\"\r\n :on-change=\"handleFileChange\"\r\n :disabled=\"disabled || uploading\"\r\n :accept=\"accept\"\r\n list-type=\"picture-card\"\r\n >\r\n <el-icon class=\"uploader-icon\">\r\n <Plus v-if=\"!uploading\" />\r\n <Loading v-else class=\"is-loading\" />\r\n </el-icon>\r\n </el-upload>\r\n\r\n <!-- 大图预览 -->\r\n <el-image-viewer\r\n v-if=\"showPreview\"\r\n :url-list=\"[imageUrl]\"\r\n :teleported=\"true\"\r\n @close=\"showPreview = false\"\r\n />\r\n </template>\r\n\r\n <div v-if=\"showTipText\" class=\"upload-tip\">\r\n <span>{{ tip }}</span>\r\n <span v-if=\"multiple && limit\"> (最多 {{ limit }} 张)</span>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, watch } from 'vue'\r\nimport { ElMessage, ElImage, ElIcon, ElUpload, ElImageViewer } from 'element-plus'\r\nimport type { UploadFile } from 'element-plus'\r\nimport { Plus, Loading, Delete, ZoomIn } from '@element-plus/icons-vue'\r\nimport draggable from 'vuedraggable'\r\nimport type { ImageItem } from './types'\r\n\r\ndefineOptions({\r\n name: 'JUploadImg'\r\n})\r\n\r\nconst props = withDefaults(defineProps<{\r\n modelValue?: string | string[]\r\n disabled?: boolean\r\n multiple?: boolean\r\n limit?: number\r\n maxSize?: number\r\n accept?: string\r\n tip?: string\r\n showTip?: boolean\r\n /** 自定义上传函数,接收 File 返回图片 URL */\r\n uploadFn?: (file: File) => Promise<string>\r\n}>(), {\r\n modelValue: '',\r\n disabled: false,\r\n multiple: false,\r\n limit: 9,\r\n maxSize: 2,\r\n accept: 'image/jpeg,image/png,image/jpg,image/gif',\r\n tip: '只能上传jpg/png/gif格式的图片,且不超过2MB',\r\n showTip: true,\r\n uploadFn: undefined\r\n})\r\n\r\nconst emit = defineEmits<{\r\n (e: 'update:modelValue', value: string | string[]): void\r\n (e: 'success', url: string): void\r\n (e: 'error', error: any): void\r\n}>()\r\n\r\n// 单图模式\r\nconst imageUrl = ref<string>('')\r\nconst showPreview = ref(false)\r\nconst showTipText = props.showTip\r\n\r\nconst handlePreviewSingle = () => {\r\n showPreview.value = true\r\n}\r\n\r\nconst handleRemoveSingle = () => {\r\n imageUrl.value = ''\r\n emit('update:modelValue', '')\r\n ElMessage.success('删除成功')\r\n}\r\n\r\n// 多图模式\r\nconst imageList = ref<ImageItem[]>([])\r\nconst uploading = ref(false)\r\n\r\n// 初始化图片列表(多图模式)\r\nconst initImageList = (urls: string[]) => {\r\n imageList.value = urls.map((url, index) => ({\r\n uid: Date.now() + index,\r\n url\r\n }))\r\n}\r\n\r\n// 监听外部值变化\r\nwatch(() => props.modelValue, (val) => {\r\n if (props.multiple) {\r\n if (Array.isArray(val) && val.length > 0) {\r\n initImageList(val)\r\n } else {\r\n imageList.value = []\r\n }\r\n } else {\r\n if (typeof val === 'string') {\r\n imageUrl.value = val\r\n } else {\r\n imageUrl.value = ''\r\n }\r\n }\r\n}, { immediate: true })\r\n\r\n// 拖拽结束(多图模式)\r\nconst handleDragEnd = () => {\r\n emitMultipleUpdate()\r\n}\r\n\r\n// 删除图片(多图模式)\r\nconst handleRemove = (index: number) => {\r\n imageList.value.splice(index, 1)\r\n emitMultipleUpdate()\r\n ElMessage.success('删除成功')\r\n}\r\n\r\n// 文件改变时触发\r\nconst handleFileChange = async (uploadFile: UploadFile) => {\r\n const file = uploadFile.raw as File\r\n\r\n if (!file) {\r\n ElMessage.error('文件不存在,请重试')\r\n return\r\n }\r\n\r\n if (file.size > props.maxSize * 1024 * 1024) {\r\n ElMessage.error(`图片大小不能超过 ${props.maxSize}MB`)\r\n return\r\n }\r\n\r\n if (!props.uploadFn) {\r\n ElMessage.error('未配置上传函数 (uploadFn)')\r\n return\r\n }\r\n\r\n try {\r\n uploading.value = true\r\n const url = await props.uploadFn(file)\r\n\r\n if (props.multiple) {\r\n imageList.value.push({ uid: Date.now(), url })\r\n emitMultipleUpdate()\r\n } else {\r\n imageUrl.value = url\r\n emit('update:modelValue', url)\r\n }\r\n\r\n emit('success', url)\r\n ElMessage.success('上传成功')\r\n } catch (error) {\r\n console.error('上传出错:', error)\r\n ElMessage.error('上传失败,请重试')\r\n emit('error', error)\r\n } finally {\r\n uploading.value = false\r\n }\r\n}\r\n\r\n// 触发多图更新\r\nconst emitMultipleUpdate = () => {\r\n const urls = imageList.value.map(item => item.url)\r\n emit('update:modelValue', urls)\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n.j-upload-img-container {\r\n display: inline-block;\r\n}\r\n\r\n/* 多图模式样式 */\r\n.images-wrapper {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 8px;\r\n align-items: flex-start;\r\n}\r\n\r\n.images-list {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 8px;\r\n}\r\n\r\n.image-item {\r\n position: relative;\r\n width: 74px;\r\n height: 74px;\r\n border: 1px solid var(--el-border-color);\r\n border-radius: 6px;\r\n overflow: hidden;\r\n cursor: move;\r\n}\r\n\r\n.image-preview {\r\n width: 100%;\r\n height: 100%;\r\n}\r\n\r\n.delete-btn {\r\n position: absolute;\r\n top: 2px;\r\n right: 2px;\r\n width: 20px;\r\n height: 20px;\r\n background-color: rgba(0, 0, 0, 0.6);\r\n border-radius: 50%;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n opacity: 0;\r\n transition: opacity 0.3s;\r\n cursor: pointer;\r\n z-index: 1;\r\n}\r\n\r\n.image-item:hover .delete-btn {\r\n opacity: 1;\r\n}\r\n\r\n.delete-btn:hover {\r\n background-color: rgba(0, 0, 0, 0.8);\r\n}\r\n\r\n.icon-delete {\r\n font-size: 12px;\r\n color: #fff;\r\n}\r\n\r\n/* 单图和多图共用样式 */\r\n.image-uploader {\r\n display: inline-block;\r\n vertical-align: top;\r\n}\r\n\r\n.image-uploader :deep(.el-upload) {\r\n border: 1px dashed var(--el-border-color);\r\n border-radius: 6px;\r\n cursor: pointer;\r\n position: relative;\r\n overflow: hidden;\r\n transition: var(--el-transition-duration-fast);\r\n width: 74px !important;\r\n height: 74px !important;\r\n}\r\n\r\n.image-uploader :deep(.el-upload:hover) {\r\n border-color: var(--el-color-primary);\r\n}\r\n\r\n.uploader-icon {\r\n font-size: 20px;\r\n color: #8c939d;\r\n width: 74px;\r\n height: 74px;\r\n text-align: center;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.single-image-item {\r\n cursor: default;\r\n}\r\n\r\n.image-actions {\r\n position: absolute;\r\n inset: 0;\r\n background-color: rgba(0, 0, 0, 0.5);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 12px;\r\n opacity: 0;\r\n transition: opacity 0.3s;\r\n}\r\n\r\n.single-image-item:hover .image-actions,\r\n.image-item:hover .image-actions {\r\n opacity: 1;\r\n}\r\n\r\n.action-icon {\r\n font-size: 18px;\r\n color: #fff;\r\n cursor: pointer;\r\n transition: transform 0.2s;\r\n}\r\n\r\n.action-icon:hover {\r\n transform: scale(1.2);\r\n}\r\n\r\n.upload-tip {\r\n margin-top: 8px;\r\n font-size: 12px;\r\n color: #909399;\r\n line-height: 1.5;\r\n}\r\n</style>\r\n","<template>\r\n <Icon v-if=\"icon\" :icon=\"icon\" :width=\"size\" :height=\"size\" v-bind=\"$attrs\" />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { Icon } from '@iconify/vue'\r\n\r\ndefineOptions({\r\n name: 'JIconRender'\r\n})\r\n\r\nwithDefaults(defineProps<{\r\n icon: string\r\n size?: string | number\r\n}>(), {\r\n size: 24,\r\n})\r\n</script>\r\n","<template>\r\n <el-card shadow=\"never\" class=\"j-search-header-card\">\r\n <el-form inline class=\"search-form\">\r\n <div\r\n ref=\"formItemsRef\"\r\n class=\"form-items-wrapper\"\r\n :class=\"{ 'is-animated': isAnimated }\"\r\n >\r\n <slot />\r\n </div>\r\n </el-form>\r\n\r\n <div class=\"action-bar\" :style=\"{ marginTop: expanded ? '0px' : '10px' }\">\r\n <div class=\"action-left\">\r\n <el-button v-if=\"showAdd\" type=\"primary\" :icon=\"Plus\" @click=\"emit('add')\">\r\n {{ addText }}\r\n </el-button>\r\n <el-button\r\n v-if=\"showBatchDelete\"\r\n type=\"danger\"\r\n :icon=\"Delete\"\r\n :disabled=\"selectedCount === 0\"\r\n @click=\"emit('batchDelete')\"\r\n >\r\n 批量删除{{ selectedCount ? `(${selectedCount})` : '' }}\r\n </el-button>\r\n <el-button v-if=\"showSearch\" type=\"primary\" :icon=\"Search\" @click=\"emit('search')\">搜索</el-button>\r\n <el-button v-if=\"showReset\" :icon=\"Refresh\" @click=\"emit('reset')\">重置</el-button>\r\n <slot name=\"actions\" />\r\n </div>\r\n <el-button\r\n v-if=\"shouldCollapse\"\r\n link\r\n type=\"primary\"\r\n @click=\"toggleExpand\"\r\n >\r\n {{ expanded ? '收起' : '展开' }}\r\n <el-icon class=\"toggle-icon\" :class=\"{ 'is-expanded': expanded }\">\r\n <ArrowDown />\r\n </el-icon>\r\n </el-button>\r\n </div>\r\n </el-card>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted, onBeforeUnmount } from 'vue'\r\nimport { ElCard, ElForm, ElButton, ElIcon } from 'element-plus'\r\nimport { Search, Refresh, Plus, Delete, ArrowDown } from '@element-plus/icons-vue'\r\n\r\ndefineOptions({\r\n name: 'JSearchHeader'\r\n})\r\n\r\nconst props = withDefaults(defineProps<{\r\n selectedCount?: number\r\n addText?: string\r\n defaultVisible?: number\r\n showAdd?: boolean\r\n showBatchDelete?: boolean\r\n showSearch?: boolean\r\n showReset?: boolean\r\n}>(), {\r\n selectedCount: 0,\r\n addText: '新增',\r\n defaultVisible: 5,\r\n showAdd: true,\r\n showBatchDelete: true,\r\n showSearch: true,\r\n showReset: true\r\n})\r\n\r\nconst emit = defineEmits<{\r\n search: []\r\n reset: []\r\n add: []\r\n batchDelete: []\r\n}>()\r\n\r\nconst formItemsRef = ref<HTMLElement>()\r\nconst expanded = ref(false)\r\nconst isAnimated = ref(false)\r\nconst itemCount = ref(0)\r\nconst collapsedHeight = ref(0)\r\n\r\nconst shouldCollapse = computed(() => itemCount.value > props.defaultVisible)\r\n\r\nconst measureItems = () => {\r\n if (!formItemsRef.value) return\r\n const items = Array.from(formItemsRef.value.children) as HTMLElement[]\r\n itemCount.value = items.length\r\n\r\n const lastVisibleItem = items[props.defaultVisible - 1]\r\n if (lastVisibleItem && formItemsRef.value) {\r\n const wrapperRect = formItemsRef.value.getBoundingClientRect()\r\n const lastVisibleRect = lastVisibleItem.getBoundingClientRect()\r\n collapsedHeight.value = lastVisibleRect.bottom - wrapperRect.top\r\n }\r\n}\r\n\r\nconst toggleExpand = () => {\r\n const el = formItemsRef.value\r\n if (!el) return\r\n\r\n if (!expanded.value) {\r\n expanded.value = true\r\n el.style.maxHeight = el.scrollHeight + 'px'\r\n const onEnd = () => {\r\n el.style.maxHeight = 'none'\r\n el.removeEventListener('transitionend', onEnd)\r\n }\r\n el.addEventListener('transitionend', onEnd)\r\n } else {\r\n measureItems()\r\n expanded.value = false\r\n el.style.maxHeight = el.scrollHeight + 'px'\r\n el.offsetHeight\r\n el.style.maxHeight = collapsedHeight.value + 'px'\r\n }\r\n}\r\n\r\nlet observer: MutationObserver | null = null\r\n\r\nonMounted(() => {\r\n measureItems()\r\n if (shouldCollapse.value && formItemsRef.value) {\r\n formItemsRef.value.style.maxHeight = collapsedHeight.value + 'px'\r\n }\r\n requestAnimationFrame(() => {\r\n requestAnimationFrame(() => {\r\n isAnimated.value = true\r\n })\r\n })\r\n if (formItemsRef.value) {\r\n observer = new MutationObserver(() => {\r\n measureItems()\r\n if (shouldCollapse.value && !expanded.value && formItemsRef.value) {\r\n formItemsRef.value.style.maxHeight = collapsedHeight.value + 'px'\r\n }\r\n })\r\n observer.observe(formItemsRef.value, { childList: true })\r\n }\r\n})\r\n\r\nonBeforeUnmount(() => {\r\n observer?.disconnect()\r\n})\r\n</script>\r\n\r\n<style scoped>\r\n.j-search-header-card :deep(.el-card__body) {\r\n padding: 16px 20px 12px;\r\n}\r\n\r\n.search-form {\r\n display: flex;\r\n flex-wrap: wrap;\r\n align-items: center;\r\n gap: 0;\r\n}\r\n\r\n.form-items-wrapper {\r\n display: flex;\r\n flex-wrap: wrap;\r\n align-items: center;\r\n overflow: hidden;\r\n}\r\n\r\n.form-items-wrapper.is-animated {\r\n transition: max-height 0.3s ease-in-out;\r\n}\r\n\r\n.form-items-wrapper :deep(.el-form-item) {\r\n margin-bottom: 10px;\r\n margin-right: 16px;\r\n}\r\n\r\n.action-bar {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding-top: 10px;\r\n border-top: 1px solid #ebeef5;\r\n}\r\n\r\n.action-left {\r\n display: flex;\r\n gap: 8px;\r\n}\r\n\r\n.toggle-icon {\r\n margin-left: 2px;\r\n transition: transform 0.25s;\r\n}\r\n\r\n.toggle-icon.is-expanded {\r\n transform: rotate(180deg);\r\n}\r\n</style>\r\n","<template>\r\n <el-dialog\r\n v-model=\"visible\"\r\n :title=\"props.title\"\r\n width=\"900px\"\r\n :close-on-click-modal=\"false\"\r\n @open=\"handleOpen\"\r\n @close=\"handleClose\"\r\n >\r\n <!-- 上传区域 -->\r\n <el-card shadow=\"never\" class=\"j-import-upload-card\">\r\n <div class=\"j-import-upload-card-title\">导入 EXCEL</div>\r\n <el-divider style=\"margin: 10px 0\" />\r\n <div class=\"j-import-upload-row\">\r\n <el-upload\r\n accept=\".xlsx,.xls\"\r\n :auto-upload=\"false\"\r\n :show-file-list=\"false\"\r\n :on-change=\"handleFileChange\"\r\n >\r\n <el-button size=\"small\">点击上传</el-button>\r\n </el-upload>\r\n <el-link\r\n v-if=\"dataColumns.length\"\r\n type=\"primary\"\r\n class=\"j-import-no-wrap\"\r\n @click=\"handleDownloadTemplate\"\r\n >\r\n 下载导入模板.xlsx\r\n </el-link>\r\n </div>\r\n </el-card>\r\n\r\n <!-- 统计信息 + 确认导入 -->\r\n <el-row class=\"j-import-stats-row\" :gutter=\"20\" align=\"middle\">\r\n <el-col :span=\"18\">\r\n <el-row class=\"j-import-stats-cols\">\r\n <el-col :span=\"4\" class=\"j-import-stat-item\">\r\n <div class=\"j-import-stat-num\">{{ stats.total }}</div>\r\n <div class=\"j-import-stat-label\">导入数量</div>\r\n </el-col>\r\n <el-col :span=\"4\" class=\"j-import-stat-item\">\r\n <div class=\"j-import-stat-num\">{{ stats.fail }}</div>\r\n <div class=\"j-import-stat-label\">失败数量</div>\r\n </el-col>\r\n <el-col :span=\"4\" class=\"j-import-stat-item\">\r\n <div class=\"j-import-stat-num\">{{ stats.success }}</div>\r\n <div class=\"j-import-stat-label\">成功数量</div>\r\n </el-col>\r\n </el-row>\r\n </el-col>\r\n <el-col :span=\"6\" class=\"j-import-confirm-col\">\r\n <el-button\r\n type=\"primary\"\r\n size=\"small\"\r\n :loading=\"submitting\"\r\n :disabled=\"!renderData.length\"\r\n @click=\"handleConfirm\"\r\n >\r\n 确认导入\r\n </el-button>\r\n </el-col>\r\n </el-row>\r\n\r\n <!-- 数据表格 -->\r\n <el-table :data=\"renderData\" border size=\"small\" max-height=\"360\" class=\"j-import-data-table\">\r\n <el-table-column\r\n v-for=\"col in dataColumns\"\r\n :key=\"col.prop\"\r\n :prop=\"col.prop\"\r\n :label=\"col.label\"\r\n :min-width=\"120\"\r\n show-overflow-tooltip\r\n />\r\n <el-table-column label=\"状态\" width=\"110\" align=\"center\" fixed=\"right\">\r\n <template #default=\"{ row }\">\r\n <span v-if=\"row._status === -1\" class=\"j-import-status-fail\">\r\n {{ row._error || '创建失败' }}\r\n </span>\r\n <span v-else>{{ statusMap[row._status] }}</span>\r\n </template>\r\n </el-table-column>\r\n <el-table-column label=\"操作\" width=\"80\" align=\"center\" fixed=\"right\">\r\n <template #default=\"{ $index, row }\">\r\n <el-button\r\n v-if=\"row._status === 0\"\r\n size=\"small\"\r\n @click=\"handleDel($index)\"\r\n >\r\n 删除\r\n </el-button>\r\n </template>\r\n </el-table-column>\r\n </el-table>\r\n\r\n <template #footer>\r\n <el-button @click=\"handleClose\">关闭</el-button>\r\n </template>\r\n </el-dialog>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed } from 'vue'\r\nimport { ElMessage, ElDialog, ElCard, ElDivider, ElUpload, ElButton, ElLink, ElRow, ElCol, ElTable, ElTableColumn } from 'element-plus'\r\nimport type { UploadFile } from 'element-plus'\r\nimport * as XLSX from 'xlsx'\r\nimport type { JImportExcelProps } from './types'\r\n\r\ndefineOptions({ name: 'JImportExcel' })\r\n\r\nconst props = withDefaults(defineProps<JImportExcelProps>(), {\r\n excludeFields: () => ['id', 'ctime', 'mtime'],\r\n title: 'Excel 批量导入',\r\n})\r\n\r\nconst emit = defineEmits<{\r\n success: []\r\n}>()\r\n\r\nconst visible = defineModel<boolean>({ default: false })\r\nconst submitting = ref(false)\r\nconst fieldMap = ref<Record<string, string>>({})\r\nconst renderData = ref<Record<string, any>[]>([])\r\nconst stats = ref({ total: 0, success: 0, fail: 0 })\r\n\r\nconst statusMap: Record<number, string> = {\r\n 0: '待创建',\r\n 1: '创建成功',\r\n 2: '创建中',\r\n [-1]: '创建失败',\r\n}\r\n\r\n/** 过滤后的表头列 */\r\nconst dataColumns = computed(() => {\r\n return Object.entries(fieldMap.value)\r\n .filter(([key]) => !props.excludeFields.includes(key))\r\n .map(([key, label]) => ({ id: key, label, prop: key }))\r\n})\r\n\r\n/** 弹窗打开时获取字段列表 */\r\nconst handleOpen = async () => {\r\n try {\r\n const res = await props.getFieldListApi()\r\n fieldMap.value = res.data.tableFieldsInfo ?? {}\r\n } catch {\r\n ElMessage.error('获取字段列表失败')\r\n }\r\n}\r\n\r\n/** 文件上传解析 */\r\nconst handleFileChange = (uploadFile: UploadFile) => {\r\n const raw = uploadFile.raw\r\n if (!raw) return\r\n\r\n const validTypes = [\r\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\r\n 'application/vnd.ms-excel',\r\n ]\r\n if (!validTypes.includes(raw.type) && !raw.name.match(/\\.xlsx?$/i)) {\r\n ElMessage.warning('请上传 .xlsx 或 .xls 格式文件')\r\n return\r\n }\r\n\r\n const reader = new FileReader()\r\n reader.onload = (e) => {\r\n try {\r\n const workbook = XLSX.read(e.target!.result, { type: 'binary' })\r\n const wsName = workbook.SheetNames[0] as string\r\n const ws = workbook.Sheets[wsName]!\r\n const rows = XLSX.utils.sheet_to_json(ws, {\r\n header: 1,\r\n defval: '',\r\n }) as any[][]\r\n\r\n const dataRows = rows.slice(1).filter((row) => row.some((cell) => cell !== ''))\r\n\r\n if (!dataRows.length) {\r\n ElMessage.warning('文件内容为空')\r\n return\r\n }\r\n\r\n // 按后端字段顺序一一映射,空单元格由 defval 补 '',避免后续列顶上来\r\n const list: Record<string, any>[] = dataRows.map((row) => {\r\n const item: Record<string, any> = { _status: 0, _error: '' }\r\n dataColumns.value.forEach((col, index) => {\r\n item[col.prop] = row[index] !== undefined ? row[index] : ''\r\n })\r\n return item\r\n })\r\n\r\n renderData.value = list\r\n stats.value = { total: list.length, success: 0, fail: 0 }\r\n } catch {\r\n ElMessage.error('解析文件失败,请检查文件格式')\r\n }\r\n }\r\n reader.readAsBinaryString(raw)\r\n}\r\n\r\n/** 删除行 */\r\nconst handleDel = (idx: number) => {\r\n renderData.value.splice(idx, 1)\r\n stats.value.total = renderData.value.length\r\n}\r\n\r\n/** 确认导入 */\r\nconst handleConfirm = async () => {\r\n const data = renderData.value\r\n .filter((row) => row._status === 0)\r\n .map(({ _status, _error, ...rest }) => rest)\r\n\r\n if (!data.length) {\r\n ElMessage.warning('没有可导入的数据')\r\n return\r\n }\r\n\r\n submitting.value = true\r\n try {\r\n const res = await props.importApi(data)\r\n if (res.code === 1) {\r\n // 全部成功\r\n renderData.value.forEach((row) => {\r\n if (row._status === 0) row._status = 1\r\n })\r\n stats.value.success = renderData.value.filter((r) => r._status === 1).length\r\n ElMessage.success('导入成功')\r\n emit('success')\r\n } else {\r\n ElMessage.error(res.msg || '导入失败')\r\n }\r\n } catch {\r\n ElMessage.error('导入失败,请重试')\r\n } finally {\r\n submitting.value = false\r\n }\r\n}\r\n\r\n/** 下载导入模板 */\r\nconst handleDownloadTemplate = () => {\r\n try {\r\n const wb = XLSX.utils.book_new()\r\n const headers = dataColumns.value.map((col) => col.label)\r\n const tr: Record<string, string> = {}\r\n headers.forEach((h) => (tr[h] = ''))\r\n const ws = XLSX.utils.json_to_sheet([tr])\r\n XLSX.utils.book_append_sheet(wb, ws, '模板')\r\n XLSX.writeFile(wb, '导入模板.xlsx')\r\n } catch {\r\n ElMessage.error('模板下载失败')\r\n }\r\n}\r\n\r\nconst handleClose = () => {\r\n if (!submitting.value) {\r\n visible.value = false\r\n renderData.value = []\r\n stats.value = { total: 0, success: 0, fail: 0 }\r\n }\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n.j-import-upload-card {\r\n margin-bottom: 16px;\r\n}\r\n.j-import-upload-card-title {\r\n font-size: 14px;\r\n color: #606266;\r\n}\r\n.j-import-upload-row {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n}\r\n.j-import-no-wrap {\r\n white-space: nowrap;\r\n}\r\n.j-import-stats-row {\r\n margin: 12px 0;\r\n}\r\n.j-import-stats-cols {\r\n text-align: center;\r\n line-height: 1.5;\r\n}\r\n.j-import-stat-item {\r\n padding: 0 8px;\r\n}\r\n.j-import-stat-num {\r\n font-size: 20px;\r\n}\r\n.j-import-stat-label {\r\n font-size: 12px;\r\n color: #909399;\r\n}\r\n.j-import-confirm-col {\r\n text-align: right;\r\n padding-top: 10px;\r\n}\r\n.j-import-data-table {\r\n margin-top: 10px;\r\n}\r\n.j-import-status-fail {\r\n color: #f56c6c;\r\n font-size: 12px;\r\n}\r\n</style>\r\n","<template>\r\n <!-- 有子菜单:渲染 el-sub-menu -->\r\n <el-sub-menu\r\n v-if=\"menuItem.children && menuItem.children.length > 0\"\r\n :index=\"menuItem.path\"\r\n :class=\"[`j-sidebar__depth-${depth}`]\"\r\n >\r\n <template #title>\r\n <JIconRender v-if=\"menuItem.icon && depth === 0\" :icon=\"menuItem.icon\" />\r\n <span class=\"j-sidebar__menu-item-title\">{{ menuItem.title || menuItem.name }}</span>\r\n </template>\r\n <!-- 递归渲染子菜单 -->\r\n <JSideMenuItem\r\n v-for=\"child in menuItem.children\"\r\n :key=\"child.path\"\r\n :menu-item=\"child\"\r\n :is-collapse=\"isCollapse\"\r\n :depth=\"depth + 1\"\r\n @menu-click=\"(item) => emit('menu-click', item)\"\r\n />\r\n </el-sub-menu>\r\n\r\n <!-- 无子菜单:渲染 el-menu-item -->\r\n <el-menu-item\r\n v-else\r\n :index=\"menuItem.path\"\r\n :class=\"[`j-sidebar__depth-${depth}`]\"\r\n @click=\"handleClick\"\r\n >\r\n <JIconRender v-if=\"menuItem.icon && depth === 0\" :icon=\"menuItem.icon\" />\r\n <template #title>\r\n <span>{{ menuItem.title || menuItem.name }}</span>\r\n </template>\r\n </el-menu-item>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport type { SidebarMenuItem } from './types'\r\nimport { ElSubMenu, ElMenuItem } from 'element-plus'\r\nimport { JIconRender } from '../JIconRender'\r\n\r\ndefineOptions({\r\n name: 'JSideMenuItem'\r\n})\r\n\r\ninterface Props {\r\n menuItem: SidebarMenuItem\r\n isCollapse?: boolean\r\n depth?: number\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), { depth: 0 })\r\n\r\nconst emit = defineEmits<{\r\n 'menu-click': [item: SidebarMenuItem]\r\n}>()\r\n\r\nconst handleClick = () => {\r\n emit('menu-click', props.menuItem)\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n.j-sidebar__menu-item-title {\r\n padding: 0 10px;\r\n}\r\n\r\n/* 二级菜单:灰色标题,作为分类标签 */\r\n.j-sidebar__depth-1 > :deep(.el-sub-menu__title) {\r\n color: #909399;\r\n font-size: 13px;\r\n}\r\n\r\n/* 二级叶子菜单(无子项)也用灰色 */\r\n:deep(.j-sidebar__depth-1.el-menu-item) {\r\n color: #909399;\r\n font-size: 13px;\r\n}\r\n\r\n/* 三级菜单:文字稍大 */\r\n:deep(.j-sidebar__depth-2.el-menu-item) {\r\n font-size: 15px;\r\n}\r\n</style>\r\n","<template>\r\n <div\r\n :class=\"['j-sidebar', innerCollapsed ? 'j-sidebar--collapsed' : 'j-sidebar--expanded']\"\r\n :style=\"{ width: innerCollapsed ? `${collapsedWidth}px` : `${expandedWidth}px` }\"\r\n >\r\n <!-- Logo 区域 -->\r\n <div class=\"j-sidebar__logo\">\r\n <slot name=\"logo\" :collapsed=\"innerCollapsed\">\r\n <h2 class=\"j-sidebar__title\">\r\n {{ innerCollapsed ? (collapsedTitle || title?.charAt(0) || '') : title }}\r\n </h2>\r\n </slot>\r\n </div>\r\n\r\n <!-- 菜单区域 -->\r\n <div class=\"j-sidebar__menu-wrapper\">\r\n <el-menu\r\n :default-active=\"activeMenu\"\r\n class=\"j-sidebar__menu\"\r\n :router=\"router\"\r\n :collapse=\"innerCollapsed\"\r\n :collapse-transition=\"false\"\r\n >\r\n <JSideMenuItem\r\n v-for=\"route in menus\"\r\n :key=\"route.path\"\r\n :menu-item=\"route\"\r\n :is-collapse=\"innerCollapsed\"\r\n @menu-click=\"(item) => emit('menu-click', item)\"\r\n />\r\n </el-menu>\r\n </div>\r\n\r\n <!-- 底部折叠按钮 -->\r\n <div class=\"j-sidebar__footer\">\r\n <slot name=\"footer\" :collapsed=\"innerCollapsed\" :toggle=\"toggleCollapse\">\r\n <button\r\n class=\"j-sidebar__collapse-btn\"\r\n @click=\"toggleCollapse\"\r\n >\r\n <JIconRender :icon=\"innerCollapsed ? 'mdi:chevron-right' : 'mdi:chevron-left'\" />\r\n </button>\r\n </slot>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, watch } from 'vue'\r\nimport { ElMenu } from 'element-plus'\r\nimport type { SidebarMenuItem } from './types'\r\nimport JSideMenuItem from './JSideMenuItem.vue'\r\nimport { JIconRender } from '../JIconRender'\r\n\r\ndefineOptions({\r\n name: 'JSidebar'\r\n})\r\n\r\ninterface Props {\r\n menus: SidebarMenuItem[]\r\n activeMenu?: string\r\n title?: string\r\n collapsedTitle?: string\r\n collapsed?: boolean\r\n collapsedWidth?: number\r\n expandedWidth?: number\r\n router?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n activeMenu: '',\r\n title: '',\r\n collapsedTitle: '',\r\n collapsed: false,\r\n collapsedWidth: 80,\r\n expandedWidth: 200,\r\n router: true,\r\n})\r\n\r\nconst emit = defineEmits<{\r\n 'update:collapsed': [value: boolean]\r\n 'menu-click': [item: SidebarMenuItem]\r\n}>()\r\n\r\nconst innerCollapsed = ref(props.collapsed)\r\n\r\nwatch(() => props.collapsed, (val) => {\r\n innerCollapsed.value = val\r\n})\r\n\r\nconst toggleCollapse = () => {\r\n innerCollapsed.value = !innerCollapsed.value\r\n emit('update:collapsed', innerCollapsed.value)\r\n}\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.j-sidebar {\r\n position: relative;\r\n background-color: $color-white;\r\n box-shadow: 2px 0 6px rgba(0, 21, 41, 0.08);\r\n overflow-x: hidden;\r\n transition: width 0.3s ease-in-out;\r\n flex-shrink: 0;\r\n display: flex;\r\n flex-direction: column;\r\n height: 100%;\r\n}\r\n\r\n.j-sidebar__logo {\r\n padding: 0 $spacing-md;\r\n display: flex;\r\n align-items: center;\r\n height: 50px;\r\n flex-shrink: 0;\r\n}\r\n\r\n\r\n.j-sidebar__title {\r\n margin: 0;\r\n font-size: $font-size-lg;\r\n font-weight: bold;\r\n color: $color-primary;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n}\r\n\r\n.j-sidebar__menu-wrapper {\r\n flex: 1;\r\n overflow-y: auto;\r\n overflow-x: hidden;\r\n}\r\n\r\n.j-sidebar__menu {\r\n border: none;\r\n width: 100%;\r\n}\r\n\r\n.j-sidebar__footer {\r\n flex-shrink: 0;\r\n padding: $spacing-sm;\r\n display: flex;\r\n}\r\n\r\n// 折叠状态:覆盖 el-menu 样式,图标+文字上下排列\r\n.j-sidebar--collapsed {\r\n :deep(.el-menu--collapse) {\r\n width: 100%;\r\n\r\n .el-menu-item,\r\n .el-sub-menu__title {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n height: auto;\r\n line-height: normal;\r\n padding: $spacing-sm 0 !important;\r\n\r\n .el-icon,\r\n .iconify {\r\n margin: 0;\r\n }\r\n\r\n span {\r\n display: block !important;\r\n visibility: visible !important;\r\n overflow: visible !important;\r\n width: auto !important;\r\n height: auto !important;\r\n font-size: $font-size-xs;\r\n margin-top: $spacing-xs;\r\n }\r\n }\r\n\r\n // 隐藏子菜单展开箭头\r\n .el-sub-menu__icon-arrow {\r\n display: none;\r\n }\r\n }\r\n}\r\n\r\n.j-sidebar__collapse-btn {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: $spacing-sm;\r\n border: none;\r\n border-radius: $border-radius-base;\r\n background-color: transparent;\r\n color: $color-text-secondary;\r\n cursor: pointer;\r\n transition: $transition-fast;\r\n\r\n &:hover {\r\n background-color: $color-bg-base;\r\n color: $color-primary;\r\n }\r\n\r\n}\r\n</style>\r\n","<template>\n <div class=\"j-admin-layout\" :style=\"layoutStyle\">\n <JSidebar\n v-if=\"sideMenus.length > 0\"\n v-model:collapsed=\"innerCollapsed\"\n :menus=\"sideMenus\"\n :active-menu=\"activeMenu\"\n :title=\"title\"\n :collapsed-title=\"collapsedTitle\"\n :collapsed-width=\"sidebarCollapsedWidth\"\n :expanded-width=\"sidebarExpandedWidth\"\n @menu-click=\"handleSideMenuClick\"\n >\n <template v-if=\"$slots.sidebarFooter\" #footer=\"{ collapsed: sidebarCollapsed, toggle }\">\n <slot name=\"sidebarFooter\" :collapsed=\"sidebarCollapsed\" :toggle=\"toggle\" />\n </template>\n </JSidebar>\n\n <div class=\"j-admin-layout__right-panel\">\n <div class=\"j-admin-layout__header\">\n <div class=\"j-admin-layout__header-left\">\n <div v-if=\"sideMenus.length === 0\" class=\"j-admin-layout__logo\">\n <slot name=\"logo\">\n <h2>{{ logoTitle || title }}</h2>\n </slot>\n </div>\n\n <el-menu\n mode=\"horizontal\"\n :default-active=\"activeTopMenu\"\n class=\"j-admin-layout__top-menu\"\n @select=\"handleTopMenuSelect\"\n >\n <el-menu-item\n v-for=\"menu in topMenus\"\n :key=\"menu.path\"\n :index=\"menu.path\"\n >\n <JIconRender v-if=\"menu.icon\" :icon=\"menu.icon\" class=\"j-admin-layout__top-menu-icon\" />\n <span>{{ menu.title || menu.name }}</span>\n </el-menu-item>\n </el-menu>\n </div>\n\n <div class=\"j-admin-layout__header-right\">\n <slot name=\"headerRight\" :username=\"username\">\n <el-dropdown v-if=\"showProfile || showLogout\">\n <span class=\"j-admin-layout__user\">\n {{ username }}\n <el-icon>\n <ArrowDown />\n </el-icon>\n </span>\n <template #dropdown>\n <el-dropdown-menu>\n <el-dropdown-item v-if=\"showProfile\" @click=\"emit('profile')\">\n {{ profileText }}\n </el-dropdown-item>\n <el-dropdown-item v-if=\"showLogout\" @click=\"emit('logout')\">\n {{ logoutText }}\n </el-dropdown-item>\n </el-dropdown-menu>\n </template>\n </el-dropdown>\n </slot>\n </div>\n </div>\n\n <div class=\"j-admin-layout__content-container\">\n <slot name=\"tabs\" />\n <div\n :class=\"[\n 'j-admin-layout__content',\n { 'j-admin-layout__content--scrollbar-hidden': hideContentScrollbar }\n ]\"\n >\n <slot />\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { ElMenu, ElMenuItem, ElDropdown, ElDropdownMenu, ElDropdownItem, ElIcon } from 'element-plus'\nimport { ArrowDown } from '@element-plus/icons-vue'\nimport { JSidebar, type SidebarMenuItem } from '../JSidebar'\nimport { JIconRender } from '../JIconRender'\nimport type { AdminLayoutMenuItem } from './types'\n\ndefineOptions({\n name: 'JAdminLayout'\n})\n\ninterface Props {\n topMenus: AdminLayoutMenuItem[]\n sideMenus: AdminLayoutMenuItem[]\n activeTopMenu?: string\n activeMenu?: string\n title?: string\n logoTitle?: string\n collapsedTitle?: string\n collapsed?: boolean\n username?: string\n profileText?: string\n logoutText?: string\n sidebarCollapsedWidth?: number\n sidebarExpandedWidth?: number\n headerHeight?: string\n contentPadding?: string\n contentBackground?: string\n headerBackground?: string\n showProfile?: boolean\n showLogout?: boolean\n hideContentScrollbar?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n activeTopMenu: '',\n activeMenu: '',\n title: '',\n logoTitle: '',\n collapsedTitle: '',\n collapsed: false,\n username: '',\n profileText: '个人资料',\n logoutText: '退出登录',\n sidebarCollapsedWidth: 80,\n sidebarExpandedWidth: 200,\n headerHeight: '50px',\n contentPadding: '10px',\n contentBackground: '#f0f2f5',\n headerBackground: '#ffffff',\n showProfile: true,\n showLogout: true,\n hideContentScrollbar: false,\n})\n\nconst emit = defineEmits<{\n 'update:collapsed': [value: boolean]\n 'top-menu-select': [path: string]\n 'side-menu-click': [item: SidebarMenuItem]\n profile: []\n logout: []\n}>()\n\nconst innerCollapsed = computed({\n get: () => props.collapsed,\n set: value => emit('update:collapsed', value),\n})\n\nconst layoutStyle = computed(() => ({\n '--j-admin-layout-header-height': props.headerHeight,\n '--j-admin-layout-content-padding': props.contentPadding,\n '--j-admin-layout-content-bg': props.contentBackground,\n '--j-admin-layout-header-bg': props.headerBackground,\n}))\n\nconst handleTopMenuSelect = (path: string) => {\n emit('top-menu-select', path)\n}\n\nconst handleSideMenuClick = (item: SidebarMenuItem) => {\n emit('side-menu-click', item)\n}\n</script>\n\n<style scoped lang=\"scss\">\n.j-admin-layout {\n width: 100vw;\n height: 100vh;\n display: flex;\n flex-direction: row;\n overflow: hidden;\n}\n\n.j-admin-layout__right-panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background-color: var(--j-admin-layout-content-bg);\n}\n\n.j-admin-layout__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n background-color: var(--j-admin-layout-header-bg);\n box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);\n height: var(--j-admin-layout-header-height);\n flex-shrink: 0;\n z-index: 100;\n}\n\n.j-admin-layout__header-left {\n display: flex;\n align-items: center;\n flex: 1;\n height: 100%;\n min-width: 0;\n}\n\n.j-admin-layout__logo {\n padding: 0 $spacing-md;\n display: flex;\n align-items: center;\n height: var(--j-admin-layout-header-height);\n flex-shrink: 0;\n}\n\n.j-admin-layout__logo h2 {\n margin: 0;\n font-size: $font-size-lg;\n font-weight: bold;\n color: $color-primary;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.j-admin-layout__top-menu {\n flex: 1;\n height: var(--j-admin-layout-header-height);\n border-bottom: none;\n min-width: 0;\n}\n\n.j-admin-layout__top-menu-icon {\n margin-right: $spacing-xs;\n}\n\n.j-admin-layout__header-right {\n display: flex;\n align-items: center;\n gap: $spacing-md;\n padding-right: $spacing-md;\n flex-shrink: 0;\n}\n\n.j-admin-layout__user {\n cursor: pointer;\n display: flex;\n align-items: center;\n color: $color-text-regular;\n}\n\n.j-admin-layout__user:hover {\n color: $color-primary;\n}\n\n.j-admin-layout__content-container {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n background-color: var(--j-admin-layout-content-bg);\n}\n\n.j-admin-layout__content {\n padding: var(--j-admin-layout-content-padding);\n flex: 1;\n overflow: auto;\n}\n\n.j-admin-layout__content--scrollbar-hidden {\n scrollbar-width: none;\n -ms-overflow-style: none;\n\n &::-webkit-scrollbar {\n display: none;\n }\n}\n</style>\n","/**\r\n * 递归转换值(处理嵌套对象和数组)\r\n */\r\nfunction deepTransformValue(value: any, transformer: (obj: Record<string, any>) => Record<string, any>): any {\r\n if (Array.isArray(value)) {\r\n return value.map((item) => deepTransformValue(item, transformer))\r\n }\r\n if (value !== null && typeof value === 'object' && !(value instanceof Date)) {\r\n return transformer(value)\r\n }\r\n return value\r\n}\r\n\r\n/**\r\n * 将对象的 key 从小驼峰转为下划线格式(支持深度嵌套)\r\n * @param obj 需要转换的对象\r\n * @param excludeKeys 不需要转换的 key 数组(可选)\r\n */\r\nexport function toSnakeCase<T extends Record<string, any>>(\r\n obj: T,\r\n excludeKeys: string[] = []\r\n): Record<string, any> {\r\n return Object.fromEntries(\r\n Object.entries(obj).map(([key, value]) => {\r\n const newValue = deepTransformValue(value, (v) => toSnakeCase(v, excludeKeys))\r\n if (excludeKeys.includes(key)) {\r\n return [key, newValue]\r\n }\r\n const snakeKey = key.replace(/([A-Z])/g, '_$1').toLowerCase()\r\n return [snakeKey, newValue]\r\n })\r\n )\r\n}\r\n\r\n/**\r\n * 将对象的 key 从下划线格式转为小驼峰(支持深度嵌套)\r\n * @param obj 需要转换的对象\r\n * @param excludeKeys 不需要转换的 key 数组(可选)\r\n */\r\nexport function toCamelCase<T extends Record<string, any>>(\r\n obj: T,\r\n excludeKeys: string[] = []\r\n): Record<string, any> {\r\n return Object.fromEntries(\r\n Object.entries(obj).map(([key, value]) => {\r\n const newValue = deepTransformValue(value, (v) => toCamelCase(v, excludeKeys))\r\n if (excludeKeys.includes(key)) {\r\n return [key, newValue]\r\n }\r\n const camelKey = key.replace(/_([a-z])/g, (_, char) => char.toUpperCase())\r\n return [camelKey, newValue]\r\n })\r\n )\r\n}\r\n\r\n/**\r\n * 从对象中提取指定的 key\r\n * @param obj 源对象\r\n * @param keys 要提取的 key 数组\r\n */\r\nexport function pick<T extends Record<string, any>, K extends keyof T>(\r\n obj: T,\r\n keys: K[]\r\n): Pick<T, K> {\r\n const result = {} as Pick<T, K>\r\n for (const key of keys) {\r\n if (key in obj) {\r\n result[key] = obj[key]\r\n }\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * 从对象中排除指定的 key\r\n * @param obj 源对象\r\n * @param keys 要排除的 key 数组\r\n */\r\nexport function omit<T extends Record<string, any>, K extends keyof T>(\r\n obj: T,\r\n keys: K[]\r\n): Omit<T, K> {\r\n const result = { ...obj }\r\n for (const key of keys) {\r\n delete result[key]\r\n }\r\n return result as Omit<T, K>\r\n}\r\n\r\n/**\r\n * 深拷贝对象\r\n * @param obj 需要拷贝的对象\r\n */\r\nexport function deepClone<T>(obj: T): T {\r\n if (obj === null || typeof obj !== 'object') return obj\r\n if (obj instanceof Date) return new Date(obj.getTime()) as unknown as T\r\n if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags) as unknown as T\r\n if (Array.isArray(obj)) return obj.map((item) => deepClone(item)) as unknown as T\r\n const cloned = {} as Record<string, any>\r\n for (const key of Object.keys(obj)) {\r\n cloned[key] = deepClone((obj as Record<string, any>)[key])\r\n }\r\n return cloned as T\r\n}\r\n\r\n/**\r\n * 过滤对象中的空值(null、undefined、空字符串)\r\n * @param obj 需要过滤的对象\r\n * @param deep 是否递归过滤嵌套对象,默认 false\r\n */\r\nexport function filterEmpty<T extends Record<string, any>>(\r\n obj: T,\r\n deep = false\r\n): Partial<T> {\r\n const result = {} as Record<string, any>\r\n for (const [key, value] of Object.entries(obj)) {\r\n if (value === null || value === undefined || value === '') continue\r\n if (deep && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date)) {\r\n const filtered = filterEmpty(value, true)\r\n if (Object.keys(filtered).length > 0) {\r\n result[key] = filtered\r\n }\r\n } else {\r\n result[key] = value\r\n }\r\n }\r\n return result as Partial<T>\r\n}\r\n\r\n/**\r\n * 将嵌套对象扁平化为单层对象\r\n * @param obj 需要扁平化的对象\r\n * @param prefix key 前缀,默认为空\r\n * @param separator 分隔符,默认为 '.'\r\n * @example flatten({ a: { b: 1, c: { d: 2 } } }) => { 'a.b': 1, 'a.c.d': 2 }\r\n */\r\nexport function flatten(\r\n obj: Record<string, any>,\r\n prefix = '',\r\n separator = '.'\r\n): Record<string, any> {\r\n const result: Record<string, any> = {}\r\n for (const [key, value] of Object.entries(obj)) {\r\n const newKey = prefix ? `${prefix}${separator}${key}` : key\r\n if (value !== null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date)) {\r\n Object.assign(result, flatten(value, newKey, separator))\r\n } else {\r\n result[newKey] = value\r\n }\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * 将扁平化的对象还原为嵌套对象\r\n * @param obj 扁平化的对象\r\n * @param separator 分隔符,默认为 '.'\r\n * @example unflatten({ 'a.b': 1, 'a.c.d': 2 }) => { a: { b: 1, c: { d: 2 } } }\r\n */\r\nexport function unflatten(\r\n obj: Record<string, any>,\r\n separator = '.'\r\n): Record<string, any> {\r\n const result: Record<string, any> = {}\r\n for (const [key, value] of Object.entries(obj)) {\r\n const parts = key.split(separator)\r\n let current = result\r\n for (let i = 0; i < parts.length - 1; i++) {\r\n const k = parts[i] as string\r\n if (!(k in current)) {\r\n current[k] = {}\r\n }\r\n current = current[k]\r\n }\r\n current[parts[parts.length - 1] as string] = value\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * 将 { key: label } 对象转换为 el-table-column 所需的表头数组\r\n * @param fieldMap 字段映射对象\r\n * @example toTableColumns({ id: '主键', name: '名称' }) => [{ id: 'id', label: '主键', prop: 'id' }, ...]\r\n */\r\nexport function toTableColumns(fieldMap: Record<string, string>) {\r\n return Object.entries(fieldMap).map(([key, label]) => ({\r\n id: key,\r\n label,\r\n prop: key,\r\n }))\r\n}\r\n","import type { RouteRecordRaw } from 'vue-router'\r\nimport type { BackendRoute } from './types'\r\n\r\ntype ViewModules = Record<string, () => Promise<unknown>>\r\n\r\ninterface RouteTreeNode extends BackendRoute {\r\n children?: RouteTreeNode[]\r\n}\r\n\r\nexport function getComponentImport(componentPath: string, viewModules: ViewModules): (() => Promise<unknown>) | null {\r\n if (!componentPath) return null\r\n\r\n let normalizedPath = componentPath.replace(/^@\\//, '')\r\n if (!normalizedPath.startsWith('views/')) normalizedPath = `views/${normalizedPath}`\r\n if (!normalizedPath.endsWith('.vue')) normalizedPath = `${normalizedPath}.vue`\r\n\r\n const fullPath = `/src/${normalizedPath}`\r\n\r\n return (viewModules[fullPath] ?? viewModules['/src/views/common/NotFound.vue'] ?? null) as (() => Promise<unknown>) | null\r\n}\r\n\r\nexport function buildRouteTree(routes: BackendRoute[]): RouteTreeNode[] {\r\n const routeMap = new Map<string, RouteTreeNode>()\r\n const rootRoutes: RouteTreeNode[] = []\r\n\r\n routes.forEach(route => routeMap.set(route.name, { ...route, children: [] }))\r\n\r\n routes.forEach(route => {\r\n const currentRoute = routeMap.get(route.name)!\r\n if (!route.parent_name) {\r\n rootRoutes.push(currentRoute)\r\n } else {\r\n const parentRoute = routeMap.get(route.parent_name)\r\n if (parentRoute) {\r\n parentRoute.children ??= []\r\n parentRoute.children.push(currentRoute)\r\n } else {\r\n rootRoutes.push(currentRoute)\r\n }\r\n }\r\n })\r\n return rootRoutes\r\n}\r\n\r\nexport function transformBackendRoutes(\r\n backendRoutes: RouteTreeNode[],\r\n viewModules: ViewModules,\r\n projectName?: string\r\n): RouteRecordRaw[] {\r\n return backendRoutes\r\n .filter(route => !projectName || !route.project || route.project === projectName)\r\n .map(route => {\r\n const routeConfig: Partial<RouteRecordRaw> = {\r\n path: route.path,\r\n name: route.name,\r\n meta: {\r\n requiresAuth: route.requiresAuth === 1,\r\n title: route.title,\r\n permissions: route.permissions\r\n ? route.permissions.split(',').map(p => p.trim()).filter(Boolean)\r\n : [],\r\n params: route.params\r\n ? route.params.split('&').map(p => p.trim()).filter(Boolean)\r\n : [],\r\n },\r\n }\r\n\r\n const component = getComponentImport(route.component, viewModules)\r\n if (component) routeConfig.component = component as RouteRecordRaw['component']\r\n\r\n if (route.redirect) routeConfig.redirect = route.redirect\r\n\r\n if (route.children?.length) {\r\n routeConfig.children = transformBackendRoutes(route.children, viewModules, projectName)\r\n }\r\n\r\n return routeConfig as RouteRecordRaw\r\n })\r\n}\r\n\r\nexport function findFirstAllowedRoute(\r\n backendRoutes: BackendRoute[],\r\n routePermissions: string[],\r\n layoutRouteName: string,\r\n projectName?: string\r\n): BackendRoute | undefined {\r\n const routeMap = new Map<string, BackendRoute>()\r\n backendRoutes.forEach(route => routeMap.set(route.name, route))\r\n\r\n const isDescendantOfLayout = (route: BackendRoute): boolean => {\r\n let parentName = route.parent_name\r\n const visited = new Set<string>()\r\n\r\n while (parentName) {\r\n if (parentName === layoutRouteName) return true\r\n if (visited.has(parentName)) return false\r\n\r\n visited.add(parentName)\r\n const parentRoute = routeMap.get(parentName)\r\n if (!parentRoute) return false\r\n parentName = parentRoute.parent_name\r\n }\r\n\r\n return false\r\n }\r\n\r\n return backendRoutes\r\n .filter(route =>\r\n route.name !== layoutRouteName &&\r\n route.is_show === 1 &&\r\n route.component &&\r\n routePermissions.includes(route.code) &&\r\n isDescendantOfLayout(route) &&\r\n (!projectName || !route.project || route.project === projectName)\r\n )\r\n .sort((a, b) => a.sorts - b.sorts)[0]\r\n}\r\n","import type { NavigationGuardNext, Router } from 'vue-router'\r\nimport NProgress from 'nprogress'\r\nimport 'nprogress/nprogress.css'\r\nimport { ElMessage } from 'element-plus'\r\nimport type { RouterGuardOptions } from './types'\r\nimport { buildRouteTree, transformBackendRoutes } from './helpers'\r\n\r\nNProgress.configure({ showSpinner: false })\r\n\r\nconst isDev = import.meta.env.DEV\r\nconst log = (...args: unknown[]) => { if (isDev) console.log('[Router]', ...args) }\r\nconst warn = (...args: unknown[]) => { if (isDev) console.warn('[Router]', ...args) }\r\nconst logError = (...args: unknown[]) => { console.error('[Router]', ...args) }\r\n\r\nexport function createRouterGuard(router: Router, options: RouterGuardOptions) {\r\n const {\r\n getRouteStore,\r\n getPermissionStore,\r\n getUserStore,\r\n isAuthenticated,\r\n viewModules,\r\n homeComponent,\r\n notFoundComponent,\r\n projectName,\r\n layoutRouteName = 'Layout',\r\n publicPaths = ['/login', '/register'],\r\n loginRouteName = 'login',\r\n forbiddenRouteName = 'Forbidden',\r\n homeRouteName = 'Home',\r\n homeRoutePath = 'home',\r\n homeTitle = '\\u9996\\u9875',\r\n noPermissionMessage = '\\u6682\\u65e0\\u6743\\u9650',\r\n } = options\r\n\r\n let hasAddedRoutes = false\r\n\r\n function addDynamicRoutes(backendRoutes: ReturnType<typeof getRouteStore>['backendRoutes']) {\r\n const treeRoutes = buildRouteTree(backendRoutes)\r\n const layoutRoute = treeRoutes.find(route => route.name === layoutRouteName)\r\n const childRoutes = layoutRoute?.children\r\n ? transformBackendRoutes(layoutRoute.children, viewModules, projectName)\r\n : []\r\n\r\n childRoutes.forEach(route => {\r\n if (route.name && router.hasRoute(route.name)) return\r\n router.addRoute(layoutRouteName, route)\r\n log(`Add route: ${String(route.name)} -> ${route.path}`)\r\n })\r\n\r\n if (!router.hasRoute(homeRouteName)) {\r\n router.addRoute(layoutRouteName, {\r\n path: homeRoutePath,\r\n name: homeRouteName,\r\n component: homeComponent as never,\r\n meta: { title: homeTitle },\r\n })\r\n }\r\n\r\n if (!router.hasRoute('NotFound')) {\r\n router.addRoute({\r\n path: '/:pathMatch(.*)*',\r\n name: 'NotFound',\r\n component: notFoundComponent as never,\r\n })\r\n }\r\n\r\n log(`Dynamic routes added: ${childRoutes.length}`)\r\n }\r\n\r\n function redirectToHomeOrContinue(\r\n toName: ReturnType<Router['resolve']>['name'],\r\n next: NavigationGuardNext\r\n ) {\r\n if (toName === homeRouteName) {\r\n next()\r\n return\r\n }\r\n\r\n if (router.hasRoute(homeRouteName)) {\r\n next({ name: homeRouteName, replace: true })\r\n } else {\r\n next()\r\n }\r\n }\r\n\r\n router.beforeEach(async (to, _from, next) => {\r\n NProgress.start()\r\n\r\n if (isAuthenticated() && !hasAddedRoutes) {\r\n try {\r\n const routeStore = getRouteStore()\r\n const permissionStore = getPermissionStore()\r\n\r\n await routeStore.initRoutes()\r\n await permissionStore.loadUserPermissions()\r\n\r\n addDynamicRoutes(routeStore.backendRoutes)\r\n hasAddedRoutes = true\r\n\r\n if (to.path === '/' || to.path === '') {\r\n redirectToHomeOrContinue(to.name, next)\r\n return\r\n }\r\n\r\n if (to.name === layoutRouteName) {\r\n redirectToHomeOrContinue(to.name, next)\r\n return\r\n }\r\n\r\n const currentRoute = routeStore.backendRoutes.find(route => route.name === to.name)\r\n if (currentRoute && !permissionStore.routePermissions.includes(currentRoute.code)) {\r\n warn('No route permission:', to.path)\r\n next({ name: forbiddenRouteName, replace: true })\r\n return\r\n }\r\n\r\n next({\r\n path: to.path,\r\n query: to.query,\r\n hash: to.hash,\r\n replace: true,\r\n })\r\n return\r\n } catch (err) {\r\n logError('Failed to load route permissions:', err)\r\n hasAddedRoutes = false\r\n await getUserStore().logout()\r\n next({ name: loginRouteName, replace: true })\r\n return\r\n }\r\n }\r\n\r\n if (publicPaths.includes(to.path)) {\r\n if (isAuthenticated()) {\r\n next({ path: '/', replace: true })\r\n } else {\r\n next()\r\n }\r\n return\r\n }\r\n\r\n if (!isAuthenticated()) {\r\n next({ name: loginRouteName, replace: true })\r\n return\r\n }\r\n\r\n const permissionStore = getPermissionStore()\r\n const routeStore = getRouteStore()\r\n\r\n if (to.name === homeRouteName) {\r\n next()\r\n return\r\n }\r\n\r\n if (permissionStore.routePermissions.length === 0) {\r\n if (to.path !== '/') {\r\n ElMessage.warning(noPermissionMessage)\r\n next({ path: '/', replace: true })\r\n } else {\r\n redirectToHomeOrContinue(to.name, next)\r\n }\r\n return\r\n }\r\n\r\n if (to.path === '/') {\r\n redirectToHomeOrContinue(to.name, next)\r\n return\r\n }\r\n\r\n if (to.name === layoutRouteName) {\r\n redirectToHomeOrContinue(to.name, next)\r\n return\r\n }\r\n\r\n const currentRoute = routeStore.backendRoutes.find(route => route.name === to.name)\r\n if (currentRoute && !permissionStore.routePermissions.includes(currentRoute.code)) {\r\n warn('No route permission:', to.path)\r\n next({ name: forbiddenRouteName, replace: true })\r\n return\r\n }\r\n\r\n next()\r\n })\r\n\r\n router.afterEach(() => NProgress.done())\r\n\r\n return {\r\n resetRouterState: () => { hasAddedRoutes = false },\r\n }\r\n}\r\n","import type { App } from 'vue'\r\nimport { JButton } from './components/JButton'\r\nimport { JUploadImg } from './components/JUploadImg'\r\nimport { JIconRender } from './components/JIconRender'\r\nimport { JSearchHeader } from './components/JSearchHeader'\r\nimport { JImportExcel } from './components/JImportExcel'\r\nimport { JSidebar, JSideMenuItem } from './components/JSidebar'\r\nimport { JAdminLayout } from './components/JAdminLayout'\r\n\r\n// 组件列表,新增组件后在此处注册\r\nconst components = [JButton, JUploadImg, JIconRender, JSearchHeader, JImportExcel, JSidebar, JSideMenuItem, JAdminLayout]\r\n\r\n// 全量安装插件(app.use(JgyComponents))\r\nconst install = (app: App) => {\r\n components.forEach((component) => {\r\n app.component(component.name ?? component.__name ?? '', component)\r\n })\r\n}\r\n\r\n// 默认导出插件对象\r\nexport default { install }\r\n\r\n// 按需导出各组件\r\nexport { JButton, JUploadImg, JIconRender, JSearchHeader, JImportExcel, JSidebar, JSideMenuItem, JAdminLayout }\r\n\r\n// 导出工具方法\r\nexport { toSnakeCase, toCamelCase, pick, omit, deepClone, filterEmpty, flatten, unflatten, toTableColumns } from './utils'\r\n\r\n// 导出路由工具\r\nexport { createRouterGuard, buildRouteTree, transformBackendRoutes, findFirstAllowedRoute, getComponentImport } from './router'\r\nexport type { BackendRoute, RouteStoreAdapter, PermissionStoreAdapter, UserStoreAdapter, RouterGuardOptions } from './router'\r\n\r\n// 导出类型\r\nexport type { ButtonType, ButtonSize } from './components/JButton'\r\nexport type { JUploadImgProps, JUploadImgEmits, ImageItem } from './components/JUploadImg'\r\nexport type { JIconRenderProps } from './components/JIconRender'\r\nexport type { JSearchHeaderProps } from './components/JSearchHeader'\r\nexport type { JImportExcelProps, ApiFn } from './components/JImportExcel'\r\nexport type { SidebarMenuItem, JSidebarProps, JSideMenuItemProps } from './components/JSidebar'\r\nexport type { AdminLayoutMenuItem, JAdminLayoutProps } from './components/JAdminLayout'\r\n"],"names":["props","__props","emit","__emit","handleClick","event","_createElementBlock","_openBlock","_hoisted_2","$slots","_hoisted_3","_renderSlot","_ctx","imageUrl","ref","showPreview","showTipText","handlePreviewSingle","handleRemoveSingle","ElMessage","imageList","uploading","initImageList","urls","url","index","watch","val","handleDragEnd","emitMultipleUpdate","handleRemove","handleFileChange","uploadFile","file","error","item","_hoisted_1","_createVNode","_unref","draggable","$event","_withCtx","element","_createElementVNode","ElImage","img","_withModifiers","ElIcon","Delete","_createBlock","ElUpload","Loading","Plus","_Fragment","_hoisted_5","_hoisted_6","ZoomIn","ElImageViewer","_hoisted_7","_hoisted_8","_toDisplayString","_mergeProps","$attrs","formItemsRef","expanded","isAnimated","itemCount","collapsedHeight","shouldCollapse","computed","measureItems","items","lastVisibleItem","wrapperRect","lastVisibleRect","toggleExpand","el","onEnd","observer","onMounted","onBeforeUnmount","ElCard","ElForm","_normalizeClass","ElButton","Search","_cache","Refresh","_createTextVNode","ArrowDown","visible","_useModel","submitting","fieldMap","renderData","stats","statusMap","dataColumns","key","label","handleOpen","res","raw","reader","e","workbook","XLSX","wsName","ws","dataRows","row","cell","list","col","handleDel","idx","handleConfirm","data","_status","_error","rest","r","handleDownloadTemplate","wb","headers","tr","h","handleClose","ElDialog","ElDivider","ElLink","ElRow","ElCol","_hoisted_4","ElTable","_renderList","ElTableColumn","$index","ElSubMenu","JIconRender","child","_component_JSideMenuItem","ElMenuItem","innerCollapsed","toggleCollapse","_normalizeStyle","_a","ElMenu","route","JSideMenuItem","value","layoutStyle","handleTopMenuSelect","path","handleSideMenuClick","JSidebar","sidebarCollapsed","toggle","menu","ElDropdown","ElDropdownMenu","ElDropdownItem","deepTransformValue","transformer","toSnakeCase","obj","excludeKeys","newValue","v","toCamelCase","_","char","pick","keys","result","omit","deepClone","cloned","filterEmpty","deep","filtered","flatten","prefix","separator","newKey","unflatten","parts","current","i","k","toTableColumns","getComponentImport","componentPath","viewModules","normalizedPath","fullPath","buildRouteTree","routes","routeMap","rootRoutes","currentRoute","parentRoute","transformBackendRoutes","backendRoutes","projectName","routeConfig","p","component","findFirstAllowedRoute","routePermissions","layoutRouteName","isDescendantOfLayout","parentName","visited","a","b","NProgress","log","args","warn","logError","createRouterGuard","router","options","getRouteStore","getPermissionStore","getUserStore","isAuthenticated","homeComponent","notFoundComponent","publicPaths","loginRouteName","forbiddenRouteName","homeRouteName","homeRoutePath","homeTitle","noPermissionMessage","hasAddedRoutes","addDynamicRoutes","layoutRoute","childRoutes","redirectToHomeOrContinue","toName","next","to","_from","routeStore","permissionStore","err","components","JButton","JUploadImg","JSearchHeader","JImportExcel","JAdminLayout","install","app"],"mappings":"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"}
|