<template>
	<div class="node">
		<ElDrawer destroy-on-close append-to-body :title="title" ref="drawerRef" @close="handleClose" v-model="showDrawer">
			<component
				:is="componentType"
				v-model="formData"
				:extendAttrConfig="props.extendAttrConfig || {}"
				ref="ruleFormRef"
				@countersignStartStepCodeChange="countersignStartStepCodeChange"
				:baseData="props.baseData"
				:nodes="props.nodes"
			/>
			<template #footer>
				<div style="flex: auto">
					<el-button @click="showDrawer = false" class="default-button">取 消</el-button>
					<el-button type="primary" @click="confirmClick(ruleFormRef)">保 存</el-button>
				</div>
			</template>
		</ElDrawer>
	</div>
</template>
<script lang="ts" setup name="flowMain">
import { computed, defineAsyncComponent, reactive, ref, unref } from 'vue';
import { NodeTypeEnum } from '../enums';

const task = defineAsyncComponent(() => import('./task.vue'));
const start = defineAsyncComponent(() => import('./start.vue'));
const end = defineAsyncComponent(() => import('./end.vue'));
const showDrawer = ref(false); // 是否显示抽屉
const drawerRef = ref(null); // 抽屉ref
let formData = reactive<any>({} as any); // 表单数据
const ruleFormRef = ref<RefType>(); // 表单ref
const NODE_NAME_LIST = ['hotline:start', 'hotline:task','hotline:end'] as string[];
// 组件列表
const COMPONENT_LIST: any = {
	task,
	start,
	end,
};
// 事件
const emits = defineEmits(['change', 'changeOther']);
// 定义属性
const props = defineProps({
	extendAttrConfig: {
		// 扩展属性配置
		type: Object,
		required: false,
		default: () => {},
	},
	baseData: {
		type: Object,
		required: false,
		default: () => {},
	},
	nodes: {
		type: Array,
		required: false,
		default: () => [],
	},
});
// 标题
const title = computed(() => {
	if (formData.type === 'process') {
		return '设置模板属性';
	} else if (formData.type === 'hotline:transition') {
		return '设置边属性';
	} else if (NODE_NAME_LIST.includes(formData.type)) {
		return '设置节点属性';
	}
	return '';
});
// 组件类型
const componentType = computed(() => {
	const mFormData = unref(formData);
	if (!mFormData || !mFormData.type) return;
	return COMPONENT_LIST[mFormData.type.replace('hotline:', '')];
});
// 节点名称
const nodeName = computed((): NodeTypeEnum => {
	const mFormData = unref(formData);
	if (!mFormData || !mFormData.type) return NodeTypeEnum.ignore;
	return mFormData.type.replace('hotline:', '') as unknown as NodeTypeEnum;
});
// 处理emits
const handleEmits = (propertyName: string, propertyValue: any) => {
	if (propertyValue === undefined) return;
	emits('change', {
		type: unref(nodeName),
		propertyName: propertyName,
		propertyValue: propertyValue,
	} as any);
};
// 处理其他节点emits
const handleEmitsOther = (propertyName: string, propertyValue: any, type: any, id: any) => {
	if (propertyValue === undefined) return;
	emits('changeOther', {
		type: type,
		propertyName: propertyName,
		propertyValue: propertyValue,
		id: id,
	} as any);
};

// 表单属性keys
const propertyKeys: Array<string> = [
	// 流程属性
	'name',
	'code',
	'id',
	'flowType',
	'description',
	// 节点属性
	'name',
	'code',
	'stepType',
	'businessType',
	'handlerType',
	'handlerTypeItems',
	'canReject',
	'executeMode',
	'canStartCountersign',
	'countersignPolicy',
	'instanceMode',
	'instancePolicy',
	'terminalDynamicMark',
	'tag',
	'summaryTargetCode',
];
// 去重后的key
const propertyKeysSet = Array.from(new Set(propertyKeys));
// 显示抽屉
const show = (args: any) => {
	// 将args的值复制给formData
	Object.assign(formData, args);
	showDrawer.value = true;
};
// 抽屉关闭处理
const handleClose = () => {
	// 清空表单值
	Object.keys(formData).forEach((key: string) => {
		delete formData[key];
	});
};
// 会签节点变化
const countersignStartStepCodeChange = (val: any) => {
	propertyKeysSet.forEach((key: string) => {
		// 监听其他节点属性变化
		handleEmitsOther(key, val[key], val.type, val.id);
	});
};
// 保存
const confirmClick = (formEl: any | undefined) => {
	if (!formEl) return;
	formEl.ruleFormRef.validate((valid: boolean) => {
		if (!valid) return;
		propertyKeysSet.forEach((key: string) => {
			// 监听属性变化
			handleEmits(key, formData[key]);
		});
		showDrawer.value = false;
	});
};
// 导入属性及方法给外部调用
defineExpose({
	show,
});
</script>
