소스 검색

Merge branch 'main' into deploy

Alsmile 1 년 전
부모
커밋
cb27fb4e6b

+ 4 - 0
index.html

@@ -23,6 +23,10 @@
         overflow: hidden;
       }
     </style>
+    <link
+      href="//at.alicdn.com/t/c/font_4042197_yrikqthz1j.css"
+      rel="stylesheet"
+    />
     <script src="//at.alicdn.com/t/c/font_4042197_yrikqthz1j.js"></script>
   </head>
   <body>

+ 386 - 0
public/theme/dark.json

@@ -0,0 +1,386 @@
+{
+    "color": [
+        "#4583ff",
+        "#37b3cc",
+        "#258ca6",
+        "#34bf6e",
+        "#239957",
+        "#3062da"
+    ],
+    "backgroundColor": "#181818",
+    "textStyle": {},
+    "title": {
+        "textStyle": {
+            "color": "#ffffff"
+        },
+        "subtextStyle": {
+            "color": "#aaaaaa"
+        }
+    },
+    "line": {
+        "itemStyle": {
+            "borderWidth": 1
+        },
+        "lineStyle": {
+            "width": 2
+        },
+        "symbolSize": 4,
+        "symbol": "circle",
+        "smooth": false
+    },
+    "radar": {
+        "itemStyle": {
+            "borderWidth": 1
+        },
+        "lineStyle": {
+            "width": 2
+        },
+        "symbolSize": 4,
+        "symbol": "circle",
+        "smooth": false
+    },
+    "bar": {
+        "itemStyle": {
+            "barBorderWidth": "1",
+            "barBorderColor": "#181818"
+        }
+    },
+    "pie": {
+        "itemStyle": {
+            "borderWidth": "1",
+            "borderColor": "#181818"
+        }
+    },
+    "scatter": {
+        "itemStyle": {
+            "borderWidth": "1",
+            "borderColor": "#181818"
+        }
+    },
+    "boxplot": {
+        "itemStyle": {
+            "borderWidth": "1",
+            "borderColor": "#181818"
+        }
+    },
+    "parallel": {
+        "itemStyle": {
+            "borderWidth": "1",
+            "borderColor": "#181818"
+        }
+    },
+    "sankey": {
+        "itemStyle": {
+            "borderWidth": "1",
+            "borderColor": "#181818"
+        }
+    },
+    "funnel": {
+        "itemStyle": {
+            "borderWidth": "1",
+            "borderColor": "#181818"
+        }
+    },
+    "gauge": {
+        "itemStyle": {
+            "borderWidth": "1",
+            "borderColor": "#181818"
+        }
+    },
+    "candlestick": {
+        "itemStyle": {
+            "color": "#fd1050",
+            "color0": "#0cf49b",
+            "borderColor": "#fd1050",
+            "borderColor0": "#0cf49b",
+            "borderWidth": 1
+        }
+    },
+    "graph": {
+        "itemStyle": {
+            "borderWidth": "1",
+            "borderColor": "#181818"
+        },
+        "lineStyle": {
+            "width": 1,
+            "color": "#aaa"
+        },
+        "symbolSize": 4,
+        "symbol": "circle",
+        "smooth": false,
+        "color": [
+            "#4583ff",
+            "#37b3cc",
+            "#258ca6",
+            "#34bf6e",
+            "#239957",
+            "#3062da"
+        ],
+        "label": {
+            "color": "#ffffff"
+        }
+    },
+    "map": {
+        "itemStyle": {
+            "areaColor": "#eee",
+            "borderColor": "#444",
+            "borderWidth": 0.5
+        },
+        "label": {
+            "color": "#000"
+        },
+        "emphasis": {
+            "itemStyle": {
+                "areaColor": "rgba(255,215,0,0.8)",
+                "borderColor": "#444",
+                "borderWidth": 1
+            },
+            "label": {
+                "color": "rgb(100,0,0)"
+            }
+        }
+    },
+    "geo": {
+        "itemStyle": {
+            "areaColor": "#eee",
+            "borderColor": "#444",
+            "borderWidth": 0.5
+        },
+        "label": {
+            "color": "#000"
+        },
+        "emphasis": {
+            "itemStyle": {
+                "areaColor": "rgba(255,215,0,0.8)",
+                "borderColor": "#444",
+                "borderWidth": 1
+            },
+            "label": {
+                "color": "rgb(100,0,0)"
+            }
+        }
+    },
+    "categoryAxis": {
+        "axisLine": {
+            "show": true,
+            "lineStyle": {
+                "color": "rgba(255,255,255,0.26)"
+            }
+        },
+        "axisTick": {
+            "show": true,
+            "lineStyle": {
+                "color": "rgba(216,216,216,0.26)"
+            }
+        },
+        "axisLabel": {
+            "show": true,
+            "color": "rgba(255,255,255,0.7)"
+        },
+        "splitLine": {
+            "show": true,
+            "lineStyle": {
+                "color": [
+                    "rgba(255,255,255,0.1)"
+                ]
+            }
+        },
+        "splitArea": {
+            "show": false,
+            "areaStyle": {
+                "color": [
+                    "#eeeeee"
+                ]
+            }
+        }
+    },
+    "valueAxis": {
+        "axisLine": {
+            "show": true,
+            "lineStyle": {
+                "color": "rgba(255,255,255,0.26)"
+            }
+        },
+        "axisTick": {
+            "show": true,
+            "lineStyle": {
+                "color": "rgba(216,216,216,0.26)"
+            }
+        },
+        "axisLabel": {
+            "show": true,
+            "color": "rgba(255,255,255,0.7)"
+        },
+        "splitLine": {
+            "show": true,
+            "lineStyle": {
+                "color": [
+                    "rgba(255,255,255,0.1)"
+                ]
+            }
+        },
+        "splitArea": {
+            "show": false,
+            "areaStyle": {
+                "color": [
+                    "#eeeeee"
+                ]
+            }
+        }
+    },
+    "logAxis": {
+        "axisLine": {
+            "show": true,
+            "lineStyle": {
+                "color": "rgba(255,255,255,0.26)"
+            }
+        },
+        "axisTick": {
+            "show": true,
+            "lineStyle": {
+                "color": "rgba(216,216,216,0.26)"
+            }
+        },
+        "axisLabel": {
+            "show": true,
+            "color": "rgba(255,255,255,0.7)"
+        },
+        "splitLine": {
+            "show": true,
+            "lineStyle": {
+                "color": [
+                    "rgba(255,255,255,0.1)"
+                ]
+            }
+        },
+        "splitArea": {
+            "show": false,
+            "areaStyle": {
+                "color": [
+                    "#eeeeee"
+                ]
+            }
+        }
+    },
+    "timeAxis": {
+        "axisLine": {
+            "show": true,
+            "lineStyle": {
+                "color": "rgba(255,255,255,0.26)"
+            }
+        },
+        "axisTick": {
+            "show": true,
+            "lineStyle": {
+                "color": "rgba(216,216,216,0.26)"
+            }
+        },
+        "axisLabel": {
+            "show": true,
+            "color": "rgba(255,255,255,0.7)"
+        },
+        "splitLine": {
+            "show": true,
+            "lineStyle": {
+                "color": [
+                    "rgba(255,255,255,0.1)"
+                ]
+            }
+        },
+        "splitArea": {
+            "show": false,
+            "areaStyle": {
+                "color": [
+                    "#eeeeee"
+                ]
+            }
+        }
+    },
+    "toolbox": {
+        "iconStyle": {
+            "borderColor": "#ffffff"
+        },
+        "emphasis": {
+            "iconStyle": {
+                "borderColor": "#666666"
+            }
+        }
+    },
+    "legend": {
+        "textStyle": {
+            "color": "rgba(255,255,255,0.7)"
+        }
+    },
+    "tooltip": {
+        "axisPointer": {
+            "lineStyle": {
+                "color": "rgba(216,216,216,0.3)",
+                "width": "1"
+            },
+            "crossStyle": {
+                "color": "rgba(216,216,216,0.3)",
+                "width": "1"
+            }
+        }
+    },
+    "timeline": {
+        "lineStyle": {
+            "color": "#eeeeee",
+            "width": 1
+        },
+        "itemStyle": {
+            "color": "#dd6b66",
+            "borderWidth": 1
+        },
+        "controlStyle": {
+            "color": "#eeeeee",
+            "borderColor": "#eeeeee",
+            "borderWidth": 0.5
+        },
+        "checkpointStyle": {
+            "color": "#e43c59",
+            "borderColor": "#c23531"
+        },
+        "label": {
+            "color": "#eeeeee"
+        },
+        "emphasis": {
+            "itemStyle": {
+                "color": "#a9334c"
+            },
+            "controlStyle": {
+                "color": "#eeeeee",
+                "borderColor": "#eeeeee",
+                "borderWidth": 0.5
+            },
+            "label": {
+                "color": "#eeeeee"
+            }
+        }
+    },
+    "visualMap": {
+        "color": [
+            "#bf444c"
+        ]
+    },
+    "dataZoom": {
+        "backgroundColor": "rgba(47,69,84,0)",
+        "dataBackgroundColor": "rgba(255,255,255,0.3)",
+        "fillerColor": "rgba(167,183,204,0.4)",
+        "handleColor": "#a7b7cc",
+        "handleSize": "100%",
+        "textStyle": {
+            "color": "#eeeeee"
+        }
+    },
+    "markPoint": {
+        "label": {
+            "color": "#ffffff"
+        },
+        "emphasis": {
+            "label": {
+                "color": "#ffffff"
+            }
+        }
+    }
+}

+ 3 - 0
src/App.vue

@@ -6,11 +6,14 @@
 import { onBeforeMount } from 'vue';
 
 import { useUser } from './services/user';
+import { changeTheme, registerTheme } from './services/echarts';
 
 const { getUser } = useUser();
 
 onBeforeMount(() => {
   getUser();
+  registerTheme();
+  changeTheme('le-dark');
 });
 </script>
 <style lang="postcss" scoped></style>

+ 4 - 1
src/http.ts

@@ -38,7 +38,10 @@ axios.interceptors.response.use(
       return;
     }
     if (error && error.response) {
-      if (error.response.config.url === '/api/account/profile') {
+      if (
+        error.response.config.url === '/api/account/profile' ||
+        error.response.data.error === '此为付费数据,请购买后访问'
+      ) {
         return;
       }
 

+ 64 - 4
src/services/common.ts

@@ -1,14 +1,72 @@
 import { reactive, ref } from 'vue';
-import router from '@/router/index';
-import { useUser } from '@/services/user';
-import { showNotification, Meta2dBackData, checkData } from '@/services/utils';
 import { MessagePlugin } from 'tdesign-vue-next';
 import localforage from 'localforage';
 import dayjs from 'dayjs';
+import axios from 'axios';
+import router from '@/router/index';
+import { useUser } from '@/services/user';
+import { showNotification, Meta2dBackData, checkData } from '@/services/utils';
 import { noLoginTip, localStorageName } from '@/services/utils';
 import { upload, dataURLtoBlob } from '@/services/file';
 import { delImage, addCollection, updateCollection } from '@/services/api';
 import { baseVer } from '@/services/upgrade';
+import { debounce } from './debouce';
+
+const assets = reactive({
+  home: 'https://le5le.com',
+  account: 'https://account.le5le.com',
+  helps: [
+    {
+      name: '产品介绍',
+      url: 'https://doc.le5le.com/document/118756411',
+    },
+    {
+      name: '快速上手',
+      url: 'https://doc.le5le.com/document/119363000',
+    },
+    {
+      name: '使用手册',
+      url: 'https://doc.le5le.com/document/118764244',
+    },
+    {
+      name: '快捷键',
+      url: 'https://doc.le5le.com/document/119620214',
+      divider: true,
+    },
+    {
+      name: '企业服务与支持',
+      url: 'https://doc.le5le.com/document/119296274',
+      divider: true,
+    },
+    {
+      name: '关于我们',
+      url: 'https://le5le.com/about.html',
+    },
+  ],
+});
+
+export const useAssets = () => {
+  const getAssets = async () => {
+    // 官网或安装包版本
+    if (
+      import.meta.env.VITE_TRIAL == undefined ||
+      import.meta.env.VITE_TRIAL == 1
+    ) {
+      return;
+    }
+
+    // 企业版
+    const ret = await axios.get('/api/assets');
+    if (ret) {
+      Object.assign(assets, ret);
+    }
+  };
+
+  return {
+    assets,
+    getAssets,
+  };
+};
 
 const dot = ref(false);
 
@@ -16,10 +74,12 @@ export const useDot = () => {
   const getDot = async () => {
     return dot;
   };
-  const setDot = async (value: boolean) => {
+  const setDot = async (value = true) => {
     dot.value = value;
     if (value) {
       tree.patch = true;
+
+      debounce(autoSave, 3000);
     }
   };
 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 1092
src/services/defaults.ts


+ 1204 - 0
src/services/echarts.ts

@@ -0,0 +1,1204 @@
+import { ReplaceMode } from '@meta2d/chart-diagram';
+
+//注册所有主题
+export function registerTheme() {
+  fetch('theme/dark.json')
+    .then((r) => r.json())
+    .then((theme) => {
+      echarts.registerTheme('le-dark', theme);
+    });
+}
+
+export function changeTheme(theme: string) {
+  charts.forEach((item) => {
+    item.list.forEach((chart) => {
+      if (chart.data.name === 'echarts') {
+        chart.data.echarts.theme = theme;
+      }
+    });
+  });
+}
+
+export const charts = [
+  {
+    name: 'Echarts - 基础图表',
+    show: true,
+    list: [
+      {
+        name: '折线图',
+        icon: 'l-line-chart',
+        data: {
+          name: 'echarts',
+          width: 400,
+          height: 300,
+          externElement: true,
+          disableAnchor: true,
+          echarts: {
+            option: {
+              tooltip: {
+                trigger: 'axis',
+              },
+              grid: {
+                top: 10,
+                bottom: 20,
+                left: 40,
+                right: 5,
+              },
+              xAxis: {
+                type: 'category',
+                data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+                axisLabel: {
+                  fontSize: 12,
+                  // color: '#ffffff',
+                },
+              },
+              yAxis: {
+                type: 'value',
+                axisLabel: {
+                  fontSize: 12,
+                  // color: '#ffffff',
+                },
+              },
+              series: [
+                {
+                  type: 'line',
+                  data: [820, 932, 901, 934, 1290, 1330, 1320],
+                },
+              ],
+            },
+            max: 100,
+          },
+          realTimes: [
+            {
+              key: 'echarts.option.series.0.data',
+              label: '数据',
+              type: 'object',
+            },
+            {
+              key: 'echarts.option',
+              label: 'echarts',
+              type: 'object',
+            },
+            {
+              key: 'echarts.max',
+              label: '最大数量',
+              type: 'number',
+            },
+          ],
+        },
+      },
+      {
+        name: '柱状图',
+        icon: 'l-bar-chart',
+        data: {
+          width: 300,
+          height: 200,
+          disableAnchor: true,
+          externElement: true,
+          name: 'echarts',
+          echarts: {
+            option: {
+              tooltip: {
+                trigger: 'axis',
+              },
+              grid: {
+                top: 10,
+                bottom: 20,
+                left: 40,
+                right: 5,
+              },
+              xAxis: {
+                type: 'category',
+                data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+                axisTick: {
+                  alignWithLabel: true,
+                },
+                axisLabel: {
+                  fontSize: 12,
+                  color: '#ffffff',
+                },
+              },
+              yAxis: {
+                type: 'value',
+                axisLabel: {
+                  fontSize: 12,
+                  color: '#ffffff',
+                },
+              },
+              series: [
+                {
+                  name: '直接访问',
+                  type: 'bar',
+                  barWidth: '60%',
+                  label: {
+                    color: '#ffffff',
+                  },
+                  data: [10, 52, 200, 334, 390, 330, 220],
+                },
+              ],
+            },
+            max: 100,
+          },
+          realTimes: [
+            {
+              key: 'echarts.option.series.0.data',
+              label: '数据',
+              type: 'object',
+            },
+            {
+              key: 'echarts.option',
+              label: 'echarts',
+              type: 'object',
+            },
+            {
+              key: 'echarts.max',
+              label: '最大数量',
+              type: 'number',
+            },
+          ],
+        },
+      },
+      {
+        name: '饼图',
+        icon: 'l-pie-chart',
+        data: {
+          width: 300,
+          height: 200,
+          disableAnchor: true,
+          externElement: true,
+          name: 'echarts',
+          echarts: {
+            option: {
+              tooltip: {
+                trigger: 'item',
+              },
+              series: [
+                {
+                  type: 'pie',
+                  radius: ['50%', '70%'],
+                  label: {
+                    color: '#ffffff',
+                  },
+                  data: [
+                    { value: 335, name: '2D' },
+                    { value: 310, name: '3D' },
+                    { value: 234, name: '大屏' },
+                    { value: 135, name: '物联网平台' },
+                    { value: 1548, name: '图形库' },
+                  ],
+                },
+              ],
+            },
+            replaceMode: ReplaceMode.Replace,
+          },
+          realTimes: [
+            {
+              key: 'echarts.option.series.0.data',
+              label: '数据',
+              type: 'object',
+            },
+            {
+              key: 'echarts.option',
+              label: 'echarts',
+              type: 'object',
+            },
+          ],
+        },
+      },
+      {
+        name: '散点图',
+        icon: 'l-sandiantu',
+        data: {
+          width: 300,
+          height: 200,
+          disableAnchor: true,
+          externElement: true,
+          name: 'echarts',
+          echarts: {
+            option: {
+              grid: {
+                top: 10,
+                bottom: 20,
+                left: 40,
+                right: 10,
+              },
+              xAxis: {
+                axisLabel: {
+                  fontSize: 12,
+                  color: '#ffffff',
+                },
+              },
+              yAxis: {
+                axisLabel: {
+                  fontSize: 12,
+                  color: '#ffffff',
+                },
+              },
+              series: [
+                {
+                  symbolSize: 10,
+                  data: [
+                    [10.0, 8.04],
+                    [8.07, 6.95],
+                    [13.0, 7.58],
+                    [9.05, 8.81],
+                    [11.0, 8.33],
+                    [14.0, 7.66],
+                    [13.4, 6.81],
+                    [10.0, 6.33],
+                    [14.0, 8.96],
+                    [12.5, 6.82],
+                    [9.15, 7.2],
+                    [11.5, 7.2],
+                    [3.03, 4.23],
+                    [12.2, 7.83],
+                    [2.02, 4.47],
+                    [1.05, 3.33],
+                    [4.05, 4.96],
+                    [6.03, 7.24],
+                    [12.0, 6.26],
+                    [12.0, 8.84],
+                    [7.08, 5.82],
+                    [5.02, 5.68],
+                  ],
+                  type: 'scatter',
+                },
+              ],
+            },
+            replaceMode: ReplaceMode.Replace,
+          },
+          realTimes: [
+            {
+              key: 'echarts.option.series.0.data',
+              label: '数据',
+              type: 'object',
+            },
+            {
+              key: 'echarts.option',
+              label: 'echarts',
+              type: 'object',
+            },
+          ],
+        },
+      },
+      {
+        name: 'K线图',
+        icon: 'l-kxiantu',
+        data: {
+          width: 300,
+          height: 200,
+          disableAnchor: true,
+          externElement: true,
+          name: 'echarts',
+          echarts: {
+            option: {
+              grid: {
+                top: 20,
+                bottom: 30,
+                left: 40,
+                right: 10,
+              },
+              xAxis: {
+                axisLabel: {
+                  fontSize: 12,
+                  color: '#ffffff',
+                },
+                data: ['2017-10-24', '2017-10-25', '2017-10-26', '2017-10-27'],
+              },
+              yAxis: {
+                axisLabel: {
+                  fontSize: 12,
+                  color: '#ffffff',
+                },
+              },
+              series: [
+                {
+                  type: 'candlestick',
+                  data: [
+                    [20, 34, 10, 38],
+                    [40, 35, 30, 50],
+                    [31, 38, 33, 44],
+                    [38, 15, 5, 42],
+                  ],
+                },
+              ],
+            },
+            replaceMode: ReplaceMode.Replace,
+          },
+          realTimes: [
+            {
+              key: 'echarts.option.series.0.data',
+              label: '数据',
+              type: 'object',
+            },
+            {
+              key: 'echarts.option',
+              label: 'echarts',
+              type: 'object',
+            },
+          ],
+        },
+      },
+      {
+        name: '雷达图',
+        icon: 'l-leidatu',
+        data: {
+          width: 300,
+          height: 200,
+          disableAnchor: true,
+          externElement: true,
+          name: 'echarts',
+          echarts: {
+            option: {
+              grid: {
+                top: 20,
+                bottom: 30,
+                left: 40,
+                right: 10,
+              },
+              radar: {
+                // shape: 'circle',
+                indicator: [
+                  { name: 'Sales', max: 6500 },
+                  { name: 'Administration', max: 16000 },
+                  { name: 'Information Technology', max: 30000 },
+                  { name: 'Customer Support', max: 38000 },
+                  { name: 'Development', max: 52000 },
+                  { name: 'Marketing', max: 25000 },
+                ],
+              },
+              series: [
+                {
+                  name: 'Budget vs spending',
+                  type: 'radar',
+                  data: [
+                    {
+                      value: [4200, 3000, 20000, 35000, 50000, 18000],
+                      name: 'Allocated Budget',
+                    },
+                    {
+                      value: [5000, 14000, 28000, 26000, 42000, 21000],
+                      name: 'Actual Spending',
+                    },
+                  ],
+                },
+              ],
+            },
+            replaceMode: ReplaceMode.Replace,
+          },
+          realTimes: [
+            {
+              key: 'echarts.option.series.0.data',
+              label: '数据',
+              type: 'object',
+            },
+            {
+              key: 'echarts.option',
+              label: 'echarts',
+              type: 'object',
+            },
+          ],
+        },
+      },
+      {
+        name: '旭日图',
+        icon: 'l-xuritu',
+        data: {
+          width: 200,
+          height: 200,
+          disableAnchor: true,
+          externElement: true,
+          name: 'echarts',
+          echarts: {
+            option: {
+              series: [
+                {
+                  radius: ['15%', '80%'],
+                  type: 'sunburst',
+                  data: [
+                    {
+                      children: [
+                        {
+                          value: 5,
+                          children: [
+                            {
+                              value: 1,
+                              itemStyle: {
+                                color: '#F54F4A',
+                              },
+                            },
+                            {
+                              value: 2,
+                              children: [
+                                {
+                                  value: 1,
+                                  itemStyle: {
+                                    color: '#FF8C75',
+                                  },
+                                },
+                              ],
+                            },
+                            {
+                              children: [
+                                {
+                                  value: 1,
+                                },
+                              ],
+                            },
+                          ],
+                          itemStyle: {
+                            color: '#F54F4A',
+                          },
+                        },
+                        {
+                          value: 10,
+                          children: [
+                            {
+                              value: 6,
+                              children: [
+                                {
+                                  value: 1,
+                                  itemStyle: {
+                                    color: '#F54F4A',
+                                  },
+                                },
+                                {
+                                  value: 1,
+                                },
+                                {
+                                  value: 1,
+                                  itemStyle: {
+                                    color: '#FF8C75',
+                                  },
+                                },
+                                {
+                                  value: 1,
+                                },
+                              ],
+                              itemStyle: {
+                                color: '#FFB499',
+                              },
+                            },
+                            {
+                              value: 2,
+                              children: [
+                                {
+                                  value: 1,
+                                },
+                              ],
+                              itemStyle: {
+                                color: '#FFB499',
+                              },
+                            },
+                            {
+                              children: [
+                                {
+                                  value: 1,
+                                  itemStyle: {
+                                    color: '#FF8C75',
+                                  },
+                                },
+                              ],
+                            },
+                          ],
+                          itemStyle: {
+                            color: '#F54F4A',
+                          },
+                        },
+                      ],
+                      itemStyle: {
+                        color: '#F54F4A',
+                      },
+                    },
+                    {
+                      value: 9,
+                      children: [
+                        {
+                          value: 4,
+                          children: [
+                            {
+                              value: 2,
+                              itemStyle: {
+                                color: '#FF8C75',
+                              },
+                            },
+                            {
+                              children: [
+                                {
+                                  value: 1,
+                                  itemStyle: {
+                                    color: '#F54F4A',
+                                  },
+                                },
+                              ],
+                            },
+                          ],
+                          itemStyle: {
+                            color: '#F54F4A',
+                          },
+                        },
+                        {
+                          children: [
+                            {
+                              value: 3,
+                              children: [
+                                {
+                                  value: 1,
+                                },
+                                {
+                                  value: 1,
+                                  itemStyle: {
+                                    color: '#FF8C75',
+                                  },
+                                },
+                              ],
+                            },
+                          ],
+                          itemStyle: {
+                            color: '#FFB499',
+                          },
+                        },
+                      ],
+                      itemStyle: {
+                        color: '#FF8C75',
+                      },
+                    },
+                    {
+                      value: 7,
+                      children: [
+                        {
+                          children: [
+                            {
+                              value: 1,
+                              itemStyle: {
+                                color: '#FFB499',
+                              },
+                            },
+                            {
+                              value: 3,
+                              children: [
+                                {
+                                  value: 1,
+                                  itemStyle: {
+                                    color: '#FF8C75',
+                                  },
+                                },
+                                {
+                                  value: 1,
+                                },
+                              ],
+                              itemStyle: {
+                                color: '#FF8C75',
+                              },
+                            },
+                            {
+                              value: 2,
+                              children: [
+                                {
+                                  value: 1,
+                                },
+                                {
+                                  value: 1,
+                                  itemStyle: {
+                                    color: '#F54F4A',
+                                  },
+                                },
+                              ],
+                              itemStyle: {
+                                color: '#F54F4A',
+                              },
+                            },
+                          ],
+                          itemStyle: {
+                            color: '#FFB499',
+                          },
+                        },
+                      ],
+                      itemStyle: {
+                        color: '#F54F4A',
+                      },
+                    },
+                    {
+                      children: [
+                        {
+                          value: 6,
+                          children: [
+                            {
+                              value: 1,
+                              itemStyle: {
+                                color: '#FF8C75',
+                              },
+                            },
+                            {
+                              value: 2,
+                              children: [
+                                {
+                                  value: 2,
+                                  itemStyle: {
+                                    color: '#FF8C75',
+                                  },
+                                },
+                              ],
+                              itemStyle: {
+                                color: '#F54F4A',
+                              },
+                            },
+                            {
+                              value: 1,
+                              itemStyle: {
+                                color: '#FFB499',
+                              },
+                            },
+                          ],
+                          itemStyle: {
+                            color: '#FFB499',
+                          },
+                        },
+                        {
+                          value: 3,
+                          children: [
+                            {
+                              value: 1,
+                            },
+                            {
+                              children: [
+                                {
+                                  value: 1,
+                                  itemStyle: {
+                                    color: '#FF8C75',
+                                  },
+                                },
+                              ],
+                            },
+                            {
+                              value: 1,
+                            },
+                          ],
+                          itemStyle: {
+                            color: '#FFB499',
+                          },
+                        },
+                      ],
+                      itemStyle: {
+                        color: '#F54F4A',
+                      },
+                    },
+                  ],
+                  label: {
+                    rotate: 'radial',
+                    color: '#ffffff',
+                  },
+                },
+              ],
+            },
+            replaceMode: ReplaceMode.Replace,
+          },
+          realTimes: [
+            {
+              key: 'echarts.option.series.0.data',
+              label: '数据',
+              type: 'object',
+            },
+            {
+              key: 'echarts.option',
+              label: 'echarts',
+              type: 'object',
+            },
+          ],
+        },
+      },
+      {
+        name: '桑基图',
+        icon: 'l-sangshentu',
+        data: {
+          width: 300,
+          height: 200,
+          disableAnchor: true,
+          externElement: true,
+          name: 'echarts',
+          echarts: {
+            option: {
+              series: {
+                type: 'sankey',
+                layout: 'none',
+                emphasis: {
+                  focus: 'adjacency',
+                },
+                data: [
+                  {
+                    name: 'a',
+                  },
+                  {
+                    name: 'b',
+                  },
+                  {
+                    name: 'a1',
+                  },
+                  {
+                    name: 'a2',
+                  },
+                  {
+                    name: 'b1',
+                  },
+                  {
+                    name: 'c',
+                  },
+                ],
+                links: [
+                  {
+                    source: 'a',
+                    target: 'a1',
+                    value: 5,
+                  },
+                  {
+                    source: 'a',
+                    target: 'a2',
+                    value: 3,
+                  },
+                  {
+                    source: 'b',
+                    target: 'b1',
+                    value: 8,
+                  },
+                  {
+                    source: 'a',
+                    target: 'b1',
+                    value: 3,
+                  },
+                  {
+                    source: 'b1',
+                    target: 'a1',
+                    value: 1,
+                  },
+                  {
+                    source: 'b1',
+                    target: 'c',
+                    value: 2,
+                  },
+                ],
+                lineStyle: {
+                  color: 'source',
+                  curveness: 0.5,
+                },
+                label: {
+                  color: '#ffffff',
+                  fontSize: 10,
+                },
+              },
+            },
+            replaceMode: ReplaceMode.Replace,
+          },
+          realTimes: [
+            {
+              key: 'echarts.option.series.0.data',
+              label: '数据',
+              type: 'object',
+            },
+            {
+              key: 'echarts.option',
+              label: 'echarts',
+              type: 'object',
+            },
+          ],
+        },
+      },
+      {
+        name: '漏斗图',
+        icon: 'l-loudoutu',
+        data: {
+          width: 200,
+          height: 200,
+          disableAnchor: true,
+          externElement: true,
+          name: 'echarts',
+          echarts: {
+            option: {
+              tooltip: {
+                trigger: 'item',
+                formatter: '{a} <br/>{b} : {c}%',
+              },
+              series: [
+                {
+                  name: 'Expected',
+                  type: 'funnel',
+                  left: '2%',
+                  width: '80%',
+                  label: {
+                    color: '#ffffff',
+                    formatter: '{b}Expected',
+                  },
+                  labelLine: {
+                    show: false,
+                  },
+                  itemStyle: {
+                    opacity: 0.7,
+                  },
+                  emphasis: {
+                    label: {
+                      position: 'inside',
+                      formatter: '{b}Expected: {c}%',
+                    },
+                  },
+                  data: [
+                    { value: 60, name: 'Visit' },
+                    { value: 40, name: 'Inquiry' },
+                    { value: 20, name: 'Order' },
+                    { value: 80, name: 'Click' },
+                    { value: 100, name: 'Show' },
+                  ],
+                },
+                {
+                  name: 'Actual',
+                  type: 'funnel',
+                  left: '2%',
+                  width: '80%',
+                  maxSize: '80%',
+                  label: {
+                    position: 'inside',
+                    formatter: '{c}%',
+                    color: '#fff',
+                  },
+                  itemStyle: {
+                    opacity: 0.5,
+                    borderColor: '#fff',
+                    borderWidth: 2,
+                  },
+                  emphasis: {
+                    label: {
+                      position: 'inside',
+                      formatter: '{b}Actual: {c}%',
+                    },
+                  },
+                  data: [
+                    { value: 30, name: 'Visit' },
+                    { value: 10, name: 'Inquiry' },
+                    { value: 5, name: 'Order' },
+                    { value: 50, name: 'Click' },
+                    { value: 80, name: 'Show' },
+                  ],
+                  z: 100,
+                },
+              ],
+            },
+            replaceMode: ReplaceMode.Replace,
+          },
+          realTimes: [
+            {
+              key: 'echarts.option.series.0.data',
+              label: '数据',
+              type: 'object',
+            },
+            {
+              key: 'echarts.option',
+              label: 'echarts',
+              type: 'object',
+            },
+          ],
+        },
+      },
+      {
+        name: '仪表盘',
+        icon: 'l-dashboard-chart',
+        data: {
+          width: 200,
+          height: 200,
+          disableAnchor: true,
+          externElement: true,
+          name: 'echarts',
+          echarts: {
+            option: {
+              tooltip: {
+                formatter: '{a} <br/>{b} : {c}%',
+              },
+              series: [
+                {
+                  type: 'gauge',
+                  axisLine: {
+                    roundCap: true,
+                  },
+                  progress: {
+                    show: true,
+                    roundCap: true,
+                  },
+                  data: [{ value: 70 }],
+                },
+              ],
+            },
+            replaceMode: ReplaceMode.Replace,
+          },
+          realTimes: [
+            {
+              key: 'echarts.option.series.0.data',
+              label: '数据',
+              type: 'object',
+            },
+            {
+              key: 'echarts.option',
+              label: 'echarts',
+              type: 'object',
+            },
+          ],
+        },
+      },
+    ],
+  },
+  {
+    name: '乐吾乐Charts',
+    show: true,
+    list: [
+      {
+        name: '折线图',
+        icon: 'l-line-chart',
+        data: {
+          name: 'lineChart',
+          width: 400,
+          disableAnchor: true,
+          height: 200,
+          chartsColor: [
+            '#1890ff',
+            '#2FC25B',
+            '#FACC14',
+            '#c23531',
+            '#2f4554',
+            '#61a0a8',
+            '#d48265',
+          ],
+          xAxisData: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+          smooth: true,
+          data: [
+            [1820, 1932, 1901, 1934, 1990, 1830, 1920],
+            [1710, 1932, 1901, 1834, 1700, 1830, 1720],
+          ],
+        },
+      },
+      {
+        name: '柱状图',
+        icon: 'l-bar-chart',
+        data: {
+          name: 'histogram',
+          x: 600,
+          y: 100,
+          width: 400,
+          height: 200,
+          disableAnchor: true,
+          chartsColor: [
+            '#1890ff',
+            '#2FC25B',
+            '#FACC14',
+            '#c23531',
+            '#2f4554',
+            '#61a0a8',
+            '#d48265',
+          ],
+          xAxisData: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+          data: [
+            [120, 200, 150, 80, 70, 110, 130],
+            [140, 250, 150, 80, 60, 10, 30],
+            [40, 50, 180, 210, 60, 70, 30],
+          ],
+        },
+      },
+      {
+        name: '饼图',
+        icon: 'l-pie-chart',
+        data: {
+          name: 'pieChart',
+          x: 100,
+          y: 300,
+          width: 400,
+          height: 200,
+          disableAnchor: true,
+          chartsColor: [
+            '#1890ff',
+            '#36CBCB',
+            '#2FC25B',
+            '#FACC14',
+            '#F2637B',
+            '#fc8452',
+            '#9a60b4',
+            '#ea7ccc',
+          ],
+          data: [
+            [
+              { value: 1048, name: 'Search Engine' },
+              { value: 735, name: 'Direct' },
+              { value: 580, name: 'Email' },
+              { value: 484, name: 'Union Ads' },
+              { value: 300, name: 'Video Ads' },
+            ],
+            [
+              { value: 1548, name: 'Search' },
+              { value: 775, name: 'Direct' },
+              { value: 679, name: 'Market' },
+            ],
+          ],
+          chartsRadius: [
+            ['60%', '70%'],
+            ['0%', '50%'],
+          ],
+        },
+      },
+      {
+        name: '仪表盘',
+        icon: 'l-dashboard-chart',
+        data: {
+          name: 'gauge',
+          x: 600,
+          y: 300,
+          width: 400,
+          height: 400,
+          disableAnchor: true,
+          value: 90,
+          unit: 'm/s',
+          axisLine: [
+            [0.3, '#67e0e3'],
+            [0.7, '#37a2da'],
+            [1, '#fd666d'],
+          ],
+          animateCycle: 1,
+          keepAnimateState: 0,
+        },
+      },
+      {
+        name: '时钟',
+        icon: 'l-07',
+        data: {
+          name: 'gauge',
+          x: 600,
+          y: 300,
+          width: 400,
+          height: 400,
+          disableAnchor: true,
+          isClock: true,
+          startAngle: 90,
+          endAngle: -270,
+          min: 0,
+          max: 12,
+          splitNumber: 12,
+          background: '#3A3A3A',
+          color: '#C0911F',
+        },
+      },
+    ],
+  },
+  {
+    name: '折线图',
+    show: true,
+    list: [
+      {
+        name: '基础折线图',
+        icon: 'l-line-chart',
+        data: {
+          name: 'echarts',
+          width: 366,
+          height: 206,
+          externElement: true,
+          disableAnchor: true,
+          echarts: {
+            option: {
+              grid: {
+                top: 20,
+                bottom: 40,
+                left: 40,
+                right: 20,
+              },
+              xAxis: {
+                type: 'category',
+                data: ['1月', '2月', '3月', '4月', '5月', '6月'],
+              },
+              yAxis: {
+                type: 'value',
+                max: 100,
+                min: 0,
+                interval: 50,
+              },
+              series: [
+                {
+                  type: 'line',
+                  data: [40, 20, 90, 60, 70, 80],
+                },
+              ],
+            },
+            max: 100,
+          },
+          realTimes: [
+            {
+              key: 'echarts.option.series.0.data',
+              label: '数据',
+              type: 'object',
+            },
+            {
+              key: 'echarts.option',
+              label: 'echarts',
+              type: 'object',
+            },
+            {
+              key: 'echarts.max',
+              label: '最大数量',
+              type: 'number',
+            },
+          ],
+        },
+      },
+      {
+        name: '双折线图',
+        icon: 'l-line-chart',
+        data: {
+          name: 'echarts',
+          width: 366,
+          height: 206,
+          externElement: true,
+          disableAnchor: true,
+          echarts: {
+            option: {
+              grid: {
+                top: 20,
+                bottom: 40,
+                left: 40,
+                right: 20,
+              },
+              xAxis: {
+                type: 'category',
+                data: ['1月', '2月', '3月', '4月', '5月', '6月'],
+              },
+              yAxis: {
+                type: 'value',
+                max: 100,
+                min: 0,
+                interval: 50,
+              },
+              series: [
+                {
+                  type: 'line',
+                  data: [40, 35, 80, 40, 45, 25],
+                },
+                {
+                  type: 'line',
+                  data: [25, 40, 20, 30, 25, 40],
+                },
+              ],
+            },
+            max: 100,
+          },
+          realTimes: [
+            {
+              key: 'echarts.option.series.0.data',
+              label: '数据',
+              type: 'object',
+            },
+            {
+              key: 'echarts.option',
+              label: 'echarts',
+              type: 'object',
+            },
+            {
+              key: 'echarts.max',
+              label: '最大数量',
+              type: 'number',
+            },
+          ],
+        },
+      },
+    ],
+  },
+];

+ 5 - 0
src/styles/app.css

@@ -106,6 +106,7 @@ h5 {
 
 .ellipsis {
   text-overflow: ellipsis;
+  overflow: hidden;
 }
 
 a {
@@ -336,6 +337,10 @@ a.hover:hover {
   padding-bottom: 4px;
 }
 
+.pl-8 {
+  padding-left: 8px;
+}
+
 .px-8 {
   padding-left: 8px;
   padding-right: 8px;

+ 9 - 0
src/styles/tdesign.css

@@ -589,3 +589,12 @@
     }
   }
 }
+
+.t-drawer__header {
+  min-height: 40px;
+  font-size: 14px;
+}
+
+.t-image__wrapper {
+  background: none;
+}

+ 2 - 1
src/views/components/ChargeCloudPublish.vue

@@ -72,6 +72,7 @@ const wechatPayDialog = reactive({
 onBeforeMount(async () => {
   const ret: { list: any } = await axios.post('/api/goods/list', {
     type: '云发布',
+    sort: { createdAt: 1 },
   });
   data.vips = ret.list;
 });
@@ -93,7 +94,7 @@ const onSuccess = (success: boolean) => {
 };
 
 const getPayResult = async () => {
-  const result: { state: number } = await axios.post('/order/pay/state', {
+  const result: { state: number } = await axios.post('/api/order/pay/state', {
     id: data.order.id || data.order._id,
   });
   if (result && result.state) {

+ 81 - 2
src/views/components/FileProps.vue

@@ -79,7 +79,7 @@
         </t-space>
         <t-space direction="vertical" size="small" class="mt-8">
           <t-collapse
-            :defaultValue="['1']"
+            :defaultValue="['1', '2']"
             expandIconPlacement="right"
             :borderless="true"
           >
@@ -131,6 +131,55 @@
             </t-collapse-panel>
             <t-collapse-panel value="2" header="进阶设置">
               <t-space direction="vertical" size="small">
+                <div class="form-item">
+                  <label>
+                    图标URL
+                    <span>
+                      <label
+                        class="vip-label"
+                        style="font-size: 10px; padding: 0 2px"
+                      >
+                        VIP
+                      </label>
+                    </span>
+                  </label>
+                  <div class="px-8" style="width: 200px">
+                    <template v-if="data.meta2dData.iconUrls">
+                      <div
+                        v-for="(icon, i) of data.meta2dData.iconUrls"
+                        class="flex middle between"
+                        style="height: 30px"
+                      >
+                        <div>
+                          {{ icon.substring(0, 8) }}...{{ icon.substr(-16) }}
+                        </div>
+                        <t-icon
+                          name="close"
+                          class="hover"
+                          @click="removeIconUrl(i)"
+                        />
+                      </div>
+                    </template>
+                    <div class="flex middle" v-if="user.isVip">
+                      <t-input
+                        v-model="data.iconUrl"
+                        placeholder="Font class方式URL"
+                        style="width: 150px; margin-left: -8px"
+                      />
+                      <t-button
+                        variant="outline"
+                        style="padding: 4px 8px; margin-left: 8px"
+                        @click="addIconUrl"
+                      >
+                        添加
+                      </t-button>
+                    </div>
+                    <div v-else class="desc mt-4">
+                      支持添加iconfont。
+                      <a :href="assets.account" target="_blank">VIP</a> 功能
+                    </div>
+                  </div>
+                </div>
                 <div class="form-item">
                   <label>初始化动作</label>
                   <t-button
@@ -188,20 +237,28 @@
 </template>
 
 <script lang="ts" setup>
-import { onMounted, reactive, onUnmounted, ref } from 'vue';
+import { onMounted, reactive, onUnmounted } from 'vue';
+import { useUser } from '@/services/user';
 import { getCookie } from '@/services/cookie';
 import ElementTree from './ElementTree.vue';
 import CodeEditor from '@/views/components/common/CodeEditor.vue';
+import { autoSave, useAssets } from '@/services/common';
+import { MessagePlugin } from 'tdesign-vue-next';
 
 const headers = {
   Authorization: 'Bearer ' + (localStorage.token || getCookie('token') || ''),
 };
 const updataData = { directory: '/项目' };
 
+const { assets } = useAssets();
+
+const { user } = useUser();
+
 const data = reactive<any>({
   tab: 1,
   background: [],
   meta2dData: {},
+  iconUrl: '',
 });
 
 const screenList = reactive([
@@ -331,6 +388,28 @@ const onOkDataTransformation = () => {
   meta2d.store.data.socketCbJs = dataTransformationDialog.data;
   dataTransformationDialog.show = false;
 };
+
+const addIconUrl = () => {
+  if (!data.iconUrl || data.iconUrl.substr(-4) !== '.css') {
+    MessagePlugin.error('请填写以.css结尾的font-class引用方式的URL地址');
+    return;
+  }
+  if (!data.meta2dData.iconUrls) {
+    data.meta2dData.iconUrls = [];
+  }
+  data.meta2dData.iconUrls.push(data.iconUrl);
+  // @ts-ignore
+  meta2d.store.data.iconUrls = data.meta2dData.iconUrls;
+  data.iconUrl = '';
+  autoSave(true);
+};
+
+const removeIconUrl = (i: number) => {
+  data.meta2dData.iconUrls.splice(i, 1);
+  // @ts-ignore
+  meta2d.store.data.iconUrls = data.meta2dData.iconUrls;
+  autoSave(true);
+};
 </script>
 <style lang="postcss" scoped>
 .props {

+ 194 - 84
src/views/components/Graphics.vue

@@ -77,9 +77,7 @@
                 v-for="elem in item.list"
                 :draggable="true"
                 @dragstart="dragStart($event, elem)"
-                @drag="drag($event, elem)"
-                @dragend="dragEnd()"
-                @click.stop="dragStart($event, elem)"
+                @click.prevent="dragStart($event, elem)"
                 @dblclick.stop="open(elem)"
                 @contextmenu="onContextMenu($event, item, elem)"
               >
@@ -114,8 +112,6 @@
             v-for="elem in subGroups"
             :draggable="true"
             @dragstart="dragStart($event, elem)"
-            @drag="drag($event, elem)"
-            @dragend="dragEnd()"
             @click.stop="dragStart($event, elem)"
             @dblclick.stop="open(elem)"
           >
@@ -149,13 +145,14 @@
       v-if="contextmenu.visible"
       tabindex="0"
       :style="contextmenu.style"
-      @blu1r="contextmenu.visible = false"
+      @blur="contextmenu.visible = false"
     >
       <t-menu class="context-menu" @change="onMenu" expandType="popup">
         <t-submenu
           value="move"
           title="移动到"
           v-if="contextmenu.subMenus.length"
+          :disabled="!contextmenu.component.component"
         >
           <t-menu-item
             v-for="subMenu in contextmenu.subMenus"
@@ -165,7 +162,9 @@
           </t-menu-item>
         </t-submenu>
         <t-menu-item value="edit"> 编辑 </t-menu-item>
-        <t-menu-item value="del"> 删除 </t-menu-item>
+        <t-menu-item value="del" :disabled="!contextmenu.component.component">
+          删除
+        </t-menu-item>
       </t-menu>
     </div>
 
@@ -179,27 +178,66 @@
     >
       确定删除该数据吗?删除后不可恢复!
     </t-dialog>
+    <t-dialog
+      v-if="chargeDialog.show"
+      :header="chargeDialog.data.name"
+      :visible="true"
+      @close="chargeDialog.show = false"
+      width="70%"
+      :top="8"
+    >
+      <t-image :src="chargeDialog.data.image" />
+      <template #footer>
+        <div class="flex between" style="margin-top: -7px">
+          <p>付费项目,购买后查看并使用</p>
+          <div>
+            <label>金额:</label>
+            <label class="bland">¥{{ chargeDialog.data.price }}</label>
+            <t-button class="primary ml-12" @click="onSubmitOrder"
+              >购买</t-button
+            >
+          </div>
+        </div>
+      </template>
+    </t-dialog>
+
+    <t-dialog
+      v-if="wechatPayDialog.show"
+      v-model:visible="wechatPayDialog.show"
+      class="pay-dialog"
+      header="乐吾乐收银台"
+      :close-on-overlay-click="false"
+      :top="95"
+      :width="700"
+      confirm-btn="支付完成"
+      :cancel-btn="null"
+      @close="getPayResult"
+    >
+      <WechatPay
+        :order="wechatPayDialog.order"
+        :code-url="wechatPayDialog.order.codeUrl"
+        @success="onChargeSuccess"
+      />
+    </t-dialog>
   </div>
 </template>
 
 <script lang="ts" setup>
 import { onMounted, onUnmounted, reactive, ref } from 'vue';
 import { useRouter } from 'vue-router';
+import { MessagePlugin } from 'tdesign-vue-next';
 import axios from 'axios';
 
-import { cases, shapes, charts, formComponents } from '@/services/defaults';
+import { cases, shapes, formComponents } from '@/services/defaults';
+import { charts } from '@/services/echarts';
 import { getFolders, getFiles, getIcons } from '@/services/png';
-import {
-  getComponents,
-  getComponentsList,
-  getLe5leV,
-  updateCollection,
-} from '@/services/api';
+import { getComponentsList, getLe5leV, updateCollection } from '@/services/api';
 import { convertPen } from '@/services/upgrade';
 import { deepClone } from '@meta2d/core';
 import { isGif } from '@/services/utils';
 import { autoSave, delAttrs } from '@/services/common';
-import { MessagePlugin } from 'tdesign-vue-next';
+
+import WechatPay from './WechatPay.vue';
 
 const router = useRouter();
 
@@ -258,6 +296,12 @@ const materials = ref([]);
 const pngs = ref([]);
 const icons = ref([]);
 
+let dropped = false;
+const chargeDialog = reactive<any>({});
+const wechatPayDialog = reactive<any>({
+  show: false,
+});
+
 const groupChange = async (name: string) => {
   activedPanel.value = [];
   activedGroup.value = name;
@@ -330,7 +374,7 @@ const getCaseProjects = async (name: string, group?: string) => {
     {
       query,
       shared: 'true',
-      projection: { _id: 1, name: 1, image: 1, price: 1 },
+      projection: { id: 1, _id: 1, name: 1, image: 1, price: 1 },
     }
   );
 
@@ -338,6 +382,9 @@ const getCaseProjects = async (name: string, group?: string) => {
     return [];
   }
   for (const item of ret.list) {
+    if (!item.id) {
+      item.id = item._id;
+    }
     item.draggable = false;
   }
   return ret.list;
@@ -391,74 +438,83 @@ const getPrivateGroups = async () => {
 
 const dragStart = async (event: DragEvent | MouseEvent, item: any) => {
   event.stopPropagation();
-
-  let data = null;
-
-  if (!item || (event instanceof DragEvent && !event.dataTransfer)) {
+  if (!item) {
     return;
   }
 
-  if (!item.draggable) {
-    data = item.data;
+  meta2d.canvas.addCaches = [];
+  dropped = false;
+
+  let data = null;
+  const id = item._id || item.id;
+  let isAsync: boolean;
+  if (item.draggable === false) {
+    // 场景
+    data = item.data || item;
   } else if (item['3d']) {
+    // 3D
     data = {
       name: 'iframe',
       width: 400,
       height: 300,
       externElement: true,
-      iframe: 'https://view3d.le5le.com/?id=' + (item._id || item.id),
+      iframe: 'https://view3d.le5le.com/?id=' + id,
     };
-  } else {
-    if (item._id && !item.componentDatas) {
-      let res: any = await getComponents(item._id);
-      item.component = true;
-      item.componentDatas = res.componentDatas;
-      item.componentData = res.componentData;
+  } else if (item.component) {
+    // 我的组件
+    if (!item.componentDatas && !item.componentData) {
+      isAsync = true;
+      const ret: any = await axios.post(`/api/data/le5leV-components/get`, {
+        id,
+      });
+      item.componentDatas = ret.componentDatas;
+      item.componentData = ret.componentData;
     }
-    if (!item.data && !item.component && item.image) {
-      let target: any = event.target;
-      target.children[0] && (target = target.children[0].children[0]);
-      // firefox naturalWidth svg 图片 可能是 0
-      const normalWidth = target.naturalWidth || target.width;
-      const normalHeight = target.naturalHeight || target.height;
-      const [name, lockedOnCombine] = isGif(item.image)
-        ? ['gif', 0]
-        : ['image', undefined];
-
-      data = {
-        name,
-        width: 100,
-        height: 100 * (normalHeight / normalWidth),
-        image: item.image,
-        imageRatio: true,
-        lockedOnCombine,
-      };
-    } else if (item.component) {
-      if (item.componentData) {
-        const pens = convertPen([item.componentData]);
-        data = deepClone(pens);
-      } else if (item.componentDatas) {
-        data = deepClone(item.componentDatas);
-      }
-    } else {
-      data = item.componentDatas || item.data;
+    if (item.componentData) {
+      const pens = convertPen([item.componentData]);
+      data = deepClone(pens);
+    } else if (item.componentDatas) {
+      data = deepClone(item.componentDatas);
     }
-  }
+  } else if (item.data) {
+    // 普通图元
+    data = item.data;
+  } else if (item.image) {
+    // 拖拽图片
+    let target: any = event.target;
+    target.children[0] && (target = target.children[0].children[0]);
+    // firefox naturalWidth svg 图片 可能是 0
+    const normalWidth = target.naturalWidth || target.width;
+    const normalHeight = target.naturalHeight || target.height;
+    const [name, lockedOnCombine] = isGif(item.image)
+      ? ['gif', 0]
+      : ['image', undefined];
 
-  if (event instanceof DragEvent) {
-    meta2d.canvas.addCaches = [];
-    event.dataTransfer?.setData('Meta2d', JSON.stringify(data));
+    data = {
+      name,
+      width: 100,
+      height: 100 * (normalHeight / normalWidth),
+      image: item.image,
+      imageRatio: true,
+      lockedOnCombine,
+    };
   } else {
-    if (!Array.isArray(data)) {
-      data = deepClone([data]);
-    }
-    meta2d.canvas.addCaches = data;
+    return;
   }
-};
 
-const drag = (event: DragEvent, item: any) => {};
+  if (!Array.isArray(data)) {
+    data = deepClone([data]);
+  }
+
+  !dropped && (meta2d.canvas.addCaches = data);
 
-const dragEnd = () => {};
+  if (event instanceof DragEvent) {
+    event.dataTransfer.setData(
+      'Meta2d',
+      isAsync ? undefined : JSON.stringify(data)
+    );
+  }
+};
 
 const dragstart = (event: any) => {
   event.target.style.opacity = 0.5;
@@ -469,9 +525,19 @@ const dragend = (event: any) => {
 };
 
 const open = async (item: any) => {
-  if (item.draggable !== false) {
+  if (!item || item.draggable !== false) {
     return;
   }
+
+  const ret: any = await getLe5leV(item._id || item.id);
+  if (!ret) {
+    if (item.price > 0) {
+      chargeDialog.data = item;
+      chargeDialog.show = true;
+    }
+    return;
+  }
+
   router.push({
     path: '/',
     query: {
@@ -479,12 +545,12 @@ const open = async (item: any) => {
     },
   });
 
-  const ret: any = await getLe5leV(item._id || item.id);
   for (const k of delAttrs) {
-    delete (ret as any)[k];
+    delete ret[k];
   }
+
+  autoSave();
   meta2d.open(ret);
-  autoSave(true);
 };
 
 const onChangeGroupPanel = async (val: string[]) => {
@@ -666,7 +732,7 @@ const onContextMenu = async (e: MouseEvent, group: string, item: any) => {
   e.preventDefault();
   e.stopPropagation();
 
-  if (activedGroup.value !== '我的' || !item.component) {
+  if (activedGroup.value !== '我的') {
     return;
   }
 
@@ -707,15 +773,23 @@ const onMenu = async (val: string) => {
 
   switch (val) {
     case 'edit':
-      autoSave();
-      router.push({
-        path: '/',
-        query: {
-          id,
-          c: 1,
-          r: Date.now() + '',
-        },
-      });
+      if (contextmenu.component.component) {
+        autoSave();
+        router.push({
+          path: '/',
+          query: {
+            id,
+            c: 1,
+            r: Date.now() + '',
+          },
+        });
+      } else {
+        let url = 'https://3d.le5le.com/?id=';
+        if (import.meta.env.VITE_TRIAL == 0 && (window as any).url3D) {
+          url = (window as any).url3D;
+        }
+        window.open(url + id, '_blank');
+      }
 
       break;
     case 'del':
@@ -796,13 +870,49 @@ const delComponet = async () => {
   delDialog.show = false;
 };
 
+const drop = (obj: any) => {
+  dropped = true;
+
+  if (obj) {
+    Array.isArray(obj) && open(obj[0]);
+  } else {
+    MessagePlugin.warning('正在请求网络数据中,请稍后重试');
+  }
+};
+
+const onSubmitOrder = async () => {
+  const result: any = await axios.post('/api/order/datas/submit', {
+    collection: 'le5leV',
+    id: chargeDialog.data._id,
+  });
+  if (result) {
+    wechatPayDialog.order = result;
+    wechatPayDialog.show = true;
+  }
+};
+
+const getPayResult = async () => {
+  const result: { state: number } = await axios.post('/api/order/pay/state', {
+    id: wechatPayDialog.order.id || wechatPayDialog.order._id,
+  });
+  if (result && result.state) {
+    return true;
+  }
+};
+
+const onChargeSuccess = () => {
+  MessagePlugin.success('支付成功!');
+  wechatPayDialog.show = false;
+  chargeDialog.show = false;
+};
+
 onMounted(() => {
   groupChange('场景');
   document.addEventListener('dragstart', dragstart, false);
   document.addEventListener('dragend', dragend, false);
 
   setTimeout(() => {
-    meta2d.on('drop', open);
+    meta2d.on('drop', drop);
   }, 2000);
 });
 
@@ -810,7 +920,7 @@ onUnmounted(() => {
   document.removeEventListener('dragstart', dragstart);
   document.removeEventListener('dragend', dragend);
 
-  meta2d.off('drop', open);
+  meta2d.off('drop', drop);
 });
 </script>
 <style lang="postcss" scoped>
@@ -830,7 +940,7 @@ onUnmounted(() => {
     flex-grow: 1;
     overflow-y: auto;
     font-size: 12px;
-    z-index: 100;
+    z-index: 7;
 
     .groups {
       & > div {

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

@@ -309,6 +309,7 @@ import {
   magnifier,
   useDot,
   delAttrs,
+  useAssets,
 } from '@/services/common';
 
 const router = useRouter();
@@ -316,38 +317,7 @@ const route = useRoute();
 
 const baseUrl = import.meta.env.BASE_URL || '/';
 
-const assets = reactive({
-  home: 'https://le5le.com',
-  account: 'https://account.le5le.com',
-  helps: [
-    {
-      name: '产品介绍',
-      url: 'https://doc.le5le.com/document/118756411',
-    },
-    {
-      name: '快速上手',
-      url: 'https://doc.le5le.com/document/119363000',
-    },
-    {
-      name: '使用手册',
-      url: 'https://doc.le5le.com/document/118764244',
-    },
-    {
-      name: '快捷键',
-      url: 'https://doc.le5le.com/document/119620214',
-      divider: true,
-    },
-    {
-      name: '企业服务与支持',
-      url: 'https://doc.le5le.com/document/119296274',
-      divider: true,
-    },
-    {
-      name: '关于我们',
-      url: 'https://le5le.com/about.html',
-    },
-  ],
-});
+const { assets, getAssets } = useAssets();
 
 const { user, signout } = useUser();
 const { setDot } = useDot();
@@ -356,24 +326,12 @@ const data = reactive({
 });
 
 onBeforeMount(async () => {
-  // 官网或安装包版本
-  if (
-    import.meta.env.VITE_TRIAL == undefined ||
-    import.meta.env.VITE_TRIAL == 1
-  ) {
-    return;
-  }
-
-  // 企业版
-  const ret = await axios.get('/api/assets');
-  if (ret) {
-    Object.assign(assets, ret);
-  }
+  getAssets();
 });
 
 const onInputName = () => {
   (meta2d.store.data as Meta2dBackData).name = data.name;
-  setDot(true);
+  setDot();
 };
 
 const initMeta2dName = () => {

+ 19 - 7
src/views/components/Network.vue

@@ -123,7 +123,7 @@
 
 <script lang="ts" setup>
 import { onBeforeMount, ref } from 'vue';
-
+import axios from 'axios';
 import { debounce } from '@/services/debouce';
 
 const { modelValue, mode } = defineProps<{
@@ -167,12 +167,19 @@ const httpMethodChange = (method: string) => {
   }
 };
 
-const onSave = () => {
+const onSave = async () => {
   emit('update:modelValue', modelValue);
   emit('change', modelValue);
 
+  const id = modelValue._id || modelValue.id;
+
   // 保存到我的数据源
-  // todo
+  if (id) {
+    modelValue._id = id;
+    await axios.post(`/api/data/datasources/update`, modelValue);
+  } else {
+    await axios.post(`/api/data/datasources/add`, modelValue);
+  }
 };
 
 const onInput = (text: string) => {
@@ -181,10 +188,15 @@ const onInput = (text: string) => {
 
 // 请求我的数据源接口
 const getNetworks = async () => {
-  // const ret: any = await axios.get(`/api/xxx`);
-  // if (ret) {
-  //   dataDialog.networkList = ret.list
-  // }
+  const ret: any = await axios.post(`/api/data/datasources/list`, {
+    q: {
+      name: modelValue.name,
+    },
+    projection: { updatedAt: 0 },
+  });
+  if (ret) {
+    networkList.value = ret.list;
+  }
 };
 
 const onSelect = (item: any) => {

+ 65 - 9
src/views/components/PenProps.vue

@@ -48,7 +48,7 @@
               v-model.number="data.rect.x"
               style="width: 80px"
               :format="decimalPlaces"
-              @change="changeValue('x')"
+              @change="changeRectValue('x')"
             />
             <t-icon name="link" class="hidden ml-4" />
             <t-input
@@ -58,7 +58,7 @@
               v-model.number="data.rect.y"
               style="width: 80px"
               :format="decimalPlaces"
-              @change="changeValue('y')"
+              @change="changeRectValue('y')"
             />
             <t-input
               class="ml-16"
@@ -84,7 +84,7 @@
               min="1"
               style="width: 80px"
               :format="decimalPlaces"
-              @change="changeValue('width')"
+              @change="changeRectValue('width')"
             />
             <t-tooltip v-if="data.pen.ratio" content="固定比例" placement="top">
               <t-icon
@@ -109,7 +109,7 @@
               min="1"
               style="width: 80px"
               :format="decimalPlaces"
-              @change="changeValue('height')"
+              @change="changeRectValue('height')"
             />
 
             <t-input
@@ -270,7 +270,7 @@
                     theme="normal"
                     placeholder="线条宽度"
                     v-model="data.pen.lineWidth"
-                    :min="1"
+                    :min="0"
                     :decimalPlaces="0"
                     @change="changeValue('lineWidth')"
                     class="ml-4"
@@ -817,8 +817,36 @@
               </t-space>
             </t-collapse-panel>
             <t-collapse-panel
-              v-if="data.pen.props.custom"
+              v-if="data.pen.props.icon"
               value="4"
+              header="图标"
+            >
+              <t-space direction="vertical" size="small" class="w-full">
+                <div class="form-item">
+                  <label style="width: 32px">图标 </label>
+                  <i
+                    class="ml-8"
+                    :class="data.pen.iconFamily"
+                    style="line-height: 30px; height: 30px; color: var(--color)"
+                  >
+                    {{ data.pen.icon }}
+                  </i>
+                  <a class="ml-12 mt-4" @click="iconsDrawer.show = true">
+                    选择
+                  </a>
+                  <t-drawer
+                    v-model:visible="iconsDrawer.show"
+                    header="选择图标"
+                    :footer="null"
+                  >
+                    <Iconfonts :urls="data.iconUrls" @change="onChangeIcon" />
+                  </t-drawer>
+                </div>
+              </t-space>
+            </t-collapse-panel>
+            <t-collapse-panel
+              v-if="data.pen.props.custom"
+              value="5"
               header="属性"
             >
               <t-space direction="vertical" size="small" class="w-full">
@@ -981,14 +1009,15 @@
 <script lang="ts" setup>
 import { onBeforeMount, onUnmounted, reactive, ref, watch } from 'vue';
 
-import CodeEditor from '@/views/components/common/CodeEditor.vue';
+import CodeEditor from './common/CodeEditor.vue';
+import Iconfonts from './common/Iconfonts.vue';
 import PenAnimates from './PenAnimates.vue';
 import PenDatas from './PenDatas.vue';
 import PenEvents from './PenEvents.vue';
 
 import { getCookie } from '@/services/cookie';
 import { useSelection } from '@/services/selections';
-import { fonts } from '@/services/common';
+import { autoSave, fonts } from '@/services/common';
 import { updatePen } from './pen';
 
 const headers = {
@@ -1010,11 +1039,16 @@ const tooltipDialog = reactive<any>({
   show: false,
 });
 
+const iconsDrawer = reactive<any>({
+  show: false,
+});
+
 onBeforeMount(() => {
   const d = meta2d.store.data as any;
   if (!d.groups) {
     d.groups = [];
   }
+  data.iconUrls = d.iconUrls;
   data.groups = d.groups;
   initPenData();
 
@@ -1040,10 +1074,16 @@ function initPenData() {
     }
   }
   if (!data.pen.props.image) {
-    if (data.pen.image || data.pen.name === 'image') {
+    if (data.pen.image) {
       data.pen.props.image = true;
     }
   }
+  if (!data.pen.props.icon) {
+    if (data.pen.icon) {
+      data.pen.props.icon = true;
+    }
+  }
+
   if (data.pen.image) {
     data.images = [
       {
@@ -1086,6 +1126,12 @@ const changeValue = (prop: string) => {
   updatePen(data.pen, prop);
 };
 
+const changeRectValue = (prop: string) => {
+  data.rect.id = data.pen.id;
+  data.rect.ratio = data.pen.ratio;
+  updatePen(data.rect, prop);
+};
+
 const onFontPopupVisible = (val: boolean) => {
   data.fontFamilyPopupVisible = val;
 };
@@ -1160,6 +1206,16 @@ const onOkTooltip = () => {
   tooltipDialog.show = false;
 };
 
+const onChangeIcon = (params: any) => {
+  Object.assign(data.pen, params);
+  meta2d.setValue({
+    id: data.pen.id,
+    icon: params.icon,
+    iconFamily: params.iconFamily,
+  });
+  autoSave(true);
+};
+
 onUnmounted(() => {
   watcher();
   meta2d.off('translatePens', getRect);

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

@@ -865,7 +865,7 @@ const openedListener = () => {
 };
 
 const patchFlag = () => {
-  setDot(true);
+  setDot();
 };
 
 onUnmounted(() => {

+ 92 - 0
src/views/components/common/Iconfonts.vue

@@ -0,0 +1,92 @@
+<template>
+  <ul class="icons">
+    <li v-for="item in icons" :key="item.icon" class="icon">
+      <i :class="item.iconFamily" @click="onSelected(item)">
+        {{ item.icon }}
+      </i>
+    </li>
+  </ul>
+</template>
+<script lang="ts" setup>
+import { onMounted, reactive } from 'vue';
+
+const { urls } = defineProps<{
+  urls: string[];
+}>();
+
+const emit = defineEmits(['change']);
+
+const icons = reactive([]);
+
+onMounted(() => {
+  urls.forEach(async (url) => {
+    const iconList: any = await addIcons(url.replace('.css', '.json'));
+    icons.push(...iconList.list);
+  });
+});
+
+const onSelected = (item: any) => {
+  emit('change', item);
+};
+
+const addIcons = (url: string) => {
+  return new Promise((resolve, reject) => {
+    const xhr = new XMLHttpRequest();
+    xhr.open('GET', url, true);
+    xhr.send();
+    xhr.onreadystatechange = () => {
+      if (xhr.readyState === 4 && xhr.status === 200) {
+        try {
+          const iconfont = JSON.parse(xhr.responseText);
+          const iconGroup = {
+            name: iconfont.name,
+            loaded: true,
+            show: true,
+            list: [],
+          };
+
+          iconfont.glyphs.forEach((item: any) => {
+            iconGroup.list.push({
+              iconFamily: iconfont.font_family,
+              icon: String.fromCharCode(item.unicode_decimal),
+            });
+          });
+          resolve(iconGroup);
+        } catch (error) {
+          reject(error);
+        }
+      }
+    };
+  });
+};
+</script>
+<style lang="postcss" scoped>
+.icons {
+  display: grid;
+  grid-template-columns: 1fr 1fr 1fr 1fr;
+  gap: 12px;
+  padding-left: 6px;
+
+  .icon {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 50px;
+    height: 50px;
+    border: 1px solid transparent;
+    border-radius: 2px;
+    cursor: pointer;
+
+    &:hover {
+      border-color: var(--color-primary);
+    }
+
+    i {
+      width: 21px;
+      height: 21px;
+      font-size: 20px;
+      color: var(--color);
+    }
+  }
+}
+</style>

+ 8 - 10
src/views/components/pen.ts

@@ -1,16 +1,14 @@
 export const updatePen = (pen: any, prop: string, render = true) => {
   const v: any = { id: pen.id };
-  const rect: any = meta2d.getPenRect(pen);
-
   v[prop] = pen[prop];
-  if (prop === 'x') {
-    v.x = rect.x;
-  } else if (prop === 'y') {
-    v.y = rect.y;
-  } else if (prop === 'width') {
-    v.height = (rect.width / pen.width) * pen.height;
-  } else if (prop === 'height') {
-    v.width = (rect.height / pen.height) * pen.width;
+  if (prop === 'width' && pen.ratio) {
+    const rect = meta2d.findOne(pen.id);
+    v.height = (pen.width / rect.width) * rect.height;
+    pen.height = v.height;
+  } else if (prop === 'height' && pen.ratio) {
+    const rect = meta2d.findOne(pen.id);
+    v.width = (pen.height / rect.height) * rect.width;
+    pen.width = v.width;
   } else if (prop === 'shadow') {
     if (v[prop]) {
       !v.shadowOffsetX && (v.shadowOffsetX = 0);

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.