123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- <template>
- <div class="meta2d">
- <div class="tools">
- <t-tooltip content="新建" placement="bottom">
- <a><t-icon name="add" @click="newFile" /></a>
- </t-tooltip>
- <t-tooltip content="保存" placement="bottom">
- <a> <t-icon name="save" @click="save" /></a>
- </t-tooltip>
- <t-tooltip content="保存为模板" placement="bottom">
- <a><t-icon name="layers" @click="saveAsComponents" /></a>
- </t-tooltip>
- <t-tooltip content="格式化" placement="bottom">
- <a>
- <svg
- width="1em"
- height="1em"
- viewBox="0 0 256 256"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- >
- <defs><path id="77456364" d="M0 0h256v256H0z"></path></defs>
- <g fill="none" fill-rule="evenodd">
- <mask id="3804093554b" fill="#fff">
- <use xlink:href="#77456364"></use>
- </mask>
- <path
- d="M213 77c0 14.36-11.64 26-26 26H69c-14.36 0-26-11.64-26-26V51c0-14.36 11.64-26 26-26h118c14.36 0 26 11.64 26 26v2h9.125c9.83 0 17.82 7.88 17.997 17.67l.003.33v50c0 9.83-7.88 17.82-17.67 17.997l-.33.003h-84.626v18H139c9.83 0 17.82 7.88 17.997 17.67l.003.33v35c0 16.016-12.984 29-29 29-15.856 0-28.74-12.725-28.996-28.52L99 210v-35c0-9.83 7.88-17.82 17.67-17.997L117 157h.499l.001-20c0-9.83 7.88-17.82 17.67-17.997l.33-.003h84.625V73H213Zm-76 100h-18v33a9 9 0 0 0 8.471 8.985l.264.011.265.004a9 9 0 0 0 8.996-8.735L137 210v-33Zm50-132H69a6 6 0 0 0-6 6v26a6 6 0 0 0 6 6h118a6 6 0 0 0 6-6V51a6 6 0 0 0-6-6Z"
- fill="currentColor"
- fill-rule="nonzero"
- mask="url(#3804093554b)"
- ></path>
- </g>
- </svg>
- </a>
- </t-tooltip>
- <t-tooltip content="清除格式" placement="bottom">
- <a>
- <svg
- width="1em"
- height="1em"
- viewBox="0 0 1024 1024"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M889.186 384.07 677.671 172.56c-53.063-53.063-139.094-53.063-192.157 0L134.617 523.457c-53.063 53.063-53.063 139.099 0 192.158l170.196 170.2a41.354 41.354 0 0 0 29.243 12.11h215.001a41.354 41.354 0 0 0 29.184-12.05L889.155 576.26c53.094-53.09 53.094-139.126.031-192.19zM830.7 442.558c20.48 20.472 20.764 53.492.855 74.319l-.961.984-298.618 297.358H351.185l-158.09-158.086c-20.76-20.763-20.76-54.43 0-75.193l350.901-350.897c20.764-20.764 54.43-20.764 75.193 0l211.515 211.511z"
- fill="currentColor"
- ></path>
- <path
- d="m685.505 678.754-58.19 58.77-317.587-314.43 58.191-58.774zm197.55 136.508c23.46 0 42.483 18.514 42.483 41.353 0 22.45-18.38 40.724-41.294 41.338l-1.19.016h-454.6c-23.462 0-42.485-18.514-42.485-41.354 0-22.449 18.381-40.723 41.295-41.338l1.19-.015h454.6z"
- fill="currentColor"
- ></path>
- </svg>
- </a>
- </t-tooltip>
- <div class="flex-grow"></div>
- <t-tooltip content="直线" placement="bottom">
- <a><t-icon name="slash" /></a>
- </t-tooltip>
- <t-tooltip content="文字" placement="bottom">
- <a>T</a>
- </t-tooltip>
- <t-tooltip content="图片" placement="bottom">
- <a><t-icon name="image" /></a>
- </t-tooltip>
- <t-tooltip content="视图大小" placement="bottom">
- <div style="line-height: 40px; margin-left: 8px">100%</div>
- </t-tooltip>
- <t-tooltip content="100%视图" placement="bottom">
- <a><t-icon name="refresh" /></a>
- </t-tooltip>
- <t-tooltip content="窗口大小" placement="bottom">
- <a><t-icon name="minus-rectangle" /></a>
- </t-tooltip>
- <t-tooltip content="数据源" placement="bottom">
- <a><t-icon name="server" /></a>
- </t-tooltip>
- <div class="flex-grow"></div>
- <t-tooltip content="预览" placement="bottom">
- <a><t-icon name="browse" /></a>
- </t-tooltip>
- <t-tooltip content="运行" placement="bottom">
- <a><t-icon name="caret-right" /></a>
- </t-tooltip>
- <t-tooltip content="手机查看" placement="bottom">
- <a><t-icon name="qrcode" /></a>
- </t-tooltip>
- <t-tooltip content="分享" placement="bottom">
- <a><t-icon name="share" /></a>
- </t-tooltip>
- <t-tooltip content="发布" placement="bottom">
- <a><t-icon name="cloud" /></a>
- </t-tooltip>
- </div>
- <div id="meta2d"></div>
- </div>
- </template>
- <script lang="ts" setup>
- import { Meta2d, Options } from "@meta2d/core";
- import { onMounted, onUnmounted ,watch} from "vue";
- import { registerBasicDiagram } from "@/services/register";
- import { Meta2dBackData, checkData } from "@/services/utils";
- import { useRouter, useRoute } from "vue-router";
- import { useUser } from "@/services/user";
- import { MessagePlugin } from "tdesign-vue-next";
- import localforage from "localforage";
- import { dataURLtoBlob, upload } from "@/services/file";
- import {
- delImage,
- getFolders,
- addCollection,
- updateCollection,
- updateFolders,
- } from "@/services/api";
- import { baseVer } from "@/services/upgrade";
- const router = useRouter();
- const route = useRoute();
- const { user, message, getUser, getMessage, signout } = useUser();
- const meta2dOptions: Options = {
- cdn: "https://assets.le5lecdn.com",
- rule: true,
- background: '#1e2430',
- x: 32,
- y: 32,
- width: 1920,
- height: 1080,
- };
- onMounted(() => {
- meta2d = new Meta2d('meta2d', meta2dOptions);
- registerBasicDiagram();
- open();
- });
- const watcher = watch(
- () => route.query.id,
- async () => {
- open();
- }
- );
- const open = async () => {
- if (route.query.id) {
- const ret: any = await axios.post('/data/le5le2d/get', {
- id: route.query.id,
- });
- ret && meta2d.open(ret);
- } else {
- meta2d.open();
- }
- };
- onUnmounted(() => {
- watcher();
- if (meta2d) {
- meta2d.destroy();
- }
- });
- enum SaveType {
- Save,
- SaveAs,
- }
- //本地保存图纸数据 key
- const localMeta2dDataName = "meta2dData";
- const save = async (type: SaveType = SaveType.Save) => {
- (<any>globalThis).meta2d.stopAnimate();
- const data: Meta2dBackData = (<any>globalThis).meta2d.data();
- if (!(user && user.username)) {
- MessagePlugin.warning("请先登录,否则无法保存!");
- localforage.setItem(localMeta2dDataName, JSON.stringify(data));
- return;
- }
- checkData(data);
- if (!data._id && route.query.id) {
- data._id = route.query.id as string;
- }
- if (
- (globalThis as any).beforeSaveMeta2d &&
- !(await (globalThis as any).beforeSaveMeta2d(data))
- ) {
- return;
- }
- if (type === SaveType.SaveAs) {
- //另存为去掉teams信息
- delete data.teams;
- }
- //如果不是自己创建的团队图纸,就不去修改缩略图(没有权限去删除缩略图)
- if (!((data as any).teams && data.owner?.id !== user.id)) {
- let blob: Blob;
- try {
- blob = dataURLtoBlob((<any>globalThis).meta2d.toPng(10));
- } catch (e) {
- MessagePlugin.error(
- "无法下载,宽度不合法,画布可能没有画笔/画布大小超出浏览器最大限制"
- );
- return;
- }
- if (data._id && type === SaveType.Save) {
- if (data.image && !(await delImage(data.image))) {
- return;
- }
- }
- const file = await upload(blob, true);
- if (!file) {
- return;
- }
- // 缩略图
- data.image = file.url;
- (<any>globalThis).meta2d.store.data.image = data.image;
- }
- if (data.component) {
- // pens 存储原数据用于二次编辑 ; componentDatas 组合后的数据,用于复用
- data.componentDatas = (<any>globalThis).meta2d.toComponent(
- undefined,
- (<any>globalThis).meta2d.store.data.showChild,
- false //自定义组合节点生成默认锚点
- );
- } else {
- data.component = false; // 必要值
- }
- let collection = data.component ? "le5le2d-components" : "le5le2d";
- let ret: any;
- if (!data.name) {
- // 文件名称
- data.name = `meta2d.${new Date().toLocaleString()}`;
- (<any>globalThis).meta2d.store.data.name = data.name;
- }
- !data.version && (data.version = baseVer);
- let list = undefined;
- let folder: any = undefined;
- let folderId = undefined;
- if (
- !data.component &&
- data.folder &&
- !(data.teams && data.owner?.id !== user.id)
- ) {
- //自己的图纸才允许去请求
- folder = getFolders({
- type: collection,
- name: data.folder,
- });
- if (folder) {
- list = folder.list; //团队图纸文件夹
- folderId = folder._id;
- }
- }
- if (!list) {
- list = [];
- }
- if (type === SaveType.SaveAs) {
- // 另存为一定走 新增 ,由于后端 未控制 userId 等属性,清空一下
- const delAttrs = [
- "userId",
- "id",
- "shared",
- "star",
- "view",
- "username",
- "editorName",
- "editorId",
- "createdAt",
- "updatedAt",
- "recommend",
- ];
- for (const k of delAttrs) {
- delete (data as any)[k];
- }
- ret = addCollection(collection, data); // 新增
- if (!data.component) {
- list.push({
- id: ret._id,
- image: data.image,
- name: data.name,
- component: data.component,
- });
- }
- } else {
- if (data._id && data.teams && data.owner?.id !== user.id) {
- // 团队图纸 不允许修改文件夹信息
- delete data.folder;
- ret = updateCollection(collection, data);
- } else if (data._id) {
- ret = updateCollection(collection, data);
- if (!data.component) {
- list.forEach((i: any) => {
- if (i.id === data._id) {
- i.image = data.image;
- }
- });
- }
- //TODO 处理老接口图纸情况
- let one = list.find((item: any) => item.id === data._id);
- if (!data.component && !one) {
- list.push({
- id: ret._id,
- image: data.image,
- name: data.name,
- component: data.component,
- });
- }
- } else {
- ret = addCollection(collection, data); // 新增
- if (!data.component) {
- list.push({
- id: ret._id,
- image: data.image,
- name: data.name,
- component: data.component,
- });
- }
- }
- }
- if (ret.error) {
- return null;
- } else {
- if (!data.component && folderId) {
- const updateRet: any = updateFolders({
- _id: folderId,
- list,
- });
- if (updateRet.error) {
- return null;
- }
- }
- // showModelSaveAsPop.value = false;
- }
- // 保存图纸之后的钩子函数
- (window as any).afterSaveMeta2d &&
- (await (window as any).afterSaveMeta2d(ret));
- if (
- !data._id ||
- data.owner?.id !== user.id ||
- route.query.version ||
- type === SaveType.SaveAs // 另存为肯定走新增,也会产生新的 id
- ) {
- data._id = ret._id;
- (<any>globalThis).meta2d.store.data._id = data._id;
- router.replace({
- path: "/",
- query: {
- id: data._id,
- r: Date.now() + "",
- component: data.component + "",
- },
- });
- }
- MessagePlugin.success("保存成功!");
- // 保存成功,重新请求文件夹
- (<any>globalThis).meta2d.emit("t-save-success", true);
- // 已保存,不再是新的,无需提示保存
- // isNew.value = false;
- localforage.removeItem(localMeta2dDataName);
- };
- const saveAsComponents = () => {
- // (<any>globalThis).meta2d.store.data.component = true;
- save();
- }
- </script>
- <style lang="postcss" scoped>
- .meta2d {
- display: flex;
- flex-direction: column;
- background-color: var(--color-background-editor);
- border-right: 1px solid var(--color-border);
- .tools {
- display: flex;
- font-size: 12px;
- background-color: var(--color-background);
- height: 40px;
- flex-shrink: 0;
- padding: 0 12px;
- a {
- display: flex;
- align-items: center;
- height: 100%;
- padding: 0 10px;
- color: var(--color);
- text-decoration: none;
- &:hover {
- color: var(--color-primary);
- }
- }
- .t-icon {
- font-size: 16px;
- }
- }
- #meta2d {
- border-top: 1px solid var(--color-border);
- height: calc(100vh - 81px);
- }
- }
- </style>
|