330 lines
7.8 KiB
Vue
330 lines
7.8 KiB
Vue
<template>
|
|
<view>
|
|
<template v-if="!readonly">
|
|
<view v-if="formProps.expanding && dataOptions.length === 0" style="color:#E79467;">无选项😢,请检查设置</view>
|
|
|
|
<!-- 多选 -->
|
|
<template v-else-if="formProps.multiple">
|
|
<uni-data-checkbox v-if="formProps.expanding" :map="optionsKeyMap" multiple v-model="__value"
|
|
:localdata="dataOptions" />
|
|
<multiple-picker v-slot="{show}" v-else index="name" v-model="__value" :options="dataOptions">
|
|
<click-input :value="selectVal" :placeholder="formProps.placeholder || '请选择'" @click="show" />
|
|
</multiple-picker>
|
|
</template>
|
|
|
|
<!-- 单选 -->
|
|
<template v-else>
|
|
<!-- title == '司机姓名' -->
|
|
<uni-data-checkbox v-if="formProps.expanding" :map="optionsKeyMap" v-model="__value"
|
|
:localdata="dataOptions" />
|
|
<picker class="picker" v-else-if="title == '司机姓名'" @cancel="onCancel" @change="ok2" mode="selector"
|
|
:value="index" range-key="name" :range="dataOptions2">
|
|
<uni-search-bar v-if="isSearch" bgColor="#fff" v-model="searchValue" class="search" radius="5"
|
|
placeholder="请输入" clearButton="auto" cancelButton="none" @input="searchChange" />
|
|
|
|
<click-input @click="isSearchFn()" :value="(modelValue || []).length > 0 ? dataOptions[index]:null"
|
|
index="name" :placeholder="formProps.placeholder || '请选择'" />
|
|
</picker>
|
|
<picker class="picker" v-else @change="ok" mode="selector" :value="index" range-key="name"
|
|
:range="dataOptions">
|
|
<click-input :value="(modelValue || []).length > 0 ? dataOptions[index]:null" index="name"
|
|
:placeholder="formProps.placeholder || '请选择'" />
|
|
</picker>
|
|
</template>
|
|
</template>
|
|
<!-- 只读模式 -->
|
|
<template v-else>
|
|
<!-- <click-input disabled v-if="formProps.multiple" :value="modelValue.length > 0 ? dataOptions[index]:null"
|
|
index="name" /> -->
|
|
<click-input disabled v-if="formProps.multiple" :value="(modelValue || []).length > 0 ? dataOptions:null"
|
|
index="name" />
|
|
<click-input disabled v-else :value="selectVal" />
|
|
</template>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {
|
|
computed,
|
|
onMounted,
|
|
ref,
|
|
watch
|
|
} from 'vue'
|
|
import {
|
|
$nEmpty
|
|
} from '@/utils/tool.js'
|
|
import ClickInput from '@/components/ClickInput.vue'
|
|
import MultiplePicker from '@/components/common/MultiplePicker.vue'
|
|
|
|
const props = defineProps({
|
|
formProps: {
|
|
type: Object,
|
|
default: () => {
|
|
return {}
|
|
}
|
|
},
|
|
modelValue: {
|
|
type: Array,
|
|
default: () => {
|
|
return []
|
|
}
|
|
},
|
|
readonly: Boolean,
|
|
title: String,
|
|
})
|
|
|
|
const _value = computed({
|
|
get() {
|
|
return props.modelValue || []
|
|
},
|
|
set(val) {
|
|
emits('update:modelValue', val)
|
|
}
|
|
})
|
|
|
|
const selectVal = computed(() => {
|
|
return dataOptions.value.filter(v => (props.modelValue || []).indexOf(v.value) > -1).map(v => v.name)
|
|
})
|
|
|
|
const __value = computed({
|
|
get() {
|
|
return props.formProps.multiple ? _value.value : _value.value[0]
|
|
},
|
|
set(val) {
|
|
if (props.formProps.multiple) {
|
|
emits('update:modelValue', val)
|
|
} else {
|
|
emits('update:modelValue', [val])
|
|
}
|
|
}
|
|
})
|
|
|
|
const emits = defineEmits(['update:modelValue', 'resize'])
|
|
|
|
const loading = ref(false)
|
|
const dataOptions = ref([])
|
|
const dataOptions2 = ref([])
|
|
let preHandlerFuc = null
|
|
let aftHandlerFuc = null
|
|
const optionsKeyMap = {
|
|
text: 'name',
|
|
value: 'value'
|
|
}
|
|
const index = ref(0)
|
|
|
|
function loadOptionsData() {
|
|
try {
|
|
if (props.formProps.fixed) {
|
|
dataOptions.value = props.formProps.options;
|
|
|
|
} else {
|
|
doRequest(dataOptions.value)
|
|
}
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
}
|
|
|
|
watch(() => dataOptions, () => {
|
|
dataOptions2.value = dataOptions.value;
|
|
}, {
|
|
deep: true
|
|
});
|
|
|
|
onMounted(() => {
|
|
loadOptionsData()
|
|
})
|
|
|
|
function resizeCollapse() {
|
|
setTimeout(() => emits('resize'), 800)
|
|
}
|
|
|
|
function ok(e) {
|
|
index.value = e.detail.value
|
|
__value.value = dataOptions.value[index.value].value
|
|
resizeCollapse();
|
|
}
|
|
|
|
function ok2(e) {
|
|
const id = dataOptions2.value[e.detail.value].value;
|
|
const findIndex = dataOptions.value.findIndex(item => item.value == id);
|
|
// alert(findIndex)
|
|
if (findIndex > -1) {
|
|
index.value = findIndex;
|
|
__value.value = dataOptions.value[findIndex].value;
|
|
resizeCollapse();
|
|
isSearch.value = false;
|
|
}
|
|
|
|
}
|
|
// 搜索查询
|
|
const isSearch = ref(false);
|
|
const searchValue = ref("");
|
|
|
|
function searchChange(e) {
|
|
console.log(e);
|
|
// ,调模糊查询然后 把返回的结果传给this.list数组
|
|
let findList = dataOptions.value.filter(item => item.name.includes(e))
|
|
dataOptions2.value = findList
|
|
if (e == '') {
|
|
dataOptions2.value = dataOptions.value
|
|
}
|
|
}
|
|
const onCancel = () => {
|
|
isSearch.value = false;
|
|
}
|
|
const isSearchFn = () => {
|
|
|
|
setTimeout(() => {
|
|
isSearch.value = true;
|
|
}, 500)
|
|
}
|
|
|
|
|
|
function doRequest(options) {
|
|
const http = props.formProps.http || {}
|
|
if (http.url && http.method) {
|
|
const params = {
|
|
url: http.url,
|
|
method: http.method,
|
|
headers: {
|
|
'content-type': http.contentType === 'JSON' ? 'application/json' :
|
|
'application/x-www-form-urlencoded',
|
|
...coverParams(http.headers || [])
|
|
},
|
|
params: {},
|
|
data: http.contentType === 'JSON' ? JSON.parse(http.data || '{}') : coverParams(http.params || []),
|
|
}
|
|
preHandler(params, http.preHandler)
|
|
if (http.contentType !== 'JSON') {
|
|
params.data = {
|
|
...params.data,
|
|
...params.params
|
|
}
|
|
}
|
|
loading.value = true
|
|
uni.request({
|
|
...params,
|
|
timeout: 20000,
|
|
header: params.headers,
|
|
withCredentials: true,
|
|
dataType: 'json',
|
|
success: (rsp) => {
|
|
loading.value = false
|
|
// console.log('获取到数据: ', JSON.stringify(rsp))
|
|
const ops = aftHandler(rsp, http.aftHandler)
|
|
options.push(...(ops || []))
|
|
},
|
|
fail: (err) => {
|
|
loading.value = false
|
|
uni.showToast({
|
|
icon: 'none',
|
|
title: '请求http数据源发生异常:' + JSON.stringify(err)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
//数组转对象
|
|
function coverParams(args, isForm = false) {
|
|
const params = {};
|
|
if (Array.isArray(args)) {
|
|
args.forEach(arg => {
|
|
if ($nEmpty(arg.name)) {
|
|
params[arg.name] = arg.value
|
|
}
|
|
})
|
|
}
|
|
return params
|
|
}
|
|
|
|
//前置处理
|
|
function preHandler(params, script) {
|
|
if (script) {
|
|
if (!preHandlerFuc) {
|
|
preHandlerFuc = new Function('ctx', `${script}\n preHandler(ctx)`)
|
|
}
|
|
try {
|
|
preHandlerFuc(params)
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//后置处理
|
|
function aftHandler(rsp, aftHandler) {
|
|
if (aftHandler) {
|
|
return toFunc(rsp, aftHandler)
|
|
} else {
|
|
//新格式,带字段设置
|
|
if (aftHandler.isJs) {
|
|
return toFunc(rsp, aftHandler.js)
|
|
} else {
|
|
//取值进行转,拿到数组
|
|
const dataArr = getData(rsp, ifEmGet(aftHandler.rule.source, 'data'));
|
|
const name = ifEmGet(aftHandler.rule.name, 'name')
|
|
const value = ifEmGet(aftHandler.rule.value, 'value')
|
|
return (dataArr || []).map(v => {
|
|
return {
|
|
name: v[name],
|
|
value: v[value],
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
function ifEmGet(v, dv) {
|
|
return $nEmpty(v) ? v : dv
|
|
}
|
|
|
|
function getData(obj, path) {
|
|
// 将路径字符串分割成数组
|
|
const keys = path.split('.');
|
|
// 初始化结果为传入的对象
|
|
let result = obj;
|
|
// 逐层查找属性值
|
|
for (const key of keys) {
|
|
if (result.hasOwnProperty(key)) {
|
|
result = result[key];
|
|
} else {
|
|
return undefined;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function toFunc(rsp, script) {
|
|
if (script) {
|
|
if (!aftHandlerFuc) {
|
|
aftHandlerFuc = new Function('rsp', `${script}\n return aftHandler(rsp)`)
|
|
}
|
|
try {
|
|
return aftHandlerFuc(rsp) || []
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
}
|
|
return []
|
|
}
|
|
</script>
|
|
<style scoped>
|
|
/* .picker {
|
|
position: relative;
|
|
} */
|
|
.search {
|
|
position: fixed;
|
|
bottom: 505rpx;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
z-index: 9999;
|
|
padding:0;
|
|
}
|
|
|
|
.search /deep/ .uni-searchbar__box {
|
|
width: 400rpx;
|
|
border: 2rpx solid #f5f5f5;
|
|
}
|
|
</style> |