Sfoglia il codice sorgente

feat: 完成柱状图、折线图、饼图调试

liaojiaxing 10 mesi fa
parent
commit
0de707cef1

+ 30 - 21
components/charts/Bar/BasicBar/src/Config.vue

@@ -39,13 +39,13 @@ import DataConfig from "../../../DataConfig.vue";
 import { CusForm, IFormItem } from "../../../../cusForm";
 import { basicBarProps } from "./props";
 import { chartFormItemsMap } from "../../../config/chartFormItemsMap";
-import { set, cloneDeep } from 'lodash-es';
+import { set, cloneDeep } from "lodash-es";
 
 const props = defineProps(basicBarProps);
 const activeTab = ref("1");
 const emit = defineEmits(["change"]);
 
-const barSeries: IFormItem[] = [
+const baseSeries: IFormItem[] = [
   {
     label: "样式",
     prop: "",
@@ -53,7 +53,7 @@ const barSeries: IFormItem[] = [
   },
   {
     label: "固定柱宽",
-    prop: "series.fixedBarWidth",
+    prop: "series.bar.fixedBarWidth",
     type: "radioGroup",
     fieldProps: {
       options: [
@@ -63,25 +63,23 @@ const barSeries: IFormItem[] = [
     },
     defaultValue: false,
     format: (formatModel, value) => {
-      formatModel.value["series.barWidth"] = value
-        ? formatModel.value?.["series.barWidth"] || 20
-        : "auto";
+      formatModel.value["series.bar.barWidth"] =
+        value && formatModel.value?.["series.bar.barWidth"] !== "auto"
+          ? formatModel.value?.["series.bar.barWidth"] || 20
+          : "auto";
     },
-    valueToForm: (value) => {
-      return value !== 'auto'
-    }
   },
   {
     label: "",
     prop: "",
     type: "dependency",
-    name: ["series.fixedBarWidth"],
+    name: ["series.bar.fixedBarWidth"],
     children: (model) => {
-      return model["series.fixedBarWidth"]
+      return model["series.bar.fixedBarWidth"]
         ? [
             {
               label: "柱宽",
-              prop: "series.barWidth",
+              prop: "series.bar.barWidth",
               type: "inputNumber",
               fieldProps: {
                 addonAfter: "px",
@@ -94,15 +92,27 @@ const barSeries: IFormItem[] = [
   },
   {
     label: "系列间隔",
-    prop: "series.barGap",
+    prop: "series.bar.barGap",
     type: "slider",
-    defaultValue: 20,
+    defaultValue: 30,
+    format: (formatFormatModel, value) => {
+      formatFormatModel.value['series.bar.barGap'] = value + "%";
+    },
+    valueToForm: (value) => {
+      return +(value?.replace("%", "") || 0);
+    },
   },
   {
     label: "分类间隔",
-    prop: "series.barCategoryGap",
+    prop: "series.bar.barCategoryGap",
     type: "slider",
     defaultValue: 20,
+    format: (formatFormatModel, value) => {
+      formatFormatModel.value['series.bar.barCategoryGap'] = value + "%";
+    },
+    valueToForm: (value) => {
+      return +(value?.replace("%", "") || 0);
+    },
   },
   {
     label: "边框",
@@ -111,7 +121,7 @@ const barSeries: IFormItem[] = [
   },
   {
     label: "线宽",
-    prop: "series.itemStyle.borderWidth",
+    prop: "series.bar.itemStyle.borderWidth",
     type: "inputNumber",
     fieldProps: {
       addonAfter: "px",
@@ -120,13 +130,13 @@ const barSeries: IFormItem[] = [
   },
   {
     label: "颜色",
-    prop: "series.itemStyle.borderColor",
+    prop: "series.bar.itemStyle.borderColor",
     type: "colorSelect",
     defaultValue: "#ccc",
   },
   {
     label: "圆角",
-    prop: "series.itemStyle.borderRadius",
+    prop: "series.bar.itemStyle.borderRadius",
     type: "inputNumber",
     fieldProps: {
       addonAfter: "px",
@@ -137,11 +147,11 @@ const barSeries: IFormItem[] = [
 const formItems: IFormItem[] = [
   chartFormItemsMap.title,
   chartFormItemsMap.legend,
-  // chartFormItemsMap.label,
+  chartFormItemsMap.label,
   {
     ...chartFormItemsMap.series,
     children: (chartFormItemsMap.series.children as IFormItem[]).concat(
-      barSeries
+      baseSeries
     ),
   },
   chartFormItemsMap.xAxis,
@@ -160,7 +170,6 @@ const handleFormChange = (formatData: any) => {
   Object.keys(formatData).forEach((key) => {
     set(obj, key, formatData[key]);
   });
-  console.log("obj:", obj, props, formatData);
   emit("change", obj);
 };
 </script>

+ 15 - 0
components/charts/Bar/BasicBar/src/props.ts

@@ -51,6 +51,20 @@ export const basicBarProps = {
   }
 };
 
+/* 系列相关 */
+const series: EChartsOption['series'] = [];
+series['bar'] = {
+  fixedBarWidth: false,
+  barWidth: 'auto',
+  barGap: '30%',
+  barCategoryGap: '20%',
+  itemStyle: {
+    borderColor: '#ccc',
+    borderRadius: 0,
+    borderWidth: 0,
+  }
+};
+
 const chartOptions = getNormalizedChart({
   title: {
     text: "柱状图标题",
@@ -58,6 +72,7 @@ const chartOptions = getNormalizedChart({
   xAxis: {
     data: ['轴标签A', '轴标签B', '轴标签C', '轴标签D']
   },
+  series
 })
 
 export const defaultPropsValue: EChartsOption = {

+ 142 - 18
components/charts/Line/BasicLine/src/Config.vue

@@ -17,38 +17,162 @@
       </Tabs>
     </div>
 
-    <DataConfig v-if="activeTab === '1'" :dataSource="dataSource" @change="handleChange"/>
-    <CusForm v-if="activeTab === '2'" :columns="formItems"/>
+    <DataConfig
+      v-if="activeTab === '1'"
+      :dataSource="dataSource"
+      @change="handleChange"
+    />
+    <CusForm
+      v-if="activeTab === '2'"
+      :columns="formItems"
+      :formModel="props"
+      @change="handleFormChange"
+    />
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, defineProps, defineEmits } from 'vue';
-import { Tabs, TabPane } from 'ant-design-vue';
-import { DatabaseOutlined, SkinOutlined } from '@ant-design/icons-vue';
-import DataConfig from '../../../DataConfig.vue';
-import { CusForm } from '../../../../cusForm';
-import { basicLineProps } from './props';
-import { chartFormItemsMap } from '../../../config/chartFormItemsMap';
+import type { IFormItem } from "../../../../cusForm";
+import { ref, defineProps, defineEmits } from "vue";
+import { Tabs, TabPane } from "ant-design-vue";
+import { DatabaseOutlined, SkinOutlined } from "@ant-design/icons-vue";
+import DataConfig from "../../../DataConfig.vue";
+import { CusForm } from "../../../../cusForm";
+import { basicLineProps } from "./props";
+import { chartFormItemsMap } from "../../../config/chartFormItemsMap";
+import { set, cloneDeep, get } from "lodash-es";
 
 const props = defineProps(basicLineProps);
-const activeTab = ref('1');
-const emit = defineEmits(['change']);
+const activeTab = ref("1");
+const emit = defineEmits(["change"]);
+
+const baseSeries: IFormItem[] = [
+  {
+    label: "线",
+    prop: "",
+    type: "divider",
+  },
+  {
+    label: "线条样式",
+    prop: "series.line.lineStyle.type",
+    type: "select",
+    fieldProps: {
+      options: [
+        { label: "实线", value: "solid" },
+        { label: "虚线", value: "dashed" },
+        { label: "点线", value: "dotted" },
+      ],
+    },
+  },
+  {
+    label: "线宽",
+    prop: "series.line.lineStyle.width",
+    type: "inputNumber",
+    fieldProps: {
+      min: 0,
+      addonAfter: "px",
+    },
+  },
+  {
+    label: "形态",
+    prop: "series.line.lineType",
+    type: "radioGroupButton",
+    fieldProps: {
+      options: [
+        { label: "普通", value: "normal" },
+        { label: "平滑", value: "smooth" },
+        { label: "阶梯", value: "step" },
+      ],
+    },
+    format: (formatModel, value) => {
+      switch(value) {
+        case 'smooth':
+          formatModel.value["series.line.smooth"] = true;
+          formatModel.value["series.line.step"] = false;
+          break;
+        case 'step':
+          formatModel.value["series.line.smooth"] = false;
+          formatModel.value["series.line.step"] = 'end';
+          break;
+        default:
+          formatModel.value["series.line.smooth"] = false;
+          formatModel.value["series.line.step"] = false;
+      }
+    },
+    valueToForm: (_, model) => {
+      const step = get(model, 'series.line.step');
+      const smooth = get(model, 'series.line.smooth');
+      return step ? 'step' : smooth ? 'smooth' : 'normal';
+    },
+  },
+  {
+    label: "标记点",
+    prop: "",
+    type: "divider",
+  },
+  {
+    label: "图形",
+    prop: "series.line.symbol",
+    type: "select",
+    fieldProps: {
+      options: [
+        { label: "圆", value: "circle" },
+        { label: "方", value: "rect" },
+        { label: "三角", value: "triangle" },
+        { label: "菱形", value: "diamond" },
+        { label: "标记", value: "pin" },
+        { label: "箭头", value: "arrow" },
+        { label: "无", value: "none" },
+      ],
+    },
+  },
+  {
+    label: "大小",
+    prop: "series.line.symbolSize",
+    type: "inputNumber",
+    fieldProps: {
+      min: 0,
+      addonAfter: "px",
+    },
+  },
+  {
+    label: "旋转",
+    prop: "series.line.symbolRotate",
+    type: "inputNumber",
+    fieldProps: {
+      min: 0,
+      addonAfter: "°",
+    },
+  }
+];
+
 const formItems = [
   chartFormItemsMap.title,
   chartFormItemsMap.legend,
-  // chartFormItemsMap.label,
-  chartFormItemsMap.series,
+  chartFormItemsMap.label,
+  {
+    ...chartFormItemsMap.series,
+    children: (chartFormItemsMap.series.children as IFormItem[]).concat(
+      baseSeries
+    ),
+  },
   chartFormItemsMap.tooltip,
-  chartFormItemsMap.background
-]
+  chartFormItemsMap.background,
+];
 
 const handleChange = (data: any) => {
-  emit('change', {
+  emit("change", {
     ...props,
     dataSource: data,
   });
-}
+};
+const handleFormChange = (formatData: any) => {
+  const obj = cloneDeep(props);
+  Object.keys(formatData).forEach((key) => {
+    set(obj, key, formatData[key]);
+  });
+  emit("change", obj);
+};
 </script>
 
 <style lang="less" scoped>
@@ -56,4 +180,4 @@ const handleChange = (data: any) => {
   text-align: center;
   margin-bottom: 12px;
 }
-</style>
+</style>

+ 15 - 0
components/charts/Line/BasicLine/src/props.ts

@@ -52,6 +52,20 @@ export const basicLineProps = {
   },
 };
 
+/* 系列相关 */
+const series: EChartsOption['series'] = [];
+series['line'] = {
+  lineStyle: {
+    type: "solid",
+    width: 1
+  },
+  symbol: "rect",
+  symbolSize: 4,
+  symbolRotate: 0,
+  smooth: false,
+  step: false,
+};
+
 const chartOptions = getNormalizedChart({
   title: {
     text: "折线图标题",
@@ -59,6 +73,7 @@ const chartOptions = getNormalizedChart({
   xAxis: {
     data: ['轴标签A', '轴标签B', '轴标签C', '轴标签D']
   },
+  series
 });
 
 export const defaultPropsValue: EChartsOption = {

+ 82 - 24
components/charts/Pie/BasicPie/src/Config.vue

@@ -17,45 +17,103 @@
       </Tabs>
     </div>
 
-    <DataConfig v-if="activeTab === '1'" :dataSource="dataSource" @change="handleDataSourceChange"/>
-    <CusForm v-if="activeTab === '2'" :columns="formItems" @change="handleFormChange"/>
+    <DataConfig
+      v-if="activeTab === '1'"
+      :dataSource="dataSource"
+      @change="handleDataSourceChange"
+    />
+    <CusForm
+      v-if="activeTab === '2'"
+      :columns="formItems"
+      :formModel="props"
+      @change="handleFormChange"
+    />
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, defineProps, defineEmits } from 'vue';
-import { Tabs, TabPane } from 'ant-design-vue';
-import { DatabaseOutlined, SkinOutlined } from '@ant-design/icons-vue';
-import DataConfig from '../../../DataConfig.vue';
-import { CusForm, IFormItem } from '../../../../cusForm';
-import { basicPieProps } from './props';
-import { chartFormItemsMap } from '../../../config/chartFormItemsMap';
+import { ref, defineProps, defineEmits } from "vue";
+import { Tabs, TabPane } from "ant-design-vue";
+import { DatabaseOutlined, SkinOutlined } from "@ant-design/icons-vue";
+import DataConfig from "../../../DataConfig.vue";
+import { CusForm, IFormItem } from "../../../../cusForm";
+import { basicPieProps } from "./props";
+import { chartFormItemsMap } from "../../../config/chartFormItemsMap";
+import { set, cloneDeep, get } from "lodash-es";
 
 const props = defineProps(basicPieProps);
-const activeTab = ref('1');
-const emit = defineEmits(['change']);
+const activeTab = ref("1");
+const emit = defineEmits(["change"]);
+
+const baseSeries: IFormItem[] = [
+  {
+    label: "样式",
+    prop: "",
+    type: "divider",
+  },
+  {
+    label: "起始角度",
+    prop: "series.pie.startAngle",
+    type: "inputNumber",
+    fieldProps: {
+      min: 0,
+      max: 360,
+      addonAfter: "°",
+    },
+  },
+  {
+    label: "完结角度",
+    prop: "series.pie.endAngle",
+    type: "inputNumber",
+    fieldProps: {
+      min: 0,
+      max: 360,
+      addonAfter: "°",
+    },
+  },
+  {
+    label: "内径占比",
+    prop: "series.pie.radius",
+    type: "slider",
+    format: (formatModel, value) => {
+      console.log("formatModel", formatModel);
+      const inner = value * 0.75;
+      formatModel.value["series.pie.radius"] = [inner + "%", "75%"];
+      return value * 100;
+    },
+    valueToForm: (value) => {
+      const inner = (value || ["0%", "75%"])[0].replace("%", "");
+      return inner / 0.75;
+    },
+  },
+];
+
 const formItems = [
   chartFormItemsMap.title,
   chartFormItemsMap.legend,
-  chartFormItemsMap.xAxis,
-  chartFormItemsMap.yAxis,
+  chartFormItemsMap.label,
+  {
+    ...chartFormItemsMap.series,
+    children: (chartFormItemsMap.series.children as IFormItem[]).concat(
+      baseSeries
+    ),
+  },
   chartFormItemsMap.tooltip,
-  chartFormItemsMap.background
-]
+];
 
 const handleDataSourceChange = (data: any) => {
-  emit('change', {
+  emit("change", {
     ...props,
     dataSource: data,
   });
-}
-const handleFormChange = (data: any) => {
-  console.log('form change:', data);
-  emit('change', {
-    ...props,
-    ...data
+};
+const handleFormChange = (formatData: any) => {
+  const obj = cloneDeep(props);
+  Object.keys(formatData).forEach((key) => {
+    set(obj, key, formatData[key]);
   });
-}
+  emit("change", obj);
+};
 </script>
 
 <style lang="less" scoped>
@@ -63,4 +121,4 @@ const handleFormChange = (data: any) => {
   text-align: center;
   margin-bottom: 12px;
 }
-</style>
+</style>

+ 12 - 2
components/charts/Pie/BasicPie/src/props.ts

@@ -43,19 +43,29 @@ export const basicPieProps = {
   }
 };
 
+/* 系列相关 */
+const series: EChartsOption['series'] = [];
+series['pie'] = {
+  top: 70,
+  startAngle: 0,
+  endAngle: 360,
+  radius: ['0%', '75%'],
+};
+
 const chartOptions = getNormalizedChart({
   title: {
     text: "饼图标题",
   },
   grid: {
-    show: false
+    show: false,
   },
   xAxis: {
     show: false
   },
   yAxis: {
     show: false
-  }
+  },
+  series
 })
 
 export const defaultPropsValue: EChartsOption = {

+ 164 - 45
components/charts/config/chartFormItemsMap.ts

@@ -160,6 +160,47 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
                     type: "round",
                   },
                   defaultValue: "top",
+                  format: (formatModel, value) => {
+                    if(['left', 'right'].includes(value)) {
+                      formatModel.value["legend.orient"] = 'vertical';
+                    } else {
+                      formatModel.value["legend.orient"] = 'horizontal';
+                    }
+                    switch(value) {
+                      case 'bottom':
+                        formatModel.value["legend.top"] = 'auto';
+                        formatModel.value["legend.right"] = 'auto';
+                        formatModel.value["legend.bottom"] = 8;
+                        formatModel.value["legend.left"] = 'center';
+                        break;
+                      case 'left':
+                        formatModel.value["legend.bottom"] = 'auto';
+                        formatModel.value["legend.right"] = 'auto';
+                        formatModel.value["legend.left"] = 8;
+                        formatModel.value["legend.top"] = 'center';
+                        break;
+                      case 'right':
+                        formatModel.value["legend.bottom"] = 'auto';
+                        formatModel.value["legend.left"] = 'auto';
+                        formatModel.value["legend.right"] = 8;
+                        formatModel.value["legend.top"] = 'center';
+                        break;
+                      default:
+                        formatModel.value["legend.bottom"] = 'auto';
+                        formatModel.value["legend.right"] = 'auto';
+                        formatModel.value["legend.top"] = 32;
+                        formatModel.value["legend.left"] = 'center';
+                    }
+                  },
+                  valueToForm: (value, model) => {
+                    if(get(model, 'legend.orient') === 'vertical') {
+                      return value === 'top' ? 'top' : value === 'bottom' ? 'bottom' : 'left';
+                    }
+                    if(get(model, 'legend.bottom') === 8 && get(model, 'legend.left') === 'center') {
+                      return 'bottom';
+                    }
+                    return 'top';
+                  },
                 },
                 {
                   label: "样式",
@@ -259,8 +300,17 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
                   },
                   defaultValue: false,
                   format: (formatModel, value) => {
-                    formatModel.value["legend.shadowBlur"] = value ? 10 : 0;
-                    formatModel.value["legend.shadowColor"] = "#000";
+                    if(value) {
+                      formatModel.value["legend.shadowBlur"] = 10;
+                      formatModel.value["legend.shadowColor"] = formatModel.value['legend.backgroundColor'] || '#000000ff';
+                      formatModel.value["legend.shadowOffsetX"] = 3;
+                      formatModel.value["legend.shadowOffsetY"] = 3;
+                    } else {
+                      formatModel.value["legend.shadowBlur"] = 0;
+                      formatModel.value["legend.shadowColor"] = "transparent";
+                      formatModel.value["legend.shadowOffsetX"] = 0;
+                      formatModel.value["legend.shadowOffsetY"] = 0;
+                    }
                   },
                   valueToForm: (value) => {
                     return value ? true : false;
@@ -314,7 +364,16 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
         },
         defaultValue: [true],
         format: (formatModel, value) => {
-          formatModel.value["xAxis.showName"] = value?.length ? true : false;
+          if(value?.length) {
+            formatModel.value["xAxis.showName"] = true;
+            formatModel.value["xAxis.name"] = 'X轴标题';
+            formatModel.value["xAxis.nameGap"] = 25;
+          }  else {
+            formatModel.value["xAxis.showName"] = false;
+            formatModel.value["xAxis.name"] = "";
+            formatModel.value["xAxis.nameGap"] = 15;
+            formatModel.value["xAxis.nameGap"] = 15;
+          }
         },
         valueToForm: (value) => {
           return value ? [true] : [];
@@ -336,12 +395,12 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
                   format: (formatModel, value) => {
                     if (formatModel.value["xAxis.showName"]) {
                       formatModel.value["xAxis.name"] = value;
-                      formatModel.value["grid.bottom"] = 40;
-                    } else {
-                      formatModel.value["xAxis.name"] = "";
-                      formatModel.value["grid.bottom"] = 20;
+                      formatModel.value["xAxis.nameGap"] = 25;
                     }
                   },
+                  valueToForm: (value) => {
+                    return value || "X 轴标题";
+                  }
                 },
                 {
                   label: "标题位置",
@@ -364,7 +423,7 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
                       middle: "center",
                       end: "right",
                     };
-                    return p[value];
+                    return p[value] || "center";
                   },
                 },
                 {
@@ -385,12 +444,12 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
                       fontStyle: value.italic ? "italic" : "normal",
                     };
                   },
-                  valueToForm: (_, model) => {
+                  valueToForm: (value, model) => {
                     return {
-                      color: get(model, 'xAxis.nameTextStyle.color', '#000000ff'),
-                      size: get(model, 'xAxis.nameTextStyle.fontSize', 12),
-                      bold: get(model, 'xAxis.nameTextStyle.fontWeight') === 'bold',
-                      italic: get(model, 'xAxis.nameTextStyle.fontStyle') === 'italic',
+                      color: value?.color || '#000000ff',
+                      size: value?.fontSize || 12,
+                      bold: value?.fontWeight === 'bold' || false,
+                      italic: value?.fontStyle === 'italic' || false,
                     }
                   }
                 },
@@ -405,7 +464,7 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
       },
       {
         label: "线宽",
-        prop: "xAxis.axisLine.width",
+        prop: "xAxis.axisLine.lineStyle.width",
         type: "inputNumber",
         fieldProps: {
           addonAfter: "px",
@@ -414,7 +473,7 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
       },
       {
         label: "颜色",
-        prop: "xAxis.axisLine.color",
+        prop: "xAxis.axisLine.lineStyle.color",
         type: "colorSelect",
         defaultValue: "#ccc",
       },
@@ -539,14 +598,22 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
     children: [
       {
         label: " ",
-        prop: "yAxis.show",
+        prop: "yAxis.showName",
         type: "checkboxGroup",
         fieldProps: {
           options: [{ label: "显示轴标题", value: true }],
         },
         defaultValue: [],
         format: (formatModel, value) => {
-          formatModel.value["yAxis.show"] = value?.length ? true : false;
+          if(value?.length) {
+            formatModel.value["yAxis.showName"] = true;
+            formatModel.value["yAxis.name"] = 'Y轴标题';
+            formatModel.value["yAxis.nameGap"] = 25;
+          }  else {
+            formatModel.value["yAxis.showName"] = false;
+            formatModel.value["yAxis.name"] = "";
+            formatModel.value["yAxis.nameGap"] = 15;
+          }
         },
         valueToForm: (value) => {
           return value ? [true] : [];
@@ -556,9 +623,9 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
         label: "",
         prop: "",
         type: "dependency",
-        name: ["yAxis.show"],
+        name: ["yAxis.showName"],
         children: (model) => {
-          return model["yAxis.show"].length
+          return model["yAxis.showName"].length
             ? [
                 {
                   label: "标题内容",
@@ -566,14 +633,17 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
                   type: "input",
                   defaultValue: "Y 轴标题",
                   format: (formatModel, value) => {
-                    if (formatModel.value["yAxis.show"]) {
+                    if (formatModel.value["yAxis.showName"]) {
                       formatModel.value["yAxis.name"] = value;
-                      formatModel.value["grid.left"] = 40;
+                      formatModel.value["yAxis.nameGap"] = 25;
                     } else {
                       formatModel.value["yAxis.name"] = "";
-                      formatModel.value["grid.left"] = 20;
+                      formatModel.value["yAxis.nameGap"] = 15;
                     }
                   },
+                  valueToForm: (value) => {
+                    return value || "Y 轴标题";
+                  }
                 },
                 {
                   label: "标题位置",
@@ -596,7 +666,7 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
                       middle: "center",
                       end: "right",
                     };
-                    return p[value];
+                    return p[value] || 'center ';
                   },
                 },
                 {
@@ -604,7 +674,7 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
                   prop: "yAxis.nameTextStyle",
                   type: "fontStyle",
                   defaultValue: {
-                    color: "#000000ff",
+                    color: "#FFFFFFFF",
                     size: 12,
                     bold: false,
                     italic: false,
@@ -617,12 +687,12 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
                       fontStyle: value.italic ? "italic" : "normal",
                     };
                   },
-                  valueToForm: (_, model) => {
+                  valueToForm: (value) => {
                     return {
-                      color: get(model, 'yAxis.nameTextStyle.color', '#000000ff'),
-                      size: get(model, 'yAxis.nameTextStyle.fontSize', 12),
-                      bold: get(model, 'yAxis.nameTextStyle.fontWeight') === 'bold',
-                      italic: get(model, 'yAxis.nameTextStyle.fontStyle') === 'italic',
+                      color: value?.color || '#000000ff',
+                      size: value?.fontSize || 12,
+                      bold: value?.fontWeight === 'bold' || false,
+                      italic: value?.fontStyle === 'italic' || false,
                     }
                   }
                 },
@@ -636,19 +706,48 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
         type: "divider",
       },
       {
-        label: "线宽",
-        prop: "yAxis.axisLine.width",
-        type: "inputNumber",
+        label: " ",
+        prop: "yAxis.axisLine.show",
+        type: "checkboxGroup",
         fieldProps: {
-          addonAfter: "px",
+          options: [{ label: "显示轴线", value: true }],
         },
-        defaultValue: 1,
+        defaultValue: [true],
+        format: (formatModel, value) => {
+          formatModel.value["yAxis.axisLine.show"] = value?.length
+            ? true
+            : false;
+        },
+        valueToForm: (value) => {
+          return value ? [true] : [];
+        }
       },
       {
-        label: "颜色",
-        prop: "yAxis.axisLine.color",
-        type: "colorSelect",
-        defaultValue: "#ccc",
+        label: "",
+        prop: "",
+        type: "dependency",
+        name: ["yAxis.axisLine.show"],
+        children: (model) => {
+          return model["yAxis.axisLine.show"].length
+            ? [
+                {
+                  label: "线宽",
+                  prop: "yAxis.axisLine.lineStyle.width",
+                  type: "inputNumber",
+                  fieldProps: {
+                    addonAfter: "px",
+                  },
+                  defaultValue: 1,
+                },
+                {
+                  label: "颜色",
+                  prop: "yAxis.axisLine.lineStyle.color",
+                  type: "colorSelect",
+                  defaultValue: "#ccc",
+                },
+              ]
+            : [];
+        }
       },
       {
         label: "刻度",
@@ -757,6 +856,17 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
                     }
                   }
                 },
+                {
+                  label: '旋转角度',
+                  prop: "yAxis.axisLabel.rotate",
+                  type: "inputNumber",
+                  fieldProps: {
+                    addonAfter: "°",
+                    min: -90,
+                    max: 90,
+                    step: 1
+                  },
+                }
               ]
             : [];
         },
@@ -811,13 +921,13 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
                     return get(model, 'tooltip.formatter')?.replace(/\{|\}/g, "")?.split(" ");
                   }
                 },
-                {
-                  label: "格式化",
-                  prop: "tooltip.valueFormatter",
-                  type: "input",
-                  tip: "支持字符串模板和回调函数",
-                  defaultValue: "(value, dataIndex) => value",
-                },
+                // {
+                //   label: "格式化",
+                //   prop: "tooltip.valueFormatter",
+                //   type: "input",
+                //   tip: "支持字符串模板和回调函数",
+                //   defaultValue: "(value, dataIndex) => value",
+                // },
                 {
                   label: "样式",
                   prop: "tooltip.textStyle",
@@ -865,6 +975,15 @@ export const chartFormItemsMap: Record<string, IFormItem> = {
                   type: "colorSelect",
                   defaultValue: "#ccc",
                 },
+                {
+                  label: "圆角",
+                  prop: "tooltip.borderRadius",
+                  type: "inputNumber",
+                  fieldProps: {
+                    addonAfter: "px",
+                  },
+                  defaultValue: 4,
+                },
                 {
                   label: "背景",
                   prop: "",

+ 89 - 10
components/charts/config/index.ts

@@ -42,43 +42,122 @@ export const chartDefaultConfig: EChartsOption = {
   },
   // 图例
   legend: {
+    show: true,
     textStyle: {
       color: "#FFFFFFFF",
     },
     top: 32,
   },
-  // 系列
-  series: [{
-    
-  }],
   // 布局
   grid: {
     bottom: 34,
     right: 20,
+    left: 50,
     top: 60,
   },
-  // 提示框
-  tooltip: {},
   // x轴
   xAxis: {
     type: "category",
+    name: '',
+    nameLocation: "middle",
+    nameTruncate: {
+      ellipsis: "...",
+      maxWidth: 80
+    },
+    nameTextStyle: {
+      color: '#FFFFFFFF',
+      fontSize: 12,
+      fontWeight: 'normal',
+      fontStyle: 'normal'
+    },
     axisLabel: {
+      show: true,
       color: "#9fadbf",
+      fontSize: 12,
+      fontWeight: "normal",
+      fontStyle: "normal",
     },
-    name: ''
+    axisLine: {
+      show: true,
+      lineStyle: {
+        width: 1
+      }
+    },
+    axisTick: {
+      show: true,
+      lineStyle: {
+        width: 1,
+        color: "#ccc"
+      }
+    }
   },
   // y轴
   yAxis: {
-    axisLabel: {
-      color: "#9fadbf",
-    },
     splitLine: {
+      show: true,
       lineStyle: {
         type: "dashed",
         color: "#36485f",
       },
     },
+    type: "category",
+    name: '',
+    nameLocation: "middle",
+    nameTruncate: {
+      ellipsis: "...",
+      maxWidth: 80
+    },
+    nameTextStyle: {
+      color: '#FFFFFFFF',
+      fontSize: 12,
+      fontWeight: 'normal',
+      fontStyle: 'normal'
+    },
+    axisLabel: {
+      show: true,
+      color: "#9fadbf",
+      fontSize: 12,
+      fontWeight: "normal",
+      fontStyle: "normal",
+      rotate: 0,
+    },
+    axisLine: {
+      show: false,
+      lineStyle: {
+        width: 1,
+        color: "#ccc"
+      }
+    },
+    axisTick: {
+      show: false,
+      lineStyle: {
+        width: 1,
+        color: "#ccc"
+      }
+    }
   },
+  // 提示
+  tooltip: {
+    show: true,
+    trigger: "axis",
+    formatter: "{b}",
+    // valueFormatter: "(value, dataIndex) => value",
+    axisPointer: {
+      type: "line",
+    },
+    textStyle: {
+      color: "#FFFFFF",
+      fontSize: 12,
+      fontWeight: "normal",
+      fontStyle: "normal",
+    },
+    padding: 10,
+    borderWidth: 1,
+    borderColor: "#ccc",
+    borderRadius: 4,
+    backgroundColor: "#fff",
+    extraCssText: "",
+  }
 }
 
 

+ 12 - 1
components/charts/hooks/useChartOptions.ts

@@ -88,11 +88,22 @@ export const useChartOptions = (chartProps: Record<string, any>) => {
       "dataSource",
     ]) as EChartsOption;
 
+    // 通用标签
+    const label = opt?.label || {};
     const result = defaultsDeep(
       {
         xAxis: xAxis.value,
         yAxis: yAxis.value,
-        series: series.value,
+        series: (series.value as any[])?.map((item: any) => {
+          // 每个类型的图,可以单独设置series.类型
+          const customSet = opt.series?.[item.type] || {};
+          // TODO 动态计算上下左右距离
+          return {
+            ...label,
+            ...item,
+            ...customSet
+          }
+        }),
       },
       opt
     );

+ 34 - 16
components/cusForm/src/CusFormItem.vue

@@ -1,52 +1,70 @@
 <template>
-  <FormItem :label="item.type !== 'divider' ? item.label : ''" :name="item.prop" :rules="item.rules">
+  <FormItem
+    :label="item.type !== 'divider' ? item.label : ''"
+    :name="item.prop"
+    :rules="item.rules"
+  >
     <template v-if="item.type === 'divider'">
       <Divider style="margin: 0">{{ item.label }}</Divider>
     </template>
     <template v-else-if="item.type === 'input'">
-      <Input v-model:value="model" v-bind="item?.fieldProps"/>
+      <Input v-model:value="model" v-bind="item?.fieldProps" />
     </template>
     <template v-else-if="item.type === 'select'">
       <Select v-model:value="model" v-bind="item?.fieldProps"></Select>
     </template>
     <template v-else-if="item.type === 'inputNumber'">
-      <InputNumber v-model:value="model"  v-bind="item?.fieldProps" style="width: 100%"/>
+      <InputNumber
+        v-model:value="model"
+        v-bind="item?.fieldProps"
+        style="width: 100%"
+      />
     </template>
     <template v-else-if="item.type === 'image'">
-      <Image v-model:value="model"  v-bind="item?.fieldProps"/>
+      <Image v-model:value="model" v-bind="item?.fieldProps" />
     </template>
     <template v-else-if="item.type === 'checkboxGroup'">
       <CheckboxGroup v-model:value="model" v-bind="item?.fieldProps">
       </CheckboxGroup>
     </template>
     <template v-else-if="item.type === 'backgroundSelect'">
-      <BackgroundSelect v-model:value="model"  v-bind="item?.fieldProps"/>
+      <BackgroundSelect v-model:value="model" v-bind="item?.fieldProps" />
     </template>
     <template v-else-if="item.type === 'colorSelect'">
-      <ColorSelect v-model:value="model"  v-bind="item?.fieldProps"/>
+      <ColorSelect v-model:value="model" v-bind="item?.fieldProps" />
     </template>
     <template v-else-if="item.type === 'colorScheme'">
-      <ColorScheme v-model:value="model"  v-bind="item?.fieldProps"/>
+      <ColorScheme v-model:value="model" v-bind="item?.fieldProps" />
     </template>
     <template v-else-if="item.type === 'radioGroup'">
       <RadioGroup v-model:value="model" size="small" v-bind="item?.fieldProps">
       </RadioGroup>
     </template>
+    <template v-else-if="item.type === 'radioGroupButton'">
+      <RadioGroup v-model:value="model" size="small" >
+        <RadioButton
+          v-for="option in item.fieldProps.options"
+          :key="option.value"
+          :value="option.value"
+          >{{ option.label }}</RadioButton
+        >
+      </RadioGroup>
+    </template>
     <template v-else-if="item.type === 'position'">
-      <Position v-model:value="model"  v-bind="item?.fieldProps"/>
+      <Position v-model:value="model" v-bind="item?.fieldProps" />
     </template>
     <template v-else-if="item.type === 'fontStyle'">
-      <FontStyle v-model:value="model"  v-bind="item?.fieldProps"/>
+      <FontStyle v-model:value="model" v-bind="item?.fieldProps" />
     </template>
     <template v-else-if="item.type === 'slider'">
       <FormItemRest>
-        <CusSlider v-model:value="model"  v-bind="item?.fieldProps"/>
+        <CusSlider v-model:value="model" v-bind="item?.fieldProps" />
       </FormItemRest>
     </template>
     <!-- 提示 -->
     <template v-if="item.tip">
       <Tooltip :title="item.tip">
-        <InfoCircleOutlined style="color: #666"/>
+        <InfoCircleOutlined style="color: #666" />
       </Tooltip>
     </template>
   </FormItem>
@@ -65,7 +83,8 @@ import {
   Image,
   Divider,
   RadioGroup,
-  Tooltip
+  Tooltip,
+  RadioButton,
 } from "ant-design-vue";
 import { InfoCircleOutlined } from "@ant-design/icons-vue";
 
@@ -76,7 +95,7 @@ import Position from "./Position.vue";
 import FontStyle from "./FontStyle.vue";
 import CusSlider from "./CusSlider.vue";
 
-const props = defineProps<{item: IFormItem, modelValue: any}>();
+const props = defineProps<{ item: IFormItem; modelValue: any }>();
 const emit = defineEmits(["update:modelValue"]);
 
 const model = ref(props.modelValue);
@@ -87,12 +106,11 @@ watch(
     emit("update:modelValue", model.value);
   },
   { deep: true }
-)
-
+);
 </script>
 
 <style lang="less" scoped>
-:deep(.ant-divider-inner-text ){
+:deep(.ant-divider-inner-text) {
   font-size: 12px;
   color: #666;
 }

+ 1 - 1
components/cusForm/src/CusSlider.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="cus-slider">
     <Slider :value="value" @change="(val) => $emit('update:value', val)" :tip-formatter="(val) => `${val}%`"/>
-    <InputNumber :value="value" addon-after="%"/>
+    <InputNumber :value="value" @change="(val) => $emit('update:value', val)" addon-after="%"/>
   </div>
 </template>
 

+ 0 - 1
components/cusForm/src/FontStyle.vue

@@ -58,7 +58,6 @@ const props = defineProps<{
     color: string;
   };
 }>();
-
 const emit = defineEmits(["update:value"]);
 
 const bold = ref(props.value?.bold);

+ 3 - 2
components/cusForm/src/index.tsx

@@ -80,6 +80,7 @@ export default defineComponent({
             pick(formModel.value, child.name || []),
             formModel
           );
+          setFormModel(list);
           return getFormItems(list);
         }
         case "group": {
@@ -102,8 +103,8 @@ export default defineComponent({
     /* 分组 */
     const getGroupItem = (item: IFormItem) => {
       return (
-        <Collapse>
-          <CollapsePanel key={item.prop} header={item.label}>
+        <Collapse style={{ borderRadius: 0}}>
+          <CollapsePanel style={{ borderRadius: 0}} key={item.prop} header={item.label}>
             {(item.children as IFormItem[])?.map((child) => {
               return getItem(child);
             })}

+ 0 - 96
components/cusForm/src/index1.vue

@@ -1,96 +0,0 @@
-<template>
-  <Form
-    :model="formModel"
-    :colon="false"
-    :label-col="{ span: 8 }"
-    ref="formRef"
-    layout="horizontal"
-    size="small"
-  >
-    <template v-for="item in formItems" :key="item.prop">
-      <!-- 联动 -->
-      <template v-if="item.type === 'dependency'">
-        
-      </template>
-      <!-- 分组 -->
-      <Collapse v-if="item.type === 'group'">
-        <CollapsePanel :key="item.prop" :header="item.label">
-          <CusFormItem v-for="child in item.children" :key="child.prop" :item="child" v-model="formModel[child.prop]" />
-        </CollapsePanel>
-      </Collapse>
-      <!-- 单个表单项 -->
-      <CusFormItem v-else :item="item" v-model="formModel[item.prop]" />
-    </template>
-  </Form>
-</template>
-
-<script setup lang="tsx">
-import type { IFormItem } from "./type";
-import type { FormInstance } from "ant-design-vue";
-import {
-  ref,
-  defineProps,
-  defineExpose,
-  computed,
-  watch,
-  defineEmits,
-} from "vue";
-import {
-  Form,
-  Collapse,
-  CollapsePanel
-} from "ant-design-vue";
-import CusFormItem from "./CusFormItem.vue";
-
-const props = defineProps<{
-  columns: IFormItem[];
-  formModel?: Record<string, any>;
-}>();
-
-const emit = defineEmits(["change"]);
-
-const formModel = ref<Record<string, any>>({});
-const formRef = ref<FormInstance>();
-
-const formItems = computed(() => {
-  return props.columns.map((item) => {
-    return {
-      ...item,
-      rules: item.rules || [],
-    };
-  });
-});
-
-watch(
-  () => formItems.value,
-  (val) => {
-    val &&
-      props.columns?.forEach((item) => {
-        // 设置表单初始值
-        if (item.type === "group") {
-          const children = item.children || [];
-          (children as IFormItem[]).forEach((child) => {
-            if(item.type === 'divider') return;
-            formModel.value[child.prop] = child?.defaultValue;
-          });
-        } else {
-          if(item.type === 'divider') return;
-          formModel.value[item.prop] = item?.defaultValue;
-        }
-      });
-  },
-  { immediate: true }
-);
-
-watch(
-  () => formModel.value,
-  (val) => {
-    emit("change", val);
-  },
-  { deep: true }
-);
-
-defineExpose(formRef.value);
-</script>
-
-<style lang="less" scoped></style>

+ 2 - 0
components/cusForm/src/type.ts

@@ -14,6 +14,8 @@ export interface IFormItem {
     | "image"
     | "checkboxGroup"
     | "radioGroup"
+    | "radioGroupButton"
+    | "switch"
     // 背景选择
     | "backgroundSelect"
     // 边框选择