导入多选下拉栏组件,调整添加订单界面
This commit is contained in:
parent
5ae934cf16
commit
45e22fdddc
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view class="order-add">
|
||||
<Topnav :topLevel="topLevel" title="新增订单" defaultBackColor="#333333"
|
||||
<Topnav :topLevel="1" title="新增订单" defaultBackColor="#333333"
|
||||
defaultNavTextColor="#333333" showBack :fixed="false" />
|
||||
<view class="order-form">
|
||||
<view class="order-field">
|
||||
@ -11,26 +11,39 @@
|
||||
<u-input class="field-input" placeholder="请选择订单类型" v-model="form.orderTypeName" type="select" disabled/>
|
||||
</u-form-item>
|
||||
<u-form-item prop="customerName" required label="客户名称:" :border-bottom="false">
|
||||
<u-input class="field-input" placeholder="请输入客户名称" v-model="form.customerName" />
|
||||
<u-input class="field-input" placeholder="请选择客户" v-model="form.customerName"
|
||||
type="select" @click="handleSelectScenOrCus('客户')"/>
|
||||
</u-form-item>
|
||||
<u-form-item prop="phone" required label="手机号码:" :border-bottom="false">
|
||||
<u-input type="number" class="field-input" placeholder="请输入手机号码" v-model.number="form.phone" />
|
||||
<u-input class="field-input" placeholder="请选择客户" v-model.number="form.phone"
|
||||
type="select" @click="handleSelectScenOrCus('客户')" />
|
||||
</u-form-item>
|
||||
<u-form-item prop="attractionName" label="景区:" required :border-bottom="false">
|
||||
<u-input class="field-input" placeholder="请选择景区" v-model="form.attractionName"
|
||||
@click="showScenics=true" type="select"/>
|
||||
@click="handleSelectScenOrCus('景区')" type="select"/>
|
||||
</u-form-item>
|
||||
<u-form-item prop="routeIds" label="路线:" required :border-bottom="false">
|
||||
<!-- <u-input class="field-input" placeholder="请选择路线" v-model="form.routeIds"
|
||||
type="select"/> -->
|
||||
<w-select class="field-w-select" v-model="form.routeIds" multiple
|
||||
:list="routes" valueName="content" keyName="id" @change="changeRoute"
|
||||
placeholder="请选择路线" width="100%" bgColor="#f8f9fb">
|
||||
</w-select>
|
||||
</u-form-item>
|
||||
<u-form-item prop="cargoWeight" required label="货物重量:" :border-bottom="false">
|
||||
<u-input type="number" class="field-input" placeholder="请输入货物重量(最多保留两位小数)" v-model.number="form.cargoWeight" />
|
||||
<u-input class="field-ninput" type="number" placeholder="请输入货物重量(最多保留两位小数)" v-model.number="form.cargoWeight" />
|
||||
<view slot="right" class="field-input-right">KG</view>
|
||||
</u-form-item>
|
||||
<u-form-item prop="surchargeAmount" required label="附加费:" :border-bottom="false">
|
||||
<u-input type="number" class="field-input" placeholder="请输入附加费(最多保留两位小数)" v-model.number="form.surchargeAmount" />
|
||||
<u-input type="number" class="field-ninput" placeholder="请输入附加费(最多保留两位小数)" v-model.number="form.surchargeAmount" />
|
||||
<view slot="right" class="field-input-right">元</view>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
</view>
|
||||
</view>
|
||||
<u-picker mode="selector" v-model="showScenics" :range="scenics" :default-selector="getDefaultSelector"
|
||||
range-key="name" confirm-color="#f7c04d" title="景区选择" @confirm="handleScenics"/>
|
||||
<u-picker mode="selector" v-model="showScenOrCus" :range="scenOrCusType==='景区'?scenics:customers"
|
||||
:default-selector="getDefaultSelector" range-key="name" confirm-color="#f7c04d"
|
||||
:title="scenOrCusType+'选择'" @confirm="handleConfirmScenOrCus"/>
|
||||
<u-toast ref="uToast"></u-toast>
|
||||
</view>
|
||||
</template>
|
||||
@ -38,33 +51,33 @@
|
||||
<script>
|
||||
import Topnav from '@/components/topnav/index.vue';
|
||||
import configService from '@/common/config.service.js';
|
||||
import WSelect from '@/components/w-select/w-select.vue'
|
||||
export default {
|
||||
// #ifdef MP
|
||||
options: {
|
||||
styleIsolation: 'shared'
|
||||
},
|
||||
// #endif
|
||||
components: { Topnav },
|
||||
components: { Topnav, WSelect },
|
||||
data(){
|
||||
return{
|
||||
// #ifdef MP
|
||||
// 微信小程序自定义导航栏参数
|
||||
CustomBar: this.CustomBar || 0,
|
||||
// #endif
|
||||
// 页面是否滚动到顶
|
||||
topLevel: 0,
|
||||
// 订单类型
|
||||
form:{
|
||||
orderType: 1,
|
||||
orderTypeName: '载物订单',
|
||||
customerName: '',
|
||||
customerId: '',
|
||||
phone: '',
|
||||
attractionName: '',
|
||||
attractionId: '',
|
||||
surchargeAmount:'',
|
||||
cargoWeight: '',
|
||||
operatorIds: '',
|
||||
routeIds: ''
|
||||
routeIds: []
|
||||
},
|
||||
// 订单类型
|
||||
orderTypes:[],
|
||||
@ -72,22 +85,13 @@ export default {
|
||||
rules:{
|
||||
customerName: [{
|
||||
required: true,
|
||||
message: '请输入客户名称',
|
||||
message: '请选择客户',
|
||||
trigger: ['change','blur']
|
||||
}],
|
||||
phone: [{
|
||||
required: true,
|
||||
message: '请输入手机号',
|
||||
message: '请选择客户',
|
||||
trigger: ['change','blur']
|
||||
},
|
||||
{
|
||||
// 自定义验证函数,见上说明
|
||||
validator: (rule, value, callback) => {
|
||||
return this.$u.test.mobile(value);
|
||||
},
|
||||
message: '手机号码不正确',
|
||||
// 触发器可以同时用blur和change
|
||||
trigger: ['change','blur'],
|
||||
}],
|
||||
attractionName: [{
|
||||
required: true,
|
||||
@ -125,27 +129,35 @@ export default {
|
||||
},
|
||||
// 景区列表
|
||||
scenics: [],
|
||||
// 客户列表
|
||||
customers: [],
|
||||
// 路线列表
|
||||
routes: [{
|
||||
id: 1,
|
||||
content: "张三",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
content: "李四",
|
||||
},],
|
||||
// 用户信息
|
||||
userMessage: this.$store.state.vuex_token === ''?{}:JSON.parse(this.$store.state.user_message),
|
||||
isPilot: this.$store.state.user_type == 1,
|
||||
// 景区选择弹窗
|
||||
showScenics: false,
|
||||
// 景区/客户选择弹窗
|
||||
showScenOrCus: false,
|
||||
// 当前景区/客户选择类型
|
||||
scenOrCusType: ''
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
this.$refs.uForm.setRules(this.rules);
|
||||
},
|
||||
onPageScroll(e) {
|
||||
const level = e.scrollTop/60;
|
||||
if(level<=1) this.topLevel = level;
|
||||
else this.topLevel = 1;
|
||||
this.scrollTop = e.scrollTop;
|
||||
},
|
||||
computed:{
|
||||
// 获取选择器默认值
|
||||
getDefaultSelector(){
|
||||
const arr = this.scenics;
|
||||
const index = this.form['attractionId'];
|
||||
const isScen = this.scenOrCusType === '景区';
|
||||
const arr = isScen ? this.scenics : this.customers;
|
||||
const index = this.form[isScen?'attractionId':'customerId'];
|
||||
return index?[arr.findIndex(item=>item.id === index)]:[0];
|
||||
}
|
||||
},
|
||||
@ -157,7 +169,13 @@ export default {
|
||||
methods: {
|
||||
// 初始化
|
||||
async init(){
|
||||
let res = await this.$api.allCustomers();
|
||||
let resp = await this.$api.aSelfDetail(this.userMessage.id);
|
||||
if(!res){
|
||||
this.$refs.uToast.show({type: 'error',title: "客户获取失败!"});
|
||||
}else{
|
||||
this.customers = res || [];
|
||||
}
|
||||
if(!resp){
|
||||
this.$refs.uToast.show({type: 'error',title: "个人信息获取失败!"});
|
||||
}else{
|
||||
@ -167,11 +185,27 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
// 选择路线
|
||||
changeRoute(e){
|
||||
console.log(this.form.routeIds);
|
||||
},
|
||||
// 点击打开景区/客户选择弹窗
|
||||
handleSelectScenOrCus(type){
|
||||
this.scenOrCusType = type;
|
||||
this.showScenOrCus = true;
|
||||
},
|
||||
// 选择景区
|
||||
handleScenics(index){
|
||||
const val = this.scenics[index[0]];
|
||||
this.form.attractionName = val.name;
|
||||
this.form.attractionId = val.id;
|
||||
handleConfirmScenOrCus(index){
|
||||
if(this.scenOrCusType === '景区'){
|
||||
const val = this.scenics[index[0]];
|
||||
this.form.attractionName = val.name;
|
||||
this.form.attractionId = val.id;
|
||||
}else{
|
||||
const val = this.customers[index[0]];
|
||||
this.form.customerId = val.id;
|
||||
this.form.customerName = val.name;
|
||||
this.form.phone = val.phone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -203,6 +237,44 @@ export default {
|
||||
background: #F8F9FB;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
.field-ninput{
|
||||
&::v-deep .u-input{
|
||||
padding: 12rpx 80rpx 12rpx 32rpx !important;
|
||||
}
|
||||
}
|
||||
.field-w-select{
|
||||
&::v-deep .w-select{
|
||||
.select-wrap{
|
||||
border: none !important;
|
||||
min-height: var(--select-wrap-height);
|
||||
height: inherit;
|
||||
}
|
||||
padding: 12rpx 32rpx !important;
|
||||
background: #F8F9FB;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
&::v-deep .select-options{
|
||||
.item-active{
|
||||
color: #f7c04d !important;
|
||||
background-color: #f5f5f5 !important;
|
||||
}
|
||||
}
|
||||
&::v-deep .select-content-item-default{
|
||||
margin-left: 0 !important;
|
||||
margin-right: 0 !important;
|
||||
font-size: 28rpx;
|
||||
line-height: 40rpx;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
.field-input-right{
|
||||
font-family: Source Han Sans SC;
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
margin-left: -80rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,9 @@ const install = (Vue, vm) => {
|
||||
vm.$api.allAreas = async () => await vm.$u.get('/emArea/all');// 获取全部区域
|
||||
vm.$api.allScenicsByAreaId = async (params = {}) => await vm.$u.get('/emScenic/all',params);// 获取区域下全部景区
|
||||
|
||||
// 客户管理
|
||||
vm.$api.allCustomers = async () => await vm.$u.get('/cnCustomer/all');// 获取全部客户
|
||||
|
||||
// 轮播图管理
|
||||
vm.$api.allBanners = async () => await vm.$u.get('/cpBanner/all');// 获取全部轮播图
|
||||
|
||||
|
116
components/w-select/readme.md
Normal file
116
components/w-select/readme.md
Normal file
@ -0,0 +1,116 @@
|
||||
#### props
|
||||
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| ----------- | ------- | -------- | ------------------------------------------------------ |
|
||||
| width | string | '200px' | 选择框宽度 |
|
||||
| height | string | '30px' | 选择框高度 |
|
||||
| bgColor | string | '#fff' | 选择框背景颜色 |
|
||||
| placeholder | string | '请选择' | 输入框占位文本 |
|
||||
| valueName | string | 'label' | 显示的内容字段名 |
|
||||
| keyName | string | 'value' | 绑定的内容字段名 |
|
||||
| list | array | [] | 展示的内容列表 |
|
||||
| showClose | boolean | true | 是否显示删除按钮 |
|
||||
| multiple | boolean | false | 是否开启多选 |
|
||||
| filterable | boolean | false | 是否开启搜索功能,开启后直接输入值不选择也可以保存内容 |
|
||||
|
||||
该组件默认下拉选择器是从底部弹出,当检测到底部高度不足时则会在上面弹出
|
||||
|
||||
#### events
|
||||
|
||||
| 事件名 | 说明 |
|
||||
| ------ | --------------------------------------------- |
|
||||
| change | 选择的内容改变时触发,返回的参数为列表的 item |
|
||||
|
||||
#### 基本使用
|
||||
|
||||
绑定的值通过`v-model`绑定,如下面的`chooseValue`,需要获取 item 的值可以监听`@change`事件
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view class="login">
|
||||
<w-select
|
||||
style="margin-left: 20rpx;"
|
||||
v-model="chooseValue"
|
||||
:list="list"
|
||||
valueName="content"
|
||||
keyName="id"
|
||||
@change="change"
|
||||
>
|
||||
</w-select>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
chooseValue: "",
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
content: "张三",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
content: "李四",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
content: "王五",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
change(e) {
|
||||
console.log("chooseValue", this.chooseValue);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
#### 多选
|
||||
|
||||
多选开启`multiple`属性,双向绑定的值必须为数组类型,在 change 事件中根据自己需求进行处理。
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<w-select
|
||||
v-model="chooseValue"
|
||||
:list="list"
|
||||
multiple
|
||||
valueName="content"
|
||||
keyName="id"
|
||||
@change="change"
|
||||
>
|
||||
</w-select>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
chooseValue: [],
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
content: "张三",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
content: "李四",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
content: "王五",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
change(e) {
|
||||
console.log("chooseValue", this.chooseValue);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
```
|
583
components/w-select/w-select.vue
Normal file
583
components/w-select/w-select.vue
Normal file
@ -0,0 +1,583 @@
|
||||
<template>
|
||||
<view
|
||||
class="w-select"
|
||||
id="wSelect"
|
||||
:style="{
|
||||
'--select-wrap-width': width,
|
||||
'--select-wrap-height': height,
|
||||
'--select-bg-color': bgColor
|
||||
}"
|
||||
>
|
||||
<view :class="isShow ? 'select-wrap-active' : ''" class="select-wrap" @click="changeShow">
|
||||
<view v-if="multiple" class="select-content">
|
||||
<view class="select-content-item-default" v-if="multiSelectList.length === 0 && !filterable">
|
||||
{{ placeholder }}
|
||||
</view>
|
||||
<view class="select-content-item" v-if="multiSelectList.length > 0">
|
||||
{{ multiSelectList[0][valueName] }}
|
||||
</view>
|
||||
<view class="select-content-item" v-if="multiSelectList.length > 1">
|
||||
{{ multiLength }}
|
||||
</view>
|
||||
</view>
|
||||
<input
|
||||
v-if="!multiple || filterable"
|
||||
type="text"
|
||||
@input="inputChange"
|
||||
@blur="blurChange"
|
||||
:placeholder="multiple ? multiSelectList.length === 0 ? placeholder : '' : placeholder"
|
||||
:disabled="!filterable"
|
||||
:style="!filterable ? 'pointer-events: none' : ''"
|
||||
:value="inputData"
|
||||
>
|
||||
<!-- #ifdef VUE2 -->
|
||||
<view
|
||||
@click.stop="refreshValue"
|
||||
class="close-icon"
|
||||
v-if="showClose && (multiple ? value.length > 0 : value)"
|
||||
>
|
||||
<image :src="refreshUrl" mode="" />
|
||||
</view>
|
||||
<view
|
||||
v-if="value.length <= 0 || !showClose"
|
||||
:class="isShow ? 'w-select-arrow-up' : ''"
|
||||
class="w-select-arrow "
|
||||
/>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef VUE3 -->
|
||||
<view
|
||||
@click.stop="refreshValue"
|
||||
class="close-icon"
|
||||
v-if="showClose && (multiple ? modelValue.length > 0 : modelValue)"
|
||||
>
|
||||
<image :src="refreshUrl" mode="" />
|
||||
</view>
|
||||
<view
|
||||
v-if="modelValue.length <= 0 || !showClose"
|
||||
:class="isShow ? 'w-select-arrow-up' : ''"
|
||||
class="w-select-arrow "
|
||||
/>
|
||||
<!-- #endif -->
|
||||
|
||||
<scroll-view
|
||||
scroll-y
|
||||
v-show="optionsShow"
|
||||
:class="[
|
||||
isShow
|
||||
? showPosition === 'bottom'
|
||||
? 'animation-bottom-in'
|
||||
: 'animation-top-in'
|
||||
: showPosition === 'bottom'
|
||||
? 'animation-bottom-out'
|
||||
: 'animation-top-out',
|
||||
showPosition === 'bottom'
|
||||
? 'position-bottom'
|
||||
: 'position-top'
|
||||
]"
|
||||
class="select-options"
|
||||
>
|
||||
<!-- #ifdef VUE2 -->
|
||||
<view
|
||||
@click.stop="handleClickItem(item)"
|
||||
:class="
|
||||
multiple &&
|
||||
multiSelectList.find(
|
||||
res => res[keyName] === item[keyName]
|
||||
)
|
||||
? 'item-active'
|
||||
: value === item[keyName]
|
||||
? 'item-active'
|
||||
: ''
|
||||
"
|
||||
v-for="item in filterList"
|
||||
:key="item[keyName]"
|
||||
class="select-option-item"
|
||||
>
|
||||
{{ item[valueName] }}
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef VUE3 -->
|
||||
<view
|
||||
@click.stop="handleClickItem(item)"
|
||||
:class="
|
||||
multiple &&
|
||||
multiSelectList.find(
|
||||
res => res[keyName] === item[keyName]
|
||||
)
|
||||
? 'item-active'
|
||||
: modelValue === item[keyName]
|
||||
? 'item-active'
|
||||
: ''
|
||||
"
|
||||
v-for="item in filterList"
|
||||
:key="item[keyName]"
|
||||
class="select-option-item"
|
||||
>
|
||||
{{ item[valueName] }}
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
|
||||
<view class="options-no-data" v-if="filterList.length < 1">
|
||||
无匹配数据~
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view v-if="isShow" @click="closeContentSelect" class="contentMask" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
width: {
|
||||
type: String,
|
||||
default: '200px'
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '30px'
|
||||
},
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: '#fff'
|
||||
},
|
||||
// 是否多选
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否可搜索
|
||||
filterable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否显示关闭按钮
|
||||
showClose: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 渲染列表
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// #ifdef VUE3
|
||||
// 双向绑定的值
|
||||
modelValue: {
|
||||
type: [Array, String, Number],
|
||||
default: ''
|
||||
},
|
||||
// #endif
|
||||
// #ifdef VUE2
|
||||
// 双向绑定的值
|
||||
value: {
|
||||
type: [Array, String, Number],
|
||||
default: ''
|
||||
},
|
||||
// #endif
|
||||
// 默认显示的内容
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择'
|
||||
},
|
||||
// 显示的内容
|
||||
valueName: {
|
||||
type: String,
|
||||
default: 'label'
|
||||
},
|
||||
// 绑定的内容
|
||||
keyName: {
|
||||
type: String,
|
||||
default: 'value'
|
||||
}
|
||||
},
|
||||
// #ifdef VUE3
|
||||
emits: ['update:modelValue', 'change'],
|
||||
// #endif
|
||||
watch: {
|
||||
list: {
|
||||
immediate: true,
|
||||
deep: true,
|
||||
handler (news) {
|
||||
this.filterList = news
|
||||
const findItem = news.find(item => {
|
||||
let isItem = ''
|
||||
// #ifdef VUE3
|
||||
if (item[this.keyName] === this.modelValue) {
|
||||
isItem = true
|
||||
} else {
|
||||
isItem = false
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef VUE2
|
||||
if (item[this.keyName] === this.value) {
|
||||
isItem = true
|
||||
} else {
|
||||
isItem = false
|
||||
}
|
||||
// #endif
|
||||
return isItem
|
||||
})
|
||||
if (findItem) {
|
||||
this.inputData = findItem[this.valueName]
|
||||
}
|
||||
}
|
||||
},
|
||||
// #ifdef VUE2
|
||||
value: {
|
||||
handler (newValue) {
|
||||
if (this.multiple) {
|
||||
this.multiSelectList = newValue || []
|
||||
} else {
|
||||
const findItem = this.list.find(it => it[this.keyName] === newValue)
|
||||
if (findItem) {
|
||||
this.inputData = findItem[this.valueName]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
modelValue: {
|
||||
handler (newValue) {
|
||||
if (this.multiple) {
|
||||
this.multiSelectList = newValue || []
|
||||
} else {
|
||||
const findItem = this.list.find(it => it[this.keyName] === newValue)
|
||||
if (findItem) {
|
||||
this.inputData = findItem[this.valueName]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
computed: {
|
||||
multiLength () {
|
||||
const length = this.multiSelectList.length - 1
|
||||
return '+' + length
|
||||
},
|
||||
bottomDistance () {
|
||||
return (
|
||||
this.windowHeight - this.distanceTop - this.curHeight
|
||||
) // 当前元素距离可视屏幕底部的距离
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
inputData: '',
|
||||
multiSelectList: [],
|
||||
isShow: false,
|
||||
optionsShow: false,
|
||||
windowHeight: null,
|
||||
curHeight: null,
|
||||
distanceTop: null,
|
||||
showPosition: 'bottom',
|
||||
filterList: [],
|
||||
refreshUrl: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDQ4IDQ4IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIgZmlsbD0id2hpdGUiIGZpbGwtb3BhY2l0eT0iMC4wMSIvPjxwYXRoIGQ9Ik0yNCA0NEMzNS4wNDU3IDQ0IDQ0IDM1LjA0NTcgNDQgMjRDNDQgMTIuOTU0MyAzNS4wNDU3IDQgMjQgNEMxMi45NTQzIDQgNCAxMi45NTQzIDQgMjRDNCAzNS4wNDU3IDEyLjk1NDMgNDQgMjQgNDRaIiBmaWxsPSJub25lIiBzdHJva2U9IiM3YzZlNmUiIHN0cm9rZS13aWR0aD0iNCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0yOS42NTY5IDE4LjM0MzFMMTguMzQzMiAyOS42NTY4IiBzdHJva2U9IiM3YzZlNmUiIHN0cm9rZS13aWR0aD0iNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZD0iTTE4LjM0MzIgMTguMzQzMUwyOS42NTY5IDI5LjY1NjgiIHN0cm9rZT0iIzdjNmU2ZSIgc3Ryb2tlLXdpZHRoPSI0IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L3N2Zz4='
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
const res = uni.getSystemInfoSync()
|
||||
this.windowHeight = res.windowHeight // 当前设备屏幕高度
|
||||
uni
|
||||
.createSelectorQuery()
|
||||
.in(this)
|
||||
.select('#wSelect')
|
||||
.boundingClientRect(data => {
|
||||
this.distanceTop = data.top // 当前元素距离顶部的距离
|
||||
this.curHeight = data.height
|
||||
})
|
||||
.exec()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
showPositon () {
|
||||
this.showPosition = 'bottom'
|
||||
if (this.bottomDistance < this.windowHeight / 3) {
|
||||
this.showPosition = 'top'
|
||||
}
|
||||
},
|
||||
changeShow () {
|
||||
this.isShow = !this.isShow
|
||||
if (this.isShow === false) {
|
||||
this.filterList = this.list
|
||||
setTimeout(() => {
|
||||
this.optionsShow = false
|
||||
}, 200)
|
||||
} else {
|
||||
this.showPositon()
|
||||
this.optionsShow = this.isShow
|
||||
}
|
||||
},
|
||||
closeContentSelect () {
|
||||
this.isShow = false
|
||||
setTimeout(() => {
|
||||
this.optionsShow = false
|
||||
}, 200)
|
||||
},
|
||||
setValue (value = '') {
|
||||
// #ifdef VUE3
|
||||
this.$emit('update:modelValue', value)
|
||||
// #endif
|
||||
|
||||
// #ifdef VUE2
|
||||
this.$emit('input', value)
|
||||
// #endif
|
||||
},
|
||||
inputChange (e) {
|
||||
const value = e.detail.value
|
||||
if (this.multiple && this.filterable) {
|
||||
this.inputData = value
|
||||
} else {
|
||||
this.setValue(value)
|
||||
this.inputData = value
|
||||
}
|
||||
|
||||
this.filterList = this.list.filter(item =>
|
||||
item[this.valueName].includes(value)
|
||||
)
|
||||
},
|
||||
blurChange (e) {
|
||||
const value = e.detail.value
|
||||
|
||||
if (this.multiple && this.filterable && value) {
|
||||
const curValue = {
|
||||
[this.keyName]: value,
|
||||
[this.valueName]: value
|
||||
}
|
||||
this.multiSelect(curValue)
|
||||
}
|
||||
},
|
||||
refreshValue () {
|
||||
this.setValue('')
|
||||
this.inputData = ''
|
||||
this.$emit('change', '')
|
||||
this.filterList = this.list
|
||||
if (this.multiple) {
|
||||
this.multiSelectList = []
|
||||
}
|
||||
},
|
||||
handleClickItem (e) {
|
||||
if (this.multiple) {
|
||||
this.multiSelect(e)
|
||||
} else {
|
||||
this.setValue(e[this.keyName])
|
||||
this.inputData = e[this.valueName]
|
||||
this.$emit('change', e)
|
||||
this.changeShow()
|
||||
}
|
||||
},
|
||||
multiSelect (item) {
|
||||
const index = this.multiSelectList.findIndex(
|
||||
res => res[this.valueName] === item[this.valueName]
|
||||
)
|
||||
if (index > -1) {
|
||||
this.multiSelectList.splice(index, 1)
|
||||
} else {
|
||||
this.multiSelectList.push(item)
|
||||
}
|
||||
this.inputData = ''
|
||||
this.filterList = this.list
|
||||
this.setValue(this.multiSelectList)
|
||||
this.$emit('change', item)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.w-select {
|
||||
--select-wrap-width: 200px;
|
||||
--select-wrap-height: 30px;
|
||||
--select-border-radius: 4px;
|
||||
--select-border: 1px solid #dcdfe6;
|
||||
--select-active-border: 1px solid #409eff;
|
||||
--select-options-max-height: 150px;
|
||||
--select-option-item-font-size: 14px;
|
||||
--select-input-font-size: 14px;
|
||||
--no-data-default-color: #999999;
|
||||
--select-options-box-shadow: 0px 0px 12px rgb(0 0 0 / 12%);
|
||||
--select-bg-color: #ffffff;
|
||||
.select-wrap {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: var(--select-wrap-width);
|
||||
height: var(--select-wrap-height);
|
||||
border: var(--select-border);
|
||||
border-radius: var(--select-border-radius);
|
||||
background-color: var(--select-bg-color);
|
||||
transition: all 0.2s;
|
||||
input {
|
||||
padding: 0 2px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
font-size: var(--select-input-font-size);
|
||||
flex: 1;
|
||||
}
|
||||
.select-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: var(--select-option-item-font-size);
|
||||
.select-content-item {
|
||||
margin-left: 5px;
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--select-border-radius);
|
||||
color: #aa93b1;
|
||||
background-color: #f4f4f5;
|
||||
}
|
||||
.select-content-item-default {
|
||||
margin-left: 5px;
|
||||
color: var(--no-data-default-color);
|
||||
}
|
||||
}
|
||||
.close-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 7px;
|
||||
z-index: 1000;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
transform: translateY(-50%);
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.position-bottom {
|
||||
top: calc(var(--select-wrap-height) + 10px);
|
||||
}
|
||||
.position-top {
|
||||
bottom: calc(var(--select-wrap-height) + 10px);
|
||||
}
|
||||
.select-options {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
overflow: scroll;
|
||||
padding: 10px;
|
||||
max-height: var(--select-options-max-height);
|
||||
border-radius: var(--select-border-radius);
|
||||
background-color: var(--select-bg-color);
|
||||
box-shadow: var(--select-options-box-shadow);
|
||||
.select-option-item {
|
||||
margin-bottom: 5px;
|
||||
padding: 5px;
|
||||
font-size: var(--select-option-item-font-size);
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
.item-active {
|
||||
font-weight: 700;
|
||||
color: #409eff;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
.options-no-data {
|
||||
font-size: var(--select-option-item-font-size);
|
||||
text-align: center;
|
||||
color: var(--no-data-default-color);
|
||||
}
|
||||
}
|
||||
.w-select-arrow {
|
||||
display: inline-block;
|
||||
margin: 3px 10px 0;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-top: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
border-bottom: 1px solid #999999;
|
||||
border-left: 1px solid #999999;
|
||||
transition: all 0.3s;
|
||||
transform: translateY(-50%) rotate(-45deg);
|
||||
}
|
||||
.w-select-arrow-up {
|
||||
transform: rotate(-225deg);
|
||||
}
|
||||
}
|
||||
.select-wrap-active {
|
||||
border: var(--select-active-border);
|
||||
}
|
||||
.animation-bottom-in {
|
||||
animation-name: bottom-in;
|
||||
animation-duration: 0.4s;
|
||||
animation-timing-function: ease-out;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
.animation-bottom-out {
|
||||
animation-name: bottom-out;
|
||||
animation-duration: 0.2s;
|
||||
animation-timing-function: ease-out;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
.animation-top-in {
|
||||
animation-name: top-in;
|
||||
animation-duration: 0.4s;
|
||||
animation-timing-function: ease-out;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
.animation-top-out {
|
||||
animation-name: top-out;
|
||||
animation-duration: 0.2s;
|
||||
animation-timing-function: ease-out;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
@keyframes bottom-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-15%);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bottom-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translateY(-20%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes top-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(15%);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes top-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translateY(20%);
|
||||
}
|
||||
}
|
||||
.contentMask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 998;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user