Bläddra i källkod

Merge branch 'main' of github.com:le5le-com/visualization-design

Alsmile 2 år sedan
förälder
incheckning
a64f7dc577
6 ändrade filer med 978 tillägg och 2407 borttagningar
  1. 12 3
      src/services/common.ts
  2. 680 2352
      src/services/defaults.ts
  3. 1 1
      src/services/icons.ts
  4. 22 8
      src/services/utils.ts
  5. 1 0
      src/views/components/Graphics.vue
  6. 262 43
      src/views/components/View.vue

+ 12 - 3
src/services/common.ts

@@ -309,13 +309,22 @@ export const showMap = () => {
 };
 
 export const title = "系统可能不会保存您所做的更改,是否继续?";
+export const unLogin = "未登录,系统可能不会保存您的文件,是否继续?";
+//未登录,当前文件可能不会保存
+// 当前文件未保存,请先手动保存!(开通vip可享受自动保存服务)
 export const newFile = async () => {
-  if (dot.value) {
-    if (await showNotification(title)) {
+  if (!(user && user.id)) {
+    if (await showNotification(unLogin)) {
       newfile(false);
     }
   } else {
-    newfile(false);
+    if (dot.value) {
+      if (await showNotification(title)) {
+        newfile(false);
+      }
+    } else {
+      newfile(false);
+    }
   }
 };
 

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 680 - 2352
src/services/defaults.ts


+ 1 - 1
src/services/icons.ts

@@ -36,7 +36,7 @@ async function svgToPens(f: any, diretoryName: string) {
     : _name;
   const image = cdn + normalFolder + diretoryName + "/" + f.name;
   const svgDom: string = await axios.get(image);
-  let _svgDom = svgDom.replace("stroke:#333;", "stroke:#4583FF;");
+  let _svgDom = svgDom.replace("stroke:#333;", "stroke:#bdc7db;");
   const data = parseSvg(_svgDom);
   return {
     name,

+ 22 - 8
src/services/utils.ts

@@ -1,6 +1,6 @@
 import { FormItem, Pen, Meta2d, Meta2dData } from "@meta2d/core";
-import { MessagePlugin, NotifyPlugin } from "tdesign-vue-next";
-import { ref } from "vue";
+import { MessagePlugin, NotifyPlugin, Button } from "tdesign-vue-next";
+import { h, ref } from "vue";
 import { cdn } from "./api";
 
 const market = import.meta.env.VITE_MARKET;
@@ -39,21 +39,35 @@ export interface Meta2dBackData extends Meta2dData {
 const notification = ref<any>(null);
 export function showNotification(title: string): Promise<boolean> {
   return new Promise<boolean>((resolve) => {
+    const btnClick = () => {
+      NotifyPlugin.close(notification.value);
+      notification.value = null;
+      resolve(true);
+    };
     if (!notification.value) {
       notification.value = NotifyPlugin.info({
         title: "提示",
         content: title,
-        closeBtn: "确定",
+        closeBtn: true,
         onCloseBtnClick: () => {
           //关闭按钮
-          NotifyPlugin.close(notification.value);
           notification.value = null;
-          resolve(true);
-        },
-        onDurationEnd: () => {
-          //计时结束
           resolve(false);
         },
+        duration: 1000000,
+        footer: h(
+          Button,
+          {
+            theme: "primary",
+            size: "small",
+            style: {
+              "margin-top": "16px",
+              "margin-left": "256px",
+            },
+            onClick: btnClick,
+          },
+          "确定"
+        ),
       });
     }
   });

+ 1 - 0
src/views/components/Graphics.vue

@@ -373,6 +373,7 @@ onUnmounted(() => {
       overflow-y: auto;
       max-height: calc(100vh - 100px);
       background-color: var(--color-background-active);
+      padding-top: 16px;
 
       * {
         background-color: var(--color-background-active);

+ 262 - 43
src/views/components/View.vue

@@ -13,7 +13,7 @@
       <t-tooltip content="保存为我的组件" placement="bottom">
         <a><t-icon name="layers" @click="save(SaveType.Save, true)" /></a>
       </t-tooltip>
-      <t-tooltip content="格式化" placement="bottom">
+      <t-tooltip content="格式化(双击可连续使用)" placement="bottom">
         <a
           @click="oneFormat"
           @dblclick="alwaysFormat"
@@ -72,13 +72,15 @@
           ><t-icon name="slash"
         /></a>
       </t-tooltip>
-      <!-- <t-tooltip content="连线" placement="top"> -->
-      <t-dropdown
-        :minColumnWidth="200"
-        :maxHeight="560"
-        :delay2="[10, 150]"
-        overlayClassName="header-dropdown"
-      >
+      <t-tooltip content="文字" placement="bottom">
+        <a
+          :draggable="true"
+          @dragstart="onAddShape($event, 'text')"
+          @click.stop="onAddShape($event, 'text')"
+          >T</a
+        >
+      </t-tooltip>
+      <t-tooltip content="连线(双击可连续使用)" placement="bottom">
         <a
           @click="oneDraw"
           @dblclick="alwaysDraw"
@@ -98,24 +100,86 @@
             ></path>
           </svg>
         </a>
+      </t-tooltip>
+      <!-- <t-tooltip content="连线" placement="top"> -->
+      <t-dropdown
+        :minColumnWidth="200"
+        :maxHeight="560"
+        :delay2="[10, 150]"
+        overlayClassName="header-dropdown"
+      >
+        <a>
+          <svg class="l-icon" aria-hidden="true">
+            <use
+              :xlink:href="
+                lineTypes.find((item) => item.value === currentLineType)?.icon
+              "
+            ></use>
+          </svg>
+        </a>
         <t-dropdown-menu>
           <t-dropdown-item v-for="item in lineTypes">
             <div class="flex middle" @click="changeLineType(item.value)">
               {{ item.name }} <span class="flex-grow"></span>
-              <t-icon v-show="item.value === currentLineType" name="check" />
+              <!-- <t-icon v-show="item.value === currentLineType" name="check" /> -->
+              <svg class="l-icon" aria-hidden="true">
+                <use :xlink:href="item.icon"></use>
+              </svg>
+            </div>
+          </t-dropdown-item>
+        </t-dropdown-menu>
+      </t-dropdown>
+      <t-dropdown
+        :minColumnWidth="200"
+        :maxHeight="560"
+        :delay2="[10, 150]"
+        overlayClassName="header-dropdown"
+      >
+        <a>
+          <svg class="l-icon" aria-hidden="true">
+            <use
+              :xlink:href="
+                fromArrows.find((item) => item.value === fromArrow)?.icon
+              "
+            ></use>
+          </svg>
+        </a>
+        <t-dropdown-menu>
+          <t-dropdown-item v-for="item in fromArrows">
+            <div class="flex middle" style="height: 30px;" @click="changeFromArrow(item.value)">
+              <svg class="l-icon" aria-hidden="true">
+                <use :xlink:href="item.icon"></use>
+              </svg>
+            </div>
+          </t-dropdown-item>
+        </t-dropdown-menu>
+      </t-dropdown>
+      <t-dropdown
+        :minColumnWidth="200"
+        :maxHeight="560"
+        :delay2="[10, 150]"
+        overlayClassName="header-dropdown"
+      >
+        <a>
+          <svg class="l-icon" aria-hidden="true">
+            <use
+              :xlink:href="
+                toArrows.find((item) => item.value === toArrow)?.icon
+              "
+            ></use>
+          </svg>
+        </a>
+        <t-dropdown-menu>
+          <t-dropdown-item v-for="item in toArrows">
+            <div class="flex middle" style="height: 30px;" @click="changeToArrow(item.value)">
+              <svg class="l-icon" aria-hidden="true">
+                <use :xlink:href="item.icon"></use>
+              </svg>
             </div>
           </t-dropdown-item>
         </t-dropdown-menu>
       </t-dropdown>
       <!-- </t-tooltip> -->
-      <t-tooltip content="文字" placement="bottom">
-        <a
-          :draggable="true"
-          @dragstart="onAddShape($event, 'text')"
-          @click.stop="onAddShape($event, 'text')"
-          >T</a
-        >
-      </t-tooltip>
       <t-tooltip content="视图大小" placement="bottom">
         <div style="line-height: 40px; margin-left: 8px">{{ scale }}%</div>
       </t-tooltip>
@@ -131,9 +195,6 @@
       </t-tooltip>
 
       <div class="flex-grow"></div>
-      <t-tooltip content="预览" placement="bottom">
-        <a @click="preview"><t-icon name="browse" /></a>
-      </t-tooltip>
       <t-tooltip
         :content="isLock === 2 ? '锁定' : isLock === 1 ? '预览' : '编辑'"
         placement="bottom"
@@ -161,6 +222,10 @@
           </svg>
         </a>
       </t-tooltip>
+      <t-tooltip content="运行(在新页面全屏查看)" placement="bottom">
+        <a @click="preview"><t-icon name="caret-right" /></a>
+      </t-tooltip>
+
       <t-tooltip content="手机查看" placement="bottom">
         <a><t-icon name="qrcode" /></a>
       </t-tooltip>
@@ -180,27 +245,35 @@
 </template>
 
 <script lang="ts" setup>
-import { Meta2d, Options, Pen, deepClone, LockState } from '@meta2d/core';
-import { onMounted, onUnmounted, watch, ref, reactive } from 'vue';
-import { registerBasicDiagram } from '@/services/register';
-import { useRouter, useRoute } from 'vue-router';
-import { useUser } from '@/services/user';
-import { getLe5le2d } from '@/services/api';
-import { useDot } from '@/services/common';
+import {
+  Meta2d,
+  Options,
+  Pen,
+  deepClone,
+  LockState,
+  PenType,
+} from "@meta2d/core";
+import { onMounted, onUnmounted, watch, ref, reactive } from "vue";
+import { registerBasicDiagram } from "@/services/register";
+import { useRouter, useRoute } from "vue-router";
+import { useUser } from "@/services/user";
+import { getLe5le2d } from "@/services/api";
+import { useDot } from "@/services/common";
 import {
   save,
   newFile,
   SaveType,
   onScaleView,
   onScaleWindow,
-} from '@/services/common';
-import { useSelection, SelectionMode } from '@/services/selections';
-import { defaultFormat } from '@/services/defaults';
-import { MessagePlugin } from 'tdesign-vue-next';
-import { localMeta2dDataName } from '@/services/utils';
-import localforage from 'localforage';
-import { checkData } from '@/services/utils';
-import { cdn } from '@/services/api';
+} from "@/services/common";
+import { useSelection, SelectionMode } from "@/services/selections";
+import { defaultFormat } from "@/services/defaults";
+import { MessagePlugin } from "tdesign-vue-next";
+import { localMeta2dDataName } from "@/services/utils";
+import localforage from "localforage";
+import { checkData, Meta2dBackData } from "@/services/utils";
+import { cdn } from "@/services/api";
+import dayjs from "dayjs";
 
 const router = useRouter();
 const route = useRoute();
@@ -216,7 +289,8 @@ const meta2dOptions: Options = {
   y: 32,
   width: 1920,
   height: 1080,
-  color: '#4583FF',
+  color: "#bdc7db",
+  disableAnchor:true,
   defaultFormat: { ...defaultFormat },
 };
 onMounted(() => {
@@ -230,7 +304,17 @@ onMounted(() => {
   // @ts-ignore
   meta2d.on('scale', scaleListener);
   // @ts-ignore
-  meta2d.on('add', lineAdd);
+  meta2d.on("add", lineAdd);
+
+  meta2d.on("undo", autoSave);
+  meta2d.on("redo", autoSave);
+  meta2d.on("add", autoSave);
+  meta2d.on("delete", autoSave);
+  meta2d.on("rotatePens", autoSave);
+  meta2d.on("translatePens", autoSave);
+
+  //TODO所有编辑栏所做修改
+  meta2d.on("components-update-value", autoSave);
 });
 
 const watcher = watch(
@@ -261,11 +345,58 @@ onUnmounted(() => {
     // @ts-ignore
     meta2d.off('scale', scaleListener);
     // @ts-ignore
-    meta2d.off('add', lineAdd);
+    meta2d.off("add", lineAdd);
+
+    meta2d.off("undo", autoSave);
+    meta2d.off("redo", autoSave);
+    meta2d.off("add", autoSave);
+    meta2d.off("delete", autoSave);
+    meta2d.off("rotatePens", autoSave);
+    meta2d.off("translatePens", autoSave);
+    meta2d.off("components-update-value", autoSave);
     meta2d.destroy();
   }
 });
 
+let localSaveTimer: any = 0;
+let saveTimer: any = 0;
+const autoSave = () => {
+  setDot(true);
+  localSaveTimer && clearTimeout(localSaveTimer);
+  localSaveTimer = setTimeout(() => {
+    const data: Meta2dBackData = meta2d.data();
+    let _localMeta2dDataName = data._id
+      ? localMeta2dDataName + "-" + data._id
+      : localMeta2dDataName;
+    (data as any).localSaveAt = dayjs().format();
+    localforage.setItem(_localMeta2dDataName, JSON.stringify(data));
+    localSaveTimer = undefined;
+  }, 3000);
+  autoSaveServer();
+};
+//运行 在新标签页查看
+function autoSaveServer() {
+  //会员享受自动保存
+  if (saveTimer) {
+    return;
+  }
+  saveTimer = setTimeout(() => {
+    const data: Meta2dBackData = meta2d.data();
+    if (
+      user &&
+      user.id &&
+      user.vipExpired &&
+      data._id &&
+      !data.component &&
+      data.owner &&
+      data.owner?.id === user.id
+    ) {
+      save(SaveType.Save);
+    }
+    saveTimer = null;
+  }, 60000);
+}
+
 const inactive = () => {
   select();
 };
@@ -318,10 +449,10 @@ const connectShow = () => {
 
 const currentLineType = ref('curve');
 const lineTypes = reactive([
-  { name: '曲线', icon: 't-icon t-curve2', value: 'curve' },
-  { name: '线段', icon: 't-icon t-polyline', value: 'polyline' },
-  { name: '直线', icon: 't-icon t-line', value: 'line' },
-  { name: '脑图曲线', icon: 't-icon t-mind', value: 'mind' },
+  { name: "曲线", icon: "#l-curve2", value: "curve" },
+  { name: "线段", icon: "#l-polyline", value: "polyline" },
+  { name: "直线", icon: "#l-line", value: "line" },
+  { name: "脑图曲线", icon: "#l-mind", value: "mind" },
 ]);
 
 const changeLineType = (value: string) => {
@@ -335,24 +466,108 @@ const changeLineType = (value: string) => {
   }
 };
 
+const fromArrow = ref("");
+const fromArrows = [
+  { icon: "#l-line", value: "" },
+  { icon: "#l-from-triangle", value: "triangle" },
+  { icon: "#l-from-diamond", value: "diamond" },
+  { icon: "#l-from-circle", value: "circle" },
+  { icon: "#l-from-lineDown", value: "lineDown" },
+  { icon: "#l-from-lineUp", value: "lineUp" },
+  { icon: "#l-from-triangleSolid", value: "triangleSolid" },
+  { icon: "#l-from-diamondSolid", value: "diamondSolid" },
+  { icon: "#l-from-circleSolid", value: "circleSolid" },
+  { icon: "#l-from-line", value: "line" },
+];
+const toArrow = ref("");
+const toArrows = [
+  { icon: "#l-line", value: "" },
+  { icon: "#l-to-triangle", value: "triangle" },
+  { icon: "#l-to-diamond", value: "diamond" },
+  { icon: "#l-to-circle", value: "circle" },
+  { icon: "#l-to-lineDown", value: "lineDown" },
+  { icon: "#l-to-lineUp", value: "lineUp" },
+  { icon: "#l-to-triangleSolid", value: "triangleSolid" },
+  { icon: "#l-to-diamondSolid", value: "diamondSolid" },
+  { icon: "#l-to-circleSolid", value: "circleSolid" },
+  { icon: "#l-to-line", value: "line" },
+];
+
+const changeFromArrow = (value: string) => {
+  fromArrow.value = value;
+  // 画布默认值
+  meta2d.store.data.fromArrow = value;
+  // 活动层的箭头都变化
+  if (meta2d.store.active) {
+    meta2d.store.active.forEach((pen: Pen) => {
+      if (pen.type === PenType.Line) {
+        pen.fromArrow = value;
+        meta2d.setValue(
+          {
+            id: pen.id,
+            fromArrow: pen.fromArrow,
+          },
+          {
+            render: false,
+          }
+        );
+      }
+    });
+    meta2d.render();
+  }
+};
+
+const changeToArrow = (value: string) => {
+  toArrow.value = value;
+  // 画布默认值
+  meta2d.store.data.toArrow = value;
+  // 活动层的箭头都变化
+  if (meta2d.store.active) {
+    meta2d.store.active.forEach((pen: Pen) => {
+      if (pen.type === PenType.Line) {
+        pen.toArrow = value;
+        meta2d.setValue(
+          {
+            id: pen.id,
+            toArrow: pen.toArrow,
+          },
+          {
+            render: false,
+          }
+        );
+      }
+    });
+    meta2d.render();
+  }
+};
+
 const oneD = ref<boolean>(false);
 const alwaysD = ref<boolean>(false);
 const oneDraw = () => {
   if (oneD.value) {
     oneD.value = false;
+    if (!alwaysD.value) {
+      meta2d.finishDrawLine();
+      meta2d.drawLine();
+      meta2d.store.options.disableAnchor =true;
+    }
   } else {
     oneD.value = true;
     meta2d.drawLine(meta2d.store.options.drawingLineName);
+    meta2d.store.options.disableAnchor =false;
   }
   if (alwaysD.value) {
     meta2d.finishDrawLine();
     meta2d.drawLine();
     oneD.value = false;
     alwaysD.value = false;
+    meta2d.store.options.disableAnchor =true;
   }
 };
 const alwaysDraw = () => {
   alwaysD.value = true;
+  meta2d.drawLine(meta2d.store.options.drawingLineName);
+  meta2d.store.options.disableAnchor =false;
 };
 
 const lineAdd = (pens: Pen[]) => {
@@ -364,6 +579,7 @@ const lineAdd = (pens: Pen[]) => {
         setTimeout(() => {
           meta2d.finishDrawLine();
           meta2d.drawLine();
+          meta2d.store.options.disableAnchor =true;
         }, 100);
       }
     }
@@ -455,7 +671,10 @@ const preview = async () => {
       padding: 0 10px;
       color: var(--color);
       text-decoration: none;
-
+      .l-icon {
+        width: 16px;
+        height: 16px;
+      }
       &:hover {
         color: var(--color-primary);
       }

Vissa filer visades inte eftersom för många filer har ändrats