初始化代码
This commit is contained in:
81
uniapp/uni-admin/src/components/ad.vue
Normal file
81
uniapp/uni-admin/src/components/ad.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<!--
|
||||
* @Descripttion: 左侧边栏广告
|
||||
* @Author: xiao li
|
||||
* @Date: 2020-07-06 12:17:06
|
||||
* @LastEditors: xiao li
|
||||
* @LastEditTime: 2021-03-15 13:22:26
|
||||
-->
|
||||
<template>
|
||||
<div class="lb-ad" :class="!adSwitch ? 'ad-collapse' : ''">
|
||||
<div class="ad-main">
|
||||
<!-- <lb-image src="@/assets/icon/apps.png"/> -->
|
||||
</div>
|
||||
<div class="flod" @click="handleFold">{{adSwitch ? '折叠' : '展开'}}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
key: '广告'
|
||||
}
|
||||
},
|
||||
created () {
|
||||
},
|
||||
methods: {
|
||||
handleFold () {
|
||||
let {adSwitch} = this
|
||||
this.$store.commit('handleAdSwitch', !adSwitch)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['adSwitch'])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lb-ad{
|
||||
width: 220px;
|
||||
position: fixed;
|
||||
transition: width 0.2s linear;
|
||||
top: 70px;
|
||||
right: 0;
|
||||
height: 1000px;
|
||||
z-index: 2;
|
||||
.ad-main{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 220px;
|
||||
background: #fff;
|
||||
height: 100%;
|
||||
font-size: 14px;
|
||||
padding: 10px;
|
||||
}
|
||||
.flod{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: -20px;
|
||||
margin: auto;
|
||||
width: 20px;
|
||||
height: 80px;
|
||||
background: #BFBFBF;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.ad-collapse{
|
||||
width: 0px;
|
||||
}
|
||||
</style>
|
||||
28
uniapp/uni-admin/src/components/basics/index.js
Normal file
28
uniapp/uni-admin/src/components/basics/index.js
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
import Vue from 'vue'
|
||||
import TopNav from './topNav.vue'
|
||||
import LbButton from './lbButton.vue'
|
||||
import LbSwitch from './lbSwitch.vue'
|
||||
import LbTips from './lbTips.vue'
|
||||
import LbPage from './lbPage.vue'
|
||||
import LbClassifyTitle from './lbClassifyTitle.vue'
|
||||
import LbUpload from './lbUpload.vue'
|
||||
import LbToolTips from './lbToolTips.vue'
|
||||
import LbUploadCover from './lbUploadCover.vue'
|
||||
import LbUeditor from './lbUeditor.vue'
|
||||
import LbCover from './lbCover.vue'
|
||||
import LbImage from './lbImage.vue'
|
||||
import LbMap from './lbMap.vue'
|
||||
Vue.component('top-nav', TopNav)
|
||||
Vue.component('lb-button', LbButton)
|
||||
Vue.component('lb-switch', LbSwitch)
|
||||
Vue.component('lb-tips', LbTips)
|
||||
Vue.component('lb-page', LbPage)
|
||||
Vue.component('lb-classify-title', LbClassifyTitle)
|
||||
Vue.component('lb-upload', LbUpload)
|
||||
Vue.component('lb-tool-tips', LbToolTips)
|
||||
Vue.component('lb-upload-cover', LbUploadCover)
|
||||
Vue.component('lb-ueditor', LbUeditor)
|
||||
Vue.component('lb-cover', LbCover)
|
||||
Vue.component('lb-image', LbImage)
|
||||
Vue.component('lb-map', LbMap)
|
||||
79
uniapp/uni-admin/src/components/basics/lbButton.vue
Normal file
79
uniapp/uni-admin/src/components/basics/lbButton.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<el-button
|
||||
:disabled="isDisabled"
|
||||
:type="type"
|
||||
:plain="plain"
|
||||
:round="round"
|
||||
:icon="icon"
|
||||
:size="size"
|
||||
:loading='loading'
|
||||
@click="handleClick"
|
||||
>
|
||||
<slot></slot>
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
plain: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
round: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'medium'
|
||||
},
|
||||
opType: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isDisabled: this.disabled,
|
||||
currentIndex: this.$store.state.operate.currentIndex
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let {isOnly, auth, pagePermission} = this.$route.meta
|
||||
let {disabled} = this
|
||||
if (disabled) {
|
||||
this.isDisabled = disabled
|
||||
} else if (this.opType) {
|
||||
if (isOnly) {
|
||||
this.isDisabled = auth.indexOf(this.opType) === -1
|
||||
} else {
|
||||
this.isDisabled = pagePermission[this.currentIndex].auth.indexOf(this.opType) === -1
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick () {
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
39
uniapp/uni-admin/src/components/basics/lbClassifyTitle.vue
Normal file
39
uniapp/uni-admin/src/components/basics/lbClassifyTitle.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<!--
|
||||
* @Description: 标题栏
|
||||
* @Author: xiao li
|
||||
* @Date: 2021-07-04 00:16:14
|
||||
* @LastEditTime: 2021-09-10 16:31:28
|
||||
* @LastEditors: xiao li
|
||||
-->
|
||||
<template>
|
||||
<div class="lb-goods-edit-classify mb-lg">
|
||||
<div class="title">{{ title }}</div>
|
||||
<span v-if="tips" class="tips">{{ tips }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['title', 'tips']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lb-goods-edit-classify {
|
||||
width: 100%;
|
||||
border-top: 1px solid $lineColor;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.title {
|
||||
display: inline-block;
|
||||
padding: 6px 15px;
|
||||
color: $themeColor;
|
||||
background: $columnBgColor;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.tips {
|
||||
color: $tipsColor;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
375
uniapp/uni-admin/src/components/basics/lbCover.vue
Normal file
375
uniapp/uni-admin/src/components/basics/lbCover.vue
Normal file
@@ -0,0 +1,375 @@
|
||||
<template>
|
||||
<div class="lb-cover-wrap">
|
||||
<div
|
||||
class="lb-cover"
|
||||
:class="[size]"
|
||||
@click="showUploadModel"
|
||||
v-if="type === 'single'"
|
||||
>
|
||||
<lb-image v-if="cover.length > 0" :src="cover[cover.length - 1].url" />
|
||||
<i v-else class="el-icon-plus"></i>
|
||||
<i
|
||||
v-if="cover.length > 0"
|
||||
@click.stop="deleteCover"
|
||||
class="el-icon-circle-close"
|
||||
></i>
|
||||
</div>
|
||||
<div v-else-if="type === 'more'" class="lb-upload-more">
|
||||
<vuedraggable @change="dragChange" v-model="cover">
|
||||
<transition-group class="flex-warp">
|
||||
<div
|
||||
class="more-item"
|
||||
:class="[size]"
|
||||
v-for="(item, index) in cover"
|
||||
:key="`drag_${index}`"
|
||||
>
|
||||
<lb-image :src="item.url" />
|
||||
<div class="mask">
|
||||
<i
|
||||
@click="lookBigImg(item.url)"
|
||||
class="el-icon-zoom-in"
|
||||
v-if="item.url"
|
||||
></i>
|
||||
<i
|
||||
@click="delImg(index)"
|
||||
class="el-icon-delete"
|
||||
v-if="isToDel"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
</transition-group>
|
||||
</vuedraggable>
|
||||
<div class="flex-warp" v-if="cover.length < fileSize">
|
||||
<div class="up-item" :class="[size]" @click="showUploadModel">
|
||||
<i class="el-icon-plus"></i>
|
||||
</div>
|
||||
<lb-tool-tips class="ml-sm" v-if="tips">{{
|
||||
`图片建议尺寸:${tips}`
|
||||
}}</lb-tool-tips>
|
||||
</div>
|
||||
<el-dialog
|
||||
:visible.sync="centerDialogVisible"
|
||||
width="800px"
|
||||
center
|
||||
:append-to-body="true"
|
||||
>
|
||||
<div class="dialog-inner-img">
|
||||
<lb-image class="dialog-img" :src="viewImg" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<lb-button type="primary" size="mini" @click="showUploadModel" v-else
|
||||
>选择</lb-button
|
||||
>
|
||||
<block v-if="isToDel">
|
||||
<lb-upload
|
||||
:paramData="paramData"
|
||||
:filesLength="fileList.length"
|
||||
:fileSize="fileSize"
|
||||
:multilineType="type"
|
||||
:visibles.sync="showUpload"
|
||||
:fileType="fileType"
|
||||
:fileAccept="fileAccept"
|
||||
@selectedFiles="selectedFiles"
|
||||
></lb-upload>
|
||||
</block>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import vuedraggable from 'vuedraggable'
|
||||
export default {
|
||||
components: {
|
||||
vuedraggable
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default () {
|
||||
return 'single'
|
||||
}
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default () {
|
||||
return 'big'
|
||||
}
|
||||
},
|
||||
tips: {
|
||||
type: String,
|
||||
default () {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
fileType: {
|
||||
type: String,
|
||||
default () {
|
||||
return 'image'
|
||||
}
|
||||
},
|
||||
fileAccept: {
|
||||
type: String,
|
||||
default () {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
fileSize: {
|
||||
type: Number,
|
||||
default () {
|
||||
return 9
|
||||
}
|
||||
},
|
||||
fileList: {
|
||||
type: [Array, String],
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
isToDel: {
|
||||
type: Boolean,
|
||||
default () {
|
||||
return true
|
||||
}
|
||||
},
|
||||
paramData: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showUpload: false,
|
||||
cover: [],
|
||||
centerDialogVisible: false,
|
||||
viewImg: ''
|
||||
}
|
||||
},
|
||||
created () {
|
||||
if (this.fileList && this.fileList.length) {
|
||||
this.cover = this.fileList
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectedFiles (img) {
|
||||
if (!img.length) return false
|
||||
let selectedImgs = this.type === 'single' ? [img[img.length - 1]] : img
|
||||
this.cover = selectedImgs
|
||||
this.$emit('selectedFiles', selectedImgs)
|
||||
},
|
||||
dragChange (e) {
|
||||
this.$emit('moveFiles', this.cover)
|
||||
},
|
||||
showUploadModel () {
|
||||
this.showUpload = true
|
||||
},
|
||||
lookBigImg (url) {
|
||||
this.viewImg = url
|
||||
this.centerDialogVisible = true
|
||||
},
|
||||
delImg (index) {
|
||||
this.cover.splice(index, 1)
|
||||
},
|
||||
deleteCover () {
|
||||
this.cover = []
|
||||
this.$emit('selectedFiles', [])
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
fileList: {
|
||||
deep: true,
|
||||
handler (val) {
|
||||
if (val && typeof val === 'object') {
|
||||
this.cover = val
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lb-cover-wrap {
|
||||
display: inline-block;
|
||||
.lb-cover.small {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
.el-image {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
i {
|
||||
font-size: 20px;
|
||||
line-height: 60px;
|
||||
}
|
||||
.el-icon-circle-close {
|
||||
font-size: 18px;
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.lb-cover.middle {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
.el-image {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
i {
|
||||
font-size: 20px;
|
||||
line-height: 80px;
|
||||
}
|
||||
.el-icon-circle-close {
|
||||
font-size: 22px;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
.lb-cover {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
.el-image {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
i {
|
||||
font-size: 26px;
|
||||
line-height: 100px;
|
||||
}
|
||||
&:hover {
|
||||
border: 1px dashed #09f;
|
||||
.el-icon-circle-close {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.el-icon-circle-close {
|
||||
display: none;
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
.lb-upload-more {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.more-item.small {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
.el-image {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
z-index: 5;
|
||||
}
|
||||
}
|
||||
.more-item.middle {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
.el-image {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
z-index: 5;
|
||||
}
|
||||
}
|
||||
.more-item {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 6px;
|
||||
position: relative;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
.el-image {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
z-index: 5;
|
||||
}
|
||||
.mask {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10;
|
||||
top: 0;
|
||||
left: 0;
|
||||
i {
|
||||
margin: 0 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.mask {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
.up-item {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
i {
|
||||
font-size: 26px;
|
||||
line-height: 100px;
|
||||
}
|
||||
&:hover {
|
||||
border: 1px dashed #09f;
|
||||
}
|
||||
}
|
||||
.up-item.small {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
i {
|
||||
font-size: 18px;
|
||||
line-height: 60px;
|
||||
}
|
||||
&:hover {
|
||||
border: 1px dashed #09f;
|
||||
}
|
||||
}
|
||||
.up-item.middle {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
i {
|
||||
font-size: 22px;
|
||||
line-height: 80px;
|
||||
}
|
||||
&:hover {
|
||||
border: 1px dashed #09f;
|
||||
}
|
||||
}
|
||||
}
|
||||
.dialog-inner-img {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.dialog-img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
36
uniapp/uni-admin/src/components/basics/lbImage.vue
Normal file
36
uniapp/uni-admin/src/components/basics/lbImage.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<el-image :fit="fit" :src="src">
|
||||
<div slot="error" class="image-slot">
|
||||
<i class="el-icon-picture-outline"></i>
|
||||
</div>
|
||||
</el-image>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
fit: {
|
||||
type: String,
|
||||
default: 'cover'
|
||||
},
|
||||
src: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-image{
|
||||
background: $bgThemeColor;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.image-slot{
|
||||
i{
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
173
uniapp/uni-admin/src/components/basics/lbMap.vue
Normal file
173
uniapp/uni-admin/src/components/basics/lbMap.vue
Normal file
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="获取经纬度"
|
||||
:visible.sync="centerDialogVisible"
|
||||
width="600px"
|
||||
center
|
||||
:append-to-body="true"
|
||||
>
|
||||
<div class="dialog-inner">
|
||||
<div class="map-search">
|
||||
<el-input placeholder="输入地址" v-model="address"></el-input>
|
||||
<lb-button size="mini" type="primary" @click="searchMapAddr"
|
||||
>搜 索</lb-button
|
||||
>
|
||||
</div>
|
||||
<div id="container"></div>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="centerDialogVisible = false">{{
|
||||
$t('action.cancel')
|
||||
}}</el-button>
|
||||
<el-button type="primary" @click="confirmLatLng">{{
|
||||
$t('action.comfirm')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
dialogVisible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
centerDialogVisible: false,
|
||||
map: null,
|
||||
info: null,
|
||||
address: '',
|
||||
marker: '',
|
||||
geocoder: null,
|
||||
latLng: {
|
||||
lat: 30.657535,
|
||||
lng: 104.065783
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initMap () {
|
||||
let that = this
|
||||
let { lat, lng } = this.latLng
|
||||
// 中心坐标
|
||||
// eslint-disable-next-line no-undef
|
||||
let center = new qq.maps.LatLng(lat, lng)
|
||||
// eslint-disable-next-line no-undef
|
||||
let map = new qq.maps.Map(
|
||||
document.getElementById('container'),
|
||||
{
|
||||
center: center,
|
||||
zoom: 12
|
||||
}
|
||||
)
|
||||
that.map = map
|
||||
// eslint-disable-next-line no-undef
|
||||
that.info = new qq.maps.InfoWindow({
|
||||
map: map
|
||||
})
|
||||
// eslint-disable-next-line no-undef
|
||||
qq.maps.event.addListener(map, 'click', async function (val, el) {
|
||||
if (that.marker) { that.marker.setMap(null) }
|
||||
let { lat, lng } = val.latLng
|
||||
that.latLng = val.latLng
|
||||
// eslint-disable-next-line no-undef
|
||||
that.marker = new qq.maps.Marker({
|
||||
// 标记的位置
|
||||
// eslint-disable-next-line no-undef
|
||||
position: new qq.maps.LatLng(lat, lng),
|
||||
map: map
|
||||
})
|
||||
that.info.open()
|
||||
that.info.setContent(`<div style="margin:10px;">
|
||||
<p>纬度:${lat}</p>
|
||||
<p>经度:${lng}</p>
|
||||
</div>`)
|
||||
// eslint-disable-next-line no-undef
|
||||
that.info.setPosition(new qq.maps.LatLng(lat, lng))
|
||||
})
|
||||
},
|
||||
openQQMap () {
|
||||
setTimeout(() => {
|
||||
this.initMap()
|
||||
this.initGeocoder()
|
||||
}, 500)
|
||||
},
|
||||
/**
|
||||
* @method 根据位置搜索坐标
|
||||
*/
|
||||
searchMapAddr () {
|
||||
let { address } = this
|
||||
this.geocoder.getLocation(address)
|
||||
},
|
||||
initGeocoder () {
|
||||
let that = this
|
||||
// eslint-disable-next-line no-undef
|
||||
that.geocoder = new qq.maps.Geocoder()
|
||||
// 设置服务请求成功的回调函数
|
||||
that.geocoder.setComplete(function (result) {
|
||||
let { lat, lng } = result.detail.location
|
||||
that.latLng = result.detail.location
|
||||
that.map.setCenter(result.detail.location)
|
||||
// eslint-disable-next-line no-undef
|
||||
that.marker = new qq.maps.Marker({
|
||||
map: that.map,
|
||||
position: result.detail.location
|
||||
})
|
||||
that.info.open()
|
||||
that.info.setContent(`<div style="margin:10px;">
|
||||
<p>纬度:${lat}</p>
|
||||
<p>经度:${lng}</p>
|
||||
</div>`)
|
||||
// eslint-disable-next-line no-undef
|
||||
that.info.setPosition(new qq.maps.LatLng(lat, lng))
|
||||
})
|
||||
// 若服务请求失败,则运行以下函数
|
||||
that.geocoder.setError(function () {
|
||||
that.$message.error('请输入包含市级的地址!')
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @method 确定经纬度
|
||||
*/
|
||||
confirmLatLng () {
|
||||
this.centerDialogVisible = false
|
||||
this.$emit('selectedLatLng', this.latLng)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dialogVisible (newValue, oldValue) {
|
||||
if (newValue) {
|
||||
this.centerDialogVisible = true
|
||||
this.openQQMap()
|
||||
}
|
||||
},
|
||||
centerDialogVisible (val) {
|
||||
if (!val) {
|
||||
this.$emit('update:dialogVisible', false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#container {
|
||||
width: 500px;
|
||||
height: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.dialog-inner {
|
||||
.map-search {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
.el-input {
|
||||
width: 300px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
150
uniapp/uni-admin/src/components/basics/lbPage.vue
Normal file
150
uniapp/uni-admin/src/components/basics/lbPage.vue
Normal file
@@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<div class="lb-page">
|
||||
<slot name="button">
|
||||
<!-- 插入按钮 -->
|
||||
</slot>
|
||||
<div v-if="batch">
|
||||
<div :class="[{ isShowBatch: isShowBatch }]">已选 {{ selected }} 条</div>
|
||||
<div>
|
||||
<span v-if="isShowBatch">批量</span>
|
||||
<slot>
|
||||
<!-- 插入按钮 -->
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="slot">
|
||||
<slot>
|
||||
<!-- 插入按钮 -->
|
||||
</slot>
|
||||
</div>
|
||||
<span v-else></span>
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="currentPage"
|
||||
:page-sizes="[5, 10, 20]"
|
||||
:page-size="currentPageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
v-if="isShowPage"
|
||||
>
|
||||
</el-pagination>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
isShowPage: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
isShowBatch: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
batch: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
slot: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
page: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
default: 10
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
selected: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
currentPage: this.page,
|
||||
currentPageSize: this.pageSize
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange (val) {
|
||||
this.currentPageSize = val
|
||||
this.$emit('handleSizeChange', val)
|
||||
},
|
||||
handleCurrentChange (val) {
|
||||
this.currentPage = val
|
||||
this.$emit('handleCurrentChange', val)
|
||||
},
|
||||
// 全选 反选
|
||||
batchUpperAll (type) {
|
||||
if (type === 1) {
|
||||
this.$refs.multipleTable.clearSelection()
|
||||
this.multipleSelection = this.tableData
|
||||
this.tableData.map(item => {
|
||||
this.$refs.multipleTable.toggleRowSelection(item)
|
||||
})
|
||||
} else {
|
||||
let data = JSON.parse(JSON.stringify(this.multipleSelection))
|
||||
let arr = []
|
||||
data.map(item => {
|
||||
arr.push(item.id)
|
||||
})
|
||||
this.$refs.multipleTable.clearSelection()
|
||||
this.multipleSelection = []
|
||||
this.tableData.map(item => {
|
||||
if (!arr.includes(item.id)) {
|
||||
this.multipleSelection.push(item)
|
||||
this.$refs.multipleTable.toggleRowSelection(item)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
page (val) {
|
||||
this.currentPage = val
|
||||
},
|
||||
pageSize (val) {
|
||||
this.currentPageSize = val
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lb-page {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 40px;
|
||||
font-size: 14px;
|
||||
> div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
> div.isShowBatch {
|
||||
border-right: 1px solid #e8e8e8;
|
||||
}
|
||||
> div {
|
||||
&:first-child {
|
||||
height: 40px;
|
||||
padding-right: 30px;
|
||||
margin-right: 30px;
|
||||
line-height: 40px;
|
||||
}
|
||||
.el-button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
109
uniapp/uni-admin/src/components/basics/lbSwitch.vue
Normal file
109
uniapp/uni-admin/src/components/basics/lbSwitch.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<el-switch
|
||||
v-model="val"
|
||||
:disabled='isDisabled'
|
||||
:width='coreWidth'
|
||||
:active-icon-class='activeIconClass'
|
||||
:inactive-icon-class='inactiveIconClass'
|
||||
:active-text='activeText'
|
||||
:inactive-text='inactiveText'
|
||||
:active-value='activeValue'
|
||||
:inactive-value='inactiveValue'
|
||||
:active-color='activeColor'
|
||||
:inactive-color='inactiveColor'
|
||||
:name='name'
|
||||
@change="handleSwitchValue"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props:
|
||||
{
|
||||
opType: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
value: {
|
||||
type: [Boolean, String, Number],
|
||||
default: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 40
|
||||
},
|
||||
activeIconClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
inactiveIconClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
activeText: String,
|
||||
inactiveText: String,
|
||||
activeColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
inactiveColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
activeValue: {
|
||||
type: [Boolean, String, Number],
|
||||
default: true
|
||||
},
|
||||
inactiveValue: {
|
||||
type: [Boolean, String, Number],
|
||||
default: false
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
validateEvent: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
id: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
val: this.value,
|
||||
coreWidth: this.width,
|
||||
isDisabled: this.disabled,
|
||||
currentIndex: this.$store.state.operate.currentIndex
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let {isOnly, auth, pagePermission} = this.$route.meta
|
||||
if (this.opType) {
|
||||
if (isOnly) {
|
||||
this.isDisabled = auth.indexOf(this.opType) === -1
|
||||
} else {
|
||||
this.isDisabled = pagePermission[this.currentIndex].auth.indexOf(this.opType) === -1
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
checked () {
|
||||
return this.value === this.activeValue
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSwitchValue (val) {
|
||||
this.$emit('change', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
62
uniapp/uni-admin/src/components/basics/lbTips.vue
Normal file
62
uniapp/uni-admin/src/components/basics/lbTips.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<!--
|
||||
* @Descripttion: 头部批注
|
||||
* @Author: xiao li
|
||||
* @Date: 2020-07-06 12:17:06
|
||||
* @LastEditors: xiao li
|
||||
* @LastEditTime: 2021-04-15 14:21:09
|
||||
-->
|
||||
<template>
|
||||
<div class="lb-tips" :class="[type]">
|
||||
<i class="iconfont" :class="[icon]" v-if="isIcon"></i>
|
||||
<div class="custom-item">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: 'icon-warn'
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'danger'
|
||||
},
|
||||
isIcon: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lb-tips {
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-left: 5px solid $primaryColor;
|
||||
background: $primaryBgColor;
|
||||
i{
|
||||
color: $primaryColor;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.custom-item{
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.lb-tips.danger {
|
||||
border-left: 5px solid $dangerColor;
|
||||
background: $dangerBgColor;
|
||||
i{
|
||||
color: $dangerColor;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
66
uniapp/uni-admin/src/components/basics/lbToolTips.vue
Normal file
66
uniapp/uni-admin/src/components/basics/lbToolTips.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<!--
|
||||
* @Descripttion: 批注
|
||||
* @Author: xiao li
|
||||
* @Date: 2020-07-06 12:17:06
|
||||
* @LastEditors: xiao li
|
||||
* @LastEditTime: 2021-09-10 16:31:43
|
||||
-->
|
||||
<template>
|
||||
<block>
|
||||
<div class="lb-tool-tips" :class="[type]" v-if="mode === 'text'">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<el-tooltip
|
||||
class="tool-tips"
|
||||
effect="dark"
|
||||
placement="right"
|
||||
:style="{ paddingTop: `${padding}px` }"
|
||||
v-if="mode === 'tooltip'"
|
||||
>
|
||||
<div class="content" slot="content"><slot></slot></div>
|
||||
<i class="el-icon-question"></i>
|
||||
</el-tooltip>
|
||||
</block>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'tooltip'
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'c-caption'
|
||||
},
|
||||
padding: {
|
||||
type: Number,
|
||||
default: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lb-tool-tips {
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.lb-tool-tips.c-link {
|
||||
cursor: pointer;
|
||||
}
|
||||
.tool-tips {
|
||||
margin-left: 5px;
|
||||
vertical-align: top;
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
.content {
|
||||
max-width: 300px;
|
||||
}
|
||||
.el-icon-question {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
355
uniapp/uni-admin/src/components/basics/lbUeditor.vue
Normal file
355
uniapp/uni-admin/src/components/basics/lbUeditor.vue
Normal file
@@ -0,0 +1,355 @@
|
||||
<template>
|
||||
<div>
|
||||
<script ref="script" :name="name" type="text/plain"></script>
|
||||
<lb-upload
|
||||
type="more"
|
||||
:fileType="fileType"
|
||||
:visibles.sync="showDialog"
|
||||
:isIframe="isIframe"
|
||||
multilineType="more"
|
||||
@selectedFiles="getChoiceFiles"
|
||||
></lb-upload>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LoadEvent from '@/utils/Event.js'
|
||||
import Debounce from '@/utils/Debounce.js'
|
||||
import Bus from '@/Bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
name: 'VueUeditorWrap',
|
||||
data () {
|
||||
return {
|
||||
showDialog: false,
|
||||
fileType: 'image',
|
||||
isIframe: false,
|
||||
status: 0,
|
||||
initValue: '',
|
||||
defaultConfig: {
|
||||
// VUE CLI 3 会添加 process.env.BASE_URL 的环境变量,而 VUE CLI 2 没有,所以借此设置 UEDITOR_HOME_URL,能涵盖大部分 Vue 开发者的使用场景
|
||||
UEDITOR_HOME_URL: process.env.NODE_ENV === 'production' ? window.lbConfig.jsPath + 'static/Ueditor/' : '/static/Ueditor/',
|
||||
enableAutoSave: false,
|
||||
// 编辑器不自动被内容撑高
|
||||
autoHeightEnabled: false,
|
||||
// 初始容器高度
|
||||
initialFrameHeight: 500,
|
||||
// 初始容器宽度
|
||||
initialFrameWidth: 'auto',
|
||||
// 上传文件接口(这个地址是我为了方便各位体验文件上传功能搭建的临时接口,请勿在生产环境使用!!!)
|
||||
serverUrl: 'http://35.201.165.105:8000/controller.php',
|
||||
// UEditor 资源文件的存放路径,如果你使用的是 vue-cli 生成的项目,通常不需要设置该选项,vue-ueditor-wrap 会自动处理常见的情况,如果需要特殊配置,参考下方的常见问题2
|
||||
// UEDITOR_HOME_URL: '/static/Ueditor/',
|
||||
zIndex: 5,
|
||||
topOffset: false,
|
||||
autoFloatEnabled: false,
|
||||
toolbars: []
|
||||
},
|
||||
thatUeditor: {}
|
||||
}
|
||||
},
|
||||
props: {
|
||||
// v-model 实现方式
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'observer',
|
||||
validator: function (value) {
|
||||
// 1. observer 借助 MutationObserver API https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver
|
||||
// 2. listener 借助 UEditor 的 contentChange 事件 https://ueditor.baidu.com/doc/#UE.Editor:contentChange
|
||||
return ['observer', 'listener'].indexOf(value) !== -1
|
||||
}
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
init: {
|
||||
type: Function,
|
||||
default: function () {
|
||||
return () => { }
|
||||
}
|
||||
},
|
||||
destroy: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
ueditorType: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
observerDebounceTime: {
|
||||
type: Number,
|
||||
default: 50,
|
||||
validator: function (value) {
|
||||
return value >= 20
|
||||
}
|
||||
},
|
||||
observerOptions: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/MutationObserverInit
|
||||
return {
|
||||
attributes: true, // 是否监听 DOM 元素的属性变化
|
||||
attributeFilter: ['src', 'style', 'type', 'name'], // 只有在该数组中的属性值的变化才会监听
|
||||
characterData: true, // 是否监听文本节点
|
||||
childList: true, // 是否监听子节点
|
||||
subtree: true // 是否监听后代元素
|
||||
}
|
||||
}
|
||||
},
|
||||
// 本组件提供对普通 Vue 项目和 Nuxt 项目开箱即 用的支持,但如果是自己搭建的 Vue SSR 项目,可能需要自行区分是客户端还是服务端环境并跳过环境检测,直接初始化
|
||||
forceInit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
Bus.$on('showLbUpload', (obj) => {
|
||||
console.log(obj)
|
||||
this.thatUeditor = obj.ueditor
|
||||
let { uploadStatus } = this
|
||||
if (uploadStatus) {
|
||||
return false
|
||||
} else {
|
||||
this.showDialog = obj.val
|
||||
this.isIframe = true
|
||||
this.fileType = obj.fileType
|
||||
this.$store.commit('handleUploadStatus', obj.val)
|
||||
}
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
mixedConfig () {
|
||||
return Object.assign({}, this.defaultConfig, this.config)
|
||||
},
|
||||
...mapGetters(['uploadStatus'])
|
||||
},
|
||||
methods: {
|
||||
// 添加自定义按钮(自定义按钮,自定义弹窗等操作从 2.2.0 版本 开始不再考虑直接集成,这会使得组件和 UEditor 过度耦合,但为了兼容一些老版用户的写法,这个方法依然保留)
|
||||
registerButton ({ name, icon, tip, handler, index, UE = window.UE }) {
|
||||
UE.registerUI(name, (editor, name) => {
|
||||
editor.registerCommand(name, {
|
||||
execCommand: () => {
|
||||
handler(editor, name)
|
||||
}
|
||||
})
|
||||
const btn = new UE.ui.Button({
|
||||
name,
|
||||
title: tip,
|
||||
cssRules: `background-image: url(${icon}) !important;background-size: cover;`,
|
||||
onclick () {
|
||||
editor.execCommand(name)
|
||||
}
|
||||
})
|
||||
editor.addListener('selectionchange', () => {
|
||||
const state = editor.queryCommandState(name)
|
||||
if (state === -1) {
|
||||
btn.setDisabled(true)
|
||||
btn.setChecked(false)
|
||||
} else {
|
||||
btn.setDisabled(false)
|
||||
btn.setChecked(state)
|
||||
}
|
||||
})
|
||||
return btn
|
||||
}, index, this.id)
|
||||
},
|
||||
// 实例化编辑器
|
||||
_initEditor () {
|
||||
let toolbars = [
|
||||
'fullscreen', 'source', '|',
|
||||
'undo', 'redo', '|',
|
||||
'bold', 'italic', 'underline', 'strikethrough', 'removeformat', 'formatmatch', 'autotypeset', 'pasteplain', '|',
|
||||
// 'forecolor', 'backcolor', 'insertorderedlist', 'insertunorderedlist', '|',
|
||||
'forecolor', 'backcolor', '|',
|
||||
'fontfamily', 'fontsize', '|',
|
||||
'justifyleft', 'justifycenter', 'justifyright', 'justifyjustify'
|
||||
]
|
||||
let arr = {
|
||||
1: ['|', 'lbinsertimage', 'lbinsertvideo', 'lbinsertmusic'],
|
||||
2: [],
|
||||
3: ['|', 'lbinsertimage']
|
||||
}
|
||||
if (arr[this.ueditorType].length > 0) {
|
||||
arr[this.ueditorType].map(item => {
|
||||
toolbars.push(item)
|
||||
})
|
||||
}
|
||||
this.defaultConfig.toolbars = [toolbars]
|
||||
this.$refs.script.id = this.id = 'editor_' + Math.random().toString(16).slice(-6) // 这么做是为了支持 Vue SSR,因为如果把 id 属性放在 data 里会导致服务端和客户端分别计算该属性的值,而造成 id 不匹配无法初始化的 BUG
|
||||
this.init()
|
||||
this.$emit('beforeInit', this.id, this.mixedConfig)
|
||||
this.editor = window.UE.getEditor(this.id, this.mixedConfig)
|
||||
this.editor.addListener('ready', () => {
|
||||
if (this.status === 2) { // 使用 keep-alive 组件会出现这种情况
|
||||
this.editor.setContent(this.value)
|
||||
} else {
|
||||
this.status = 2
|
||||
this.$emit('ready', this.editor)
|
||||
this.editor.setContent(this.initValue)
|
||||
}
|
||||
if (this.mode === 'observer' && window.MutationObserver) {
|
||||
this._observerChangeListener()
|
||||
} else {
|
||||
this._normalChangeListener()
|
||||
}
|
||||
})
|
||||
},
|
||||
// 检测依赖,确保 UEditor 资源文件已加载完毕
|
||||
_checkDependencies () {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 判断ueditor.config.js和ueditor.all.js是否均已加载(仅加载完ueditor.config.js时UE对象和UEDITOR_CONFIG对象存在,仅加载完ueditor.all.js时UEDITOR_CONFIG对象存在,但为空对象)
|
||||
let scriptsLoaded = !!window.UE && !!window.UEDITOR_CONFIG && Object.keys(window.UEDITOR_CONFIG).length !== 0 && !!window.UE.getEditor
|
||||
if (scriptsLoaded) {
|
||||
resolve()
|
||||
} else if (window['$loadEnv']) { // 利用订阅发布,确保同时渲染多个组件时,不会重复创建script标签
|
||||
window['$loadEnv'].on('scriptsLoaded', () => {
|
||||
resolve()
|
||||
})
|
||||
} else {
|
||||
window['$loadEnv'] = new LoadEvent()
|
||||
// 如果在其他地方只引用ueditor.all.min.js,在加载ueditor.config.js之后仍需要重新加载ueditor.all.min.js,所以必须确保ueditor.config.js已加载
|
||||
this._loadConfig().then(() => this._loadCore()).then(() => {
|
||||
resolve()
|
||||
window['$loadEnv'].emit('scriptsLoaded')
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
_loadConfig () {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (window.UE && window.UEDITOR_CONFIG && Object.keys(window.UEDITOR_CONFIG).length !== 0) {
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
let configScript = document.createElement('script')
|
||||
configScript.type = 'text/javascript'
|
||||
configScript.src = this.mixedConfig.UEDITOR_HOME_URL + 'ueditor.config.js'
|
||||
document.getElementsByTagName('head')[0].appendChild(configScript)
|
||||
configScript.onload = function () {
|
||||
if (window.UE && window.UEDITOR_CONFIG && Object.keys(window.UEDITOR_CONFIG).length !== 0) {
|
||||
resolve()
|
||||
} else {
|
||||
console.warn('加载ueditor.config.js失败,请检查您的配置地址UEDITOR_HOME_URL填写是否正确!\n', configScript.src)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
_loadCore () {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (window.UE && window.UE.getEditor) {
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
let coreScript = document.createElement('script')
|
||||
coreScript.type = 'text/javascript'
|
||||
coreScript.src = this.mixedConfig.UEDITOR_HOME_URL + 'ueditor.all.min.js'
|
||||
document.getElementsByTagName('head')[0].appendChild(coreScript)
|
||||
coreScript.onload = function () {
|
||||
if (window.UE && window.UE.getEditor) {
|
||||
resolve()
|
||||
} else {
|
||||
console.warn('加载ueditor.all.min.js失败,请检查您的配置地址UEDITOR_HOME_URL填写是否正确!\n', coreScript.src)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
// 设置内容
|
||||
_setContent (value) {
|
||||
value === this.editor.getContent() || this.editor.setContent(value)
|
||||
},
|
||||
contentChangeHandler () {
|
||||
this.$emit('input', this.editor.getContent())
|
||||
},
|
||||
// 基于 UEditor 的 contentChange 事件
|
||||
_normalChangeListener () {
|
||||
this.editor.addListener('contentChange', this.contentChangeHandler)
|
||||
},
|
||||
// 基于 MutationObserver API
|
||||
_observerChangeListener () {
|
||||
const changeHandle = (mutationsList) => {
|
||||
if (this.editor.document.getElementById('baidu_pastebin')) {
|
||||
return
|
||||
}
|
||||
this.$emit('input', this.editor.getContent())
|
||||
}
|
||||
// 函数防抖
|
||||
this.observer = new MutationObserver(Debounce(changeHandle, this.observerDebounceTime))
|
||||
this.observer.observe(this.editor.body, this.observerOptions)
|
||||
},
|
||||
getChoiceFiles (files) {
|
||||
console.log(files)
|
||||
for (let i = 0, len = files.length; i < len; i++) {
|
||||
let insetHtml
|
||||
if (files[i].type === 1) {
|
||||
insetHtml = `<img src="${files[i].url}" style="box-sizing: border-box !important; overflow-wrap: break-word !important; visibility: visible !important;"/>`
|
||||
} else if (files[i].type === 2) {
|
||||
insetHtml = `<audio src="${files[i].url}" controls="controls"></audio>`
|
||||
} else if (files[i].type === 3) {
|
||||
insetHtml = `<img width='343' height='220' class='edui-upload-video vjs-default-skin video-js' _url='${files[i].url}' style="background:url(https://lbqny.migugu.com/admin/public/videologo.gif) no-repeat center center; border:1px solid gray;" />`
|
||||
} else if (files[i].type === 5) { // iframe标签
|
||||
insetHtml = files[i].url
|
||||
}
|
||||
this.thatUeditor.execCommand('insertHtml', insetHtml)
|
||||
}
|
||||
}
|
||||
},
|
||||
deactivated () {
|
||||
this.editor && this.editor.removeListener('contentChange', this.contentChangeHandler)
|
||||
this.observer && this.observer.disconnect()
|
||||
},
|
||||
beforeDestroy () {
|
||||
if (this.destroy && this.editor && this.editor.destroy) {
|
||||
this.editor.destroy()
|
||||
}
|
||||
if (this.observer && this.observer.disconnect) {
|
||||
this.observer.disconnect()
|
||||
}
|
||||
this.$store.commit('handleUploadStatus', false)
|
||||
Bus.$off('showLbUpload')
|
||||
},
|
||||
// v-model语法糖实现
|
||||
watch: {
|
||||
value: {
|
||||
handler (value) {
|
||||
// 0: 尚未初始化 1: 开始初始化但尚未ready 2 初始化完成并已ready
|
||||
value = value.replace('font-family: "Microsoft Yahei";', 'font-family: Microsoft Yahei;')
|
||||
switch (this.status) {
|
||||
case 0:
|
||||
this.status = 1
|
||||
this.initValue = value;
|
||||
// 判断执行环境是服务端还是客户端,这里的 process.client 是 Nuxt 添加的环境变量
|
||||
(this.forceInit || (typeof process !== 'undefined' && process.client) || typeof window !== 'undefined') && this._checkDependencies().then(() => {
|
||||
this.$refs.script ? this._initEditor() : this.$nextTick(() => this._initEditor())
|
||||
})
|
||||
break
|
||||
case 1:
|
||||
this.initValue = value
|
||||
break
|
||||
case 2:
|
||||
this._setContent(value)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
showDialog (val) {
|
||||
if (!val) {
|
||||
this.$store.commit('handleUploadStatus', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
1295
uniapp/uni-admin/src/components/basics/lbUpload.vue
Normal file
1295
uniapp/uni-admin/src/components/basics/lbUpload.vue
Normal file
File diff suppressed because it is too large
Load Diff
66
uniapp/uni-admin/src/components/basics/lbUploadCover.vue
Normal file
66
uniapp/uni-admin/src/components/basics/lbUploadCover.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<!--
|
||||
* @Description:
|
||||
* @Author: xiao li
|
||||
* @Date: 2022-06-30 10:06:40
|
||||
* @LastEditTime: 2022-09-07 15:23:24
|
||||
* @LastEditors: xiao li
|
||||
-->
|
||||
<template>
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
action="https://jsonplaceholder.typicode.com/posts/"
|
||||
:show-file-list="false"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
>
|
||||
<lb-image v-if="coverImg" :src="coverImg" class="avatar" />
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['coverImg'],
|
||||
methods: {
|
||||
handleAvatarSuccess (response, file) {
|
||||
let imageUrl = URL.createObjectURL(file.raw)
|
||||
this.$emit('uploadImg', imageUrl)
|
||||
},
|
||||
beforeAvatarUpload (file) {
|
||||
const isLt2M = file.size / 1024 / 1024 < 2
|
||||
if (!isLt2M) {
|
||||
this.$message.error('上传头像图片大小不能超过 2MB!')
|
||||
}
|
||||
return isLt2M
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.avatar-uploader {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
}
|
||||
.avatar-uploader:hover {
|
||||
border-color: #409eff;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
line-height: 128px;
|
||||
text-align: center;
|
||||
}
|
||||
.avatar {
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
99
uniapp/uni-admin/src/components/basics/topNav.vue
Normal file
99
uniapp/uni-admin/src/components/basics/topNav.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div class="lb-top-nav">
|
||||
<div @click="goBack" class="nav-item" v-if="title">
|
||||
<i class="iconfont icon-left" v-if="isBack"></i> {{ title }}
|
||||
</div>
|
||||
<div @click="goBack" class="nav-item" v-else-if="nav.length === 1">
|
||||
<i class="iconfont icon-left" v-if="isBack"></i>
|
||||
{{ $t('menu.' + nav[0].title) }}
|
||||
</div>
|
||||
<router-link
|
||||
v-else-if="nav.length > 1"
|
||||
v-for="(item, index) in nav"
|
||||
tag="div"
|
||||
class="nav-item"
|
||||
:key="index"
|
||||
active-class="nav-item-active"
|
||||
:to="item.url"
|
||||
>
|
||||
{{ $t('menu.' + item.title) }}
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
active: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
isBack: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
activeNav: this.active,
|
||||
nav: []
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let { pagePermission } = this.$route.meta
|
||||
if (pagePermission) {
|
||||
this.nav = pagePermission
|
||||
this.activeNav = this.nav[0].index
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack () {
|
||||
if (!this.isBack) return
|
||||
this.$router.back(-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lb-top-nav {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
border-bottom: 1px solid #e1e1e1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
.nav-item {
|
||||
height: 60px;
|
||||
padding: 0 20px;
|
||||
line-height: 60px;
|
||||
cursor: pointer;
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 0%;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
height: 0px;
|
||||
background: $themeColor;
|
||||
transform: all 0.3 linear;
|
||||
}
|
||||
}
|
||||
.nav-item-active {
|
||||
color: $themeColor;
|
||||
position: relative;
|
||||
&::after {
|
||||
width: 90%;
|
||||
height: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
50
uniapp/uni-admin/src/components/container.vue
Normal file
50
uniapp/uni-admin/src/components/container.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div class="lb-container">
|
||||
<top-nav :nav='nav' @changNav='handleNav'></top-nav>
|
||||
<transition name="fade">
|
||||
<router-view></router-view>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
nav: []
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.nav = this.$route.meta.topMenu || []
|
||||
},
|
||||
methods: {
|
||||
handleNav (index) {}
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
deep: true,
|
||||
handler (val) {
|
||||
this.nav = val.meta.topMenu || []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lb-container{
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
margin-left: 120px;
|
||||
margin-top: 120px;
|
||||
.fade-enter, .fade-leave-to {
|
||||
opacity: 0
|
||||
}
|
||||
.fade-leave, .fade-enter-to {
|
||||
opacity: 1
|
||||
}
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: all .2s
|
||||
}
|
||||
}
|
||||
</style>
|
||||
46
uniapp/uni-admin/src/components/footer.vue
Normal file
46
uniapp/uni-admin/src/components/footer.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<!--
|
||||
* @Descripttion:
|
||||
* @Author: xiao li
|
||||
* @Date: 2020-07-06 12:17:06
|
||||
* @LastEditors: xiao li
|
||||
* @LastEditTime: 2020-12-17 17:22:48
|
||||
-->
|
||||
<!-- 页面底部 -->
|
||||
<template>
|
||||
<div v-html="fHtml" class="lb-footer"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
fHtml: ''
|
||||
}
|
||||
},
|
||||
created () {
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lb-footer{
|
||||
width: 100%;
|
||||
height: 49px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-top: 1px solid #ccc;
|
||||
color: #ccc;
|
||||
font-size: 12px;
|
||||
z-index: 10;
|
||||
background: #fff;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
line-height: 1;
|
||||
}
|
||||
</style>
|
||||
202
uniapp/uni-admin/src/components/header.vue
Normal file
202
uniapp/uni-admin/src/components/header.vue
Normal file
@@ -0,0 +1,202 @@
|
||||
<!-- 页面头部 -->
|
||||
<template>
|
||||
<div class="lb-header">
|
||||
<div class="lb-left">
|
||||
<div class="logo">
|
||||
<!-- <el-image class="logo-img" :src="routesItem.logo" fit="cover" @click="$router.push('/')" ></el-image> -->
|
||||
<div @click="$router.push('/')" class="flex-center logo-img c-base">
|
||||
<img class="flex-center logo-img c-base" :src="banner" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isIndex" class="admin-title"></div>
|
||||
<div v-else class="menu-title">{{ $t('menu.' + title) }}</div>
|
||||
</div>
|
||||
<div class="lb-right">
|
||||
<el-link :underline="false" @click="clearCache" :icon="icon">清除缓存</el-link>
|
||||
<el-dropdown
|
||||
v-if="!isWe7"
|
||||
class="user-name"
|
||||
trigger="click"
|
||||
@command="handleCommand"
|
||||
>
|
||||
<span class="el-dropdown-link">
|
||||
{{ username }}
|
||||
<i class="el-icon-caret-bottom"></i>
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="myaccount">编辑账户</el-dropdown-item>
|
||||
<el-dropdown-item command="loginout">退出登录</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import Bus from '@/Bus.js'
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
isIndex: true,
|
||||
title: '',
|
||||
banner: require('@/./style/image/zhnc.png'),
|
||||
icon: 'el-icon-s-open',
|
||||
notice_list: { data: [] },
|
||||
visible: false,
|
||||
isAdmin: window.lbConfig.isWe7 && window.lbConfig.is_founder,
|
||||
agentUrl: '',
|
||||
username: window.sessionStorage.getItem('ms_username'),
|
||||
isWe7: window.lbConfig.isWe7,
|
||||
dialogVisible: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.handleTitle(this.$route.meta.title)
|
||||
this.handleAgentUrl()
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
routesItem: state => state.routes
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['changeRoutesItem']),
|
||||
// 用户名下拉菜单选择事件
|
||||
handleCommand (command) {
|
||||
if (command === 'myaccount') {
|
||||
this.$emit('handleAccount', true)
|
||||
} else if (command === 'loginout') {
|
||||
// this.$api.userlogout().then(res => {
|
||||
// if (res.code === 200) {
|
||||
this.changeRoutesItem({ key: 'isAuth', val: false })
|
||||
sessionStorage.removeItem('lbtk') // 删除token
|
||||
sessionStorage.removeItem('ms_username')
|
||||
this.$router.push('/login')
|
||||
window.location.reload()
|
||||
// }
|
||||
// })
|
||||
}
|
||||
},
|
||||
clearCache () {
|
||||
this.icon = 'el-icon-loading'
|
||||
this.$api.base.clearCache().then(res => {
|
||||
this.icon = 'el-icon-s-open'
|
||||
if (res.code === 200) {
|
||||
this.$message.success('清除成功!')
|
||||
}
|
||||
})
|
||||
},
|
||||
handleTitle (title) {
|
||||
this.isIndex = !title
|
||||
this.title = title
|
||||
},
|
||||
handleAgentUrl () {
|
||||
let currentUrl = window.location.href
|
||||
let agentUrl = currentUrl.slice(0, currentUrl.indexOf('#')) + '&s=/agent/index'
|
||||
this.agentUrl = agentUrl
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
handler (val, oldVal) {
|
||||
this.handleTitle(val.meta.title)
|
||||
},
|
||||
// 深度观察监听
|
||||
deep: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lb-header {
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
z-index: 10;
|
||||
|
||||
.lb-left {
|
||||
display: flex;
|
||||
height: 71px;
|
||||
background: #1c2c3c;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.logo {
|
||||
width: 120px;
|
||||
height: 70px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.logo-img {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
margin-bottom: 0;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.admin-title {
|
||||
padding: 0 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #ffffff;
|
||||
|
||||
span {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-title {
|
||||
height: 71px !important;
|
||||
width: 140px;
|
||||
border-right: 1px solid #eeeeee;
|
||||
border-bottom: 1px solid #eeeeee;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
color: #666;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.lb-right {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0 30px;
|
||||
cursor: pointer;
|
||||
.notice-item {
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
.el-dropdown-link {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.el-dropdown-menu__item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span {
|
||||
margin: 0 5px 0 20px;
|
||||
}
|
||||
|
||||
.el-link {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
313
uniapp/uni-admin/src/components/layout.vue
Normal file
313
uniapp/uni-admin/src/components/layout.vue
Normal file
@@ -0,0 +1,313 @@
|
||||
<!-- 公共组件 -->
|
||||
<template>
|
||||
<div class="home">
|
||||
<lb-header @handleAccount="handleAccount"></lb-header>
|
||||
<sidebar></sidebar>
|
||||
<div
|
||||
class="container"
|
||||
:style="{
|
||||
'margin-right': adSwitch ? '220px' : '0px',
|
||||
'margin-left': sideBarSwitch ? '260px' : '120px'
|
||||
}"
|
||||
>
|
||||
<!-- 内容区域 -->
|
||||
<div class="main">
|
||||
<transition name="fade" mode="out-in">
|
||||
<keep-alive :max="1">
|
||||
<router-view v-if="$route.meta.keepAlive"></router-view>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
<transition name="fade" mode="out-in">
|
||||
<router-view v-if="!$route.meta.keepAlive"></router-view>
|
||||
</transition>
|
||||
</div>
|
||||
<!-- <div
|
||||
class="home-footer"
|
||||
v-html="fHtml"
|
||||
></div> -->
|
||||
</div>
|
||||
<!-- 右侧展开折叠栏 ad -->
|
||||
<!-- <ad></ad> -->
|
||||
<!-- <lb-footer></lb-footer> -->
|
||||
|
||||
<!-- 编辑账户 -->
|
||||
<el-dialog title="编辑账户" :visible.sync="dialogVisible" width="520px">
|
||||
<el-form
|
||||
@submit.native.prevent
|
||||
:model="accountForm"
|
||||
:rules="accountFormRules"
|
||||
ref="accountForm"
|
||||
label-width="130px"
|
||||
class="basic-form"
|
||||
style="padding-right: 30px"
|
||||
>
|
||||
<el-form-item label="账号" prop="account">
|
||||
<el-input
|
||||
v-model="accountForm.account"
|
||||
:disabled="true"
|
||||
placeholder="账号"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item
|
||||
label="原密码"
|
||||
prop="old_passwd"
|
||||
>
|
||||
<el-input
|
||||
v-model="accountForm.old_passwd"
|
||||
placeholder="请输入原密码"
|
||||
></el-input>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="新密码" prop="new_passwd">
|
||||
<el-input
|
||||
v-model="accountForm.new_passwd"
|
||||
placeholder="请输入新密码"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认新密码" prop="again_passwd">
|
||||
<el-input
|
||||
v-model="accountForm.again_passwd"
|
||||
placeholder="请确认新密码"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm('accountForm')">{{
|
||||
$t('action.submit')
|
||||
}}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import lbHeader from './header'
|
||||
import lbFooter from './footer'
|
||||
import sidebar from './sidebar'
|
||||
import ad from './ad'
|
||||
import { mapGetters, mapState, mapMutations } from 'vuex'
|
||||
export default {
|
||||
name: 'Home',
|
||||
data () {
|
||||
let validatePassword = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error('请输入密码'))
|
||||
} else if (!/^(\S){6,20}$/.test(value)) {
|
||||
callback(new Error('请输入6-20位非空白符的字符!'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
let validateAgainPassword = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error('请再次输入密码'))
|
||||
} else if (value !== this.accountForm.new_passwd) {
|
||||
callback(new Error('两次输入密码不一致'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
return {
|
||||
isChangeRoutes: true,
|
||||
fHtml: '',
|
||||
dialogVisible: false,
|
||||
accountForm: {
|
||||
account: window.sessionStorage.getItem('ms_username'),
|
||||
new_passwd: ''
|
||||
},
|
||||
accountFormRules: {
|
||||
// old_passwd: {
|
||||
// required: true,
|
||||
// type: 'string',
|
||||
// validator: validatePassword,
|
||||
// trigger: 'blur'
|
||||
// },
|
||||
new_passwd: {
|
||||
required: true,
|
||||
type: 'string',
|
||||
validator: validatePassword,
|
||||
trigger: 'blur'
|
||||
},
|
||||
again_passwd: {
|
||||
required: true,
|
||||
type: 'string',
|
||||
validator: validateAgainPassword,
|
||||
trigger: 'blur'
|
||||
}
|
||||
},
|
||||
authForm: {
|
||||
pass: ''
|
||||
},
|
||||
authFormRules: {
|
||||
pass: { required: true, type: 'string', message: '请输入获取到的激活口令', trigger: 'blur' }
|
||||
},
|
||||
modelAuthImg: 'https://lbqny.migugu.com/admin/card/WechatIMG322.jpeg',
|
||||
modelAuthList: {
|
||||
// https://lbqny.migugu.com/weixin/WechatIMG495.jpeg
|
||||
longbing_card: 'https://lbqny.migugu.com/admin/card/WechatIMG322.jpeg',
|
||||
longbing_radarstore: 'https://lbqny.migugu.com/admin/card/WechatIMG322.jpeg',
|
||||
longbing_decorate: 'https://lbqny.migugu.com/admin/card/WechatIMG322.jpeg',
|
||||
longbing_shortvideo: 'https://lbqny.migugu.com/admin/card/WechatIMG322.jpeg',
|
||||
longbing_restaurant: 'https://lbqny.migugu.com/admin/card/WechatIMG322.jpeg',
|
||||
longbing_member: 'https://lbqny.migugu.com/admin/card/WechatIMG322.jpeg'
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
lbHeader,
|
||||
lbFooter,
|
||||
sidebar,
|
||||
ad
|
||||
},
|
||||
created () {
|
||||
this.getCopyrightInfo()
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['adSwitch', 'sideBarSwitch']),
|
||||
...mapState({
|
||||
routesItem: state => state.routes
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['changeIsShowPrompt', 'changeRoutesItem']),
|
||||
handleAccount (flag) {
|
||||
this.dialogVisible = flag
|
||||
},
|
||||
submitForm (name) {
|
||||
this.$refs[name].validate(valid => {
|
||||
if (valid) {
|
||||
let {
|
||||
new_passwd: pass
|
||||
} = JSON.parse(JSON.stringify(this.accountForm))
|
||||
this.$api.base.updatePasswd({
|
||||
pass
|
||||
}).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success(this.$t('tips.successRev'))
|
||||
sessionStorage.removeItem('lbtk') // 删除token
|
||||
sessionStorage.removeItem('ms_username') // 删除用户名
|
||||
this.$router.push('/login')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
submitAuthForm (name) {
|
||||
this.$refs[name].validate(valid => {
|
||||
if (valid) {
|
||||
let { pass } = this.authForm
|
||||
this.$api.baseGiveAuth({
|
||||
pass
|
||||
}).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success(this.$t('tips.successSub'))
|
||||
this.changeRoutesItem({ key: 'isFreeAuth', val: false })
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
getCopyrightInfo () {
|
||||
let { systemCopyInfo } = this.routesItem
|
||||
if (systemCopyInfo === 1) {
|
||||
this.fHtml = ''
|
||||
} else {
|
||||
if (!systemCopyInfo.footerleft) {
|
||||
this.fHtml =
|
||||
`<div>Powered by <a class='el-link el-link--info' href="http://www.we7.cc"><b>微擎</b></a>
|
||||
v${systemCopyInfo.version} © 2014-2015
|
||||
<a class='el-link el-link--info' href="http://www.we7.cc">www.we7.cc</a></div>`
|
||||
} else {
|
||||
this.fHtml = systemCopyInfo.footerleft
|
||||
}
|
||||
if (systemCopyInfo.icp) {
|
||||
this.fHtml = this.fHtml +
|
||||
`<div>备案号:<a class='el-link el-link--info' href="http://www.miitbeian.gov.cn" target="_blank">${systemCopyInfo.icp}</a></div>`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.home {
|
||||
border: 1px solid transparent;
|
||||
background: #f0f0f0;
|
||||
|
||||
.container {
|
||||
margin: 70px 0 0 140px;
|
||||
padding: 20px;
|
||||
background: $bgThemeColor;
|
||||
transition: margin 0.2s linear;
|
||||
|
||||
.main {
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
min-height: calc(100vh - 70px - 92px);
|
||||
}
|
||||
|
||||
.home-footer {
|
||||
height: 49px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #ccc;
|
||||
font-size: 12px;
|
||||
z-index: 10;
|
||||
margin: 0 auto;
|
||||
line-height: 1;
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fade-transform-leave-active,
|
||||
.fade-transform-enter-active {
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.fade-transform-enter {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
|
||||
.fade-transform-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
|
||||
.slide-fade-enter-active {
|
||||
transition: all 2s ease;
|
||||
}
|
||||
|
||||
.slide-fade-leave-active {
|
||||
transition: all 0s ease;
|
||||
}
|
||||
|
||||
.slide-fade-enter,
|
||||
.slide-fade-leave-to {
|
||||
transform: translateX(20px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.fade-leave,
|
||||
.fade-enter-to {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
61
uniapp/uni-admin/src/components/prompt.vue
Normal file
61
uniapp/uni-admin/src/components/prompt.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<el-dialog :visible.sync="isShowPrompt" center :before-close="close">
|
||||
<el-form>
|
||||
<div solt="title" class="titleFont">服务到期通知</div>
|
||||
<div class="delog">
|
||||
<div>你开通的套餐{{promptData.status!==1?'已于':''}} {{ promptData.time }} {{promptData.status===1?'即将':''}}到期,请联系所属运营商续费后使用</div>
|
||||
<div>感谢对我们工作的理解与支持。</div>
|
||||
<el-button type="primary" size="small" class="pad" @click="close">我知道了</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
export default {
|
||||
// props:{
|
||||
// isShow:String
|
||||
// },
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
created () {},
|
||||
computed: {
|
||||
...mapState({
|
||||
promptData: state => state.routes.promptData,
|
||||
isShowPrompt: state => state.routes.isShowPrompt
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['changeIsShowPrompt']),
|
||||
close () {
|
||||
this.changeIsShowPrompt(false)
|
||||
},
|
||||
handleClose (done) {
|
||||
this.$confirm('确认关闭?')
|
||||
.then(_ => {
|
||||
this.changeIsShowPrompt(false)
|
||||
})
|
||||
.catch(_ => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.delog {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.titleFont {
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
}
|
||||
.pad {
|
||||
margin-top: 100px;
|
||||
}
|
||||
</style>
|
||||
274
uniapp/uni-admin/src/components/sidebar.vue
Normal file
274
uniapp/uni-admin/src/components/sidebar.vue
Normal file
@@ -0,0 +1,274 @@
|
||||
<!-- 右侧边栏 -->
|
||||
<template>
|
||||
<div class="lb-sidebar">
|
||||
<div class="menu">
|
||||
<vue-scroll :ops="ops">
|
||||
<ul class="menu-top" @click="showDialog">
|
||||
<router-link
|
||||
v-for="(item, index) in routes"
|
||||
tag="li"
|
||||
:key="index"
|
||||
active-class="menu-active"
|
||||
:to="item.path"
|
||||
:style="{ marginTop: item.meta.menuName === 'diy' ? '50px' : '0' }"
|
||||
v-show="!item.isHidden"
|
||||
>
|
||||
<i
|
||||
v-if="item.meta.icon"
|
||||
class="iconfont"
|
||||
:class="item.meta.icon"
|
||||
></i>
|
||||
<img v-else :src="item.meta.img" />
|
||||
{{ $t('menu.' + item.meta.menuName) }}
|
||||
</router-link>
|
||||
</ul>
|
||||
</vue-scroll>
|
||||
</div>
|
||||
<div :class="subnav.length > 0 ? 'isopen' : ''" class="submenu">
|
||||
<vue-scroll :ops="ops">
|
||||
<el-collapse
|
||||
v-for="(item, index) in subnav"
|
||||
:key="index"
|
||||
v-model="activeNames"
|
||||
>
|
||||
<div :title="$t('menu.' + item.name)" :name="index">
|
||||
<div class="item" v-for="(items, indexs) in item.url" :key="indexs">
|
||||
<router-link
|
||||
tag="span"
|
||||
active-class="el-collapse-item-active"
|
||||
:to="items.url"
|
||||
>{{ $t('menu.' + items.name) }}</router-link
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</el-collapse>
|
||||
</vue-scroll>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations, mapState } from 'vuex'
|
||||
import vuescroll from 'vuescroll'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
isFirst: true,
|
||||
routes: [], // 路由表
|
||||
subnav: [], // 二级菜单表
|
||||
activeNames: [], // 二级菜单展开的配置
|
||||
ops: {
|
||||
vuescroll: {
|
||||
wheelScrollDuration: 600
|
||||
},
|
||||
scrollPanel: {
|
||||
initialScrollY: false,
|
||||
initialScrollX: false,
|
||||
scrollingX: true,
|
||||
scrollingY: true,
|
||||
speed: 1000,
|
||||
easing: undefined,
|
||||
verticalNativeBarPos: 'right'
|
||||
},
|
||||
rail: {},
|
||||
bar: {
|
||||
showDelay: 500,
|
||||
onlyShowBarOnScroll: true,
|
||||
keepShow: false,
|
||||
background: '#c1c1c1',
|
||||
opacity: 0.5,
|
||||
hoverStyle: false,
|
||||
specifyBorderRadius: false,
|
||||
minSize: false,
|
||||
size: '6px',
|
||||
disable: false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
promptData: state => state.routes.promptData
|
||||
})
|
||||
},
|
||||
components: {
|
||||
vuescroll
|
||||
},
|
||||
created () {
|
||||
this.handleRoute()
|
||||
this.handleSubnav(this.$route.name)
|
||||
},
|
||||
methods: {
|
||||
...mapMutations([]),
|
||||
showDialog () {
|
||||
},
|
||||
/**
|
||||
* @method 处理路由表,渲染到侧边栏
|
||||
*/
|
||||
handleRoute () {
|
||||
let { routes } = this.$store.getters // JSON.parse(localStorage.getItem('routes'))
|
||||
// console.log(routes)
|
||||
this.routes = routes.filter(item => {
|
||||
if (!item.hidden) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @method 处理二级菜单导航
|
||||
*/
|
||||
handleSubnav (name) {
|
||||
let { routes } = this
|
||||
// console.log(routes)
|
||||
for (let i = 0, len = routes.length; i < len; i++) {
|
||||
let children = routes[i].children
|
||||
for (let j = 0, l = children.length; j < l; j++) {
|
||||
if (children[j].name === name) {
|
||||
this.subnav = routes[i].meta.subNavName || []
|
||||
this.$store.commit('handleSideBarSwitch', this.subnav.length > 0)
|
||||
this.openSubnav()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @method 展开二级菜单
|
||||
*/
|
||||
openSubnav () {
|
||||
let arr = []
|
||||
this.subnav.forEach((item, index) => {
|
||||
arr.push(index)
|
||||
})
|
||||
this.activeNames = arr
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
handler (val, oldVal) {
|
||||
this.handleSubnav(val.name)
|
||||
},
|
||||
// 深度观察监听
|
||||
deep: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lb-sidebar {
|
||||
position: fixed;
|
||||
top: 70px;
|
||||
left: 0;
|
||||
display: flex;
|
||||
height: calc(100% - 70px);
|
||||
z-index: 2;
|
||||
.menu {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
width: 120px;
|
||||
height: 100%;
|
||||
background: #1c2c3c;
|
||||
z-index: 3;
|
||||
.menu-top {
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
li {
|
||||
width: 100%;
|
||||
min-height: 50px;
|
||||
padding: 15px 8px;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
i {
|
||||
margin-right: 10px;
|
||||
}
|
||||
img {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
&:hover {
|
||||
color: #fff;
|
||||
background-color: #26394b;
|
||||
}
|
||||
}
|
||||
.menu-active {
|
||||
background: #2d8cf0;
|
||||
color: #fff;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.submenu {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 120px;
|
||||
z-index: 2;
|
||||
width: 139px;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
display: none;
|
||||
transition: all 0.2s linear;
|
||||
.el-collapse {
|
||||
margin: 0 auto;
|
||||
border-top: 1px;
|
||||
.item {
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
span {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
line-height: 45px;
|
||||
}
|
||||
&:hover {
|
||||
span {
|
||||
background-color: #f5faff;
|
||||
color: #2d8cf0;
|
||||
}
|
||||
.el-collapse-item-active {
|
||||
color: #2d8cf0;
|
||||
}
|
||||
}
|
||||
.el-collapse-item-active {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
background: #c9e9ff;
|
||||
border-radius: 2px;
|
||||
text-align: center;
|
||||
color: #2d8cf0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.el-collapse-item-active:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 2px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: #2d8cf0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.isopen {
|
||||
width: 139px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user