jeecg-boot 1.0版本发布 | 企业级快速开发平台
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<a-breadcrumb class="breadcrumb">
|
||||
<a-breadcrumb-item v-for="(item, index) in breadList" :key="index">
|
||||
<router-link v-if="item.name != name" :to="{ path: item.path }">
|
||||
{{ item.meta.title }}
|
||||
</router-link>
|
||||
<span v-else>{{ item.meta.title }}</span>
|
||||
</a-breadcrumb-item>
|
||||
</a-breadcrumb>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
breadList: [],
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getBreadcrumb()
|
||||
},
|
||||
methods: {
|
||||
getBreadcrumb() {
|
||||
|
||||
console.log('this.$route.matched', this.$route.matched)
|
||||
|
||||
this.breadList = []
|
||||
this.breadList.push({ name: 'dashboard', path: '/dashboard/', meta: { title: '首页' } })
|
||||
|
||||
this.name = this.$route.name
|
||||
this.$route.matched.forEach((item) => {
|
||||
// item.meta.name === 'dashboard' ? item.path = '/dashboard' : this.$route.path === item.path
|
||||
this.breadList.push(item)
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.getBreadcrumb()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div :class="['detail-list', size, layout === 'vertical' ? 'vertical': 'horizontal']">
|
||||
<div v-if="title" class="title">{{ title }}</div>
|
||||
<a-row>
|
||||
<slot></slot>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Col } from 'ant-design-vue/es/grid/'
|
||||
|
||||
const Item = {
|
||||
name: 'DetailListItem',
|
||||
props: {
|
||||
term: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: false
|
||||
},
|
||||
},
|
||||
inject: {
|
||||
col: {
|
||||
type: Number
|
||||
}
|
||||
},
|
||||
render () {
|
||||
return (
|
||||
<Col {...{props: responsive[this.col]}}>
|
||||
<div class="term">{this.$props.term}</div>
|
||||
<div class="content">{this.$slots.default}</div>
|
||||
</Col>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const responsive = {
|
||||
1: { xs: 24 },
|
||||
2: { xs: 24, sm: 12 },
|
||||
3: { xs: 24, sm: 12, md: 8 },
|
||||
4: { xs: 24, sm: 12, md: 6 }
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "DetailList",
|
||||
Item: Item,
|
||||
components: {
|
||||
Col
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: false
|
||||
},
|
||||
col: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 3
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'large'
|
||||
},
|
||||
layout: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'horizontal'
|
||||
}
|
||||
},
|
||||
provide () {
|
||||
return {
|
||||
col: this.col > 4 ? 4 : this.col
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.detail-list {
|
||||
|
||||
.title {
|
||||
color: rgba(0,0,0,.85);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.term {
|
||||
color: rgba(0,0,0,.85);
|
||||
display: table-cell;
|
||||
line-height: 20px;
|
||||
margin-right: 8px;
|
||||
padding-bottom: 16px;
|
||||
white-space: nowrap;
|
||||
|
||||
&:after {
|
||||
content: ":";
|
||||
margin: 0 8px 0 2px;
|
||||
position: relative;
|
||||
top: -.5px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
color: rgba(0,0,0,.65);
|
||||
display: table-cell;
|
||||
line-height: 22px;
|
||||
padding-bottom: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.small {
|
||||
|
||||
.title {
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, .65);
|
||||
font-weight: normal;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.term, .content {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&.large {
|
||||
.term, .content {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&.vertical {
|
||||
.term {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.term, .content {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div class="toolbar">
|
||||
<div style="float: left">
|
||||
<slot name="extra"></slot>
|
||||
</div>
|
||||
<div style="float: right">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "FooterToolBar"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.toolbar {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
height: 56px;
|
||||
line-height: 56px;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.03);
|
||||
background: #fff;
|
||||
border-top: 1px solid #e8e8e8;
|
||||
padding: 0 24px;
|
||||
z-index: 9;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="head-info" :class="center && 'center'">
|
||||
<span>{{ title }}</span>
|
||||
<p>{{ content }}</p>
|
||||
<em v-if="bordered"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "HeadInfo",
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
center: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.head-info {
|
||||
position: relative;
|
||||
text-align: left;
|
||||
padding: 0 32px 0 0;
|
||||
min-width: 125px;
|
||||
|
||||
&.center {
|
||||
text-align: center;
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: rgba(0, 0, 0, .45);
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
p {
|
||||
color: rgba(0, 0, 0, .85);
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
margin: 0;
|
||||
}
|
||||
em {
|
||||
background-color: #e8e8e8;
|
||||
position: absolute;
|
||||
height: 56px;
|
||||
width: 1px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<a-popover
|
||||
trigger="click"
|
||||
placement="bottomRight"
|
||||
:autoAdjustOverflow="true"
|
||||
:arrowPointAtCenter="true"
|
||||
overlayClassName="header-notice-wrapper"
|
||||
:overlayStyle="{ width: '300px', top: '50px' }">
|
||||
<template slot="content">
|
||||
<a-spin :spinning="loadding">
|
||||
<a-tabs>
|
||||
<a-tab-pane tab="通知" key="1">
|
||||
<a-list>
|
||||
<a-list-item>
|
||||
<a-list-item-meta title="你收到了 14 份新周报" description="一年前">
|
||||
<a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"/>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<a-list-item-meta title="你推荐的 曲妮妮 已通过第三轮面试" description="一年前">
|
||||
<a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png"/>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<a-list-item-meta title="这种模板可以区分多种通知类型" description="一年前">
|
||||
<a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png"/>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="消息" key="2">
|
||||
123
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="待办" key="3">
|
||||
123
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-spin>
|
||||
</template>
|
||||
<span @click="fetchNotice" class="header-notice">
|
||||
<a-badge count="12">
|
||||
<a-icon style="font-size: 16px; padding: 4px" type="bell" />
|
||||
</a-badge>
|
||||
</span>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "HeaderNotice",
|
||||
data () {
|
||||
return {
|
||||
loadding: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchNotice () {
|
||||
if (this.loadding) {
|
||||
this.loadding = false
|
||||
return
|
||||
}
|
||||
this.loadding = true
|
||||
setTimeout(() => {
|
||||
this.loadding = false
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css">
|
||||
.header-notice-wrapper {
|
||||
top: 50px !important;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.header-notice{
|
||||
display: inline-block;
|
||||
transition: all 0.3s;
|
||||
|
||||
span {
|
||||
vertical-align: initial;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div class="logo">
|
||||
<router-link :to="{name:'dashboard'}">
|
||||
<img src="~@/assets/logo.svg" alt="logo">
|
||||
<h1 v-if="showTitle">{{ title }}</h1>
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Logo",
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Jeecg-Boot Pro',
|
||||
required: false
|
||||
},
|
||||
showTitle: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
required: false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/*缩小首页布 局顶部的高度*/
|
||||
.sider .logo {
|
||||
height: 59px!important;
|
||||
line-height: 59px!important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<!-- 两步验证 -->
|
||||
<a-modal
|
||||
centered
|
||||
v-model="visible"
|
||||
@cancel="handleCancel"
|
||||
:maskClosable="false"
|
||||
>
|
||||
<div slot="title" :style="{ textAlign: 'center' }">两步验证</div>
|
||||
<template slot="footer">
|
||||
<div :style="{ textAlign: 'center' }">
|
||||
<a-button key="back" @click="handleCancel">返回</a-button>
|
||||
<a-button key="submit" type="primary" :loading="stepLoading" @click="handleStepOk">
|
||||
继续
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<a-spin :spinning="stepLoading">
|
||||
<a-form layout="vertical" :auto-form-create="(form)=>{this.form = form}">
|
||||
<div class="step-form-wrapper">
|
||||
<p style="text-align: center" v-if="!stepLoading">请在手机中打开 Google Authenticator 或两步验证 APP<br />输入 6 位动态码</p>
|
||||
<p style="text-align: center" v-else>正在验证..<br/>请稍后</p>
|
||||
<a-form-item
|
||||
:style="{ textAlign: 'center' }"
|
||||
hasFeedback
|
||||
fieldDecoratorId="stepCode"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: '请输入 6 位动态码!', pattern: /^\d{6}$/, len: 6 }]}"
|
||||
>
|
||||
<a-input :style="{ textAlign: 'center' }" @keyup.enter.native="handleStepOk" placeholder="000000" />
|
||||
</a-form-item>
|
||||
<p style="text-align: center">
|
||||
<a @click="onForgeStepCode">遗失手机?</a>
|
||||
</p>
|
||||
</div>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
stepLoading: false,
|
||||
|
||||
form: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleStepOk() {
|
||||
const vm = this
|
||||
this.stepLoading = true
|
||||
this.form.validateFields((err, values) => {
|
||||
if (!err) {
|
||||
console.log('values', values)
|
||||
setTimeout( () => {
|
||||
vm.stepLoading = false
|
||||
vm.$emit('success', { values })
|
||||
}, 2000)
|
||||
return;
|
||||
}
|
||||
this.stepLoading = false
|
||||
this.$emit('error', { err })
|
||||
})
|
||||
},
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.$emit('cancel')
|
||||
},
|
||||
onForgeStepCode() {
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.step-form-wrapper {
|
||||
margin: 0 auto;
|
||||
width: 80%;
|
||||
max-width: 400px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div class="user-wrapper">
|
||||
<span class="action">
|
||||
<a-icon type="question-circle-o"></a-icon>
|
||||
</span>
|
||||
<header-notice class="action"/>
|
||||
<a-dropdown>
|
||||
<span class="action ant-dropdown-link user-dropdown-menu">
|
||||
<a-avatar class="avatar" size="small" :src="getAvatar()"/>
|
||||
<span>欢迎您,{{ nickname() }}</span>
|
||||
</span>
|
||||
<a-menu slot="overlay" class="user-dropdown-menu-wrapper">
|
||||
<a-menu-item key="0">
|
||||
<router-link :to="{ name: 'account-center' }">
|
||||
<a-icon type="user"/>
|
||||
<span>个人中心</span>
|
||||
</router-link>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="1">
|
||||
<router-link :to="{ name: 'account-settings' }">
|
||||
<a-icon type="setting"/>
|
||||
<span>账户设置</span>
|
||||
</router-link>
|
||||
</a-menu-item>
|
||||
<!-- <a-menu-item key="2" disabled>
|
||||
<a-icon type="setting"/>
|
||||
<span>测试</span>
|
||||
</a-menu-item>
|
||||
<a-menu-divider/>
|
||||
<a-menu-item key="3">
|
||||
<a href="javascript:;" @click="handleLogout">
|
||||
<a-icon type="logout"/>
|
||||
<span>退出登录</span>
|
||||
</a>
|
||||
</a-menu-item>-->
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
<span class="action">
|
||||
<a class="logout_title" href="javascript:;" @click="handleLogout">
|
||||
<a-icon type="logout"/>
|
||||
<span> 退出登录</span>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HeaderNotice from './HeaderNotice'
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
import {imgView} from '@/api/api'
|
||||
|
||||
export default {
|
||||
name: "UserMenu",
|
||||
components: {
|
||||
HeaderNotice
|
||||
},
|
||||
methods: {
|
||||
...mapActions(["Logout"]),
|
||||
...mapGetters(["nickname", "avatar"]),
|
||||
getAvatar(){
|
||||
console.log('url = '+ imgView+this.avatar())
|
||||
return imgView+this.avatar()
|
||||
},
|
||||
handleLogout() {
|
||||
const that = this
|
||||
|
||||
this.$confirm({
|
||||
title: '提示',
|
||||
content: '真的要注销登录吗 ?',
|
||||
onOk() {
|
||||
return that.Logout({}).then(() => {
|
||||
window.location.reload()
|
||||
}).catch(err => {
|
||||
that.$message.error({
|
||||
title: '错误',
|
||||
description: err.message
|
||||
})
|
||||
})
|
||||
},
|
||||
onCancel() {
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.logout_title{
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
text-decoration:none;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,95 @@
|
||||
import { message } from 'ant-design-vue/es';
|
||||
// import defaultSettings from '../defaultSettings';
|
||||
|
||||
let lessNodesAppended;
|
||||
|
||||
const colorList = [
|
||||
{
|
||||
key: '薄暮', color: '#F5222D',
|
||||
},
|
||||
{
|
||||
key: '火山', color: '#FA541C',
|
||||
},
|
||||
{
|
||||
key: '日暮', color: '#FAAD14',
|
||||
},
|
||||
{
|
||||
key: '明青', color: '#13C2C2',
|
||||
},
|
||||
{
|
||||
key: '极光绿', color: '#52C41A',
|
||||
},
|
||||
{
|
||||
key: '拂晓蓝(默认)', color: '#1890FF',
|
||||
},
|
||||
{
|
||||
key: '极客蓝', color: '#2F54EB',
|
||||
},
|
||||
{
|
||||
key: '酱紫', color: '#722ED1',
|
||||
},
|
||||
];
|
||||
|
||||
const updateTheme = primaryColor => {
|
||||
// Don't compile less in production!
|
||||
/* if (process.env.NODE_ENV === 'production') {
|
||||
return;
|
||||
} */
|
||||
// Determine if the component is remounted
|
||||
if (!primaryColor) {
|
||||
return;
|
||||
}
|
||||
const hideMessage = message.loading('正在编译主题!', 0);
|
||||
function buildIt() {
|
||||
if (!window.less) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
window.less
|
||||
.modifyVars({
|
||||
'@primary-color': primaryColor,
|
||||
})
|
||||
.then(() => {
|
||||
hideMessage();
|
||||
})
|
||||
.catch(() => {
|
||||
message.error('Failed to update theme');
|
||||
hideMessage();
|
||||
});
|
||||
}, 200);
|
||||
}
|
||||
if (!lessNodesAppended) {
|
||||
// insert less.js and color.less
|
||||
const lessStyleNode = document.createElement('link');
|
||||
const lessConfigNode = document.createElement('script');
|
||||
const lessScriptNode = document.createElement('script');
|
||||
lessStyleNode.setAttribute('rel', 'stylesheet/less');
|
||||
lessStyleNode.setAttribute('href', '/color.less');
|
||||
lessConfigNode.innerHTML = `
|
||||
window.less = {
|
||||
async: true,
|
||||
env: 'production',
|
||||
javascriptEnabled: true
|
||||
};
|
||||
`;
|
||||
lessScriptNode.src = 'https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js';
|
||||
lessScriptNode.async = true;
|
||||
lessScriptNode.onload = () => {
|
||||
buildIt();
|
||||
lessScriptNode.onload = null;
|
||||
};
|
||||
document.body.appendChild(lessStyleNode);
|
||||
document.body.appendChild(lessConfigNode);
|
||||
document.body.appendChild(lessScriptNode);
|
||||
lessNodesAppended = true;
|
||||
} else {
|
||||
buildIt();
|
||||
}
|
||||
};
|
||||
|
||||
const updateColorWeak = colorWeak => {
|
||||
// document.body.className = colorWeak ? 'colorWeak' : '';
|
||||
colorWeak ? document.body.classList.add('colorWeak') : document.body.classList.remove('colorWeak')
|
||||
};
|
||||
|
||||
export { updateTheme, colorList, updateColorWeak }
|
||||
Reference in New Issue
Block a user