Bläddra i källkod

feat: 添加柱形图配置项

liaojiaxing 1 år sedan
förälder
incheckning
a5ca489db5

+ 2 - 22
src/components/Charts/Bar/BasicBar/src/Config.vue

@@ -27,34 +27,14 @@ import { ref, defineProps, defineEmits } from 'vue';
 import { Tabs, TabPane } from 'ant-design-vue';
 import { DatabaseOutlined, SkinOutlined } from '@ant-design/icons-vue';
 import DataConfig from '@/components/Charts/DataConfig.vue';
-import { CusForm, IFormItem } from '@/components/CusForm';
+import { CusForm } from '@/components/CusForm';
 import { basicBarProps } from './props';
+import { formItems } from './styleFormData';
 
 const props = defineProps(basicBarProps);
 const activeTab = ref('1');
 const emit = defineEmits(['change']);
 
-const formItems: IFormItem[] = [
-  {
-    label: '标题',
-    prop: 'title',
-    type: 'group',
-    children: [
-      {
-        label: '标题可见',
-        prop: 'showTitle',
-        type: 'checkbox',
-      },
-      {
-        label: '文本',
-        prop: 'titleText',
-        type: 'input',
-      },
-
-    ]
-  }
-]
-
 const handleChange = (data: any) => {
   emit('change', {
     ...props,

+ 798 - 0
src/components/Charts/Bar/BasicBar/src/styleFormData.ts

@@ -0,0 +1,798 @@
+import { IFormItem } from "@/components/CusForm";
+
+export const formItems: IFormItem[] = [
+  {
+    label: "标题",
+    prop: "title",
+    type: "group",
+    children: [
+      {
+        label: " ",
+        prop: "showTitle",
+        type: "checkboxGroup",
+        fieldProps: {
+          options: [{ label: "标题可见", value: true }],
+        },
+        defaultValue: []
+      },
+      {
+        label: "文本",
+        prop: "titleText",
+        type: "input",
+        defaultValue: "图表标题"
+      },
+      {
+        label: "位置",
+        prop: "titlePosition",
+        type: "position",
+        defaultValue: "center"
+      },
+      {
+        label: "样式",
+        prop: "titleStyle",
+        type: "fontStyle",
+        defaultValue: {
+          size: 18,
+          bold: true,
+          italic: false,
+          underline: false,
+        }
+      },
+      {
+        label: "背景",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "填充",
+        prop: "titleBackground",
+        type: "backgroundSelect",
+        fieldProps: {
+          filterOptions: ["image"],
+        },
+        defaultValue: {
+          type: "color",
+          color: "#fff",
+        }
+      },
+      {
+        label: "透明度",
+        prop: "titleOpacity",
+        type: "slider",
+        defaultValue: 100
+      },
+      {
+        label: "圆角",
+        prop: "titleBorderRadius",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 0
+      },
+    ],
+  },
+  {
+    label: "图例",
+    prop: "legend",
+    type: "group",
+    children: [
+      {
+        label: " ",
+        prop: "showLegend",
+        type: "checkboxGroup",
+        fieldProps: {
+          options: [{ label: "图例可见", value: true }],
+        },
+        defaultValue: [true]
+      },
+      {
+        label: "位置",
+        prop: "legendPosition",
+        type: "position",
+        fieldProps: {
+          type: "round",
+        },
+        defaultValue: "top"
+      },
+      {
+        label: "样式",
+        prop: "legendStyle",
+        type: "fontStyle",
+        defaultValue: {
+          size: 12,
+          bold: false,
+          italic: false,
+          underline: false,
+        }
+      },
+      {
+        label: "边框",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "线宽",
+        prop: "legendBorderWidth",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 0
+      },
+      {
+        label: "颜色",
+        prop: "legendBorderColor",
+        type: "colorSelect",
+        defaultValue: "#ccc"
+      },
+      {
+        label: "圆角",
+        prop: "legendBorderRadius",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 0
+      },
+      {
+        label: "背景",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "背景",
+        prop: "legendBackground",
+        type: "backgroundSelect",
+        fieldProps: {
+          filterOptions: ["image"],
+        },
+        defaultValue: {
+          type: "color",
+          color: "#fff",
+        }
+      },
+      {
+        label: "背景透明度",
+        prop: "legendBackgroudOpacity",
+        type: "slider",
+        defaultValue: 100
+      },
+      {
+        label: "背景圆角",
+        prop: "legendBackgroundRadius",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 0
+      },
+      {
+        label: "阴影",
+        prop: "legendShadow",
+        type: "radioGroup",
+        fieldProps: {
+          options: [
+            { label: "开启", value: true },
+            { label: "关闭", value: false },
+          ],
+        },
+        defaultValue: false
+      },
+    ],
+  },
+  {
+    label: "标签",
+    prop: "label",
+    type: "group",
+    children: [
+      {
+        label: " ",
+        prop: "showLabel",
+        type: "checkboxGroup",
+        fieldProps: {
+          options: [{ label: "标签可见", value: true }],
+        },
+        defaultValue: false
+      },
+      {
+        label: "文本",
+        prop: "labelValueType",
+        type: "checkboxGroup",
+        fieldProps: {
+          options: [
+            { label: "分类名", value: 'category' },
+            { label: "系列名", value: 'serie' },
+            { label: "数值", value: 'value' },
+            { label: "百分比", value: 'percent' },
+          ]
+        },
+        defaultValue: ['value']
+      },
+      {
+        label: "格式化",
+        prop: "labelFormatter",
+        type: "input",
+        tip: "支持字符串模板和回调函数",
+        defaultValue: "{value}"
+      },
+      {
+        label: "颜色",
+        prop: "labelColor",
+        type: "colorSelect",
+        defaultValue: "#000"
+      },
+      {
+        label: "样式",
+        prop: "labelStyle",
+        type: "fontStyle",
+        defaultValue: {
+          size: 12,
+          bold: false,
+          italic: false,
+          underline: false,
+        }
+      },
+      {
+        label: "布局",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "位置",
+        prop: "labelPosition",
+        type: "radioGroup",
+        fieldProps: {
+          options: [
+            { label: "内部", value: "inside" },
+            { label: "外部", value: "outside" },
+            { label: "中间", value: "center" },
+          ],
+        },
+        defaultValue: "outside"
+      },
+      {
+        label: "文本方向",
+        prop: "labelDirection",
+        type: "radioGroup",
+        fieldProps: {
+          options: [
+            { label: "水平", value: "horizontal" },
+            { label: "垂直", value: "vertical" },
+          ],
+        },
+        defaultValue: "horizontal"
+      },
+      {
+        label: "边框",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "线宽",
+        prop: "labelBorderWidth",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 0
+      },
+      {
+        label: "颜色",
+        prop: "labelBorderColor",
+        type: "colorSelect",
+        defaultValue: "#ccc"
+      },
+      {
+        label: "圆角",
+        prop: "labelBorderRadius",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 0
+      },
+    ],
+  },
+  {
+    label: "系列",
+    prop: "serie",
+    type: "group",
+    children: [
+      {
+        label: "配色",
+        prop: "colorScheme",
+        type: "colorScheme",
+        defaultValue: "custom"
+      },
+      {
+        label: "样式",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "固定柱宽",
+        prop: "serieBarFixedWidth",
+        type: "radioGroup",
+        fieldProps: {
+          options: [
+            { label: "是", value: true },
+            { label: "否", value: false },
+          ],
+        },
+        defaultValue: false
+      },
+      {
+        label: "系列间隔",
+        prop: "serieGap",
+        type: "slider",
+        defaultValue: 20
+      },
+      {
+        label: "分类间隔",
+        prop: "categoryGap",
+        type: "slider",
+        defaultValue: 20
+      },
+      {
+        label: "边框",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "线宽",
+        prop: "serieBorderWidth",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 0
+      },
+      {
+        label: "颜色",
+        prop: "serieBorderColor",
+        type: "colorSelect",
+        defaultValue: "#ccc"
+      },
+      {
+        label: "圆角",
+        prop: "serieBorderRadius",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 0
+      },
+    ]
+  },
+  {
+    label: "X 轴",
+    prop: "xAxis",
+    type: "group",
+    children: [
+      {
+        label: "类型",
+        prop: "xAxisType",
+        type: "select",
+        fieldProps: {
+          options: [
+            { label: "类目坐标轴", value: "category" },
+            { label: "数值坐标轴", value: "value" },
+            { label: "时间坐标轴", value: "time" },
+          ],
+        },
+        defaultValue: "category"
+      },
+      {
+        label: "轴标题",
+        prop: "xAliasShowTitle",
+        type: "radioGroup",
+        fieldProps: {
+          options: [
+            { label: "显示", value: true },
+            { label: "隐藏", value: false },
+          ],
+        },
+        defaultValue: false
+      },
+      {
+        label: "标题内容",
+        prop: "xAliasTitle",
+        type: "input",
+        defaultValue: "X 轴标题"
+      },
+      {
+        label: "标题位置",
+        prop: "xAliasPosition",
+        type: "position",
+        defaultValue: "center"
+      },
+      {
+        label: "标题样式",
+        prop: "xAliasStyle",
+        type: "fontStyle",
+        defaultValue: {
+          size: 12,
+          bold: false,
+          italic: false,
+          underline: false,
+        }
+      },
+      {
+        label: "轴线",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "线宽",
+        prop: "xAliasLineWidth",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 1
+      },
+      {
+        label: "颜色",
+        prop: "xAliasLineColor",
+        type: "colorSelect",
+        defaultValue: "#ccc"
+      },
+      {
+        label: "刻度",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "显示刻度",
+        prop: "xAliasTickShow",
+        type: "radioGroup",
+        fieldProps: {
+          options: [
+            { label: "显示", value: true },
+            { label: "隐藏", value: false },
+          ],
+        },
+        defaultValue: true
+      },
+      {
+        label: "刻度长度",
+        prop: "xAliasTickLength",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 5
+      },
+      {
+        label: "刻度颜色",
+        prop: "xAliasTickColor",
+        type: "colorSelect",
+        defaultValue: "#ccc"
+      },
+      {
+        label: "标签",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "颜色",
+        prop: "xAliasLabelColor",
+        type: "colorSelect",
+        defaultValue: "#000"
+      },
+      {
+        label: "样式",
+        prop: "xAliasLabelStyle",
+        type: "fontStyle",
+        defaultValue: {
+          size: 12,
+          bold: false,
+          italic: false,
+          underline: false,
+        }
+      },
+    ]
+  },
+  {
+    label: "Y 轴",
+    prop: "yAxis",
+    type: "group",
+    children: [
+      {
+        label: "轴标题",
+        prop: "yAliasShowTitle",
+        type: "radioGroup",
+        fieldProps: {
+          options: [
+            { label: "显示", value: true },
+            { label: "隐藏", value: false },
+          ],
+        },
+        defaultValue: false
+      },
+      {
+        label: "标题内容",
+        prop: "yAliasTitle",
+        type: "input",
+        defaultValue: "Y 轴标题"
+      },
+      {
+        label: "标题位置",
+        prop: "yAliasPosition",
+        type: "position",
+        defaultValue: "center"
+      },
+      {
+        label: "标题样式",
+        prop: "yAliasStyle",
+        type: "fontStyle",
+        defaultValue: {
+          size: 12,
+          bold: false,
+          italic: false,
+          underline: false,
+        }
+      },
+      {
+        label: "轴线",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "线宽",
+        prop: "yAliasLineWidth",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 1
+      },
+      {
+        label: "颜色",
+        prop: "yAliasLineColor",
+        type: "colorSelect",
+        defaultValue: "#ccc"
+      },
+      {
+        label: "刻度",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "显示刻度",
+        prop: "yAliasTickShow",
+        type: "radioGroup",
+        fieldProps: {
+          options: [
+            { label: "显示", value: true },
+            { label: "隐藏", value: false },
+          ],
+        },
+        defaultValue: true
+      },
+      {
+        label: "刻度长度",
+        prop: "yAliasTickLength",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 5
+      },
+      {
+        label: "刻度颜色",
+        prop: "yAliasTickColor",
+        type: "colorSelect",
+        defaultValue: "#ccc"
+      },
+      {
+        label: "标签",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "颜色",
+        prop: "yAliasLabelColor",
+        type: "colorSelect",
+        defaultValue: "#000"
+      },
+      {
+        label: "样式",
+        prop: "yAliasLabelStyle",
+        type: "fontStyle",
+        defaultValue: {
+          size: 12,
+          bold: false,
+          italic: false,
+          underline: false,
+        }
+      },
+    ]
+  },
+  {
+    label: "提示",
+    prop: "tooltip",
+    type: "group",
+    children: [
+      {
+        label: " ",
+        prop: "showTooltip",
+        type: "checkboxGroup",
+        fieldProps: {
+          options: [
+            { label: "提示可见", value: true },
+          ],
+        },
+        defaultValue: [true]
+      },
+      {
+        label: "文本",
+        prop: "tooltipValueType",
+        type: "checkboxGroup",
+        fieldProps: {
+          options: [
+            { label: "分类名", value: 'category' },
+            { label: "系列名", value: 'serie' },
+            { label: "数值", value: 'value' },
+            { label: "百分比", value: 'percent' },
+          ]
+        },
+        defaultValue: ['value']
+      },
+      {
+        label: "格式化",
+        prop: "tooltipFormatter",
+        type: "input",
+        tip: "支持字符串模板和回调函数",
+        defaultValue: "{value}"
+      },
+      {
+        label: "样式",
+        prop: "tooltipStyle",
+        type: "fontStyle",
+        defaultValue: {
+          size: 12,
+          bold: false,
+          italic: false,
+          underline: false,
+        }
+      },
+      {
+        label: "边框",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "线宽",
+        prop: "tooltipBorderWidth",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 1
+      },
+      {
+        label: "颜色",
+        prop: "tooltipBorderColor",
+        type: "colorSelect",
+        defaultValue: "#ccc"
+      },
+      {
+        label: "圆角",
+        prop: "tooltipBorderRadius",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 0
+      },
+      {
+        label: "背景",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "填充",
+        prop: "tooltipBackground",
+        type: "backgroundSelect",
+        fieldProps: {
+          filterOptions: ["image"],
+        },
+        defaultValue: {
+          type: "color",
+          color: "#fff",
+        }
+      },
+      {
+        label: "背景透明度",
+        prop: "tooltipBackgroudOpacity",
+        type: "slider",
+        defaultValue: 100
+      },
+      {
+        label: "阴影",
+        prop: "tooltipShadow",
+        type: "radioGroup",
+        fieldProps: {
+          options: [
+            { label: "开启", value: true },
+            { label: "关闭", value: false },
+          ],
+        },
+        defaultValue: false
+      },
+    ]
+  },
+  {
+    label: "背景",
+    prop: "background",
+    type: "group",
+    children: [
+      {
+        label: "边框",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "线宽",
+        prop: "backgroundBorderWidth",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 0
+      },
+      {
+        label: "颜色",
+        prop: "backgroundBorderColor",
+        type: "colorSelect",
+        defaultValue: "#ccc"
+      },
+      {
+        label: "圆角",
+        prop: "backgroundBorderRadius",
+        type: "inputNumber",
+        fieldProps: {
+          addonAfter: "px",
+        },
+        defaultValue: 0
+      },
+      {
+        label: "背景",
+        prop: "",
+        type: "divider",
+      },
+      {
+        label: "填充",
+        prop: "backgroundBackground",
+        type: "backgroundSelect",
+        fieldProps: {
+          filterOptions: ["image"],
+        },
+        defaultValue: {
+          type: "color",
+          color: "#fff",
+        }
+      },
+      {
+        label: "背景透明度",
+        prop: "backgroundBackgroudOpacity",
+        type: "slider",
+        defaultValue: 100
+      },
+      {
+        label: "阴影",
+        prop: "backgroundShadow",
+        type: "radioGroup",
+        fieldProps: {
+          options: [
+            { label: "开启", value: true },
+            { label: "关闭", value: false },
+          ],
+        },
+        defaultValue: false
+      },
+    ]
+  }
+];

+ 11 - 2
src/components/CusForm/src/BackgroundSelect.vue

@@ -1,5 +1,5 @@
 <template>
-  <Select v-model:value="backgroundObj.type" style="width: 100%" :options="options" @change="handleChangeColor"/>
+  <Select v-model:value="backgroundObj.type" style="width: 100%" :options="getOptions" @change="handleChangeColor"/>
   <template v-if="backgroundObj.type === 'color'">
     <div class="color-box">
       <ElColorPicker v-model="backgroundObj.color" color-format="hex" show-alpha size="small"/>
@@ -21,7 +21,7 @@
 </template>
 
 <script setup lang="ts">
-import { defineEmits, defineProps, withDefaults, ref, watch } from "vue";
+import { defineEmits, defineProps, withDefaults, ref, watch, computed } from "vue";
 import { Select, Image } from "ant-design-vue";
 import { ElColorPicker, ElRadioGroup, ElRadioButton, ElInput } from "element-plus";
 
@@ -32,6 +32,7 @@ interface Prop {
     image?: string;
     fillType?: "cover" | "contain" | "stretch" | "";
   };
+  filterOptions?: string[];
 }
 const props = withDefaults(defineProps<Prop>(), {
   background: () => ({
@@ -52,6 +53,13 @@ const options = [
   { label: "图片", value: "image" },
 ];
 
+const getOptions = computed(() => {
+  if(!props.filterOptions) {
+    return options;
+  }
+  return options.filter((item) => !props.filterOptions?.includes(item.value));
+});
+
 watch(
   () => backgroundObj.value,
   () => {
@@ -74,6 +82,7 @@ const handleChangeColor = (type: any) => {
   display: flex;
   align-items: center;
   margin: 12px 0;
+  margin-bottom: 0;
   :deep(.el-color-picker) {
     margin-right: 8px;
   }

+ 2 - 2
src/components/CusForm/src/ColorSelect.vue

@@ -50,14 +50,14 @@ watch(
 .color-box {
   display: flex;
   align-items: center;
-  margin: 12px 0;
+  margin-top: 12px;
   :deep(.el-color-picker) {
     margin-right: 8px;
   }
 }
 .gradient-box {
   padding: 2px;
-  margin: 12px 0;
+  margin-top: 12px;
   border: solid 1px #eee;
   width: 100%;
   display: flex;

+ 49 - 41
src/components/CusForm/src/CusFormItem.vue

@@ -1,52 +1,51 @@
 <template>
-  <FormItem :label="item.label" :name="item.prop" :rules="item.rules">
-    <template v-if="item.type === 'input'">
-      <Input v-model:value="model" />
+  <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"/>
     </template>
     <template v-else-if="item.type === 'select'">
-      <Select v-model:value="model" :options="item.options"></Select>
+      <Select v-model:value="model" v-bind="item?.fieldProps"></Select>
     </template>
-    <template v-else-if="item.type === 'inputnumber'">
-      <InputNumber v-model:value="model" />
+    <template v-else-if="item.type === 'inputNumber'">
+      <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" />
+      <Image v-model:value="model"  v-bind="item?.fieldProps"/>
     </template>
-    <template v-else-if="item.type === 'checkbox'">
-      <Checkbox v-model:value="model" />
+    <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:background="model" />
+      <BackgroundSelect v-model:background="model"  v-bind="item?.fieldProps"/>
     </template>
     <template v-else-if="item.type === 'colorSelect'">
-      <ColorSelect v-model:value="model" />
+      <ColorSelect v-model:value="model"  v-bind="item?.fieldProps"/>
     </template>
     <template v-else-if="item.type === 'radioGroup'">
-      <ElRadioGroup v-model="model" size="small">
-        <ElRadioButton
-          v-for="option in item.options"
-          :key="option.value"
-          :value="option.value"
-        >
-          {{ option.label }}
-        </ElRadioButton>
-      </ElRadioGroup>
+      <RadioGroup v-model:value="model" size="small" v-bind="item?.fieldProps">
+      </RadioGroup>
+    </template>
+    <template v-else-if="item.type === 'position'">
+      <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"/>
+    </template>
+    <template v-else-if="item.type === 'slider'">
+      <FormItemRest>
+        <CusSlider v-model:value="model"  v-bind="item?.fieldProps"/>
+      </FormItemRest>
+    </template>
+    <!-- 提示 -->
+    <template v-if="item.tip">
+      <Tooltip :title="item.tip">
+        <InfoCircleOutlined style="color: #666"/>
+      </Tooltip>
     </template>
-    <!--<template v-else-if="item.type === 'boderRadiusSelect'">
-          <BoderRadiusSelect v-model="formModel[item.key]" />
-        </template>
-        <template v-else-if="item.type === 'shodowSelect'">
-          <ShodowSelect v-model="formModel[item.key]" />
-        </template>
-        <template v-else-if="item.type === 'paddingSelect'">
-          <PaddingSelect v-model="formModel[item.key]" />
-        </template>
-        <template v-else-if="item.type === 'rotateSelect'">
-          <RotateSelect v-model="formModel[item.key]" />
-        </template>
-        <template v-else-if="item.type === 'opacitySelect'">
-          <OpacitySelect v-model="formModel[item.key]" />
-        </template> -->
   </FormItem>
 </template>
 
@@ -55,23 +54,32 @@ import { IFormItem } from "./type";
 import { defineProps, defineModel } from "vue";
 import {
   FormItem,
+  FormItemRest,
   Input,
   Select,
   InputNumber,
-  Checkbox,
+  CheckboxGroup,
   Image,
+  Divider,
+  RadioGroup,
+  Tooltip
 } from "ant-design-vue";
-import {
-  ElRadioGroup,
-  ElRadioButton,
-} from "element-plus";
+import { InfoCircleOutlined } from "@ant-design/icons-vue";
 
 import BackgroundSelect from "./BackgroundSelect.vue";
 import ColorSelect from "./ColorSelect.vue";
+import Position from "./Position.vue";
+import FontStyle from "./FontStyle.vue";
+import CusSlider from "./CusSlider.vue";
 
 defineProps<{item: IFormItem}>();
 const model = defineModel<any>();
 
 </script>
 
-<style scoped></style>
+<style lang="less" scoped>
+:deep(.ant-divider-inner-text ){
+  font-size: 12px;
+  color: #666;
+}
+</style>

+ 27 - 0
src/components/CusForm/src/CusSlider.vue

@@ -0,0 +1,27 @@
+<template>
+  <div class="cus-slider">
+    <Slider :value="value" @change="(val) => $emit('update:value', val)" :tip-formatter="(val) => `${val}%`"/>
+    <InputNumber :value="value" addon-after="%"/>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { defineProps, defineEmits } from "vue";
+import { Slider, InputNumber } from "ant-design-vue";
+
+defineProps<{ value: number }>();
+defineEmits(["update:value"]);
+</script>
+
+<style lang="less" scoped>
+.cus-slider {
+  display: flex;
+  align-items: center;
+  .ant-slider {
+    flex: 1;
+  }
+  .ant-input-number-group-wrapper {
+    flex: 15%;
+  }
+}
+</style>

+ 31 - 23
src/components/CusForm/src/FontStyle.vue

@@ -11,13 +11,15 @@
     /></span>
     <InputNumber
       size="small"
-      :min="0"
-      :max="100"
+      :value="size"
+      :min="12"
       :step="1"
       :precision="0"
       style="width: 80px"
       @change="handleChange"
-    />
+    >
+      <template #addonAfter>px</template>
+    </InputNumber>
   </div>
 </template>
 
@@ -31,39 +33,45 @@ import {
 import { InputNumber } from "ant-design-vue";
 
 const props = defineProps<{
-  size: number;
-  bold: boolean;
-  italic: boolean;
-  underline: boolean;
+  value: {
+    size: number;
+    bold: boolean;
+    italic: boolean;
+    underline: boolean;
+  };
 }>();
 
-const emit = defineEmits([
-  "update:value",
-  "update:bold",
-  "update:italic",
-  "update:underline",
-]);
+const emit = defineEmits(["update:value"]);
 
-const bold = ref(props.bold);
-const italic = ref(props.italic);
-const underline = ref(props.underline);
-const size = ref(props.size);
+const bold = ref(props.value?.bold);
+const italic = ref(props.value?.italic);
+const underline = ref(props.value?.underline);
+const size = ref(props.value?.size);
+
+const handleUpdate = () => {
+  emit("update:value", {
+    size: size.value,
+    bold: bold.value,
+    italic: italic.value,
+    underline: underline.value,
+  });
+};
 
 const handleBold = () => {
   bold.value = !bold.value;
-  emit("update:bold", bold.value);
+  handleUpdate();
 };
 const handleItalic = () => {
   italic.value = !italic.value;
-  emit("update:italic", italic.value);
+  handleUpdate();
 };
 const handleUnderline = () => {
   underline.value = !underline.value;
-  emit("update:underline", underline.value);
+  handleUpdate();
 };
-const handleChange = (e: any) => {
-  size.value = e.target.value;
-  emit("update:value", size.value);
+const handleChange = (val: number) => {
+  size.value = val;
+  handleUpdate();
 };
 </script>
 

+ 24 - 5
src/components/CusForm/src/Position.vue

@@ -1,18 +1,37 @@
 <template>
-  <div>
-    <RadioGroup v-model:value="formModel.title.position">
+  <div class="position">
+    <RadioGroup v-if="type === 'line'" :value="value" @change="(e) => $emit('update:value', e.target.value)">
       <RadioButton value="left"><AlignLeftOutlined/></RadioButton>
       <RadioButton value="center"><AlignCenterOutlined/></RadioButton>
       <RadioButton value="right"><AlignRightOutlined/></RadioButton>
     </RadioGroup>
+
+    <RadioGroup v-else-if="type === 'round'" :value="value" @change="(e) => $emit('update:value', e.target.value)">
+      <RadioButton value="top"><BorderTopOutlined/></RadioButton>
+      <RadioButton value="bottom"><BorderBottomOutlined/></RadioButton>
+      <RadioButton value="left"><BorderLeftOutlined/></RadioButton>
+      <RadioButton value="right"><BorderRightOutlined/></RadioButton>
+      <!-- <RadioButton value="right-top"><AlignRightOutlined/></RadioButton> -->
+    </RadioGroup>
   </div>
 </template>
 
 <script setup lang="ts">
+import { defineProps, defineEmits, withDefaults } from 'vue';
 import { RadioGroup, RadioButton } from 'ant-design-vue';
-import { AlignCenterOutlined, AlignRightOutlined, AlignLeftOutlined } from '@ant-design/icons-vue';
-</script>
+import { AlignCenterOutlined, AlignRightOutlined, AlignLeftOutlined, BorderBottomOutlined, BorderTopOutlined, BorderLeftOutlined, BorderRightOutlined } from '@ant-design/icons-vue';
 
-<style scoped>
+withDefaults(defineProps<{value: string, type?: 'round' | 'line'}>(), { type: 'line'});
+defineEmits(['update:value']);
+</script>
 
+<style lang="less" scoped>
+:deep(.ant-radio-group) {
+  width: 100%;
+  display: flex;
+}
+:deep(.ant-radio-button-wrapper) {
+  flex: 1;
+  text-align: center;
+}
 </style>

+ 5 - 3
src/components/CusForm/src/index.vue

@@ -2,7 +2,7 @@
   <Form
     :model="formModel"
     :colon="false"
-    :label-col="{ span: 6 }"
+    :label-col="{ span: 8 }"
     ref="formRef"
     layout="horizontal"
     size="small"
@@ -10,8 +10,8 @@
     <template v-for="item in formItems" :key="item.prop">
       <!-- 分组 -->
       <Collapse v-if="item.type === 'group'">
-        <CollapsePanel :name="item.prop" :label="item.label">
-          <CusFormItem :item="item" v-model="formModel[item.prop]" />
+        <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>
       <!-- 单个表单项 -->
@@ -66,9 +66,11 @@ watch(
         if (item.type === "group") {
           const children = item.children || [];
           children.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;
         }
       });

+ 14 - 5
src/components/CusForm/src/type.ts

@@ -1,3 +1,5 @@
+import { VNode } from "vue";
+
 export interface IFormItem {
   label: string;
   icon?: string;
@@ -7,9 +9,9 @@ export interface IFormItem {
     | "group"
     | "input"
     | "select"
-    | "inputnumber"
+    | "inputNumber"
     | "image"
-    | "checkbox"
+    | "checkboxGroup"
     | "radioGroup"
     // 背景选择
     | "backgroundSelect"
@@ -33,11 +35,18 @@ export interface IFormItem {
     | "fontStyle"
     // 位置
     | "position"
-  options?: any[];
-  prefix?: string;
-  suffix?: string;
+    // 滑块
+    | "slider"
+    // 分割线
+    | "divider"
   rules?: any[];
   defaultValue?: any;
   // 分组表单项
   children?: IFormItem[];
+  // 组件属性
+  fieldProps?: any;
+  // 自定义渲染
+  render?: (form: any) => VNode;
+  // 提示内容
+  tip?: string;
 }

+ 2 - 1
src/views/home/component/AddModal.vue

@@ -80,7 +80,7 @@ const formData = reactive({
 });
 const projectStore = useProjectStore();
 
-const emit = defineEmits(["change"]);
+const emit = defineEmits(["change", "update:open"]);
 
 watch(
   () => formData.sizeType,
@@ -114,6 +114,7 @@ const handleOk = async () => {
   window.open(`/#/designer`);
   emit("change");
   message.success("新增成功");
+  emit("update:open", false);
 };
 </script>