Alsmile %!s(int64=2) %!d(string=hai) anos
pai
achega
0062b2bb4a

+ 3 - 0
src/styles/app.css

@@ -233,6 +233,9 @@ a.hover:hover {
 .ml-8 {
   margin-left: 8px;
 }
+.-ml-8 {
+  margin-left: -8px;
+}
 
 .ml-12 {
   margin-left: 12px;

+ 10 - 1
src/styles/props.css

@@ -12,7 +12,7 @@
   .form-item {
     display: flex;
 
-    label {
+    & > label {
       width: 76px;
       font-size: 12px;
       line-height: 30px;
@@ -77,6 +77,15 @@
       font-size: 16px;
       height: 30px;
     }
+
+    .t-tag {
+      line-height: 24px;
+      .t-icon {
+        height: 23px;
+        margin-left: 4px;
+        margin-right: -4px;
+      }
+    }
   }
 
   .t-collapse.t--border-less {

+ 4 - 0
src/styles/tdesign.css

@@ -337,6 +337,10 @@
   &.w-full {
     .t-input--auto-width {
       min-width: 100%;
+      max-width: 100%;
+      .t-input .t-input__inner {
+        text-overflow: ellipsis;
+      }
     }
   }
 

+ 1 - 0
src/styles/var.css

@@ -60,4 +60,5 @@
   --td-border-level-1-color: var(--color-background-input);
   --td-text-color-placeholder: var(--color-desc);
   --td-brand-color: var(--color-primary);
+  --td-bg-color-component: var(--color-border-input);
 }

+ 47 - 48
src/views/components/ElementTree.vue

@@ -86,45 +86,45 @@
         </div>
       </template>
     </t-tree>
-    <div class="groups" style="padding: 8px 0">
+    <div class="groups-panel" style="padding: 8px 0">
       <div class="flex middle between" style="padding: 0 12px">
-        <div class="title">图层</div>
-        <a @click="addLayer"> +新建图层</a>
+        <div class="title">分组</div>
+        <a @click="addGroup"> +新建分组</a>
       </div>
-      <div class="layers">
+      <div class="groups">
         <div
-          v-for="(item, i) in data.layers"
+          v-for="(item, i) in data.groups"
           class="flex middle between hover"
-          :class="{ primary: i == data.activedLayer }"
+          :class="{ primary: i == data.activedGroup }"
         >
           <span
             class="flex-grow"
-            v-if="i != data.editedLayer"
-            @click="activeLayer(i)"
+            v-if="i != data.editedGroup"
+            @click="activeGroup(i)"
             @dblclick="
-              data.activedLayer = data.editedLayer = i;
-              data.layer = item;
+              data.activedGroup = data.editedGroup = i;
+              data.group = item;
             "
           >
             {{ item }}
           </span>
           <t-input
             v-else
-            v-model="data.layer"
+            v-model="data.group"
             :autofocus="true"
-            @blur="setLayer"
-            @enter="setLayer"
+            @blur="setGroup"
+            @enter="setGroup"
           />
           <t-popconfirm
-            content="确认删除该图层吗?"
-            @confirm="delLayer"
-            @cancel="data.deleteLayer = undefined"
+            content="确认删除该分组吗?"
+            @confirm="delGroup"
+            @cancel="data.deleteGroup = undefined"
           >
             <t-icon
               name="delete"
               class="ml-8"
-              :class="{ block: i == data.deleteLayer }"
-              @click="data.deleteLayer = i"
+              :class="{ block: i == data.deleteGroup }"
+              @click="data.deleteGroup = i"
             />
           </t-popconfirm>
         </div>
@@ -142,7 +142,7 @@ const tree = ref<any>(null);
 const data = reactive<any>({
   tree: [],
   actived: [],
-  layers: [],
+  groups: [],
 });
 
 onBeforeMount(() => {
@@ -156,10 +156,10 @@ onBeforeMount(() => {
   getTree();
 
   const d = meta2d.store.data as any;
-  if (!d.layers) {
-    d.layers = [];
+  if (!d.groups) {
+    d.groups = [];
   }
-  data.layers = d.layers;
+  data.groups = d.groups;
 });
 
 const getTree = () => {
@@ -249,20 +249,19 @@ const onDescription = (node: any) => {
   });
 };
 
-const addLayer = () => {
-  const i = data.layers.length + 1;
-  data.layer = '图层' + i;
-  data.layers.push(data.layer);
-  data.activedLayer = data.editedLayer = i;
+const addGroup = () => {
+  const i = data.groups.length + 1;
+  data.group = '组' + i;
+  data.groups.push(data.group);
+  data.activedGroup = data.editedGroup = i;
 };
 
-const activeLayer = (i: number) => {
-  data.activedLayer = i;
-  const layer = data.layers[i];
+const activeGroup = (i: number) => {
+  data.activedGroup = i;
+  const group = data.groups[i];
   const pens: Pen[] = [];
   for (const item of meta2d.store.data.pens) {
-    // @ts-ignore
-    if (item.layer === layer) {
+    if (item.tags?.includes(group)) {
       pens.push(item);
     }
   }
@@ -270,39 +269,39 @@ const activeLayer = (i: number) => {
   meta2d.render();
 };
 
-const setLayer = () => {
-  if (data.layers[data.editedLayer] === data.layer) {
-    data.editedLayer = undefined;
+const setGroup = () => {
+  if (data.groups[data.editedGroup] === data.group) {
+    data.editedGroup = undefined;
     return;
   }
 
-  if (data.layers.includes(data.layer)) {
-    MessagePlugin.error('已经存在相同图层!');
+  if (data.groups.includes(data.group)) {
+    MessagePlugin.error('已经存在相同分组!');
     return;
   }
 
   for (const item of meta2d.store.data.pens) {
     // @ts-ignore
-    if (item.layer === data.layers[data.editedLayer]) {
+    if (item.group === data.groups[data.editedGroup]) {
       // @ts-ignore
-      item.layer === data.layer;
+      item.group === data.group;
     }
   }
 
-  data.layers[data.editedLayer] = data.layer;
-  data.editedLayer = undefined;
+  data.groups[data.editedGroup] = data.group;
+  data.editedGroup = undefined;
 };
 
-const delLayer = () => {
+const delGroup = () => {
   for (const item of meta2d.store.data.pens) {
     // @ts-ignore
-    if (item.layer === data.layers[data.deleteLayer]) {
+    if (item.group === data.groups[data.deleteGroup]) {
       // @ts-ignore
-      delete item.layer;
+      delete item.group;
     }
   }
-  data.layers.splice(data.deleteLayer, 1);
-  data.deleteLayer = undefined;
+  data.groups.splice(data.deleteGroup, 1);
+  data.deleteGroup = undefined;
 };
 
 onBeforeUnmount(() => {
@@ -325,14 +324,14 @@ onBeforeUnmount(() => {
     width: 100%;
   }
 
-  .groups {
+  .groups-panel {
     flex-shrink: 0;
     height: 240px;
     border-top: 1px solid var(--color-border-input);
     padding: 8px 12px;
   }
 
-  .layers {
+  .groups {
     height: calc(100% - 24px);
     overflow-y: auto;
     padding: 0 12px 16px 12px;

+ 131 - 29
src/views/components/PenProps.vue

@@ -4,16 +4,7 @@
       <t-tab-panel :value="1" label="外观">
         <t-space direction="vertical" class="py-16 w-full">
           <div class="form-item px-12">
-            <label>ID</label>
-            <t-input
-              class="w-full"
-              placeholder="唯一标识"
-              v-model.number="data.pen.id"
-              @change="changeValue('id')"
-            />
-          </div>
-          <div class="form-item px-12" style="margin-top: -12px">
-            <label>名称</label>
+            <label style="width: 50px">名称</label>
             <t-input
               class="w-full"
               placeholder="名称"
@@ -22,13 +13,31 @@
             />
           </div>
           <div class="form-item px-12" style="margin-top: -12px">
-            <label>标签</label>
-            <t-taginput
-              class="w-full"
-              placeholder="标签"
-              v-model="data.pen.tags"
-              @change="changeValue('tags')"
-            />
+            <label style="width: 50px">分组</label>
+            <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' }"
+            >
+              <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>
           <t-divider style="margin: -8px 0" />
           <div class="form-item" style="margin-top: -12px">
@@ -155,16 +164,7 @@
                     v-model="data.pen.color"
                     @change="changeValue('color')"
                   />
-                  <label style="width: 44px">前景</label>
-                  <t-color-picker
-                    class="simple mt-8 mr-4"
-                    format="CSS"
-                    :color-modes="['monochrome']"
-                    :show-primary-color-preview="false"
-                    v-model="data.pen.background"
-                    @change="changeValue('background')"
-                  />
-                  <label style="width: 44px">背景</label>
+                  <label style="width: 64px">前景颜色</label>
 
                   <t-color-picker
                     class="simple mt-8 mr-4"
@@ -174,7 +174,7 @@
                     v-model="data.pen.hoverColor"
                     @change="changeValue('hoverColor')"
                   />
-                  <label style="width: 44px">悬停</label>
+                  <label style="width: 64px">悬停颜色</label>
 
                   <t-color-picker
                     class="simple mt-8 mr-4"
@@ -184,7 +184,7 @@
                     v-model="data.pen.activeColor"
                     @change="changeValue('activeColor')"
                   />
-                  <label style="width: 44px">选中</label>
+                  <label style="width: 64px">选中颜色</label>
                 </div>
 
                 <div class="form-item">
@@ -364,6 +364,70 @@
                     <div class="mt-4" style="font-size: 12px">连接样式</div>
                   </div>
                 </div>
+                <div class="form-item">
+                  <label style="width: 32px">背景</label>
+                  <div class="ml-8">
+                    <t-radio-group
+                      size="small"
+                      v-model="data.pen.bkType"
+                      :default-value="0"
+                      @change="changeValue('bkType')"
+                    >
+                      <t-radio-button :value="0"> 纯色 </t-radio-button>
+                      <t-radio-button :value="1"> 线性渐变 </t-radio-button>
+                      <t-radio-button :value="2"> 径向渐变 </t-radio-button>
+                    </t-radio-group>
+                    <div v-if="data.pen.bkType === 0" class="mt-8 -ml-8">
+                      <t-color-picker
+                        class="w-full"
+                        format="CSS"
+                        :color-modes="['monochrome']"
+                        :show-primary-color-preview="false"
+                        v-model="data.pen.background"
+                        @change="changeValue('background')"
+                      />
+                    </div>
+                    <div
+                      v-else-if="data.pen.bkType === 1"
+                      class="mt-8 -ml-8"
+                      style="width: 200px"
+                    >
+                      <t-color-picker
+                        class="w-full"
+                        format="CSS"
+                        :color-modes="['linear-gradient']"
+                        :show-primary-color-preview="false"
+                        v-model="data.pen.gradientColors"
+                        @change="changeValue('gradientColors')"
+                      />
+                    </div>
+                    <div
+                      v-else-if="data.pen.bkType === 2"
+                      class="mt-8 flex middle"
+                    >
+                      <t-color-picker
+                        class="simple"
+                        format="CSS"
+                        :color-modes="['linear-gradient']"
+                        :show-primary-color-preview="false"
+                        v-model="data.pen.gradientColors"
+                        @change="changeValue('gradientColors')"
+                      />
+
+                      <t-input-number
+                        theme="column"
+                        placeholder="渐变半径"
+                        v-model="data.pen.gradientRadius"
+                        :min="0"
+                        :max="1"
+                        :step="0.1"
+                        @change="changeValue('gradientRadius')"
+                        class="ml-8"
+                        style="width: 100px"
+                      />
+                    </div>
+                  </div>
+                </div>
                 <div class="form-item">
                   <label style="width: 32px">阴影 </label>
                   <div class="flex middle ml-8">
@@ -913,6 +977,12 @@ const fonts = [
 const { selections } = useSelection();
 
 onBeforeMount(() => {
+  const d = meta2d.store.data as any;
+  if (!d.groups) {
+    d.groups = [];
+  }
+  data.groups = d.groups;
+
   data.pen = selections.pen;
   if (!data.pen.props) {
     data.pen.props = {};
@@ -940,6 +1010,12 @@ onBeforeMount(() => {
       },
     ];
   }
+  if (!data.pen.tags) {
+    data.pen.tags = [];
+  }
+  if (data.pen.bkType == undefined) {
+    data.pen.bkType = 0;
+  }
 
   // 测试代码
   data.pen.props.custom = [
@@ -1042,6 +1118,32 @@ const upload = () => {
   uploadRef.value.triggerUpload();
 };
 
+const onSelectTag = (tag: string) => {
+  data.tagPopupVisible = false;
+  if (data.pen.tags.includes(tag)) {
+    return;
+  }
+  data.pen.tags.push(tag);
+  changeValue('tags');
+};
+
+const onChangeInputTag = (currentTags: any, context: any) => {
+  const { trigger, index, item } = context;
+  if (['tag-remove', 'backspace'].includes(trigger)) {
+    data.pen.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;
+};
+
 onUnmounted(() => {
   meta2d.off('translatePens', getRect);
   meta2d.off('resizePens', getRect);