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

This commit is contained in:
hooray
2022-02-11 09:47:14 +08:00
parent bc22055623
commit e4b4bc0957
35 changed files with 712 additions and 712 deletions
+4 -4
View File
@@ -1,13 +1,13 @@
<script setup{{#if isGlobal}} name="{{ properCase name }}"{{/if}}>
// const { proxy } = getCurrentInstance()
</script>
<template>
<div>
<!-- 内容区 -->
</div>
</template>
<script setup{{#if isGlobal}} name="{{ properCase name }}"{{/if}}>
// const { proxy } = getCurrentInstance()
</script>
<style lang="scss" scoped>
// scss
</style>
+6 -6
View File
@@ -1,3 +1,9 @@
<script setup name="{{ properCase componentName }}">
// const { proxy } = getCurrentInstance()
// const router = useRouter()
// const route = useRoute()
</script>
<template>
<div>
<page-header title="{{ cname }}" />
@@ -7,12 +13,6 @@
</div>
</template>
<script setup name="{{ properCase componentName }}">
// const { proxy } = getCurrentInstance()
// const router = useRouter()
// const route = useRoute()
</script>
<style lang="scss" scoped>
// scss
</style>
+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;
+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 {
+35 -35
View File
@@ -1,3 +1,38 @@
<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
}
}
</script>
<template>
<div class="tools">
<div class="buttons">
@@ -33,41 +68,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
}
}
</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;
+33 -33
View File
@@ -1,36 +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 />
</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'
@@ -99,6 +67,38 @@ 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 />
</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;
+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 {
+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>