采用script、template、style的顺序优化所有sfc文件

This commit is contained in:
hooray
2022-02-11 09:51:43 +08:00
parent 09efe7d54a
commit 41c6bbf3f0
68 changed files with 1316 additions and 1328 deletions
+11 -11
View File
@@ -1,14 +1,3 @@
<template>
<el-config-provider :size="settingsStore.app.elementSize">
<RouterView
:style="{
'--g-main-sidebar-actual-width': mainSidebarActualWidth,
'--g-sub-sidebar-actual-width': subSidebarActualWidth
}"
/>
</el-config-provider>
</template>
<script setup>
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
@@ -75,3 +64,14 @@ onMounted(() => {
window.onresize()
})
</script>
<template>
<el-config-provider :size="settingsStore.app.elementSize">
<RouterView
:style="{
'--g-main-sidebar-actual-width': mainSidebarActualWidth,
'--g-sub-sidebar-actual-width': subSidebarActualWidth
}"
/>
</el-config-provider>
</template>
+8 -8
View File
@@ -1,11 +1,4 @@
<template>
<div>
<slot v-if="check()" />
<slot v-else name="no-auth" />
</div>
</template>
<script setup>
<script setup name="Auth">
import { auth } from '@/util'
const props = defineProps({
@@ -19,3 +12,10 @@ function check() {
return auth(props.value)
}
</script>
<template>
<div>
<slot v-if="check()" />
<slot v-else name="no-auth" />
</div>
</template>
+8 -8
View File
@@ -1,11 +1,4 @@
<template>
<div>
<slot v-if="check()" />
<slot v-else name="no-auth" />
</div>
</template>
<script setup>
<script setup name="AuthAll">
import { authAll } from '@/util'
const props = defineProps({
@@ -19,3 +12,10 @@ function check() {
return authAll(props.value)
}
</script>
<template>
<div>
<slot v-if="check()" />
<slot v-else name="no-auth" />
</div>
</template>
+11 -11
View File
@@ -1,14 +1,4 @@
<template>
<div class="batch-action-bar">
<el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" :disabled="!data.length">当页全选</el-checkbox>
<div v-if="selectionData.length" class="tips">已选 {{ selectionData.length }} 项</div>
<el-form :disabled="!selectionData.length">
<slot />
</el-form>
</div>
</template>
<script setup>
<script setup name="BatchActionBar">
const props = defineProps({
data: {
type: Array,
@@ -44,6 +34,16 @@ const isIndeterminate = computed(() => {
})
</script>
<template>
<div class="batch-action-bar">
<el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" :disabled="!data.length">当页全选</el-checkbox>
<div v-if="selectionData.length" class="tips">已选 {{ selectionData.length }} 项</div>
<el-form :disabled="!selectionData.length">
<slot />
</el-form>
</div>
</template>
<style lang="scss" scoped>
.batch-action-bar {
display: flex;
+7 -7
View File
@@ -1,10 +1,4 @@
<template>
<div>
<el-cascader v-model="myValue" :options="data.options" :props="data.props" :size="size" :disabled="disabled" clearable filterable />
</div>
</template>
<script setup>
<script setup name="CascaderArea">
import area from '@/util/area'
const props = defineProps({
@@ -84,6 +78,12 @@ const myValue = computed({
})
</script>
<template>
<div>
<el-cascader v-model="myValue" :options="data.options" :props="data.props" :size="size" :disabled="disabled" clearable filterable />
</div>
</template>
<style lang="scss" scoped>
:deep(.el-cascader) {
width: 100%;
+5 -5
View File
@@ -1,3 +1,8 @@
<script setup name="Copyright">
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
</script>
<template>
<footer class="copyright">
Copyright © {{ settingsStore.copyright.dates }}
@@ -7,11 +12,6 @@
</footer>
</template>
<script setup>
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
</script>
<style lang="scss" scoped>
footer {
margin: 40px 0 20px;
+7 -7
View File
@@ -1,10 +1,4 @@
<template>
<div class="editor">
<TinymceEditor v-model="myValue" :init="completeSetting" :disabled="disabled" />
</div>
</template>
<script setup>
<script setup name="Editor">
import tinymce from 'tinymce/tinymce'
import TinymceEditor from '@tinymce/tinymce-vue'
import 'tinymce/themes/silver/theme'
@@ -88,6 +82,12 @@ onMounted(() => {
})
</script>
<template>
<div class="editor">
<TinymceEditor v-model="myValue" :init="completeSetting" :disabled="disabled" />
</div>
</template>
<style lang="scss" scoped>
:deep(.tox-tinymce) {
border: 1px solid #dcdfe6;
+27 -27
View File
@@ -1,30 +1,4 @@
<template>
<el-upload
:action="action"
:data="data"
:name="name"
:before-upload="beforeUpload"
:on-exceed="onExceed"
:on-success="onSuccess"
:file-list="files"
:limit="max"
drag
>
<div class="slot">
<el-icon class="el-icon--upload"><el-icon-upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</div>
<template #tip>
<div v-if="!notip" class="el-upload__tip">
<div style="display: inline-block;">
<el-alert :title="`上传文件支持 ${ ext.join(' / ') } 格式,单个文件大小不超过 ${ size }MB,且文件数量不超过 ${ max } 个`" type="info" show-icon :closable="false" />
</div>
</div>
</template>
</el-upload>
</template>
<script setup>
<script setup name="FileUpload">
const { proxy } = getCurrentInstance()
const props = defineProps({
@@ -89,6 +63,32 @@ function onSuccess(res, file) {
}
</script>
<template>
<el-upload
:action="action"
:data="data"
:name="name"
:before-upload="beforeUpload"
:on-exceed="onExceed"
:on-success="onSuccess"
:file-list="files"
:limit="max"
drag
>
<div class="slot">
<el-icon class="el-icon--upload"><el-icon-upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</div>
<template #tip>
<div v-if="!notip" class="el-upload__tip">
<div style="display: inline-block;">
<el-alert :title="`上传文件支持 ${ ext.join(' / ') } 格式,单个文件大小不超过 ${ size }MB,且文件数量不超过 ${ max } 个`" type="info" show-icon :closable="false" />
</div>
</div>
</template>
</el-upload>
</template>
<style lang="scss" scoped>
:deep(.el-upload-dragger) {
width: auto;
+7 -7
View File
@@ -1,10 +1,4 @@
<template>
<div class="actionbar" :class="{'shadow': !data.isBottom}" data-fixed-calc-width>
<slot />
</div>
</template>
<script setup>
<script setup name="FixedActionBar">
const data = ref({
isBottom: true
})
@@ -34,6 +28,12 @@ function onScroll() {
}
</script>
<template>
<div class="actionbar" :class="{'shadow': !data.isBottom}" data-fixed-calc-width>
<slot />
</div>
</template>
<style lang="scss" scoped>
.actionbar {
z-index: 4;
+11 -11
View File
@@ -1,14 +1,4 @@
<template>
<el-image :src="src" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="[src]">
<template #error>
<div class="image-slot">
<svg-icon name="image-load-fail" />
</div>
</template>
</el-image>
</template>
<script setup>
<script setup name="ImagePreview">
const props = defineProps({
src: {
type: String,
@@ -33,6 +23,16 @@ const realHeight = computed(() => {
})
</script>
<template>
<el-image :src="src" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="[src]">
<template #error>
<div class="image-slot">
<svg-icon name="image-load-fail" />
</div>
</template>
</el-image>
</template>
<style lang="scss" scoped>
.el-image {
border-radius: 5px;
+48 -48
View File
@@ -1,51 +1,4 @@
<template>
<div class="upload-container">
<el-upload
:show-file-list="false"
:headers="headers"
:action="action"
:data="data"
:name="name"
:before-upload="beforeUpload"
:on-progress="onProgress"
:on-success="onSuccess"
drag
>
<el-image v-if="url === ''" :src="url === '' ? placeholder : url" :style="`width:${width}px;height:${height}px;`" fit="fill">
<template #error>
<div class="image-slot">
<svg-icon name="el-icon-plus" />
</div>
</template>
</el-image>
<div v-else class="image">
<el-image :src="url" :style="`width:${width}px;height:${height}px;`" fit="fill" />
<div class="mask">
<div class="actions">
<span title="预览" @click.stop="preview">
<el-icon><el-icon-zoom-in /></el-icon>
</span>
<span title="移除" @click.stop="remove">
<el-icon><el-icon-delete /></el-icon>
</span>
</div>
</div>
</div>
<div v-show="url === '' && uploadData.progress.percent" class="progress" :style="`width:${width}px;height:${height}px;`">
<el-image :src="uploadData.progress.preview" :style="`width:${width}px;height:${height}px;`" fit="fill" />
<el-progress type="circle" :width="Math.min(width, height) * 0.8" :percentage="uploadData.progress.percent" />
</div>
</el-upload>
<div v-if="!notip" class="el-upload__tip">
<div style="display: inline-block;">
<el-alert :title="`上传图片支持 ${ ext.join(' / ') } 格式,且图片大小不超过 ${ size }MB,建议图片尺寸为 ${width}*${height}`" type="info" show-icon :closable="false" />
</div>
</div>
<el-image-viewer v-if="uploadData.imageViewerVisible" :url-list="[url]" @close="previewClose" />
</div>
</template>
<script setup>
<script setup name="ImageUpload">
const { proxy } = getCurrentInstance()
const props = defineProps({
@@ -143,6 +96,53 @@ function onSuccess(res) {
}
</script>
<template>
<div class="upload-container">
<el-upload
:show-file-list="false"
:headers="headers"
:action="action"
:data="data"
:name="name"
:before-upload="beforeUpload"
:on-progress="onProgress"
:on-success="onSuccess"
drag
>
<el-image v-if="url === ''" :src="url === '' ? placeholder : url" :style="`width:${width}px;height:${height}px;`" fit="fill">
<template #error>
<div class="image-slot">
<svg-icon name="el-icon-plus" />
</div>
</template>
</el-image>
<div v-else class="image">
<el-image :src="url" :style="`width:${width}px;height:${height}px;`" fit="fill" />
<div class="mask">
<div class="actions">
<span title="预览" @click.stop="preview">
<el-icon><el-icon-zoom-in /></el-icon>
</span>
<span title="移除" @click.stop="remove">
<el-icon><el-icon-delete /></el-icon>
</span>
</div>
</div>
</div>
<div v-show="url === '' && uploadData.progress.percent" class="progress" :style="`width:${width}px;height:${height}px;`">
<el-image :src="uploadData.progress.preview" :style="`width:${width}px;height:${height}px;`" fit="fill" />
<el-progress type="circle" :width="Math.min(width, height) * 0.8" :percentage="uploadData.progress.percent" />
</div>
</el-upload>
<div v-if="!notip" class="el-upload__tip">
<div style="display: inline-block;">
<el-alert :title="`上传图片支持 ${ ext.join(' / ') } 格式,且图片大小不超过 ${ size }MB,建议图片尺寸为 ${width}*${height}`" type="info" show-icon :closable="false" />
</div>
</div>
<el-image-viewer v-if="uploadData.imageViewerVisible" :url-list="[url]" @close="previewClose" />
</div>
</template>
<style lang="scss" scoped>
.upload-container {
line-height: initial;
+52 -52
View File
@@ -1,55 +1,4 @@
<template>
<div class="upload-container">
<div v-for="(item, index) in url" :key="index" class="images">
<el-image v-if="index < max" :src="item" :style="`width:${width}px;height:${height}px;`" fit="cover" />
<div class="mask">
<div class="actions">
<span title="预览" @click="preview(index)">
<el-icon><el-icon-zoom-in /></el-icon>
</span>
<span title="移除" @click="remove(index)">
<el-icon><el-icon-delete /></el-icon>
</span>
<span v-show="url.length > 1" title="左移" :class="{'disabled': index == 0}" @click="move(index, 'left')">
<el-icon><el-icon-back /></el-icon>
</span>
<span v-show="url.length > 1" title="右移" :class="{'disabled': index == url.length - 1}" @click="move(index, 'right')">
<el-icon><el-icon-right /></el-icon>
</span>
</div>
</div>
</div>
<el-upload
v-show="url.length < max"
:show-file-list="false"
:headers="headers"
:action="action"
:data="data"
:name="name"
:before-upload="beforeUpload"
:on-progress="onProgress"
:on-success="onSuccess"
drag
class="images-upload"
>
<div class="image-slot" :style="`width:${width}px;height:${height}px;`">
<svg-icon name="el-icon-plus" />
</div>
<div v-show="uploadData.progress.percent" class="progress" :style="`width:${width}px;height:${height}px;`">
<el-image :src="uploadData.progress.preview" :style="`width:${width}px;height:${height}px;`" fit="fill" />
<el-progress type="circle" :width="Math.min(width, height) * 0.8" :percentage="uploadData.progress.percent" />
</div>
</el-upload>
<div v-if="!notip" class="el-upload__tip">
<div style="display: inline-block;">
<el-alert :title="`上传图片支持 ${ ext.join(' / ') } 格式,单张图片大小不超过 ${ size }MB,建议图片尺寸为 ${width}*${height},且图片数量不超过 ${ max } 张`" type="info" show-icon :closable="false" />
</div>
</div>
<el-image-viewer v-if="uploadData.imageViewerVisible" :url-list="url" :initial-index="uploadData.dialogImageIndex" @close="previewClose" />
</div>
</template>
<script setup>
<script setup name="ImagesUpload">
const { proxy } = getCurrentInstance()
const props = defineProps({
@@ -166,6 +115,57 @@ function onSuccess(res) {
}
</script>
<template>
<div class="upload-container">
<div v-for="(item, index) in url" :key="index" class="images">
<el-image v-if="index < max" :src="item" :style="`width:${width}px;height:${height}px;`" fit="cover" />
<div class="mask">
<div class="actions">
<span title="预览" @click="preview(index)">
<el-icon><el-icon-zoom-in /></el-icon>
</span>
<span title="移除" @click="remove(index)">
<el-icon><el-icon-delete /></el-icon>
</span>
<span v-show="url.length > 1" title="左移" :class="{'disabled': index == 0}" @click="move(index, 'left')">
<el-icon><el-icon-back /></el-icon>
</span>
<span v-show="url.length > 1" title="右移" :class="{'disabled': index == url.length - 1}" @click="move(index, 'right')">
<el-icon><el-icon-right /></el-icon>
</span>
</div>
</div>
</div>
<el-upload
v-show="url.length < max"
:show-file-list="false"
:headers="headers"
:action="action"
:data="data"
:name="name"
:before-upload="beforeUpload"
:on-progress="onProgress"
:on-success="onSuccess"
drag
class="images-upload"
>
<div class="image-slot" :style="`width:${width}px;height:${height}px;`">
<svg-icon name="el-icon-plus" />
</div>
<div v-show="uploadData.progress.percent" class="progress" :style="`width:${width}px;height:${height}px;`">
<el-image :src="uploadData.progress.preview" :style="`width:${width}px;height:${height}px;`" fit="fill" />
<el-progress type="circle" :width="Math.min(width, height) * 0.8" :percentage="uploadData.progress.percent" />
</div>
</el-upload>
<div v-if="!notip" class="el-upload__tip">
<div style="display: inline-block;">
<el-alert :title="`上传图片支持 ${ ext.join(' / ') } 格式,单张图片大小不超过 ${ size }MB,建议图片尺寸为 ${width}*${height},且图片数量不超过 ${ max } 张`" type="info" show-icon :closable="false" />
</div>
</div>
<el-image-viewer v-if="uploadData.imageViewerVisible" :url-list="url" :initial-index="uploadData.dialogImageIndex" @close="previewClose" />
</div>
</template>
<style lang="scss" scoped>
.upload-container {
line-height: initial;
+13 -13
View File
@@ -1,3 +1,16 @@
<script setup name="PageHeader">
defineProps({
title: {
type: String,
required: true
},
content: {
type: String,
default: ''
}
})
</script>
<template>
<div class="header">
<div class="main">
@@ -12,19 +25,6 @@
</div>
</template>
<script setup>
defineProps({
title: {
type: String,
required: true
},
content: {
type: String,
default: ''
}
})
</script>
<style lang="scss" scoped>
.header {
display: flex;
+18 -18
View File
@@ -1,21 +1,4 @@
<template>
<div
:class="{
'page-main': true,
'is-collaspe': collaspeData
}" :style="{
'height': collaspeData ? height : ''
}"
>
<div v-if="title" class="title-container">{{ title }}</div>
<slot />
<div v-if="collaspeData" class="collaspe" title="展开" @click="unCollaspe">
<el-icon><el-icon-arrow-down /></el-icon>
</div>
</div>
</template>
<script setup>
<script setup name="PageMain">
const props = defineProps({
title: {
type: String,
@@ -38,6 +21,23 @@ function unCollaspe() {
}
</script>
<template>
<div
:class="{
'page-main': true,
'is-collaspe': collaspeData
}" :style="{
'height': collaspeData ? height : ''
}"
>
<div v-if="title" class="title-container">{{ title }}</div>
<slot />
<div v-if="collaspeData" class="collaspe" title="展开" @click="unCollaspe">
<el-icon><el-icon-arrow-down /></el-icon>
</div>
</div>
</template>
<style lang="scss" scoped>
.page-main {
position: relative;
+18 -18
View File
@@ -1,3 +1,21 @@
<script setup name="Result">
defineProps({
type: {
type: String,
validator: val => ['success', 'warning', 'error'].includes(val),
required: true
},
title: {
type: String,
required: true
},
desc: {
type: String,
default: ''
}
})
</script>
<template>
<div class="result">
<div v-if="type === 'success'" class="icon icon-success">
@@ -20,24 +38,6 @@
</div>
</template>
<script setup>
defineProps({
type: {
type: String,
validator: val => ['success', 'warning', 'error'].includes(val),
required: true
},
title: {
type: String,
required: true
},
desc: {
type: String,
default: ''
}
})
</script>
<style lang="scss" scoped>
$success: #67c23a;
$warning: #e6a23c;
+10 -10
View File
@@ -1,13 +1,4 @@
<template>
<div class="search-container">
<slot />
<div v-if="showMore" class="more">
<el-button type="text" size="small" :icon="isUnfold ? 'el-icon-caret-top' : 'el-icon-caret-bottom'" @click="toggle">{{ isUnfold ? '收起' : '展开' }}</el-button>
</div>
</div>
</template>
<script setup>
<script setup name="SearchBar">
const props = defineProps({
showMore: {
type: Boolean,
@@ -33,6 +24,15 @@ function toggle() {
}
</script>
<template>
<div class="search-container">
<slot />
<div v-if="showMore" class="more">
<el-button type="text" size="small" :icon="isUnfold ? 'el-icon-caret-top' : 'el-icon-caret-bottom'" @click="toggle">{{ isUnfold ? '收起' : '展开' }}</el-button>
</div>
</div>
</template>
<style lang="scss" scoped>
.search-container {
position: relative;
+11 -11
View File
@@ -1,13 +1,4 @@
<template>
<el-icon v-if="name.indexOf('el-icon-') === 0 || name.indexOf('ElIcon') === 0" class="svg-icon" :style="transformStyle">
<Component :is="name" />
</el-icon>
<svg v-else class="svg-icon" :style="transformStyle" aria-hidden="true">
<use :xlink:href="`#icon-${name}`" />
</svg>
</template>
<script setup>
<script setup name="SvgIcon">
const props = defineProps({
name: {
type: String,
@@ -52,12 +43,21 @@ const transformStyle = computed(() => {
})
</script>
<template>
<el-icon v-if="name.indexOf('el-icon-') === 0 || name.indexOf('ElIcon') === 0" class="svg-icon" :style="transformStyle">
<Component :is="name" />
</el-icon>
<svg v-else class="svg-icon" :style="transformStyle" aria-hidden="true">
<use :xlink:href="`#icon-${name}`" />
</svg>
</template>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
fill: currentcolor;
overflow: hidden;
}
</style>
+6 -6
View File
@@ -1,9 +1,3 @@
<template>
<div class="adaption-container">
<slot />
</div>
</template>
<script setup name="TableHeightAdaption">
onMounted(() => {
nextTick(() => {
@@ -18,6 +12,12 @@ onMounted(() => {
})
</script>
<template>
<div class="adaption-container">
<slot />
</div>
</template>
<style lang="scss" scoped>
.adaption-container {
height: 100%;
+10 -10
View File
@@ -1,13 +1,4 @@
<template>
<div :class="`trend ${isUp ? 'up' : 'down'}`">
<span v-if="prefix" class="prefix">{{ prefix }}</span>
<span class="text">{{ value }}</span>
<span v-if="suffix" class="suffix">{{ suffix }}</span>
<svg-icon :name="`${isUp ? 'el-icon-caret-top' : 'el-icon-caret-bottom'}`" />
</div>
</template>
<script setup>
<script setup name="Trend">
const props = defineProps({
value: {
type: String,
@@ -41,6 +32,15 @@ const isUp = computed(() => {
})
</script>
<template>
<div :class="`trend ${isUp ? 'up' : 'down'}`">
<span v-if="prefix" class="prefix">{{ prefix }}</span>
<span class="text">{{ value }}</span>
<span v-if="suffix" class="suffix">{{ suffix }}</span>
<svg-icon :name="`${isUp ? 'el-icon-caret-top' : 'el-icon-caret-bottom'}`" />
</div>
</template>
<style lang="scss" scoped>
.trend {
display: inline-block;
+42 -42
View File
@@ -1,3 +1,45 @@
<script setup name="AppSetting">
const { proxy } = getCurrentInstance()
const route = useRoute()
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useMenuStore } from '@/store/modules/menu'
const menuStore = useMenuStore()
const isShow = ref(false)
import globalSettings from '@/settings'
const settings = ref(globalSettings)
watch(() => settings, () => {
settingsStore.updateThemeSetting(settings.value)
menuStore.setActived(0)
settings.value.menu.menuMode !== 'single' && menuStore.setActived(route.fullPath)
}, {
deep: true
})
onMounted(() => {
proxy.$eventBus.on('global-theme-toggle', () => {
isShow.value = !isShow.value
})
})
import { useClipboard } from '@vueuse/core'
const { copy, copied, isSupported } = useClipboard()
watch(copied, val => {
if (val) {
proxy.$message.success('复制成功,请粘贴到 src/settings.custom.json 文件中!')
}
})
function handleCopy() {
copy(JSON.stringify(settings.value, null, 4))
}
</script>
<template>
<div>
<el-drawer v-model="isShow" title="应用配置" direction="rtl" :size="350" custom-class="flex-container">
@@ -163,48 +205,6 @@
</div>
</template>
<script setup>
const { proxy } = getCurrentInstance()
const route = useRoute()
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useMenuStore } from '@/store/modules/menu'
const menuStore = useMenuStore()
const isShow = ref(false)
import globalSettings from '@/settings'
const settings = ref(globalSettings)
watch(() => settings, () => {
settingsStore.updateThemeSetting(settings.value)
menuStore.setActived(0)
settings.value.menu.menuMode !== 'single' && menuStore.setActived(route.fullPath)
}, {
deep: true
})
onMounted(() => {
proxy.$eventBus.on('global-theme-toggle', () => {
isShow.value = !isShow.value
})
})
import { useClipboard } from '@vueuse/core'
const { copy, copied, isSupported } = useClipboard()
watch(copied, val => {
if (val) {
proxy.$message.success('复制成功,请粘贴到 src/settings.custom.json 文件中!')
}
})
function handleCopy() {
copy(JSON.stringify(settings.value, null, 4))
}
</script>
<style lang="scss" scoped>
:deep(.el-drawer__body) {
display: flex;
+26 -26
View File
@@ -1,29 +1,4 @@
<template>
<div class="buy-it" :class="{'actived': isActived}">
<div class="item" @click="open('https://wpa.qq.com/msgrd?v=3&uin=304327508&site=qq&menu=yes')">
<svg-icon name="fixed-right-qq" />
<span class="title">在线<br>咨询</span>
</div>
<div class="item chat" @click="open('https://qm.qq.com/cgi-bin/qm/qr?k=WoDBYN0S9r94f9oBZkxlGbiYxu3dEzgt&jump_from=webapi')">
<svg-icon name="fixed-right-chat" />
<span class="title">加入<br>QQ群</span>
</div>
<div class="item buy" @click="open(`https://hooray.${locationOrigin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/buy.html`)">
<svg-icon name="fixed-right-buy" />
<span class="title">购买<br>专业版</span>
</div>
<div class="item doc" @click="open(`https://hooray.${locationOrigin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/`)">
<svg-icon name="fixed-right-doc" />
<span class="title">开发<br>文档</span>
</div>
<div class="item code" @click="open(`https://${locationOrigin.includes('gitee') ? 'gitee' : 'github'}.com/hooray/fantastic-admin/`)">
<svg-icon name="fixed-right-code" />
<span class="title">下载<br>基础版</span>
</div>
</div>
</template>
<script setup>
<script setup name="BuyIt">
const { proxy } = getCurrentInstance()
const locationOrigin = ref(location.href)
@@ -64,6 +39,31 @@ function open(url) {
}
</script>
<template>
<div class="buy-it" :class="{'actived': isActived}">
<div class="item" @click="open('https://wpa.qq.com/msgrd?v=3&uin=304327508&site=qq&menu=yes')">
<svg-icon name="fixed-right-qq" />
<span class="title">在线<br>咨询</span>
</div>
<div class="item chat" @click="open('https://qm.qq.com/cgi-bin/qm/qr?k=WoDBYN0S9r94f9oBZkxlGbiYxu3dEzgt&jump_from=webapi')">
<svg-icon name="fixed-right-chat" />
<span class="title">加入<br>QQ群</span>
</div>
<div class="item buy" @click="open(`https://hooray.${locationOrigin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/buy.html`)">
<svg-icon name="fixed-right-buy" />
<span class="title">购买<br>专业版</span>
</div>
<div class="item doc" @click="open(`https://hooray.${locationOrigin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/`)">
<svg-icon name="fixed-right-doc" />
<span class="title">开发<br>文档</span>
</div>
<div class="item code" @click="open(`https://${locationOrigin.includes('gitee') ? 'gitee' : 'github'}.com/hooray/fantastic-admin/`)">
<svg-icon name="fixed-right-code" />
<span class="title">下载<br>基础版</span>
</div>
</div>
</template>
<style lang="scss" scoped>
.buy-it {
position: fixed;
+12 -12
View File
@@ -1,3 +1,15 @@
<script setup name="Header">
import Logo from '../Logo/index.vue'
import Tools from '../Tools/index.vue'
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useMenuStore } from '@/store/modules/menu'
const menuStore = useMenuStore()
const switchMenu = inject('switchMenu')
</script>
<template>
<transition name="header">
<header v-if="settingsStore.mode === 'pc' && settingsStore.menu.menuMode === 'head'">
@@ -20,18 +32,6 @@
</transition>
</template>
<script setup>
import Logo from '../Logo/index.vue'
import Tools from '../Tools/index.vue'
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useMenuStore } from '@/store/modules/menu'
const menuStore = useMenuStore()
const switchMenu = inject('switchMenu')
</script>
<style lang="scss" scoped>
// 头部动画
.header-enter-active {
+8 -8
View File
@@ -1,11 +1,4 @@
<template>
<router-link :to="to" class="title" :class="{'is-link': settingsStore.dashboard.enable}" :title="title">
<img v-if="showLogo" :src="logo" class="logo">
<span v-if="showTitle">{{ title }}</span>
</router-link>
</template>
<script setup>
<script setup name="Logo">
import imgLogo from '@/assets/images/logo.png'
import { useSettingsStore } from '@/store/modules/settings'
@@ -34,6 +27,13 @@ const to = computed(() => {
})
</script>
<template>
<router-link :to="to" class="title" :class="{'is-link': settingsStore.dashboard.enable}" :title="title">
<img v-if="showLogo" :src="logo" class="logo">
<span v-if="showTitle">{{ title }}</span>
</router-link>
</template>
<style lang="scss" scoped>
.title {
position: fixed;
+11 -11
View File
@@ -1,3 +1,14 @@
<script setup name="MainSidebar">
import Logo from '../Logo/index.vue'
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useMenuStore } from '@/store/modules/menu'
const menuStore = useMenuStore()
const switchMenu = inject('switchMenu')
</script>
<template>
<transition name="main-sidebar">
<div v-if="settingsStore.menu.menuMode === 'side' || (settingsStore.mode === 'mobile' && settingsStore.menu.menuMode !== 'single')" class="main-sidebar-container">
@@ -20,17 +31,6 @@
</transition>
</template>
<script setup>
import Logo from '../Logo/index.vue'
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useMenuStore } from '@/store/modules/menu'
const menuStore = useMenuStore()
const switchMenu = inject('switchMenu')
</script>
<style lang="scss" scoped>
// 主侧边栏动画
.main-sidebar-enter-active {
+54 -54
View File
@@ -1,57 +1,4 @@
<template>
<teleport to="#app">
<div id="search" :class="{'searching': isShow}" @click="isShow && $eventBus.emit('global-search-toggle')">
<div class="container">
<div class="search-box" @click.stop>
<el-input ref="input" v-model="searchInput" prefix-icon="el-icon-search" placeholder="搜索页面,支持标题、URL模糊查询" clearable @keydown.esc="$eventBus.emit('global-search-toggle')" @keydown.up.prevent="keyUp" @keydown.down.prevent="keyDown" @keydown.enter.prevent="keyEnter" />
<div v-if="settingsStore.mode === 'pc'" class="tips">
<div class="tip">
<span>Alt</span>+<span>S</span>
唤醒搜索面板
</div>
<div class="tip">
<span><svg-icon name="search-up" /></span>
<span><svg-icon name="search-down" /></span>
切换搜索结果
</div>
<div class="tip">
<span><svg-icon name="search-enter" /></span>
访问页面
</div>
<div class="tip">
<span>ESC</span>
退出
</div>
</div>
</div>
<div ref="search" class="result" :class="{'mobile': settingsStore.mode === 'mobile'}">
<router-link v-for="(item, index) in resultList" :key="item.path" v-slot="{ href, navigate }" custom :to="isShow ? item.path : ''">
<a :ref="`search-item-${index}`" :href="isExternalLink(item.path) ? item.path : href" class="item" :class="{'actived': index === actived}" :target="isExternalLink(item.path) ? '_blank' : '_self'" @click="navigate" @mouseover="actived = index">
<div class="icon">
<svg-icon v-if="item.icon" :name="item.icon" />
</div>
<div class="info">
<div class="title">
{{ item.title }}
<svg-icon v-if="item.isExternalLink" name="external-link" />
</div>
<div class="breadcrumb">
<span v-for="(bc, bcIndex) in item.breadcrumb" :key="bcIndex">
{{ bc }}
<svg-icon name="el-icon-arrow-right" />
</span>
</div>
<div class="path">{{ item.path }}</div>
</div>
</a>
</router-link>
</div>
</div>
</div>
</teleport>
</template>
<script setup>
<script setup name="Search">
import { deepClone, isExternalLink } from '@/util'
const { proxy } = getCurrentInstance()
@@ -212,6 +159,59 @@ function scrollTo(offsetTop) {
}
</script>
<template>
<teleport to="#app">
<div id="search" :class="{'searching': isShow}" @click="isShow && $eventBus.emit('global-search-toggle')">
<div class="container">
<div class="search-box" @click.stop>
<el-input ref="input" v-model="searchInput" prefix-icon="el-icon-search" placeholder="搜索页面,支持标题、URL模糊查询" clearable @keydown.esc="$eventBus.emit('global-search-toggle')" @keydown.up.prevent="keyUp" @keydown.down.prevent="keyDown" @keydown.enter.prevent="keyEnter" />
<div v-if="settingsStore.mode === 'pc'" class="tips">
<div class="tip">
<span>Alt</span>+<span>S</span>
唤醒搜索面板
</div>
<div class="tip">
<span><svg-icon name="search-up" /></span>
<span><svg-icon name="search-down" /></span>
切换搜索结果
</div>
<div class="tip">
<span><svg-icon name="search-enter" /></span>
访问页面
</div>
<div class="tip">
<span>ESC</span>
退出
</div>
</div>
</div>
<div ref="search" class="result" :class="{'mobile': settingsStore.mode === 'mobile'}">
<router-link v-for="(item, index) in resultList" :key="item.path" v-slot="{ href, navigate }" custom :to="isShow ? item.path : ''">
<a :ref="`search-item-${index}`" :href="isExternalLink(item.path) ? item.path : href" class="item" :class="{'actived': index === actived}" :target="isExternalLink(item.path) ? '_blank' : '_self'" @click="navigate" @mouseover="actived = index">
<div class="icon">
<svg-icon v-if="item.icon" :name="item.icon" />
</div>
<div class="info">
<div class="title">
{{ item.title }}
<svg-icon v-if="item.isExternalLink" name="external-link" />
</div>
<div class="breadcrumb">
<span v-for="(bc, bcIndex) in item.breadcrumb" :key="bcIndex">
{{ bc }}
<svg-icon name="el-icon-arrow-right" />
</span>
</div>
<div class="path">{{ item.path }}</div>
</div>
</a>
</router-link>
</div>
</div>
</div>
</teleport>
</template>
<style lang="scss" scoped>
#search {
position: fixed;
+28 -28
View File
@@ -1,31 +1,4 @@
<template>
<div v-if="item.meta.sidebar !== false" class="sidebar-item">
<el-sub-menu v-if="item.path == undefined" :title="item.meta.title" :index="JSON.stringify(item)">
<template #title>
<svg-icon v-if="item.meta.icon" :name="item.meta.icon" />
<span class="title">{{ item.meta.title }}</span>
</template>
<SidebarItem v-for="route in item.children" :key="route.path" :item="route" />
</el-sub-menu>
<router-link v-else-if="!hasChildren" v-slot="{ href, navigate, isActive, isExactActive }" custom :to="resolveRoutePath(basePath, item.path)">
<a :href="isExternalLink(resolveRoutePath(basePath, item.path)) ? resolveRoutePath(basePath, item.path) : href" :class="[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']" :target="isExternalLink(resolveRoutePath(basePath, item.path)) ? '_blank' : '_self'" @click="navigate">
<el-menu-item :title="item.meta.title" :index="resolveRoutePath(basePath, item.path)">
<svg-icon v-if="item.meta.icon" :name="item.meta.icon" />
<span class="title">{{ item.meta.title }}</span>
</el-menu-item>
</a>
</router-link>
<el-sub-menu v-else :title="item.meta.title" :index="resolveRoutePath(basePath, item.path)">
<template #title>
<svg-icon v-if="item.meta.icon" :name="item.meta.icon" />
<span class="title">{{ item.meta.title }}</span>
</template>
<SidebarItem v-for="route in item.children" :key="route.path" :item="route" :base-path="resolveRoutePath(basePath, item.path)" />
</el-sub-menu>
</div>
</template>
<script setup>
<script setup name="SidebarItem">
import SidebarItem from './index.vue'
import { isExternalLink, resolveRoutePath } from '@/util'
@@ -53,6 +26,33 @@ const hasChildren = computed(() => {
})
</script>
<template>
<div v-if="item.meta.sidebar !== false" class="sidebar-item">
<el-sub-menu v-if="item.path == undefined" :title="item.meta.title" :index="JSON.stringify(item)">
<template #title>
<svg-icon v-if="item.meta.icon" :name="item.meta.icon" />
<span class="title">{{ item.meta.title }}</span>
</template>
<SidebarItem v-for="route in item.children" :key="route.path" :item="route" />
</el-sub-menu>
<router-link v-else-if="!hasChildren" v-slot="{ href, navigate, isActive, isExactActive }" custom :to="resolveRoutePath(basePath, item.path)">
<a :href="isExternalLink(resolveRoutePath(basePath, item.path)) ? resolveRoutePath(basePath, item.path) : href" :class="[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']" :target="isExternalLink(resolveRoutePath(basePath, item.path)) ? '_blank' : '_self'" @click="navigate">
<el-menu-item :title="item.meta.title" :index="resolveRoutePath(basePath, item.path)">
<svg-icon v-if="item.meta.icon" :name="item.meta.icon" />
<span class="title">{{ item.meta.title }}</span>
</el-menu-item>
</a>
</router-link>
<el-sub-menu v-else :title="item.meta.title" :index="resolveRoutePath(basePath, item.path)">
<template #title>
<svg-icon v-if="item.meta.icon" :name="item.meta.icon" />
<span class="title">{{ item.meta.title }}</span>
</template>
<SidebarItem v-for="route in item.children" :key="route.path" :item="route" :base-path="resolveRoutePath(basePath, item.path)" />
</el-sub-menu>
</div>
</template>
<style lang="scss" scoped>
:deep(.el-menu-item),
:deep(.el-menu-item span.title),
+16 -16
View File
@@ -1,3 +1,19 @@
<script setup name="SubSidebar">
import Logo from '../Logo/index.vue'
import SidebarItem from '../SidebarItem/index.vue'
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useMenuStore } from '@/store/modules/menu'
const menuStore = useMenuStore()
const sidebarScrollTop = ref(0)
function onSidebarScroll(e) {
sidebarScrollTop.value = e.target.scrollTop
}
</script>
<template>
<div v-if="['side', 'head', 'single'].includes(settingsStore.menu.menuMode) || settingsStore.mode === 'mobile'" class="sub-sidebar-container" :class="{'is-collapse': settingsStore.mode === 'pc' && settingsStore.menu.subMenuCollapse}" @scroll="onSidebarScroll">
<Logo
@@ -22,22 +38,6 @@
</div>
</template>
<script setup>
import Logo from '../Logo/index.vue'
import SidebarItem from '../SidebarItem/index.vue'
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useMenuStore } from '@/store/modules/menu'
const menuStore = useMenuStore()
const sidebarScrollTop = ref(0)
function onSidebarScroll(e) {
sidebarScrollTop.value = e.target.scrollTop
}
</script>
<style lang="scss" scoped>
// 次侧边栏动画
.sub-sidebar-enter-active {
+38 -38
View File
@@ -1,3 +1,41 @@
<script setup name="Tools">
const reload = inject('reload')
const router = useRouter()
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useUserStore } from '@/store/modules/user'
const userStore = useUserStore()
import { useFullscreen } from '@vueuse/core'
const { isFullscreen, toggle } = useFullscreen()
function userCommand(command) {
switch (command) {
case 'dashboard':
router.push({
name: 'dashboard'
})
break
case 'setting':
router.push({
name: 'personalSetting'
})
break
case 'logout':
userStore.logout().then(() => {
router.push({
name: 'login'
})
})
break
}
}
function pro() {
window.open(`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/vue3/pro`, 'top')
}
</script>
<template>
<div class="tools">
<div class="buttons">
@@ -37,44 +75,6 @@
</div>
</template>
<script setup>
const reload = inject('reload')
const router = useRouter()
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useUserStore } from '@/store/modules/user'
const userStore = useUserStore()
import { useFullscreen } from '@vueuse/core'
const { isFullscreen, toggle } = useFullscreen()
function userCommand(command) {
switch (command) {
case 'dashboard':
router.push({
name: 'dashboard'
})
break
case 'setting':
router.push({
name: 'personalSetting'
})
break
case 'logout':
userStore.logout().then(() => {
router.push({
name: 'login'
})
})
break
}
}
function pro() {
window.open(`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/vue3/pro`, 'top')
}
</script>
<style lang="scss" scoped>
.tools {
display: flex;
+29 -29
View File
@@ -1,32 +1,4 @@
<template>
<div
class="topbar-container" :class="{
'fixed': settingsStore.topbar.fixed,
'shadow': scrollTop
}" data-fixed-calc-width
>
<div class="left-box">
<div v-if="enableSidebarCollapse" class="sidebar-collapse" :class="{'is-collapse': settingsStore.menu.subMenuCollapse}" @click="settingsStore.toggleSidebarCollapse()">
<svg-icon name="toolbar-collapse" />
</div>
<el-breadcrumb v-if="settingsStore.topbar.enableBreadcrumb && settingsStore.mode === 'pc'" separator-class="el-icon-arrow-right">
<transition-group name="breadcrumb">
<template v-for="(item, index) in breadcrumbList">
<el-breadcrumb-item v-if="index < breadcrumbList.length - 1" :key="item.path" :to="pathCompile(item.path)">
{{ item.title }}
</el-breadcrumb-item>
<el-breadcrumb-item v-else :key="item.path">
{{ item.title }}
</el-breadcrumb-item>
</template>
</transition-group>
</el-breadcrumb>
</div>
<Tools />
</div>
</template>
<script setup>
<script setup name="Topbar">
import { compile } from 'path-to-regexp'
import { deepClone } from '@/util'
import Tools from '../Tools/index.vue'
@@ -74,6 +46,34 @@ function pathCompile(path) {
}
</script>
<template>
<div
class="topbar-container" :class="{
'fixed': settingsStore.topbar.fixed,
'shadow': scrollTop
}" data-fixed-calc-width
>
<div class="left-box">
<div v-if="enableSidebarCollapse" class="sidebar-collapse" :class="{'is-collapse': settingsStore.menu.subMenuCollapse}" @click="settingsStore.toggleSidebarCollapse()">
<svg-icon name="toolbar-collapse" />
</div>
<el-breadcrumb v-if="settingsStore.topbar.enableBreadcrumb && settingsStore.mode === 'pc'" separator-class="el-icon-arrow-right">
<transition-group name="breadcrumb">
<template v-for="(item, index) in breadcrumbList">
<el-breadcrumb-item v-if="index < breadcrumbList.length - 1" :key="item.path" :to="pathCompile(item.path)">
{{ item.title }}
</el-breadcrumb-item>
<el-breadcrumb-item v-else :key="item.path">
{{ item.title }}
</el-breadcrumb-item>
</template>
</transition-group>
</el-breadcrumb>
</div>
<Tools />
</div>
</template>
<style lang="scss" scoped>
.topbar-container {
position: absolute;
+34 -34
View File
@@ -1,37 +1,4 @@
<template>
<div class="layout">
<div id="app-main">
<Header />
<div class="wrapper">
<div class="sidebar-container" :class="{'show': settingsStore.mode === 'mobile' && !settingsStore.menu.subMenuCollapse}">
<MainSidebar />
<SubSidebar />
</div>
<div class="sidebar-mask" :class="{'show': settingsStore.mode === 'mobile' && !settingsStore.menu.subMenuCollapse}" @click="settingsStore.toggleSidebarCollapse()" />
<div class="main-container" :style="{'padding-bottom': $route.meta.paddingBottom}">
<Topbar v-if="!(settingsStore.menu.menuMode === 'head' && !settingsStore.topbar.enableSidebarCollapse && !settingsStore.topbar.enableBreadcrumb)" />
<div class="main">
<router-view v-slot="{ Component, route }">
<transition name="main" mode="out-in" appear>
<!-- BUG https://github.com/vuejs/vue-next/issues/4984 -->
<keep-alive :include="[...keepAliveStore.list]">
<component :is="Component" :key="route.fullPath" />
</keep-alive>
</transition>
</router-view>
</div>
<Copyright v-if="showCopyright" />
</div>
</div>
<el-backtop :right="20" :bottom="20" title="回到顶部" />
</div>
<Search />
<AppSetting />
<BuyIt />
</div>
</template>
<script setup>
<script setup name="Layout">
import Header from './components/Header/index.vue'
import MainSidebar from './components/MainSidebar/index.vue'
import SubSidebar from './components/SubSidebar/index.vue'
@@ -101,6 +68,39 @@ function switchMenu(index) {
}
</script>
<template>
<div class="layout">
<div id="app-main">
<Header />
<div class="wrapper">
<div class="sidebar-container" :class="{'show': settingsStore.mode === 'mobile' && !settingsStore.menu.subMenuCollapse}">
<MainSidebar />
<SubSidebar />
</div>
<div class="sidebar-mask" :class="{'show': settingsStore.mode === 'mobile' && !settingsStore.menu.subMenuCollapse}" @click="settingsStore.toggleSidebarCollapse()" />
<div class="main-container" :style="{'padding-bottom': $route.meta.paddingBottom}">
<Topbar v-if="!(settingsStore.menu.menuMode === 'head' && !settingsStore.topbar.enableSidebarCollapse && !settingsStore.topbar.enableBreadcrumb)" />
<div class="main">
<router-view v-slot="{ Component, route }">
<transition name="main" mode="out-in" appear>
<!-- BUG https://github.com/vuejs/vue-next/issues/4984 -->
<keep-alive :include="[...keepAliveStore.list]">
<component :is="Component" :key="route.fullPath" />
</keep-alive>
</transition>
</router-view>
</div>
<Copyright v-if="showCopyright" />
</div>
</div>
<el-backtop :right="20" :bottom="20" title="回到顶部" />
</div>
<Search />
<AppSetting />
<BuyIt />
</div>
</template>
<style lang="scss" scoped>
[data-mode="mobile"] {
.sidebar-container {
+11 -11
View File
@@ -1,14 +1,3 @@
<template>
<div class="notfound">
<svg-icon name="404" />
<div class="content">
<h1>404</h1>
<div class="desc">抱歉,你访问的页面不存在</div>
<el-button type="primary" @click="goBack">{{ data.countdown }} 秒后,返回首页</el-button>
</div>
</div>
</template>
<script setup>
import { onBeforeRouteLeave } from 'vue-router'
const router = useRouter()
@@ -37,6 +26,17 @@ function goBack() {
}
</script>
<template>
<div class="notfound">
<svg-icon name="404" />
<div class="content">
<h1>404</h1>
<div class="desc">抱歉,你访问的页面不存在</div>
<el-button type="primary" @click="goBack">{{ data.countdown }} 秒后,返回首页</el-button>
</div>
</div>
</template>
<style lang="scss" scoped>
.notfound {
display: flex;
+5 -5
View File
@@ -1,3 +1,8 @@
<script setup>
import Alert from './components/alert.vue'
import { Search, Edit, Check, Message, Star, Delete, Share, ArrowLeft } from '@element-plus/icons-vue'
</script>
<template>
<div>
<Alert />
@@ -97,11 +102,6 @@
</div>
</template>
<script setup>
import Alert from './components/alert.vue'
import { Search, Edit, Check, Message, Star, Delete, Share, ArrowLeft } from '@element-plus/icons-vue'
</script>
<style lang="scss" scoped>
.demo {
.el-row {
+25 -25
View File
@@ -1,3 +1,28 @@
<script>
import Alert from './components/alert.vue'
const cityOptions = ['上海', '北京', '广州', '深圳']
export default {
components: {
Alert
},
data() {
return {
checked: true,
checked1: false,
checked2: true,
checkList: ['选中且禁用', '复选框 A'],
checkedCities: ['上海', '北京'],
cities: cityOptions,
checkboxGroup1: ['上海'],
checked3: true,
checked4: false
}
}
}
</script>
<template>
<div>
<Alert />
@@ -34,28 +59,3 @@
</page-main>
</div>
</template>
<script>
import Alert from './components/alert.vue'
const cityOptions = ['上海', '北京', '广州', '深圳']
export default {
components: {
Alert
},
data() {
return {
checked: true,
checked1: false,
checked2: true,
checkList: ['选中且禁用', '复选框 A'],
checkedCities: ['上海', '北京'],
cities: cityOptions,
checkboxGroup1: ['上海'],
checked3: true,
checked4: false
}
}
}
</script>
@@ -1,32 +1,3 @@
<template>
<div>
<Alert />
<page-header title="日期选择器" />
<page-main title="选择日" class="demo">
<div>默认</div>
<el-date-picker v-model="value1" type="date" placeholder="选择日期" />
<div>带快捷选项</div>
<el-date-picker v-model="value2" align="right" type="date" placeholder="选择日期" :disabled-date="disabledDate" :shortcuts="shortcuts" />
</page-main>
<page-main title="其他日期单位" class="demo">
<div>周</div>
<el-date-picker v-model="value3" type="week" format="gggg 第 ww 周" placeholder="选择周" />
<div>月</div>
<el-date-picker v-model="value4" type="month" placeholder="选择月" />
<div>年</div>
<el-date-picker v-model="value5" type="year" placeholder="选择年" />
<div>多个日期</div>
<el-date-picker v-model="value6" type="dates" placeholder="选择一个或多个日期" />
</page-main>
<page-main title="选择日期范围" class="demo">
<el-date-picker v-model="value7" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</page-main>
<page-main title="选择月份范围" class="demo">
<el-date-picker v-model="value8" type="monthrange" range-separator="至" start-placeholder="开始月份" end-placeholder="结束月份" />
</page-main>
</div>
</template>
<script>
import Alert from './components/alert.vue'
@@ -73,3 +44,32 @@ export default {
}
}
</script>
<template>
<div>
<Alert />
<page-header title="日期选择器" />
<page-main title="选择日" class="demo">
<div>默认</div>
<el-date-picker v-model="value1" type="date" placeholder="选择日期" />
<div>带快捷选项</div>
<el-date-picker v-model="value2" align="right" type="date" placeholder="选择日期" :disabled-date="disabledDate" :shortcuts="shortcuts" />
</page-main>
<page-main title="其他日期单位" class="demo">
<div>周</div>
<el-date-picker v-model="value3" type="week" format="gggg 第 ww 周" placeholder="选择周" />
<div>月</div>
<el-date-picker v-model="value4" type="month" placeholder="选择月" />
<div>年</div>
<el-date-picker v-model="value5" type="year" placeholder="选择年" />
<div>多个日期</div>
<el-date-picker v-model="value6" type="dates" placeholder="选择一个或多个日期" />
</page-main>
<page-main title="选择日期范围" class="demo">
<el-date-picker v-model="value7" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</page-main>
<page-main title="选择月份范围" class="demo">
<el-date-picker v-model="value8" type="monthrange" range-separator="至" start-placeholder="开始月份" end-placeholder="结束月份" />
</page-main>
</div>
</template>
@@ -1,20 +1,3 @@
<template>
<div>
<Alert />
<page-header title="日期时间选择器" />
<page-main title="日期和时间点" class="demo">
<el-date-picker v-model="value1" type="datetime" placeholder="选择日期时间" />
</page-main>
<page-main title="日期和时间范围" class="demo">
<el-date-picker v-model="value2" type="datetimerange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</page-main>
<page-main title="默认的起始与结束时刻" class="demo">
<div>起始日期时刻为 12:00:00,结束日期时刻为 08:00:00</div>
<el-date-picker v-model="value3" type="datetimerange" align="right" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="[new Date(2000, 1, 1, 12, 0, 0), new Date(2000, 2, 1, 8, 0, 0)]" />
</page-main>
</div>
</template>
<script>
import Alert from './components/alert.vue'
@@ -31,3 +14,20 @@ export default {
}
}
</script>
<template>
<div>
<Alert />
<page-header title="日期时间选择器" />
<page-main title="日期和时间点" class="demo">
<el-date-picker v-model="value1" type="datetime" placeholder="选择日期时间" />
</page-main>
<page-main title="日期和时间范围" class="demo">
<el-date-picker v-model="value2" type="datetimerange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</page-main>
<page-main title="默认的起始与结束时刻" class="demo">
<div>起始日期时刻为 12:00:00,结束日期时刻为 08:00:00</div>
<el-date-picker v-model="value3" type="datetimerange" align="right" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="[new Date(2000, 1, 1, 12, 0, 0), new Date(2000, 2, 1, 8, 0, 0)]" />
</page-main>
</div>
</template>
+9 -9
View File
@@ -1,3 +1,12 @@
<script setup>
import Alert from './components/alert.vue'
import { Search } from '@element-plus/icons-vue'
import * as ElementIcons from '@element-plus/icons-vue'
import { hyphen } from 'naming-style'
const icon = Object.keys(ElementIcons)
</script>
<template>
<div>
<Alert />
@@ -20,15 +29,6 @@
</div>
</template>
<script setup>
import Alert from './components/alert.vue'
import { Search } from '@element-plus/icons-vue'
import * as ElementIcons from '@element-plus/icons-vue'
import { hyphen } from 'naming-style'
const icon = Object.keys(ElementIcons)
</script>
<style lang="scss" scoped>
.demo {
> .el-icon {
+20 -20
View File
@@ -1,3 +1,21 @@
<script>
import Alert from './components/alert.vue'
export default {
components: {
Alert
},
data() {
return {
input: '',
input1: '',
input2: '',
textarea: ''
}
}
}
</script>
<template>
<div>
<Alert />
@@ -17,12 +35,12 @@
<page-main title="带 icon 的输入框" class="demo">
<el-input v-model="input1" placeholder="请选择日期">
<template #suffix>
<el-icon><el-icon-calendar /></el-icon>
<el-icon class="el-input__icon"><el-icon-calendar /></el-icon>
</template>
</el-input>
<el-input v-model="input2" placeholder="请输入内容">
<template #prefix>
<el-icon><el-icon-search /></el-icon>
<el-icon class="el-input__icon"><el-icon-search /></el-icon>
</template>
</el-input>
</page-main>
@@ -31,21 +49,3 @@
</page-main>
</div>
</template>
<script>
import Alert from './components/alert.vue'
export default {
components: {
Alert
},
data() {
return {
input: '',
input1: '',
input2: '',
textarea: ''
}
}
}
</script>
@@ -1,3 +1,22 @@
<script>
import Alert from './components/alert.vue'
export default {
components: {
Alert
},
data() {
return {
num: 1,
num2: 1,
num3: 5,
num4: 1,
num5: 1
}
}
}
</script>
<template>
<div>
<Alert />
@@ -19,22 +38,3 @@
</page-main>
</div>
</template>
<script>
import Alert from './components/alert.vue'
export default {
components: {
Alert
},
data() {
return {
num: 1,
num2: 1,
num3: 5,
num4: 1,
num5: 1
}
}
}
</script>
+5 -5
View File
@@ -1,3 +1,8 @@
<script setup>
import Alert from './components/alert.vue'
import { Edit } from '@element-plus/icons-vue'
</script>
<template>
<div>
<Alert />
@@ -32,11 +37,6 @@
</div>
</template>
<script setup>
import Alert from './components/alert.vue'
import { Edit } from '@element-plus/icons-vue'
</script>
<style lang="scss" scoped>
.demo {
.el-link {
+19 -19
View File
@@ -1,3 +1,22 @@
<script>
import Alert from './components/alert.vue'
export default {
components: {
Alert
},
data() {
return {
radio: '1',
radio2: '选中且禁用',
radio3: 3,
radio4: '上海',
radio5: '1'
}
}
}
</script>
<template>
<div>
<Alert />
@@ -31,22 +50,3 @@
</page-main>
</div>
</template>
<script>
import Alert from './components/alert.vue'
export default {
components: {
Alert
},
data() {
return {
radio: '1',
radio2: '选中且禁用',
radio3: 3,
radio4: '上海',
radio5: '1'
}
}
}
</script>
+16 -16
View File
@@ -1,19 +1,3 @@
<template>
<div>
<Alert />
<page-header title="评分" />
<page-main title="基础用法" class="demo">
<el-rate v-model="value1" />
</page-main>
<page-main title="辅助文字" class="demo">
<el-rate v-model="value2" show-text :texts="['极差', '差', '一般', '好', '极好']" />
</page-main>
<page-main title="只读" class="demo">
<el-rate v-model="value3" disabled show-score text-color="#ff9900" score-template="{value}" />
</page-main>
</div>
</template>
<script>
import Alert from './components/alert.vue'
@@ -30,3 +14,19 @@ export default {
}
}
</script>
<template>
<div>
<Alert />
<page-header title="评分" />
<page-main title="基础用法" class="demo">
<el-rate v-model="value1" />
</page-main>
<page-main title="辅助文字" class="demo">
<el-rate v-model="value2" show-text :texts="['极差', '差', '一般', '好', '极好']" />
</page-main>
<page-main title="只读" class="demo">
<el-rate v-model="value3" disabled show-score text-color="#ff9900" score-template="{value}" />
</page-main>
</div>
</template>
+31 -31
View File
@@ -1,3 +1,34 @@
<script>
import Alert from './components/alert.vue'
export default {
components: {
Alert
},
data() {
return {
options1: [
{ value: '选项1', label: '黄金糕' },
{ value: '选项2', label: '双皮奶' },
{ value: '选项3', label: '蚵仔煎' },
{ value: '选项4', label: '龙须面' },
{ value: '选项5', label: '北京烤鸭' }
],
value1: '',
options2: [
{ value: '选项1', label: '黄金糕' },
{ value: '选项2', label: '双皮奶', disabled: true },
{ value: '选项3', label: '蚵仔煎' },
{ value: '选项4', label: '龙须面' },
{ value: '选项5', label: '北京烤鸭' }
],
value2: '',
value3: []
}
}
}
</script>
<template>
<div>
<Alert />
@@ -34,34 +65,3 @@
</page-main>
</div>
</template>
<script>
import Alert from './components/alert.vue'
export default {
components: {
Alert
},
data() {
return {
options1: [
{ value: '选项1', label: '黄金糕' },
{ value: '选项2', label: '双皮奶' },
{ value: '选项3', label: '蚵仔煎' },
{ value: '选项4', label: '龙须面' },
{ value: '选项5', label: '北京烤鸭' }
],
value1: '',
options2: [
{ value: '选项1', label: '黄金糕' },
{ value: '选项2', label: '双皮奶', disabled: true },
{ value: '选项3', label: '蚵仔煎' },
{ value: '选项4', label: '龙须面' },
{ value: '选项5', label: '北京烤鸭' }
],
value2: '',
value3: []
}
}
}
</script>
+28 -28
View File
@@ -1,3 +1,31 @@
<script>
import Alert from './components/alert.vue'
export default {
components: {
Alert
},
data() {
return {
value1: 0,
value2: 50,
value3: 36,
value4: 48,
value5: 42,
value6: 0,
value7: 0,
value8: [4, 8],
value9: 0
}
},
methods: {
formatTooltip(val) {
return val / 100
}
}
}
</script>
<template>
<div>
<Alert />
@@ -31,31 +59,3 @@
</page-main>
</div>
</template>
<script>
import Alert from './components/alert.vue'
export default {
components: {
Alert
},
data() {
return {
value1: 0,
value2: 50,
value3: 36,
value4: 48,
value5: 42,
value6: 0,
value7: 0,
value8: [4, 8],
value9: 0
}
},
methods: {
formatTooltip(val) {
return val / 100
}
}
}
</script>
+17 -17
View File
@@ -1,20 +1,3 @@
<template>
<div>
<Alert />
<page-header title="开关" />
<page-main title="基础用法" class="demo">
<el-switch v-model="value" active-color="#13ce66" inactive-color="#ff4949" />
</page-main>
<page-main title="文字描述" class="demo">
<el-switch v-model="value1" active-text="按月付费" inactive-text="按年付费" />
</page-main>
<page-main title="禁用状态" class="demo">
<el-switch v-model="value2" disabled style="margin-right: 10px;" />
<el-switch v-model="value3" disabled />
</page-main>
</div>
</template>
<script>
import Alert from './components/alert.vue'
@@ -32,3 +15,20 @@ export default {
}
}
</script>
<template>
<div>
<Alert />
<page-header title="开关" />
<page-main title="基础用法" class="demo">
<el-switch v-model="value" active-color="#13ce66" inactive-color="#ff4949" />
</page-main>
<page-main title="文字描述" class="demo">
<el-switch v-model="value1" active-text="按月付费" inactive-text="按年付费" />
</page-main>
<page-main title="禁用状态" class="demo">
<el-switch v-model="value2" disabled style="margin-right: 10px;" />
<el-switch v-model="value3" disabled />
</page-main>
</div>
</template>
@@ -1,20 +1,3 @@
<template>
<div>
<Alert />
<page-header title="时间选择器" />
<page-main title="固定时间点" class="demo">
<el-time-select v-model="value" start="08:30" step="00:15" end="18:30" placeholder="选择时间" />
</page-main>
<page-main title="任意时间点" class="demo">
<el-time-picker v-model="value1" :disabled-hours="disabledHours" :disabled-minutes="disabledMinutes" :disabled-seconds="disabledSeconds" placeholder="任意时间点" />
</page-main>
<page-main title="固定时间范围" class="demo">
<el-time-select v-model="startTime" placeholder="起始时间" start="08:30" step="00:15" end="18:30" style="margin-right: 10px;" />
<el-time-select v-model="endTime" placeholder="结束时间" start="08:30" step="00:15" end="18:30" :min-time="startTime" />
</page-main>
</div>
</template>
<script>
import Alert from './components/alert.vue'
@@ -58,3 +41,20 @@ export default {
}
}
</script>
<template>
<div>
<Alert />
<page-header title="时间选择器" />
<page-main title="固定时间点" class="demo">
<el-time-select v-model="value" start="08:30" step="00:15" end="18:30" placeholder="选择时间" />
</page-main>
<page-main title="任意时间点" class="demo">
<el-time-picker v-model="value1" :disabled-hours="disabledHours" :disabled-minutes="disabledMinutes" :disabled-seconds="disabledSeconds" placeholder="任意时间点" />
</page-main>
<page-main title="固定时间范围" class="demo">
<el-time-select v-model="startTime" placeholder="起始时间" start="08:30" step="00:15" end="18:30" style="margin-right: 10px;" />
<el-time-select v-model="endTime" placeholder="结束时间" start="08:30" step="00:15" end="18:30" :min-time="startTime" />
</page-main>
</div>
</template>
@@ -1,3 +1,22 @@
<script>
export default {
data() {
return {
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
}
}
}
</script>
<template>
<div>
<page-header title="固定底部操作栏" content="避免因页面过长导致操作按钮需要滚动到页面底部才能操作,例如表单页">
@@ -134,22 +153,3 @@
</fixed-action-bar>
</div>
</template>
<script>
export default {
data() {
return {
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
}
}
}
</script>
@@ -1,22 +1,3 @@
<template>
<div>
<page-header title="省市区联动" content="CascaderArea" />
<page-main>
<cascader-area v-model="area" />
</page-main>
<page-main title="表单验证">
<el-form ref="ruleForm" :model="ruleForm" :rules="rules">
<el-form-item label="地区" prop="area">
<cascader-area v-model="ruleForm.area" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提交</el-button>
</el-form-item>
</el-form>
</page-main>
</div>
</template>
<script>
export default {
name: 'ComponentExampleArea',
@@ -48,6 +29,21 @@ export default {
}
</script>
<style lang="scss" scoped>
// scss
</style>
<template>
<div>
<page-header title="省市区联动" content="CascaderArea" />
<page-main>
<cascader-area v-model="area" />
</page-main>
<page-main title="表单验证">
<el-form ref="ruleForm" :model="ruleForm" :rules="rules">
<el-form-item label="地区" prop="area">
<cascader-area v-model="ruleForm.area" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提交</el-button>
</el-form-item>
</el-form>
</page-main>
</div>
</template>
@@ -1,36 +1,3 @@
<template>
<div>
<page-header title="批量操作栏">
<template #content>
<p>BatchActionBar</p>
<p style="margin-bottom: 0;">该组件需要和 ElTable 搭配使用</p>
</template>
</page-header>
<page-main>
<batch-action-bar :data="dataList" :selection-data="selectionDataList" @check-all="$refs.table.toggleAllSelection()" @check-null="$refs.table.clearSelection()">
<el-button size="default">单个批量操作按钮</el-button>
<el-button-group>
<el-button size="default">批量操作按钮组1</el-button>
<el-button size="default">批量操作按钮组2</el-button>
</el-button-group>
</batch-action-bar>
<el-table ref="table" :data="dataList" border stripe highlight-current-row @selection-change="selectionDataList = $event">
<el-table-column type="selection" width="40" />
<el-table-column prop="date" label="日期" width="180" />
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="address" label="地址" />
</el-table>
<batch-action-bar :data="dataList" :selection-data="selectionDataList" @check-all="$refs.table.toggleAllSelection()" @check-null="$refs.table.clearSelection()">
<el-button size="default">单个批量操作按钮</el-button>
<el-button-group>
<el-button size="default">批量操作按钮组1</el-button>
<el-button size="default">批量操作按钮组2</el-button>
</el-button-group>
</batch-action-bar>
</page-main>
</div>
</template>
<script>
export default {
name: 'ComponentExampleBatchactionbar',
@@ -68,6 +35,35 @@ export default {
}
</script>
<style lang="scss" scoped>
// scss
</style>
<template>
<div>
<page-header title="批量操作栏">
<template #content>
<p>BatchActionBar</p>
<p style="margin-bottom: 0;">该组件需要和 ElTable 搭配使用</p>
</template>
</page-header>
<page-main>
<batch-action-bar :data="dataList" :selection-data="selectionDataList" @check-all="$refs.table.toggleAllSelection()" @check-null="$refs.table.clearSelection()">
<el-button size="default">单个批量操作按钮</el-button>
<el-button-group>
<el-button size="default">批量操作按钮组1</el-button>
<el-button size="default">批量操作按钮组2</el-button>
</el-button-group>
</batch-action-bar>
<el-table ref="table" :data="dataList" border stripe highlight-current-row @selection-change="selectionDataList = $event">
<el-table-column type="selection" width="40" />
<el-table-column prop="date" label="日期" width="180" />
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="address" label="地址" />
</el-table>
<batch-action-bar :data="dataList" :selection-data="selectionDataList" @check-all="$refs.table.toggleAllSelection()" @check-null="$refs.table.clearSelection()">
<el-button size="default">单个批量操作按钮</el-button>
<el-button-group>
<el-button size="default">批量操作按钮组1</el-button>
<el-button size="default">批量操作按钮组2</el-button>
</el-button-group>
</batch-action-bar>
</page-main>
</div>
</template>
@@ -1,16 +1,3 @@
<template>
<div>
<page-main title="富文本编辑器">
<editor v-model="content1" />
<div class="preview" v-html="content1" />
</page-main>
<page-main title="markdown 编辑器">
<mavon-editor v-model="content2" style="z-index: 9;" />
<div class="preview" v-html="mdContent2" />
</page-main>
</div>
</template>
<script setup>
import { mavonEditor } from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
@@ -24,6 +11,19 @@ const mdContent2 = computed(() => {
})
</script>
<template>
<div>
<page-main title="富文本编辑器">
<editor v-model="content1" />
<div class="preview" v-html="content1" />
</page-main>
<page-main title="markdown 编辑器">
<mavon-editor v-model="content2" style="z-index: 9;" />
<div class="preview" v-html="mdContent2" />
</page-main>
</div>
</template>
<style lang="scss" scoped>
.preview {
margin-top: 10px;
@@ -1,19 +1,3 @@
<template>
<div>
<page-header title="图片预览" content="ImagePreview" />
<page-main>
<div>
<image-preview :src="`https://hooray.${locationOrigin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/logo.png`" :width="200" />
</div>
</page-main>
<page-main title="图片加载失败时">
<div>
<image-preview src="http://www.baidu.com" width="100px" height="100px" />
</div>
</page-main>
</div>
</template>
<script>
export default {
props: {},
@@ -29,6 +13,18 @@ export default {
}
</script>
<style lang="scss" scoped>
// scss
</style>
<template>
<div>
<page-header title="图片预览" content="ImagePreview" />
<page-main>
<div>
<image-preview :src="`https://hooray.${locationOrigin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/logo.png`" :width="200" />
</div>
</page-main>
<page-main title="图片加载失败时">
<div>
<image-preview src="http://www.baidu.com" width="100px" height="100px" />
</div>
</page-main>
</div>
</template>
@@ -1,3 +1,22 @@
<script>
export default {
data() {
return {
search: {
name: '',
department_id: '',
department_job_id: '',
role_id: '',
check1: true,
check2: false
},
searchMore: false,
searchMore2: false
}
}
}
</script>
<template>
<div>
<page-header title="搜索面板" content="SearchBar" />
@@ -111,22 +130,3 @@
</page-main>
</div>
</template>
<script>
export default {
data() {
return {
search: {
name: '',
department_id: '',
department_job_id: '',
role_id: '',
check1: true,
check2: false
},
searchMore: false,
searchMore2: false
}
}
}
</script>
+11 -11
View File
@@ -1,3 +1,14 @@
<script>
export default {
data() {
return {
flip: '',
rotate: 0
}
}
}
</script>
<template>
<div>
<page-header title="SVG Icon" content="除了使用 Element Plus 提供的图标外,你还可以使用自己的 SVG 图标" />
@@ -29,17 +40,6 @@
</div>
</template>
<script>
export default {
data() {
return {
flip: '',
rotate: 0
}
}
}
</script>
<style scoped>
.example-icon {
font-size: 48px;
@@ -1,25 +1,3 @@
<template>
<div class="absolute-container">
<page-header title="表格高度自适应">
<template #content>
<p>TableHeightAdaption</p>
<p style="margin-bottom: 0;">该组件必须包裹 ElTable 使用,并且需要对上级元素设置高度后才会生效</p>
</template>
</page-header>
<page-main>
<TableHeightAdaption>
<el-table :data="dataList" border stripe highlight-current-row>
<el-table-column type="index" width="50" />
<el-table-column prop="date" label="日期" width="180" />
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="address" label="地址" />
</el-table>
</TableHeightAdaption>
<el-button type="primary">按钮</el-button>
</page-main>
</div>
</template>
<script>
export default {
name: 'ComponentExampleTableHeightAdaption',
@@ -133,6 +111,28 @@ export default {
}
</script>
<template>
<div class="absolute-container">
<page-header title="表格高度自适应">
<template #content>
<p>TableHeightAdaption</p>
<p style="margin-bottom: 0;">该组件必须包裹 ElTable 使用,并且需要对上级元素设置高度后才会生效</p>
</template>
</page-header>
<page-main>
<TableHeightAdaption>
<el-table :data="dataList" border stripe highlight-current-row>
<el-table-column type="index" width="50" />
<el-table-column prop="date" label="日期" width="180" />
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="address" label="地址" />
</el-table>
</TableHeightAdaption>
<el-button type="primary">按钮</el-button>
</page-main>
</div>
</template>
<style lang="scss" scoped>
.absolute-container {
position: absolute;
@@ -1,18 +1,3 @@
<template>
<div>
<page-header title="上传" content="ImageUpload / ImagesUpload / FileUpload" />
<page-main title="单图上传">
<image-upload v-model:url="image" action="http://scrm.1daas.com/api/upload/upload" name="image" :width="250" :height="150" :data="{'token':'TKE615916022101558'}" @on-success="handleSuccess1" />
</page-main>
<page-main title="多图上传(默认最多3张)">
<images-upload v-model:url="images" action="http://scrm.1daas.com/api/upload/upload" name="image" :data="{'token':'TKE615916022101558'}" @on-success="handleSuccess2" />
</page-main>
<page-main title="文件上传(默认最多3个)">
<file-upload :files="files" action="http://scrm.1daas.com/api/upload/upload" name="image" :data="{'token':'TKE615916022101558'}" @on-success="handleSuccess3" />
</page-main>
</div>
</template>
<script>
export default {
data() {
@@ -65,3 +50,18 @@ export default {
}
}
</script>
<template>
<div>
<page-header title="上传" content="ImageUpload / ImagesUpload / FileUpload" />
<page-main title="单图上传">
<image-upload v-model:url="image" action="http://scrm.1daas.com/api/upload/upload" name="image" :width="250" :height="150" :data="{'token':'TKE615916022101558'}" @on-success="handleSuccess1" />
</page-main>
<page-main title="多图上传(默认最多3张)">
<images-upload v-model:url="images" action="http://scrm.1daas.com/api/upload/upload" name="image" :data="{'token':'TKE615916022101558'}" @on-success="handleSuccess2" />
</page-main>
<page-main title="文件上传(默认最多3个)">
<file-upload :files="files" action="http://scrm.1daas.com/api/upload/upload" name="image" :data="{'token':'TKE615916022101558'}" @on-success="handleSuccess3" />
</page-main>
</div>
</template>
+46 -46
View File
@@ -1,3 +1,49 @@
<script setup>
const locationOrigin = location.origin
function open(url) {
window.open(url, 'top')
}
const fantasticTemplateInfo = ref({
feature: [
'默认集成 vue-router 和 pinia',
'全局 SCSS 资源引入',
'全局组件自动注册',
'支持 SVG 图标,CSS 精灵图自动合成',
'支持 mock 数据,可摆脱后端束缚独立开发',
'支持 gzip / brotli 优化项目体积,提高加载速度',
'结合 IDE 插件、ESlint 、stylelint 、Git 钩子,轻松实现团队代码规范'
]
})
const fantasticAdminInfo = ref({
imageVisible: false,
index: 0,
data: [
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/preview1.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/preview2.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/preview3.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/preview4.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/preview5.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/preview6.png`
]
})
const oneStepAdminInfo = ref({
imageVisible: false,
index: 0,
data: [
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/one-step-admin/preview1.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/one-step-admin/preview2.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/one-step-admin/preview3.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/one-step-admin/preview4.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/one-step-admin/preview5.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/one-step-admin/preview6.png`
]
})
</script>
<template>
<div>
<page-header title="欢迎使用 Fantastic-admin(基础版)">
@@ -93,52 +139,6 @@
</div>
</template>
<script setup>
const locationOrigin = location.origin
function open(url) {
window.open(url, 'top')
}
const fantasticTemplateInfo = ref({
feature: [
'默认集成 vue-router 和 pinia',
'全局 SCSS 资源引入',
'全局组件自动注册',
'支持 SVG 图标,CSS 精灵图自动合成',
'支持 mock 数据,可摆脱后端束缚独立开发',
'支持 gzip / brotli 优化项目体积,提高加载速度',
'结合 IDE 插件、ESlint 、stylelint 、Git 钩子,轻松实现团队代码规范'
]
})
const fantasticAdminInfo = ref({
imageVisible: false,
index: 0,
data: [
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/preview1.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/preview2.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/preview3.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/preview4.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/preview5.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/preview6.png`
]
})
const oneStepAdminInfo = ref({
imageVisible: false,
index: 0,
data: [
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/one-step-admin/preview1.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/one-step-admin/preview2.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/one-step-admin/preview3.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/one-step-admin/preview4.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/one-step-admin/preview5.png`,
`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/one-step-admin/preview6.png`
]
})
</script>
<style lang="scss" scoped>
.text-emphasis {
/* stylelint-disable-next-line property-no-vendor-prefix */
@@ -1,3 +1,8 @@
<script setup name="TabExampleNested1">
import { useKeepAliveStore } from '@/store/modules/keepAlive'
const keepAliveStore = useKeepAliveStore()
</script>
<template>
<div>
<page-main>
@@ -10,8 +15,3 @@
</page-main>
</div>
</template>
<script setup name="TabExampleNested1">
import { useKeepAliveStore } from '@/store/modules/keepAlive'
const keepAliveStore = useKeepAliveStore()
</script>
@@ -1,3 +1,8 @@
<script setup name="TabExampleNested2">
import { useKeepAliveStore } from '@/store/modules/keepAlive'
const keepAliveStore = useKeepAliveStore()
</script>
<template>
<div>
<page-main>
@@ -10,8 +15,3 @@
</page-main>
</div>
</template>
<script setup name="TabExampleNested2">
import { useKeepAliveStore } from '@/store/modules/keepAlive'
const keepAliveStore = useKeepAliveStore()
</script>
@@ -1,12 +1,3 @@
<template>
<div>
<page-main>
<div>层级 1-1-1</div>
<el-input v-model="val" />
</page-main>
</div>
</template>
<script>
export default {
name: 'TabExampleNestedTest',
@@ -17,3 +8,12 @@ export default {
}
}
</script>
<template>
<div>
<page-main>
<div>层级 1-1-1</div>
<el-input v-model="val" />
</page-main>
</div>
</template>
@@ -1,12 +1,3 @@
<template>
<div>
<page-main>
<div>层级 1-1-2</div>
<el-input v-model="val" />
</page-main>
</div>
</template>
<script>
export default {
name: 'TabExampleNestedTest2',
@@ -17,3 +8,12 @@ export default {
}
}
</script>
<template>
<div>
<page-main>
<div>层级 1-1-2</div>
<el-input v-model="val" />
</page-main>
</div>
</template>
+18 -18
View File
@@ -1,21 +1,3 @@
<template>
<div>
<page-header title="页面缓存" content="除了可以在路由里配置页面是否需要缓存外,你也可以不使用框架提供的方法,而是在页面里自行实现,该方法目前仅支持在 Options API 中实现。" />
<page-main>
<div class="block">
<el-switch v-model="openKeepAlive" active-text="开启缓存" inactive-text="关闭缓存" />
</div>
<div class="block">
<el-input-number v-model="num" />
</div>
<div class="block">
<el-button @click="go(1)">进入同级路由页面</el-button>
<el-button @click="go(2)">进入下级路由页面</el-button>
</div>
</page-main>
</div>
</template>
<script setup name="KeepAliveExamplePage">
import { onBeforeRouteLeave } from 'vue-router'
@@ -54,6 +36,24 @@ onBeforeRouteLeave((to, from) => {
})
</script>
<template>
<div>
<page-header title="页面缓存" content="除了可以在路由里配置页面是否需要缓存外,你也可以不使用框架提供的方法,而是在页面里自行实现,该方法目前仅支持在 Options API 中实现。" />
<page-main>
<div class="block">
<el-switch v-model="openKeepAlive" active-text="开启缓存" inactive-text="关闭缓存" />
</div>
<div class="block">
<el-input-number v-model="num" />
</div>
<div class="block">
<el-button @click="go(1)">进入同级路由页面</el-button>
<el-button @click="go(2)">进入下级路由页面</el-button>
</div>
</page-main>
</div>
</template>
<style lang="scss" scoped>
.block {
margin-bottom: 10px;
+86 -86
View File
@@ -1,89 +1,3 @@
<template>
<div>
<div class="bg-banner" />
<div id="login-box">
<div class="login-banner" />
<el-form v-show="formType == 'login'" ref="loginFormRef" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left">
<div class="title-container">
<h3 class="title">{{ title }}管理后台</h3>
</div>
<div>
<el-form-item prop="account">
<el-input ref="name" v-model="loginForm.account" placeholder="用户名" type="text" tabindex="1" autocomplete="on">
<template #prefix>
<svg-icon name="user" />
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input ref="password" v-model="loginForm.password" :type="passwordType" placeholder="密码" tabindex="2" autocomplete="on" @keyup.enter="handleLogin">
<template #prefix>
<svg-icon name="password" />
</template>
<template #suffix>
<svg-icon :name="passwordType === 'password' ? 'eye' : 'eye-open'" @click="showPassword" />
</template>
</el-input>
</el-form-item>
</div>
<div class="flex-bar">
<el-checkbox v-model="loginForm.remember">记住我</el-checkbox>
<el-button type="text" @click="formType = 'reset'">忘记密码</el-button>
</div>
<el-button :loading="loading" type="primary" size="large" style="width: 100%;" @click.prevent="handleLogin">登 录</el-button>
<div style="margin-top: 20px; margin-bottom: -10px; color: #666; font-size: 14px; text-align: center; font-weight: bold;">
<span style="margin-right: 5px;">演示帐号一键登录:</span>
<el-button type="danger" size="small" @click="testAccount('admin')">admin</el-button>
<el-button type="danger" size="small" plain @click="testAccount('test')">test</el-button>
</div>
</el-form>
<el-form v-show="formType == 'reset'" ref="resetFormRef" :model="resetForm" :rules="resetRules" class="login-form" auto-complete="on" label-position="left">
<div class="title-container">
<h3 class="title">重置密码</h3>
</div>
<div>
<el-form-item prop="account">
<el-input ref="name" v-model="resetForm.account" placeholder="用户名" type="text" tabindex="1" autocomplete="on">
<template #prefix>
<svg-icon name="user" />
</template>
</el-input>
</el-form-item>
<el-form-item prop="captcha">
<el-input ref="captcha" v-model="resetForm.captcha" placeholder="验证码" type="text" tabindex="2" autocomplete="on">
<template #prefix>
<svg-icon name="captcha" />
</template>
<template #append>
<el-button>发送验证码</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item prop="newPassword">
<el-input ref="newPassword" v-model="resetForm.newPassword" :type="passwordType" placeholder="新密码" tabindex="3" autocomplete="on">
<template #prefix>
<svg-icon name="password" />
</template>
<template #suffix>
<svg-icon :name="passwordType === 'password' ? 'eye' : 'eye-open'" @click="showPassword" />
</template>
</el-input>
</el-form-item>
</div>
<el-row :gutter="15" style="padding-top: 20px;">
<el-col :md="6">
<el-button size="large" style="width: 100%;" @click="formType = 'login'">去登录</el-button>
</el-col>
<el-col :md="18">
<el-button :loading="loading" type="primary" size="large" style="width: 100%;" @click.prevent="handleFind">确 认</el-button>
</el-col>
</el-row>
</el-form>
</div>
<Copyright v-if="settingsStore.copyright.enable" />
</div>
</template>
<script setup name="Login">
const { proxy } = getCurrentInstance()
const route = useRoute(), router = useRouter()
@@ -184,6 +98,92 @@ function testAccount(account) {
}
</script>
<template>
<div>
<div class="bg-banner" />
<div id="login-box">
<div class="login-banner" />
<el-form v-show="formType == 'login'" ref="loginFormRef" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left">
<div class="title-container">
<h3 class="title">{{ title }}管理后台</h3>
</div>
<div>
<el-form-item prop="account">
<el-input ref="name" v-model="loginForm.account" placeholder="用户名" type="text" tabindex="1" autocomplete="on">
<template #prefix>
<svg-icon name="user" />
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input ref="password" v-model="loginForm.password" :type="passwordType" placeholder="密码" tabindex="2" autocomplete="on" @keyup.enter="handleLogin">
<template #prefix>
<svg-icon name="password" />
</template>
<template #suffix>
<svg-icon :name="passwordType === 'password' ? 'eye' : 'eye-open'" @click="showPassword" />
</template>
</el-input>
</el-form-item>
</div>
<div class="flex-bar">
<el-checkbox v-model="loginForm.remember">记住我</el-checkbox>
<el-button type="text" @click="formType = 'reset'">忘记密码</el-button>
</div>
<el-button :loading="loading" type="primary" size="large" style="width: 100%;" @click.prevent="handleLogin">登 录</el-button>
<div style="margin-top: 20px; margin-bottom: -10px; color: #666; font-size: 14px; text-align: center; font-weight: bold;">
<span style="margin-right: 5px;">演示帐号一键登录:</span>
<el-button type="danger" size="small" @click="testAccount('admin')">admin</el-button>
<el-button type="danger" size="small" plain @click="testAccount('test')">test</el-button>
</div>
</el-form>
<el-form v-show="formType == 'reset'" ref="resetFormRef" :model="resetForm" :rules="resetRules" class="login-form" auto-complete="on" label-position="left">
<div class="title-container">
<h3 class="title">重置密码</h3>
</div>
<div>
<el-form-item prop="account">
<el-input ref="name" v-model="resetForm.account" placeholder="用户名" type="text" tabindex="1" autocomplete="on">
<template #prefix>
<svg-icon name="user" />
</template>
</el-input>
</el-form-item>
<el-form-item prop="captcha">
<el-input ref="captcha" v-model="resetForm.captcha" placeholder="验证码" type="text" tabindex="2" autocomplete="on">
<template #prefix>
<svg-icon name="captcha" />
</template>
<template #append>
<el-button>发送验证码</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item prop="newPassword">
<el-input ref="newPassword" v-model="resetForm.newPassword" :type="passwordType" placeholder="新密码" tabindex="3" autocomplete="on">
<template #prefix>
<svg-icon name="password" />
</template>
<template #suffix>
<svg-icon :name="passwordType === 'password' ? 'eye' : 'eye-open'" @click="showPassword" />
</template>
</el-input>
</el-form-item>
</div>
<el-row :gutter="15" style="padding-top: 20px;">
<el-col :md="6">
<el-button size="large" style="width: 100%;" @click="formType = 'login'">去登录</el-button>
</el-col>
<el-col :md="18">
<el-button :loading="loading" type="primary" size="large" style="width: 100%;" @click.prevent="handleFind">确 认</el-button>
</el-col>
</el-row>
</el-form>
</div>
<Copyright v-if="settingsStore.copyright.enable" />
</div>
</template>
<style lang="scss" scoped>
[data-mode="mobile"] {
#login-box {
+11 -11
View File
@@ -1,14 +1,3 @@
<template>
<div>
<page-header title="Mock" content="通过拦截 Ajax 请求,返回模拟的响应数据,可以让前端工程师独立于后端进行开发,本演示站的登录和权限获取就是通过 mock 实现的。更多 Mock 语法规则请查询官方文档">
<el-button icon="el-icon-link" @click="open('http://mockjs.com/')">Mock.js 官网</el-button>
</page-header>
<page-main>
<el-button @click="getPermission">测试:获取用户权限</el-button>
</page-main>
</div>
</template>
<script setup>
const { proxy } = getCurrentInstance()
@@ -29,3 +18,14 @@ function open(url) {
window.open(url, 'top')
}
</script>
<template>
<div>
<page-header title="Mock" content="通过拦截 Ajax 请求,返回模拟的响应数据,可以让前端工程师独立于后端进行开发,本演示站的登录和权限获取就是通过 mock 实现的。更多 Mock 语法规则请查询官方文档">
<el-button icon="el-icon-link" @click="open('http://mockjs.com/')">Mock.js 官网</el-button>
</page-header>
<page-main>
<el-button @click="getPermission">测试:获取用户权限</el-button>
</page-main>
</div>
</template>
+39 -39
View File
@@ -1,3 +1,42 @@
<script setup>
const { proxy } = getCurrentInstance()
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useUserStore } from '@/store/modules/user'
const userStore = useUserStore()
function accountChange(val) {
proxy.$loading({
lock: true,
text: '帐号切换中',
background: 'rgba(0, 0, 0, 0.7)'
})
userStore.login({
account: val,
password: ''
}).then(() => {
setTimeout(() => {
location.reload()
}, 1000)
})
}
function permissionCheck(permissions) {
if (proxy.$auth(permissions)) {
proxy.$message.success('校验通过')
} else {
proxy.$message.error('校验不通过')
}
}
function permissionCheck2(permissions) {
if (proxy.$authAll(permissions)) {
proxy.$message.success('校验通过')
} else {
proxy.$message.error('校验不通过')
}
}
</script>
<template>
<div>
<page-header title="权限验证" />
@@ -68,42 +107,3 @@
</page-main>
</div>
</template>
<script setup>
const { proxy } = getCurrentInstance()
import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useUserStore } from '@/store/modules/user'
const userStore = useUserStore()
function accountChange(val) {
proxy.$loading({
lock: true,
text: '帐号切换中',
background: 'rgba(0, 0, 0, 0.7)'
})
userStore.login({
account: val,
password: ''
}).then(() => {
setTimeout(() => {
location.reload()
}, 1000)
})
}
function permissionCheck(permissions) {
if (proxy.$auth(permissions)) {
proxy.$message.success('校验通过')
} else {
proxy.$message.error('校验不通过')
}
}
function permissionCheck2(permissions) {
if (proxy.$authAll(permissions)) {
proxy.$message.success('校验通过')
} else {
proxy.$message.error('校验不通过')
}
}
</script>
+26 -26
View File
@@ -1,29 +1,3 @@
<template>
<div>
<page-header title="修改密码" content="定期修改密码可以提高帐号安全性噢~" />
<page-main>
<el-row>
<el-col :md="24" :lg="12">
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="原密码" prop="password">
<el-input v-model="form.password" type="password" placeholder="请输入原密码" />
</el-form-item>
<el-form-item label="新密码" prop="newpassword">
<el-input v-model="form.newpassword" type="password" placeholder="请输入原密码" />
</el-form-item>
<el-form-item label="确认新密码" prop="checkpassword">
<el-input v-model="form.checkpassword" type="password" placeholder="请输入原密码" />
</el-form-item>
</el-form>
</el-col>
</el-row>
</page-main>
<fixed-action-bar>
<el-button type="primary" size="large" @click="onSubmit">提交</el-button>
</fixed-action-bar>
</div>
</template>
<script setup name="PersonalEditPassword">
const route = useRoute(), router = useRouter()
const { proxy } = getCurrentInstance()
@@ -80,3 +54,29 @@ function onSubmit() {
})
}
</script>
<template>
<div>
<page-header title="修改密码" content="定期修改密码可以提高帐号安全性噢~" />
<page-main>
<el-row>
<el-col :md="24" :lg="12">
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="原密码" prop="password">
<el-input v-model="form.password" type="password" placeholder="请输入原密码" />
</el-form-item>
<el-form-item label="新密码" prop="newpassword">
<el-input v-model="form.newpassword" type="password" placeholder="请输入原密码" />
</el-form-item>
<el-form-item label="确认新密码" prop="checkpassword">
<el-input v-model="form.checkpassword" type="password" placeholder="请输入原密码" />
</el-form-item>
</el-form>
</el-col>
</el-row>
</page-main>
<fixed-action-bar>
<el-button type="primary" size="large" @click="onSubmit">提交</el-button>
</fixed-action-bar>
</div>
</template>
+26 -26
View File
@@ -1,3 +1,29 @@
<script setup name="PersonalSetting">
const router = useRouter()
const { proxy } = getCurrentInstance()
const form = ref({
headimg: '',
mobile: '',
name: '',
qq: '',
wechat: ''
})
function handleSuccess(res) {
if (res.error == '') {
form.value.headimg = res.data.path
} else {
proxy.$message.warning(res.error)
}
}
function editPassword() {
router.push({
name: 'personalEditPassword'
})
}
</script>
<template>
<div>
<!-- 页面:Setting -->
@@ -67,32 +93,6 @@
</div>
</template>
<script setup name="PersonalSetting">
const router = useRouter()
const { proxy } = getCurrentInstance()
const form = ref({
headimg: '',
mobile: '',
name: '',
qq: '',
wechat: ''
})
function handleSuccess(res) {
if (res.error == '') {
form.value.headimg = res.data.path
} else {
proxy.$message.warning(res.error)
}
}
function editPassword() {
router.push({
name: 'personalEditPassword'
})
}
</script>
<style lang="scss" scoped>
:deep(.el-tabs) {
.el-tabs__header .el-tabs__nav {
+8 -8
View File
@@ -1,11 +1,11 @@
<script setup>
const router = useRouter()
onMounted(() => {
router.go(-1)
})
</script>
<template>
<div />
</template>
<script>
export default {
mounted() {
this.$router.go(-1)
}
}
</script>