parent
5a9e8516c8
commit
4dacb5cb65
19 changed files with 1808 additions and 191 deletions
@ -0,0 +1,130 @@ |
|||||||
|
<template> |
||||||
|
<view |
||||||
|
class="u-mask" |
||||||
|
hover-stop-propagation |
||||||
|
:style="[maskStyle, zoomStyle]" |
||||||
|
@tap="click" |
||||||
|
@touchmove.stop.prevent="() => {}" |
||||||
|
:class="{ |
||||||
|
'u-mask-zoom': zoom, |
||||||
|
'u-mask-show': show, |
||||||
|
}" |
||||||
|
> |
||||||
|
<slot /> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
/** |
||||||
|
* mask 遮罩 |
||||||
|
* @description 创建一个遮罩层,用于强调特定的页面元素,并阻止用户对遮罩下层的内容进行操作,一般用于弹窗场景 |
||||||
|
* @tutorial https://www.uviewui.com/components/mask.html |
||||||
|
* @property {Boolean} show 是否显示遮罩(默认false) |
||||||
|
* @property {String Number} z-index z-index 层级(默认1070) |
||||||
|
* @property {Object} custom-style 自定义样式对象,见上方说明 |
||||||
|
* @property {String Number} duration 动画时长,单位毫秒(默认300) |
||||||
|
* @property {Boolean} zoom 是否使用scale对这招进行缩放(默认true) |
||||||
|
* @property {Boolean} mask-click-able 遮罩是否可点击,为false时点击不会发送click事件(默认true) |
||||||
|
* @event {Function} click mask-click-able为true时,点击遮罩发送此事件 |
||||||
|
* @example <u-mask :show="show" @click="show = false"></u-mask> |
||||||
|
*/ |
||||||
|
export default { |
||||||
|
name: "u-mask", |
||||||
|
props: { |
||||||
|
// 是否显示遮罩 |
||||||
|
show: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
// 层级z-index |
||||||
|
zIndex: { |
||||||
|
type: [Number, String], |
||||||
|
default: "", |
||||||
|
}, |
||||||
|
// 用户自定义样式 |
||||||
|
customStyle: { |
||||||
|
type: Object, |
||||||
|
default() { |
||||||
|
return {}; |
||||||
|
}, |
||||||
|
}, |
||||||
|
// 遮罩的动画样式, 是否使用使用zoom进行scale进行缩放 |
||||||
|
zoom: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
// 遮罩的过渡时间,单位为ms |
||||||
|
duration: { |
||||||
|
type: [Number, String], |
||||||
|
default: 300, |
||||||
|
}, |
||||||
|
// 是否可以通过点击遮罩进行关闭 |
||||||
|
maskClickAble: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
zoomStyle: { |
||||||
|
transform: "", |
||||||
|
}, |
||||||
|
scale: "scale(1.2, 1.2)", |
||||||
|
}; |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
show(n) { |
||||||
|
if (n && this.zoom) { |
||||||
|
// 当展示遮罩的时候,设置scale为1,达到缩小(原来为1.2)的效果 |
||||||
|
this.zoomStyle.transform = "scale(1, 1)"; |
||||||
|
} else if (!n && this.zoom) { |
||||||
|
// 当隐藏遮罩的时候,设置scale为1.2,达到放大(因为显示遮罩时已重置为1)的效果 |
||||||
|
this.zoomStyle.transform = this.scale; |
||||||
|
} |
||||||
|
}, |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
maskStyle() { |
||||||
|
let style = {}; |
||||||
|
style.backgroundColor = "rgba(0, 0, 0, 0.6)"; |
||||||
|
if (this.show) |
||||||
|
style.zIndex = this.zIndex ? this.zIndex : this.$u.zIndex.mask; |
||||||
|
else style.zIndex = -1; |
||||||
|
style.transition = `all ${this.duration / 1000}s ease-in-out`; |
||||||
|
// 判断用户传递的对象是否为空,不为空就进行合并 |
||||||
|
if (Object.keys(this.customStyle).length) |
||||||
|
style = { |
||||||
|
...style, |
||||||
|
...this.customStyle, |
||||||
|
}; |
||||||
|
return style; |
||||||
|
}, |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
click() { |
||||||
|
if (!this.maskClickAble) return; |
||||||
|
this.$emit("click"); |
||||||
|
}, |
||||||
|
}, |
||||||
|
}; |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
.u-mask { |
||||||
|
position: fixed; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
bottom: 0; |
||||||
|
opacity: 0; |
||||||
|
transition: transform 0.3s; |
||||||
|
} |
||||||
|
|
||||||
|
.u-mask-show { |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
|
||||||
|
.u-mask-zoom { |
||||||
|
transform: scale(1.2, 1.2); |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,510 @@ |
|||||||
|
<template> |
||||||
|
<view |
||||||
|
v-if="visibleSync" |
||||||
|
:style="[ |
||||||
|
customStyle, |
||||||
|
{ |
||||||
|
zIndex: uZindex - 1, |
||||||
|
}, |
||||||
|
]" |
||||||
|
class="u-drawer" |
||||||
|
hover-stop-propagation |
||||||
|
> |
||||||
|
<z-mask |
||||||
|
:duration="duration" |
||||||
|
:custom-style="maskCustomStyle" |
||||||
|
:maskClickAble="maskCloseAble" |
||||||
|
:z-index="uZindex - 2" |
||||||
|
:show="showDrawer && mask" |
||||||
|
@click="maskClick" |
||||||
|
></z-mask> |
||||||
|
<view |
||||||
|
class="u-drawer-content" |
||||||
|
@tap="modeCenterClose(mode)" |
||||||
|
:class="[ |
||||||
|
safeAreaInsetBottom ? 'safe-area-inset-bottom' : '', |
||||||
|
'u-drawer-' + mode, |
||||||
|
showDrawer ? 'u-drawer-content-visible' : '', |
||||||
|
zoom && mode == 'center' ? 'u-animation-zoom' : '', |
||||||
|
]" |
||||||
|
@transitionend="transitionend" |
||||||
|
@touchmove.stop.prevent |
||||||
|
@tap.stop.prevent |
||||||
|
:style="[style]" |
||||||
|
> |
||||||
|
<view |
||||||
|
class="u-mode-center-box" |
||||||
|
@tap.stop.prevent |
||||||
|
@touchmove.stop.prevent |
||||||
|
v-if="mode == 'center'" |
||||||
|
:style="[centerStyle]" |
||||||
|
> |
||||||
|
<u-icon |
||||||
|
@click="close" |
||||||
|
v-if="closeable" |
||||||
|
class="u-close" |
||||||
|
:class="['u-close--' + closeIconPos]" |
||||||
|
:name="closeIcon" |
||||||
|
:color="closeIconColor" |
||||||
|
:size="closeIconSize" |
||||||
|
></u-icon> |
||||||
|
<scroll-view class="u-drawer__scroll-view" scroll-y="true"> |
||||||
|
<slot /> |
||||||
|
</scroll-view> |
||||||
|
<slot name="fixedContent" /> |
||||||
|
</view> |
||||||
|
<scroll-view class="u-drawer__scroll-view" scroll-y="true" v-else> |
||||||
|
<slot /> |
||||||
|
</scroll-view> |
||||||
|
<view @tap="close" class="u-close" :class="['u-close--' + closeIconPos]"> |
||||||
|
<u-icon |
||||||
|
v-if="mode != 'center' && closeable" |
||||||
|
:name="closeIcon" |
||||||
|
:color="closeIconColor" |
||||||
|
:size="closeIconSize" |
||||||
|
></u-icon> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
/** |
||||||
|
* popup 弹窗 |
||||||
|
* @description 弹出层容器,用于展示弹窗、信息提示等内容,支持上、下、左、右和中部弹出。组件只提供容器,内部内容由用户自定义 |
||||||
|
* @tutorial https://www.uviewui.com/components/popup.html |
||||||
|
* @property {String} mode 弹出方向(默认left) |
||||||
|
* @property {Boolean} mask 是否显示遮罩(默认true) |
||||||
|
* @property {Stringr | Number} length mode=left | 见官网说明(默认auto) |
||||||
|
* @property {Boolean} zoom 是否开启缩放动画,只在mode为center时有效(默认true) |
||||||
|
* @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false) |
||||||
|
* @property {Boolean} mask-close-able 点击遮罩是否可以关闭弹出层(默认true) |
||||||
|
* @property {Object} custom-style 用户自定义样式 |
||||||
|
* @property {Stringr | Number} negative-top 中部弹出时,往上偏移的值 |
||||||
|
* @property {Numberr | String} border-radius 弹窗圆角值(默认0) |
||||||
|
* @property {Numberr | String} z-index 弹出内容的z-index值(默认1075) |
||||||
|
* @property {Boolean} closeable 是否显示关闭图标(默认false) |
||||||
|
* @property {String} close-icon 关闭图标的名称,只能uView的内置图标 |
||||||
|
* @property {String} close-icon-pos 自定义关闭图标位置(默认top-right) |
||||||
|
* @property {String} close-icon-color 关闭图标的颜色(默认#909399) |
||||||
|
* @property {Number | String} close-icon-size 关闭图标的大小,单位rpx(默认30) |
||||||
|
* @event {Function} open 弹出层打开 |
||||||
|
* @event {Function} close 弹出层收起 |
||||||
|
* @example <u-popup v-model="show"><view>出淤泥而不染,濯清涟而不妖</view></u-popup> |
||||||
|
*/ |
||||||
|
import ZMask from "./mask.vue"; |
||||||
|
export default { |
||||||
|
name: "popup", |
||||||
|
components: { |
||||||
|
ZMask, |
||||||
|
}, |
||||||
|
props: { |
||||||
|
/** |
||||||
|
* 显示状态 |
||||||
|
*/ |
||||||
|
show: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
/** |
||||||
|
* 弹出方向,left|right|top|bottom|center |
||||||
|
*/ |
||||||
|
mode: { |
||||||
|
type: String, |
||||||
|
default: "left", |
||||||
|
}, |
||||||
|
/** |
||||||
|
* 是否显示遮罩 |
||||||
|
*/ |
||||||
|
mask: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
// 抽屉的宽度(mode=left|right),或者高度(mode=top|bottom),单位rpx,或者"auto" |
||||||
|
// 或者百分比"50%",表示由内容撑开高度或者宽度 |
||||||
|
length: { |
||||||
|
type: [Number, String], |
||||||
|
default: "auto", |
||||||
|
}, |
||||||
|
// 是否开启缩放动画,只在mode=center时有效 |
||||||
|
zoom: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
// 是否开启底部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距 |
||||||
|
safeAreaInsetBottom: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
// 是否可以通过点击遮罩进行关闭 |
||||||
|
maskCloseAble: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
// 用户自定义样式 |
||||||
|
customStyle: { |
||||||
|
type: Object, |
||||||
|
default() { |
||||||
|
return {}; |
||||||
|
}, |
||||||
|
}, |
||||||
|
value: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
// 此为内部参数,不在文档对外使用,为了解决Picker和keyboard等融合了弹窗的组件 |
||||||
|
// 对v-model双向绑定多层调用造成报错不能修改props值的问题 |
||||||
|
popup: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
// 显示显示弹窗的圆角,单位rpx |
||||||
|
borderRadius: { |
||||||
|
type: [Number, String], |
||||||
|
default: 0, |
||||||
|
}, |
||||||
|
zIndex: { |
||||||
|
type: [Number, String], |
||||||
|
default: "10075", |
||||||
|
}, |
||||||
|
// 是否显示关闭图标 |
||||||
|
closeable: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
// 关闭图标的名称,只能uView的内置图标 |
||||||
|
closeIcon: { |
||||||
|
type: String, |
||||||
|
default: "close", |
||||||
|
}, |
||||||
|
// 自定义关闭图标位置,top-left为左上角,top-right为右上角,bottom-left为左下角,bottom-right为右下角 |
||||||
|
closeIconPos: { |
||||||
|
type: String, |
||||||
|
default: "top-right", |
||||||
|
}, |
||||||
|
// 关闭图标的颜色 |
||||||
|
closeIconColor: { |
||||||
|
type: String, |
||||||
|
default: "#909399", |
||||||
|
}, |
||||||
|
// 关闭图标的大小,单位rpx |
||||||
|
closeIconSize: { |
||||||
|
type: [String, Number], |
||||||
|
default: "30", |
||||||
|
}, |
||||||
|
// 宽度,只对左,右,中部弹出时起作用,单位rpx,或者"auto" |
||||||
|
// 或者百分比"50%",表示由内容撑开高度或者宽度,优先级高于length参数 |
||||||
|
width: { |
||||||
|
type: String, |
||||||
|
default: "", |
||||||
|
}, |
||||||
|
// 高度,只对上,下,中部弹出时起作用,单位rpx,或者"auto" |
||||||
|
// 或者百分比"50%",表示由内容撑开高度或者宽度,优先级高于length参数 |
||||||
|
height: { |
||||||
|
type: String, |
||||||
|
default: "", |
||||||
|
}, |
||||||
|
// 给一个负的margin-top,往上偏移,避免和键盘重合的情况,仅在mode=center时有效 |
||||||
|
negativeTop: { |
||||||
|
type: [String, Number], |
||||||
|
default: 0, |
||||||
|
}, |
||||||
|
// 遮罩的样式,一般用于修改遮罩的透明度 |
||||||
|
maskCustomStyle: { |
||||||
|
type: Object, |
||||||
|
default() { |
||||||
|
return {}; |
||||||
|
}, |
||||||
|
}, |
||||||
|
// 遮罩打开或收起的动画过渡时间,单位ms |
||||||
|
duration: { |
||||||
|
type: [String, Number], |
||||||
|
default: 250, |
||||||
|
}, |
||||||
|
// 中间弹窗的背景颜色值 |
||||||
|
centerPupBg: { |
||||||
|
type: String, |
||||||
|
default: "#fff", |
||||||
|
}, |
||||||
|
bgColor: { |
||||||
|
type: String, |
||||||
|
default: "#fff", |
||||||
|
}, |
||||||
|
}, |
||||||
|
|
||||||
|
data() { |
||||||
|
return { |
||||||
|
visibleSync: false, |
||||||
|
showDrawer: false, |
||||||
|
timer: null, |
||||||
|
closeFromInner: false, // value的值改变,是发生在内部还是外部 |
||||||
|
}; |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
// 根据mode的位置,设定其弹窗的宽度(mode = left|right),或者高度(mode = top|bottom) |
||||||
|
style() { |
||||||
|
let style = {}; |
||||||
|
// 如果是左边或者上边弹出时,需要给translate设置为负值,用于隐藏 |
||||||
|
if (this.mode == "left" || this.mode == "right") { |
||||||
|
style = { |
||||||
|
width: this.width |
||||||
|
? this.getUnitValue(this.width) |
||||||
|
: this.getUnitValue(this.length), |
||||||
|
height: "100%", |
||||||
|
transform: `translate3D(${ |
||||||
|
this.mode == "left" ? "-100%" : "100%" |
||||||
|
},0px,0px)`, |
||||||
|
background: this.bgColor, |
||||||
|
}; |
||||||
|
} else if (this.mode == "top" || this.mode == "bottom") { |
||||||
|
style = { |
||||||
|
width: "100%", |
||||||
|
height: this.height |
||||||
|
? this.getUnitValue(this.height) |
||||||
|
: this.getUnitValue(this.length), |
||||||
|
transform: `translate3D(0px,${ |
||||||
|
this.mode == "top" ? "-100%" : "100%" |
||||||
|
},0px)`, |
||||||
|
background: this.bgColor, |
||||||
|
}; |
||||||
|
} |
||||||
|
style.zIndex = this.uZindex; |
||||||
|
// 如果用户设置了borderRadius值,添加弹窗的圆角 |
||||||
|
if (this.borderRadius) { |
||||||
|
switch (this.mode) { |
||||||
|
case "left": |
||||||
|
style.borderRadius = `0 ${this.borderRadius}rpx ${this.borderRadius}rpx 0`; |
||||||
|
break; |
||||||
|
case "top": |
||||||
|
style.borderRadius = `0 0 ${this.borderRadius}rpx ${this.borderRadius}rpx`; |
||||||
|
break; |
||||||
|
case "right": |
||||||
|
style.borderRadius = `${this.borderRadius}rpx 0 0 ${this.borderRadius}rpx`; |
||||||
|
break; |
||||||
|
case "bottom": |
||||||
|
style.borderRadius = `${this.borderRadius}rpx ${this.borderRadius}rpx 0 0`; |
||||||
|
break; |
||||||
|
default: |
||||||
|
} |
||||||
|
// 不加可能圆角无效 |
||||||
|
style.overflow = "hidden"; |
||||||
|
} |
||||||
|
if (this.duration) |
||||||
|
style.transition = `all ${this.duration / 1000}s linear`; |
||||||
|
return style; |
||||||
|
}, |
||||||
|
// 中部弹窗的特有样式 |
||||||
|
centerStyle() { |
||||||
|
let style = {}; |
||||||
|
style.width = this.width |
||||||
|
? this.getUnitValue(this.width) |
||||||
|
: this.getUnitValue(this.length); |
||||||
|
// 中部弹出的模式,如果没有设置高度,就用auto值,由内容撑开高度 |
||||||
|
style.height = this.height ? this.getUnitValue(this.height) : "auto"; |
||||||
|
style.zIndex = this.uZindex; |
||||||
|
// style.marginTop = `-${this.$u.addUnit(this.negativeTop)}`; |
||||||
|
style.background = this.centerPupBg; |
||||||
|
if (this.borderRadius) { |
||||||
|
style.borderRadius = `${this.borderRadius}rpx`; |
||||||
|
// 不加可能圆角无效 |
||||||
|
style.overflow = "hidden"; |
||||||
|
} |
||||||
|
return style; |
||||||
|
}, |
||||||
|
// 计算整理后的z-index值 |
||||||
|
uZindex() { |
||||||
|
return this.zIndex ? this.zIndex : this.$u.zIndex.popup; |
||||||
|
}, |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
value(val) { |
||||||
|
if (val) { |
||||||
|
this.open(); |
||||||
|
} else if (!this.closeFromInner) { |
||||||
|
this.close(); |
||||||
|
} |
||||||
|
this.closeFromInner = false; |
||||||
|
}, |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
// 组件渲染完成时,检查value是否为true,如果是,弹出popup |
||||||
|
this.value && this.open(); |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 动画结束回调 |
||||||
|
transitionend(e) { |
||||||
|
// console.log(e, "动画结束popup"); |
||||||
|
}, |
||||||
|
// 判断传入的值,是否带有单位,如果没有,就默认用rpx单位 |
||||||
|
getUnitValue(val) { |
||||||
|
if (/(%|px|rpx|auto)$/.test(val)) return val; |
||||||
|
else return val + "rpx"; |
||||||
|
}, |
||||||
|
// 遮罩被点击 |
||||||
|
maskClick() { |
||||||
|
this.close(); |
||||||
|
}, |
||||||
|
close() { |
||||||
|
// 标记关闭是内部发生的,否则修改了value值,导致watch中对value检测,导致再执行一遍close |
||||||
|
// 造成@close事件触发两次 |
||||||
|
this.closeFromInner = true; |
||||||
|
this.change("showDrawer", "visibleSync", false); |
||||||
|
}, |
||||||
|
// 中部弹出时,需要.u-drawer-content将居中内容,此元素会铺满屏幕,点击需要关闭弹窗 |
||||||
|
// 让其只在mode=center时起作用 |
||||||
|
modeCenterClose(mode) { |
||||||
|
if (mode != "center" || !this.maskCloseAble) return; |
||||||
|
this.close(); |
||||||
|
}, |
||||||
|
open() { |
||||||
|
this.change("visibleSync", "showDrawer", true); |
||||||
|
}, |
||||||
|
// 此处的原理是,关闭时先通过动画隐藏弹窗和遮罩,再移除整个组件 |
||||||
|
// 打开时,先渲染组件,延时一定时间再让遮罩和弹窗的动画起作用 |
||||||
|
change(param1, param2, status) { |
||||||
|
// 如果this.popup为false,意味着为picker,actionsheet等组件调用了popup组件 |
||||||
|
if (this.popup == true) { |
||||||
|
this.$emit("input", status); |
||||||
|
} |
||||||
|
this[param1] = status; |
||||||
|
if (status) { |
||||||
|
// #ifdef H5 || MP |
||||||
|
this.timer = setTimeout(() => { |
||||||
|
this[param2] = status; |
||||||
|
this.$emit(status ? "open" : "close"); |
||||||
|
}, 50); |
||||||
|
// #endif |
||||||
|
// #ifndef H5 || MP |
||||||
|
this.$nextTick(() => { |
||||||
|
this[param2] = status; |
||||||
|
this.$emit(status ? "open" : "close"); |
||||||
|
}); |
||||||
|
// #endif |
||||||
|
} else { |
||||||
|
this.timer = setTimeout(() => { |
||||||
|
this[param2] = status; |
||||||
|
this.$emit(status ? "open" : "close"); |
||||||
|
}, this.duration); |
||||||
|
} |
||||||
|
}, |
||||||
|
}, |
||||||
|
}; |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
@mixin vue-flex($direction: row) { |
||||||
|
/* #ifndef APP-NVUE */ |
||||||
|
display: flex; |
||||||
|
flex-direction: $direction; |
||||||
|
/* #endif */ |
||||||
|
} |
||||||
|
.u-drawer { |
||||||
|
/* #ifndef APP-NVUE */ |
||||||
|
display: block; |
||||||
|
/* #endif */ |
||||||
|
position: fixed; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
bottom: 0; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-content { |
||||||
|
/* #ifndef APP-NVUE */ |
||||||
|
display: block; |
||||||
|
/* #endif */ |
||||||
|
position: absolute; |
||||||
|
z-index: 1003; |
||||||
|
transition: all 0.25s linear; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer__scroll-view { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-left { |
||||||
|
top: 0; |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-right { |
||||||
|
right: 0; |
||||||
|
top: 0; |
||||||
|
bottom: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-top { |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-bottom { |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-center { |
||||||
|
@include vue-flex; |
||||||
|
flex-direction: column; |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
top: 0; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
opacity: 0; |
||||||
|
z-index: 99999; |
||||||
|
} |
||||||
|
|
||||||
|
.u-mode-center-box { |
||||||
|
min-width: 100rpx; |
||||||
|
min-height: 100rpx; |
||||||
|
/* #ifndef APP-NVUE */ |
||||||
|
display: block; |
||||||
|
/* #endif */ |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-content-visible.u-drawer-center { |
||||||
|
transform: scale(1); |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
|
||||||
|
.u-animation-zoom { |
||||||
|
transform: scale(1.15); |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-content-visible { |
||||||
|
transform: translate3D(0px, 0px, 0px) !important; |
||||||
|
} |
||||||
|
|
||||||
|
.u-close { |
||||||
|
position: absolute; |
||||||
|
z-index: 3; |
||||||
|
} |
||||||
|
|
||||||
|
.u-close--top-left { |
||||||
|
top: 30rpx; |
||||||
|
left: 30rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.u-close--top-right { |
||||||
|
top: 30rpx; |
||||||
|
right: 30rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.u-close--bottom-left { |
||||||
|
bottom: 30rpx; |
||||||
|
left: 30rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.u-close--bottom-right { |
||||||
|
right: 30rpx; |
||||||
|
bottom: 30rpx; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,155 @@ |
|||||||
|
## 导入即用 全端支持 |
||||||
|
|
||||||
|
### 有问题 + wx : zy597172583 标注来意 可评论 看到及时回复 |
||||||
|
1.使用方式 |
||||||
|
|
||||||
|
```javascript |
||||||
|
<template> |
||||||
|
<filter-popup :data="filterData" :form.sync="filterForm" v-model="popup.filter" title="全部筛选" height="1104rpx" @finsh="subFinsh"></filter-popup> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import FilterPopup from "@/components/filter-popup/filter-popup"; |
||||||
|
export default { |
||||||
|
components: { |
||||||
|
FilterPopup, |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
//筛选表单数据 |
||||||
|
filterData: [ |
||||||
|
{ |
||||||
|
children: false,//是否有子项 |
||||||
|
title: "意向度", |
||||||
|
key: "intention_type", //键名 接收对象名字 |
||||||
|
keyValue: "value", //获取的值是哪个 |
||||||
|
isRadio: true, //是否单选 否则多选 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: "一般意向", |
||||||
|
id: 1, |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "中意向度", |
||||||
|
id: 2, |
||||||
|
value: 2, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "高意向度", |
||||||
|
id: 3, |
||||||
|
value: 3, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
{ |
||||||
|
children: false,//是否有子项 |
||||||
|
title: "手机号码", |
||||||
|
key: "is_bind_phone", //键名 接收对象名字 |
||||||
|
keyValue: "value", //获取的值是哪个 |
||||||
|
isRadio: true, //是否单选 否则多选 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: "未绑定", |
||||||
|
value: 0, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "已绑定", |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
{ |
||||||
|
children: false,//是否有子项 |
||||||
|
title: "企微好友", |
||||||
|
key: "is_work_customer", //键名 接收对象名字 |
||||||
|
keyValue: "value", //获取的值是哪个 |
||||||
|
isRadio: true, //是否单选 否则多选 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: "未添加", |
||||||
|
value: 0, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "已添加", |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
{ |
||||||
|
children: true,//是否有子项 |
||||||
|
isRadio: false, //是否单选 |
||||||
|
title: "标签内容", |
||||||
|
key: "label", //键名 接收对象名字 |
||||||
|
keyValue: "id", //获取的值是哪个 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: "客户重要程度", |
||||||
|
id: 22, |
||||||
|
children: [ |
||||||
|
{ |
||||||
|
title: "一般意向2", |
||||||
|
id: 32, |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "一般意向3", |
||||||
|
id: 12, |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "客户重要程度2", |
||||||
|
id: 122, |
||||||
|
children: [ |
||||||
|
{ |
||||||
|
title: "一般意向2", |
||||||
|
id: 43, |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "一般意向3", |
||||||
|
id: 23, |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
], //筛选数据 |
||||||
|
filterForm: {}, //选中的表单 |
||||||
|
}; |
||||||
|
}, |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
2.组件props |
||||||
|
|
||||||
|
| 参数名 | 类型 | 介绍 | |
||||||
|
| ---------- | ------- | ------------------------------------------------- | |
||||||
|
| form | Object | .sync双向绑定的表单值 , 可传入显示初始哪些被选中 | |
||||||
|
| data | Array | 动态渲染选项的数据数组 | |
||||||
|
| title | String | 标题 | |
||||||
|
| height | String | 弹出层高度 单位 rpx px upx 百分比 vw等 | |
||||||
|
| themeColor | String | 组件主体颜色 默认:\#0066ff | |
||||||
|
| mask | Boolean | 是否显示弹出遮盖层 | |
||||||
|
|
||||||
|
3.data 参数 |
||||||
|
|
||||||
|
| 参数名 | 类型 | 是否必填 | 介绍 | |
||||||
|
| -------- | ------- | -------- | ------------------------------------------------------------ | |
||||||
|
| children | Boolean | 是 | 是否有子项 | |
||||||
|
| data | Array | 是 | 渲染出来的选项数据 | |
||||||
|
| isRadio | Boolean | 是 | 是否单选 单个选项指定,单选还是多选 | |
||||||
|
| title | String | 是 | 标签内容标题 | |
||||||
|
| key | String | 是 | 接收对象名字 会作为@finsh返回对象的键名 | |
||||||
|
| keyValue | String | 是 | 获取的值是哪个 自定义指定获取哪个键值 value还是id或者自己定义的 | |
||||||
|
|
||||||
|
4.事件 |
||||||
|
|
||||||
|
| 事件名 | 返回参数 | 简介 | |
||||||
|
| ------ | -------- | ----------------------------------------- | |
||||||
|
| finsh | Object | 点击确定时触发 返回参数为选中值的对象数组 | |
||||||
|
| close | 无 | 组件点击关闭时触发 | |
||||||
|
|
||||||
|
![image-20210730095456900](https://yzhsaas-cdn.qietongvip.com/asd.png) |
@ -0,0 +1,466 @@ |
|||||||
|
<template> |
||||||
|
<popup |
||||||
|
:mask="mask" |
||||||
|
border-radius="50" |
||||||
|
v-model="acceptValue" |
||||||
|
mode="bottom" |
||||||
|
class="filter-popup" |
||||||
|
:height="height" |
||||||
|
@close="close" |
||||||
|
:style="{ '--color': themeColor }" |
||||||
|
:mask-custom-style="{ background: 'rgba(0, 0, 0, 0.7)' }" |
||||||
|
> |
||||||
|
<view class="top-title flex-row-sb" v-if="showTop"> |
||||||
|
<view></view> <view class="popup-title flex-row-c-c">{{ title }}</view |
||||||
|
><text class="saasIcon flex-row-c-c" @click="close"></text> |
||||||
|
</view> |
||||||
|
|
||||||
|
<scroll-view class="select-scroll" scroll-y :style="{ height: `calc( ${height} - 120rpx - 152rpx )` }"> |
||||||
|
<view class="select-main"> |
||||||
|
<view class="select-item" v-for="(item, index) in data" :key="index"> |
||||||
|
<view class="title"> {{ item.title }} </view> |
||||||
|
<view class="tag-list" v-if="!item.children"> |
||||||
|
<view |
||||||
|
class="tag-item" |
||||||
|
:class="[acceptForm[item.key].includes(item2.value) ? 'select-on' : '']" |
||||||
|
v-for="(item2, index2) in item.data" |
||||||
|
:key="index2" |
||||||
|
@click="selectTagBuyValueOrId(item2, item.key, item.keyValue, item.isRadio)" |
||||||
|
> |
||||||
|
{{ item2.title }} |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<!-- 有childer --> |
||||||
|
<view class="select-childer" v-else v-for="item2 in item.data" :key="item2.id"> |
||||||
|
<view class="childer-title flex-row--c">{{ item2.title }}</view> |
||||||
|
<view class="tag-list"> |
||||||
|
<view |
||||||
|
class="tag-item" |
||||||
|
:class="[acceptForm[item.key].includes(item3.id) ? 'select-on' : '']" |
||||||
|
v-for="item3 in item2.children" |
||||||
|
:key="item3.id" |
||||||
|
@click="selectTagBuyValueOrId(item3, item.key, item.keyValue, item.isRadio)" |
||||||
|
> |
||||||
|
{{ item3.title }} |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</scroll-view> |
||||||
|
|
||||||
|
<view class="filter-button flex-row-c"> |
||||||
|
<view class="btn flex-row"> |
||||||
|
<view class="btn-1 flex-row-c-c" @click="reset">重置</view> |
||||||
|
<view class="btn-2 flex-row-c-c" @click="finsh">完成</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</popup> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import Popup from './components/popup.vue'; |
||||||
|
export default { |
||||||
|
components:{ |
||||||
|
Popup |
||||||
|
}, |
||||||
|
name: "filter-popup", |
||||||
|
props: { |
||||||
|
//选中的表单 |
||||||
|
form: { |
||||||
|
type: Object, |
||||||
|
default: () => {}, |
||||||
|
}, |
||||||
|
//主题颜色 |
||||||
|
themeColor: { |
||||||
|
type: String, |
||||||
|
default: "#0066ff", |
||||||
|
}, |
||||||
|
//渲染数据 |
||||||
|
data: { |
||||||
|
type: Array, |
||||||
|
default: () => [], |
||||||
|
}, |
||||||
|
//标题 |
||||||
|
title: { |
||||||
|
type: String, |
||||||
|
default: "请选择", |
||||||
|
}, |
||||||
|
value: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
mask: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
height: { |
||||||
|
type: String, |
||||||
|
default: "600rpx", |
||||||
|
}, |
||||||
|
//是否显示退出按钮 |
||||||
|
showTop: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
// 接收表单 |
||||||
|
acceptForm: { |
||||||
|
get() { |
||||||
|
this.originForm = JSON.parse(JSON.stringify(this.form)) |
||||||
|
if (Object.keys(this.form).length) { |
||||||
|
return this.form; |
||||||
|
} else { |
||||||
|
let obj = {}; |
||||||
|
this.data.forEach((item) => { |
||||||
|
obj[item.key] = []; |
||||||
|
}); |
||||||
|
return obj; |
||||||
|
} |
||||||
|
}, |
||||||
|
set(nval) { |
||||||
|
// console.log("set Form :>> ", nval); |
||||||
|
this.$emit("update:form", nval); |
||||||
|
}, |
||||||
|
}, |
||||||
|
acceptValue: { |
||||||
|
get() { |
||||||
|
return this.value; |
||||||
|
}, |
||||||
|
set(nval) { |
||||||
|
this.$emit("input", nval); |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
originForm: {} |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
//选择存value 还是id |
||||||
|
selectTagBuyValueOrId(item, key, keyValue, isRadio) { |
||||||
|
//如果是单选 |
||||||
|
if (isRadio) { |
||||||
|
if (keyValue == "value") { |
||||||
|
if (this.acceptForm[key].some((value) => value === item.value)) { |
||||||
|
this.acceptForm[key] = this.acceptForm[key].filter((value) => value !== item.value); |
||||||
|
return; |
||||||
|
} |
||||||
|
this.acceptForm[key] = []; |
||||||
|
this.acceptForm[key].push(item.value); |
||||||
|
} else { |
||||||
|
if (this.acceptForm[key].some((id) => id === item.id)) { |
||||||
|
this.acceptForm[key] = this.acceptForm[key].filter((id) => id !== item.id); |
||||||
|
return; |
||||||
|
} |
||||||
|
this.acceptForm[key] = []; |
||||||
|
this.acceptForm[key].push(item.id); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (keyValue == "value") { |
||||||
|
this.acceptForm[key].some((value) => value === item.value) |
||||||
|
? (this.acceptForm[key] = this.acceptForm[key].filter((value) => value !== item.value)) |
||||||
|
: this.acceptForm[key].push(item.value); |
||||||
|
} else { |
||||||
|
this.acceptForm[key].some((id) => id === item.id) |
||||||
|
? (this.acceptForm[key] = this.acceptForm[key].filter((id) => id !== item.id)) |
||||||
|
: this.acceptForm[key].push(item.id); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
this.acceptForm = this.acceptForm; |
||||||
|
}, |
||||||
|
// 点击完成 |
||||||
|
finsh() { |
||||||
|
this.$emit("finsh", this.acceptForm); |
||||||
|
this.$emit("input", false); |
||||||
|
}, |
||||||
|
close() { |
||||||
|
this.$emit("input", false); |
||||||
|
this.$emit("close"); |
||||||
|
}, |
||||||
|
//重置 |
||||||
|
reset() { |
||||||
|
this.acceptForm = {} |
||||||
|
}, |
||||||
|
}, |
||||||
|
}; |
||||||
|
</script> |
||||||
|
<style lang="scss" scoped> |
||||||
|
@font-face { |
||||||
|
font-family: 'iconfont'; /* Project id 2729410 */ |
||||||
|
src: url('https://at.alicdn.com/t/font_2729410_3nhq3ibbcqg.woff2?t=1628330097695') format('woff2'), |
||||||
|
url('https://at.alicdn.com/t/font_2729410_3nhq3ibbcqg.woff?t=1628330097695') format('woff'), |
||||||
|
url('https://at.alicdn.com/t/font_2729410_3nhq3ibbcqg.ttf?t=1628330097695') format('truetype'); |
||||||
|
} |
||||||
|
.saasIcon { |
||||||
|
font-family: "iconfont" !important; |
||||||
|
font-style: normal; |
||||||
|
-webkit-font-smoothing: antialiased; |
||||||
|
-webkit-text-stroke-width: 0.2px; |
||||||
|
-moz-osx-font-smoothing: grayscale; |
||||||
|
} |
||||||
|
.filter-popup { |
||||||
|
color: #000000; |
||||||
|
.top-title { |
||||||
|
font-weight: bold; |
||||||
|
height: 90rpx; |
||||||
|
margin-left: 70rpx; |
||||||
|
font-size: 30rpx; |
||||||
|
margin-top: 20rpx; |
||||||
|
.popup-title { |
||||||
|
height: 100%; |
||||||
|
} |
||||||
|
.saasIcon { |
||||||
|
// width: 150rpx; |
||||||
|
height: 100%; |
||||||
|
padding-right: 70rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.select-scroll { |
||||||
|
} |
||||||
|
.select-main { |
||||||
|
padding: 0 32rpx; |
||||||
|
.select-item { |
||||||
|
.title { |
||||||
|
font-weight: bold; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #000000; |
||||||
|
padding-top: 30rpx; |
||||||
|
} |
||||||
|
.tag-list { |
||||||
|
display: flex; |
||||||
|
flex-wrap: wrap; |
||||||
|
margin-left: -12rpx; |
||||||
|
.tag-item { |
||||||
|
margin-top: 20rpx; |
||||||
|
padding: 10rpx 40rpx; |
||||||
|
font-size: 26rpx; |
||||||
|
background: #f5f5f5; |
||||||
|
color: #484848; |
||||||
|
border-radius: 36rpx; |
||||||
|
margin-left: 12rpx; |
||||||
|
&.select-on { |
||||||
|
background: var(--color); |
||||||
|
color: #fff; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.select-childer { |
||||||
|
.childer-title { |
||||||
|
color: #484848; |
||||||
|
font-size: 28rpx; |
||||||
|
border-bottom: 1px solid #f5f5f5; |
||||||
|
height: 80rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.filter-button { |
||||||
|
width: 100%; |
||||||
|
height: 152rpx; |
||||||
|
background: #ffffff; |
||||||
|
box-shadow: 0px -3px 12px rgba(0, 0, 0, 0.06); |
||||||
|
position: fixed; |
||||||
|
bottom: 0; |
||||||
|
.btn { |
||||||
|
border-radius: 100rpx; |
||||||
|
margin-top: 26rpx; |
||||||
|
width: 680rpx; |
||||||
|
height: 80rpx; |
||||||
|
color: #ffffff; |
||||||
|
font-size: 28rpx; |
||||||
|
overflow: hidden; |
||||||
|
.btn-1 { |
||||||
|
flex: 1; |
||||||
|
background: linear-gradient(271deg, #2698fb 0%, #84c6ff 100%); |
||||||
|
} |
||||||
|
.btn-2 { |
||||||
|
flex: 1; |
||||||
|
background: linear-gradient(90deg, #0066ff 0%, #1371ff 100%); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 自定义css |
||||||
|
.flex-row { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-c { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row--c { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-c-c { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-sb-c { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-sb-t { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: flex-start; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-sb-b { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: flex-end; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-c-sb { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: space-between; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-sb { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-l { |
||||||
|
display: flex; |
||||||
|
justify-content: flex-start; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-l-c { |
||||||
|
display: flex; |
||||||
|
justify-content: flex-start; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-c-t { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: flex-start; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-r-c { |
||||||
|
display: flex; |
||||||
|
justify-content: flex-end; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-r { |
||||||
|
display: flex; |
||||||
|
justify-content: flex-end; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row--b { |
||||||
|
display: flex; |
||||||
|
align-items: flex-end; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-c { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col--c { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-c-c { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-sb-c { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-c-sb { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
align-items: space-between; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-sb { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: space-between; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-t-c { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: flex-start; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-c-l { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
align-items: flex-start; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-t { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: flex-start; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-b { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: flex-end; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-b-c { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: flex-end; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-c-l { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
align-items: flex-end; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col--l { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: flex-start; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col--r { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: flex-end; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,12 @@ |
|||||||
|
{ |
||||||
|
"id": "filter-popup", |
||||||
|
"name": "筛选 菜单 筛选菜单 上拉筛选 ", |
||||||
|
"version": "1.0.4", |
||||||
|
"description": "筛选菜单,支持单选和多选 , 选择后的数据通过.sync双向绑定,全端支持 导入即用", |
||||||
|
"keywords": [ |
||||||
|
"筛选", |
||||||
|
"菜单", |
||||||
|
"筛选菜单", |
||||||
|
"上拉筛选" |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<view class="input"> |
||||||
|
<uni-easyinput v-model.trim="account" placeholder="请输入账号"></uni-easyinput> |
||||||
|
</view> |
||||||
|
<button type="primary" @click="submit">确认</button> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { queryUserInfoDetails, updatePersonCenter } from '@/apis/modules/user.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
account: '', |
||||||
|
hrUserInfo: {}, |
||||||
|
personalFileList: [], |
||||||
|
userAccountList: [], |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
this.getInfo() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 获取个人信息 |
||||||
|
getInfo() { |
||||||
|
queryUserInfoDetails().then(({ result }) => { |
||||||
|
this.hrUserInfo = result.hrUserInfo |
||||||
|
this.userAccountList = result.userAccountList |
||||||
|
}).catch(e => {}) |
||||||
|
}, |
||||||
|
submit() { |
||||||
|
const { account, hrUserInfo, userAccountList } = this |
||||||
|
if(!account) return this.$util.errMsg('请输入账号') |
||||||
|
userAccountList[0].userId = hrUserInfo.userId |
||||||
|
userAccountList[0].account = account |
||||||
|
updatePersonCenter({ |
||||||
|
hrUserInfo, |
||||||
|
userAccountList |
||||||
|
}).then(res => { |
||||||
|
this.$util.sucMsg('修改成功!') |
||||||
|
setTimeout(() => { |
||||||
|
uni.reLaunch({ |
||||||
|
url: '../person/person' |
||||||
|
}) |
||||||
|
}, 1000) |
||||||
|
}).catch(e => {}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
padding: 20px; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
/deep/.input { |
||||||
|
margin-bottom: 15px; |
||||||
|
.is-input-border { |
||||||
|
border-color: #dedede !important; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,130 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<view class="input"> |
||||||
|
<uni-easyinput v-model="form.email" placeholder="请填写你的邮箱" :clearable="false" /> |
||||||
|
</view> |
||||||
|
<view class="input code-wrap"> |
||||||
|
<uni-easyinput class="code" v-model="form.code" placeholder="验证码" :clearable="false" /> |
||||||
|
<view class="send-code" @click="sendCode" :disabled="codeDisabled">{{ btnText }}</view> |
||||||
|
</view> |
||||||
|
<button type="primary" @click="submit">确认</button> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { queryUserInfoDetails, bindPhoneOrEmail, sendPhoneOrEmailCode } from '@/apis/modules/user.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
userId: '', |
||||||
|
form: { |
||||||
|
email: '', |
||||||
|
code: '' |
||||||
|
}, |
||||||
|
codeDisabled: false, |
||||||
|
phoneTimer: null, |
||||||
|
phoneOpener: '', |
||||||
|
btnText: '发送验证码', |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
this.getInfo() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 获取个人信息 |
||||||
|
getInfo() { |
||||||
|
queryUserInfoDetails().then(({ result }) => { |
||||||
|
this.userId = result.hrUserInfo.userId |
||||||
|
}).catch(e => {}) |
||||||
|
}, |
||||||
|
// 发送验证码 |
||||||
|
sendCode() { |
||||||
|
const { email } = this.form |
||||||
|
if (!email) return this.$util.errMsg('请输入邮箱') |
||||||
|
if (!/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(email) && !/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(email)) return this.$util.errMsg('请输入正确的请输入邮箱') |
||||||
|
sendPhoneOrEmailCode({ |
||||||
|
userId: this.userId, |
||||||
|
email, |
||||||
|
types: 1 |
||||||
|
}).then(({ message }) => { |
||||||
|
if (message.opener) { |
||||||
|
this.phoneCountdown() |
||||||
|
this.phoneOpener = message.opener |
||||||
|
} else { |
||||||
|
this.$util.errMsg(message) |
||||||
|
} |
||||||
|
}).catch(res => {}) |
||||||
|
}, |
||||||
|
// 验证码倒计时 |
||||||
|
phoneCountdown() { |
||||||
|
let count = 60 |
||||||
|
if (!this.phoneTimer) { |
||||||
|
this.codeDisabled = true |
||||||
|
this.phoneTimer = setInterval(() => { |
||||||
|
if (count > 0) { |
||||||
|
count-- |
||||||
|
this.btnText = `${count}秒后重试` |
||||||
|
} else { |
||||||
|
this.codeDisabled = false |
||||||
|
clearInterval(this.phoneTimer) |
||||||
|
this.phoneTimer = null |
||||||
|
this.btnText = `发送验证码` |
||||||
|
} |
||||||
|
}, 1000) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 提交 |
||||||
|
submit() { |
||||||
|
const { email, code } = this.form |
||||||
|
if (!email) return this.$util.errMsg('请输入邮箱') |
||||||
|
if (!code) return this.$util.errMsg('请输入验证码') |
||||||
|
bindPhoneOrEmail({ |
||||||
|
userId: this.userId, |
||||||
|
email, |
||||||
|
types: 1, |
||||||
|
code, |
||||||
|
opener: this.phoneOpener |
||||||
|
}).then(res => { |
||||||
|
this.$util.sucMsg('修改成功!') |
||||||
|
setTimeout(() => { |
||||||
|
uni.reLaunch({ |
||||||
|
url: '../person/person' |
||||||
|
}) |
||||||
|
}, 1500) |
||||||
|
}).catch(res => {}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
padding: 20px; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
/deep/.input { |
||||||
|
margin-bottom: 15px; |
||||||
|
.is-input-border { |
||||||
|
border-color: #dedede !important; |
||||||
|
} |
||||||
|
} |
||||||
|
.input { |
||||||
|
margin-bottom: 20px; |
||||||
|
} |
||||||
|
.code-wrap { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
.code { |
||||||
|
flex: 1; |
||||||
|
} |
||||||
|
.send-code { |
||||||
|
width: 100px; |
||||||
|
margin-left: 20px; |
||||||
|
text-align: center; |
||||||
|
color: #4386ff; |
||||||
|
font-size: 12px; |
||||||
|
line-height: 36px; |
||||||
|
border: 1px solid #4386ff; |
||||||
|
border-radius: 5px; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,130 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<view class="input"> |
||||||
|
<uni-easyinput v-model="form.phone" placeholder="请填写你的手机号" :clearable="false" /> |
||||||
|
</view> |
||||||
|
<view class="input code-wrap"> |
||||||
|
<uni-easyinput class="code" v-model="form.code" placeholder="验证码" :clearable="false" /> |
||||||
|
<view class="send-code" @click="sendCode" :disabled="codeDisabled">{{ btnText }}</view> |
||||||
|
</view> |
||||||
|
<button type="primary" @click="submit">确认</button> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { queryUserInfoDetails, bindPhoneOrEmail, sendPhoneOrEmailCode } from '@/apis/modules/user.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
userId: '', |
||||||
|
form: { |
||||||
|
phone: '', |
||||||
|
code: '' |
||||||
|
}, |
||||||
|
codeDisabled: false, |
||||||
|
phoneTimer: null, |
||||||
|
phoneOpener: '', |
||||||
|
btnText: '发送验证码', |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
this.getInfo() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 获取个人信息 |
||||||
|
getInfo() { |
||||||
|
queryUserInfoDetails().then(({ result }) => { |
||||||
|
this.userId = result.hrUserInfo.userId |
||||||
|
}).catch(e => {}) |
||||||
|
}, |
||||||
|
// 发送验证码 |
||||||
|
sendCode() { |
||||||
|
const { phone } = this.form |
||||||
|
if (!phone) return this.$util.errMsg('请输入手机号') |
||||||
|
if (!/^1[3456789]\d{9}$/.test(phone) && !/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(phone)) return this.$util.errMsg('请输入正确的手机号') |
||||||
|
sendPhoneOrEmailCode({ |
||||||
|
userId: this.userId, |
||||||
|
phone, |
||||||
|
types: 2 |
||||||
|
}).then(({ message }) => { |
||||||
|
if (message.opener) { |
||||||
|
this.phoneCountdown() |
||||||
|
this.phoneOpener = message.opener |
||||||
|
} else { |
||||||
|
this.$util.errMsg(message) |
||||||
|
} |
||||||
|
}).catch(res => {}) |
||||||
|
}, |
||||||
|
// 验证码倒计时 |
||||||
|
phoneCountdown() { |
||||||
|
let count = 60 |
||||||
|
if (!this.phoneTimer) { |
||||||
|
this.codeDisabled = true |
||||||
|
this.phoneTimer = setInterval(() => { |
||||||
|
if (count > 0) { |
||||||
|
count-- |
||||||
|
this.btnText = `${count}秒后重试` |
||||||
|
} else { |
||||||
|
this.codeDisabled = false |
||||||
|
clearInterval(this.phoneTimer) |
||||||
|
this.phoneTimer = null |
||||||
|
this.btnText = `发送验证码` |
||||||
|
} |
||||||
|
}, 1000) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 提交 |
||||||
|
submit() { |
||||||
|
const { phone, code } = this.form |
||||||
|
if (!phone) return this.$util.errMsg('请输入手机号') |
||||||
|
if (!code) return this.$util.errMsg('请输入验证码') |
||||||
|
bindPhoneOrEmail({ |
||||||
|
userId: this.userId, |
||||||
|
phone, |
||||||
|
types: 2, |
||||||
|
code, |
||||||
|
opener: this.phoneOpener |
||||||
|
}).then(res => { |
||||||
|
this.$util.sucMsg('修改成功!') |
||||||
|
setTimeout(() => { |
||||||
|
uni.reLaunch({ |
||||||
|
url: '../person/person' |
||||||
|
}) |
||||||
|
}, 1500) |
||||||
|
}).catch(res => {}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
padding: 20px; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
/deep/.input { |
||||||
|
margin-bottom: 15px; |
||||||
|
.is-input-border { |
||||||
|
border-color: #dedede !important; |
||||||
|
} |
||||||
|
} |
||||||
|
.input { |
||||||
|
margin-bottom: 20px; |
||||||
|
} |
||||||
|
.code-wrap { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
.code { |
||||||
|
flex: 1; |
||||||
|
} |
||||||
|
.send-code { |
||||||
|
width: 100px; |
||||||
|
margin-left: 20px; |
||||||
|
text-align: center; |
||||||
|
color: #4386ff; |
||||||
|
font-size: 12px; |
||||||
|
line-height: 36px; |
||||||
|
border: 1px solid #4386ff; |
||||||
|
border-radius: 5px; |
||||||
|
} |
||||||
|
</style> |
Loading…
Reference in new issue