<!-- 
    filename: dialogForm.vue
    author: liubin
    date: 2023-08-02 10:32:36
    description: 弹窗的表单组件
-->

<template>
	<el-form
		ref="form"
		:model="form"
		:label-width="`${labelWidth}px`"
		v-loading="formLoading">
		<el-row :gutter="20" v-for="(row, rindex) in rows" :key="rindex">
			<el-col v-for="col in row" :key="col.label" :span="24 / row.length">
				<el-form-item :label="col.label" :prop="col.prop" :rules="col.rules">
					<el-input
						v-if="col.input"
						v-model="form[col.prop]"
						@change="$emit('update', form)"
						:placeholder="`请输入${col.label}`"
						v-bind="col.bind" />
					<el-input
						v-if="col.textarea"
						type="textarea"
						v-model="form[col.prop]"
						@change="$emit('update', form)"
						:placeholder="`请输入${col.label}`"
						v-bind="col.bind" />
					<el-select
						v-if="col.select"
						v-model="form[col.prop]"
						:placeholder="`请选择${col.label}`"
						@change="$emit('update', form)"
						v-bind="col.bind">
						<el-option
							v-for="opt in optionListOf[col.prop]"
							:key="opt.value"
							:label="opt.label"
							:value="opt.value" />
					</el-select>
					<el-date-picker
						v-if="col.datetime"
						v-model="form[col.prop]"
						type="datetime"
						:placeholder="`请选择${col.label}`"
						v-bind="col.bind"></el-date-picker>
				</el-form-item>
			</el-col>
		</el-row>
	</el-form>
</template>

<script>
/**
 * 找到最长的label
 * @param {*} options
 */
function findMaxLabelWidth(rows) {
	let max = 0;
	rows.forEach((row) => {
		row.forEach((opt) => {
			if (opt.label.length > max) {
				max = opt.label.length;
			}
		});
	});
	return max;
}

export default {
	name: 'DialogForm',
	model: {
		prop: 'dataForm',
		event: 'update',
	},
	emits: ['update'],
	components: {},
	props: {
		rows: {
			type: Array,
			default: () => [],
		},
		dataForm: {
			type: Object,
			default: () => ({}),
		},
	},
	data() {
		return {
			formLoading: true,
			optionListOf: {},
		};
	},
	computed: {
		labelWidth() {
			let max = findMaxLabelWidth(this.rows);
			// 每个汉字占20px
			return max * 20;
			// return max * 20 + 'px';
		},
		form: {
			get() {
				return this.dataForm;
			},
			set(val) {
				console.log('set form', val);
			},
		},
	},
	watch: {
		rows: {
			handler() {
				console.log('watch triggered!');
				this.$nextTick(() => {
					this.handleOptions('watch');
				});
			},
			deep: true,
			immediate: false,
		},
	},
	mounted() {
		// 处理 options
		this.handleOptions();
	},
	methods: {
		/** 模拟透传 ref  */
		validate(cb) {
			return this.$refs.form.validate(cb);
		},
		resetFields(args) {
			return this.$refs.form.resetFields(args);
		},
		// getCode
		async getCode(url) {
			const response = await this.$axios(url);
			return response.data;
		},
		async handleOptions(trigger = 'monuted') {
			// console.log("[dialogForm:handleOptions]")
			const promiseList = [];
			this.rows.forEach((cols) => {
				cols.forEach((opt) => {
					if (opt.value && !this.form[opt.prop]) {
						// 默认值
						this.form[opt.prop] = opt.value;
					}

					if (opt.options) {
						this.$set(this.optionListOf, opt.prop, opt.options);
					} else if (opt.url) {
						// 如果是下拉框，或者新增模式下的输入框，才去请求
						if (opt.select || (opt.input && !this.form?.id)) {
							promiseList.push(async () => {
								const response = await this.$axios(opt.url, {
									method: opt.method ?? 'get',
								});
								console.log('[dialogForm:handleOptions:response]', response);
								if (opt.select) {
									// 处理下拉框选项
									const list =
										'list' in response.data
											? response.data.list
											: response.data;
									this.$set(
										this.optionListOf,
										opt.prop,
										list.map((item) => ({
											label: item[opt.labelKey ?? 'name'],
											value: item[opt.valueKey ?? 'id'],
										}))
									);
								} else if (opt.input) {
									// 处理输入框数据
									this.form[opt.prop] = response.data;
								}
							});
						}
					}
				});
			});

			// 如果是 watch 触发的，不需要执行进一步的请求
			if (trigger == 'watch') {
				this.formLoading = false;
				return;
			}
			try {
				await Promise.all(promiseList.map((fn) => fn()));
				this.formLoading = false;
				// console.log("[dialogForm:handleOptions:optionListOf]", this.optionListOf)
			} catch (error) {
				console.log('[dialogForm:handleOptions:error]', error);
				this.formLoading = false;
			}
			if (!promiseList.length) this.formLoading = false;
		},
	},
};
</script>

<style scoped lang="scss">
.el-date-editor,
.el-select {
	width: 100%;
}
</style>
