init
This commit is contained in:
348
components/zy/addAllHouse.vue
Normal file
348
components/zy/addAllHouse.vue
Normal file
@@ -0,0 +1,348 @@
|
||||
<template>
|
||||
<view>
|
||||
<scroll-view scroll-y="true" class="scroll-wrapper">
|
||||
<view>
|
||||
<view class="wrap">
|
||||
<u-form ref="uForm">
|
||||
<u-form-item :label-position="labelPosition" label="户型" label-width="150" required>
|
||||
<u-input :border="border" type="select" :select-open="selectShow" v-model="houseTypeVo" placeholder="请选择户型" @click="selectShow = true"></u-input>
|
||||
</u-form-item>
|
||||
<u-form-item label-width="150" :label-position="labelPosition" label="面积" required>
|
||||
<u-input :border="border" placeholder="请输入面积" v-model="model.houseArea" type="number"></u-input>
|
||||
</u-form-item>
|
||||
<u-form-item label-width="150" :label-position="labelPosition" label="租金" required>
|
||||
<u-input :border="border" placeholder="请输入租金" v-model="model.price" type="number"></u-input>
|
||||
</u-form-item>
|
||||
<u-form-item label-width="150" :label-position="labelPosition" label="起租日期">
|
||||
<view class="dateBtn" @click="dateClick">
|
||||
{{dateLabel}}<u-icon name="arrow-right"></u-icon>
|
||||
</view>
|
||||
</u-form-item>
|
||||
<view class="custom-gap"></view>
|
||||
<u-form-item :label-position="labelPosition" label="房源图片" label-width="150" required>
|
||||
<u-upload
|
||||
:custom-btn="true" ref="uUpload" :auto-upload="true" :action="action" :max-size="10 * 1024 * 1024" max-count="9" width="160" height="160" :size-type="siteType">
|
||||
<view slot="addBtn" class="slot-btn" hover-class="slot-btn__hover" hover-stay-time="150">
|
||||
<u-icon name="plus" size="60" :color="$u.color['lightColor']"></u-icon>
|
||||
</view>
|
||||
</u-upload>
|
||||
</u-form-item>
|
||||
<u-form-item label-width="150" :label-position="labelPosition" label="房源描述">
|
||||
<u-input type="textarea" :border="border" placeholder="请填写房屋描述" v-model="model.introduce" />
|
||||
</u-form-item>
|
||||
<u-form-item label-width="150" :label-position="labelPosition" label="房源亮点" required>
|
||||
<u-checkbox-group @change="checkboxGroupChange" :width="radioCheckWidth" :wrap="radioCheckWrap">
|
||||
<u-checkbox v-model="item.checked" v-for="(item, index) in checkboxList" :key="index" :name="item.name">{{ item.name }}</u-checkbox>
|
||||
</u-checkbox-group>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<u-select mode="mutil-column" :list="selectList" v-model="selectShow" @confirm="selectConfirm"></u-select>
|
||||
<u-action-sheet :list="actionSheetList" v-model="actionSheetShow" @click="actionSheetCallback"></u-action-sheet>
|
||||
<u-calendar v-model="show" :mode="mode" @change="changeDate" max-date="2100-01-01"></u-calendar>
|
||||
<view class="bottom-btn">
|
||||
<u-button type="primary" @click="submit">提交</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import config from "@/common/config.js" // 全局配置文件
|
||||
export default {
|
||||
props:{
|
||||
model:Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
houseTypeVo: '',
|
||||
show: false,
|
||||
mode: 'date',
|
||||
selectList: [
|
||||
[
|
||||
{
|
||||
value: '一室',
|
||||
label: '一室'
|
||||
},
|
||||
{
|
||||
value: '二室',
|
||||
label: '二室'
|
||||
},
|
||||
{
|
||||
value: '三室',
|
||||
label: '三室'
|
||||
},
|
||||
{
|
||||
value: '四室',
|
||||
label: '四室'
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
value: '',
|
||||
label: ''
|
||||
},
|
||||
{
|
||||
value: '一厅',
|
||||
label: '一厅'
|
||||
},
|
||||
{
|
||||
value: '二厅',
|
||||
label: '二厅'
|
||||
},
|
||||
{
|
||||
value: '三厅',
|
||||
label: '三厅'
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
value: '',
|
||||
label: ''
|
||||
},
|
||||
{
|
||||
value: '一卫',
|
||||
label: '一卫'
|
||||
},
|
||||
{
|
||||
value: '二卫',
|
||||
label: '二卫'
|
||||
}
|
||||
],
|
||||
],
|
||||
border: false,
|
||||
check: false,
|
||||
selectStatus: 'close',
|
||||
checkboxList: [
|
||||
{
|
||||
name: '看房方便',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '独卫',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '独立阳台',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '智能锁',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '可短租',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '首次出租',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '免物业费',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '民用水电',
|
||||
checked: false,
|
||||
disabled: false
|
||||
}
|
||||
],
|
||||
actionSheetList: [
|
||||
{
|
||||
text: '电梯房'
|
||||
},
|
||||
{
|
||||
text: '楼梯房'
|
||||
}
|
||||
],
|
||||
selectShow: false,
|
||||
radioCheckWidth: 'auto',
|
||||
radioCheckWrap: false,
|
||||
labelPosition: 'left',
|
||||
errorType: ['toast'],
|
||||
actionSheetShow: false,
|
||||
dateLabel:'随时入住',
|
||||
// 服务器地址
|
||||
action: config.staticUrl + '/common/upload',
|
||||
siteType:['compressed'],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
model: {
|
||||
handler(newName, oldName) {
|
||||
this.houseTypeVo = newName.houseType
|
||||
// 回显房源亮点
|
||||
if(this.model.featureList){
|
||||
this.checkboxList.forEach(item=>{
|
||||
this.model.featureList.forEach(feature=>{
|
||||
if(feature.feature == item.name){
|
||||
item.checked=true
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
if(this.$u.test.isEmpty(this.model.houseType)){
|
||||
return this.$mytip.toast('请选择户型')
|
||||
}
|
||||
if(this.$u.test.isEmpty(this.model.houseArea)){
|
||||
return this.$mytip.toast('请输入面积')
|
||||
}
|
||||
if(this.$u.test.isEmpty(this.model.price)){
|
||||
return this.$mytip.toast('请输入租金')
|
||||
}
|
||||
let files = [];
|
||||
// 通过filter,筛选出上传进度为100的文件(因为某些上传失败的文件,进度值不为100,这个是可选的操作)
|
||||
files = this.$refs.uUpload.lists.filter(val => {
|
||||
return val.progress == 100;
|
||||
})
|
||||
if(this.$u.test.isEmpty(files)){
|
||||
return this.$mytip.toast('请至少选择一张房源图片')
|
||||
}
|
||||
let imageList = files.map(val => {
|
||||
return {
|
||||
imageName: val.response.realName,
|
||||
imagePath: val.response.fileName,
|
||||
imgUrl: val.response.url,
|
||||
imageSize: val.file.size
|
||||
}
|
||||
})
|
||||
this.model.imageList = imageList
|
||||
if(this.$u.test.isEmpty(this.model.featureList)){
|
||||
return this.$mytip.toast('请至少选择一个房源亮点')
|
||||
}
|
||||
let url = "api/houseApi/saveHouse";
|
||||
if(this.model.id){
|
||||
url = "api/houseApi/updateHouse";
|
||||
}
|
||||
this.model.publishId = uni.getStorageSync('lifeData').vuex_user.user.userId;
|
||||
this.$u.post(url,this.model).then(data => {
|
||||
// uni.$emit('findIndexHouseList', {});
|
||||
// this.$u.route({
|
||||
// type: 'tab',url: '/pages/index/index'
|
||||
// })
|
||||
this.$u.route({
|
||||
url: 'pages/center/order',
|
||||
})
|
||||
});
|
||||
},
|
||||
// 选择类型回调
|
||||
selectConfirm(e) {
|
||||
this.model.houseType = ''
|
||||
e.map((val, index) => {
|
||||
if(index == 0){
|
||||
this.model.houseNum = val.label;
|
||||
}else if(index == 1){
|
||||
this.model.houseHall = val.label;
|
||||
}else if(index == 2){
|
||||
this.model.toiletNum = val.label;
|
||||
}
|
||||
this.model.houseType += val.label;
|
||||
this.houseTypeVo = this.model.houseType
|
||||
})
|
||||
},
|
||||
// 点击actionSheet回调
|
||||
actionSheetCallback(index) {
|
||||
uni.hideKeyboard();
|
||||
this.model.stepType = this.actionSheetList[index].text;
|
||||
},
|
||||
// checkbox选择发生变化
|
||||
checkboxGroupChange(e) {
|
||||
let featureList = e.map(val => {
|
||||
return {
|
||||
feature: val
|
||||
}
|
||||
})
|
||||
this.model.featureList = featureList
|
||||
},
|
||||
borderChange(index) {
|
||||
this.border = !index;
|
||||
},
|
||||
labelPositionChange(index) {
|
||||
this.labelPosition = index == 0 ? 'left' : 'top';
|
||||
},
|
||||
codeChange(text) {
|
||||
this.codeTips = text;
|
||||
},
|
||||
dateClick(){
|
||||
this.show = true
|
||||
},
|
||||
changeDate(e){
|
||||
this.model.startDate = e.result
|
||||
this.dateLabel = e.result
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page{
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss">
|
||||
|
||||
.wrap {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.scroll-wrapper{
|
||||
position: absolute;
|
||||
left: 0rpx;
|
||||
right: 0rpx;
|
||||
top: 0rpx;
|
||||
bottom: 120rpx;
|
||||
}
|
||||
|
||||
.bottom-btn {
|
||||
position: fixed;
|
||||
bottom: 8rpx;
|
||||
width: 100%;
|
||||
padding: 30rpx;
|
||||
border-top: 1rpx solid #ccc;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.dateBtn{
|
||||
position: absolute;
|
||||
right: 0rpx;
|
||||
top:10rpx;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.slot-btn {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: rgb(244, 245, 246);
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.slot-btn__hover {
|
||||
background-color: rgb(235, 236, 238);
|
||||
}
|
||||
|
||||
.custom-gap{
|
||||
width: 1000rpx;
|
||||
height: 10rpx;
|
||||
margin: 0 -200rpx 0 -200rpx;
|
||||
background-color: rgb(235, 236, 238);
|
||||
}
|
||||
</style>
|
||||
342
components/zy/addSubHouse.vue
Normal file
342
components/zy/addSubHouse.vue
Normal file
@@ -0,0 +1,342 @@
|
||||
<template>
|
||||
<view>
|
||||
<scroll-view scroll-y="true" class="scroll-wrapper">
|
||||
<view>
|
||||
<view class="wrap">
|
||||
<u-form ref="uForm">
|
||||
<u-form-item :label-position="labelPosition" label="出租房间" label-width="150" required>
|
||||
<u-input :border="border" type="select" :select-open="selectShow" v-model="roomLabelVo" placeholder="请选择出租房间" @click="selectShow = true"></u-input>
|
||||
</u-form-item>
|
||||
|
||||
<u-form-item label-width="150" :label-position="labelPosition" label="房间号" required>
|
||||
<u-input :border="border" placeholder="如 A01..." v-model="model.roomCode" type="text"></u-input>
|
||||
</u-form-item>
|
||||
<u-form-item label-width="150" :label-position="labelPosition" label="房屋面积" required>
|
||||
<u-input :border="border" placeholder="请输入房屋面积" v-model="model.roomArea" type="number"></u-input>
|
||||
</u-form-item>
|
||||
<u-form-item label-width="150" :label-position="labelPosition" label="朝向" >
|
||||
<u-input :border="border" type="select" :select-open="directionShow" v-model="directionVo" placeholder="请选择朝向" @click="directionShow = true"></u-input>
|
||||
</u-form-item>
|
||||
</u-form-item>
|
||||
<u-form-item label-width="150" :label-position="labelPosition" label="租金" required>
|
||||
<u-input :border="border" placeholder="请输入租金" v-model="model.price" type="number"></u-input>
|
||||
</u-form-item>
|
||||
<u-form-item label-width="150" :label-position="labelPosition" label="起租日期">
|
||||
<view class="dateBtn" @click="dateClick">
|
||||
{{dateLabel}}<u-icon name="arrow-right"></u-icon>
|
||||
</view>
|
||||
</u-form-item>
|
||||
<view class="custom-gap"></view>
|
||||
<u-form-item :label-position="labelPosition" label="房源图片" label-width="150" required>
|
||||
<u-upload
|
||||
:custom-btn="true" ref="uUpload" :auto-upload="true" :action="action" :max-size="10 * 1024 * 1024" max-count="9" width="160" height="160" :size-type="siteType">
|
||||
<view slot="addBtn" class="slot-btn" hover-class="slot-btn__hover" hover-stay-time="150">
|
||||
<u-icon name="plus" size="60" :color="$u.color['lightColor']"></u-icon>
|
||||
</view>
|
||||
</u-upload>
|
||||
</u-form-item>
|
||||
<u-form-item label-width="150" :label-position="labelPosition" label="房源描述">
|
||||
<u-input type="textarea" :border="border" placeholder="请填写房屋描述" v-model="model.introduce" />
|
||||
</u-form-item>
|
||||
<u-form-item label-width="150" :label-position="labelPosition" label="房源亮点" required>
|
||||
<u-checkbox-group @change="checkboxGroupChange" :width="radioCheckWidth" :wrap="radioCheckWrap">
|
||||
<u-checkbox v-model="item.checked" v-for="(item, index) in checkboxList" :key="index" :name="item.name">{{ item.name }}</u-checkbox>
|
||||
</u-checkbox-group>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<u-select mode="single-column" :list="selectList" v-model="selectShow" @confirm="selectConfirm"></u-select>
|
||||
<u-select mode="single-column" :list="directionList" v-model="directionShow" @confirm="directionConfirm"></u-select>
|
||||
<u-action-sheet :list="actionSheetList" v-model="actionSheetShow" @click="actionSheetCallback"></u-action-sheet>
|
||||
<u-calendar v-model="show" :mode="mode" @change="changeDate" max-date="2100-01-01"></u-calendar>
|
||||
<view class="bottom-btn">
|
||||
<u-button type="primary" @click="submit">提交</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import config from "@/common/config.js" // 全局配置文件
|
||||
export default {
|
||||
props:{
|
||||
model:Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
roomLabelVo:'',
|
||||
directionVo:'',
|
||||
show: false,
|
||||
mode: 'date',
|
||||
selectList: [
|
||||
{
|
||||
value: '1',
|
||||
label: '主卧'
|
||||
},
|
||||
{
|
||||
value: '2',
|
||||
label: '次卧'
|
||||
}
|
||||
],
|
||||
directionList:[
|
||||
{
|
||||
value: '东',
|
||||
label: '东'
|
||||
},
|
||||
{
|
||||
value: '南',
|
||||
label: '南'
|
||||
},
|
||||
{
|
||||
value: '西',
|
||||
label: '西'
|
||||
},
|
||||
{
|
||||
value: '北',
|
||||
label: '北'
|
||||
},
|
||||
],
|
||||
border: false,
|
||||
check: false,
|
||||
checkboxList: [
|
||||
{
|
||||
name: '看房方便',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '独卫',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '独立阳台',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '智能锁',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '可短租',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '首次出租',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '免物业费',
|
||||
checked: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '民用水电',
|
||||
checked: false,
|
||||
disabled: false
|
||||
}
|
||||
],
|
||||
actionSheetList: [
|
||||
{
|
||||
text: '电梯房'
|
||||
},
|
||||
{
|
||||
text: '楼梯房'
|
||||
}
|
||||
],
|
||||
selectShow: false,
|
||||
directionShow: false,
|
||||
radioCheckWidth: 'auto',
|
||||
radioCheckWrap: false,
|
||||
labelPosition: 'left',
|
||||
errorType: ['toast'],
|
||||
actionSheetShow: false,
|
||||
dateLabel:'随时入住',
|
||||
// 图片服务器地址
|
||||
action: config.staticUrl + '/common/upload',
|
||||
siteType:['compressed'],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
model: {
|
||||
handler(newName, oldName) {
|
||||
this.roomLabelVo = newName.roomLabel
|
||||
// 回显房源亮点
|
||||
if(this.model.featureList){
|
||||
this.checkboxList.forEach(item=>{
|
||||
this.model.featureList.forEach(feature=>{
|
||||
if(feature.feature == item.name){
|
||||
item.checked=true
|
||||
}
|
||||
})
|
||||
})
|
||||
this.directionVo = newName.direction
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
if(this.$u.test.isEmpty(this.model.roomType)){
|
||||
return this.$mytip.toast('请选择租房间')
|
||||
}
|
||||
if(this.$u.test.isEmpty(this.model.roomCode)){
|
||||
return this.$mytip.toast('请输入房间号')
|
||||
}
|
||||
if(this.$u.test.isEmpty(this.model.roomArea)){
|
||||
return this.$mytip.toast('请输入房屋面积')
|
||||
}
|
||||
// if(this.$u.test.isEmpty(this.model.direction)){
|
||||
// return this.$mytip.toast('请输入朝向')
|
||||
// }
|
||||
if(this.$u.test.isEmpty(this.model.price)){
|
||||
return this.$mytip.toast('请输入租金')
|
||||
}
|
||||
let files = [];
|
||||
// 通过filter,筛选出上传进度为100的文件(因为某些上传失败的文件,进度值不为100,这个是可选的操作)
|
||||
files = this.$refs.uUpload.lists.filter(val => {
|
||||
return val.progress == 100;
|
||||
})
|
||||
if(this.$u.test.isEmpty(files)){
|
||||
return this.$mytip.toast('请至少选择一张房源图片')
|
||||
}
|
||||
let imageList = files.map(val => {
|
||||
return {
|
||||
imageName: val.response.realName,
|
||||
imagePath: val.response.fileName,
|
||||
imgUrl: val.response.url,
|
||||
imageSize: val.file.size
|
||||
}
|
||||
})
|
||||
this.model.imageList = imageList
|
||||
if(this.$u.test.isEmpty(this.model.featureList)){
|
||||
return this.$mytip.toast('请至少选择一个房源亮点')
|
||||
}
|
||||
let url = "api/houseApi/saveHouse";
|
||||
if(this.model.id){
|
||||
url = "api/houseApi/updateHouse";
|
||||
}
|
||||
this.model.publishId = uni.getStorageSync('lifeData').vuex_user.user.userId;
|
||||
this.$u.post(url,this.model).then(data => {
|
||||
// uni.$emit('findIndexHouseList', {});
|
||||
// this.$u.route({
|
||||
// type: 'tab',url: '/pages/index/index'
|
||||
// })
|
||||
this.$u.route({
|
||||
url: 'pages/center/order',
|
||||
})
|
||||
});
|
||||
},
|
||||
// 选择类型回调
|
||||
selectConfirm(e) {
|
||||
this.model.roomLabel = ''
|
||||
this.model.roomType = ''
|
||||
e.map((val, index) => {
|
||||
this.model.roomLabel += val.label;
|
||||
this.model.roomType += val.value;
|
||||
})
|
||||
this.roomLabelVo = this.model.roomLabel
|
||||
},
|
||||
directionConfirm(e) {
|
||||
e.map((val, index) => {
|
||||
this.model.direction = val.label;
|
||||
this.directionVo = val.label;
|
||||
})
|
||||
},
|
||||
// 点击actionSheet回调
|
||||
actionSheetCallback(index) {
|
||||
uni.hideKeyboard();
|
||||
this.model.stepType = this.actionSheetList[index].text;
|
||||
},
|
||||
// checkbox选择发生变化
|
||||
checkboxGroupChange(e) {
|
||||
let featureList = e.map(val => {
|
||||
return {
|
||||
feature: val
|
||||
}
|
||||
})
|
||||
this.model.featureList = featureList
|
||||
},
|
||||
borderChange(index) {
|
||||
this.border = !index;
|
||||
},
|
||||
labelPositionChange(index) {
|
||||
this.labelPosition = index == 0 ? 'left' : 'top';
|
||||
},
|
||||
codeChange(text) {
|
||||
this.codeTips = text;
|
||||
},
|
||||
dateClick(){
|
||||
this.show = true
|
||||
},
|
||||
changeDate(e){
|
||||
this.model.startDate = e.result
|
||||
this.dateLabel = e.result
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page{
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss">
|
||||
|
||||
.wrap {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.scroll-wrapper{
|
||||
position: absolute;
|
||||
left: 0rpx;
|
||||
right: 0rpx;
|
||||
top: 0rpx;
|
||||
bottom: 120rpx;
|
||||
}
|
||||
|
||||
.bottom-btn {
|
||||
position: fixed;
|
||||
bottom: 8rpx;
|
||||
width: 100%;
|
||||
padding: 30rpx;
|
||||
border-top: 1rpx solid #ccc;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.dateBtn{
|
||||
position: absolute;
|
||||
right: 0rpx;
|
||||
top:10rpx;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.slot-btn {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: rgb(244, 245, 246);
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.slot-btn__hover {
|
||||
background-color: rgb(235, 236, 238);
|
||||
}
|
||||
|
||||
.custom-gap{
|
||||
width: 1000rpx;
|
||||
height: 10rpx;
|
||||
margin: 0 -200rpx 0 -200rpx;
|
||||
background-color: rgb(235, 236, 238);
|
||||
}
|
||||
</style>
|
||||
856
components/zy/filterDropdown.vue
Normal file
856
components/zy/filterDropdown.vue
Normal file
@@ -0,0 +1,856 @@
|
||||
<template>
|
||||
<view class="HMfilterDropdown" :class="{'setDropdownBottom':maskVisibility}" :style="{'top':menuTop+'rpx'}"
|
||||
@touchmove.stop.prevent="discard" @tap.stop="discard">
|
||||
<view class="nav">
|
||||
<block v-for="(item,index) in menu" :key="index">
|
||||
<view class="first-menu" :class="{'on':showPage==index}" @tap="togglePage(index)">
|
||||
<text class="name">{{item.name}}</text>
|
||||
<text class="iconfont triangle" :style="'transform:rotate('+triangleDeg[index]+'deg);'"></text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
<view class="mask" :class="{'show':isShowMask,'hide':maskVisibility!=true}" @tap="togglePage(showPage)"></view>
|
||||
<block v-for="(page,page_index) in subData" :key="page_index">
|
||||
<view class="sub-menu-class" :class="{'show':showPage==page_index,'hide':pageState[page_index]!=true}">
|
||||
<block v-if="page.type=='hierarchy'&& page.submenu.length>0">
|
||||
<scroll-view class="sub-menu-list" :class="[activeMenuArr[page_index].length>1?'first':'alone']"
|
||||
:scroll-y="true" :scroll-into-view="'first_id'+firstScrollInto">
|
||||
<block v-for="(sub,index) in page.submenu" :key="index">
|
||||
<view class="sub-menu" :id="'first_id'+index"
|
||||
:class="{'on':activeMenuArr[page_index][0]==index}"
|
||||
@tap="selectHierarchyMenu(page_index,index,null,null)">
|
||||
<view class="menu-name">
|
||||
<text>{{sub.name}}</text>
|
||||
<text class="iconfont selected"></text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
<block v-for="(sub,index) in page.submenu" :key="index">
|
||||
<scroll-view class="sub-menu-list not-first" :scroll-y="true"
|
||||
v-if="activeMenuArr[page_index][0]==index&&sub.submenu.length>0"
|
||||
:scroll-into-view="'second_id'+secondScrollInto">
|
||||
<block v-for="(sub_second,second_index) in sub.submenu" :key="second_index">
|
||||
<view class="sub-menu" :id="'second_id'+second_index"
|
||||
:class="{'on':activeMenuArr[page_index][1]==second_index}">
|
||||
<view class="menu-name"
|
||||
@tap="selectHierarchyMenu(page_index,activeMenuArr[page_index][0],second_index,null)">
|
||||
<text>{{sub_second.name}}</text>
|
||||
<text class="iconfont selected"></text>
|
||||
</view>
|
||||
<view class="more-sub-menu"
|
||||
v-if="sub_second.submenu&&sub.submenu.length>0&&sub_second.submenu.length>0">
|
||||
<block v-for="(sub2,sub2_index) in sub_second.submenu" :key="sub2_index">
|
||||
<text v-if="sub_second.showAllSub || (sub2_index<8)"
|
||||
:class="{'on':activeMenuArr[page_index][1]==second_index&&activeMenuArr[page_index][2]==sub2_index}"
|
||||
@tap="selectHierarchyMenu(page_index,activeMenuArr[page_index][0],second_index,sub2_index)">
|
||||
{{sub2.name}}
|
||||
</text>
|
||||
<text v-if="sub_second.showAllSub!=true && sub2_index==8 && sub_second.submenu.length>9"
|
||||
@tap="showMoreSub(second_index)">更多
|
||||
<text
|
||||
class="iconfont triangle"></text>
|
||||
</text>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</block>
|
||||
</block>
|
||||
<block v-if="page.type=='filter'">
|
||||
<view class="filter">
|
||||
<scroll-view class="menu-box" :scroll-y="true">
|
||||
<view class="box" v-for="(box,box_index) in page.submenu" :key="box_index">
|
||||
<view class="title">{{box.name}}</view>
|
||||
<view class="labels">
|
||||
<view v-for="(label,label_index) in box.submenu" :key="label_index"
|
||||
@tap="selectFilterLabel(page_index,box_index,label_index)"
|
||||
:class="{'on':label.selected}">{{label.name}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="btn-box">
|
||||
<view class="reset" @tap="resetFilterData(page_index)">重置</view>
|
||||
<view class="submit" @tap="setFilterData(page_index)">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block v-if="page.type=='radio'">
|
||||
<view class="filter">
|
||||
<scroll-view class="menu-box" :scroll-y="true">
|
||||
<view class="box" v-for="(box,box_index) in page.submenu" :key="box_index">
|
||||
<view class="title">{{box.name}}</view>
|
||||
<view class="labels">
|
||||
<view v-for="(label,label_index) in box.submenu" :key="label_index"
|
||||
@tap="selectRadioLabel(page_index,box_index,label_index)"
|
||||
:class="{'on':label.selected}">{{label.name}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="btn-box">
|
||||
<view class="reset" @tap="resetFilterData(page_index)">重置</view>
|
||||
<view class="submit" @tap="setFilterData(page_index)">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
subData: [], //菜单数据
|
||||
menu: [], //顶部横条数据
|
||||
showPage: -1, //菜单页面显示/隐藏动画控制
|
||||
pageState: [], //页面的状态
|
||||
activeMenuArr: [], //UI状态
|
||||
shadowActiveMenuArr: [], //记录选中
|
||||
defaultActive: [],
|
||||
triangleDeg: [], //小三角形的翻转动画控制
|
||||
isShowMask: false, //遮罩层显示/隐藏动画控制
|
||||
maskVisibility: false, //遮罩层显示/隐藏状态
|
||||
//滚动区域定位
|
||||
firstScrollInto: 0,
|
||||
secondScrollInto: 0,
|
||||
componentTop: 0,//组件top
|
||||
isReadNewSelect: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
menuTop: {
|
||||
value: Number,
|
||||
default: false
|
||||
},
|
||||
filterData: {
|
||||
value: Array,
|
||||
default: []
|
||||
},
|
||||
defaultSelected: {
|
||||
value: Array,
|
||||
default: []
|
||||
},
|
||||
updateMenuName: {
|
||||
value: Boolean,
|
||||
default: true
|
||||
},
|
||||
dataFormat: {
|
||||
value: String,
|
||||
default: 'Array'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterData: {
|
||||
handler() {
|
||||
this.initMenu(); //filterData重新赋值初始化菜单
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
defaultSelected(newVal) {
|
||||
|
||||
if (newVal.length == 0) {
|
||||
return;
|
||||
}
|
||||
this.defaultActive = JSON.parse(JSON.stringify(newVal));
|
||||
this.activeMenuArr = JSON.parse(JSON.stringify(newVal));
|
||||
this.shadowActiveMenuArr = JSON.parse(JSON.stringify(newVal));
|
||||
if (this.updateMenuName) {
|
||||
this.setMenuName();
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initMenu() {
|
||||
|
||||
let tmpMenuActiveArr = [];
|
||||
let tmpMenu = [];
|
||||
for (let i = 0; i < this.filterData.length; i++) {
|
||||
let tmpitem = this.filterData[i];
|
||||
tmpMenu.push({
|
||||
//如果没有设置name,则取第一个菜单作为menu.name,filter类型则将"筛选"作为menu.name
|
||||
name: tmpitem.name || (tmpitem.type == "filter" ? "筛选" : tmpitem.submenu[0].name),
|
||||
type: tmpitem.type
|
||||
});
|
||||
//初始化选中项数组-ui状态
|
||||
tmpMenuActiveArr.push(this.processActive(tmpitem));
|
||||
//初始化角度数组
|
||||
this.triangleDeg.push(0);
|
||||
//初始化控制显示状态数组
|
||||
this.pageState.push(false);
|
||||
//递归处理子菜单数据
|
||||
tmpitem = this.processSubMenu(tmpitem);
|
||||
this.filterData[i] = tmpitem;
|
||||
}
|
||||
this.menu = tmpMenu;
|
||||
//初始化选中项数组
|
||||
tmpMenuActiveArr = this.defaultActive.length > 0 ? this.defaultActive : this.activeMenuArr.length > 0 ? this.activeMenuArr : tmpMenuActiveArr;
|
||||
this.defaultActive = [];
|
||||
this.activeMenuArr = JSON.parse(JSON.stringify(tmpMenuActiveArr));
|
||||
this.shadowActiveMenuArr = JSON.parse(JSON.stringify(tmpMenuActiveArr));
|
||||
//加载菜单数据
|
||||
this.subData = this.filterData;
|
||||
//设定顶部菜单名字
|
||||
if (this.updateMenuName) {
|
||||
this.setMenuName();
|
||||
}
|
||||
},
|
||||
setMenuName() {
|
||||
for (var i = 0; i < this.activeMenuArr.length; i++) {
|
||||
let row = this.activeMenuArr[i];
|
||||
if (this.subData[i].type == 'hierarchy') {
|
||||
if (typeof (row[0]) == 'number') {
|
||||
let tmpsub = this.subData[i].submenu[row[0]];
|
||||
if (row.length > 1) {
|
||||
tmpsub = tmpsub.submenu[row[1]];
|
||||
if (row.length > 2) {
|
||||
tmpsub = tmpsub.submenu[row[2]];
|
||||
}
|
||||
}
|
||||
this.menu[i].name = tmpsub.name;
|
||||
} else {
|
||||
this.menu[i].name = this.subData[i].name;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
//展开更多
|
||||
showMoreSub(index) {
|
||||
this.subData[this.showPage].submenu[this.activeMenuArr[this.showPage][0]].submenu[index].showAllSub = true;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
//选中
|
||||
selectHierarchyMenu(page_index, level1_index, level2_index, level3_index) {
|
||||
//读取记录
|
||||
if (level1_index != null && level2_index == null && level3_index == null && this.shadowActiveMenuArr[page_index][0] ==
|
||||
level1_index) {
|
||||
this.activeMenuArr.splice(page_index, 1, JSON.parse(JSON.stringify(this.shadowActiveMenuArr[page_index])));
|
||||
} else {
|
||||
this.activeMenuArr[page_index].splice(0, 1, level1_index);
|
||||
(level2_index != null || this.activeMenuArr[page_index].length >= 2) && this.activeMenuArr[page_index].splice(1, 1, level2_index) || this.activeMenuArr[page_index].splice(1, 1);
|
||||
(level3_index != null || this.activeMenuArr[page_index].length >= 3) && this.activeMenuArr[page_index].splice(2, 1, level3_index) || this.activeMenuArr[page_index].splice(2, 1);
|
||||
}
|
||||
//写入结果
|
||||
if (level3_index != null || level2_index != null || (level1_index != null && this.subData[page_index].submenu[level1_index].submenu.length == 0)
|
||||
) {
|
||||
let sub = this.subData[page_index].submenu[level1_index].submenu[level2_index];
|
||||
if (this.updateMenuName) {
|
||||
this.menu[page_index].name = (level3_index != null && sub.submenu[level3_index].name) || (level2_index != null && sub.name) || this.subData[page_index].submenu[level1_index].name;
|
||||
}
|
||||
this.shadowActiveMenuArr[page_index] = JSON.parse(JSON.stringify(this.activeMenuArr[page_index]));
|
||||
this.togglePage(this.showPage);
|
||||
}
|
||||
},
|
||||
//写入结果,筛选
|
||||
setFilterData(page_index) {
|
||||
this.shadowActiveMenuArr[page_index] = JSON.parse(JSON.stringify(this.activeMenuArr[page_index]));
|
||||
this.togglePage(this.showPage);
|
||||
},
|
||||
//重置结果和ui,筛选
|
||||
resetFilterData(page_index) {
|
||||
let tmpArr = [];
|
||||
let level = this.shadowActiveMenuArr[page_index].length;
|
||||
while (level > 0) {
|
||||
tmpArr.push([]);
|
||||
let box = this.subData[page_index].submenu[level - 1].submenu;
|
||||
for (let i = 0; i < box.length; i++) {
|
||||
this.subData[page_index].submenu[level - 1].submenu[i].selected = false;
|
||||
}
|
||||
level--;
|
||||
}
|
||||
this.activeMenuArr[page_index] = JSON.parse(JSON.stringify(tmpArr));
|
||||
this.$forceUpdate();
|
||||
},
|
||||
//选中筛选类label-UI状态
|
||||
selectFilterLabel(page_index, box_index, label_index) {
|
||||
let find_index = this.activeMenuArr[page_index][box_index].indexOf(label_index);
|
||||
if (find_index > -1) {
|
||||
this.activeMenuArr[page_index][box_index].splice(find_index, 1);
|
||||
this.subData[page_index].submenu[box_index].submenu[label_index].selected = false;
|
||||
} else {
|
||||
this.activeMenuArr[page_index][box_index].push(label_index);
|
||||
this.subData[page_index].submenu[box_index].submenu[label_index].selected = true;
|
||||
}
|
||||
this.$forceUpdate();
|
||||
},
|
||||
//选中单选类label-UI状态
|
||||
selectRadioLabel(page_index, box_index, label_index) {
|
||||
|
||||
let activeIndex = this.activeMenuArr[page_index][box_index][0];
|
||||
if (activeIndex == label_index) {
|
||||
this.subData[page_index].submenu[box_index].submenu[activeIndex].selected = false;
|
||||
this.activeMenuArr[page_index][box_index][0] = null;
|
||||
} else {
|
||||
if (activeIndex != null && activeIndex < this.subData[page_index].submenu[box_index].submenu.length) {
|
||||
this.subData[page_index].submenu[box_index].submenu[activeIndex].selected = false;
|
||||
}
|
||||
|
||||
this.subData[page_index].submenu[box_index].submenu[label_index].selected = true;
|
||||
this.activeMenuArr[page_index][box_index][0] = label_index;
|
||||
}
|
||||
this.$forceUpdate();
|
||||
},
|
||||
//菜单开关
|
||||
togglePage(index) {
|
||||
if (index == this.showPage) {
|
||||
this.hidePageLayer(true);
|
||||
this.hideMask();
|
||||
this.showPage = -1;
|
||||
} else {
|
||||
if (this.showPage > -1) {
|
||||
this.hidePageLayer(false);
|
||||
}
|
||||
this.showPageLayer(index);
|
||||
this.showMask();
|
||||
}
|
||||
},
|
||||
//hide遮罩层
|
||||
hideMask() {
|
||||
this.isShowMask = false;
|
||||
setTimeout(() => {
|
||||
this.maskVisibility = false;
|
||||
}, 200);
|
||||
},
|
||||
//show遮罩层
|
||||
showMask() {
|
||||
this.maskVisibility = true;
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.isShowMask = true;
|
||||
}, 0);
|
||||
})
|
||||
},
|
||||
//hide菜单页
|
||||
hidePageLayer(isAnimation) {
|
||||
this.triangleDeg[this.showPage] = 0;
|
||||
let tmpIndex = this.showPage;
|
||||
if (isAnimation) {
|
||||
setTimeout(() => {
|
||||
this.pageState.splice(tmpIndex, 1, false);
|
||||
}, 200);
|
||||
this.confirm();
|
||||
} else {
|
||||
this.pageState.splice(tmpIndex, 1, false)
|
||||
}
|
||||
this.firstScrollInto = null;
|
||||
this.secondScrollInto = null;
|
||||
},
|
||||
confirm() {
|
||||
let index = JSON.parse(JSON.stringify(this.shadowActiveMenuArr));
|
||||
let value = JSON.parse(JSON.stringify(this.shadowActiveMenuArr));
|
||||
|
||||
//对结果做一下处理
|
||||
index.forEach((item, i) => {
|
||||
if (typeof (item[0]) == 'object') {
|
||||
//针对筛选结果过一个排序
|
||||
item.forEach((s, j) => {
|
||||
if (s != null) {
|
||||
s.sort((val1, val2) => {
|
||||
return val1 - val2;
|
||||
});
|
||||
item[j] = s;
|
||||
s.forEach((v, k) => {
|
||||
value[i][j][k] = (v == null || v >= this.subData[i].submenu[j].submenu.length) ? null : this.subData[i].submenu[j].submenu[v].value;
|
||||
if (this.subData[i].type == 'radio' && value[i][j][k] == null) {
|
||||
value[i][j] = [];
|
||||
index[i][j] = [];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let submenu = this.subData[i].submenu[item[0]];
|
||||
value[i][0] = submenu.value;
|
||||
if (value[i].length >= 2 && item[1] != null) {
|
||||
if (submenu.submenu.length > 0) {
|
||||
submenu = submenu.submenu[item[1]];
|
||||
value[i][1] = submenu.hasOwnProperty('value') ? submenu.value : null;
|
||||
} else {
|
||||
value[i][1] = null
|
||||
}
|
||||
if (value[i].length >= 3 && item[2] != null) {
|
||||
if (submenu.submenu.length > 0) {
|
||||
submenu = submenu.submenu[item[2]];
|
||||
value[i][2] = submenu.hasOwnProperty('value') ? submenu.value : null;
|
||||
} else {
|
||||
value[i][2] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
index[i] = item;
|
||||
|
||||
});
|
||||
// 输出
|
||||
this.$emit('confirm', {
|
||||
index: index,
|
||||
value: value
|
||||
});
|
||||
},
|
||||
//show菜单页
|
||||
showPageLayer(index) {
|
||||
this.processPage(index);
|
||||
this.pageState.splice(index, 1, true);
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.showPage = index;
|
||||
}, 0);
|
||||
})
|
||||
this.triangleDeg[index] = 180;
|
||||
},
|
||||
reloadActiveMenuArr() {
|
||||
for (let i = 0; i < this.filterData.length; i++) {
|
||||
let tmpitem = this.filterData[i];
|
||||
let tmpArr = this.processActive(tmpitem);
|
||||
tmpitem = this.processSubMenu(tmpitem);
|
||||
if (this.activeMenuArr[i].length != tmpArr.length) {
|
||||
this.filterData[i] = tmpitem;
|
||||
this.activeMenuArr.splice(i, 1, JSON.parse(JSON.stringify(tmpArr)));
|
||||
this.shadowActiveMenuArr.splice(i, 1, JSON.parse(JSON.stringify(tmpArr)));
|
||||
}
|
||||
}
|
||||
this.subData = this.filterData;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
processPage(index) {
|
||||
//check UI控制数组,结果数组,防止传入数据层级和UI控制数组不同步
|
||||
this.reloadActiveMenuArr();
|
||||
//重置UI控制数组
|
||||
this.activeMenuArr.splice(index, 1, JSON.parse(JSON.stringify(this.shadowActiveMenuArr[index])));
|
||||
if (this.menu[index].type == 'filter') {
|
||||
//重载筛选页选中状态
|
||||
let level = this.shadowActiveMenuArr[index].length;
|
||||
for (let i = 0; i < level; i++) {
|
||||
let box = this.subData[index].submenu[i].submenu;
|
||||
for (let j = 0; j < box.length; j++) {
|
||||
if (this.shadowActiveMenuArr[index][i].indexOf(j) > -1) {
|
||||
this.subData[index].submenu[i].submenu[j].selected = true;
|
||||
} else {
|
||||
this.subData[index].submenu[i].submenu[j].selected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this.menu[index].type == 'hierarchy') {
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
//滚动到选中项
|
||||
this.firstScrollInto = parseInt(this.activeMenuArr[index][0]);
|
||||
this.secondScrollInto = parseInt(this.activeMenuArr[index][1]);
|
||||
}, 0);
|
||||
})
|
||||
} else if (this.menu[index].type == 'radio') {
|
||||
//重载筛选页选中状态
|
||||
let level = this.shadowActiveMenuArr[index].length;
|
||||
for (let i = 0; i < level; i++) {
|
||||
let box = this.subData[index].submenu[i].submenu;
|
||||
for (let j = 0; j < box.length; j++) {
|
||||
if (this.shadowActiveMenuArr[index][i].indexOf(j) > -1) {
|
||||
this.subData[index].submenu[i].submenu[j].selected = true;
|
||||
} else {
|
||||
this.subData[index].submenu[i].submenu[j].selected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
processActive(tmpitem) {
|
||||
let tmpArr = []
|
||||
if (tmpitem.type == 'hierarchy' && tmpitem.hasOwnProperty('submenu') && tmpitem.submenu.length > 0) {
|
||||
let level = this.getMaxFloor(tmpitem.submenu);
|
||||
while (level > 0) {
|
||||
tmpArr.push(null);
|
||||
level--;
|
||||
}
|
||||
} else if (tmpitem.type == 'filter') {
|
||||
let level = tmpitem.submenu.length;
|
||||
while (level > 0) {
|
||||
tmpArr.push([]);
|
||||
level--;
|
||||
}
|
||||
} else if (tmpitem.type == 'radio') {
|
||||
let level = tmpitem.submenu.length;
|
||||
while (level > 0) {
|
||||
tmpArr.push([]);
|
||||
level--;
|
||||
}
|
||||
}
|
||||
return tmpArr;
|
||||
},
|
||||
processSubMenu(menu) {
|
||||
if (menu.hasOwnProperty('submenu') && menu.submenu.length > 0) {
|
||||
for (let i = 0; i < menu.submenu.length; i++) {
|
||||
menu.submenu[i] = this.processSubMenu(menu.submenu[i]);
|
||||
}
|
||||
} else {
|
||||
menu.submenu = [];
|
||||
}
|
||||
return menu;
|
||||
},
|
||||
//计算菜单层级
|
||||
getMaxFloor(treeData) {
|
||||
let floor = 0
|
||||
let max = 0
|
||||
|
||||
function each(data, floor) {
|
||||
data.forEach(e => {
|
||||
max = floor > max ? floor : max;
|
||||
if (e.hasOwnProperty('submenu') && e.submenu.length > 0) {
|
||||
each(e.submenu, floor + 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
each(treeData, 1)
|
||||
return max;
|
||||
},
|
||||
discard() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.HMfilterDropdown {
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
// position: absolute;
|
||||
// z-index: 997;
|
||||
flex-wrap: nowrap;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
// top: var(--window-top);
|
||||
overflow-y: hidden;
|
||||
|
||||
&.setDropdownBottom {
|
||||
height: 1500rpx;
|
||||
}
|
||||
|
||||
view {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.region {
|
||||
flex: 1;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.nav {
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
border-bottom: solid 1rpx #eee;
|
||||
z-index: 12;
|
||||
background-color: #ffffff;
|
||||
flex-direction: row;
|
||||
|
||||
.first-menu {
|
||||
width: 100%;
|
||||
font-size: 15px;
|
||||
color: #757575;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: color .2s linear;
|
||||
|
||||
&.on {
|
||||
color: #2979ff;
|
||||
|
||||
.iconfont {
|
||||
color: #2979ff;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
text-overflow: clip;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: transform .2s linear, color .2s linear;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sub-menu-class {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
transform: translate3d(0, - 100%, 0);
|
||||
max-height: 345px;
|
||||
background-color: #ffffff;
|
||||
z-index: 11;
|
||||
box-shadow: 0 5px 5px rgba(0, 0, 0, .1);
|
||||
overflow: hidden;
|
||||
flex-direction: row;
|
||||
transition: transform .15s linear;
|
||||
|
||||
&.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.show {
|
||||
transform: translate3d(0, calc(44px + 1rpx), 0);
|
||||
}
|
||||
}
|
||||
|
||||
.sub-menu-list {
|
||||
width: 100%;
|
||||
height: 345px;
|
||||
flex-direction: column;
|
||||
|
||||
.sub-menu {
|
||||
min-height: 44px;
|
||||
font-size: 13px;
|
||||
flex-direction: column;
|
||||
padding-right: 15px;
|
||||
|
||||
> .menu-name {
|
||||
padding-left: 20px;
|
||||
height: 44px;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
> .iconfont {
|
||||
display: none;
|
||||
font-size: 18px;
|
||||
color: #2979ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.first {
|
||||
flex-shrink: 0;
|
||||
width: 236rpx;
|
||||
background-color: #f0f0f0;
|
||||
|
||||
.sub-menu {
|
||||
padding-left: 15px;
|
||||
|
||||
&.on {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.alone {
|
||||
max-height: 345px;
|
||||
min-height: 120px;
|
||||
height: auto;
|
||||
|
||||
.sub-menu {
|
||||
min-height: calc(44px - 1rpx);
|
||||
margin-left: 15px;
|
||||
border-bottom: solid 1rpx #e5e5e5;
|
||||
|
||||
&.on {
|
||||
color: #2979ff;
|
||||
|
||||
> .menu-name {
|
||||
> .iconfont {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.not-first {
|
||||
.sub-menu {
|
||||
min-height: calc(44px - 1rpx);
|
||||
margin-left: 15px;
|
||||
border-bottom: solid 1rpx #e5e5e5;
|
||||
|
||||
> .menu-name {
|
||||
height: calc(44px - 1rpx);
|
||||
|
||||
> .iconfont {
|
||||
display: none;
|
||||
font-size: 18px;
|
||||
color: #2979ff;
|
||||
}
|
||||
}
|
||||
|
||||
&.on {
|
||||
color: #2979ff;
|
||||
|
||||
> .menu-name {
|
||||
> .iconfont {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.more-sub-menu {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
padding-bottom: 9px;
|
||||
|
||||
> text {
|
||||
height: 30px;
|
||||
border-radius: 3px;
|
||||
background-color: #f5f5f5;
|
||||
color: #9b9b9b;
|
||||
margin-bottom: 6px;
|
||||
margin-right: 6px;
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
border: solid #f5f5f5 1rpx;
|
||||
flex: 0 0 calc(33.33% - 6px);
|
||||
overflow: hidden;
|
||||
font-size: 12px;
|
||||
|
||||
&:nth-child(3n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&.on {
|
||||
border-color: #f6c8ac;
|
||||
color: #2979ff;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
color: #9b9b9b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter {
|
||||
width: 100%;
|
||||
height: 345px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.menu-box {
|
||||
width: 698rpx;
|
||||
height: calc(345px - 75px);
|
||||
flex-shrink: 1;
|
||||
|
||||
.box {
|
||||
width: 100%;
|
||||
margin-top: 16px;
|
||||
flex-direction: column;
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
font-size: 13px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.labels {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.on {
|
||||
border-color: #2979ff;
|
||||
background-color: #2979ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
> view {
|
||||
width: 148rpx;
|
||||
height: 30px;
|
||||
border: solid 1rpx #adadad;
|
||||
border-radius: 2px;
|
||||
margin-right: 15px;
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&:nth-child(4n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-box {
|
||||
flex-shrink: 0;
|
||||
width: 698rpx;
|
||||
height: 75px;
|
||||
flex-direction: row !important;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
> view {
|
||||
width: 320rpx;
|
||||
height: 42px;
|
||||
border-radius: 42px;
|
||||
border: 2rpx solid #2979ff;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.reset {
|
||||
color:#2979ff;
|
||||
}
|
||||
|
||||
.submit {
|
||||
color: #fff;
|
||||
background-color: #2979ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mask {
|
||||
z-index: 10;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
transition: background-color .15s linear;
|
||||
|
||||
&.show {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
&.hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* 字体图标 */
|
||||
@font-face {
|
||||
font-family: "HM-FD-font";
|
||||
src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAALAAAsAAAAABpQAAAJzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgp4gQIBNgIkAwwLCAAEIAWEbQc5G8sFERWMIbIfCbbzqA4hp7InSBibVsYGb4J42o82b3e/nJlHMw/NHbGOlwKJRCRpwzPtpAECCOZubdqxjYpQLMlVg+70/08edrgQOtx2ukpVyApZn+dyehPoQObHo3O85rYx9vOjXoBxQIHugW2yIkqIW2QXcScu4jwE8CSWbKSmrqUHFwOaJoCsLM5P4haSGIxRcRHshrUGucLCVcfqI3AZfV/+USguKCwNmtsxVztDxU/n55C+3W0Z4QQpEOTNFqCBbMCAjDUWB9CIwWk87aa70cYgqLkyd3dEmm+18R8eKATEBrV7A5CulBT8dKiWOYZk412XNcDdKSEKSGODnyKIDl+dmVt9/Dx4pu/xyeutkMlHISGPTsPCnoTNP9nOT6wTtDdlO6dPr47efvj942lkYuQzrhMKEjq9N6y98P3340gmlJ/RStUD6F31CAEEPtUW94/7rf+7XgaAz57X0ZHXAGsFFwVgw38yALuMb0IBbVyNamFYEw4oKMDTj3AHRQP5Pt4dci9VwSVkRNQh5r7CLskZadhsWHhRDBsXczk8ZYk3ewnCxmQeQKa3BOHvA8XXO2j+vqRhf7CE+sPmn4anvoL29JLa4qqaUQkmoK+QG2osCckq7txi2leK86aIPyJ3eQZ8xytXYmyQ51jQndJAxIJlqiGSLsOqImiZCjTiZCJt6Lq26U2OoXqwUo0hRaAE0K5AziANy/uLVeXzWyjVqyjcoeupjxDr5MMDn8MDkLG9Aenu5ZrOSSoghAUsRmogkkahSoWAtnlUARnCkY3It0Iu7mWhdmd9Z/19BwBP6GidEi0G56opckXTGZVSPxgAAAA=');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "HM-FD-font" !important;
|
||||
font-size: 13px;
|
||||
font-style: normal;
|
||||
color: #757575;
|
||||
|
||||
&.triangle {
|
||||
&:before {
|
||||
content: "\e65a";
|
||||
}
|
||||
}
|
||||
|
||||
&.selected {
|
||||
&:before {
|
||||
content: "\e607";
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
386
components/zy/video-swiper.vue
Normal file
386
components/zy/video-swiper.vue
Normal file
@@ -0,0 +1,386 @@
|
||||
<template>
|
||||
<view class="video-swiper" :style="{backgroundColor: bgColor,height: height+'rpx'}">
|
||||
<swiper
|
||||
class="video-swiper__wrapper"
|
||||
:style="{
|
||||
height: height+'rpx',
|
||||
}"
|
||||
@change="change"
|
||||
:circular="circular"
|
||||
:interval="interval"
|
||||
:duration="duration"
|
||||
:autoplay="autoplay"
|
||||
:current="current"
|
||||
:previousMargin="previousMargin+'rpx'"
|
||||
:nextMargin="nextMargin+'rpx'"
|
||||
:acceleration="acceleration"
|
||||
:displayMultipleItems="displayMultipleItems"
|
||||
:easingFunction="easingFunction"
|
||||
>
|
||||
<swiper-item
|
||||
class="video-swiper__wrapper__item"
|
||||
v-for="(item, index) in list"
|
||||
:key="index"
|
||||
>
|
||||
<view
|
||||
class="video-swiper__wrapper__item__wrapper"
|
||||
:style="[itemStyle(index)]"
|
||||
>
|
||||
<image
|
||||
class="video-swiper__wrapper__item__wrapper__image"
|
||||
v-if="getItemType(item) === 'image'"
|
||||
:src="getSource(item)"
|
||||
:mode="imgMode"
|
||||
@tap="clickHandler(index)"
|
||||
:style="{
|
||||
height: height+'rpx',
|
||||
}"
|
||||
></image>
|
||||
<video
|
||||
class="video-swiper__wrapper__item__wrapper__video"
|
||||
v-if="getItemType(item) === 'video'"
|
||||
:id="`video-${index}`"
|
||||
:enable-progress-gesture="false"
|
||||
:src="getSource(item)"
|
||||
:poster="getPoster(item)"
|
||||
:title="showTitle && item.title ? item.title : ''"
|
||||
:style="{
|
||||
height: height+'rpx',
|
||||
}"
|
||||
controls
|
||||
@tap="clickHandler(index)"
|
||||
:show-fullscreen-btn="false"
|
||||
object-fit="fill"
|
||||
></video>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="video-swiper__indicator">
|
||||
<slot name="indicator">
|
||||
<view class="video-swiper-indicator__wrapper">
|
||||
<view
|
||||
class="video-swiper-indicator_dot"
|
||||
v-for="(item, index) in list.length"
|
||||
:key="index"
|
||||
:class="[index === currentIndex && 'video-swiper-indicator_active']"
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'video-swiper',
|
||||
props: {
|
||||
// 列表数组,元素可为字符串,如为对象可通过keyName指定目标属性名
|
||||
list: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
// 是否显示面板指示器
|
||||
indicator: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 指示器非激活颜色
|
||||
indicatorActiveColor: {
|
||||
type: String,
|
||||
default: '#FFFFFF'
|
||||
},
|
||||
// 指示器的激活颜色
|
||||
indicatorInactiveColor: {
|
||||
type: String,
|
||||
default:'rgba(255, 255, 255, 0.35)'
|
||||
},
|
||||
// 指示器样式,可通过bottom,left,right进行定位
|
||||
indicatorStyle: {
|
||||
type: [String, Object],
|
||||
default: 'right'
|
||||
},
|
||||
// 指示器模式,line-线型,dot-点型
|
||||
indicatorMode: {
|
||||
type: String,
|
||||
default: 'dot'
|
||||
},
|
||||
// 是否自动切换
|
||||
autoplay: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 当前所在滑块的 index
|
||||
current: {
|
||||
type: [String, Number],
|
||||
default: '0'
|
||||
},
|
||||
// 滑块自动切换时间间隔
|
||||
interval: {
|
||||
type: [String, Number],
|
||||
default: 5000
|
||||
},
|
||||
// 滑块切换过程所需时间
|
||||
duration: {
|
||||
type: [String, Number],
|
||||
default: 500
|
||||
},
|
||||
// 播放到末尾后是否重新回到开头
|
||||
circular: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 前边距,可用于露出前一项的一小部分,nvue和支付宝不支持
|
||||
previousMargin: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
// 后边距,可用于露出后一项的一小部分,nvue和支付宝不支持
|
||||
nextMargin: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
// 当开启时,会根据滑动速度,连续滑动多屏,支付宝不支持
|
||||
acceleration: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 同时显示的滑块数量,nvue、支付宝小程序不支持
|
||||
displayMultipleItems: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
// 指定swiper切换缓动动画类型,有效值:default、linear、easeInCubic、easeOutCubic、easeInOutCubic
|
||||
// 只对微信小程序有效
|
||||
easingFunction: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
// list数组中指定对象的目标属性名
|
||||
keyName: {
|
||||
type: String,
|
||||
default: 'url'
|
||||
},
|
||||
// 图片的裁剪模式
|
||||
imgMode: {
|
||||
type: String,
|
||||
default: 'aspectFill'
|
||||
},
|
||||
// 组件高度
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: 350
|
||||
},
|
||||
// 背景颜色
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: '#f3f4f6'
|
||||
},
|
||||
// 组件圆角,数值或带单位的字符串
|
||||
radius: {
|
||||
type: [String, Number],
|
||||
default: 4
|
||||
},
|
||||
// 是否加载中
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否显示标题,要求数组对象中有title属性
|
||||
showTitle: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentIndex: 0,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
current(val, preVal) {
|
||||
if(val === preVal) return;
|
||||
this.currentIndex = val; // 和上游数据关联上
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
itemStyle() {
|
||||
return index => {
|
||||
const style = {}
|
||||
// #ifndef APP-NVUE || MP-TOUTIAO
|
||||
// 左右流出空间的写法不支持nvue和头条
|
||||
// 只有配置了此二值,才加上对应的圆角,以及缩放
|
||||
if (this.nextMargin && this.previousMargin) {
|
||||
style.borderRadius = this.radius+'rpx'
|
||||
if (index !== this.currentIndex) style.transform = 'scale(0.92)'
|
||||
}
|
||||
// #endif
|
||||
return style
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getItemType(item) {
|
||||
if (typeof item === 'string') return 'image'
|
||||
if (typeof item === 'object') {
|
||||
if (item.type === 'image') return 'image'
|
||||
if (item.type === 'video') return 'video'
|
||||
return 'image'
|
||||
}
|
||||
},
|
||||
// 获取目标路径,可能数组中为字符串,对象的形式,额外可指定对象的目标属性名keyName
|
||||
getSource(item) {
|
||||
if (typeof item === 'string') return item
|
||||
if (typeof item === 'object' && this.keyName) return item[this.keyName]
|
||||
else console.log('请按格式传递列表参数');
|
||||
return ''
|
||||
},
|
||||
// 轮播切换事件
|
||||
change(e) {
|
||||
// 当前的激活索引
|
||||
const {
|
||||
current
|
||||
} = e.detail
|
||||
this.pauseVideo(this.currentIndex)
|
||||
this.currentIndex = current
|
||||
this.$emit('change', e.detail)
|
||||
},
|
||||
// 切换轮播时,暂停视频播放
|
||||
pauseVideo(index) {
|
||||
const lastItem = this.getSource(this.list[index])
|
||||
// 当视频隐藏时,暂停播放
|
||||
const video = uni.createVideoContext(`video-${index}`, this)
|
||||
video.pause()
|
||||
},
|
||||
// 当一个轮播item为视频时,获取它的视频海报
|
||||
getPoster(item) {
|
||||
return typeof item === 'object' && item.poster ? item.poster : ''
|
||||
},
|
||||
// 点击某个item,点击图片预览,点击视频播放
|
||||
clickHandler(index) {
|
||||
if(this.list[index].type && this.list[index].type === 'video'){
|
||||
return
|
||||
}
|
||||
let imgArr = []
|
||||
this.list.filter(item=>{
|
||||
if(item.type == undefined || item.type==='image'){
|
||||
imgArr.push(item.url)
|
||||
}
|
||||
})
|
||||
// 预览图片
|
||||
uni.previewImage({
|
||||
current: index-1,
|
||||
urls: imgArr
|
||||
});
|
||||
this.$emit('click', index)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.video-swiper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&__wrapper {
|
||||
flex: 1;
|
||||
|
||||
&__item {
|
||||
flex: 1;
|
||||
|
||||
&__wrapper {
|
||||
display: flex;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: transform 0.3s;
|
||||
flex: 1;
|
||||
|
||||
&__image {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__video {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__title {
|
||||
position: absolute;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
font-size: 28rpx;
|
||||
padding: 12rpx 24rpx;
|
||||
color: #FFFFFF;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__indicator {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.video-swiper-indicator {
|
||||
&__wrapper {
|
||||
display: flex;
|
||||
.video-swiper-indicator_dot{
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 100px;
|
||||
margin: 0 4px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.video-swiper-indicator_active{
|
||||
width: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!--
|
||||
// test.vue 调用案例
|
||||
<template>
|
||||
<view>
|
||||
<VideoSwiper
|
||||
:list="list"
|
||||
keyName="url"
|
||||
:autoplay="false">
|
||||
</VideoSwiper>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VideoSwiper from "./video-swiper.vue"
|
||||
export default {
|
||||
components: {
|
||||
"VideoSwiper":VideoSwiper
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [
|
||||
{
|
||||
url: 'https://cdn.uviewui.com/uview/resources/video.mp4',
|
||||
title: '昨夜星辰昨夜风,画楼西畔桂堂东',
|
||||
poster: 'https://cdn.uviewui.com/uview/swiper/swiper1.png',
|
||||
type:'video'
|
||||
},
|
||||
{
|
||||
url: 'https://cdn.uviewui.com/uview/swiper/swiper2.png',
|
||||
title: '身无彩凤双飞翼,心有灵犀一点通'
|
||||
},{
|
||||
url: 'https://cdn.uviewui.com/uview/swiper/swiper3.png',
|
||||
title: '谁念西风独自凉,萧萧黄叶闭疏窗,沉思往事立残阳'
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
</script> -->
|
||||
Reference in New Issue
Block a user