Procházet zdrojové kódy

Merge branch 'pgsql' of https://github.com/le5le-com/visualization-design into pgsql

Wind-Breaker1 před 1 rokem
rodič
revize
fc92a537da

+ 6 - 4
src/services/common.ts

@@ -843,7 +843,7 @@ export const getPenTree = () => {
     const elem = calcElem(item);
     elem && list.push(elem);
   }
-  tree.list = list;
+  tree.list = list.reverse();
 
   return tree.list;
 };
@@ -877,12 +877,14 @@ const calcElem = (node: any) => {
     meta2d.store.options.domShapes.includes(node.name)
   ) {
     tag = 'dom';
-  } else if (node.template) {
+  } else if (node.canvasLayer === 1) {
     tag = '模板';
   } else if (node.name === 'image') {
-    if (node.isBottom) {
+    if(node.canvasLayer === 2){
       tag = '下层';
-    } else {
+    }else if(node.canvasLayer===3){
+      tag = '中层';
+    }else{
       tag = '上层';
     }
   } else {

+ 26 - 0
src/services/defaults.ts

@@ -1,6 +1,32 @@
 import { Pen, FormItem } from '@meta2d/core';
 import { cdn } from './api';
 
+export 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' },
+];
+
+export 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' },
+];
+
 export const lineDashObj = [
   undefined,
   [5, 5],

+ 1 - 1
src/views/components/Actions.vue

@@ -327,7 +327,7 @@
         </template>
         <template v-else-if="a.action == 5">
           <div class="form-item mt-8">
-            <label>函数</label>
+            <!-- <label>函数</label> -->
             <div class="w-full">
               <div>function javascriptFn(pen) {</div>
               <CodeEditor

+ 1 - 1
src/views/components/ContextMenu.vue

@@ -44,7 +44,7 @@
         <div class="flex">撤销<span class="flex-grow"></span>Ctrl + Z</div>
       </t-menu-item>
       <t-menu-item :disabled="cantRedo" value="redo">
-        <div class="flex">恢复<span class="flex-grow"></span>Shift + Z</div>
+        <div class="flex">重做<span class="flex-grow"></span>Shift + Z</div>
       </t-menu-item>
       <t-divider />
       <t-menu-item :disabled="!selections.mode" value="cut">

+ 25 - 9
src/views/components/ElementTree.vue

@@ -190,6 +190,7 @@ onMounted(() => {
   meta2d.on('combine', getTree);
   meta2d.on('click', getActived);
   meta2d.on('paste', getActived);
+  meta2d.on('layer', layerChange);
 
   if (inTreePanel.timer) {
     clearTimeout(inTreePanel.timer);
@@ -212,6 +213,16 @@ const getTree = () => {
   data.tree = getPenTree();
 };
 
+const layerChange = () =>{
+  getTree();
+  setTimeout(() => {
+    if(meta2d.store.active&&meta2d.store.active[0]){
+      let index = data.tree.findIndex((item) => item.value === meta2d.store.active[0].id);
+      tree.value?.scrollToElement({index:index-5});
+    }
+  }, 500);
+}
+
 const getHiddenGroups = () => {
   data.groups.forEach((item) => {
     if (
@@ -227,7 +238,8 @@ const getHiddenGroups = () => {
 
 const getActived = () => {
   data.actived = [];
-  if (meta2d.store.active) {
+  if (meta2d.store.active && meta2d.store.active.length) {
+   
     for (const pen of meta2d.store.active) {
       data.actived.push(pen.id);
     }
@@ -235,16 +247,19 @@ const getActived = () => {
     const element = document.body.querySelector(
       `[data-value="${data.actived[0]}"]`
     );
-
     if (element) {
-      element.scrollIntoView({ block: 'center' });
+      element.scrollIntoView({behavior:'smooth', block: 'nearest' });
     } else {
-      setTimeout(() => {
-        const element = document.body.querySelector(
-          `[data-value="${data.actived[0]}"]`
-        );
-        element && element.scrollIntoView({ block: 'center' });
-      }, 500);
+      // setTimeout(() => {
+      //   const element = document.body.querySelector(
+      //     `[data-value="${data.actived[0]}"]`
+      //   );
+      //   element && element.scrollIntoView({ block: 'center' });
+      // }, 500);
+      // let pens = meta2d.store.data.pens.filter((pen) => !pen.parentId);
+      // let index = pens.findIndex((item) => item.id === meta2d.store.active[0].id);
+      let index = data.tree.findIndex((item) => item.value === meta2d.store.active[0].id);
+      tree.value?.scrollToElement({index:index-5});
     }
   }
 };
@@ -405,6 +420,7 @@ onBeforeUnmount(() => {
   meta2d.off('combine', getTree);
   meta2d.off('click', getActived);
   meta2d.off('paste', getActived);
+  meta2d.off('layer', layerChange);
 
   inTreePanel.timer = setTimeout(() => {
     inTreePanel.value = false;

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

@@ -2068,8 +2068,22 @@ const updateAfterSave = (e) => {
 
 const onManageGraphic = () => {
   if (activedGroup.value === '素材') {
+    materials.forEach((item) => {
+      item.list.forEach((_item) => {
+        if(_item.visible === undefined){
+          _item.visible = true;
+        }
+      });
+    });
     manageDialog.data = deepClone(materials);
   } else if (activedGroup.value === '图元') {
+    pngs.forEach((item) => {
+      item.list.forEach((_item) => {
+        if(_item.visible === undefined){
+          _item.visible = true;
+        }
+      });
+    });
     manageDialog.data = deepClone(pngs);
   }
   manageDialog.show = true;

+ 14 - 4
src/views/components/Header.vue

@@ -103,7 +103,7 @@
         <t-dropdown-item divider="true">
           <a @click="onRedo">
             <div class="flex">
-              恢复 <span class="flex-grow"></span> Ctrl + Y
+              重做 <span class="flex-grow"></span> Ctrl + Y
             </div>
           </a>
         </t-dropdown-item>
@@ -1169,7 +1169,12 @@ const showPayListDialog = async () => {
     (pen) =>
       pen.name === 'iframe' &&
       (pen.iframe.indexOf('2d.le5le.com') !== -1 ||
-        pen.iframe.indexOf('/2d') !== -1||pen.iframe.indexOf('v.le5le.com') !== -1 ||
+        pen.iframe.indexOf('/2d') !== -1)
+  );
+  const pen_v = meta2d.store.data.pens.filter(
+    (pen) =>
+      pen.name === 'iframe' &&
+      (pen.iframe.indexOf('v.le5le.com') !== -1 ||
         pen.iframe.indexOf('/view/v') !== -1||pen.iframe.indexOf('data=v') !== -1)
   );
   let price = 0;
@@ -1183,8 +1188,13 @@ const showPayListDialog = async () => {
         data.payGoods[item.id]=pen_3d.length;
      }
    }else if(item.name==="2D离线部署下载"){
-     price+=item.price*(pen_2d.length+1);
-     data.payGoods[item.id]=pen_2d.length+1;
+     price+=item.price*pen_2d.length;
+     if(pen_2d.length){
+        data.payGoods[item.id]=pen_2d.length;
+     }
+   }else if(item.name==="大屏离线部署下载"){
+     price+=item.price*(pen_v.length+1);
+     data.payGoods[item.id]=pen_v.length+1;
    }
   });
   data.deploy.price = price;

+ 80 - 7
src/views/components/PenDatas.vue

@@ -120,7 +120,7 @@
               @change="changeValue(item.key)"
               :placeholder="item.placeholder"
             />
-            <t-button
+            <!-- <t-button
               class="ml-8"
               v-else-if="item.type === 'code'"
               shape="square"
@@ -129,9 +129,17 @@
               @click="showPropsEdit(item)"
             >
               <ellipsis-icon slot="icon"/>
-              <!-- <t-icon name="ellipsis" slot="icon"
-            /> -->
-             </t-button>
+            </t-button> -->
+            <t-button
+              class="ml-8"
+              v-else-if="item.type === 'code'"
+              shape="square"
+              variant="outline"
+              style="width: 24px"
+              @click="showDrawer(item)"
+            >
+              <ChevronLeftDoubleIcon slot="icon"/>
+            </t-button>
             <t-slider
               v-else-if="item.type === 'slider'"
               v-model="props.pen[item.key]"
@@ -284,7 +292,28 @@
       </t-collapse-panel>
     </t-collapse>
   </div>
-
+  <t-drawer 
+    v-model:visible="drawer.visible" 
+    :header="drawer.header" 
+    cancelBtn="关闭"
+    confirmBtn="运行"
+    @confirm="onConfirmDrawer"
+    :closeOnOverlayClick="false" 
+    :sizeDraggable="true"
+    >
+    <div style="height:100%">
+      <CodeEditor
+        style="height: 100%"
+        :key="drawer.randomkey"
+        :json="true"
+        :language="'json'"
+        v-model="drawer.value"
+      />
+    </div>
+    <div class="gray" style="font-size: 12px">
+      {{ drawer.placeholder }}
+    </div>
+    </t-drawer>
   <t-dialog
     v-if="addDataDialog.show"
     :visible="true"
@@ -398,6 +427,7 @@
           :columns="dataSetColumns"
           size="small"
           bordered
+          rowSelectionAllowUncheck
           :loading="dataBindDialog.loading"
           :pagination="query"
           @page-change="onChangePagination"
@@ -683,7 +713,8 @@ import Actions from './Actions.vue';
 import { useSelection } from '@/services/selections';
 import { defaultGradientColor, defaultPureColor } from '@/services/defaults';
 import { getLe5le3d, getLe5leV, getLe5le2d } from '@/services/api';
-import { EllipsisIcon, MoreIcon, LinkIcon, RelativityIcon, AddRectangleIcon, SearchIcon ,DeleteIcon, ArrowRightIcon, CloseIcon } from 'tdesign-icons-vue-next';
+import { EllipsisIcon, MoreIcon, LinkIcon, RelativityIcon, AddRectangleIcon, SearchIcon ,DeleteIcon, ArrowRightIcon, CloseIcon, ChevronLeftDoubleIcon } from 'tdesign-icons-vue-next';
+import { s8 } from '@/services/random';
 
 const route = useRoute();
 const router = useRouter();
@@ -960,6 +991,9 @@ const onConfirmData = () => {
       MessagePlugin.error('已经存在相同属性数据!');
       return;
     }
+    if(props.pen[addDataDialog.data.key] === undefined && addDataDialog.data.key.indexOf('.') !== -1){
+      props.pen[addDataDialog.data.key] = getter(props.pen, addDataDialog.data.key);
+    }
     props.pen.realTimes.push(addDataDialog.data);
   }
 
@@ -1075,6 +1109,9 @@ const onSelectBindsChange = (value: string[], options: any) => {
   if (options.type === 'check') {
     dataBindDialog.selectedIds = value;
     dataBindDialog.data.bind = toRaw(options.selectedRowData[0]);
+    if(dataBindDialog.data.bind.id){
+      dataBindDialog.data.enableMock = false;
+    }
     dataBindDialog.data.mock = dataBindDialog.data.bind.mock;
     dataBindDialog.data.type = dataBindDialog.data.bind.type;
     doBindInit();
@@ -1086,7 +1123,7 @@ const onSelectBindsChange = (value: string[], options: any) => {
 
 const doBindInit = () => {
   let { id } = dataBindDialog.data;
-  if (props.pen.name === 'echarts' && id.includes('echarts.option.series')) {
+  if (props.pen.name === 'echarts' && id?.includes('echarts.option.series')) {
     const { replaceMode } = props.pen.echarts;
     const { xAxis } = props.pen.echarts.option;
 
@@ -1133,6 +1170,10 @@ const changeValue = (prop: string) => {
   if (prop === 'iframe') {
     getThumbImg();
   }
+  if(prop === 'apiEnable'){
+    meta2d.penNetwork(props.pen);
+    meta2d.connectNetwork();
+  }
 };
 
 const onTrigger = (item: any) => {
@@ -1328,6 +1369,28 @@ const valueChange = (e,c:any)=>{
   c.value= changeType(e);
 }
 
+const drawer = reactive<any>({
+  visible: false,
+});
+
+const showDrawer = (item:any)=>{
+  drawer.key = item.key;
+  drawer.header = `${item.label}(${item.key})`;
+  drawer.value = deepClone(props.pen[item.key]);
+  drawer.placeholder = item.placeholder;
+  drawer.randomkey = s8();//props.pen.id;
+  drawer.visible = true;
+}
+
+const onConfirmDrawer = () => {
+  if (!drawer.value) {
+    MessagePlugin.error('数据不满足json格式');
+    return;
+  }
+  props.pen[drawer.key] = drawer.value;
+  updatePen(props.pen, drawer.key);
+};
+
 onUnmounted(() => {
   clearInterval(timer);
 });
@@ -1460,3 +1523,13 @@ onUnmounted(() => {
   }
 }
 </style>
+
+<style lang="postcss">
+.t-drawer__mask{
+  background-color: #fff0;
+}
+
+.t-drawer__body{
+  padding:0px;
+}
+</style>

+ 86 - 11
src/views/components/PenProps.vue

@@ -30,14 +30,13 @@
             <t-select-input
               v-model:inputValue="data.inputTag"
               :value="data.pen.tags"
-              v-model:popupVisible="data.tagPopupVisible"
               allow-input
               placeholder="请输入或选择分组"
               multiple
               @tag-change="onChangeInputTag"
               @focus="data.tagPopupVisible = true"
               @blur="data.tagPopupVisible = false"
-              :tag-input-props="{ excessTagsDisplayType: 'scroll' }"
+              :tag-input-props="{ excessTagsDisplayType: 'break-line' }"
             >
               <template #panel>
                 <ul style="padding: 8px 12px">
@@ -52,14 +51,33 @@
               </template>
             </t-select-input>
           </div>
-          <div class="form-item px-12" style="margin-top: -12px">
-            <label style="width: 50px">模板</label>
-            <t-switch
+          <div v-if="isDom" class="form-item px-12" style="margin-top: -12px">
+            <label style="width: 50px">z-index</label>
+            <t-input-number
+              v-model="data.pen.zIndex"
+              theme="column"
+              :min="0"
+              placeholder="默认5"
+              @change="changeValue('zIndex')"
+            />
+          </div>
+          <div v-else class="form-item px-12" style="margin-top: -12px">
+            <label style="width: 50px">画布层</label>
+            <!-- <t-switch
               class="mt-8 ml-8"
               v-model="data.pen.template"
               size="small"
               @change="changeValue('template')"
-            />
+            /> -->
+            <t-select
+              v-model="data.pen.canvasLayer"
+              @change="changeValue('canvasLayer')"
+            >
+              <t-option :key="4" :disabled="data.pen.name!=='image'" :value="4" label="上层图片层"> 上层图片层 </t-option>
+              <t-option :key="3" :value="3" label="主画布层"> 主画布层 </t-option>
+              <t-option :key="2" :disabled="data.pen.name!=='image'" :value="2" label="下层图片层"> 下层图片层 </t-option>
+              <t-option :key="1" :value="1" label="模板层"> 模板层 </t-option>
+            </t-select>
           </div>
           <t-divider style="margin: -8px 0" />
           <div style="margin: 0 16px 16px 16px">
@@ -398,6 +416,44 @@
                     />
                   </t-tooltip>
                 </div>
+                <div class="form-item">
+                  <label style="width: 52px">起点箭头 </label>
+                  <t-select
+                    v-model="data.pen.fromArrow"
+                    placeholder="线条样式"
+                    @change="changeValue('fromArrow')"
+                    style="width: 80px"
+                  >
+                    <template #valueDisplay="{ value }">
+                      <svg v-if="value" class="l-icon" aria-hidden="true">
+                        <use :xlink:href="fromArrows.find(item=>item.value===value).icon"></use>
+                      </svg>
+                    </template>
+                    <t-option v-for="item in fromArrows" :key="item.value" :value="item.value">
+                      <svg class="l-icon" aria-hidden="true">
+                        <use :xlink:href="item.icon"></use>
+                      </svg>
+                    </t-option>
+                  </t-select>
+                  <label style="width: 52px" class="ml-4">终点箭头 </label>
+                  <t-select
+                    v-model="data.pen.toArrow"
+                    placeholder="线条样式"
+                    @change="changeValue('toArrow')"
+                    style="width: 80px"
+                  >
+                    <template #valueDisplay="{ value }">
+                      <svg v-if="value" class="l-icon" aria-hidden="true">
+                        <use :xlink:href="toArrows.find(item=>item.value===value).icon"></use>
+                      </svg>
+                    </template>
+                    <t-option v-for="item in toArrows" :key="item.value" :value="item.value">
+                      <svg class="l-icon" aria-hidden="true">
+                        <use :xlink:href="item.icon"></use>
+                      </svg>
+                    </t-option>
+                  </t-select>
+                </div>
                 <div class="flex" style="margin-left: 40px">
                   <div class="flex column middle">
                     <t-radio-group
@@ -1026,9 +1082,15 @@
                     置底
                   </t-checkbox>
                 </div>
-                <div class="flex">
+                <div class="form-item">
                   <label style="width: 30px; color: var(--color)">Url:</label>
-                  {{ data.pen.image }}
+                  <!-- {{ data.pen.image }} -->
+                  <t-input
+                    class="w-full"
+                    placeholder="图片地址"
+                    v-model.number="data.pen.image"
+                    @change="changeValue('image')"
+                  />
                 </div>
               </t-space>
             </t-collapse-panel>
@@ -1342,7 +1404,7 @@
 </template>
 
 <script lang="ts" setup>
-import { onBeforeMount, onUnmounted, reactive, ref, watch } from 'vue';
+import { onBeforeMount, onUnmounted, reactive, ref, watch, computed } from 'vue';
 
 import CodeEditor from './common/CodeEditor.vue';
 import Iconfonts from './common/Iconfonts.vue';
@@ -1357,8 +1419,8 @@ import { autoSave, fonts, inTreePanel } from '@/services/common';
 import { updatePen } from './pen';
 import { MessagePlugin } from 'tdesign-vue-next';
 import { useUser } from '@/services/user';
-import { getter, queryURLParams } from '@meta2d/core';
-import { defaultGradientColor, defaultPureColor } from '@/services/defaults';
+import { getter, queryURLParams, isDomShapes } from '@meta2d/core';
+import { defaultGradientColor, defaultPureColor, fromArrows, toArrows } from '@/services/defaults';
 import { getLe5le3d, getLe5leV, getLe5le2d } from '@/services/api';
 import { s8 } from '@/services/random';
 import { EllipsisIcon, LinkIcon, LinkUnlinkIcon, ChevronDownIcon, FormatVerticalAlignLeftIcon, FormatHorizontalAlignCenterIcon, FormatVerticalAlignCenterIcon, FormatVerticalAlignRightIcon, FormatHorizontalAlignTopIcon, FormatHorizontalAlignBottomIcon  } from 'tdesign-icons-vue-next';
@@ -1540,6 +1602,13 @@ const changeValue = (prop: string) => {
   if (prop === 'iframe') {
     getThumbImg();
   }
+  if(prop === 'image'){
+    data.images = [
+      {
+        url: data.pen.image,
+      },
+    ];
+  }
 };
 
 const getThumbImg = async () => {
@@ -1714,6 +1783,12 @@ const changetemProgressFlag = (pen: any) => {
   }
 };
 
+const isDom = computed(() => {
+  return isDomShapes.includes(data.pen.name) ||
+    data.pen.name.endsWith('Dom') ||
+    meta2d.store.options.domShapes.includes(data.pen.name)
+});
+
 onUnmounted(() => {
   watcher();
   meta2d.off('translatePens', getRect);

+ 91 - 11
src/views/components/PensProps.vue

@@ -3,7 +3,7 @@
     <t-tabs v-model="data.tab">
       <t-tab-panel :value="1" label="外观">
         <t-space direction="vertical" class="py-16 w-full">
-          <div class="px-16 flex between">
+          <div class="px-16 flex between" style="margin-bottom:2px;">
             <label>选中了{{ selections.pens.length }}个图元</label>
             <div class="icons">
               <t-tooltip
@@ -67,13 +67,42 @@
             </div>
           </div>
           <div class="form-item px-16" style="margin-top: -12px">
-            <label style="width: 50px">模板</label>
-            <t-switch
-              class="mt-8 ml-8"
-              size="small"
-              v-model="data.template"
-              @change="changeValue('template')"
-            />
+            <label style="width: 50px">分组</label>
+            <t-select-input
+              v-model:inputValue="data.inputTag"
+              :value="data.tags"
+              allow-input
+              placeholder="请输入或选择分组"
+              multiple
+              @tag-change="onChangeInputTag"
+              @focus="data.tagPopupVisible = true"
+              @blur="data.tagPopupVisible = false"
+              :tag-input-props="{ excessTagsDisplayType: 'break-line' }"
+            >
+              <template #panel>
+                <ul style="padding: 8px 12px">
+                  <li
+                    v-for="item in data.groups"
+                    :key="item"
+                    @click="onSelectTag(item)"
+                  >
+                    {{ item }}
+                  </li>
+                </ul>
+              </template>
+            </t-select-input>
+          </div>
+          <div class="form-item px-16" style="margin-top: -12px">
+            <label style="width: 50px">画布层</label>
+            <t-select
+              v-model="data.canvasLayer"
+              @change="changeValue('canvasLayer')"
+            >
+              <t-option :key="4" :disabled="!allImg" :value="4" label="上层图片层"> 上层图片层 </t-option>
+              <t-option :key="3" :disabled="hasDom" :value="3" label="主画布层"> 主画布层 </t-option>
+              <t-option :key="2" :disabled="!allImg" :value="2" label="下层图片层"> 下层图片层 </t-option>
+              <t-option :key="1" :disabled="hasDom" :value="1" label="模板层"> 模板层 </t-option>
+            </t-select>
           </div>
           <t-collapse
             :defaultValue="['1', '2', '3', '4']"
@@ -812,9 +841,9 @@
 </template>
 
 <script lang="ts" setup>
-import { onBeforeMount, onUnmounted, reactive, ref } from 'vue';
+import { onBeforeMount, onUnmounted, reactive, ref, computed } from 'vue';
 
-import { LockState, Pen } from '@meta2d/core';
+import { LockState, Pen, isDomShapes } from '@meta2d/core';
 
 import { updatePen } from './pen';
 
@@ -912,7 +941,17 @@ const aligns2 = [
   },
 ];
 
-onBeforeMount(() => {});
+onBeforeMount(() => {
+  const d = meta2d.store.data as any;
+  if (!d.groups) {
+    d.groups = [];
+  }
+  data.groups = d.groups;
+
+  if (!data.tags) {
+    data.tags = [];
+  }
+});
 
 const lock = (v: LockState) => {
   data.locked = v;
@@ -970,6 +1009,47 @@ const onFontPopupVisible = (val: boolean) => {
 const decimalRound = (val: number) => {
   return Math.round(+val || 0);
 };
+
+const onSelectTag = (tag: string) => {
+  data.tagPopupVisible = false;
+  if (data.tags.includes(tag)) {
+    return;
+  }
+  data.tags.push(tag);
+  changeValue('tags');
+};
+
+const onChangeInputTag = (currentTags: any, context: any) => {
+  const { trigger, index, item } = context;
+  if (['tag-remove', 'backspace'].includes(trigger)) {
+    data.tags.splice(index, 1);
+  }
+  if (trigger === 'enter') {
+    onSelectTag(item);
+    const d = meta2d.store.data as any;
+    if (!d.groups.includes(item)) {
+      d.groups.push(item);
+      data.groups = d.groups;
+    }
+    data.inputTag = '';
+  }
+  data.tagPopupVisible = false;
+};
+
+const hasDom = computed(() => {
+  return selections.pens.some((item: Pen) => {
+    return isDomShapes.includes(item.name) ||
+      item.name.endsWith('Dom') ||
+      meta2d.store.options.domShapes.includes(item.name);
+  });
+});
+
+const allImg = computed(() => {
+  return selections.pens.every((item: Pen) => {
+    return item.name === 'image';
+  });
+});
+
 </script>
 <style lang="postcss" scoped>
 .props {

+ 34 - 26
src/views/components/View.vue

@@ -410,7 +410,7 @@
                           @click="onSelectNetWork(item)"
                         >
                           <div style="font-size: 14px">{{ item.name }}</div>
-                          <div class="desc">{{ item.url }}</div>
+                          <div class="desc">{{ item.url || item.data.url }}</div>
                           <span class="del" @click.stop="onDelNetWork(item, i)">
                             <delete-icon />
                             <!-- <t-icon name="delete" /> -->
@@ -824,7 +824,7 @@ import {
   autoSaveAS,
 } from '@/services/common';
 import { useSelection } from '@/services/selections';
-import { defaultFormat } from '@/services/defaults';
+import { defaultFormat, fromArrows, toArrows } from '@/services/defaults';
 import { checkData, localStorageName, Meta2dBackData } from '@/services/utils';
 import { debounce } from '@/services/debouce';
 import { s8 } from '@/services/random';
@@ -1073,31 +1073,31 @@ 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 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 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;
@@ -1504,6 +1504,14 @@ const deleteNetwork = (index: number) => {
 const onOkNetwork = async () => {
   const data = transformData(dataDialog.network,'toNetwork');
   if (dataDialog.editNetwork === 1) {
+    if(!dataDialog.network.data.url) {
+      MessagePlugin.error('URL地址不能为空!');
+      return;
+    }
+    if(!dataDialog.network.name) {
+      MessagePlugin.error('名称不能为空!');
+      return;
+    }
     if (dataDialog.save) {
       const ret: any = await axios.post(
         `/api/data/datasource/add`,

+ 2 - 0
src/views/components/common/CodeEditor.vue

@@ -96,6 +96,8 @@ onMounted(() => {
     minimap: { enabled: false },
     language: language || 'javascript',
     theme: 'vs-dark',
+    lineNumbersMinChars:1,
+    lineDecorationsWidth:0,
     ...options,
   });
   editor.onDidChangeModelContent(() => {