1
This commit is contained in:
277
src/components/FloatPanel/index.vue
Normal file
277
src/components/FloatPanel/index.vue
Normal file
@@ -0,0 +1,277 @@
|
||||
<template>
|
||||
<transition name="float-panel">
|
||||
<div v-if="showPanel" class="float-panel-wrapper" @click.self="handleBackdropClick">
|
||||
<div class="float-panel" :class="panelClass" :style="panelStyle">
|
||||
<div class="float-panel-header">
|
||||
<div class="header-left">
|
||||
<Button v-if="showBack" type="text" icon="ios-arrow-back" @click="handleBack">
|
||||
{{ backText }}
|
||||
</Button>
|
||||
<span v-if="title" class="panel-title">{{ title }}</span>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<slot name="header-right"></slot>
|
||||
<Button v-if="showClose" type="text" icon="ios-close" @click="hide"></Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="float-panel-body">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'FloatPanel',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: '100%'
|
||||
},
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: '100%'
|
||||
},
|
||||
position: {
|
||||
type: String,
|
||||
default: 'right', // left, right, top, bottom, center
|
||||
validator: (value) => ['left', 'right', 'top', 'bottom', 'center'].includes(value)
|
||||
},
|
||||
showBack: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showClose: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
backText: {
|
||||
type: String,
|
||||
default: '返回'
|
||||
},
|
||||
closeOnClickBackdrop: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
mask: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
default: 1000
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showPanel: false,
|
||||
callback: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
panelClass() {
|
||||
return {
|
||||
[`float-panel-${this.position}`]: true
|
||||
}
|
||||
},
|
||||
panelStyle() {
|
||||
const style = {
|
||||
zIndex: this.zIndex,
|
||||
width: typeof this.width === 'number' ? `${this.width}px` : this.width,
|
||||
height: typeof this.height === 'number' ? `${this.height}px` : this.height
|
||||
}
|
||||
return style
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
show(callback) {
|
||||
this.showPanel = true
|
||||
this.callback = callback
|
||||
},
|
||||
hide() {
|
||||
this.showPanel = false
|
||||
this.callback = null
|
||||
},
|
||||
handleBack() {
|
||||
this.$emit('back')
|
||||
this.hide()
|
||||
},
|
||||
handleBackdropClick() {
|
||||
if (this.closeOnClickBackdrop) {
|
||||
this.hide()
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
showPanel(newVal) {
|
||||
if (newVal) {
|
||||
document.body.style.overflow = 'hidden'
|
||||
} else {
|
||||
document.body.style.overflow = ''
|
||||
}
|
||||
},
|
||||
// 监听路由变化
|
||||
'$route'(to, from) {
|
||||
if (this.showPanel) {
|
||||
this.hide()
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
// 组件销毁时关闭面板并清理
|
||||
if (this.showPanel) {
|
||||
this.hide()
|
||||
}
|
||||
document.body.style.overflow = ''
|
||||
},
|
||||
destroyed() {
|
||||
// 确保清理
|
||||
document.body.style.overflow = ''
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.float-panel-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.float-panel {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
&.float-panel-right {
|
||||
animation: slideInRight 0.3s ease-out;
|
||||
}
|
||||
|
||||
&.float-panel-left {
|
||||
animation: slideInLeft 0.3s ease-out;
|
||||
}
|
||||
|
||||
&.float-panel-top {
|
||||
animation: slideInTop 0.3s ease-out;
|
||||
}
|
||||
|
||||
&.float-panel-bottom {
|
||||
animation: slideInBottom 0.3s ease-out;
|
||||
}
|
||||
|
||||
&.float-panel-center {
|
||||
animation: fadeInScale 0.3s ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
.float-panel-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 20px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
|
||||
.panel-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #17233d;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.float-panel-body {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
|
||||
// 动画效果
|
||||
.float-panel-enter-active,
|
||||
.float-panel-leave-active {
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.float-panel-enter,
|
||||
.float-panel-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInLeft {
|
||||
from {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInTop {
|
||||
from {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInBottom {
|
||||
from {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInScale {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -19,6 +19,7 @@ import Editor from './editor/index.vue'
|
||||
import editModal from './tables/editModal.vue'
|
||||
import fieldItem from './tables/fieldItem.vue'
|
||||
import FieldRenderer from './tables/fieldRenderer.vue'
|
||||
import FloatPanel from './FloatPanel/index.vue'
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +49,7 @@ const registerGlobalComponents = (Vue) => {
|
||||
Vue.component('editModal', editModal)
|
||||
Vue.component('fieldItem', fieldItem)
|
||||
Vue.component('FieldRenderer', FieldRenderer)
|
||||
Vue.component('FloatPanel', FloatPanel)
|
||||
}
|
||||
|
||||
// 注册自定义组件的方法
|
||||
@@ -80,7 +82,7 @@ export default {
|
||||
editModal,
|
||||
fieldItem,
|
||||
FieldRenderer,
|
||||
|
||||
FloatPanel
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ export default {
|
||||
|
||||
.table-scroll-container {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
overflow: auto;
|
||||
overflow-y: visible;
|
||||
/* 横向滚动条始终可见,不需要滚动到底 */
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export default class uiTool {
|
||||
*/
|
||||
static downloadFile(res, fileName) {
|
||||
// 开头和结尾去掉 中间不去掉
|
||||
let tempFileName = fileName || `${new Date().getTime()}.csv`
|
||||
let tempFileName = fileName || `${new Date().getTime()}.csv`
|
||||
|
||||
const blob = new Blob([res.data || res])
|
||||
const downloadElement = document.createElement('a')
|
||||
@@ -130,20 +130,20 @@ export default class uiTool {
|
||||
}
|
||||
|
||||
static delConfirm(callback) {
|
||||
const Modal = (window.framework && window.framework.ViewUI && window.framework.ViewUI.Modal) || window.$Modal
|
||||
if (Modal) {
|
||||
Modal.confirm({
|
||||
title: '温馨提示',
|
||||
content: '<p>你确定删除吗?</p>',
|
||||
onOk: () => {
|
||||
callback && callback()
|
||||
}
|
||||
})
|
||||
}
|
||||
const Modal = window.rootVue.$Modal
|
||||
|
||||
Modal.confirm({
|
||||
title: '温馨提示',
|
||||
content: '<p>你确定删除吗?</p>',
|
||||
onOk: () => {
|
||||
callback && callback()
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
static showConfirm({ title = '温馨提示', content = '内容' }, callback) {
|
||||
const Modal = (window.framework && window.framework.ViewUI && window.framework.ViewUI.Modal) || window.$Modal
|
||||
const Modal = window.rootVue.$Modal
|
||||
if (Modal) {
|
||||
Modal.confirm({
|
||||
title,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="content-view ">
|
||||
<div class="tree-box">
|
||||
<div class="btn-top-box pa10">
|
||||
<Button type="warning" size="small" @click="delAll">全部删除</Button>
|
||||
<Button type="warning" size="small" @click="delAll">全部删除2</Button>
|
||||
</div>
|
||||
<Tree class="mt10" :data="treeData" :render="renderContent" @on-select-change="selectChange"></Tree>
|
||||
</div>
|
||||
@@ -83,25 +83,33 @@ export default {
|
||||
}
|
||||
}),
|
||||
h('span', data.title),
|
||||
h('Icon', {
|
||||
props: {
|
||||
type: 'ios-trash',
|
||||
size: '18'
|
||||
},
|
||||
h('span', {
|
||||
on: {
|
||||
click: () => {
|
||||
click: (e) => {
|
||||
e.stopPropagation() // 阻止事件冒泡
|
||||
e.preventDefault() // 阻止默认行为
|
||||
this.deleteLog(data)
|
||||
}
|
||||
},
|
||||
style: {
|
||||
'margin-left': '8px'
|
||||
'margin-left': '8px',
|
||||
cursor: 'pointer',
|
||||
display: 'inline-block'
|
||||
}
|
||||
})
|
||||
}, [
|
||||
h('Icon', {
|
||||
props: {
|
||||
type: 'ios-trash',
|
||||
size: '18'
|
||||
}
|
||||
})
|
||||
])
|
||||
])
|
||||
]
|
||||
)
|
||||
},
|
||||
async selectChange(row) {
|
||||
|
||||
row[0].selected = true
|
||||
this.selectRow = row[0].title
|
||||
let res = await sys_log_serve.detail({ title: this.selectRow })
|
||||
@@ -135,7 +143,7 @@ export default {
|
||||
.content-view {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.tree-box {
|
||||
.log-box {
|
||||
height: 90vh;
|
||||
width: 300px;
|
||||
border-right: solid 1px #ccc;
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
<Button type="primary" @click="addWarp()">新增</Button>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<card class="tree-box">
|
||||
<TreeGrid :columns="gridOption.columns" :data="gridOption.data"></TreeGrid>
|
||||
</card>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="gridOption.editColumns" :rules="gridOption.rules">
|
||||
<div slot="bottom">
|
||||
@@ -254,7 +252,7 @@ export default {
|
||||
this.gridOption.menuData = this.mapTree(menuTree)
|
||||
|
||||
this.$store.dispatch('setAuthorityMenus')
|
||||
|
||||
|
||||
},
|
||||
async initCol() {
|
||||
let res = await menuServer.modelAll()
|
||||
@@ -394,9 +392,5 @@ export default {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.tree-box {
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
max-height: calc(100vh - 200px);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user