Ver código fonte

feat: 调整配置,添加饼图组件

liaojiaxing 1 ano atrás
pai
commit
6a1106ffb5
37 arquivos alterados com 1858 adições e 1140 exclusões
  1. 126 84
      components/charts/Bar/BasicBar/src/Config.vue
  2. 0 4
      components/charts/Bar/BasicBar/src/props.ts
  3. 1 1
      components/charts/Charts.vue
  4. 0 2
      components/charts/Line/BasicLine/src/Config.vue
  5. 12 0
      components/charts/Pie/BasicPie/index.ts
  6. 2 2
      components/charts/Pie/BasicPie/src/BasicPie.vue
  7. 2 9
      components/charts/Pie/BasicPie/src/Config.vue
  8. 22 31
      components/charts/Pie/BasicPie/src/props.ts
  9. 506 300
      components/charts/config/chartFormItemsMap.ts
  10. 9 2
      components/charts/config/index.ts
  11. 12 7
      components/charts/hooks/useChartOptions.ts
  12. 1 1
      components/charts/hooks/useEcharts.ts
  13. 1 1
      components/charts/utils/index.ts
  14. 1 1
      components/charts/utils/transChartOption.ts
  15. 13 2
      components/components.ts
  16. 6 7
      components/cusForm/src/BackgroundSelect.vue
  17. 3 2
      components/cusForm/src/CusFormItem.vue
  18. 58 21
      components/cusForm/src/FontStyle.vue
  19. 34 21
      components/cusForm/src/index.tsx
  20. 2 0
      components/cusForm/src/type.ts
  21. 1 2
      components/index.ts
  22. 1 0
      components/text/Title/index.ts
  23. 87 1
      lib/demo.html
  24. 455 309
      lib/shaluDashBoardUi.common.js
  25. 1 1
      lib/shaluDashBoardUi.common.js.map
  26. 1 1
      lib/shaluDashBoardUi.css
  27. 455 309
      lib/shaluDashBoardUi.umd.js
  28. 1 1
      lib/shaluDashBoardUi.umd.js.map
  29. 9 9
      lib/shaluDashBoardUi.umd.min.js
  30. 1 1
      lib/shaluDashBoardUi.umd.min.js.map
  31. 20 2
      package.json
  32. 2 2
      pnpm-lock.yaml
  33. 1 2
      public/index.html
  34. 3 1
      tsconfig.json
  35. 8 1
      types/index.d.ts
  36. 0 0
      typings/global.d.ts
  37. 1 0
      vue.config.js

+ 126 - 84
components/charts/Bar/BasicBar/src/Config.vue

@@ -17,110 +17,152 @@
       </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 { basicBarProps } from './props';
-import { chartFormItemsMap } from '../../../config/chartFormItemsMap';
+import { ref, defineProps, defineEmits, computed } 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 { basicBarProps } from "./props";
+import { chartFormItemsMap } from "../../../config/chartFormItemsMap";
+import { set, cloneDeep } from 'lodash-es';
 
 const props = defineProps(basicBarProps);
-const activeTab = ref('1');
-const emit = defineEmits(['change']);
-const formItems = [
+const activeTab = ref("1");
+const emit = defineEmits(["change"]);
+
+const barSeries: IFormItem[] = [
+  {
+    label: "样式",
+    prop: "",
+    type: "divider",
+  },
+  {
+    label: "固定柱宽",
+    prop: "series.fixedBarWidth",
+    type: "radioGroup",
+    fieldProps: {
+      options: [
+        { label: "是", value: true },
+        { label: "否", value: false },
+      ],
+    },
+    defaultValue: false,
+    format: (formatModel, value) => {
+      formatModel.value["series.barWidth"] = value
+        ? formatModel.value?.["series.barWidth"] || 20
+        : "auto";
+    },
+    valueToForm: (value) => {
+      return value !== 'auto'
+    }
+  },
+  {
+    label: "",
+    prop: "",
+    type: "dependency",
+    name: ["series.fixedBarWidth"],
+    children: (model) => {
+      return model["series.fixedBarWidth"]
+        ? [
+            {
+              label: "柱宽",
+              prop: "series.barWidth",
+              type: "inputNumber",
+              fieldProps: {
+                addonAfter: "px",
+              },
+              defaultValue: 20,
+            },
+          ]
+        : [];
+    },
+  },
+  {
+    label: "系列间隔",
+    prop: "series.barGap",
+    type: "slider",
+    defaultValue: 20,
+  },
+  {
+    label: "分类间隔",
+    prop: "series.barCategoryGap",
+    type: "slider",
+    defaultValue: 20,
+  },
+  {
+    label: "边框",
+    prop: "",
+    type: "divider",
+  },
+  {
+    label: "线宽",
+    prop: "series.itemStyle.borderWidth",
+    type: "inputNumber",
+    fieldProps: {
+      addonAfter: "px",
+    },
+    defaultValue: 0,
+  },
+  {
+    label: "颜色",
+    prop: "series.itemStyle.borderColor",
+    type: "colorSelect",
+    defaultValue: "#ccc",
+  },
+  {
+    label: "圆角",
+    prop: "series.itemStyle.borderRadius",
+    type: "inputNumber",
+    fieldProps: {
+      addonAfter: "px",
+    },
+    defaultValue: 0,
+  },
+];
+const formItems: IFormItem[] = [
   chartFormItemsMap.title,
   chartFormItemsMap.legend,
   // chartFormItemsMap.label,
   {
     ...chartFormItemsMap.series,
-    children: [
-      ...(chartFormItemsMap.serie.children as IFormItem[]),
-      {
-        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,
-      },
-    ]
+    children: (chartFormItemsMap.series.children as IFormItem[]).concat(
+      barSeries
+    ),
   },
   chartFormItemsMap.xAxis,
   chartFormItemsMap.yAxis,
   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]);
   });
-}
+  console.log("obj:", obj, props, formatData);
+  emit("change", obj);
+};
 </script>
 
 <style lang="less" scoped>
@@ -128,4 +170,4 @@ const handleFormChange = (data: any) => {
   text-align: center;
   margin-bottom: 12px;
 }
-</style>
+</style>

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

@@ -45,10 +45,6 @@ export const basicBarProps = {
   series: {
     type: Array as PropType<EChartsOption["series"]>,
   },
-  // 数据集
-  dataset: {
-    type: Object as PropType<EChartsOption["dataset"]>,
-  },
   // color
   color: {
     type: Object as PropType<EChartsOption["color"]>

+ 1 - 1
components/charts/Charts.vue

@@ -11,7 +11,7 @@ import { Spin } from "ant-design-vue";
 import { LoadingOutlined } from "@ant-design/icons-vue";
 import { useEcharts } from "./hooks/useEcharts";
 import type { EChartsOption } from "echarts";
-import { throttle } from "lodash";
+import { throttle } from "lodash-es";
 
 const props = defineProps<{
   echartsOptions: EChartsOption;

+ 0 - 2
components/charts/Line/BasicLine/src/Config.vue

@@ -39,8 +39,6 @@ const formItems = [
   chartFormItemsMap.legend,
   // chartFormItemsMap.label,
   chartFormItemsMap.series,
-  chartFormItemsMap.xAxis,
-  chartFormItemsMap.yAxis,
   chartFormItemsMap.tooltip,
   chartFormItemsMap.background
 ]

+ 12 - 0
components/charts/Pie/BasicPie/index.ts

@@ -0,0 +1,12 @@
+import BasicPie from './src/BasicPie.vue';
+import Config from './src/Config.vue';
+
+BasicPie.Config = Config;
+BasicPie.install = (app: any) => {
+  app.component('FmDashboardBasicPie', BasicPie);
+  return app;
+};
+
+export default BasicPie;
+export { Config };
+export { defaultPropsValue, basicPieProps } from './src/props';

+ 2 - 2
components/charts/Pie/BasicPie/src/BasicPie.vue

@@ -5,10 +5,10 @@
 <script setup lang="ts" name="fmDashboardBasicBar">
 import { defineProps } from 'vue';
 import Charts from '../../../Charts.vue';
-import { basicBarProps } from "./props";
+import { basicPieProps } from "./props";
 import { useChartOptions } from "../../../hooks/useChartOptions";
 
-const props = defineProps(basicBarProps);
+const props = defineProps(basicPieProps);
 
 const { options, loading } = useChartOptions(props);
 

+ 2 - 9
components/charts/Pie/BasicPie/src/Config.vue

@@ -28,22 +28,15 @@ 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 { basicBarProps } from './props';
+import { basicPieProps } from './props';
 import { chartFormItemsMap } from '../../../config/chartFormItemsMap';
 
-const props = defineProps(basicBarProps);
+const props = defineProps(basicPieProps);
 const activeTab = ref('1');
 const emit = defineEmits(['change']);
 const formItems = [
   chartFormItemsMap.title,
   chartFormItemsMap.legend,
-  // chartFormItemsMap.label,
-  {
-    ...chartFormItemsMap.series,
-    children: [
-      ...(chartFormItemsMap.serie.children as IFormItem[]),
-    ]
-  },
   chartFormItemsMap.xAxis,
   chartFormItemsMap.yAxis,
   chartFormItemsMap.tooltip,

+ 22 - 31
components/charts/Pie/BasicPie/src/props.ts

@@ -3,7 +3,7 @@ import { EChartsOption } from "echarts";
 import { getNormalizedChart, dataSource } from "../../../utils";
 import { DataSourceType } from "../../../chartEnum";
 
-export const basicBarProps = {
+export const basicPieProps = {
   width: {
     type: Number as PropType<number>,
     default: 400,
@@ -33,22 +33,10 @@ export const basicBarProps = {
   tooltip: {
     type: Object as PropType<EChartsOption["tooltip"]>,
   },
-  // x轴数据
-  xAxis: {
-    type: Object as PropType<EChartsOption["xAxis"]>,
-  },
-  // y轴数据
-  yAxis: {
-    type: Object as PropType<EChartsOption["yAxis"]>,
-  },
-  // 折线
+  // 饼图数据
   series: {
     type: Array as PropType<EChartsOption["series"]>,
   },
-  // 数据集
-  dataset: {
-    type: Object as PropType<EChartsOption["dataset"]>,
-  },
   // color
   color: {
     type: Object as PropType<EChartsOption["color"]>
@@ -57,11 +45,17 @@ export const basicBarProps = {
 
 const chartOptions = getNormalizedChart({
   title: {
-    text: "柱状图标题",
+    text: "饼图标题",
+  },
+  grid: {
+    show: false
   },
   xAxis: {
-    data: ['轴标签A', '轴标签B', '轴标签C', '轴标签D']
+    show: false
   },
+  yAxis: {
+    show: false
+  }
 })
 
 export const defaultPropsValue: EChartsOption = {
@@ -78,21 +72,20 @@ export const defaultPropsValue: EChartsOption = {
     dataSource: {
       sourceType: DataSourceType.STATIC,
       data: {
-        xData: ['轴标签A', '轴标签B', '轴标签C', '轴标签D'],
         series: [
           {
-            type: 'bar',
+            type: 'pie',
             name: '系列1',
-            data: [89.3, 92.1, 94.4, 85.4]
-          },
-          {
-            type: 'bar',
-            name: '系列2',
-            data: [95.8, 89.4, 91.2, 76.9]
-          },
+            data: [
+              { value: 335, name: '直接访问' },
+              { value: 310, name: '邮件营销' },
+              { value: 234, name: '联盟广告' },
+              { value: 135, name: '视频广告' },
+            ]
+          }
         ]
       },
-      url: location.origin + "/mock/api/get/example/bar",
+      url: location.origin + "/mock/api/get/example/pie",
       method: "POST",
       params: {},
       headers: {},
@@ -101,16 +94,14 @@ export const defaultPropsValue: EChartsOption = {
         (res) => {
           // 取出列表
           const data = res.data;
-          // x轴数据
-          const xData = data.map((item) => item.name); 
+
           // 系列数据
           const series = [
-            { type: 'bar', name: '价格', data: data.map(item => item.price) },
-            { type: 'bar', name: '总量', data: data.map(item => item.count) },
+            { type: 'pie', name: '价格', data: data.map(item => item.price) },
           ];
 
           // 返回图表数据
-          return { xData, series };
+          return { series };
         }
       `
     },

Diferenças do arquivo suprimidas por serem muito extensas
+ 506 - 300
components/charts/config/chartFormItemsMap.ts


+ 9 - 2
components/charts/config/index.ts

@@ -31,20 +31,26 @@ export const chartDefaultConfig: EChartsOption = {
   color: colorPreset[0].color,
   // 标题
   title: {
+    show: true,
     left: "center",
     top: 8,
     textStyle: {
-      color: "#fff",
+      color: "#FFFFFFFF",
       fontSize: 16,
+      fontWeight: "normal",
     },
   },
   // 图例
   legend: {
     textStyle: {
-      color: "#fff",
+      color: "#FFFFFFFF",
     },
     top: 32,
   },
+  // 系列
+  series: [{
+    
+  }],
   // 布局
   grid: {
     bottom: 34,
@@ -59,6 +65,7 @@ export const chartDefaultConfig: EChartsOption = {
     axisLabel: {
       color: "#9fadbf",
     },
+    name: ''
   },
   // y轴
   yAxis: {

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

@@ -1,6 +1,6 @@
 import type { EChartsOption } from "echarts";
 import { computed, watch, ref } from "vue";
-import { omit, defaultsDeep } from "lodash";
+import { omit, defaultsDeep } from "lodash-es";
 import { useRequest } from "vue-hooks-plus";
 import { DataSourceType } from "../chartEnum";
 import { message } from "ant-design-vue";
@@ -8,8 +8,8 @@ import { cllJsCode } from "../utils";
 
 export const useChartOptions = (chartProps: Record<string, any>) => {
   const dataSource = chartProps.dataSource || {};
-  const xAxis = ref<EChartsOption["xAxis"]>({ data: dataSource?.data?.xData });
-  const yAxis = ref<EChartsOption["yAxis"]>({ data: dataSource?.data?.yData });
+  const xAxis = ref<EChartsOption["xAxis"]>();
+  const yAxis = ref<EChartsOption["yAxis"]>();
   const series = ref<EChartsOption["series"]>(dataSource?.data?.series);
 
   const server = computed(() => {
@@ -66,9 +66,14 @@ export const useChartOptions = (chartProps: Record<string, any>) => {
       } else {
         cancel();
         const dataSource = chartProps.dataSource || {};
-        xAxis.value = { data: dataSource?.data?.xData };
-        yAxis.value = { data: dataSource?.data?.yData };
-        series.value = dataSource?.data?.series;
+        const { xData, yData, series } = dataSource?.data || {};
+        if(xData) {
+          xAxis.value = { data: xData };
+        }
+        if(yData) {
+          yAxis.value = { data: yData };
+        }
+        series.value = series;
       }
     },
     {
@@ -91,7 +96,7 @@ export const useChartOptions = (chartProps: Record<string, any>) => {
       },
       opt
     );
-
+    console.log('option result:', result)
     return result;
   });
 

+ 1 - 1
components/charts/hooks/useEcharts.ts

@@ -41,7 +41,7 @@ export function useEcharts(
     removeResizeFn = removeEvent;
   }
 
-  function setOptions(options: EChartsOption, clear = true) {
+  function setOptions(options: EChartsOption, clear = false) {
     cacheOptions.value = options;
     return new Promise((resolve) => {
       if (unref(elRef)?.offsetHeight === 0) {

+ 1 - 1
components/charts/utils/index.ts

@@ -1,5 +1,5 @@
 import type { DataSource } from "../types";
-import { defaultsDeep } from "lodash";
+import { defaultsDeep } from "lodash-es";
 import { containerDefaultConfig, chartDefaultConfig } from "../config";
 import { EChartsOption } from "echarts";
 import { PropType } from "vue";

+ 1 - 1
components/charts/utils/transChartOption.ts

@@ -1,6 +1,6 @@
 // import { EChartsOption } from "echarts";
 // import { isArray } from "element-plus/es/utils";
-// import { set } from "lodash";
+// import { set } from "lodash-es";
 
 // /* 配置表单 转 echartsOption */
 // export const config2Option = (config: Record<string, any>) => {

+ 13 - 2
components/components.ts

@@ -2,6 +2,7 @@ export const asyncComponentAll = {
   Title: () => import('./text/Title'),
   BasicLine: () => import('./charts/Line/BasicLine'),
   BasicBar: () => import('./charts/Bar/BasicBar'),
+  BasicPie: () => import('./charts/Pie/BasicPie'),
 }
 
 export { DataSourceType } from './charts/chartEnum';
@@ -26,17 +27,27 @@ export {
   basicBarProps as BasicBarProps
 } from './charts/Bar/BasicBar';
 
+/* 基础饼图 */
+import { default as BasicPie } from './charts/Pie/BasicPie/src/BasicPie.vue';
+export { 
+  Config as BasicPieConfig,
+  defaultPropsValue as BasicPieDefaultProps,
+  basicPieProps as BasicPieProps
+} from './charts/Pie/BasicPie';
+
 export type { IFormItem } from './cusForm';
 export { CusForm } from './cusForm';
 
 export const components = {
   BasicLine,
   BasicBar,
-  Title
+  Title,
+  BasicPie
 }
 
 export {
   BasicLine,
   BasicBar,
-  Title
+  Title,
+  BasicPie
 }

+ 6 - 7
components/cusForm/src/BackgroundSelect.vue

@@ -26,7 +26,7 @@ import { Select, Image } from "ant-design-vue";
 import { ElColorPicker, ElRadioGroup, ElRadioButton, ElInput } from "element-plus";
 
 interface Prop {
-  background: {
+  value: {
     type: "none" | "color" | "image";
     color?: string;
     image?: string;
@@ -35,7 +35,7 @@ interface Prop {
   filterOptions?: string[];
 }
 const props = withDefaults(defineProps<Prop>(), {
-  background: () => ({
+  value: () => ({
     type: "none",
     color: "",
     image: "",
@@ -43,9 +43,9 @@ const props = withDefaults(defineProps<Prop>(), {
   })
 });
 
-const emit = defineEmits(["update:background"]);
+const emit = defineEmits(["update:value"]);
 
-const backgroundObj = ref(props.background);
+const backgroundObj = ref(props.value);
 
 const options = [
   { label: "无", value: "none" },
@@ -63,10 +63,9 @@ const getOptions = computed(() => {
 watch(
   () => backgroundObj.value,
   () => {
-    emit("update:background", backgroundObj.value);
+    emit("update:value", backgroundObj.value);
   }, {
-    deep: true,
-    immediate: true
+    deep: true
   }
 )
 

+ 3 - 2
components/cusForm/src/CusFormItem.vue

@@ -20,7 +20,7 @@
       </CheckboxGroup>
     </template>
     <template v-else-if="item.type === 'backgroundSelect'">
-      <BackgroundSelect v-model:background="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"/>
@@ -85,7 +85,8 @@ watch(
   () => model.value,
   () => {
     emit("update:modelValue", model.value);
-  }
+  },
+  { deep: true }
 )
 
 </script>

+ 58 - 21
components/cusForm/src/FontStyle.vue

@@ -1,22 +1,39 @@
 <template>
   <div class="font-style">
-    <span class="cus-btn" :class="{ 'active-btn': bold }"
-      ><BoldOutlined @click="handleBold"
-    /></span>
-    <span class="cus-btn" :class="{ 'active-btn': italic }"
-      ><ItalicOutlined @click="handleItalic"
-    /></span>
-    <!-- <span class="cus-btn" :class="{ 'active-btn': underline }"
-      ><UnderlineOutlined @click="handleUnderline"
-    /></span> -->
+    <Button size="small" @click="handleShowColorPicker">
+      <span class="cus-btn"
+        ><FontColorsOutlined />
+        <div class="color-block" :style="{ background: color }"></div>
+        <ElColorPicker
+          ref="colorPckerRef"
+          style="width: 0; height: 0; opacity: 0"
+          v-model:value="color"
+          @change="handleColorChange"
+        >
+        </ElColorPicker>
+      </span>
+    </Button>
+
+    <Button size="small" @click="handleBold">
+      <span class="cus-btn" :class="{ 'active-btn': bold }"
+        ><BoldOutlined 
+      /></span>
+    </Button>
+
+    <Button size="small"  @click="handleItalic">
+      <span class="cus-btn" :class="{ 'active-btn': italic }"
+        ><ItalicOutlined
+      /></span>
+    </Button>
+
     <InputNumber
       size="small"
       :value="size"
       :min="12"
       :step="1"
       :precision="0"
-      style="width: 80px"
-      @change="handleChange"
+      style="width: 80px;"
+      @change="handleValueChange"
     >
       <template #addonAfter>px</template>
     </InputNumber>
@@ -28,16 +45,17 @@ import { defineProps, defineEmits, ref } from "vue";
 import {
   BoldOutlined,
   ItalicOutlined,
-  // UnderlineOutlined,
+  FontColorsOutlined,
 } from "@ant-design/icons-vue";
-import { InputNumber } from "ant-design-vue";
+import { InputNumber, Button } from "ant-design-vue";
+import { ElColorPicker } from "element-plus";
 
 const props = defineProps<{
   value: {
     size: number;
     bold: boolean;
     italic: boolean;
-    // underline: boolean;
+    color: string;
   };
 }>();
 
@@ -45,15 +63,16 @@ const emit = defineEmits(["update:value"]);
 
 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 color = ref(props.value?.color);
+const colorPckerRef = ref<InstanceType<typeof ElColorPicker>>();
 
 const handleUpdate = () => {
   emit("update:value", {
     size: size.value,
     bold: bold.value,
     italic: italic.value,
-    // underline: underline.value,
+    color: color.value,
   });
 };
 
@@ -65,14 +84,17 @@ const handleItalic = () => {
   italic.value = !italic.value;
   handleUpdate();
 };
-// const handleUnderline = () => {
-//   underline.value = !underline.value;
-//   handleUpdate();
-// };
-const handleChange = (val: number) => {
+const handleColorChange = (val: string) => {
+  color.value = val;
+  handleUpdate();
+};
+const handleValueChange = (val: number) => {
   size.value = val;
   handleUpdate();
 };
+const handleShowColorPicker = () => {
+  colorPckerRef.value?.show();
+};
 </script>
 
 <style lang="less" scoped>
@@ -83,4 +105,19 @@ const handleChange = (val: number) => {
 .active-btn {
   color: #1890ff;
 }
+.color-block {
+  width: 1em;
+  height: 2px;
+  position: absolute;
+  left: 4px;
+  bottom: 4px;
+  border: solid 1px #666;
+}
+:deep(.ant-btn) {
+  margin-right: 2px;
+  padding: 0 4px;
+}
+:deep(.el-color-picker__trigger) {
+  display: none;
+}
 </style>

+ 34 - 21
components/cusForm/src/index.tsx

@@ -3,7 +3,7 @@ import type { FormInstance } from "ant-design-vue";
 import { ref, computed, watch, defineComponent } from "vue";
 import { Form, Collapse, CollapsePanel } from "ant-design-vue";
 import CusFormItem from "./CusFormItem.vue";
-import { pick } from "lodash";
+import { pick, get } from "lodash-es";
 
 export default defineComponent({
   props: {
@@ -21,13 +21,13 @@ export default defineComponent({
     const formModel = ref<Record<string, any>>({});
     const formRef = ref<FormInstance>();
     // 记录被格式化的数据
-    // const formatFormModel = ref<Record<string, any>>({});
+    const formatFormModel = ref<Record<string, any>>({});
 
     const formItems = computed(() => {
       return props.columns.map((item) => {
         return {
           ...item,
-          rules: item.rules || [],
+          rules: item?.rules || [],
         };
       });
     });
@@ -45,26 +45,32 @@ export default defineComponent({
           setFormModel(list);
         } else {
           if (item.type === "divider") return;
-          formModel.value[item.prop] = item?.defaultValue;
+          // 获取初始值 先从formModel中取,没有则取默认值
+          const value = get(props.formModel, item.prop);
+          // 表单的值需要转换成把option值转换成表单值
+          formModel.value[item.prop] = item?.valueToForm
+            ? item.valueToForm(value, props.formModel)
+            : value ?? item.defaultValue;
+          if (item.format) {
+            item.format(formatFormModel, formModel.value[item.prop]);
+          } else {
+            formatFormModel.value[item.prop] = value ?? item.defaultValue;
+          }
         }
       });
     };
 
-    watch(
-      () => formItems.value,
-      (val) => {
-        if (val) setFormModel(val);
-      },
-      { immediate: true }
-    );
-
-    watch(
-      () => formModel.value,
-      (val) => {
-        emit("change", val);
-      },
-      { deep: true, immediate: true }
-    );
+    /* 处理修改值 */
+    const handleValueChange = (val: unknown, child: IFormItem) => {
+      formModel.value[child.prop] = val;
+      // 根据传入转换方法,格式化数据
+      if (child.format) {
+        child.format(formatFormModel, val);
+      } else {
+        formatFormModel.value[child.prop] = val;
+      }
+      emit("change", formatFormModel.value);
+    };
 
     /* 单个表单项 */
     const getItem = (child: IFormItem) => {
@@ -74,7 +80,6 @@ export default defineComponent({
             pick(formModel.value, child.name || []),
             formModel
           );
-          if (list) setFormModel(list);
           return getFormItems(list);
         }
         case "group": {
@@ -87,7 +92,7 @@ export default defineComponent({
               item={child}
               modelValue={formModel.value[child.prop]}
               onUpdate:modelValue={(val: any) => {
-                formModel.value[child.prop] = val;
+                handleValueChange(val, child);
               }}
             />
           );
@@ -119,6 +124,14 @@ export default defineComponent({
       });
     };
 
+    watch(
+      () => formItems.value,
+      (val) => {
+        if (val) setFormModel(val);
+      },
+      { immediate: true }
+    );
+
     return () => (
       <Form
         model={formModel}

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

@@ -56,6 +56,8 @@ export interface IFormItem {
   name?: string[]; 
   // 格式化数据
   format?: (formatModel: Ref<Record<string, any>>, value: any) => void;
+  // 值转表单值
+  valueToForm?: (value: any, model?: Record<string, any>) => any;
 }
 
 

+ 1 - 2
components/index.ts

@@ -2,10 +2,9 @@ import type { App } from 'vue';
 import { components } from './components';
 export * from './components';
 
-export type ComponentType = keyof typeof components;
 export const install = function (app: App) {
   Object.keys(components).forEach(key => {
-    const component = components[key as keyof typeof components] as { install?: (app: App<any>) => any };
+    const component = components[key];
     if (component?.install) {
       console.log('注册组件:', key);
       app.use(component as any);

+ 1 - 0
components/text/Title/index.ts

@@ -2,6 +2,7 @@ import Title from './src/index.vue';
 import Config from './src/Config.vue';
 
 Title.Config = Config;
+/* istanbul ignore next */
 Title.install = (app: any) => {
   app.component('FmDashboardTitle', Title);
   return app;

+ 87 - 1
lib/demo.html

@@ -1 +1,87 @@
-<!doctype html><meta charset="utf-8"><title>shaluDashBoardUi demo</title><script src="./shaluDashBoardUi.umd.js"></script><link rel="stylesheet" href="./shaluDashBoardUi.css"><script>console.log(shaluDashBoardUi)</script>
+<!DOCTYPE html><meta charset="utf-8" /><title>shaluDashBoardUi demo</title>
+<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
+<script src="./shaluDashBoardUi.umd.js"></script>
+<link rel="stylesheet" href="./shaluDashBoardUi.css" />
+<body>
+  <div id="app">
+    <fm-dashboard-basic-bar
+      :width="400"
+      :height="300"
+      :dataSource="dataSource"
+      v-bind="other"
+    />
+  </div>
+  <script>
+    Vue.createApp({
+      data() {
+        return {
+          message: "hello",
+          dataSource: {
+            sourceType: 0,
+            data: {
+              xData: ["轴标签A", "轴标签B", "轴标签C", "轴标签D"],
+              series: [
+                {
+                  type: "bar",
+                  name: "系列1",
+                  data: [89.3, 92.1, 94.4, 85.4],
+                },
+                {
+                  type: "bar",
+                  name: "系列2",
+                  data: [95.8, 89.4, 91.2, 76.9],
+                },
+              ],
+            },
+          },
+          other: {
+            title: {
+              left: "center",
+              top: 8,
+              textStyle: {
+                color: "#fff",
+                fontSize: 16,
+              },
+            },
+            // 图例
+            legend: {
+              textStyle: {
+                color: "#fff",
+              },
+              top: 32,
+            },
+            // 布局
+            grid: {
+              bottom: 34,
+              right: 20,
+              top: 60,
+            },
+            // 提示框
+            tooltip: {},
+            // x轴
+            xAxis: {
+              type: "category",
+              axisLabel: {
+                color: "#9fadbf",
+              },
+            },
+            // y轴
+            yAxis: {
+              axisLabel: {
+                color: "#9fadbf",
+              },
+              splitLine: {
+                lineStyle: {
+                  type: "dashed",
+                  color: "#36485f",
+                },
+              },
+            },
+          },
+        };
+      },
+    })
+      .use(shaluDashBoardUi)
+      .mount("#app");
+  </script>
+</body>

Diferenças do arquivo suprimidas por serem muito extensas
+ 455 - 309
lib/shaluDashBoardUi.common.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
lib/shaluDashBoardUi.common.js.map


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
lib/shaluDashBoardUi.css


Diferenças do arquivo suprimidas por serem muito extensas
+ 455 - 309
lib/shaluDashBoardUi.umd.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
lib/shaluDashBoardUi.umd.js.map


Diferenças do arquivo suprimidas por serem muito extensas
+ 9 - 9
lib/shaluDashBoardUi.umd.min.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
lib/shaluDashBoardUi.umd.min.js.map


+ 20 - 2
package.json

@@ -2,6 +2,9 @@
   "name": "shalu-dashboard-ui",
   "version": "1.0.0",
   "private": true,
+  "main": "index.js",
+  "module": "index.js",
+  "typings": "./typings/global.d.ts",
   "scripts": {
     "serve": "vue-cli-service serve",
     "build": "vue-cli-service build --target lib --name shaluDashBoardUi --dest lib index.js --inline-vue",
@@ -13,7 +16,7 @@
     "@vueuse/core": "^10.11.0",
     "core-js": "^3.8.3",
     "echarts": "^5.5.1",
-    "lodash": "^4.17.21"
+    "lodash-es": "^4.17.21"
   },
   "devDependencies": {
     "@ant-design/icons-vue": "^7.0.1",
@@ -71,7 +74,8 @@
       "ecmaVersion": 2020
     },
     "rules": {
-      "vue/multi-word-component-names": "off"
+      "vue/multi-word-component-names": "off",
+      "@typescript-eslint/no-implicit-any-catch": "off"
     },
     "overrides": [
       {
@@ -82,6 +86,20 @@
         "env": {
           "jest": true
         }
+      },
+      {
+        "files": [
+          "**/*.umd.js"
+        ],
+        "rules": {
+          "@typescript-eslint/explicit-module-boundary-types": "off",
+          "@typescript-eslint/no-extra-semi": "off",
+          "@typescript-eslint/no-this-alias": "off",
+          "no-empty": "off",
+          "no-fallthrough": "off",
+          "no-unused-vars": "off",
+          "@typescript-eslint/no-empty-function": "off"
+        }
       }
     ]
   },

+ 2 - 2
pnpm-lock.yaml

@@ -17,7 +17,7 @@ dependencies:
   echarts:
     specifier: ^5.5.1
     version: 5.5.1
-  lodash:
+  lodash-es:
     specifier: ^4.17.21
     version: 4.17.21
 
@@ -7495,7 +7495,6 @@ packages:
 
   /lodash-es@4.17.21:
     resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
-    dev: true
 
   /lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21):
     resolution: {integrity: sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==}
@@ -7543,6 +7542,7 @@ packages:
 
   /lodash@4.17.21:
     resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+    dev: true
 
   /log-symbols@4.1.0:
     resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}

+ 1 - 2
public/index.html

@@ -15,6 +15,5 @@
     <div id="app"></div>
     <!-- built files will be auto injected -->
   </body>
-  <script src="./shalu-dashboard-ui.umd.js"></script>
-  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
+  <!-- <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> -->
 </html>

+ 3 - 1
tsconfig.json

@@ -12,10 +12,12 @@
     "forceConsistentCasingInFileNames": true,
     "useDefineForClassFields": true,
     "sourceMap": true,
+    "allowJs": true,
     "baseUrl": ".",
     "types": [
       "webpack-env",
-      "jest"
+      "jest",
+      "vue"
     ],
     "paths": {
       "@/*": [

+ 8 - 1
types/index.d.ts

@@ -1 +1,8 @@
-declare type Recordable<T = any> = Record<string, T>;
+declare type Recordable<T = any> = Record<string, T>;
+
+declare module '*.umd.js' {
+  const value: any;
+  export default value;
+}
+
+declare module 'lodash';

typing/global.d.ts → typings/global.d.ts


+ 1 - 0
vue.config.js

@@ -1,4 +1,5 @@
 const { defineConfig } = require("@vue/cli-service");
 module.exports = defineConfig({
   transpileDependencies: true,
+  // lintOnSave: false
 });