<template>
	<view class="s-dynamic-form-wrapper">
		<s-form :labelPosition="labelPosition" :model="models" ref="form" :labelWidth="labelWidth">
			<s-form-item :customStyle="formItemStyle" v-for="(item, index) in list" :prop="item.model" :key="item.key"
				:label="item.label">
				<!-- 根据传入的type动态生成组件 -->
				<!-- uniapp组件动态引入会有问题 -->
				<!-- <component :is="formTypeKeyList[item.type]" ></component> -->

				<!-- s-input -->
				<view style="width: 100%;display: flex;align-items: center;"
					v-if="formTypeKeyList[item.type] && formTypeKeyList[item.type] === 's-input'">
					<!-- <s-input :disabled="disabled" :placeholder="item.options.placeholder || '请输入'" v-model="models[item.model]"></s-input> -->
					<view class="" style="flex: 1;width: 0;">
						<s-textarea @click.native="clickHandler(item)" @blur="e => { blurHandler(item) }"
							:disabled="disabled" v-model="models[item.model]" placeholder="请输入内容" autoHeight :height="30">
						</s-textarea>
					</view>
					<slot :row="item" name="suffixIcon"></slot>
				</view>

				<!-- s-textarea -->
				<template v-else-if="formTypeKeyList[item.type] && formTypeKeyList[item.type] === 's-textarea'">
					<s-textarea :disabled="disabled" v-model="models[item.model]"></s-textarea>
				</template>

				<!-- s-picker -->
				<template v-else-if="formTypeKeyList[item.type] && formTypeKeyList[item.type] === 's-picker'">
					<picker :disabled="disabled" @change="value => changeSelect(value, item)" range-key="label"
						:range="item.options.options">
						<text :class="disabled ? 'disabled-text' : ''" v-text="findValue(item)"></text>
					</picker>
				</template>

				<!-- s-checkbox-group -->
				<template v-else-if="formTypeKeyList[item.type] && formTypeKeyList[item.type] === 's-checkbox-group'">
					<s-checkbox-group placement="column" @change="value => { changeCheckbox(value, item) }"
						:disabled="disabled" v-model="models[item.model]" shape="square">
						<s-checkbox style="margin-bottom: 20rpx;" v-for="(sitem, sindex) in item.options.options"
							:key="sindex" :label="sitem.label" :name="sitem.value"></s-checkbox>
					</s-checkbox-group>
				</template>

				<!-- s-radio-group -->
				<template v-else-if="formTypeKeyList[item.type] && formTypeKeyList[item.type] === 's-radio-group'">
					<s-radio-group placement="column" @change="value => { changeRadioBox(value, item) }"
						:disabled="disabled" v-model="models[item.model]" shape="square">
						<s-radio style="margin-bottom: 20rpx;" shape="circle"
							v-for="(sitem, sindex) in item.options.options" :key="sindex" :label="sitem.label"
							:name="sitem.value"></s-radio>
					</s-radio-group>
				</template>

				<!-- s-datetime-picker -->
				<view class="my-border"
					v-else-if="formTypeKeyList[item.type] && formTypeKeyList[item.type] === 's-datetime-picker'">
					<text :class="disabled ? 'disabled-text' : ''" @click="clickDatePicker(item)"
						v-text="models[item.model] || item.options.placeholder"></text>
				</view>

				<!-- s-rate -->
				<template v-else-if="formTypeKeyList[item.type] && formTypeKeyList[item.type] === 's-rate'">
					<s-rate :disabled="disabled" v-model="models[item.model]"></s-rate>
				</template>

				<!-- s-slider -->
				<template v-else-if="formTypeKeyList[item.type] && formTypeKeyList[item.type] === 's-slider'">
					<s-slider :disabled="disabled" v-model="models[item.model]"></s-slider>
				</template>

				<!-- s-switch -->
				<template v-else-if="formTypeKeyList[item.type] && formTypeKeyList[item.type] === 's-switch'">
					<s-switch :disabled="disabled" v-model="models[item.model]"></s-switch>
				</template>

				<!-- s-doc-select -->
				<template v-else-if="formTypeKeyList[item.type] && formTypeKeyList[item.type] === 's-doc-select'">
					<doc-select @event-callback="eventCallback" @change="changeDocValue" v-model="models[item.model]"
						:record="item" :disabled="disabled" :models="models"></doc-select>
				</template>

				<!-- ask-template -->
				<template v-else-if="formTypeKeyList[item.type] && formTypeKeyList[item.type] === 's-ask-template'">
					<ask-template :showEditBtn="showEditBtn" ref="ask-template" @start-recording="$emit('start-recording')"
						@end-recording="$emit('end-recording')" :showAskTemplate="showAskTemplate"
						@event-callback="eventCallback" :record="item" @change-models="changeModels"
						@add-options="(options) => { askTemplateAdd(options, item) }" @change="changeAskTemplate"
						:disabled="disabled" :models="models"></ask-template>
				</template>

				<!-- doc-upload -->
				<template v-else-if="formTypeKeyList[item.type] && formTypeKeyList[item.type] === 's-doc-upload'">
					<doc-upload :suffixPath="suffixPath" @change="changeUploadDocValue" :headers="headers"
						:baseUrl="baseUrl" :showRemoveIcon="showRemoveIcon" :uploadSuccessHandler="uploadSuccessHandler"
						:uploadImgPreviewHandler="uploadImgPreviewHandler" :disabled="disabled" :models="models"
						:record="item"></doc-upload>
				</template>

			</s-form-item>
		</s-form>

		<s-datetime-picker v-model="dateTimeValue" @cancel="showDate = false" @close="showDate = false"
			@confirm="confirmDatePicker" :show="showDate" mode="datetime" closeOnClickOverlay></s-datetime-picker>

	</view>
</template>

<script>
import { getEmitModel } from "./utils/eventEmit"
import {
	parseTime
} from "./utils/index"
import DocUpload from "./doc-upload"
import DocSelect from "./doc-select"
import AskTemplate from "./ask-template"
export default {
	props: {
		// 每一项的样式
		formItemStyle: {
			type: Object,
			default: () => { }
		},
		// 传入的json数据
		formTemplate: {
			type: Object,
			default: () => { }
		},
		// 传入的当前models
		models: {
			type: Object,
			default: () => { }
		},
		// label固定位置
		labelPosition: {
			type: String,
			default: "left"
		},
		// label默认宽度
		labelWidth: {
			type: Number | String,
			default: "100"
		},
		// 是否禁用
		disabled: {
			type: Boolean,
			default: false
		},
		// 请求头
		headers: {
			type: Object,
			default: () => { }
		},
		// 问答模块是否显示模板按钮
		showAskTemplate: {
			type: Boolean,
			default: true
		},


		// 图片上传成功后生成预览图片地址的处理函数
		uploadImgPreviewHandler: {
			type: Function,
			default: () => { }
		},
		// 图片上传成功后将会把接口返回的数据添加到models，这里进行中间处理
		uploadSuccessHandler: {
			type: Function,
			default: null
		},
		// 是否显示可移除上传文件图标
		showRemoveIcon: {
			type: Boolean,
			default: true
		},
		// 部分应用内发起的请求有需要区分baseUrl
		baseUrl: {
			type: String,
			default: ""
		},
		// 图片上传成功后将会把接口返回的数据添加到models，这里进行中间处理
		uploadSuccessHandler: {
			type: Function | Promise,
			default: null
		},
		// 是否显示可移除图标
		suffixPath: {
			type: String,
			default: ""
		},
		// 问答模块是否显示模板按钮
		showEditBtn: {
			type: Boolean,
			default: true
		},
	},
	components: {
		DocSelect,
		AskTemplate,
		DocUpload
	},
	computed: {
		findValue() {
			return item => {
				if (item.options.options && item.options.options.length) {
					const index = item.options.options.findIndex(k => k.value == this.models[item.model])
					if (index > -1) {
						return item.options.options[index].label
					} else {
						return item.options.placeholder
					}
				} else {
					return item.options.defaultValue || item.options.placeholder
				}
			}
		}
	},
	data() {
		return {
			// 显示picker
			show: false,

			dateTimeValue: "",

			// 显示datePicker
			showDate: false,

			// 当前点击选中的datePicker
			currentPickerModel: "",

			// input、textarea、number、select、checkbox、radio、date、time、
			// datePicker、rate、slider、cascader、switch
			// pc端表单对应的移动端表单
			formTypeKeyList: {
				input: "s-input",
				number: "s-input",
				textarea: "s-textarea",
				select: "s-picker",
				checkbox: "s-checkbox-group",
				radio: "s-radio-group",
				time: "s-datetime-picker",
				date: "s-datetime-picker",
				datePicker: "s-datetime-picker",
				rate: "s-rate",
				slider: "s-slider",
				// cascader: "s-picker",
				switch: "s-switch",
				'doc-select': 's-doc-select',
				documentDatePicker: "s-datetime-picker",
				'ask-template': 's-ask-template',
				'doc-upload': 's-doc-upload'
			},

			// 循环的动态表单数据
			list: []
		}
	},
	created() {
		this.initList()
	},
	methods: {
		addOneQA(){
			this.$refs['ask-template'][0].addItem()
		},
		clickHandler(item) {
			// // 监听换行输入框自定义的blur事件
			// if (item.options && item.options.isOpenBlur) {
			// 	const eventData = getEmitModel('blur', item.options.eventKey, item.model, value)
			// 	this.$emit("event-callback", eventData)
			// }

			if (item.options && item.options.isOpenClick) {
				const eventData = getEmitModel(
					"click",
					item.options.eventKey,
					item.model, ""
				);
				this.$emit("event-callback", eventData);
			}
		},
		blurHandler(item) {
			console.log("blur item", item);
		},
		// 设置当前的录音文本
		setEndRecordText(text) {
			console.log("this.$refs['ask-template']", this.$refs['ask-template']);
			this.$refs['ask-template'][0].setEndRecordText(text)
		},
		eventCallback(data) {
			this.$emit("event-callback", data)
		},
		// 添加一个问答
		askTemplateAdd(options, item) {
			const key = item.key
			const index = this.list.findIndex((k) => k.key === key)
			if (index > -1) {
				this.list[index].options = JSON.parse(JSON.stringify(options))
			}
		},
		/**
		 * 当前models中对应数据修改后触发
		 * @param {*} key 
		 * @param {*} value 
		 */
		changeModels(key, value) {
			this.$set(this.models, key, value)
		},
		// ask-template 输入框数据变化
		changeAskTemplate(tempData, model) {
			const {
				index,
				value,
				type
			} = tempData
			if (this.models[model] && (typeof (this.models[model]) == 'string')) {
				// 获取当前问答模板对应的数据
				const data = JSON.parse(this.models[model])

				// 获取到当前操作的数据
				const currentData = data[index]
				const keys = Object.keys(currentData)
				// 更新当前的输入值
				currentData[type == 1 ? (keys[0]) : (keys[1])] = value
				// 更新输入后的值
				data[index] = currentData
				// 更新整体值
				this.$set(this.models, model, JSON.stringify(data))
			}
		},
		// 初始化数据	
		initList() {
			let tempList = []

			// 需要请求接口数据进行数据填充的
			let dynamicOptionsList = []

			if (this.formTemplate.list && this.formTemplate.list.length) {
				const result = this.changeObjectToList(this.formTemplate.list)
				tempList = result.filter(k => Object.hasOwn(this.formTypeKeyList, k.type))
			}

			for (let item of tempList) {
				if (['radio', 'checkbox', 'select'].includes(item.type)) {
					if (item.options.remoteFunc && item.options.dataPath && item.options.remoteLabel && item.options
						.remoteValue) {
						// 添加需要请求接口的promise对象
						dynamicOptionsList.push(
							this.getPromise(item.options.remoteFunc, item.key, item.options.dataPath, item.options
								.remoteLabel, item.options.remoteValue)
						)
					}
				}
			}

			Promise.all(dynamicOptionsList).then(res2 => {
				for (let item of res2) {
					const data = item.data[item.dataPath]
					const optionsList = data.map(k => {
						return {
							label: k[item.label],
							value: k[item.value]
						}
					})
					const index = tempList.findIndex(k => k.key == item.key)

					tempList[index].options.options = optionsList
				}
				this.list = tempList


			}).catch(error => {
				console.log("error", error);
			}).finally(() => {
				this.list = tempList

				this.list.forEach(item => {
					if (item.type == 'documentDatePicker') {
						const model = item.model
						// 是否开启了获取当前时间
						const isNowDate = item.options.isNowDate

						if (!this.models[model] && isNowDate) {
							this.$set(this.models, model, parseTime(new Date()))
						}

					}
				})
			})
		},
		/***
		 *  根据传入指定下标 动态新增List项
		 * 	lineConfig 新增项的下标  start开始   end结束  insertPosition插入位置
		 * 	field  重置的key
		 */ 
		 addListData(lineConfig, field) {
			if(!this.list.length > 0) return
			// 获取指定需要的数组项 进行深拷贝
			const copyList = JSON.parse(JSON.stringify(this.list.slice(lineConfig.start, lineConfig.end)));
			// 重置key  model
			copyList.map(item => {
				item.key = `${item.type}_${new Date().getTime() + Math.floor(Math.random() * 99) + 1}`
				item.model = `${item.model}${field}`
			})
			this.list.splice(lineConfig.insertPosition, 0, ...copyList);
		},
		/**
		 * start  开始     end   结束
		 */ 
		delListData(start, end) {
			if(!this.list.length > 0) return
			this.list.splice(start, (end - start));
		},

		/**
		 * 将当前最新的模板json返回
		 */
		getModel() {
			return new Promise((resolve, reject) => {
				const {
					config,
					list
				} = JSON.parse(JSON.stringify(this.formTemplate))
				const flexJson = list[0]
				flexJson.list = this.list

				list[0] = flexJson

				resolve({
					config,
					list
				})
			})
		},
		/**
		 * 返回一个uni.request 的promise对象
		 * @param {*} url 
		 * @param {*} dataPath 
		 * @param {*} label 
		 * @param {*} value 
		 */
		getPromise(url, key, dataPath, label, value) {
			return new Promise((resolve, reject) => {

				uni.request({
					url: url, //仅为示例，并非真实接口地址。
					header: this.headers,
					success: (res) => {
						resolve({
							data: res.data,
							dataPath,
							label,
							value,
							key
						})
					},
					error: (error) => {
						reject(error)
					}
				})

			})
		},
		// 将当前的物料操作的json压缩成一维的数组对象，方便表单模式进行遍历
		/**
		 * 
		 * @param {*} list 下一级需要遍历的数组
		 * @param {*} model 当前已找到的结果集
		 */
		changeObjectToList(list, models = []) {
			if (Array.isArray(list) && list.length) {
				for (let item of list) {
					// control和flex type类型子级数组采用的是list字段
					if (item.type === 'control' || item.type === 'flex') {
						this.changeObjectToList(item.list, models)
					} else if (item.type === 'grid') {
						if (item.columns && item.columns.length) {
							for (let sitem of item.columns) {
								if (sitem.list) {
									this.changeObjectToList(sitem.list, models)
								}
							}
						}
					} else if (item.type === 'table') {
						if (item.trs && item.trs.length) {
							for (let sitem of item.trs) {
								if (sitem.tds && sitem.tds.length) {
									for (let pitem of sitem.tds) {
										this.changeObjectToList(pitem.list, models)
									}
								}
							}
						}
					} else {
						// 排除容器组件剩余的普通组件
						if (item.model) {
							if (models.findIndex(k => k.model == item.model) < 0) {
								models.push(item)
							}
						}
					}
				}
			}
			return models
		},
		// 多选框改变
		changeCheckbox(value, item) {
			const labelArr = []
			if (value.length) {
				for (let sitem of item.options.options) {
					if (value.includes(sitem.value)) {
						labelArr.push(sitem.label)
					}
				}
				// 与pc端多选框选中models赋值保持一致
				this.$set(this.models, `${item.model}_label`, labelArr.join(","))
			}
		},
		// 单选框改变
		changeRadioBox(value, item) {
			if (value) {
				const label = item.options.options.find(k => k.value === value).label
				this.$set(this.models, `${item.model}_label`, label)
			}
		},
		getData() {
			return new Promise((resolve, reject) => {
				resolve(this.models)
			})
		},
		clickDatePicker(item) {
			if (this.disabled) return
			this.dateTimeValue = this.models[item.model];
			this.currentPickerModel = item.model
			this.showDate = true
		},
		/**日期事件函数确认操作
		 * @param {Object} e
		 * @param {Object} item
		 */
		confirmDatePicker(e) {
			const key = this.currentPickerModel
			const value = this.parseTime(new Date(e.value))
			this.$set(this.models, key, value)
			this.$emit("change", value, key)
			this.showDate = false
		},
		/**
		 * 文书select组件内部数据变化
		 * @param {*} key 
		 * @param {*} value 
		 */
		changeDocValue(key, value) {
			console.log(`value change: key ${key}  value ${value}`);
			this.$set(this.models, key, value)
		},
		changeUploadDocValue(key, value) {
			console.log(`value change: key ${key}  value ${value}`);
			this.$set(this.models, key, value)
		},
		/** 选择datetimePicker
		 * @param {Object} e picker回调事件
		 * @param {Object} item
		 */
		changeSelect(e, item) {
			const index = e.detail.value
			const key = item.model
			const value = item?.options?.options[e.detail.value]?.value
			if (value) {
				this.$set(this.models, key, value)
				this.$emit("change", value, key)
				console.log("item", item);
				console.log("this.models", this.models);
			}
		},
		/**
		 * @param {Object} time 目标时间字符串
		 * @param {Object} cFormat 需要转化成的时间格式
		 */
		parseTime(time, cFormat) {
			if (arguments.length === 0) {
				return null
			}

			// 默认格式
			const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
			let date
			if (typeof time === 'object') {
				date = time
			} else {
				if (('' + time).length === 10) time = parseInt(time) * 1000
				date = new Date(time)
			}
			const formatObj = {
				y: date.getFullYear(),
				m: date.getMonth() + 1,
				d: date.getDate(),
				h: date.getHours(),
				i: date.getMinutes(),
				s: date.getSeconds(),
				a: date.getDay()
			}
			const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
				let value = formatObj[key]
				if (key === 'a') {
					.0.return['一', '二', '三', '四', '五', '六', '日'][value - 1]
				}
				if (result.length > 0 && value < 10) {
					value = '0' + value
				}
				return value || 0
			})
			return time_str
		}
	}
}
</script>

<style lang="scss" scoped>
.s-dynamic-form-wrapper {
	.my-border {
		border-width: 0.5px !important;
		padding: 8px 12px;
		width: 100%;

		border-color: #DADBDE !important;
		border-style: solid;
		border-radius: 4px;
		padding-left: 12px;
	}

	.disabled-text {
		color: rgb(153, 153, 153);
	}
}
</style>
