Browse Source

feat: 添加表单示例,可通过`JSON`格式配置生成 (#999)

* feat: 添加表单示例,可通过`JSON`格式配置生成
xiaoming 1 year ago
parent
commit
9e0518319b

+ 1 - 0
locales/en.yaml

@@ -131,6 +131,7 @@ menus:
   hsSensitive: Sensitive Filter
   hsPinyin: PinYin
   hsdanmaku: Danmaku
+  hsSchemaForm: Form
   hsPureTableBase: Base Usage
   hsPureTableHigh: High Usage
   hsPureTableEdit: Edit Usage

+ 2 - 1
locales/zh-CN.yaml

@@ -116,7 +116,7 @@ menus:
   hsIconSelect: 图标选择器
   hsTimeline: 时间线
   hsLineTree: 树形连接线
-  hsList: 列表页
+  hsList: 列表页
   hsListCard: 卡片列表页
   hsDebounce: 防抖节流
   hsFormDesign: 表单设计器
@@ -131,6 +131,7 @@ menus:
   hsSensitive: 敏感词过滤
   hsPinyin: 汉语拼音
   hsdanmaku: 弹幕
+  hsSchemaForm: 表单
   hsPureTableBase: 基础用法
   hsPureTableHigh: 高级用法
   hsPureTableEdit: 可编辑用法

+ 1 - 1
package.json

@@ -81,7 +81,7 @@
     "path": "^0.12.7",
     "pinia": "^2.1.7",
     "pinyin-pro": "^3.19.6",
-    "plus-pro-components": "^0.0.2",
+    "plus-pro-components": "^0.0.5",
     "qrcode": "^1.5.3",
     "qs": "^6.12.0",
     "responsive-storage": "^2.2.0",

File diff suppressed because it is too large
+ 203 - 197
pnpm-lock.yaml


+ 6 - 2
src/App.vue

@@ -9,9 +9,11 @@
 import { defineComponent } from "vue";
 import { checkVersion } from "version-rocket";
 import { ElConfigProvider } from "element-plus";
-import en from "element-plus/dist/locale/en.mjs";
 import { ReDialog } from "@/components/ReDialog";
+import en from "element-plus/dist/locale/en.mjs";
 import zhCn from "element-plus/dist/locale/zh-cn.mjs";
+import plusEn from "plus-pro-components/locale/en.mjs";
+import plusZhCn from "plus-pro-components/locale/zh-cn.mjs";
 
 export default defineComponent({
   name: "app",
@@ -21,7 +23,9 @@ export default defineComponent({
   },
   computed: {
     currentLocale() {
-      return this.$storage.locale?.locale === "zh" ? zhCn : en;
+      return this.$storage.locale?.locale === "zh"
+        ? { ...zhCn, ...plusZhCn }
+        : { ...en, ...plusEn };
     }
   },
   beforeCreate() {

+ 2 - 0
src/components/ReIcon/src/offlineIcon.ts

@@ -38,6 +38,7 @@ import SystemLog from "@iconify-icons/ri/file-search-line";
 import ListCheck from "@iconify-icons/ri/list-check";
 import UbuntuFill from "@iconify-icons/ri/ubuntu-fill";
 import OnlineUser from "@iconify-icons/ri/user-voice-line";
+import EditBoxLine from "@iconify-icons/ri/edit-box-line";
 import OperationLog from "@iconify-icons/ri/history-fill";
 import InformationLine from "@iconify-icons/ri/information-line";
 import TerminalWindowLine from "@iconify-icons/ri/terminal-window-line";
@@ -60,6 +61,7 @@ addIcon("ri:artboard-line", Artboard);
 addIcon("ri:list-check", ListCheck);
 addIcon("ri:ubuntu-fill", UbuntuFill);
 addIcon("ri:user-voice-line", OnlineUser);
+addIcon("ri:edit-box-line", EditBoxLine);
 addIcon("ri:history-fill", OperationLog);
 addIcon("ri:information-line", InformationLine);
 addIcon("ri:terminal-window-line", TerminalWindowLine);

+ 19 - 17
src/router/enums.ts

@@ -6,23 +6,24 @@ const home = 0, // 平台规定只有 home 路由的 rank 才能为 0 ,所以
   components = 3,
   able = 4,
   table = 5,
-  list = 6,
-  result = 7,
-  error = 8,
-  frame = 9,
-  nested = 10,
-  permission = 11,
-  system = 12,
-  monitor = 13,
-  tabs = 14,
-  about = 15,
-  editor = 16,
-  flowchart = 17,
-  formdesign = 18,
-  board = 19,
-  ppt = 20,
-  guide = 21,
-  menuoverflow = 22;
+  form = 6,
+  list = 7,
+  result = 8,
+  error = 9,
+  frame = 10,
+  nested = 11,
+  permission = 12,
+  system = 13,
+  monitor = 14,
+  tabs = 15,
+  about = 16,
+  editor = 17,
+  flowchart = 18,
+  formdesign = 19,
+  board = 20,
+  ppt = 21,
+  guide = 22,
+  menuoverflow = 23;
 
 export {
   home,
@@ -31,6 +32,7 @@ export {
   components,
   able,
   table,
+  form,
   list,
   result,
   error,

+ 23 - 0
src/router/modules/form.ts

@@ -0,0 +1,23 @@
+import { $t } from "@/plugins/i18n";
+import { form } from "@/router/enums";
+
+export default {
+  path: "/form",
+  redirect: "/form/index",
+  meta: {
+    icon: "ri:edit-box-line",
+    title: $t("menus.hsSchemaForm"),
+    rank: form
+  },
+  children: [
+    {
+      path: "/form/index",
+      name: "SchemaForm",
+      component: () => import("@/views/schema-form/index.vue"),
+      meta: {
+        title: $t("menus.hsSchemaForm"),
+        extraIcon: "IF-pure-iconfont-new svg"
+      }
+    }
+  ]
+} satisfies RouteConfigsTable;

+ 1 - 1
src/views/components/check-card.vue

@@ -1,8 +1,8 @@
 <script setup lang="ts">
 import { ref, watch } from "vue";
 // https://plus-pro-components.com/components/check-card-group.html
-import { PlusCheckCardGroup } from "plus-pro-components";
 import "plus-pro-components/es/components/check-card-group/style/css";
+import { PlusCheckCardGroup } from "plus-pro-components";
 
 defineOptions({
   name: "CheckCard"

+ 162 - 0
src/views/schema-form/form/base.vue

@@ -0,0 +1,162 @@
+<script setup lang="ts">
+import { ref } from "vue";
+// https://plus-pro-components.com/components/form.html
+import "plus-pro-components/es/components/form/style/css";
+import {
+  type PlusColumn,
+  type FieldValues,
+  PlusForm
+} from "plus-pro-components";
+
+const state = ref<FieldValues>({
+  status: "1",
+  name: "",
+  rate: 4,
+  progress: 100,
+  switch: true,
+  time: new Date().toString(),
+  endTime: []
+});
+
+const rules = {
+  name: [
+    {
+      required: true,
+      message: "请输入名称"
+    }
+  ]
+};
+
+const columns: PlusColumn[] = [
+  {
+    label: "名称",
+    width: 120,
+    prop: "name",
+    valueType: "copy",
+    tooltip: "我是名称"
+  },
+  {
+    label: "状态",
+    width: 120,
+    prop: "status",
+    valueType: "select",
+    options: [
+      {
+        label: "未解决",
+        value: "0",
+        color: "red"
+      },
+      {
+        label: "已解决",
+        value: "1",
+        color: "blue"
+      },
+      {
+        label: "解决中",
+        value: "2",
+        color: "yellow"
+      },
+      {
+        label: "失败",
+        value: "3",
+        color: "red"
+      }
+    ]
+  },
+  {
+    label: "执行进度",
+    width: 200,
+    prop: "progress"
+  },
+  {
+    label: "评分",
+    width: 200,
+    prop: "rate",
+    valueType: "rate"
+  },
+  {
+    label: "是否显示",
+    width: 100,
+    prop: "switch",
+    valueType: "switch"
+  },
+  {
+    label: "时间",
+    prop: "time",
+    valueType: "date-picker"
+  },
+  {
+    label: "数量",
+    prop: "number",
+    valueType: "input-number",
+    fieldProps: { precision: 2, step: 2 }
+  },
+  {
+    label: "梦想",
+    prop: "gift",
+    valueType: "radio",
+    options: [
+      {
+        label: "诗",
+        value: "0"
+      },
+      {
+        label: "远方",
+        value: "1"
+      },
+      {
+        label: "美食",
+        value: "2"
+      }
+    ]
+  },
+  {
+    label: "到期时间",
+    prop: "endTime",
+    valueType: "date-picker",
+    fieldProps: {
+      type: "datetimerange",
+      startPlaceholder: "请选择开始时间",
+      endPlaceholder: "请选择结束时间"
+    }
+  },
+  {
+    label: "说明",
+    prop: "desc",
+    valueType: "textarea",
+    fieldProps: {
+      maxlength: 10,
+      showWordLimit: true,
+      // @ts-expect-error
+      autosize: { minRows: 2, maxRows: 4 }
+    }
+  }
+];
+
+const handleChange = (values: FieldValues, prop: PlusColumn) => {
+  console.log(values, prop, "change");
+};
+const handleSubmit = (values: FieldValues) => {
+  console.log(values, "Submit");
+};
+const handleSubmitError = (err: any) => {
+  console.log(err, "err");
+};
+const handleReset = () => {
+  console.log("handleReset");
+};
+</script>
+
+<template>
+  <PlusForm
+    v-model="state"
+    class="w-[450px] m-auto"
+    :columns="columns"
+    :rules="rules"
+    label-position="right"
+    @change="handleChange"
+    @submit="handleSubmit"
+    @submit-error="handleSubmitError"
+    @reset="handleReset"
+  />
+</template>

+ 206 - 0
src/views/schema-form/form/dialog.vue

@@ -0,0 +1,206 @@
+<script setup lang="ts">
+import { ref } from "vue";
+// https://plus-pro-components.com/components/dialog-form.html
+import "plus-pro-components/es/components/dialog-form/style/css";
+import {
+  type PlusColumn,
+  type FieldValues,
+  PlusDialogForm
+} from "plus-pro-components";
+
+const columns: PlusColumn[] = [
+  {
+    label: "名称",
+    width: 120,
+    prop: "name",
+    valueType: "copy",
+    tooltip: "名称最多显示6个字符"
+  },
+  {
+    label: "状态",
+    width: 120,
+    prop: "status",
+    valueType: "select",
+    options: [
+      {
+        label: "未解决",
+        value: "0",
+        color: "red"
+      },
+      {
+        label: "已解决",
+        value: "1",
+        color: "blue"
+      },
+      {
+        label: "解决中",
+        value: "2",
+        color: "yellow"
+      },
+      {
+        label: "失败",
+        value: "3",
+        color: "red"
+      }
+    ]
+  },
+  {
+    label: "是否显示",
+    width: 100,
+    prop: "switch",
+    valueType: "switch"
+  },
+
+  {
+    label: "时间",
+    prop: "time",
+    valueType: "date-picker"
+  },
+  {
+    label: "数量",
+    prop: "number",
+    valueType: "input-number",
+    fieldProps: { precision: 2, step: 2 }
+  },
+  {
+    label: "城市",
+    prop: "city",
+    valueType: "cascader",
+    options: [
+      {
+        value: "0",
+        label: "陕西",
+        children: [
+          {
+            value: "0-0",
+            label: "西安",
+            children: [
+              {
+                value: "0-0-0",
+                label: "新城区"
+              },
+              {
+                value: "0-0-1",
+                label: "高新区"
+              },
+              {
+                value: "0-0-2",
+                label: "灞桥区"
+              }
+            ]
+          }
+        ]
+      },
+      {
+        value: "1",
+        label: "山西",
+        children: [
+          {
+            value: "1-0",
+            label: "太原",
+            children: [
+              {
+                value: "1-0-0",
+                label: "小店区"
+              },
+              {
+                value: "1-0-1",
+                label: "古交市"
+              },
+              {
+                value: "1-0-2",
+                label: "万柏林区"
+              }
+            ]
+          }
+        ]
+      }
+    ]
+  },
+  {
+    label: "地区",
+    prop: "place",
+    tooltip: "请精确到门牌号",
+    fieldProps: {
+      placeholder: "请精确到门牌号"
+    }
+  },
+  {
+    label: "要求",
+    prop: "demand",
+    valueType: "checkbox",
+    options: [
+      {
+        label: "四六级",
+        value: "0"
+      },
+      {
+        label: "计算机二级证书",
+        value: "1"
+      },
+      {
+        label: "普通话证书",
+        value: "2"
+      }
+    ]
+  },
+  {
+    label: "梦想",
+    prop: "gift",
+    valueType: "radio",
+    options: [
+      {
+        label: "诗",
+        value: "0"
+      },
+      {
+        label: "远方",
+        value: "1"
+      },
+      {
+        label: "美食",
+        value: "2"
+      }
+    ]
+  },
+  {
+    label: "到期时间",
+    prop: "endTime",
+    valueType: "date-picker",
+    fieldProps: {
+      type: "datetimerange",
+      startPlaceholder: "请选择开始时间",
+      endPlaceholder: "请选择结束时间"
+    }
+  },
+  {
+    label: "说明",
+    prop: "desc",
+    valueType: "textarea",
+    fieldProps: {
+      maxlength: 10,
+      showWordLimit: true,
+      // @ts-expect-error
+      autosize: { minRows: 2, maxRows: 4 }
+    }
+  }
+];
+
+const visible = ref(false);
+const values = ref<FieldValues>({});
+
+const handleOpen = () => {
+  visible.value = true;
+};
+</script>
+
+<template>
+  <div>
+    <el-button @click="handleOpen">打开弹窗表单</el-button>
+    <PlusDialogForm
+      v-model:visible="visible"
+      v-model="values"
+      :form="{ columns }"
+    />
+  </div>
+</template>

+ 206 - 0
src/views/schema-form/form/drawer.vue

@@ -0,0 +1,206 @@
+<script setup lang="ts">
+import { ref } from "vue";
+// https://plus-pro-components.com/components/drawer-form.html
+import "plus-pro-components/es/components/drawer-form/style/css";
+import {
+  type PlusColumn,
+  type FieldValues,
+  PlusDrawerForm
+} from "plus-pro-components";
+
+const columns: PlusColumn[] = [
+  {
+    label: "名称",
+    width: 120,
+    prop: "name",
+    valueType: "copy",
+    tooltip: "名称最多显示6个字符"
+  },
+  {
+    label: "状态",
+    width: 120,
+    prop: "status",
+    valueType: "select",
+    options: [
+      {
+        label: "未解决",
+        value: "0",
+        color: "red"
+      },
+      {
+        label: "已解决",
+        value: "1",
+        color: "blue"
+      },
+      {
+        label: "解决中",
+        value: "2",
+        color: "yellow"
+      },
+      {
+        label: "失败",
+        value: "3",
+        color: "red"
+      }
+    ]
+  },
+  {
+    label: "是否显示",
+    width: 100,
+    prop: "switch",
+    valueType: "switch"
+  },
+
+  {
+    label: "时间",
+    prop: "time",
+    valueType: "date-picker"
+  },
+  {
+    label: "数量",
+    prop: "number",
+    valueType: "input-number",
+    fieldProps: { precision: 2, step: 2 }
+  },
+  {
+    label: "城市",
+    prop: "city",
+    valueType: "cascader",
+    options: [
+      {
+        value: "0",
+        label: "陕西",
+        children: [
+          {
+            value: "0-0",
+            label: "西安",
+            children: [
+              {
+                value: "0-0-0",
+                label: "新城区"
+              },
+              {
+                value: "0-0-1",
+                label: "高新区"
+              },
+              {
+                value: "0-0-2",
+                label: "灞桥区"
+              }
+            ]
+          }
+        ]
+      },
+      {
+        value: "1",
+        label: "山西",
+        children: [
+          {
+            value: "1-0",
+            label: "太原",
+            children: [
+              {
+                value: "1-0-0",
+                label: "小店区"
+              },
+              {
+                value: "1-0-1",
+                label: "古交市"
+              },
+              {
+                value: "1-0-2",
+                label: "万柏林区"
+              }
+            ]
+          }
+        ]
+      }
+    ]
+  },
+  {
+    label: "地区",
+    prop: "place",
+    tooltip: "请精确到门牌号",
+    fieldProps: {
+      placeholder: "请精确到门牌号"
+    }
+  },
+  {
+    label: "要求",
+    prop: "demand",
+    valueType: "checkbox",
+    options: [
+      {
+        label: "四六级",
+        value: "0"
+      },
+      {
+        label: "计算机二级证书",
+        value: "1"
+      },
+      {
+        label: "普通话证书",
+        value: "2"
+      }
+    ]
+  },
+  {
+    label: "梦想",
+    prop: "gift",
+    valueType: "radio",
+    options: [
+      {
+        label: "诗",
+        value: "0"
+      },
+      {
+        label: "远方",
+        value: "1"
+      },
+      {
+        label: "美食",
+        value: "2"
+      }
+    ]
+  },
+  {
+    label: "到期时间",
+    prop: "endTime",
+    valueType: "date-picker",
+    fieldProps: {
+      type: "datetimerange",
+      startPlaceholder: "请选择开始时间",
+      endPlaceholder: "请选择结束时间"
+    }
+  },
+  {
+    label: "说明",
+    prop: "desc",
+    valueType: "textarea",
+    fieldProps: {
+      maxlength: 10,
+      showWordLimit: true,
+      // @ts-expect-error
+      autosize: { minRows: 2, maxRows: 4 }
+    }
+  }
+];
+
+const visible = ref(false);
+const values = ref<FieldValues>({});
+
+const handleOpen = () => {
+  visible.value = true;
+};
+</script>
+
+<template>
+  <div>
+    <el-button @click="handleOpen">打开抽屉表单</el-button>
+    <PlusDrawerForm
+      v-model:visible="visible"
+      v-model="values"
+      :form="{ columns }"
+    />
+  </div>
+</template>

+ 162 - 0
src/views/schema-form/form/search.vue

@@ -0,0 +1,162 @@
+<script setup lang="ts">
+import { ref } from "vue";
+// https://plus-pro-components.com/components/search.html
+import "plus-pro-components/es/components/search/style/css";
+import { type PlusColumn, PlusSearch } from "plus-pro-components";
+
+const state = ref({
+  status: "0",
+  time: new Date().toString()
+});
+
+const columns: PlusColumn[] = [
+  {
+    label: "名称",
+    prop: "name",
+    valueType: "copy",
+    tooltip: "名称最多显示6个字符"
+  },
+  {
+    label: "状态",
+    prop: "status",
+    valueType: "select",
+    options: [
+      {
+        label: "未解决",
+        value: "0",
+        color: "red"
+      },
+      {
+        label: "已解决",
+        value: "1",
+        color: "blue"
+      },
+      {
+        label: "解决中",
+        value: "2",
+        color: "yellow"
+      },
+      {
+        label: "失败",
+        value: "3",
+        color: "red"
+      }
+    ]
+  },
+  {
+    label: "时间",
+    prop: "time",
+    valueType: "date-picker"
+  },
+  {
+    label: "数量",
+    prop: "number",
+    valueType: "input-number",
+    fieldProps: { precision: 2, step: 2 }
+  },
+  {
+    label: "城市",
+    prop: "city",
+    valueType: "cascader",
+    options: [
+      {
+        value: "0",
+        label: "陕西",
+        children: [
+          {
+            value: "0-0",
+            label: "西安",
+            children: [
+              {
+                value: "0-0-0",
+                label: "新城区"
+              },
+              {
+                value: "0-0-1",
+                label: "高新区"
+              },
+              {
+                value: "0-0-2",
+                label: "灞桥区"
+              }
+            ]
+          }
+        ]
+      },
+      {
+        value: "1",
+        label: "山西",
+        children: [
+          {
+            value: "1-0",
+            label: "太原",
+            children: [
+              {
+                value: "1-0-0",
+                label: "小店区"
+              },
+              {
+                value: "1-0-1",
+                label: "古交市"
+              },
+              {
+                value: "1-0-2",
+                label: "万柏林区"
+              }
+            ]
+          }
+        ]
+      }
+    ]
+  },
+  {
+    label: "地区",
+    prop: "place",
+    tooltip: "请精确到门牌号",
+    fieldProps: {
+      placeholder: "请精确到门牌号"
+    }
+  },
+  {
+    label: "到期时间",
+    prop: "endTime",
+    valueType: "date-picker",
+    fieldProps: {
+      type: "datetimerange",
+      startPlaceholder: "请选择",
+      endPlaceholder: "请选择"
+    }
+  },
+  {
+    label: "奖励",
+    prop: "price"
+  },
+  {
+    label: "提成",
+    prop: "percentage"
+  }
+];
+
+const handleChange = (values: any) => {
+  console.log(values, "change");
+};
+const handleSearch = (values: any) => {
+  console.log(values, "search");
+};
+const handleRest = () => {
+  console.log("handleRest");
+};
+</script>
+
+<template>
+  <PlusSearch
+    v-model="state"
+    :columns="columns"
+    :show-number="2"
+    label-width="80"
+    label-position="right"
+    @change="handleChange"
+    @search="handleSearch"
+    @reset="handleRest"
+  />
+</template>

+ 204 - 0
src/views/schema-form/form/steps.vue

@@ -0,0 +1,204 @@
+<script setup lang="ts">
+import { ref } from "vue";
+// https://plus-pro-components.com/components/steps-form.html
+import "plus-pro-components/es/components/steps-form/style/css";
+import { PlusStepsForm } from "plus-pro-components";
+
+const stepForm = ref([
+  {
+    title: "第一步",
+    form: {
+      labelPosition: "top",
+      style: {
+        width: "400px",
+        margin: "40px auto"
+      },
+      modelValue: {},
+      columns: [
+        {
+          label: "名称",
+          width: 120,
+          prop: "name",
+          valueType: "copy",
+          tooltip: "名称最多显示6个字符"
+        },
+        {
+          label: "状态",
+          width: 120,
+          prop: "status",
+          valueType: "select",
+          options: [
+            {
+              label: "未解决",
+              value: "0",
+              color: "red"
+            },
+            {
+              label: "已解决",
+              value: "1",
+              color: "blue"
+            },
+            {
+              label: "解决中",
+              value: "2",
+              color: "yellow"
+            },
+            {
+              label: "失败",
+              value: "3",
+              color: "red"
+            }
+          ]
+        }
+      ],
+      rules: {
+        name: [
+          {
+            required: true,
+            message: "请输入名称"
+          }
+        ]
+      }
+    }
+  },
+  {
+    title: "第二步",
+    form: {
+      labelPosition: "top",
+      style: {
+        width: "400px",
+        margin: "40px auto"
+      },
+      labelWidth: "100",
+      modelValue: {},
+      columns: [
+        {
+          label: "标签",
+          width: 120,
+          prop: "tag"
+        },
+        {
+          label: "执行进度",
+          width: 200,
+          prop: "progress"
+        },
+        {
+          label: "评分",
+          width: 200,
+          prop: "rate",
+          valueType: "rate"
+        },
+        {
+          label: "是否显示",
+          width: 100,
+          prop: "switch",
+          valueType: "switch"
+        }
+      ],
+      rules: {
+        tag: [
+          {
+            required: true,
+            message: "请输入标签"
+          }
+        ],
+        progress: [
+          {
+            required: true,
+            message: "请输入执行进度"
+          }
+        ]
+      }
+    }
+  },
+  {
+    title: "第三步",
+    form: {
+      labelPosition: "top",
+      style: {
+        width: "400px",
+        margin: "40px auto"
+      },
+      modelValue: {},
+      columns: [
+        {
+          label: "时间",
+          prop: "time",
+          valueType: "date-picker"
+        },
+        {
+          label: "要求",
+          prop: "demand",
+          valueType: "checkbox",
+          options: [
+            {
+              label: "四六级",
+              value: "0"
+            },
+            {
+              label: "计算机二级证书",
+              value: "1"
+            },
+            {
+              label: "普通话证书",
+              value: "2"
+            }
+          ]
+        },
+        {
+          label: "奖励",
+          prop: "price"
+        },
+        {
+          label: "提成",
+          prop: "percentage"
+        },
+        {
+          label: "说明",
+          prop: "desc",
+          valueType: "textarea",
+          fieldProps: {
+            maxlength: 10,
+            showWordLimit: true,
+            autosize: { minRows: 2, maxRows: 4 }
+          }
+        }
+      ],
+      rules: {
+        time: [
+          {
+            required: true,
+            trigger: "change",
+            message: "请选择时间"
+          }
+        ],
+        demand: [
+          {
+            required: true,
+            trigger: "change",
+            message: "请选择要求"
+          }
+        ]
+      }
+    }
+  }
+]);
+
+const active = ref(1);
+
+const next = (actives: number, values: any) => {
+  active.value = actives;
+  console.log(active, values, stepForm.value);
+};
+</script>
+
+<template>
+  <PlusStepsForm
+    v-model="active"
+    simple
+    class="w-[800px] m-auto"
+    :data="stepForm"
+    align-center
+    @next="next"
+  />
+</template>

+ 67 - 0
src/views/schema-form/index.vue

@@ -0,0 +1,67 @@
+<script setup lang="ts">
+import { ref } from "vue";
+import { list } from "./list";
+
+defineOptions({
+  name: "SchemaForm"
+});
+
+const selected = ref(0);
+
+function tabClick({ index }) {
+  selected.value = index;
+}
+</script>
+
+<template>
+  <el-card shadow="never" :body-style="{ height: 'calc(100vh - 180px)' }">
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium">
+          JSON 格式配置表单,采用优秀开源的
+          <el-link
+            href="https://plus-pro-components.com/components/form.html"
+            target="_blank"
+            style="margin: 0 4px 5px; font-size: 16px"
+          >
+            PlusProComponents
+          </el-link>
+          ,维护整体表单只需操作 columns 配置即可
+        </span>
+      </div>
+    </template>
+
+    <el-tabs @tab-click="tabClick">
+      <template v-for="(item, index) of list" :key="item.key">
+        <el-tab-pane :lazy="true">
+          <template #label>
+            <el-tooltip
+              :content="`(第 ${index + 1} 个示例)${item.content}`"
+              placement="top-end"
+            >
+              <span>{{ item.title }}</span>
+            </el-tooltip>
+          </template>
+          <component :is="item.component" v-if="selected == index" />
+        </el-tab-pane>
+      </template>
+    </el-tabs>
+  </el-card>
+</template>
+
+<style scoped>
+:deep(.el-tabs__nav-wrap)::after {
+  height: 1px;
+}
+
+:deep(.el-tabs__nav-next),
+:deep(.el-tabs__nav-prev) {
+  font-size: 16px;
+  color: var(--el-text-color-primary);
+}
+
+:deep(.el-tabs__nav-next.is-disabled),
+:deep(.el-tabs__nav-prev.is-disabled) {
+  opacity: 0.5;
+}
+</style>

+ 41 - 0
src/views/schema-form/list.tsx

@@ -0,0 +1,41 @@
+import Base from "./form/base.vue";
+import Dialog from "./form/dialog.vue";
+import Drawer from "./form/drawer.vue";
+import Steps from "./form/steps.vue";
+import Search from "./form/search.vue";
+
+const rendContent = (val: string) =>
+  `代码位置:src/views/schema-form/form/${val}.vue`;
+
+export const list = [
+  {
+    key: "base",
+    content: rendContent("base"),
+    title: "基础表单",
+    component: Base
+  },
+  {
+    key: "dialog",
+    content: rendContent("dialog"),
+    title: "弹框表单",
+    component: Dialog
+  },
+  {
+    key: "drawer",
+    content: rendContent("drawer"),
+    title: "抽屉表单",
+    component: Drawer
+  },
+  {
+    key: "steps",
+    content: rendContent("steps"),
+    title: "分步表单",
+    component: Steps
+  },
+  {
+    key: "search",
+    content: rendContent("search"),
+    title: "搜索表单",
+    component: Search
+  }
+];

+ 2 - 0
types/shims-vue.d.ts

@@ -14,3 +14,5 @@ declare module "vue-virtual-scroller";
 declare module "vuedraggable/src/vuedraggable";
 declare module "element-plus/dist/locale/en.mjs";
 declare module "element-plus/dist/locale/zh-cn.mjs";
+declare module "plus-pro-components/locale/en.mjs";
+declare module "plus-pro-components/locale/zh-cn.mjs";

Some files were not shown because too many files changed in this diff