解析psd文件,并映射成组件

const comsData = ref([]);
const closed = () => {
	comsData.value = [];
};
const menu = useMenuStore();
const frame = useFrameStore();
const psdFileRef = ref(null);
const psdFileHandler = e => {
	loadingInstance.value = ElLoading.service({
		// target: '#main'
		// customClass: 'el-loading--custom',
		background: 'rgba(0, 0, 0, 0.8)',
		text: '',
	});
	const reader = new FileReader();
	reader.onloadend = () => {
		onDrop({
			dataTransfer: { files: [psdFileRef.value.files[0]] },
			target: {
				result: null,
			},
		})
	};
	reader.readAsText(psdFileRef.value.files[0], 'utf8');
	loadingInstance.value.close();
};

var PSD = require('psd');
const onDragOver = e => {
	e.stopPropagation();
	e.preventDefault();
	e.dataTransfer.dropEffect = 'copy';
};
const onDrop = e => {
	repeatNumber++;
	loadingInstance.value = ElLoading.service({
		// target: '#main'
		// customClass: 'el-loading--custom',
		background: 'rgba(0, 0, 0, 0.8)',
		text: '',
	});
	PSD.fromEvent(e).then(function (psd) {
		const config = psd.tree().export();
		const { children } = config;
		const { width, height } = config.document; //页面宽高
		// frame.center.height = height
		// frame.center.width = width
		dgc(children, psd.tree().children());
	});
	loadingInstance.value.close();
};
const dataURLtoBlob = dataurl => {
	let arr = dataurl.split(','),
		mime = arr[0].match(/:(.*?);/)[1],
		bstr = atob(arr[1]),
		n = bstr.length,
		u8arr = new Uint8Array(n);
	while (n--) {
		u8arr[n] = bstr.charCodeAt(n);
	}
	return new Blob([u8arr], { type: mime });
};
let repeatNumber = 0; //同个文件上传失败次数
const loadingInstance = ref(null);

const dgc = (c, tree) => {
	for (let i = 0; i < c.length; i++) {
		const item = c[i];
		const t = tree[i];
		const { visible, children, type } = item;
		//children存在或者type==='group'证明有子,否则就是可用项
		if (visible && children) {
			dgc(children, t.children());
		} else if (visible) {
			const { name, text, width, height, bottom, left, top } = item;
			if (text && width > 0 && height > 0) {
				setCom(item, 'text');
			} else if (width > 0 && height > 0) {
				let file = new File([dataURLtoBlob(t.toPng().src)], `${name || 'file'}.png`);
				let formData = new FormData();
				formData.append('file', file);
				setCom(item, 'rect', formData);
				//挂载图片组件
				// t.toBase64();
				// document.getElementById('image').appendChild(t.toPng());
			}
		}
	}
	console.log('当前组件22', comsData.value);
};
// 映射生成组件
const setCom = async (item, comType, formData) => {
	const { name, text, width, height, bottom, left, top, type } = item;
	const options = {
		type: comType == 'text' ? 'text' : 'rect',
		model: 'base',
		style: {
			left,
			top,
			'z-index': 100, //随便给的,后面点击确定按钮会重置
		},
	};
	if (comType == 'text') {
		const { value } = text;
		const com = getInitialAttrs(options);
		if (com) {
			const { model, type } = com;
			com.vueData[`${model}_${type}`].gWidth = null;
			com.vueData[`${model}_${type}`].gHeight = null;
			com.vueData[`${model}_${type}`].text = value;
			com.vueData[`${model}_${type}`].fontSize = text.font.sizes[0];
			com.vueData[`${model}_${type}`].color = `rgba(${text.font.colors[0]})`;
		}
		comsData.value.unshift(com);
	} else if (comType == 'rect') {
		const rectCom = getInitialAttrs(options);
		// 上传图片,并返回地址
		const url = await sendImage(formData)
			.then(res => {
				if (res.data.StatusCode == 200) {
					return res.data.Data;
				}
				repeatNumber = 0;
			})
			.catch(err => {
				if (repeatNumber < 5) {
					setCom(item, comType, formData, index);
				}
			});
		if (rectCom) {
			const { model, type } = rectCom;
			rectCom.vueData[`${model}_${type}`].backgroundImage = url;
			rectCom.vueData[`${model}_${type}`].gWidth = width;
			rectCom.vueData[`${model}_${type}`].gHeight = height;
			rectCom.vueData[`${model}_${type}`].urlPre = 'http://192.168.0.150:8008';
		}
		comsData.value.unshift(rectCom);
	}
};
const sendImage = formData => {
	const url = `${domain.uploadUrl}${uploadFile}`;
	return axios({
		method: 'post',
		url,
		data: formData,
		headers: {
			accesstoken: 'adcf40f89d4acd38bddb9',
			app: 'cloudconfigure',
			ext: '.png',
		},
	});
};

原来文件

<template>
	<el-dialog
		v-model="state.dialogVisible"
		:title="props.dialogType == 'new' ? '新建页面' : '编辑页面'"
		width="400px"
		custom-class="pageDialog_container"
		:destroy-on-close="true"
		:before-close="close"
		@closed="closed"
	>
		<!-- custom-class="pageList_dialog" -->
		<!-- :rules="rules" -->
		<el-form ref="pageFromRef" :model="state.pageFrom" :rules="rules" label-width="100px">
			<el-form-item label="页面名称" prop="name">
				<el-input
					v-model="state.pageFrom.name"
					autocomplete="off"
					placeholder="请输入页面名称"
					style="width: 250px"
				/>
			</el-form-item>
			<el-form-item v-if="props.dialogType == 'new'" label="页面类型" prop="type">
				<el-select v-model="state.pageFrom.type" placeholder="请选择页面类型" style="width: 250px">
					<el-option
						v-for="(item, index) in localPageList"
						:value="item.value"
						:label="item.label"
						:key="item.value"
					></el-option>
				</el-select>
			</el-form-item>
			<el-form-item label="页面权限" prop="authority">
				<el-select
					v-model="state.pageFrom.authority"
					placeholder="请选择是页面权限"
					style="width: 250px"
				>
					<el-option
						v-for="(item, i) in authorityList"
						:key="i"
						:value="item.value"
						:label="item.label"
					></el-option>
				</el-select>
			</el-form-item>
			<el-form-item label="菜单隐藏" v-show="!state.pageFrom.isShowMenuPage" prop="isHide">
				<el-select
					v-model="state.pageFrom.isHide"
					placeholder="请选择是否隐藏菜单栏"
					style="width: 250px"
				>
					<el-option
						v-for="item in menuStatus"
						:key="item.value"
						:label="item.label"
						:value="item.value"
					></el-option>
				</el-select>
			</el-form-item>
			<el-form-item label="弹框主题" v-show="state.pageFrom.isShowMenuPage">
				<el-select v-model="state.pageFrom.themeProDialog" style="width: 250px">
					<el-option
						v-for="(item, i) in themeList"
						:key="i"
						:value="item.value"
						:label="item.label"
					>
					</el-option>
				</el-select>
			</el-form-item>
			<el-form-item v-if="props.dialogType == 'new'" label="窗口页面">
				<el-switch
					:disabled="dialogType == 'edit'"
					v-model="state.pageFrom.isShowMenuPage"
				></el-switch>
			</el-form-item>
			<el-form-item label="解析psd">
				<div class="psdFile_container">
					<el-icon class="hand_icon"><Plus /></el-icon>
					<input
						class="fileInput"
						type="file"
						ref="psdFileRef"
						accept=".psd"
						@change="psdFileHandler"
					/>
				</div>
			</el-form-item>
		</el-form>
		<div class="dialog_footer flex_c">
			<el-button type="primary" class="OKbtn" @click="confirmHandler">确定</el-button>
			<el-button class="cancelbtn" @click="cancelHandler">取消</el-button>
		</div>
	</el-dialog>
</template>
<script setup>
import { ref, onMounted, reactive, toRefs, nextTick } from 'vue';
import { Plus } from '@element-plus/icons-vue';
import { useMenuStore, useFrameStore } from '@/store';
import { newPageList } from '@/hooks/useMouseMenu.js';
import { getInitialAttrs } from '@/components/CenterEdit/hooks/useCompt/add.js';
import { state as centerStore, setBodyVueMap, addPageCompt } from '@/hooks/useCenterHook.js';
import domain from '@/utils/http/domain.http.js';
import { uploadFile } from '@/utils/http/api.http';
import axios from 'axios';
import { ElMessage, ElLoading } from 'element-plus';
import { maxZindex } from '@/components/CenterEdit/hooks/useCompt/index.js';

const comsData = ref([]);
const closed = () => {
	comsData.value = [];
};
const menu = useMenuStore();
const frame = useFrameStore();
const psdFileRef = ref(null);
const psdFileHandler = e => {
	loadingInstance.value = ElLoading.service({
		// target: '#main'
		// customClass: 'el-loading--custom',
		background: 'rgba(0, 0, 0, 0.8)',
		text: '',
	});
	const reader = new FileReader();
	reader.onloadend = () => {
		onDrop({
			dataTransfer: { files: [psdFileRef.value.files[0]] },
			target: {
				result: null,
			},
		})
	};
	reader.readAsText(psdFileRef.value.files[0], 'utf8');
	loadingInstance.value.close();
};

var PSD = require('psd');
const onDragOver = e => {
	e.stopPropagation();
	e.preventDefault();
	e.dataTransfer.dropEffect = 'copy';
};
const onDrop = e => {
	repeatNumber++;
	loadingInstance.value = ElLoading.service({
		// target: '#main'
		// customClass: 'el-loading--custom',
		background: 'rgba(0, 0, 0, 0.8)',
		text: '',
	});
	PSD.fromEvent(e).then(function (psd) {
		const config = psd.tree().export();
		const { children } = config;
		const { width, height } = config.document; //页面宽高
		// frame.center.height = height
		// frame.center.width = width
		dgc(children, psd.tree().children());
	});
	loadingInstance.value.close();
};
const dataURLtoBlob = dataurl => {
	let arr = dataurl.split(','),
		mime = arr[0].match(/:(.*?);/)[1],
		bstr = atob(arr[1]),
		n = bstr.length,
		u8arr = new Uint8Array(n);
	while (n--) {
		u8arr[n] = bstr.charCodeAt(n);
	}
	return new Blob([u8arr], { type: mime });
};
let repeatNumber = 0; //同个文件上传失败次数
const loadingInstance = ref(null);

const dgc = (c, tree) => {
	for (let i = 0; i < c.length; i++) {
		const item = c[i];
		const t = tree[i];
		const { visible, children, type } = item;
		//children存在或者type==='group'证明有子,否则就是可用项
		if (visible && children) {
			dgc(children, t.children());
		} else if (visible) {
			const { name, text, width, height, bottom, left, top } = item;
			if (text && width > 0 && height > 0) {
				setCom(item, 'text');
			} else if (width > 0 && height > 0) {
				let file = new File([dataURLtoBlob(t.toPng().src)], `${name || 'file'}.png`);
				let formData = new FormData();
				formData.append('file', file);
				setCom(item, 'rect', formData);
				//挂载图片组件
				// t.toBase64();
				// document.getElementById('image').appendChild(t.toPng());
			}
		}
	}
	console.log('当前组件22', comsData.value);
};
// 映射生成组件
const setCom = async (item, comType, formData) => {
	const { name, text, width, height, bottom, left, top, type } = item;
	const options = {
		type: comType == 'text' ? 'text' : 'rect',
		model: 'base',
		style: {
			left,
			top,
			'z-index': 100, //随便给的,后面点击确定按钮会重置
		},
	};
	if (comType == 'text') {
		const { value } = text;
		const com = getInitialAttrs(options);
		if (com) {
			const { model, type } = com;
			com.vueData[`${model}_${type}`].gWidth = null;
			com.vueData[`${model}_${type}`].gHeight = null;
			com.vueData[`${model}_${type}`].text = value;
			com.vueData[`${model}_${type}`].fontSize = text.font.sizes[0];
			com.vueData[`${model}_${type}`].color = `rgba(${text.font.colors[0]})`;
		}
		comsData.value.unshift(com);
	} else if (comType == 'rect') {
		const rectCom = getInitialAttrs(options);
		// 上传图片,并返回地址
		const url = await sendImage(formData)
			.then(res => {
				if (res.data.StatusCode == 200) {
					return res.data.Data;
				}
				repeatNumber = 0;
			})
			.catch(err => {
				if (repeatNumber < 5) {
					setCom(item, comType, formData, index);
				}
			});
		if (rectCom) {
			const { model, type } = rectCom;
			rectCom.vueData[`${model}_${type}`].backgroundImage = url;
			rectCom.vueData[`${model}_${type}`].gWidth = width;
			rectCom.vueData[`${model}_${type}`].gHeight = height;
			rectCom.vueData[`${model}_${type}`].urlPre = 'http://192.168.0.150:8008';
		}
		comsData.value.unshift(rectCom);
	}
};
const sendImage = formData => {
	const url = `${domain.uploadUrl}${uploadFile}`;
	return axios({
		method: 'post',
		url,
		data: formData,
		headers: {
			accesstoken: 'adcf40f89d4acd38bddb9',
			app: 'cloudconfigure',
			ext: '.png',
		},
	});
};
// const isActivePsd = e => {
// 	document.getElementById('dropzone').addEventListener('dragover', onDragOver, true);
// 	document.getElementById('dropzone').addEventListener('drop', onDrop, true);
// };
const localPageList = Object.freeze([
	{ label: '单页面', value: 'opage' },
	{ label: '多页面', value: 'mpage' },
]);
const authorityList = Object.freeze([
	{ label: '零级权限', value: 0 },
	{ label: '一级权限', value: 1 },
	{ label: '二级权限', value: 2 },
	{ label: '三级权限', value: 3 },
	{ label: '四级权限', value: 4 },
	{ label: '五级权限', value: 5 },
]);
const menuStatus = Object.freeze([
	{
		label: '显示菜单',
		value: '0',
	},
	{
		label: '隐藏菜单',
		value: '1',
	},
	{
		label: '全屏显示',
		value: '2',
	},
]);
const themeList = Object.freeze([
	{ label: '主题一', value: 'black' },
	{ label: '主题二', value: 'white' },
]);
const props = defineProps({
	//弹框类型
	dialogType: {
		type: String,
		default: 'new', //edit
	},
	//编辑菜单的数据
	pageItem: {
		type: Object,
		default: () => {
			return {
				name: '',
				type: 'opage',
				isHide: '0', //菜单隐藏
				authority: 0, //页面权限
				isShowMenuPage: false, // 是否显示菜单隐藏
				themeProDialog: 'black', // 主题
				size: 0,
			};
		},
	},
});

const pageFromRef = ref(null);
const state = reactive({
	dialogVisible: false,
	pageFrom: {
		name: '',
		type: 'opage',
		isHide: '0', //菜单隐藏
		authority: 0, //页面权限
		isShowMenuPage: false, // 是否显示菜单隐藏
		themeProDialog: 'black', // 主题
		size: 0,
	},
});
//校验
const validatePageName = (rule, value, callback) => {
	const tempI = menu.pageList.findIndex(item => item.name == value);
	if (value === '') {
		callback(new Error('请输入页面名称'));
	} else if (tempI != -1) {
		callback(new Error('页面名称不能重复哦!'));
	} else {
		callback();
	}
};
const rules = reactive({
	name: [{ required: true, validator: validatePageName, trigger: 'blur' }],
	type: [{ required: true, message: '必填项', trigger: 'blur' }],
	authority: [{ required: true, message: '必填项', trigger: 'blur' }],
});

const createdPageList = data => {
	const type = props.dialogType;
	if (type == 'new') {
		//新建页面
		newPageList(state.pageFrom);
		// 添加组件
		addPsdCom(state.pageFrom.id, comsData.value);
	} else {
		//编辑页面
		editPageList();
	}
};

const addPsdCom = (id, datas) => {
	const page = centerStore.pageData.find(item => item.id == id);
	datas.forEach((item, index) => {
		const { model, type } = item;
		item.vueData[`${model}_${type}`].gZindex = index + maxZindex.value;
		setBodyVueMap(item);
	});
	page.pageCompts.push(...datas);
	console.log('最终的centerStore', centerStore);
};

//编辑页面
const editPageList = () => {
	// 取出变化值塞给pageList项
	menu.replacePageList(JSON.parse(JSON.stringify(state.pageFrom)));
};
// 确定和取消按钮
const confirmHandler = () => {
	if (!pageFromRef.value) return;
	pageFromRef.value.validate(valid => {
		if (valid) {
			createdPageList(); //数据操作
			cancelHandler(); //弹框关闭操作
		} else {
			return false;
		}
	});
};
const cancelHandler = () => {
	close();
};
const resetPageForm = () => {
	state.pageFrom = {
		name: '',
		type: 'opage',
		isHide: '0', //菜单隐藏
		authority: 0, //页面权限
		isShowMenuPage: false, // 是否显示菜单隐藏
		themeProDialog: 'black', // 主题
	};
};
//open/close暴露出去用
const open = () => {
	state.dialogVisible = true;
};
const close = () => {
	if (!pageFromRef.value) return;
	pageFromRef.value.resetFields();
	resetPageForm();
	state.dialogVisible = false;
};
//初始化弹框数据,不走props,父组件还要传递数据
const initEditData = params => {
	Object.assign(state.pageFrom, params);
};

defineExpose({
	...toRefs(state),
	open,
	close,
	initEditData,
});
</script>
<style lang="less">
.pageDialog_container {
	.el-dialog__body {
		padding: 15px;
	}
	.el-dialog__footer {
		padding: 0 !important;
	}
}
#dropzone {
	margin-left: 20px;
	height: 32px;
	width: 190px;
	border: 1px #ababab dashed;
	box-sizing: border-box;
}

#dropzone p {
	text-align: center;
	line-height: 32px;
	margin: 0;
	padding: 0;
}
.psdFile_container {
	border: 1px #ababab dashed;
	width: 40px;
	height: 20px;
	position: relative;
	.hand_icon {
		position: absolute;
		left: 50%;
		top: 50%;
		transform: translate(-50%, -50%);
	}
	.fileInput {
		width: 40px;
		height: 20px;
		opacity: 0;
	}
}
</style>

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值