@wp1001/ui 2.9.13

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 (177) hide show
  1. package/.env +6 -0
  2. package/@vant-D4fmGxs6.js +3891 -0
  3. package/index.js +8419 -0
  4. package/package.json +59 -0
  5. package/packages/assets/devtools-detector.js +2 -0
  6. package/packages/components/xarray/index.js +64 -0
  7. package/packages/components/xarray/xarray.vue +57 -0
  8. package/packages/components/xautorows/index.js +35 -0
  9. package/packages/components/xautorows/xautorows.vue +29 -0
  10. package/packages/components/xbutton/mobile.js +3 -0
  11. package/packages/components/xbutton/mobile.vue +9 -0
  12. package/packages/components/xbutton/pc.js +3 -0
  13. package/packages/components/xbutton/pc.vue +9 -0
  14. package/packages/components/xbuttons/mobile.js +51 -0
  15. package/packages/components/xbuttons/mobile.vue +12 -0
  16. package/packages/components/xbuttons/pc.js +51 -0
  17. package/packages/components/xbuttons/pc.vue +16 -0
  18. package/packages/components/xchart/constants.js +58 -0
  19. package/packages/components/xchart/index.js +263 -0
  20. package/packages/components/xchart/utils.js +121 -0
  21. package/packages/components/xchart/xchart.vue +173 -0
  22. package/packages/components/xcheckboxs/mobile.js +58 -0
  23. package/packages/components/xcheckboxs/mobile.vue +38 -0
  24. package/packages/components/xcheckboxs/pc.js +49 -0
  25. package/packages/components/xcheckboxs/pc.vue +42 -0
  26. package/packages/components/xcol/mobile.js +10 -0
  27. package/packages/components/xcol/mobile.vue +9 -0
  28. package/packages/components/xcol/pc.js +10 -0
  29. package/packages/components/xcol/pc.vue +9 -0
  30. package/packages/components/xdatepicker/mobile.js +71 -0
  31. package/packages/components/xdatepicker/mobile.vue +44 -0
  32. package/packages/components/xdatepicker/pc.js +9 -0
  33. package/packages/components/xdatepicker/pc.vue +12 -0
  34. package/packages/components/xdialog/mobile.js +60 -0
  35. package/packages/components/xdialog/mobile.vue +43 -0
  36. package/packages/components/xdialog/pc.js +64 -0
  37. package/packages/components/xdialog/pc.vue +51 -0
  38. package/packages/components/xdict/index.js +47 -0
  39. package/packages/components/xdict/xdict.vue +9 -0
  40. package/packages/components/xdistrictselect/mobile.js +79 -0
  41. package/packages/components/xdistrictselect/mobile.vue +28 -0
  42. package/packages/components/xdistrictselect/pc.js +127 -0
  43. package/packages/components/xdistrictselect/pc.vue +32 -0
  44. package/packages/components/xform/mobile.js +29 -0
  45. package/packages/components/xform/mobile.vue +43 -0
  46. package/packages/components/xform/pc.js +42 -0
  47. package/packages/components/xform/pc.vue +76 -0
  48. package/packages/components/xform/utils.js +95 -0
  49. package/packages/components/xformitem/mobile.js +56 -0
  50. package/packages/components/xformitem/mobile.vue +3 -0
  51. package/packages/components/xformitem/pc.js +72 -0
  52. package/packages/components/xformitem/pc.vue +10 -0
  53. package/packages/components/xformitem/utils.jsx +181 -0
  54. package/packages/components/xicon/mobile.js +35 -0
  55. package/packages/components/xicon/mobile.vue +9 -0
  56. package/packages/components/xicon/pc.js +35 -0
  57. package/packages/components/xicon/pc.vue +11 -0
  58. package/packages/components/xinfo/index.js +100 -0
  59. package/packages/components/xinfo/xinfo.vue +140 -0
  60. package/packages/components/xlooper/index.js +7 -0
  61. package/packages/components/xlooper/xlooper.vue +20 -0
  62. package/packages/components/xpagination/mobile.js +21 -0
  63. package/packages/components/xpagination/mobile.vue +31 -0
  64. package/packages/components/xpagination/pc.js +21 -0
  65. package/packages/components/xpagination/pc.vue +16 -0
  66. package/packages/components/xpicker/index.js +38 -0
  67. package/packages/components/xpicker/xpicker.vue +29 -0
  68. package/packages/components/xradios/mobile.js +40 -0
  69. package/packages/components/xradios/mobile.vue +22 -0
  70. package/packages/components/xradios/pc.js +53 -0
  71. package/packages/components/xradios/pc.vue +43 -0
  72. package/packages/components/xrow/mobile.js +9 -0
  73. package/packages/components/xrow/mobile.vue +23 -0
  74. package/packages/components/xrow/pc.js +9 -0
  75. package/packages/components/xrow/pc.vue +22 -0
  76. package/packages/components/xscan/mobile.js +24 -0
  77. package/packages/components/xscan/mobile.vue +21 -0
  78. package/packages/components/xscan/pc.js +20 -0
  79. package/packages/components/xscan/pc.vue +18 -0
  80. package/packages/components/xsearcher/index.js +198 -0
  81. package/packages/components/xsearcher/xsearcher.vue +170 -0
  82. package/packages/components/xselect/mobile.js +86 -0
  83. package/packages/components/xselect/mobile.vue +24 -0
  84. package/packages/components/xselect/pc.js +114 -0
  85. package/packages/components/xselect/pc.vue +55 -0
  86. package/packages/components/xselect/util.js +66 -0
  87. package/packages/components/xselectv2/index.js +91 -0
  88. package/packages/components/xselectv2/xselectv2.vue +46 -0
  89. package/packages/components/xtable/mobile.js +108 -0
  90. package/packages/components/xtable/mobile.vue +246 -0
  91. package/packages/components/xtable/pc.js +143 -0
  92. package/packages/components/xtable/pc.vue +421 -0
  93. package/packages/components/xtable/searcher.js +477 -0
  94. package/packages/components/xtable/searcher.jsx +330 -0
  95. package/packages/components/xtable/searcher.vue +133 -0
  96. package/packages/components/xtable/settings.js +80 -0
  97. package/packages/components/xtable/settings.vue +77 -0
  98. package/packages/components/xtable/utils.js +692 -0
  99. package/packages/components/xtabletools/mobile.js +25 -0
  100. package/packages/components/xtabletools/mobile.vue +126 -0
  101. package/packages/components/xtabletools/pc.js +18 -0
  102. package/packages/components/xtabletools/pc.vue +135 -0
  103. package/packages/components/xtablev2/index.js +53 -0
  104. package/packages/components/xtablev2/utils.jsx +214 -0
  105. package/packages/components/xtablev2/xtablev2.vue +147 -0
  106. package/packages/components/xtags/mobile.js +17 -0
  107. package/packages/components/xtags/mobile.vue +21 -0
  108. package/packages/components/xtags/pc.js +17 -0
  109. package/packages/components/xtags/pc.vue +22 -0
  110. package/packages/components/xtinymce/index.js +71 -0
  111. package/packages/components/xtinymce/xtinymce.vue +9 -0
  112. package/packages/components/xuploader/xfileuploader.js +48 -0
  113. package/packages/components/xuploader/xfileuploader.vue +54 -0
  114. package/packages/components/xuploader/ximageuploader.js +53 -0
  115. package/packages/components/xuploader/ximageuploader.vue +52 -0
  116. package/packages/comps.js +108 -0
  117. package/packages/controllers/BaseController.js +125 -0
  118. package/packages/controllers/CrudController.js +907 -0
  119. package/packages/controllers/TempCrudController.js +32 -0
  120. package/packages/controllers/index.js +15 -0
  121. package/packages/directives/el-table-infinite-scroll.js +55 -0
  122. package/packages/directives/index.js +5 -0
  123. package/packages/index.js +81 -0
  124. package/packages/index.scss +4 -0
  125. package/packages/layout/breadcrumb/breadcrumb.vue +31 -0
  126. package/packages/layout/breadcrumb/index.js +41 -0
  127. package/packages/layout/header/header.vue +281 -0
  128. package/packages/layout/header/inner.js +11 -0
  129. package/packages/layout/header/inner.vue +3 -0
  130. package/packages/layout/mobile-menu.vue +83 -0
  131. package/packages/layout/mobile-tabs.vue +54 -0
  132. package/packages/layout/pc.vue +85 -0
  133. package/packages/layout/screenlock/index.js +129 -0
  134. package/packages/layout/screenlock/screenlock.vue +85 -0
  135. package/packages/layout/sidebar/item.js +16 -0
  136. package/packages/layout/sidebar/item.vue +16 -0
  137. package/packages/layout/sidebar/menu.js +72 -0
  138. package/packages/layout/sidebar/menu.vue +106 -0
  139. package/packages/layout/sidebar/sidebar.vue +147 -0
  140. package/packages/layout/tagsview/ScrollPane.js +65 -0
  141. package/packages/layout/tagsview/ScrollPane.vue +24 -0
  142. package/packages/layout/tagsview/index.js +169 -0
  143. package/packages/layout/tagsview/index.vue +124 -0
  144. package/packages/plop/actions/make-fill-admin-partials-action.js +95 -0
  145. package/packages/plop/generators/make-admin-page.js +39 -0
  146. package/packages/plop/generators/make-database-admin-pages.js +84 -0
  147. package/packages/plop/generators/make-page-generator.js +52 -0
  148. package/packages/plop/generators/make-simple-page.js +20 -0
  149. package/packages/plop/plopfile.js +24 -0
  150. package/packages/plop/templates/admin_page/controller.js +3 -0
  151. package/packages/plop/templates/admin_page/model.js +24 -0
  152. package/packages/plop/templates/admin_page/{{snakeCase pagename}}-scoped.scss +3 -0
  153. package/packages/plop/templates/admin_page/{{snakeCase pagename}}.vue +11 -0
  154. package/packages/plop/templates/simple_page/controller.js +3 -0
  155. package/packages/plop/templates/simple_page/model.js +6 -0
  156. package/packages/plop/templates/simple_page/{{snakeCase pagename}}-scoped.scss +3 -0
  157. package/packages/plop/templates/simple_page/{{snakeCase pagename}}.vue +7 -0
  158. package/packages/plop/utils/index.js +168 -0
  159. package/packages/plop/utils/plop-utils.js +86 -0
  160. package/packages/styles/common.scss +137 -0
  161. package/packages/styles/element-ui.scss +142 -0
  162. package/packages/styles/vant.scss +133 -0
  163. package/packages/styles/variables.scss +23 -0
  164. package/packages/utils/crypt.js +24 -0
  165. package/packages/utils/decorators.js +67 -0
  166. package/packages/utils/disallowDevtools.js +53 -0
  167. package/packages/utils/effects.js +173 -0
  168. package/packages/utils/funcs.js +78 -0
  169. package/packages/utils/index.js +95 -0
  170. package/packages/utils/message.js +110 -0
  171. package/packages/utils/middlewares.js +86 -0
  172. package/packages/utils/model.js +71 -0
  173. package/packages/utils/modelUtils.js +203 -0
  174. package/packages/utils/request.js +57 -0
  175. package/packages/utils/site.js +33 -0
  176. package/packages/vite-plugins.js +141 -0
  177. package/publish.sh +12 -0
@@ -0,0 +1,65 @@
1
+ const tagAndTagSpacing = 4
2
+
3
+ export default {
4
+ name: 'ScrollPane',
5
+ data() {
6
+ return {
7
+ left: 0
8
+ }
9
+ },
10
+ computed: {
11
+ scrollWrapper() {
12
+ return this.$refs.scrollContainer.$refs.wrapRef
13
+ }
14
+ },
15
+ mounted() {
16
+ this.scrollWrapper.addEventListener('scroll', this.emitScroll, true)
17
+ },
18
+ beforeUnmount() {
19
+ this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
20
+ },
21
+ methods: {
22
+ handleScroll(e) {
23
+ const eventDelta = e.wheelDelta || -e.deltaY * 40
24
+ const $scrollWrapper = this.scrollWrapper
25
+ $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
26
+ },
27
+ emitScroll() {
28
+ this.$emit('scroll')
29
+ },
30
+ moveToTarget(currentTag) {
31
+ const $container = this.$refs.scrollContainer.$el
32
+ const $containerWidth = $container.offsetWidth
33
+ const $scrollWrapper = this.scrollWrapper
34
+ const tagList = this.$parent.$refs.tag
35
+
36
+ let firstTag = null
37
+ let lastTag = null
38
+
39
+ if (tagList.length > 0) {
40
+ firstTag = tagList[0]
41
+ lastTag = tagList[tagList.length - 1]
42
+ }
43
+
44
+ if (firstTag === currentTag) {
45
+ $scrollWrapper.scrollLeft = 0
46
+ } else if (lastTag === currentTag) {
47
+ $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
48
+ } else {
49
+ const currentIndex = tagList.findIndex(item => item === currentTag)
50
+ const prevTag = tagList[currentIndex - 1]
51
+ const nextTag = tagList[currentIndex + 1]
52
+
53
+ const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
54
+
55
+ const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
56
+
57
+ if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
58
+ $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
59
+ } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
60
+ $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
@@ -0,0 +1,24 @@
1
+ <script>
2
+ export { default } from './ScrollPane.js'
3
+ </script>
4
+
5
+ <template>
6
+ <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
7
+ <slot />
8
+ </el-scrollbar>
9
+ </template>
10
+
11
+ <style lang="scss" scoped>
12
+ .scroll-container {
13
+ white-space: nowrap;
14
+ position: relative;
15
+ overflow: hidden;
16
+ width: 100%;
17
+ :deep(.el-scrollbar__bar) {
18
+ bottom: 0px;
19
+ }
20
+ :deep(.el-scrollbar__wrap) {
21
+ height: 35px;
22
+ }
23
+ }
24
+ </style>
@@ -0,0 +1,169 @@
1
+ import ScrollPane from './ScrollPane.vue'
2
+ import router from '@/router'
3
+
4
+ export default {
5
+ components: { ScrollPane },
6
+ data() {
7
+ return {
8
+ visible: false,
9
+ top: 0,
10
+ left: 0,
11
+ selectedTag: {},
12
+ affixTags: []
13
+ }
14
+ },
15
+ computed: {
16
+ visitedViews() {
17
+ return this.$store.tagsview.visitedViews
18
+ },
19
+ routes() {
20
+ return router.getRoutes()
21
+ }
22
+ },
23
+ watch: {
24
+ $route() {
25
+ this.addTags()
26
+ this.moveToCurrentTag()
27
+ },
28
+ visible(value) {
29
+ if (value) {
30
+ document.body.addEventListener('click', this.closeMenu)
31
+ } else {
32
+ document.body.removeEventListener('click', this.closeMenu)
33
+ }
34
+ }
35
+ },
36
+ mounted() {
37
+ this.initTags()
38
+ this.addTags()
39
+ },
40
+ methods: {
41
+ isActive(route) {
42
+ return route.path === this.$route.path
43
+ },
44
+ isAffix(tag) {
45
+ return tag.meta?.affix
46
+ },
47
+ filterAffixTags(routes, basePath = '/') {
48
+ let tags = []
49
+ routes.forEach(route => {
50
+ if (route.meta?.affix) {
51
+ const tagPath = this.resolvePath(basePath, route.path)
52
+ tags.push({
53
+ fullPath: tagPath,
54
+ path: tagPath,
55
+ name: route.name,
56
+ meta: { ...route.meta }
57
+ })
58
+ }
59
+ if (route.children) {
60
+ const tempTags = this.filterAffixTags(route.children, this.resolvePath(basePath, route.path))
61
+ if (tempTags.length >= 1) {
62
+ tags = [...tags, ...tempTags]
63
+ }
64
+ }
65
+ })
66
+ return tags
67
+ },
68
+ initTags() {
69
+ const affixTags = this.affixTags = this.filterAffixTags(this.routes)
70
+ for (const tag of affixTags) {
71
+ if (tag.name) {
72
+ this.$store.tagsview.addVisitedView(tag)
73
+ }
74
+ }
75
+ },
76
+ addTags() {
77
+ const { name } = this.$route
78
+ if (name) {
79
+ this.$store.tagsview.addView(this.$route)
80
+ }
81
+ return false
82
+ },
83
+ moveToCurrentTag() {
84
+ const tags = this.$refs.tag
85
+ this.$nextTick(() => {
86
+ for (const tag of tags) {
87
+ if (tag.to.path === this.$route.path) {
88
+ this.$refs.scrollPane.moveToTarget(tag)
89
+ if (tag.to.fullPath !== this.$route.fullPath) {
90
+ this.$store.tagsview.updateVisitedView(this.$route)
91
+ }
92
+ break
93
+ }
94
+ }
95
+ })
96
+ },
97
+ refreshSelectedTag(view) {
98
+ this.$store.tagsview.delCachedView(view).then(() => {
99
+ const { fullPath } = view
100
+ this.$nextTick(() => {
101
+ this.$router.replace({ path: fullPath })
102
+ })
103
+ })
104
+ },
105
+ closeSelectedTag(view) {
106
+ this.$store.tagsview.delView(view).then(({ visitedViews }) => {
107
+ if (this.isActive(view)) {
108
+ this.toLastView(visitedViews, view)
109
+ }
110
+ })
111
+ },
112
+ closeOthersTags() {
113
+ this.$router.push(this.selectedTag)
114
+ this.$store.tagsview.delOthersViews(this.selectedTag).then(() => {
115
+ this.moveToCurrentTag()
116
+ })
117
+ },
118
+ closeAllTags(view) {
119
+ this.$store.tagsview.delAllViews().then(({ visitedViews }) => {
120
+ if (this.affixTags.some(tag => tag.path === view.path)) {
121
+ return
122
+ }
123
+ this.toLastView(visitedViews, view)
124
+ })
125
+ },
126
+ toLastView(visitedViews, view) {
127
+ const latestView = visitedViews.slice(-1)[0]
128
+ if (latestView) {
129
+ this.$router.push(latestView.fullPath)
130
+ } else {
131
+ if (view.name === 'Dashboard') {
132
+ this.$router.replace({ path: view.fullPath })
133
+ } else {
134
+ this.$router.push('/')
135
+ }
136
+ }
137
+ },
138
+ openMenu(tag, e) {
139
+ const menuMinWidth = 105
140
+ const offsetLeft = this.$el.getBoundingClientRect().left
141
+ const offsetWidth = this.$el.offsetWidth
142
+ const maxLeft = offsetWidth - menuMinWidth
143
+ const left = e.clientX - offsetLeft + 15
144
+
145
+ if (left > maxLeft) {
146
+ this.left = maxLeft
147
+ } else {
148
+ this.left = left
149
+ }
150
+
151
+ this.top = e.clientY
152
+ this.visible = true
153
+ this.selectedTag = tag
154
+ },
155
+ closeMenu() {
156
+ this.visible = false
157
+ },
158
+ handleScroll() {
159
+ this.closeMenu()
160
+ },
161
+ resolvePath(base, path) {
162
+ if (base[0] !== '/') base = '/' + base
163
+ if (base.length > 1 && base.endsWith('/')) base = base.slice(0, -1)
164
+ if (base === '/') base = ''
165
+ if (path[0] !== '/') path = '/' + path
166
+ return base + path
167
+ }
168
+ }
169
+ }
@@ -0,0 +1,124 @@
1
+ <script>
2
+ export { default } from './index.js'
3
+ </script>
4
+
5
+ <template>
6
+ <div id="tags-view-container" class="tags-view-container">
7
+ <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
8
+ <router-link
9
+ v-for="tag in visitedViews"
10
+ ref="tag"
11
+ :key="tag.path"
12
+ :class="isActive(tag)?'active':''"
13
+ :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
14
+ tag="span"
15
+ class="tags-view-item"
16
+ @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
17
+ @contextmenu.prevent.native="openMenu(tag,$event)"
18
+ >
19
+ {{ tag.title }}
20
+ <x-icon v-if="!isAffix(tag)" name="Close" class="close" @click.prevent.stop="closeSelectedTag(tag)" />
21
+ </router-link>
22
+ </scroll-pane>
23
+ <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
24
+ <li @click="refreshSelectedTag(selectedTag)">Refresh</li>
25
+ <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">Close</li>
26
+ <li @click="closeOthersTags">Close Others</li>
27
+ <li @click="closeAllTags(selectedTag)">Close All</li>
28
+ </ul>
29
+ </div>
30
+ </template>
31
+
32
+ <style lang="scss" scoped>
33
+ .tags-view-container {
34
+ position: relative;
35
+ height: var(--x-tagsview-height);
36
+ border-bottom: 1px solid #d8dce5;
37
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
38
+ .tags-view-wrapper {
39
+ .tags-view-item {
40
+ display: inline-block;
41
+ position: relative;
42
+ cursor: pointer;
43
+ height: 29px;
44
+ line-height: 27px;
45
+ border: 1px solid #d8dce5;
46
+ color: #495060;
47
+ background: #ecf5ff;
48
+ padding: 0 6px 0 8px;
49
+ font-size: 12px;
50
+ margin-left: 5px;
51
+ margin-top: 5px;
52
+ &:first-of-type {
53
+ margin-left: 10px;
54
+ }
55
+ &:last-of-type {
56
+ margin-right: 10px;
57
+ }
58
+ &.active {
59
+ background-color: var(--el-color-primary);
60
+ color: #fff;
61
+ border-color: #42b983;
62
+ &::before {
63
+ content: '';
64
+ background: #fff;
65
+ display: inline-block;
66
+ width: 8px;
67
+ height: 8px;
68
+ border-radius: 50%;
69
+ position: relative;
70
+ margin-right: 2px;
71
+ }
72
+ }
73
+ }
74
+ }
75
+ .contextmenu {
76
+ margin: 0;
77
+ background: #fff;
78
+ z-index: 3000;
79
+ position: absolute;
80
+ list-style-type: none;
81
+ padding: 5px 0;
82
+ border-radius: 4px;
83
+ font-size: 12px;
84
+ font-weight: 400;
85
+ color: #333;
86
+ box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
87
+ li {
88
+ margin: 0;
89
+ padding: 7px 16px;
90
+ cursor: pointer;
91
+ &:hover {
92
+ background: #eee;
93
+ }
94
+ }
95
+ }
96
+ }
97
+ </style>
98
+
99
+ <style lang="scss">
100
+ .tags-view-wrapper {
101
+ .tags-view-item {
102
+ .close {
103
+ position: relative;
104
+ top: 5px;
105
+ width: 16px;
106
+ height: 16px;
107
+ vertical-align: 2px;
108
+ border-radius: 50%;
109
+ text-align: center;
110
+ transition: all .3s cubic-bezier(.645, .045, .355, 1);
111
+ transform-origin: 100% 50%;
112
+ &:before {
113
+ transform: scale(.6);
114
+ display: inline-block;
115
+ vertical-align: -3px;
116
+ }
117
+ &:hover {
118
+ background-color: #b4bccc;
119
+ color: #fff;
120
+ }
121
+ }
122
+ }
123
+ }
124
+ </style>
@@ -0,0 +1,95 @@
1
+ import plopUtils from '../utils/plop-utils.js'
2
+ import {
3
+ getModel,
4
+ makeFields,
5
+ } from '../utils/index.js'
6
+
7
+ const {
8
+ makePartial
9
+ } = plopUtils
10
+
11
+ const viewOnlyFields = [
12
+ 'creator_id',
13
+ 'updater_id',
14
+ 'created_at',
15
+ 'updated_at',
16
+ 'deleted_at'
17
+ ]
18
+
19
+ const makeFillAdminPartialsAction = (plop) => {
20
+ return async function (data) {
21
+ const model = await getModel(plop, data)
22
+ const attrs = model.tableAttributes
23
+
24
+ data.tableName = model.tableName
25
+
26
+ Object.keys(attrs).forEach(key => {
27
+ if (attrs[key]._autoGenerated) {
28
+ if (key.startsWith('created')) {
29
+ attrs[key].label = '创建时间'
30
+ } else if (key.startsWith('updated')) {
31
+ attrs[key].label = '更新时间'
32
+ } else if (key.startsWith('deleted')) {
33
+ attrs[key].label = '删除时间'
34
+ }
35
+ }
36
+ })
37
+
38
+ fillIdFieldPartial(plop, model)
39
+ fillFieldsPartial(plop, model)
40
+
41
+ Object.keys(attrs).forEach(key => {
42
+ const { autoIncrement, _autoGenerated } = attrs[key]
43
+ if (autoIncrement || _autoGenerated) {
44
+ delete attrs[key]
45
+ }
46
+ })
47
+
48
+ viewOnlyFields.forEach(field => delete attrs[field])
49
+ }
50
+ }
51
+
52
+ const fillIdFieldPartial = (plop, model) => {
53
+ plop.setPartial('idFieldPartial', model.primaryKeyField)
54
+ }
55
+
56
+ const fillFieldsPartial = (plop, model) => {
57
+ const fields = makeFields(model)
58
+ plop.setPartial('fieldsPartial', makeFieldsPartial(fields))
59
+ }
60
+
61
+ const makeFieldsPartial = (fields) => {
62
+ const afterKeys = ['tableAttrs', 'formAttrs']
63
+ fields.map(field => {
64
+ const values = afterKeys.map(key => field[key])
65
+ afterKeys.forEach(key => delete field[key])
66
+ values.forEach((value, index) => {
67
+ const prefix = afterKeys[index][0] + afterKeys[index].match(/[A-Z]/)[0].toLowerCase() + '_'
68
+ if (value && Object.keys(value).length) {
69
+ for (let k in value) {
70
+ field[prefix + k] = value[k]
71
+ }
72
+ }
73
+ })
74
+ })
75
+ const partial = makePartial(fields)
76
+ let code = ''
77
+ partial.split('\n').forEach(line => {
78
+ const trimed = line.trim()
79
+ if ('[{}]'.includes(trimed[0])) {
80
+ code += line
81
+ if ('{'.includes(trimed[0])) {
82
+ code += ' '
83
+ }
84
+ if ('}'.includes(trimed[0])) {
85
+ code += '\n'
86
+ }
87
+ } else {
88
+ code += trimed + ' '
89
+ }
90
+ })
91
+ code = code.slice(0, -1)
92
+ return code
93
+ }
94
+
95
+ export default makeFillAdminPartialsAction
@@ -0,0 +1,39 @@
1
+ import plopUtils from '../utils/plop-utils.js'
2
+ import makePageGenerator from './make-page-generator.js'
3
+ import makeFillAdminPartialsAction from '../actions/make-fill-admin-partials-action.js'
4
+
5
+ const {
6
+ makeInputPrompt,
7
+ makeConfirmPrompt
8
+ } = plopUtils
9
+
10
+ const makeGenerator = (plop) => {
11
+ const dir = 'admin_page'
12
+
13
+ const generator = makePageGenerator(plop, dir)
14
+
15
+ plop.setPartial('fieldsPartial', '[\n]')
16
+
17
+ return {
18
+ name: 'make-admin-page',
19
+ description: '创建新的后台管理页面',
20
+ prompts: [
21
+ ...generator.prompts,
22
+ makeConfirmPrompt('autoGenerateColumns', '是否需要自动生成 table.columns (表格的数据列)?'),
23
+ {
24
+ ...makeInputPrompt('database', '数据库名称'),
25
+ when: anwsers => anwsers.autoGenerateColumns
26
+ },
27
+ {
28
+ ...makeInputPrompt('table', '数据表名称'),
29
+ when: anwsers => anwsers.autoGenerateColumns
30
+ }
31
+ ],
32
+ actions: [
33
+ makeFillAdminPartialsAction(plop),
34
+ ...generator.actions,
35
+ ]
36
+ }
37
+ }
38
+
39
+ export default makeGenerator
@@ -0,0 +1,84 @@
1
+ import path from 'node:path'
2
+ import chalk from 'chalk'
3
+ import clipboardy from 'clipboardy'
4
+ import { fsUtils } from '@stardust_js/node'
5
+
6
+ import plopUtils from '../utils/plop-utils.js'
7
+
8
+ const {
9
+ makeInputPrompt,
10
+ getGenerator
11
+ } = plopUtils
12
+
13
+ const makeGenerator = (plop) => {
14
+ const mapGenerator = getGenerator(plop, 'make-admin-page', { force: false })
15
+ const pascalCase = plop.getHelper('pascalCase')
16
+ const snakeCase = plop.getHelper('snakeCase')
17
+
18
+ const generator = {
19
+ name: 'make-database-admin-pages',
20
+ description: '根据 backender 中已存在的数据库模型目录为其中所有模型创建后台管理页面',
21
+ prompts: [
22
+ makeInputPrompt('database', '数据库名称'),
23
+ makeInputPrompt('dir', '目的文件夹路径')
24
+ ],
25
+ actions: [
26
+ async ({ database, dir }) => {
27
+ const databaseDir = path.join(plop.backenderPath, `/models/${database}`)
28
+ let files = await fsUtils.listDir(databaseDir)
29
+ files = files.filter(file => file.includes('.js') && !file.includes('init-models.js') && file.split('/').pop() !== 'index.js')
30
+ const tables = files.map(file => file.slice(0, -3))
31
+
32
+ const results = []
33
+ for (let i = 0, len = tables.length; i < len; i++) {
34
+ const table = tables[i]
35
+ const result = await mapGenerator.runActions({
36
+ dir,
37
+ pagename: table,
38
+ database,
39
+ table: snakeCase(table),
40
+ })
41
+ if (!result.changes[2]) {
42
+ console.log(chalk.red(`数据表 ${database}.${table} 构建页面失败`), result.changes)
43
+ } else {
44
+ results.push(result)
45
+ }
46
+ console.log(chalk.cyan(`Finished ${i + 1} / ${len} ${((i + 1) / len * 100).toFixed(2)}%`))
47
+ }
48
+ console.log(chalk.bgCyan('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^'))
49
+ console.log(chalk.bgCyan('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^'))
50
+ const routes = results.map(result => result.changes[2].path)
51
+ const childrenCode = routes.map(c => {
52
+ return c.split('\n').map(line => ' ' + line).join('\n').trimEnd()
53
+ }).join('').trimStart()
54
+ const rootCode = `
55
+ {
56
+ path: '/${dir}',
57
+ name: '${pascalCase(dir)}',
58
+ redirect: '/${dir}/${snakeCase(tables[0])}',
59
+ component: Layout,
60
+ meta: {
61
+ title: '${pascalCase(dir)}',
62
+ icon: 'menu'
63
+ },
64
+ children: [
65
+ #code#
66
+ ]
67
+ },
68
+ `.split('\n').map(line => line.slice(10)).join('\n')
69
+ const numDirLevels = dir.split('/').length
70
+ const code = rootCode.replace('#code#', childrenCode).split('\n').map(line => {
71
+ return ' '.repeat(numDirLevels) + line
72
+ }).join('\n').trim()
73
+ clipboardy.writeSync(code)
74
+ console.log(code)
75
+ console.log(chalk.black.bgYellow('上面有一个参考的 route 代码, (已复制到剪贴板)'))
76
+ console.log(chalk.bgCyan('$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$'))
77
+ console.log(chalk.bgCyan('$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$'))
78
+ }
79
+ ]
80
+ }
81
+ return generator
82
+ }
83
+
84
+ export default makeGenerator
@@ -0,0 +1,52 @@
1
+ import path from 'node:path'
2
+ import chalk from 'chalk'
3
+ import clipboardy from 'clipboardy'
4
+
5
+ import plopUtils from '../utils/plop-utils.js'
6
+
7
+ const dirname = import.meta.dirname.split('node_modules')[0]
8
+
9
+ const {
10
+ makeInputPrompt,
11
+ } = plopUtils
12
+
13
+ const makePageGenerator = (plop, dir) => {
14
+ const properCase = plop.getHelper('properCase')
15
+ const snakeCase = plop.getHelper('snakeCase')
16
+
17
+ return {
18
+ prompts: [
19
+ makeInputPrompt('dir', '目的文件夹路径'),
20
+ makeInputPrompt('pagename', '目的页面名称'),
21
+ ],
22
+ actions: [
23
+ {
24
+ type: 'addMany',
25
+ destination: path.join(dirname, 'src/views/{{dir}}/{{snakeCase pagename}}'),
26
+ base: path.join(dirname, 'node_modules/@stardust_js/ui/packages/plop/templates/' + dir),
27
+ templateFiles: path.join(dirname, 'node_modules/@stardust_js/ui/packages/plop/templates/' + dir + '/*.*')
28
+ },
29
+ function (data) {
30
+ let { dir, pagename } = data
31
+ const title = properCase(pagename)
32
+ const name = (dir ? properCase(dir) : '') + title
33
+ pagename = snakeCase(pagename)
34
+ const code = `
35
+ {
36
+ path: '${pagename}',
37
+ name: '${name}',
38
+ component: () => import('@/views/${dir ? (dir + '/') : ''}${pagename}/${pagename}.vue'),
39
+ meta: {
40
+ title: '${title}'
41
+ }
42
+ },
43
+ `.split('\n').map(line => line.slice(8)).join('\n')
44
+ clipboardy.writeSync(code)
45
+ console.log(chalk.black.bgYellow('这里有一个参考的 route 代码, (已复制到剪贴板)'))
46
+ return code
47
+ }
48
+ ]
49
+ }
50
+ }
51
+
52
+ export default makePageGenerator
@@ -0,0 +1,20 @@
1
+ import makePageGenerator from './make-page-generator.js'
2
+
3
+ const makeGenerator = (plop) => {
4
+ const dir = 'simple_page'
5
+
6
+ const generator = makePageGenerator(plop, dir)
7
+
8
+ return {
9
+ name: 'make-simple-page',
10
+ description: '创建新的页面',
11
+ prompts: [
12
+ ...generator.prompts
13
+ ],
14
+ actions: [
15
+ ...generator.actions
16
+ ]
17
+ }
18
+ }
19
+
20
+ export default makeGenerator
@@ -0,0 +1,24 @@
1
+ import path from 'node:path'
2
+ import chalk from 'chalk'
3
+ import plopUtils from './utils/plop-utils.js'
4
+
5
+ import makeAdminPage from './generators/make-admin-page.js'
6
+ import makeDatabaseAdminPages from './generators/make-database-admin-pages.js'
7
+ import makeSimplePage from './generators/make-simple-page.js'
8
+
9
+ const generators = {
10
+ makeAdminPage,
11
+ makeDatabaseAdminPages,
12
+ makeSimplePage
13
+ }
14
+
15
+ export default function (plop) {
16
+ const hello = '欢迎使用 stardust-frontender 代码生成工具,请从以下生成器中选择一个 : '
17
+ plop.setWelcomeMessage(chalk.bgGreen.white(hello))
18
+ plop.backenderPath = plopUtils.absPath(plop, '../backender')
19
+
20
+ Object.keys(generators).forEach(name => {
21
+ const generator = generators[name](plop)
22
+ plop.setGenerator(generator.name, generator)
23
+ })
24
+ }