@wanglindoc/elpis 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +52 -0
  3. package/.idea/codeStyles/Project.xml +14 -0
  4. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  5. package/.idea/elpis.iml +12 -0
  6. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  7. package/.idea/modules.xml +8 -0
  8. package/.idea/prettier.xml +7 -0
  9. package/.idea/vcs.xml +6 -0
  10. package/README.md +232 -0
  11. package/app/controller/base.js +42 -0
  12. package/app/controller/project.js +76 -0
  13. package/app/controller/view.js +19 -0
  14. package/app/extend/logger.js +42 -0
  15. package/app/middleware/api-params-verify.js +81 -0
  16. package/app/middleware/api-sign-verify.js +45 -0
  17. package/app/middleware/error-handler.js +41 -0
  18. package/app/middleware/project-handler.js +30 -0
  19. package/app/middleware.js +42 -0
  20. package/app/pages/assets/custom.css +14 -0
  21. package/app/pages/boot.js +51 -0
  22. package/app/pages/common/curl.js +91 -0
  23. package/app/pages/common/utils.js +7 -0
  24. package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +18 -0
  25. package/app/pages/dashboard/complex-view/header-view/header-view.vue +154 -0
  26. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +46 -0
  27. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +40 -0
  28. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +127 -0
  29. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +22 -0
  30. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +95 -0
  31. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +104 -0
  32. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +129 -0
  33. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +137 -0
  34. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +102 -0
  35. package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu.vue +21 -0
  36. package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +141 -0
  37. package/app/pages/dashboard/dashboard.vue +96 -0
  38. package/app/pages/dashboard/entry.dashboard.js +53 -0
  39. package/app/pages/dashboard/todo/todo.vue +6 -0
  40. package/app/pages/store/index.js +5 -0
  41. package/app/pages/store/menu.js +73 -0
  42. package/app/pages/store/project.js +15 -0
  43. package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
  44. package/app/pages/widgets/header-container/asserts/logo.png +0 -0
  45. package/app/pages/widgets/header-container/header-container.vue +106 -0
  46. package/app/pages/widgets/schema-form/complex-view/input/input.vue +137 -0
  47. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +135 -0
  48. package/app/pages/widgets/schema-form/complex-view/select/select.vue +119 -0
  49. package/app/pages/widgets/schema-form/form-item-config.js +20 -0
  50. package/app/pages/widgets/schema-form/schema-form.vue +145 -0
  51. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +52 -0
  52. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +65 -0
  53. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +42 -0
  54. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +49 -0
  55. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +129 -0
  56. package/app/pages/widgets/schema-search-bar/search-item-config.js +24 -0
  57. package/app/pages/widgets/schema-table/schema-table.vue +212 -0
  58. package/app/pages/widgets/sider-container/sider-container.vue +26 -0
  59. package/app/public/output/entry.page1.tpl +55 -0
  60. package/app/public/output/entry.page2.tpl +11 -0
  61. package/app/public/static/favicon.ico +0 -0
  62. package/app/public/static/normalize.css +267 -0
  63. package/app/router/project.js +14 -0
  64. package/app/router/view.js +9 -0
  65. package/app/router-schema/project.js +32 -0
  66. package/app/service/base.js +15 -0
  67. package/app/service/project.js +48 -0
  68. package/app/view/entry.tpl +22 -0
  69. package/app/webpack/build-dev.js +64 -0
  70. package/app/webpack/build-prod.js +29 -0
  71. package/app/webpack/config/webpack.base.js +352 -0
  72. package/app/webpack/config/webpack.dev.js +59 -0
  73. package/app/webpack/config/webpack.prod.js +145 -0
  74. package/app/webpack/libs/blank.js +1 -0
  75. package/config/config.default.js +4 -0
  76. package/elpis-core/env.js +20 -0
  77. package/elpis-core/index.js +106 -0
  78. package/elpis-core/loader/config.js +62 -0
  79. package/elpis-core/loader/controller.js +79 -0
  80. package/elpis-core/loader/extend.js +67 -0
  81. package/elpis-core/loader/middleware.js +77 -0
  82. package/elpis-core/loader/router-schema.js +57 -0
  83. package/elpis-core/loader/router.js +57 -0
  84. package/elpis-core/loader/service.js +76 -0
  85. package/index.js +39 -0
  86. package/model/index.js +128 -0
  87. package/package.json +90 -0
  88. package/test/controller/project.test.js +243 -0
@@ -0,0 +1,141 @@
1
+ <template>
2
+ <sider-container>
3
+ <template #menu-content>
4
+ <el-menu
5
+ mode="vertical"
6
+ :default-active="activeKey"
7
+ :ellipsis="false"
8
+ @select="onMenuSelect"
9
+ >
10
+ <template v-for="item in menuList">
11
+ <!-- group -->
12
+ <sub-menu
13
+ v-if="item.subMenu && item.subMenu.length > 0"
14
+ :menu-item="item"
15
+ >
16
+ </sub-menu>
17
+
18
+ <!-- module -->
19
+ <el-menu-item v-else :index="item.key"> {{ item.name }}</el-menu-item>
20
+ </template>
21
+ </el-menu>
22
+ </template>
23
+
24
+ <template #main-content>
25
+ <router-view></router-view>
26
+ </template>
27
+ </sider-container>
28
+ </template>
29
+
30
+ <script setup>
31
+ import { onMounted, ref, watch } from "vue";
32
+ import SiderContainer from "../../../widgets/sider-container/sider-container.vue";
33
+ import SubMenu from "./complex-view/sub-menu.vue";
34
+ import { RouterView, useRoute, useRouter } from "vue-router";
35
+ import { useMenuStore } from "$elpisStore/menu.js";
36
+
37
+ const route = useRoute();
38
+ const router = useRouter();
39
+
40
+ const menuStore = useMenuStore();
41
+
42
+ const activeKey = ref("");
43
+ const setActiveKey = function () {
44
+ let siderMenuItem = menuStore.findMenuItem({
45
+ key: "key",
46
+ value: route.query.sider_key,
47
+ });
48
+
49
+ // 如果首次加载 sider-view,用户未选中左侧菜单,需要默认选中第一个
50
+ if (!siderMenuItem) {
51
+ const headerMenuItem = menuStore.findMenuItem({
52
+ key: "key",
53
+ value: route.query.key,
54
+ });
55
+
56
+ if (
57
+ headerMenuItem &&
58
+ headerMenuItem.siderConfig &&
59
+ headerMenuItem.siderConfig.menu
60
+ ) {
61
+ const siderMenuList = headerMenuItem.siderConfig.menu;
62
+ // 找出左侧菜单中的第一项
63
+ siderMenuItem = menuStore.findFirstMenuItem(siderMenuList);
64
+
65
+ if (siderMenuItem) {
66
+ handleMenuSelect(siderMenuItem.key);
67
+ }
68
+ }
69
+ }
70
+
71
+ activeKey.value = siderMenuItem?.key;
72
+ };
73
+
74
+ const menuList = ref([]);
75
+ const setMenuList = function () {
76
+ const menuItem = menuStore.findMenuItem({
77
+ key: "key",
78
+ value: route.query.key,
79
+ });
80
+
81
+ if (menuItem && menuItem.siderConfig && menuItem.siderConfig.menu) {
82
+ menuList.value = menuItem.siderConfig.menu;
83
+ }
84
+ };
85
+
86
+ watch(
87
+ () => route.query.key,
88
+ () => {
89
+ setActiveKey();
90
+ setMenuList();
91
+ },
92
+ );
93
+
94
+ watch(
95
+ () => menuStore.menuList,
96
+ () => {
97
+ setActiveKey();
98
+ setMenuList();
99
+ },
100
+ {
101
+ deep: true,
102
+ },
103
+ );
104
+
105
+ const onMenuSelect = (menuKey) => handleMenuSelect(menuKey);
106
+
107
+ const handleMenuSelect = function (menuKey) {
108
+ const menuItem = menuStore.findMenuItem({
109
+ key: "key",
110
+ value: menuKey,
111
+ });
112
+
113
+ const { moduleType, key, customConfig } = menuItem;
114
+
115
+ if (key === route.query.sider_key) {
116
+ return;
117
+ }
118
+
119
+ const pathMap = {
120
+ iframe: "/iframe",
121
+ schema: "/schema",
122
+ custom: customConfig?.path,
123
+ };
124
+
125
+ router.push({
126
+ path: `/view/dashboard/sider${pathMap[moduleType]}`,
127
+ query: {
128
+ proj_key: route.query.proj_key,
129
+ key: route.query.key,
130
+ sider_key: key,
131
+ },
132
+ });
133
+ };
134
+
135
+ onMounted(() => {
136
+ setActiveKey();
137
+ setMenuList();
138
+ });
139
+ </script>
140
+
141
+ <style scoped lang="less"></style>
@@ -0,0 +1,96 @@
1
+ <template>
2
+ <el-config-provider :locale="zhCn">
3
+ <header-view :proj-name="projName" @menu-select="onMenuSelect">
4
+ <template #main-content>
5
+ <router-view></router-view>
6
+ </template>
7
+ </header-view>
8
+ </el-config-provider>
9
+ </template>
10
+
11
+ <script setup>
12
+ import { onMounted, ref } from "vue";
13
+ import zhCn from "element-plus/es/locale/lang/zh-cn";
14
+ import HeaderView from "./complex-view/header-view/header-view.vue";
15
+ import $curl from "$elpisCommon/curl.js";
16
+ import { useMenuStore } from "$elpisStore/menu";
17
+ import { useProjectStore } from "$elpisStore/project";
18
+ import { RouterView, useRoute, useRouter } from "vue-router";
19
+ const route = useRoute();
20
+ const router = useRouter();
21
+
22
+ const menuStore = useMenuStore();
23
+ const projectStore = useProjectStore();
24
+
25
+ const projName = ref("");
26
+
27
+ /**
28
+ * 请求 /api/project/list 接口 并缓存到 project-store 中
29
+ */
30
+ async function getProjectList() {
31
+ const res = await $curl({
32
+ url: "/api/project/list",
33
+ method: "get",
34
+ query: {
35
+ proj_key: route.query.proj_key,
36
+ },
37
+ });
38
+
39
+ if (!res || !res.success || !res.data) {
40
+ return;
41
+ }
42
+
43
+ projectStore.setProjectList(res.data);
44
+ }
45
+
46
+ /**
47
+ * 请求 /api/project 接口 并缓存到 menu-store 中
48
+ */
49
+ async function getProjectConfig() {
50
+ const res = await $curl({
51
+ url: "/api/project",
52
+ method: "get",
53
+ query: {
54
+ proj_key: route.query.proj_key,
55
+ },
56
+ });
57
+
58
+ if (!res || !res.success || !res.data) {
59
+ return;
60
+ }
61
+
62
+ const { name, menu } = res.data;
63
+
64
+ projName.value = name;
65
+
66
+ menuStore.setMenuList(menu);
67
+ }
68
+
69
+ const onMenuSelect = (menuItem) => {
70
+ const { moduleType, key, customConfig } = menuItem;
71
+
72
+ if (key === route.query.key) return;
73
+
74
+ const pathMap = {
75
+ iframe: "/iframe",
76
+ sider: "/sider",
77
+ schema: "/schema",
78
+ custom: customConfig?.path,
79
+ };
80
+
81
+ router.push({
82
+ path: `/view/dashboard${pathMap[moduleType]}`,
83
+ query: {
84
+ proj_key: route.query.proj_key,
85
+ key,
86
+ },
87
+ });
88
+ };
89
+
90
+ onMounted(() => {
91
+ getProjectList();
92
+ getProjectConfig();
93
+ });
94
+ </script>
95
+
96
+ <style lang="less" scoped></style>
@@ -0,0 +1,53 @@
1
+ import boot from "../boot";
2
+ import dashboard from "./dashboard.vue";
3
+
4
+ // 1.此方式如果 $businessDashboardRouterConfig 在使用方的项目目录下没找到文件,webpack 编译时就会报错
5
+ import businessDashboardRouterConfig from "$businessDashboardRouterConfig"; // 3.所以仍然采用此方式导入,但需要在 webpack 中做文章
6
+
7
+ // 2.try catch 依然无法避免,因为 webpack 是静态构建工具,并不是运行时构建,所以在构建时发现 alias 别名配置,就会去路径下找文件,找不到就抛出错误
8
+ // let businessDashboardRouterConfig;
9
+ // try {
10
+ // businessDashboardRouterConfig = require("$businessDashboardRouterConfig");
11
+ // } catch (error) {}
12
+
13
+ const routes = [];
14
+
15
+ // 头部菜单路由
16
+ routes.push({
17
+ path: "/view/dashboard/iframe",
18
+ component: () => import("./complex-view/iframe-view/iframe-view.vue"),
19
+ });
20
+ routes.push({
21
+ path: "/view/dashboard/schema",
22
+ component: () => import("./complex-view/schema-view/schema-view.vue"),
23
+ });
24
+
25
+ const siderRoutes = [
26
+ {
27
+ path: "iframe",
28
+ component: () => import("./complex-view/iframe-view/iframe-view.vue"),
29
+ },
30
+ {
31
+ path: "schema",
32
+ component: () => import("./complex-view/schema-view/schema-view.vue"),
33
+ },
34
+ ];
35
+
36
+ if (typeof businessDashboardRouterConfig === "function") {
37
+ businessDashboardRouterConfig({ routes, siderRoutes });
38
+ }
39
+
40
+ // 侧边栏菜单路由
41
+ routes.push({
42
+ path: "/view/dashboard/sider",
43
+ component: () => import("./complex-view/sider-view/sider-view.vue"),
44
+ children: siderRoutes,
45
+ });
46
+
47
+ // 侧边栏兜底策略
48
+ routes.push({
49
+ path: "/view/dashboard/sider/:chapters+",
50
+ component: () => import("./complex-view/sider-view/sider-view.vue"),
51
+ });
52
+
53
+ boot(dashboard, { routes });
@@ -0,0 +1,6 @@
1
+ <template>
2
+ <h1>todo</h1>
3
+ </template>
4
+
5
+ <script setup></script>
6
+ <style scoped lang="less"></style>
@@ -0,0 +1,5 @@
1
+ import { createPinia } from "pinia";
2
+
3
+ const pinia = createPinia();
4
+
5
+ export default pinia;
@@ -0,0 +1,73 @@
1
+ import { defineStore } from "pinia";
2
+ import { ref } from "vue";
3
+
4
+ export const useMenuStore = defineStore("menu", () => {
5
+ const menuList = ref([]);
6
+
7
+ const setMenuList = function (list) {
8
+ menuList.value = list;
9
+ };
10
+
11
+ /**
12
+ * 找到菜单目录
13
+ * @param {*} param0
14
+ * @param {*} mList
15
+ */
16
+ const findMenuItem = function ({ key, value }, mList = menuList.value) {
17
+ for (let i = 0; i < mList.length; ++i) {
18
+ const menuItem = mList[i];
19
+
20
+ if (!menuItem) {
21
+ continue;
22
+ }
23
+
24
+ const { menuType, moduleType } = menuItem;
25
+
26
+ if (menuItem[key] === value) {
27
+ return menuItem;
28
+ }
29
+
30
+ if (menuType === "group" && menuItem.subMenu) {
31
+ const mItem = findMenuItem({ key, value }, menuItem.subMenu);
32
+ if (mItem) {
33
+ return mItem;
34
+ }
35
+ }
36
+
37
+ if (
38
+ moduleType === "sider" &&
39
+ menuItem.siderConfig &&
40
+ menuItem.siderConfig.menu
41
+ ) {
42
+ const mItem = findMenuItem({ key, value }, menuItem.siderConfig.menu);
43
+ if (mItem) {
44
+ return mItem;
45
+ }
46
+ }
47
+ }
48
+ };
49
+
50
+ /**
51
+ * 找出第一个菜单目录
52
+ * @param {*} mList 菜单列表
53
+ */
54
+ const findFirstMenuItem = function (mList = menuList.value) {
55
+ if (!mList || !mList[0]) {
56
+ return;
57
+ }
58
+
59
+ let firstMenuItem = mList[0];
60
+ if (firstMenuItem.subMenu) {
61
+ firstMenuItem = findFirstMenuItem(firstMenuItem.subMenu);
62
+ }
63
+
64
+ return firstMenuItem;
65
+ };
66
+
67
+ return {
68
+ menuList,
69
+ setMenuList,
70
+ findMenuItem,
71
+ findFirstMenuItem,
72
+ };
73
+ });
@@ -0,0 +1,15 @@
1
+ import { defineStore } from "pinia";
2
+ import { ref } from "vue";
3
+
4
+ export const useProjectStore = defineStore("project", () => {
5
+ const projectList = ref([]);
6
+
7
+ const setProjectList = function (list) {
8
+ projectList.value = list;
9
+ };
10
+
11
+ return {
12
+ projectList,
13
+ setProjectList,
14
+ };
15
+ });
@@ -0,0 +1,106 @@
1
+ <template>
2
+ <el-container class="header-container">
3
+ <el-header class="header">
4
+ <!-- logo & title -->
5
+ <el-row type="flex" align="middle" class="header-row">
6
+ <el-row type="flex" align="middle" class="title-panel">
7
+ <img src="./asserts/logo.png" alt="logo" class="logo" />
8
+ <el-row class="text">{{ title }}</el-row>
9
+ </el-row>
10
+
11
+ <!-- 插槽 菜单区域 -->
12
+ <slot name="nemu-content"></slot>
13
+
14
+ <!-- 设置区域 -->
15
+ <el-row type="flex" align="middle" justify="end" class="setting-panel">
16
+ <!-- 插槽 设置区域 -->
17
+ <slot name="setting-content"></slot>
18
+ <img src="./asserts/avatar.png" alt="avatar" class="avatar" />
19
+ <el-dropdown @command="handleUserCommand">
20
+ <span class="username">
21
+ {{ userName }}
22
+ <i class="el-icon-arrow-down el-icon--right"></i>
23
+ </span>
24
+ <template #dropdown>
25
+ <el-dropdown-item command="logout"> 退出登录 </el-dropdown-item>
26
+ </template>
27
+ </el-dropdown>
28
+ </el-row>
29
+ </el-row>
30
+ </el-header>
31
+
32
+ <el-main class="main-container">
33
+ <!-- 插槽 核心内容填充区域 -->
34
+ <slot name="main-content"></slot>
35
+ </el-main>
36
+ </el-container>
37
+ </template>
38
+
39
+ <script setup>
40
+ import { ref } from "vue";
41
+
42
+ defineProps({ title: String });
43
+
44
+ const userName = ref("管理员");
45
+
46
+ const handleUserCommand = () => {};
47
+ </script>
48
+
49
+ <style lang="less" scoped>
50
+ .header-container {
51
+ height: 100%;
52
+ min-width: 1000px;
53
+ overflow: hidden;
54
+
55
+ .header {
56
+ max-height: 120px;
57
+ border-bottom: 1px solid #e8e8e8;
58
+
59
+ .header-row {
60
+ height: 60px;
61
+ padding: 0 20px;
62
+ .title-panel {
63
+ width: 180px;
64
+ min-width: 180px;
65
+ .logo {
66
+ margin-right: 10px;
67
+ width: 30px;
68
+ height: 30px;
69
+ border-radius: 50%;
70
+ }
71
+ .text {
72
+ font-size: 16px;
73
+ font-weight: 500;
74
+ }
75
+ }
76
+ }
77
+
78
+ .setting-panel {
79
+ margin-left: auto;
80
+ min-width: 180px;
81
+ .avatar {
82
+ margin-right: 12px;
83
+ width: 30px;
84
+ height: 30px;
85
+ border-radius: 50%;
86
+ }
87
+
88
+ .username {
89
+ font-size: 16px;
90
+ font-weight: 500;
91
+ cursor: pointer;
92
+ height: 60px;
93
+ line-height: 60px;
94
+ outline: none;
95
+ }
96
+ }
97
+ }
98
+
99
+ .main-container {
100
+ }
101
+ }
102
+
103
+ :deep(.el-header) {
104
+ padding: 0;
105
+ }
106
+ </style>
@@ -0,0 +1,137 @@
1
+ <template>
2
+ <el-row type="flex" align="middle" class="form-item">
3
+ <el-row class="item-label" justify="end">
4
+ <el-row
5
+ v-if="schema && schema.option?.required"
6
+ type="flex"
7
+ class="required"
8
+ >
9
+ *
10
+ </el-row>
11
+ {{ schema.label }}
12
+ </el-row>
13
+
14
+ <el-row class="item-value">
15
+ <el-input
16
+ v-model="dtoValue"
17
+ v-bind="schema.option"
18
+ :placeholder="placeholder"
19
+ class="component"
20
+ :class="validTips ? 'valid-border' : ''"
21
+ @focus="onFocus"
22
+ @blur="onBlur"
23
+ ></el-input>
24
+ </el-row>
25
+
26
+ <!-- 错误信息 -->
27
+ <el-row v-if="validTips" class="valid-tips">
28
+ {{ validTips }}
29
+ </el-row>
30
+ </el-row>
31
+ </template>
32
+
33
+ <script setup>
34
+ import { ref, toRefs, watch, inject, onMounted } from "vue";
35
+ const ajv = inject("ajv");
36
+
37
+ const props = defineProps({
38
+ schemaKey: String,
39
+ schema: Object,
40
+ model: String,
41
+ });
42
+
43
+ const { schema, schemaKey } = props;
44
+ const { model } = toRefs(props);
45
+
46
+ const name = ref("input");
47
+ const dtoValue = ref();
48
+ const validTips = ref(null);
49
+ const placeholder = ref("");
50
+ const initData = () => {
51
+ dtoValue.value = model.value ?? schema.option?.default;
52
+ validTips.value = null;
53
+
54
+ const { minLength, maxLength, pattern } = schema;
55
+ const ruleList = [];
56
+ if (schema.option?.placeholder) {
57
+ ruleList.push(schema.option.placeholder);
58
+ }
59
+
60
+ if (minLength) {
61
+ ruleList.push(`最小长度:${minLength}`);
62
+ }
63
+
64
+ if (maxLength) {
65
+ ruleList.push(`最大长度:${maxLength}`);
66
+ }
67
+
68
+ if (pattern) {
69
+ ruleList.push(`格式:${pattern}`);
70
+ }
71
+
72
+ placeholder.value = ruleList.join["|"];
73
+ };
74
+
75
+ onMounted(() => {
76
+ initData();
77
+ });
78
+
79
+ watch(
80
+ [model, schema],
81
+ () => {
82
+ initData();
83
+ },
84
+ { deep: true },
85
+ );
86
+
87
+ const validate = () => {
88
+ validTips.value = null;
89
+ const { type } = schema;
90
+
91
+ if (schema.option?.required && !dtoValue.value) {
92
+ validTips.value = "不能为空";
93
+ return false;
94
+ }
95
+
96
+ if (dtoValue.value) {
97
+ const validate = ajv.compile(schema);
98
+ const valid = validate(dtoValue.value);
99
+
100
+ if (!valid && validate.errors && validate.errors[0]) {
101
+ const { keyword, params } = validate.errors[0];
102
+ if (keyword === "type") {
103
+ validTips.value = `类型必须为 ${type}`;
104
+ } else if (keyword === "maxLength") {
105
+ validTips.value = `最大长度应为 ${params.limit}`;
106
+ } else if (keyword === "minLength") {
107
+ validTips.value = `最小长度应为 ${params.limit}`;
108
+ } else if (keyword === "pattern") {
109
+ validTips.value = "格式不正确";
110
+ } else {
111
+ console.log(validate.errors[0]);
112
+ validTips.value = "不符合要求";
113
+ }
114
+
115
+ return false;
116
+ }
117
+ }
118
+
119
+ return true;
120
+ };
121
+
122
+ const getValue = () => {
123
+ return dtoValue.value !== undefined ? { [schemaKey]: dtoValue.value } : {};
124
+ };
125
+
126
+ const onFocus = () => (validTips.value = null);
127
+
128
+ const onBlur = () => validate();
129
+
130
+ defineExpose({
131
+ name,
132
+ validate,
133
+ getValue,
134
+ });
135
+ </script>
136
+
137
+ <style scoped lang="less"></style>