<template>
	<view class="uni-stat__select" :class="multiple?'multiple':''">
		<span v-if="label" class="uni-label-text hide-on-phone">{{label + '：'}}</span>
		<view class="uni-stat-box" :class="{'uni-stat__actived': current}">
			<view class="uni-select" :class="{'uni-select--disabled':disabled}">
				<view class="uni-select__input-box" @click="toggleSelector">
					<view>
						<view v-if="multiple" class="uni-select__flex">
							<view v-for="(item,index) in current" :key="item" class="uni-select__flex-item">
								<view class="flex">{{item}}<view @click.stop="clearTag(index)"><uni-icons type="ant-design:close-outlined" custom-prefix="antfont" color="#c0c4cc" size="12" /></view></view>
							</view> 
							<input v-if="isSearch" class="uni-select__input-text" v-model="keyword" :placeholder="current.length>0 ?'':placeholder"
							placeholder-class="uni-select__input-placeholder" :focus="showSelector" @input="searchData" @blur="onBlur" @focus="onFocus"/>
						</view>
						<view v-else-if="current && !multiple && !showSelector && isSearch" class="uni-select__input-text">{{current}}</view>
						<view v-if="!isSearch">
							<view v-if="current && !multiple" class="uni-select__input-text">{{current}}</view>
							<view v-else-if="current.length<=0 &&multiple||!current && !multiple" class="uni-select__input-text uni-select__input-placeholder">{{placeholder}}</view>
						</view>
						<input v-if="!multiple&&isSearch" class="uni-select__input-text position" v-model="keyword" :placeholder="current ?'':placeholder"
						placeholder-class="uni-select__input-placeholder" :focus="showSelector" @input="searchData" @blur="onBlur" @focus="onFocus"/>
					</view>
					 
					<view class="close-btn" v-if="(current&&!multiple || current.length>0&&multiple) && clear && !disabled " @click.stop="clearVal" ><uni-icons type="clear" color="#c0c4cc" size="24"/></view>
					<uni-icons v-else-if="!multiple" :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
				</view>
				<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
				<view class="uni-select__selector" v-if="showSelector">
					<view class="uni-popper__arrow"></view>
					<scroll-view scroll-y="true" class="uni-select__selector-scroll">
						<view class="uni-select__selector-empty"  @click="toggleSelector" v-if="mixinDatacomResData.length === 0">
							<text>{{emptyTips}}</text>
						</view>
						<view v-else class="uni-select__selector-item relative" v-for="(item,index) in mixinDatacomResData" :key="index"
							@click="change(item)">
							<view :class="{'uni-select__selector__disabled': item.disable}">{{item.text}}
							<uni-icons class="checked" v-if="multiple&&current.includes(item.text)" type="ant-design:check-outlined" custom-prefix="antfont" color="#5e95ff" size="12" /></view>
						</view>
					</scroll-view>
				</view>
			</view>
		</view>
	</view>
</template>

<script setup>
	import {
		inject,
		watch,
		watchEffect,
		ref,
		onMounted
	} from 'vue';
	import {
		getDicDetailList
	} from '@/common/api/system/dictionary/index.js';
	import {
		changeApiOptions,
		isValidJSON,
		camelCaseString
	} from '@/common/api/magic-api/useApiRequest.js';
	/**
	 * DataChecklist 数据选择器
	 * @description 通过数据渲染的下拉框组件
	 * @tutorial https://uniapp.dcloud.io/component/uniui/uni-data-select
	 * @property {String} value 默认值
	 * @property {Array} localdata 本地数据 ，格式 [{text:'',value:''}]
	 * @property {Boolean} clear 是否可以清空已选项
	 * @property {Boolean} emptyText 没有数据时显示的文字 ，本地数据无效
	 * @property {String} label 左侧标题
	 * @property {String} placeholder 输入框的提示文字
	 * @property {Boolean} disabled 是否禁用
	 * @event {Function} change  选中发生变化触发
	 * @property {Object} map 字段映射， 默认 map={text:'text',value:'value'}
	 * @property {Object} apiConfig API请求时的配置 
	 * @property {String} itemId 数据字典id
	 */

	const props = defineProps({
		localdata: {
			type: Array,
			default: []
		},
		modelValue: {
			type: String,
			default: null
		},
		label: {
			type: String,
			default: ''
		},
		placeholder: {
			type: String,
			default: '请选择'
		},
		emptyTips: {
			type: String,
			default: '无选项'
		},
		clear: {
			type: Boolean,
			default: true
		},
		disabled: {
			type: Boolean,
			default: false
		},
		map: {
			type: Object,
			default: () => {
				return {
					text: 'text',
					value: 'value'
				}
			}
		},
		apiConfig: {
			type: Object,
			default: () => {
				return {}
			}
		},
		itemId: {
			type: String,
			default: ''
		},
		index: {
			type: Number
		},
		multiple: {
			type: Boolean,
			default: false
		},
		isSearch: {
			type: Boolean,
			default: false
		},
	})
	const emit = defineEmits(['change', 'update:modelValue']);
	const formModel = inject('formModel');
	const isCustomForm = inject('isCustomForm', false);
	const keyword=ref()
	const showSelector = ref(false);
	const current = ref(props.multiple?[]:'');
	const dataValue = ref(props.multiple?[]:'');
	const mixinDatacomResData = ref([]);

	const channels = ref([]);
	onMounted(() => { 
		fetch()
	})

	watchEffect(() => { 
		if (props.apiConfig?.path) { 
			if (props.apiConfig?.requestParamsConfigs) apiconfigs(props.apiConfig.requestParamsConfigs)
			if (props.apiConfig?.requestHeaderConfigs) apiconfigs(props.apiConfig.requestHeaderConfigs)
			fetch();
		}
	});
	watch(
		() => props.modelValue,
		(val) => {
			initDefVal()
		},
	);
	watch(
		() => props.localdata,
		(newVal) => {
			channels.value = newVal
			mixinDatacomResData.value = getDataList()
		}, {
			deep: true,
			immediate: true
		},
	);

	async function fetch() { 
		if (props.localdata && props.localdata.length !== 0) {
			channels.value = props.localdata
			mixinDatacomResData.value = getDataList()
		} else if (props.itemId) {
			let res = await getDicDetailList({
				itemId: props.itemId
			})
			if (res.success) {
				channels.value = Array.isArray(res.data) ? res.data : []
				mixinDatacomResData.value = getDataList()
			}
		} else if (props.apiConfig?.path) {
			let res = await changeApiOptions(props.apiConfig, formModel.value, isCustomForm, props.index);
			if (res.data) {
				channels.value = Array.isArray(res.data) ? res.data : [];
				mixinDatacomResData.value = getDataList()
			}
		}
		initDefVal()
	}

	function apiconfigs(Configs) {
		Configs.forEach((o) => { 
			if (o.assignmentType == 'data') {
				let val = isValidJSON(o.value);
				let field = '';
				if (val && val.bindTable) {
					let table = isCustomForm ?
						val.bindTable + 'List' :
						camelCaseString(val.bindTable + '_List');
					field = isCustomForm ? val.bindField : camelCaseString(val.bindField);

					formModel.value &&
						formModel.value[table][props.index || 0] &&
						formModel.value[table][props.index || 0][field];
				} else if (val && val.bindField) {
					field = isCustomForm ? val.bindField : camelCaseString(val.bindField);
					formModel.value && formModel.value[field];
				}
			} 
		});
	}

	function initDefVal() {
		let defValue = '';
		dataValue.value =props.multiple?[]:'';
		if ((props.modelValue || props.modelValue === 0) && !isDisabled(props.modelValue)) {
			defValue = props.modelValue
		}
		if(defValue) dataValue.value = props.multiple?defValue.split(','):defValue

		
		if(props.multiple){
			current.value =[]
			if(dataValue.value?.length>0){
				dataValue.value.forEach(o=>{
					const def = channels.value.find(item => item[props.map.value] === o)
					if(def){current.value.push(def[props.map.text])}
				}) 
			}
		}else{
			const def = channels.value.find(item => item[props.map.value] === defValue)
			current.value = def ? def[props.map.text] : defValue
		}
		
	}
	/**
	 * 获取渲染的新数组
	 * @param {Object} value 选中内容
	 */
	function getDataList() {
		// 解除引用关系，破坏原引用关系，避免污染源数据
		let dataList = JSON.parse(JSON.stringify(channels.value))
		let list = []
		dataList.forEach((item, index) => {
			item.value = item[props.map.value];
			item.text = item[props.map.text]
			item.disabled = item.disable || item.disabled || false
			item.selected = dataValue.value === item[props.map.value]
			list.push(item)
		})
		return list
	}
	/**
	 * @param {[String, Number]} value
	 * 判断用户给的 value 是否同时为禁用状态
	 */
	function isDisabled(value) {
		let isDisabled = false;

		mixinDatacomResData.value.forEach(item => {
			if (item.value === value) {
				isDisabled = item.disable
			}
		})

		return isDisabled;
	}

	function clearVal() {
		showSelector.value =false
		cusomemit('')
	}
	function clearTag(idx){
		current.value.splice(idx,1)
		dataValue.value.splice(idx,1)
		cusomemit(dataValue.value.join(','))
	}
	function change(item) { 
		if (!item.disable) {
			showSelector.value = false
			keyword.value=''
			if(props.multiple){
				if(dataValue.value.includes(item.value)){
					let idx=dataValue.value.findIndex(o=>o==item.value)
					if(idx>=0) clearTag(idx)
				}else{
					current.value.push(item.text)
					dataValue.value.push(item.value)
					cusomemit(dataValue.value.join(','), item) 
				}
			}else{
				current.value = item.text;
				cusomemit(item.value, item)
			} 
		}
	}

	function cusomemit(val, option) { 
		emit('update:modelValue', val) 
		emit('change',{
				value: val,
				data: option
			})
	}

	function toggleSelector() {
		if (props.disabled) {
			return
		} 
		showSelector.value = !showSelector.value 
	}
	function searchData(event) { 
		let value = event.detail.value; 
		mixinDatacomResData.value=getDataList()
		if(value){
			mixinDatacomResData.value=mixinDatacomResData.value.filter(o=>{return o.text.includes(value)})
		} 
	} 
	function onBlur(){
		keyword.value='';   
	}
	function onFocus(){
		mixinDatacomResData.value=getDataList() 
	}
</script>

<style lang="scss">
	$uni-base-color: #6a6a6a !default;
	$uni-main-color: #333 !default;
	$uni-secondary-color: #909399 !default;
	$uni-border-3: #e5e5e5;
	.relative{
		position: relative;
	}
	.checked{
		position: absolute;
		top: 5px;
		right: 10px;
	}
	.flex{
		display:flex
	}
	/* #ifndef APP-NVUE */
	@media screen and (max-width: 500px) {
		.hide-on-phone {
			display: none;
		}
	}

	/* #endif */
	.uni-stat__select {
		display: flex;
		align-items: center;
		// padding: 15px;
		cursor: pointer;
		width: 100%;
		flex: 1;
		box-sizing: border-box;
	}

	.uni-stat-box {
		width: 100%;
		flex: 1;
	}

	.uni-stat__actived {
		width: 100%;
		flex: 1;
		// outline: 1px solid #2979ff;
	}

	.uni-label-text {
		font-size: 14px;
		font-weight: bold;
		color: $uni-base-color;
		margin: auto 0;
		margin-right: 5px;
	}

	.uni-select {
		font-size: 14px;
		border: 1px solid $uni-border-3;
		box-sizing: border-box;
		border-radius: 4px;
		padding: 0 5px;
		padding-left: 10px;
		position: relative;
		/* #ifndef APP-NVUE */
		display: flex;
		user-select: none;
		/* #endif */
		flex-direction: row;
		align-items: center;
		border-bottom: solid 1px $uni-border-3;
		width: 100%;
		flex: 1;
		height: 35px;

		&--disabled {
			background-color: #f5f7fa;
			cursor: not-allowed;
		}
	}
	.multiple{
		.uni-select{
			padding: 0 4px;
		}
		.uni-select,
		.uni-select__input-box{
			height: auto;
			min-height: 35px;
		} 
		.uni-select__input-placeholder{
			padding-left: 6px;
		}
	}
	.uni-select__label {
		font-size: 16px;
		// line-height: 22px;
		height: 35px;
		padding-right: 10px;
		color: $uni-secondary-color;
	}

	.uni-select__input-box {
		height: 35px;
		position: relative;
		/* #ifndef APP-NVUE */
		display: flex;
		/* #endif */
		flex: 1;
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
	}

	.uni-select__input {
		flex: 1;
		font-size: 14px;
		height: 22px;
		line-height: 22px;
	}
 

	.uni-select__selector {
		/* #ifndef APP-NVUE */
		box-sizing: border-box;
		/* #endif */
		position: absolute;
		top: calc(100% + 12px);
		left: 0;
		width: 100%;
		background-color: #FFFFFF;
		border: 1px solid #EBEEF5;
		border-radius: 6px;
		box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
		z-index: 4;
		padding: 4px 0;
	}

	.uni-select__selector-scroll {
		/* #ifndef APP-NVUE */
		max-height: 200px;
		box-sizing: border-box;
		/* #endif */
	}

	.uni-select__selector-empty,
	.uni-select__selector-item {
		/* #ifndef APP-NVUE */
		display: flex;
		cursor: pointer;
		/* #endif */
		line-height: 35px;
		font-size: 14px;
		text-align: center;
		/* border-bottom: solid 1px $uni-border-3; */
		padding: 0px 10px;
	}

	.uni-select__selector-item:hover {
		background-color: #f9f9f9;
	}

	.uni-select__selector-empty:last-child,
	.uni-select__selector-item:last-child {
		/* #ifndef APP-NVUE */
		border-bottom: none;
		/* #endif */
	}

	.uni-select__selector__disabled {
		opacity: 0.4;
		cursor: default;
	}

	/* picker 弹出层通用的指示小三角 */
	.uni-popper__arrow,
	.uni-popper__arrow::after {
		position: absolute;
		display: block;
		width: 0;
		height: 0;
		border-color: transparent;
		border-style: solid;
		border-width: 6px;
	}

	.uni-popper__arrow {
		filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
		top: -6px;
		left: 10%;
		margin-right: 3px;
		border-top-width: 0;
		border-bottom-color: #EBEEF5;
	}

	.uni-popper__arrow::after {
		content: " ";
		top: 1px;
		margin-left: -6px;
		border-top-width: 0;
		border-bottom-color: #fff;
	}

	.uni-select__input-text {
		display: inline;
		flex: 1;
		height: 30px;
		line-height: 30px;
		width: 100%;
		color: $uni-main-color;
		white-space: nowrap;
		text-overflow: ellipsis;
		-o-text-overflow: ellipsis;
		overflow: hidden;
		&.position{
			position: absolute;
			left: 0;
			top:2.5px;
			width: calc(100% - 30px);
		}
	}
	
	.uni-select__flex{
		display: flex;
		flex-wrap: wrap;
		&-item{
			background: rgba(0, 0, 0, 0.06);
			padding: 4px;
			border-radius: 4px;
			margin-right: 4px;
			margin-top: 2px;
			margin-bottom: 2px;
		}
	}

	.uni-select__input-placeholder {
		color: $uni-base-color;
		font-size: 12px;
	}

	.uni-select--mask {
		position: fixed;
		top: 0;
		bottom: 0;
		right: 0;
		left: 0;
	}
	.close-btn{
		position: absolute;
		top:1px;
		bottom: 1px;
		right:0;
		z-index: 3;
		background: #fff;
		display: flex;
		align-items: center;
	}
</style>