@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,170 @@
1
+ <script>
2
+ export { default } from './index.js'
3
+ </script>
4
+
5
+ <template>
6
+ <div class="x-searcher" :class="isMobile ? 'mobile-x-searcher' : 'pc-x-searcher'">
7
+ <el-input
8
+ v-if="!isMobile"
9
+ :modelValue="$attrs.formatValue?.(modelValue) ?? modelValue"
10
+ :placeholder="_placeholder"
11
+ :clearable
12
+ :readonly
13
+ :disabled
14
+ @focus="handleFocus"
15
+ @clear="handleClear"
16
+ @click="handleShow"
17
+ />
18
+ <van-cell
19
+ v-else
20
+ :title="modelValue ? ($attrs.formatValue?.(modelValue) ?? modelValue) : _placeholder"
21
+ is-link
22
+ :class="modelValue ? 'x-searcher__value' : 'x-searcher__placeholder'"
23
+ @click="handleShow"
24
+ />
25
+
26
+ <x-dialog
27
+ v-model="visible" :title :width :fullscreen actionsheet
28
+ class="x-searcher__dialog"
29
+ :class="[
30
+ isMobile ? 'mobile-x-searcher__dialog' : 'pc-x-searcher__dialog',
31
+ hideSearcher ? 'hide-searcher' : '',
32
+ $attrs['dialog-class'] ?? $attrs.dialogClass
33
+ ]"
34
+ :onSubmit="multiple ? () => visible = false : null"
35
+ >
36
+ <template v-if="$slots.header" #header>
37
+ <slot name="header" />
38
+ </template>
39
+ <van-search
40
+ v-if="!hideSearcher"
41
+ v-model="keywords"
42
+ show-action
43
+ :clearable="isMobile"
44
+ :placeholder="searcherPlaceholder || '输入关键词搜索'"
45
+ @search="handleSearch"
46
+ >
47
+ <template #action>
48
+ <div @click="handleSearch">搜索</div>
49
+ </template>
50
+ </van-search>
51
+ <x-table
52
+ v-if="header?.length"
53
+ :table="{}" :data="list" :columns="calcColumns()" plain
54
+ >
55
+ <template v-if="$slots.cell" #cell="{ scope, column, value }">
56
+ <slot name="cell" :item="scope.row" :column :value :index="scope.$index" />
57
+ </template>
58
+ <template #operates="{ scope }">
59
+ <slot name="right" :item="scope.row" :index="scope.$index" />
60
+ </template>
61
+ </x-table>
62
+ <van-list
63
+ v-else
64
+ v-loading="loading" element-loading-text="加载中..."
65
+ :class="{ 'no-data': !list.length }"
66
+ >
67
+ <van-cell
68
+ v-for="(item, index) in list" :key="index"
69
+ :title="calcTitles(item)"
70
+ :label="calcSubTitles(item)"
71
+ @click="handleSelect(item, index)"
72
+ >
73
+ <template v-if="$slots.title" #title>
74
+ <slot name="title" :item :index />
75
+ </template>
76
+ <template v-if="$slots['sub-title']" #label>
77
+ <slot name="sub-title" :item :index />
78
+ </template>
79
+ <template #right-icon>
80
+ <span class="right-custom">
81
+ <slot name="right" :item :index />
82
+ </span>
83
+ <van-icon
84
+ v-if="Array.isArray(modelValue) ? modelValue.includes(item[value]) : modelValue === item[value]"
85
+ name="success" class="is-current"
86
+ />
87
+ </template>
88
+ </van-cell>
89
+ </van-list>
90
+ <van-empty v-show="!list.length" :description="emptyText || ('未查询到' + title)" />
91
+ </x-dialog>
92
+ </div>
93
+ </template>
94
+
95
+ <style lang="scss">
96
+ .x-searcher {
97
+ .van-cell {
98
+ padding: 0 !important;
99
+ }
100
+ &__placeholder {
101
+ color: #c3c3c3;
102
+ }
103
+ &__dialog {
104
+ .el-dialog__body {
105
+ padding-top: 0 !important;
106
+ }
107
+ &.hide-searcher {
108
+ .van-list {
109
+ height: 100%;
110
+ }
111
+ }
112
+ .van-search {
113
+ padding: 10px 0;
114
+ position: sticky;
115
+ left: 0;
116
+ top: 0;
117
+ z-index: 100;
118
+ .van-search__action {
119
+ padding-right: 0;
120
+ }
121
+ }
122
+ .el-table {
123
+ max-height: 400px !important;
124
+ }
125
+ .van-list {
126
+ position: relative;
127
+ height: calc(100% - 44px);
128
+ padding-bottom: 10px;
129
+ overflow-y: auto;
130
+ &.no-data {
131
+ height: 0 !important;
132
+ }
133
+ .van-cell {
134
+ position: relative;
135
+ cursor: pointer;
136
+ padding: 5px;
137
+ &:hover {
138
+ background-color: #eee;
139
+ }
140
+ .van-cell__label {
141
+ margin-top: 0;
142
+ }
143
+ }
144
+ }
145
+ .right-custom {
146
+ position: absolute;
147
+ right: 20px;
148
+ top: 50%;
149
+ transform: translateY(-50%);
150
+ }
151
+ .is-current {
152
+ position: absolute;
153
+ right: 0;
154
+ top: 50%;
155
+ transform: translateY(-50%);
156
+ line-height: 24px;
157
+ }
158
+ }
159
+ }
160
+ .mobile-x-searcher__dialog {
161
+ .van-action-sheet__content {
162
+ height: 60vh;
163
+ }
164
+ .van-list {
165
+ .van-cell {
166
+ padding: 5px 0;
167
+ }
168
+ }
169
+ }
170
+ </style>
@@ -0,0 +1,86 @@
1
+ import { formatOptions } from '../../utils/index.js'
2
+ import { remoteSearch } from './util.js'
3
+
4
+ export default {
5
+ name: 'MobileXSelect',
6
+ inheritAttrs: false,
7
+ props: {
8
+ modelValue: Boolean | Number | String | Array,
9
+ modelName: String,
10
+ params: Object,
11
+ modelValue: Boolean | Number | String,
12
+ text: {
13
+ type: String,
14
+ default: 'text'
15
+ },
16
+ value: {
17
+ type: String,
18
+ default: 'value'
19
+ },
20
+ sort: Boolean | String,
21
+ options: Array | Object
22
+ },
23
+ emits: ['update:modelValue', 'change'],
24
+ computed: {
25
+ canEdit () {
26
+ return !this.$attrs.disabled && !this.$attrs.readonly
27
+ }
28
+ },
29
+ data () {
30
+ return {
31
+ visible: false,
32
+ _value: undefined,
33
+ _options: []
34
+ }
35
+ },
36
+ watch: {
37
+ modelValue: {
38
+ immediate: true,
39
+ handler (value) {
40
+ this._value = value
41
+ }
42
+ },
43
+ options: {
44
+ immediate: true,
45
+ deep: true,
46
+ handler () {
47
+ this._options = formatOptions(this.options, this)
48
+ }
49
+ }
50
+ },
51
+ created () {
52
+ if (this.modelName) {
53
+ this.remoteSearch()
54
+ }
55
+ },
56
+ methods: {
57
+ formatOptions,
58
+ remoteSearch (query) {
59
+ if (!this.modelName) {
60
+ return this._options
61
+ }
62
+ remoteSearch(this.service.restful, query, this)
63
+ },
64
+ onShow () {
65
+ if (!this.canEdit) return
66
+ this.visible = true
67
+ },
68
+ onClick (e) {
69
+ if (!this.canEdit) return
70
+ if (!e.target.classList.contains('van-overlay')) {
71
+ this.onShow()
72
+ }
73
+ },
74
+ onConfirm () {
75
+ if (this._value == null || this._value === '') {
76
+ this._value = this._options[0].value
77
+ }
78
+ this.visible = false
79
+ this.$emit('update:modelValue', this._value)
80
+ this.$emit('change', this._value)
81
+ },
82
+ onChange (e) {
83
+ this._value = e.selectedValues[0]
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,24 @@
1
+ <script>
2
+ export { default } from './mobile.js'
3
+ </script>
4
+
5
+ <template>
6
+ <div
7
+ @click.native="onClick"
8
+ class="x-select mobile-x-select"
9
+ >
10
+ <x-picker
11
+ v-bind="$attrs"
12
+ :modelValue="_value"
13
+ @update:modelValue="onChange"
14
+ :show="visible"
15
+ :columns="_options"
16
+ class="x-select__picker"
17
+ @click.stop
18
+ @show="onShow"
19
+ @cancel="visible = false"
20
+ @confirm="onConfirm"
21
+ @change="onChange"
22
+ />
23
+ </div>
24
+ </template>
@@ -0,0 +1,114 @@
1
+ import { markRaw } from 'vue'
2
+ import { formatOptions } from '../../utils/index.js'
3
+ import { remoteSearch, calcMainLabel, calcRemarkLabel } from './util.js'
4
+
5
+ export default {
6
+ name: 'PcXSelect',
7
+ props: {
8
+ modelName: String,
9
+ params: Object,
10
+ modelValue: Boolean | Number | String,
11
+ plain: {
12
+ type: Boolean,
13
+ default: false
14
+ },
15
+ text: {
16
+ type: String,
17
+ default: 'text'
18
+ },
19
+ labelTexts: Array,
20
+ value: {
21
+ type: String,
22
+ default: 'value'
23
+ },
24
+ filterable: {
25
+ type: Boolean,
26
+ default: true
27
+ },
28
+ remote: {
29
+ type: Boolean,
30
+ default: false
31
+ },
32
+ sort: Boolean | String,
33
+ options: Array | Object,
34
+
35
+ // 接收下面这几个属性,为了避免这些属性被绑定到当前组件根节点上,在下面会进行过滤传给子组件
36
+ platform: String
37
+ },
38
+ emits: ['update:modelValue'],
39
+ data () {
40
+ return {
41
+ loading: false,
42
+ _options: [],
43
+ list: []
44
+ }
45
+ },
46
+ computed: {
47
+ placeholder () {
48
+ if (this.$attrs.placeholder) return this.$attrs.placeholder
49
+ return this.remote ? '请搜索关键词以选择' : '请选择'
50
+ }
51
+ },
52
+ watch: {
53
+ options: {
54
+ immediate: true,
55
+ deep: true,
56
+ handler () {
57
+ const ops = formatOptions(this.options, this)
58
+ if (!this.$slots.custom) {
59
+ ops.forEach((op, index) => {
60
+ op._main_ = calcMainLabel(this.options[index], this)
61
+ op._remark_ = calcRemarkLabel(this.options[index], this)
62
+ })
63
+ }
64
+ this._options = markRaw(ops)
65
+ this.list = this._options
66
+ }
67
+ }
68
+ },
69
+ created () {
70
+ const ps = this.remoteSearch()
71
+ const un = this.$watch(() => this.modelValue, value => {
72
+ if (!value) return
73
+ ps.then(this.remoteSearch)
74
+ un()
75
+ })
76
+ },
77
+ methods: {
78
+ formatOptions,
79
+ handleRemote (e) {
80
+ const keywords = e.target.value.trim()
81
+ if (keywords === this._last_keywords_) return
82
+ this._last_keywords_ = keywords
83
+ if (this.$attrs.remoteMethod) this.$attrs.remoteMethod(keywords)
84
+ else if (this.remoteSearch) this.remoteSearch(keywords)
85
+ },
86
+ onChange (value) {
87
+ this.$emit('update:modelValue', value)
88
+ },
89
+ filter (keywords) {
90
+ keywords = keywords.trim()
91
+ if (!keywords) {
92
+ return this.list = markRaw(this._options)
93
+ }
94
+ const isRemarking = !this.$slots.custom && this.labelTexts
95
+ this.list = markRaw(this._options.filter(op => {
96
+ let text = op.text
97
+ if (isRemarking) text += op._main_ + op._remark_
98
+ return text.includes(keywords)
99
+ }))
100
+ },
101
+ async remoteSearch (query) {
102
+ if (!this.remote && !this.modelName) {
103
+ return this._options
104
+ }
105
+ await remoteSearch(this.service.restful, query, this)
106
+ },
107
+ calcMainLabel (option) {
108
+ return calcMainLabel(option, this)
109
+ },
110
+ calcRemarkLabel (option) {
111
+ return calcRemarkLabel(option, this)
112
+ }
113
+ }
114
+ }
@@ -0,0 +1,55 @@
1
+ <script>
2
+ export { default } from './pc.js'
3
+ </script>
4
+
5
+ <template>
6
+ <el-select
7
+ class="x-select pc-x-select"
8
+ :class="plain ? 'x-select--plain' : ''"
9
+ :loading
10
+ :value-on-clear="null"
11
+ v-bind="$attrs"
12
+ :modelValue
13
+ :filterable
14
+ :remote
15
+ clearable
16
+ :placeholder
17
+ :filter-method="remote ? undefined : ($attrs.filterMethod || filter)"
18
+ @keyup.enter="handleRemote"
19
+ @update:modelValue="onChange"
20
+ >
21
+ <el-option
22
+ v-for="(option, index) in list"
23
+ v-bind="$attrs"
24
+ :disabled="option.raw?.disabled"
25
+ :key="option.value"
26
+ :label="option.text"
27
+ :value="option.value"
28
+ >
29
+ <slot
30
+ v-if="$slots.custom"
31
+ name="custom"
32
+ :option
33
+ :raw="option.raw"
34
+ />
35
+ <span v-else>
36
+ <span class="main">{{ option._main_ }}</span>
37
+ <span class="remark">{{ option._remark_ }}</span>
38
+ </span>
39
+ </el-option>
40
+ </el-select>
41
+ </template>
42
+
43
+ <style lang="scss" scoped>
44
+ .x-select--plain {
45
+ width: 100px;
46
+ :deep(.el-select__wrapper) {
47
+ box-shadow: none;
48
+ cursor: pointer;
49
+ }
50
+ }
51
+ .remark {
52
+ color: #a0aaaa;
53
+ margin-left: 10px;
54
+ }
55
+ </style>
@@ -0,0 +1,66 @@
1
+ const { highdict } = StardustJs
2
+
3
+ const remoteSearch = async (restful, query, vm) => {
4
+ if (vm.loading || vm.options._loading) return
5
+ vm.loading = true
6
+ vm.options._loading = true
7
+ const keywords = query?.trim().split(' ').filter(k => k)
8
+ const { text = 'text', value = 'value', labelTexts, $props, $attrs, params = {} } = vm
9
+ params.attributes = [...new Set(params.attributes || [...(labelTexts || []), text, value])]
10
+ params.page ||= 1
11
+ params.limit ||= 20
12
+ params.where ||= {}
13
+ const ors = []
14
+ if (keywords?.length) {
15
+ if (labelTexts?.length > 1) {
16
+ labelTexts.forEach(t => {
17
+ keywords.forEach(k => {
18
+ ors.push({ [t]: { '[Op.like]': `%${k}%` } })
19
+ })
20
+ })
21
+ } else {
22
+ keywords.forEach(k => {
23
+ ors.push({ [text]: { '[Op.like]': `%${k}%` } })
24
+ })
25
+ }
26
+ }
27
+ if (ors.length) params.where['[Op.or]'] = ors
28
+ const data = await restful.search(vm.modelName, params, 'data')
29
+ if ($props.modelValue != undefined && $props.modelValue !== '') {
30
+ const values = Array.isArray($props.modelValue) ? $props.modelValue : [$props.modelValue]
31
+ const allValues = data.map(ele => ele[value])
32
+ const unfoundValues = values.filter(v => !allValues.includes(v))
33
+ if (unfoundValues.length) {
34
+ const unfoundData = await restful.search(vm.modelName, {
35
+ ...params,
36
+ where: {
37
+ [value]: { '[Op.in]': unfoundValues }
38
+ }
39
+ }, 'data')
40
+ data.push(...unfoundData)
41
+ }
42
+ data.sort((a, b) => values.indexOf(b[value]) - values.indexOf(a[value]))
43
+ }
44
+ vm.options.splice(0, vm.options.length, ...data)
45
+ vm.loading = false
46
+ vm.options._loading = false
47
+ }
48
+
49
+ const calcMainLabel = (option, vm) => {
50
+ if (!option || typeof option !== 'object') return option
51
+ if (!vm.labelTexts?.length) return highdict.get(option, vm.text)
52
+ return highdict.get(option, vm.labelTexts[0])
53
+ }
54
+
55
+ const calcRemarkLabel = (option, vm) => {
56
+ if (!option || typeof option !== 'object') return ''
57
+ if (!vm.labelTexts || vm.labelTexts.length < 2) return ''
58
+ const labels = vm.labelTexts.slice(1).map(text => highdict.get(option, text))
59
+ return '(' + labels.join(' - ') + ')'
60
+ }
61
+
62
+ export {
63
+ remoteSearch,
64
+ calcMainLabel,
65
+ calcRemarkLabel
66
+ }
@@ -0,0 +1,91 @@
1
+ import { markRaw } from 'vue'
2
+ import { formatOptions } from '../../utils/index.js'
3
+ import { remoteSearch, calcMainLabel, calcRemarkLabel } from '../xselect/util.js'
4
+
5
+ export default {
6
+ name: 'XSelectV2',
7
+ props: {
8
+ modelName: String,
9
+ params: Object,
10
+ plain: {
11
+ type: Boolean,
12
+ default: false
13
+ },
14
+ text: {
15
+ type: String,
16
+ default: 'text'
17
+ },
18
+ labelTexts: Array,
19
+ value: {
20
+ type: String,
21
+ default: 'value'
22
+ },
23
+ filterable: {
24
+ type: Boolean,
25
+ default: true
26
+ },
27
+ remote: {
28
+ type: Boolean,
29
+ default: false
30
+ },
31
+ sort: Boolean | String,
32
+ options: Array | Object,
33
+ },
34
+ data () {
35
+ return {
36
+ loading: false,
37
+ _options: [],
38
+ list: []
39
+ }
40
+ },
41
+ watch: {
42
+ options: {
43
+ immediate: true,
44
+ deep: true,
45
+ handler () {
46
+ const ops = formatOptions(this.options, this)
47
+ if (!this.$slots.custom) {
48
+ ops.forEach((op, index) => {
49
+ op._main_ = calcMainLabel(this.options[index], this)
50
+ op._remark_ = calcRemarkLabel(this.options[index], this)
51
+ })
52
+ }
53
+ this._options = markRaw(ops)
54
+ this.list = this._options
55
+ }
56
+ }
57
+ },
58
+ created () {
59
+ if (this.modelName) {
60
+ this.remoteSearch()
61
+ }
62
+ },
63
+ methods: {
64
+ formatOptions,
65
+ handleRemote (e) {
66
+ const keywords = e.target.value.trim()
67
+ if (keywords === this._last_keywords_) return
68
+ this._last_keywords_ = keywords
69
+ if (this.$attrs.remoteMethod) this.$attrs.remoteMethod(keywords)
70
+ else if (this.remoteSearch) this.remoteSearch(keywords)
71
+ },
72
+ filter (keywords) {
73
+ keywords = keywords.trim()
74
+ if (!keywords) {
75
+ return this.list = markRaw(this._options)
76
+ }
77
+ const isCustom = !!this.$slots.custom
78
+ this.list = markRaw(this._options.filter(op => {
79
+ let text = op.text
80
+ if (!isCustom) text += op._main_ + op._remark_
81
+ return text.includes(keywords)
82
+ }))
83
+ },
84
+ remoteSearch (query) {
85
+ if (!this.remote && !this.modelName) {
86
+ return this._options
87
+ }
88
+ remoteSearch(this.service.restful, query, this)
89
+ }
90
+ }
91
+ }
@@ -0,0 +1,46 @@
1
+ <script>
2
+ export { default } from './index.js'
3
+ </script>
4
+
5
+ <template>
6
+ <el-select-v2
7
+ class="x-select-v2 pc-x-select-v2"
8
+ :class="plain ? 'x-select-v2--plain' : ''"
9
+ :loading
10
+ v-bind="$attrs"
11
+ :options="list"
12
+ :props="{ label: 'text' }"
13
+ :filterable
14
+ :remote
15
+ clearable
16
+ :filter-method="remote ? undefined : ($attrs.filterMethod || filter)"
17
+ @keyup.enter="handleRemote"
18
+ >
19
+ <template #default="{ item, index }">
20
+ <slot
21
+ v-if="$slots.custom"
22
+ name="custom"
23
+ :option="item"
24
+ :raw="item.raw"
25
+ />
26
+ <span v-else>
27
+ <span class="main">{{ item._main_ }}</span>
28
+ <span class="remark">{{ item._remark_ }}</span>
29
+ </span>
30
+ </template>
31
+ </el-select-v2>
32
+ </template>
33
+
34
+ <style lang="scss" scoped>
35
+ .x-select-v2--plain {
36
+ width: 100px;
37
+ :deep(.el-select__wrapper) {
38
+ box-shadow: none;
39
+ cursor: pointer;
40
+ }
41
+ }
42
+ .remark {
43
+ color: #a0aaaa;
44
+ margin-left: 10px;
45
+ }
46
+ </style>