update 进行了一系列优化

This commit is contained in:
2021-04-26 21:02:54 +08:00
parent 460aa3f3d9
commit 748e890b55
15 changed files with 344 additions and 86 deletions

View File

@@ -22,6 +22,7 @@
@import './lib/description.less'; @import './lib/description.less';
@import './lib/select.less'; @import './lib/select.less';
@import './lib/dropdown.less'; @import './lib/dropdown.less';
@import './lib/modal.less';
@import './lib/tree-layout.less'; @import './lib/tree-layout.less';
@import './lib/authority-view.less'; @import './lib/authority-view.less';
@import './lib/icon-selector.less'; @import './lib/icon-selector.less';

View File

@@ -0,0 +1,33 @@
@import (reference) '~@/assets/style/extend.less';
.ant-modal-content {
background-color: fade(@primary-color, 20%);
backdrop-filter: blur(10px);
}
.ant-modal-header {
padding: @padding-sm @padding-md;
background-color: transparent;
}
.ant-modal-title {
color: fade(@white, 85%);
}
.ant-modal-body {
background-color: @white;
}
.ant-modal-footer {
background-color: @white;
}
.ant-modal-close {
color: fade(@white, 45%);
&:focus,
&:hover {
color: fade(@white, 75%);
}
}
.ant-modal-close-x {
line-height: 46px;
width: 46px;
height: 46px;
}

View File

@@ -1,3 +1,7 @@
import Swiper from 'swiper'
let timer, swiper
export default { export default {
props: { props: {
loadData: { loadData: {
@@ -20,6 +24,7 @@ export default {
searchValue: '', searchValue: '',
selectedKeys: [],
expandedKeys: [], expandedKeys: [],
autoExpandParent: true autoExpandParent: true
} }
@@ -29,7 +34,64 @@ export default {
this.onLoadData() this.onLoadData()
}, },
mounted() {
const container = this.$refs.swiper,
scrollBar = container.querySelector('.swiper-scrollbar')
const swiperOptions = {
direction: 'vertical',
slidesPerView: 'auto',
freeMode: true,
scrollbar: {
el: scrollBar,
},
mousewheel: true,
}
swiper = new Swiper(container, swiperOptions)
window.addEventListener('resize', () => {
this.onUpdateSwiper()
})
},
methods: { methods: {
renderBreadcrumbItem() {
const path = ['顶级']
const findPath = (data, level) => {
level = level || 1
for (let i = 0; i < data.length; i++) {
const item = data[i]
path[level] = item.title
if (item.id === this.selectedKeys[0]) {
path.length = level + 1
return true
}
if (item.children && item.children.length) {
const found = findPath(item.children, level + 1)
if (found) {
return true
}
}
}
}
if (this.selectedKeys.length) {
findPath(this.data)
}
return path.map(p => (
<a-breadcrumb-item>{p}</a-breadcrumb-item>
))
},
onLoadData() { onLoadData() {
this.loading = true this.loading = true
@@ -42,6 +104,10 @@ export default {
} }
this.data = data this.data = data
this.$nextTick(() => {
this.onUpdateSwiper()
})
this.loading = false this.loading = false
}) })
}, },
@@ -51,8 +117,9 @@ export default {
}, },
onExpand(expandedKeys) { onExpand(expandedKeys) {
this.expandedKeys = expandedKeys; this.expandedKeys = expandedKeys
this.autoExpandParent = false; this.autoExpandParent = false
this.onUpdateSwiper()
}, },
onSearch(value) { onSearch(value) {
@@ -77,9 +144,18 @@ export default {
const data = this.list.find(m => m.key === p) const data = this.list.find(m => m.key === p)
selectedIds.push(data.id) selectedIds.push(data.id)
}) })
this.selectedKeys = selectedIds
this.$emit('select', selectedIds) this.$emit('select', selectedIds)
}, },
onUpdateSwiper() {
clearTimeout(timer)
timer = setTimeout(() => {
swiper.update()
swiper.update()
}, 300)
},
generateKey(data, level) { generateKey(data, level) {
const n = level || [0] const n = level || [0]
n.push(0) n.push(0)
@@ -98,9 +174,9 @@ export default {
// 这里获取不到Key // 这里获取不到Key
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
const { key, id, title, children } = data[i] const { key, id, title, children } = data[i]
this.list.push({ key, id, title }); this.list.push({ key, id, title })
if (children) { if (children) {
this.generateList(children); this.generateList(children)
} }
} }
}, },
@@ -108,12 +184,12 @@ export default {
getParentKey(key, tree) { getParentKey(key, tree) {
let parentKey; let parentKey;
for (let i = 0; i < tree.length; i++) { for (let i = 0; i < tree.length; i++) {
const node = tree[i]; const node = tree[i]
if (node.children) { if (node.children) {
if (node.children.some(item => item.key === key)) { if (node.children.some(item => item.key === key)) {
parentKey = node.key; parentKey = node.key
} else if (this.getParentKey(key, node.children)) { } else if (this.getParentKey(key, node.children)) {
parentKey = this.getParentKey(key, node.children); parentKey = this.getParentKey(key, node.children)
} }
} }
} }
@@ -123,14 +199,6 @@ export default {
render() { render() {
const swiperOptions = {
direction: 'vertical',
slidesPerView: 'auto',
freeMode: true,
scrollbar: true,
mousewheel: true,
}
const props = { const props = {
treeData: this.data, treeData: this.data,
expandedKeys: this.expandedKeys, expandedKeys: this.expandedKeys,
@@ -170,16 +238,24 @@ export default {
<a-input-search allowClear={true} placeholder="请输入检索关键字" onSearch={this.onSearch} /> <a-input-search allowClear={true} placeholder="请输入检索关键字" onSearch={this.onSearch} />
</div> </div>
</a-layout-header> </a-layout-header>
<swiper options={swiperOptions}> <div class="swiper-container" ref="swiper">
<a-spin style={{ height: '100%' }} spinning={this.loading}> <div class="swiper-wrapper">
<a-icon slot="indicator" type="loading" spin /> <div class="swiper-slide">
<swiper-slide> <a-spin style={{ height: '100%' }} spinning={this.loading}>
<a-tree {...{ props, on, scopedSlots }} /> <a-icon slot="indicator" type="loading" spin />
</swiper-slide> <a-tree {...{ props, on, scopedSlots }} />
</a-spin> </a-spin>
</swiper> </div>
</div>
<div class="swiper-scrollbar" />
</div>
</a-layout-sider> </a-layout-sider>
<a-layout-content> <a-layout-content>
<container>
<a-breadcrumb class="mt-md mb-md">
{this.renderBreadcrumbItem()}
</a-breadcrumb>
</container>
{this.$scopedSlots.default ? this.$scopedSlots.default() : null} {this.$scopedSlots.default ? this.$scopedSlots.default() : null}
</a-layout-content> </a-layout-content>
</a-layout> </a-layout>

View File

@@ -13,9 +13,7 @@ Vue.use(Antd)
/** /**
* 引入swiper * 引入swiper
*/ */
import VueAwesomeSwiper from 'vue-awesome-swiper'
import 'swiper/swiper-bundle.css' import 'swiper/swiper-bundle.css'
Vue.use(VueAwesomeSwiper)
import { import {
Swiper as SwiperClass, Swiper as SwiperClass,
Pagination, Pagination,

View File

@@ -2,7 +2,8 @@
<a-modal <a-modal
:confirmLoading="confirmLoading" :confirmLoading="confirmLoading"
:visible="visible" :visible="visible"
@close="onCancel" @cancel="onCancel"
@ok="onOk"
class="yo-modal-form" class="yo-modal-form"
title="编辑XX" title="编辑XX"
> >

View File

@@ -166,7 +166,6 @@ export default {
this.$message.success(successMessage); this.$message.success(successMessage);
this.onReloadData(); this.onReloadData();
} }
this.$refs.table.onLoaded();
}, },
/** /**
@@ -180,6 +179,9 @@ export default {
.testDeleteApi(record) .testDeleteApi(record)
.then(({ success }) => { .then(({ success }) => {
this.onResult(success, '删除成功'); this.onResult(success, '删除成功');
})
.finally(() => {
this.$refs.table.onLoaded();
}); });
}, },
}, },

View File

@@ -5,7 +5,7 @@
@cancel="onCancel" @cancel="onCancel"
@ok="onOk" @ok="onOk"
class="yo-modal-form" class="yo-modal-form"
title="编辑XX" title="编辑字典数据"
> >
<FormBody ref="form-body" /> <FormBody ref="form-body" />
</a-modal> </a-modal>

View File

@@ -42,9 +42,7 @@ export default {
await this.formBody.onInit(); await this.formBody.onInit();
// 获取外部选中的部门id // 获取外部选中的部门id
this.formBody.onFillData({ this.formBody.onFillData(record, orgId);
pid: orgId,
});
}); });
}, },

View File

@@ -11,6 +11,7 @@
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="上级机构" prop="pid"> <a-form-model-item label="上级机构" prop="pid">
<a-tree-select <a-tree-select
:dropdown-style="{ maxHeight: '300px', overflow: 'auto' }"
:tree-data="orgData" :tree-data="orgData"
placeholder="请选择上级机构" placeholder="请选择上级机构"
tree-default-expand-all tree-default-expand-all
@@ -26,7 +27,7 @@
v-model="form.sort" v-model="form.sort"
/> />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="备注"> <a-form-model-item label="备注" prop="remark">
<a-textarea placeholder="请输入备注" v-model="form.remark" /> <a-textarea placeholder="请输入备注" v-model="form.remark" />
</a-form-model-item> </a-form-model-item>
</div> </div>
@@ -39,7 +40,10 @@ import { EMPTY_ID } from '@/util/global';
export default { export default {
data() { data() {
return { return {
form: {}, form: {
pid: undefined,
sort: 100,
},
rules: { rules: {
name: [{ required: true, message: '请输入机构名称' }], name: [{ required: true, message: '请输入机构名称' }],
code: [{ required: true, message: '请输入唯一编码' }], code: [{ required: true, message: '请输入唯一编码' }],
@@ -56,8 +60,12 @@ export default {
* 必要的方法 * 必要的方法
* 在打开编辑页时允许填充数据 * 在打开编辑页时允许填充数据
*/ */
onFillData(record) { onFillData(record, orgId) {
this.form = this.$_.cloneDeep(record); if (orgId) {
this.form.pid = orgId;
} else if (record) {
this.form = this.$_.cloneDeep(record);
}
}, },
/** /**
@@ -98,10 +106,6 @@ export default {
]; ];
}); });
}, },
onChangeExtData(value, record, type) {
record[type] = value;
},
}, },
}; };
</script> </script>

View File

@@ -6,7 +6,6 @@
ref="tree-layout" ref="tree-layout"
> >
<container> <container>
<br />
<a-card :bordered="false"> <a-card :bordered="false">
<Auth auth="sysOrg:page"> <Auth auth="sysOrg:page">
<div class="yo-query-bar"> <div class="yo-query-bar">

View File

@@ -43,11 +43,7 @@ export default {
await this.formBody.onInit(); await this.formBody.onInit();
// 获取外部选中的部门id // 获取外部选中的部门id
this.formBody.onFillData({ this.formBody.onFillData(record, id);
sysEmpParam: {
orgId: id,
},
});
}); });
}, },

View File

@@ -57,9 +57,10 @@
<div class="yo-form-group"> <div class="yo-form-group">
<a-form-model-item label="所属组织机构" prop="sysEmpParam.orgId"> <a-form-model-item label="所属组织机构" prop="sysEmpParam.orgId">
<a-tree-select <a-tree-select
:dropdown-style="{ maxHeight: '300px', overflow: 'auto' }"
:tree-data="orgData" :tree-data="orgData"
placeholder="请选择所属组织机构" placeholder="请选择所属组织机构"
treeDefaultExpandAll tree-default-expand-all
v-model="form.sysEmpParam.orgId" v-model="form.sysEmpParam.orgId"
/> />
</a-form-model-item> </a-form-model-item>
@@ -89,6 +90,7 @@
<template slot="orgId" slot-scope="text, record"> <template slot="orgId" slot-scope="text, record">
<a-tree-select <a-tree-select
:default-value="text" :default-value="text"
:dropdown-style="{ maxHeight: '300px', overflow: 'auto' }"
:tree-data="orgData" :tree-data="orgData"
@change="value => onChangeExtData(value, record, 'orgId')" @change="value => onChangeExtData(value, record, 'orgId')"
placeholder="请选择附加组织机构" placeholder="请选择附加组织机构"
@@ -183,8 +185,8 @@ export default {
* 必要的方法 * 必要的方法
* 在打开编辑页时允许填充数据 * 在打开编辑页时允许填充数据
*/ */
onFillData(record) { onFillData(record, orgId) {
const form = this.$_.cloneDeep(record); const form = this.$_.cloneDeep(record || {});
// 日期特殊处理 // 日期特殊处理
if (form.birthday) { if (form.birthday) {
form.birthday = moment(form.birthday).format('YYYY-MM-DD'); form.birthday = moment(form.birthday).format('YYYY-MM-DD');
@@ -212,6 +214,10 @@ export default {
}; };
}); });
} }
if (orgId) {
form.sysEmpParam.orgId = orgId;
}
this.form = form; this.form = form;
}, },

View File

@@ -1,7 +1,6 @@
<template> <template>
<yo-tree-layout :load-data="loadTreeData" @select="onSelect" default-expanded-keys> <yo-tree-layout :load-data="loadTreeData" @select="onSelect" default-expanded-keys>
<container> <container>
<br />
<a-alert closable type="error"> <a-alert closable type="error">
<template slot="message"> <template slot="message">
后端bug:生日不填写,在保存时会默认写入0001-01-01 后端bug:生日不填写,在保存时会默认写入0001-01-01
@@ -9,10 +8,6 @@
</template> </template>
</a-alert> </a-alert>
<br /> <br />
<a-alert closable type="warning">
<template slot="message">缺授权的两块功能</template>
</a-alert>
<br />
<a-card :bordered="false"> <a-card :bordered="false">
<Auth auth="sysUser:page"> <Auth auth="sysUser:page">
<div class="yo-query-bar"> <div class="yo-query-bar">

View File

@@ -0,0 +1,138 @@
<template>
<section>
<a-layout-sider
:collapsed="siderCollapsed === undefined ? $root.global.settings.siderCollapsed : siderCollapsed"
@collapse="onCollapse"
v-if="$root.global.settings.layout === 'left-menu' || $root.global.settings.layout === 'right-menu'"
width="200"
>
<Logo />
<div class="yo-sider-nav">
<App :apps="nav.apps" @change-app="(app) => $emit('change-app', app)" />
<!-- <swiper :options="siderSwiperOptions" ref="sider-swiper">
<swiper-slide>
<a-spin :spinning="nav.loading">
<a-icon slot="indicator" spin type="loading" />
<Menu
:menu-style="{ height: '100%', borderRight: 0 }"
:nav="nav"
@openChange="onMenuOpenChange"
mode="inline"
/>
</a-spin>
</swiper-slide>
<div class="swiper-scrollbar" id="layout--swiper-scrollbar" slot="scrollbar"></div>
</swiper>-->
<div class="swiper-container" id="layout--swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide">
<a-spin :spinning="nav.loading">
<a-icon slot="indicator" spin type="loading" />
<Menu
:menu-style="{ height: '100%', borderRight: 0 }"
:nav="nav"
@openChange="onMenuOpenChange"
mode="inline"
/>
</a-spin>
</div>
<div class="swiper-scrollbar" id="layout--swiper-scrollbar"></div>
</div>
</div>
</div>
</a-layout-sider>
<template v-else-if="$root.global.settings.layout === 'top-nav'">
<Menu
:menu-style="{ borderBottom: 0 }"
:nav="nav"
@openChange="onMenuOpenChange"
mode="horizontal"
/>
</template>
</section>
</template>
<script>
import Logo from '../logo';
import App from './app';
import Menu from './menu';
import Swiper from 'swiper';
let timer,
swiper,
siderSwiperOptions = {
direction: 'vertical',
slidesPerView: 'auto',
freeMode: true,
scrollbar: {
el: '#layout--swiper-scrollbar',
},
mousewheel: true,
};
export default {
components: {
Logo,
App,
Menu,
},
props: {
nav: {
default() {
return {
apps: [],
menus: [],
loading: false,
};
},
type: Object,
},
},
data() {
return {
siderCollapsed: undefined,
};
},
mounted() {
swiper = new Swiper('#layout--swiper-container', siderSwiperOptions);
window.addEventListener('resize', () => {
if (this.$root.global.settings.layout === 'left-menu' || this.$root.global.settings.layout === 'right-menu') {
if (!this.$root.global.settings.siderCollapsed) {
if (window.innerWidth < 1000) {
this.siderCollapsed = true;
} else {
this.siderCollapsed = undefined;
}
}
this.onUpdateSwiper();
}
});
},
methods: {
onUpdateSwiper() {
clearTimeout(timer);
timer = setTimeout(() => {
// if (this.$refs['sider-swiper']) {
// this.$refs['sider-swiper'].$swiper.update();
// }
swiper.update();
}, 300);
},
onMenuOpenChange() {
this.onUpdateSwiper();
},
onCollapse() {
this.onUpdateSwiper();
},
windowTriggerResize() {
let e = new Event('resize');
window.dispatchEvent(e);
},
},
};
</script>

View File

@@ -9,20 +9,22 @@
<Logo /> <Logo />
<div class="yo-sider-nav"> <div class="yo-sider-nav">
<App :apps="nav.apps" @change-app="(app) => $emit('change-app', app)" /> <App :apps="nav.apps" @change-app="(app) => $emit('change-app', app)" />
<swiper :options="siderSwiperOptions" ref="sider-swiper"> <div class="swiper-container" id="layout--swiper-container">
<swiper-slide> <div class="swiper-wrapper">
<a-spin :spinning="nav.loading"> <div class="swiper-slide">
<a-icon slot="indicator" spin type="loading" /> <a-spin :spinning="nav.loading">
<Menu <a-icon slot="indicator" spin type="loading" />
:menu-style="{ height: '100%', borderRight: 0 }" <Menu
:nav="nav" :menu-style="{ height: '100%', borderRight: 0 }"
@openChange="onMenuOpenChange" :nav="nav"
mode="inline" @openChange="onMenuOpenChange"
/> mode="inline"
</a-spin> />
</swiper-slide> </a-spin>
<div class="swiper-scrollbar" id="layout--swiper-scrollbar" slot="scrollbar"></div> </div>
</swiper> </div>
<div class="swiper-scrollbar" id="layout--swiper-scrollbar"></div>
</div>
</div> </div>
</a-layout-sider> </a-layout-sider>
<template v-else-if="$root.global.settings.layout === 'top-nav'"> <template v-else-if="$root.global.settings.layout === 'top-nav'">
@@ -40,7 +42,19 @@ import Logo from '../logo';
import App from './app'; import App from './app';
import Menu from './menu'; import Menu from './menu';
let timer; import Swiper from 'swiper';
let timer,
swiper,
siderSwiperOptions = {
direction: 'vertical',
slidesPerView: 'auto',
freeMode: true,
scrollbar: {
el: '#layout--swiper-scrollbar',
},
mousewheel: true,
};
export default { export default {
components: { components: {
@@ -62,20 +76,13 @@ export default {
}, },
data() { data() {
return { return {
siderSwiperOptions: {
direction: 'vertical',
slidesPerView: 'auto',
freeMode: true,
scrollbar: {
el: '#layout--swiper-scrollbar',
},
mousewheel: true,
},
siderCollapsed: undefined, siderCollapsed: undefined,
}; };
}, },
mounted() { mounted() {
// swiper不能使用vue版本的组件.效果相当差
swiper = new Swiper('#layout--swiper-container', siderSwiperOptions);
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
if (this.$root.global.settings.layout === 'left-menu' || this.$root.global.settings.layout === 'right-menu') { if (this.$root.global.settings.layout === 'left-menu' || this.$root.global.settings.layout === 'right-menu') {
if (!this.$root.global.settings.siderCollapsed) { if (!this.$root.global.settings.siderCollapsed) {
@@ -86,22 +93,26 @@ export default {
} }
} }
clearTimeout(timer); this.onUpdateSwiper();
timer = setTimeout(() => {
if (this.$refs['sider-swiper']) {
this.$refs['sider-swiper'].$swiper.update();
}
}, 300);
} }
}); });
}, },
methods: { methods: {
onUpdateSwiper() {
clearTimeout(timer);
timer = setTimeout(() => {
// 需要更新两次
swiper.update();
swiper.update();
}, 300);
},
onMenuOpenChange() { onMenuOpenChange() {
this.windowTriggerResize(); this.onUpdateSwiper();
}, },
onCollapse() { onCollapse() {
this.windowTriggerResize(); this.onUpdateSwiper();
}, },
windowTriggerResize() { windowTriggerResize() {