This commit is contained in:
fengchenchen
2023-08-14 17:10:11 +08:00
commit 37f6ec895d
1145 changed files with 437754 additions and 0 deletions
+242
View File
@@ -0,0 +1,242 @@
<template>
<a-modal
ref="modal"
:class="getClass(modalClass)"
:style="getStyle(modalStyle)"
:visible="visible"
v-bind="_attrs"
v-on="$listeners"
@ok="handleOk"
@cancel="handleCancel"
destroyOnClose
>
<slot></slot>
<!--有设置标题-->
<template v-if="!isNoTitle" slot="title">
<a-row class="j-modal-title-row" type="flex">
<a-col class="left">
<slot name="title">{{ title }}</slot>
</a-col>
<a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
<a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
</a-col>
</a-row>
</template>
<!--没有设置标题-->
<template v-else slot="title">
<a-row class="j-modal-title-row" type="flex">
<a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
<a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
</a-col>
</a-row>
</template>
<!-- 处理 scopedSlots -->
<template v-for="slotName of scopedSlotsKeys" :slot="slotName">
<slot :name="slotName"></slot>
</template>
<!-- 处理 slots -->
<template v-for="slotName of slotsKeys" v-slot:[slotName]>
<slot :name="slotName"></slot>
</template>
</a-modal>
</template>
<script>
import { getClass, getStyle } from '@/utils/props-util'
import { triggerWindowResizeEvent } from '@/utils/util'
export default {
name: 'JModal',
props: {
title: String,
// 可使用 .sync 修饰符
visible: Boolean,
// 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
fullscreen: {
type: Boolean,
default: false
},
// 是否允许切换全屏(允许后右上角会出现一个按钮)
switchFullscreen: {
type: Boolean,
default: false
},
// 点击确定按钮的时候是否关闭弹窗
okClose: {
type: Boolean,
default: true
}
},
data () {
return {
// 内部使用的 slots ,不再处理
usedSlots: ['title'],
// 实际控制是否全屏的参数
innerFullscreen: this.fullscreen
}
},
computed: {
// 一些未处理的参数或特殊处理的参数绑定到 a-modal 上
_attrs () {
const attrs = { ...this.$attrs }
// 如果全屏就将宽度设为 100%
if (this.innerFullscreen) {
attrs.width = '100%'
}
return attrs
},
modalClass () {
return {
'j-modal-box': true,
fullscreen: this.innerFullscreen,
'no-title': this.isNoTitle,
'no-footer': this.isNoFooter
}
},
modalStyle () {
const style = {}
// 如果全屏就将top设为 0
if (this.innerFullscreen) {
style.top = '0'
}
return style
},
isNoTitle () {
return !this.title && !this.allSlotsKeys.includes('title')
},
isNoFooter () {
return this._attrs.footer === null
},
slotsKeys () {
return Object.keys(this.$slots).filter(key => !this.usedSlots.includes(key))
},
scopedSlotsKeys () {
return Object.keys(this.$scopedSlots).filter(key => !this.usedSlots.includes(key))
},
allSlotsKeys () {
return Object.keys(this.$slots).concat(Object.keys(this.$scopedSlots))
},
// 切换全屏的按钮图标
fullscreenButtonIcon () {
return this.innerFullscreen ? 'fullscreen-exit' : 'fullscreen'
}
},
watch: {
visible () {
if (this.visible) {
this.innerFullscreen = this.fullscreen
}
},
innerFullscreen (val) {
this.$emit('update:fullscreen', val)
}
},
methods: {
getClass (clazz) {
return { ...getClass(this), ...clazz }
},
getStyle (style) {
return { ...getStyle(this), ...style }
},
close () {
this.$emit('update:visible', false)
},
handleOk () {
if (this.okClose) {
this.close()
}
},
handleCancel () {
this.close()
},
/** 切换全屏 */
toggleFullscreen () {
this.innerFullscreen = !this.innerFullscreen
triggerWindowResizeEvent()
}
}
}
</script>
<style lang="less">
.j-modal-box {
&.fullscreen {
top: 0;
left: 0;
padding: 0;
// 兼容1.6.2版本的antdv
& .ant-modal {
top: 0;
padding: 0;
height: 100vh;
}
& .ant-modal-content {
height: 100vh;
border-radius: 0;
& .ant-modal-body {
/* title 和 footer 各占 55px */
height: calc(100% - 55px - 55px);
overflow: auto;
}
}
&.no-title, &.no-footer {
.ant-modal-body {
height: calc(100% - 55px);
}
}
&.no-title.no-footer {
.ant-modal-body {
height: 100%;
}
}
}
.j-modal-title-row {
.left {
width: calc(100% - 56px - 56px);
}
.right {
width: 56px;
position: inherit;
.ant-modal-close {
right: 56px;
color: rgba(0, 0, 0, 0.45);
&:hover {
color: rgba(0, 0, 0, 0.75);
}
}
}
}
&.no-title{
.ant-modal-header {
padding: 0 24px;
border-bottom: 0 !important;
}
}
}
@media (max-width: 767px) {
.j-modal-box.fullscreen {
margin: 0;
max-width: 100vw;
}
}
</style>
+124
View File
@@ -0,0 +1,124 @@
<template>
<j-modal :visible="visible" :confirmLoading="loading" :after-close="afterClose" v-bind="modalProps" @ok="onOk" @cancel="onCancel">
<a-spin :spinning="loading">
<div v-html="content"></div>
<a-form-model ref="form" :model="model" :rules="rules">
<a-form-model-item prop="input">
<a-input ref="input" v-model="model.input" v-bind="inputProps" @pressEnter="onInputPressEnter"/>
</a-form-model-item>
</a-form-model>
</a-spin>
</j-modal>
</template>
<script>
import pick from 'lodash.pick'
export default {
name: 'JPrompt',
data () {
return {
visible: false,
loading: false,
content: '',
// 弹窗参数
modalProps: {
title: ''
},
inputProps: {
placeholder: ''
},
// form model
model: {
input: ''
},
// 校验
rule: [],
// 回调函数
callback: {}
}
},
computed: {
rules () {
return {
input: this.rule
}
}
},
methods: {
show (options) {
this.content = options.content
if (Array.isArray(options.rule)) {
this.rule = options.rule
}
if (options.defaultValue != null) {
this.model.input = options.defaultValue
}
// 取出常用的弹窗参数
const pickModalProps = pick(options, 'title', 'centered', 'cancelText', 'closable', 'mask', 'maskClosable', 'okText', 'okType', 'okButtonProps', 'cancelButtonProps', 'width', 'wrapClassName', 'zIndex', 'dialogStyle', 'dialogClass')
this.modalProps = Object.assign({}, pickModalProps, options.modalProps)
// 取出常用的input参数
const pickInputProps = pick(options, 'placeholder', 'allowClear')
this.inputProps = Object.assign({}, pickInputProps, options.inputProps)
// 回调函数
this.callback = pick(options, 'onOk', 'onOkAsync', 'onCancel')
this.visible = true
this.$nextTick(() => this.$refs.input.focus())
},
onOk () {
this.$refs.form.validate((ok) => {
if (ok) {
const event = { value: this.model.input, target: this }
// 异步方法优先级高于同步方法
if (typeof this.callback.onOkAsync === 'function') {
this.callback.onOkAsync(event)
} else if (typeof this.callback.onOk === 'function') {
this.callback.onOk(event)
this.close()
} else {
this.close()
}
}
})
},
onCancel () {
if (typeof this.callback.onCancel === 'function') {
this.callback.onCancel(this.model.input)
}
this.close()
},
onInputPressEnter () {
this.onOk()
},
close () {
this.visible = this.loading ? this.visible : false
},
forceClose () {
this.visible = false
},
showLoading () {
this.loading = true
},
hideLoading () {
this.loading = false
},
afterClose (e) {
if (typeof this.modalProps.afterClose === 'function') {
this.modalProps.afterClose(e)
}
this.$emit('after-close', e)
}
}
}
</script>
<style scoped>
</style>
+18
View File
@@ -0,0 +1,18 @@
import JModal from './JModal'
import JPrompt from './JPrompt'
export default {
install (Vue) {
Vue.component(JModal.name, JModal)
const JPromptExtend = Vue.extend(JPrompt)
Vue.prototype.$JPrompt = function (options = {}) {
// 创建prompt实例
const vm = new JPromptExtend().$mount()
vm.show(options)
// 关闭后销毁
vm.$on('after-close', () => vm.$destroy())
return vm
}
}
}
+241
View File
@@ -0,0 +1,241 @@
<template>
<a-modal
ref="modal"
:class="getClass(modalClass)"
:style="getStyle(modalStyle)"
:visible="visible"
v-bind="_attrs"
v-on="$listeners"
@ok="handleOk"
@cancel="handleCancel"
destroyOnClose
>
<slot></slot>
<!--有设置标题-->
<template v-if="!isNoTitle" slot="title">
<a-row class="j-modal-title-row" type="flex">
<a-col class="left">
<slot name="title">{{ title }}</slot>
</a-col>
<a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
<a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
</a-col>
</a-row>
</template>
<!--没有设置标题-->
<template v-else slot="title">
<a-row class="j-modal-title-row" type="flex">
<a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
<a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
</a-col>
</a-row>
</template>
<!-- 处理 scopedSlots -->
<template v-for="slotName of scopedSlotsKeys" :slot="slotName">
<slot :name="slotName"></slot>
</template>
<!-- 处理 slots -->
<template v-for="slotName of slotsKeys" v-slot:[slotName]>
<slot :name="slotName"></slot>
</template>
</a-modal>
</template>
<script>
import { getClass, getStyle } from '@/utils/props-util'
import { triggerWindowResizeEvent } from '@/utils/util'
export default {
name: 'JModal',
props: {
title: String,
// 可使用 .sync 修饰符
visible: Boolean,
// 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
fullscreen: {
type: Boolean,
default: false
},
// 是否允许切换全屏(允许后右上角会出现一个按钮)
switchFullscreen: {
type: Boolean,
default: false
},
// 点击确定按钮的时候是否关闭弹窗
okClose: {
type: Boolean,
default: true
}
},
data () {
return {
// 内部使用的 slots ,不再处理
usedSlots: ['title'],
// 实际控制是否全屏的参数
innerFullscreen: this.fullscreen
}
},
computed: {
// 一些未处理的参数或特殊处理的参数绑定到 a-modal 上
_attrs () {
const attrs = { ...this.$attrs }
// 如果全屏就将宽度设为 100%
if (this.innerFullscreen) {
attrs.width = '100%'
}
return attrs
},
modalClass () {
return {
'j-modal-box': true,
fullscreen: this.innerFullscreen,
'no-title': this.isNoTitle,
'no-footer': this.isNoFooter
}
},
modalStyle () {
const style = {}
// 如果全屏就将top设为 0
if (this.innerFullscreen) {
style.top = '0'
}
return style
},
isNoTitle () {
return !this.title && !this.allSlotsKeys.includes('title')
},
isNoFooter () {
return this._attrs.footer === null
},
slotsKeys () {
return Object.keys(this.$slots).filter(key => !this.usedSlots.includes(key))
},
scopedSlotsKeys () {
return Object.keys(this.$scopedSlots).filter(key => !this.usedSlots.includes(key))
},
allSlotsKeys () {
return Object.keys(this.$slots).concat(Object.keys(this.$scopedSlots))
},
// 切换全屏的按钮图标
fullscreenButtonIcon () {
return this.innerFullscreen ? 'fullscreen-exit' : 'fullscreen'
}
},
watch: {
visible () {
if (this.visible) {
this.innerFullscreen = this.fullscreen
}
},
innerFullscreen (val) {
this.$emit('update:fullscreen', val)
}
},
methods: {
getClass (clazz) {
return { ...getClass(this), ...clazz }
},
getStyle (style) {
return { ...getStyle(this), ...style }
},
close () {
this.$emit('update:visible', false)
},
handleOk () {
if (this.okClose) {
this.close()
}
},
handleCancel () {
this.close()
},
/** 切换全屏 */
toggleFullscreen () {
this.innerFullscreen = !this.innerFullscreen
triggerWindowResizeEvent()
}
}
}
</script>
<style lang="less">
.j-modal-box {
&.fullscreen {
top: 0;
left: 0;
padding: 0;
// 兼容1.6.2版本的antdv
& .ant-modal {
top: 0;
padding: 0;
height: 100vh;
}
& .ant-modal-content {
height: 100vh;
border-radius: 0;
& .ant-modal-body {
/* title 和 footer 各占 55px */
height: calc(100% - 55px - 55px);
overflow: auto;
}
}
&.no-title, &.no-footer {
.ant-modal-body {
height: calc(100% - 55px);
}
}
&.no-title.no-footer {
.ant-modal-body {
height: 100%;
}
}
}
.j-modal-title-row {
.left {
width: calc(100% - 56px - 56px);
}
.right {
width: 56px;
position: inherit;
.ant-modal-close {
right: 56px;
color: rgba(0, 0, 0, 0.45);
&:hover {
color: rgba(0, 0, 0, 0.75);
}
}
}
}
&.no-title{
.ant-modal-header {
padding: 0 24px;
border-bottom: 0 !important;
}
}
}
@media (max-width: 767px) {
.j-modal-box.fullscreen {
margin: 0;
max-width: 100vw;
}
}
</style>