@xmszm/core 0.0.1

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 (45) hide show
  1. package/dist/index.cjs +2 -0
  2. package/dist/index.mjs +2145 -0
  3. package/dist/style.css +1 -0
  4. package/docs/components/dataform.md +61 -0
  5. package/docs/components/datatable.md +77 -0
  6. package/docs/components/dialog.md +78 -0
  7. package/docs/components/options.md +55 -0
  8. package/docs/components/query.md +49 -0
  9. package/docs/components/utils.md +56 -0
  10. package/docs/guide/demo.md +213 -0
  11. package/docs/guide/quickstart.md +77 -0
  12. package/docs/index.md +25 -0
  13. package/docs/usage.md +61 -0
  14. package/examples/demo.vue +224 -0
  15. package/package.json +64 -0
  16. package/src/dialog/commonDialog.jsx +230 -0
  17. package/src/dialog/style/commonDialog.less +40 -0
  18. package/src/dialog/utils/dialog.js +82 -0
  19. package/src/enum/options.js +3 -0
  20. package/src/enum/sort.jsx +31 -0
  21. package/src/form/DataForm.vue +125 -0
  22. package/src/image/ImagesUpload.vue +268 -0
  23. package/src/image/SvgIcon.vue +30 -0
  24. package/src/index.js +46 -0
  25. package/src/list/useList.jsx +99 -0
  26. package/src/options/Options.jsx +338 -0
  27. package/src/options/defaultOptions.jsx +580 -0
  28. package/src/options/options.md +77 -0
  29. package/src/plugin/vite/initRouteMeta.js +54 -0
  30. package/src/query/CommonQuery.vue +272 -0
  31. package/src/store/utils/index.js +6 -0
  32. package/src/table/DataTable.vue +315 -0
  33. package/src/table/FilterDialog.vue +157 -0
  34. package/src/table/opr/DataColumnCollet.jsx +127 -0
  35. package/src/table/opr/useDataColumn.jsx +196 -0
  36. package/src/table/opr/useDataColumnButton.jsx +56 -0
  37. package/src/table/opr/useDataColumnPop.jsx +57 -0
  38. package/src/table/test.md +248 -0
  39. package/src/table/utils/ellipsis.js +22 -0
  40. package/src/utils/array.js +26 -0
  41. package/src/utils/auth.js +118 -0
  42. package/src/utils/object.js +32 -0
  43. package/src/utils/time.js +7 -0
  44. package/src/utils/upload.js +46 -0
  45. package/types/index.d.ts +67 -0
@@ -0,0 +1,82 @@
1
+ export const dialogDefaultOption = {
2
+ showIcon: false,
3
+ autoFocus: false,
4
+ }
5
+
6
+ export function initRules({
7
+ options = [],
8
+ model,
9
+ labelField = 'label',
10
+ formOpr = {},
11
+ }) {
12
+ return computed(
13
+ () =>
14
+ options?.reduce((o, { fields, ...n }) => {
15
+ if (Array.isArray(n?.key)) {
16
+ n.key.forEach((v) => {
17
+ if(n?.required) o[String(v)] = {
18
+ key:v,
19
+ type:'any',
20
+ required: n?.required
21
+ ? typeof n?.required === 'function'
22
+ ? n?.required(unref(model), { ...formOpr })
23
+ : n?.required
24
+ : false,
25
+ message: n?.message || `请选择${n?.[labelField]}`,
26
+ fields,
27
+ }
28
+ })
29
+ }
30
+ // } else {
31
+ const rule = n?.rule
32
+ ? typeof n?.rule !== 'function'
33
+ ? n?.rule
34
+ : n?.rule(unref(model), { ...formOpr })
35
+ : fields
36
+ ? {
37
+ key: n?.key,
38
+ type:'any',
39
+ required: n?.required
40
+ ? typeof n?.required === 'function'
41
+ ? n?.required(unref(model), { ...formOpr })
42
+ : n?.required
43
+ : false,
44
+ message:
45
+ n?.message
46
+ || `请${n?.options?.length ? '选择' : '输入'}${n?.[labelField]}`,
47
+ fields,
48
+ }
49
+ : {
50
+ key: n?.key,
51
+ type:'any',
52
+ required: n?.required
53
+ ? typeof n?.required === 'function'
54
+ ? n?.required(unref(model), { ...formOpr })
55
+ : n?.required
56
+ : false,
57
+ message:
58
+ n?.message
59
+ || `请${n?.options?.length ? '选择' : '输入'}${n?.[labelField]}`,
60
+ ...(Array.isArray(n?.key)
61
+ ? {
62
+ validator: (rule) => {
63
+ console.log(rule)
64
+
65
+ const obj = n?.key.every(v => unref(model)[v])
66
+ if (!obj && n?.required)
67
+ return new Error(rule?.message)
68
+
69
+ return true
70
+ },
71
+ }
72
+ : {}),
73
+ }
74
+ if(rule?.required){
75
+ o[String(n?.key)] = rule
76
+ }
77
+ // }
78
+
79
+ return o
80
+ }, {}) || {},
81
+ )
82
+ }
@@ -0,0 +1,3 @@
1
+ export const labelField = 'name'
2
+
3
+ export const valueField = 'id'
@@ -0,0 +1,31 @@
1
+ import { ChevronDown, ChevronUp, Code } from '@vicons/ionicons5'
2
+
3
+ export const orderEnum = {
4
+ ascend: {
5
+ title: '升序',
6
+ value: true,
7
+ Icon: <ChevronUp />,
8
+ fn: (listQuery, key) => {
9
+ listQuery.desc = true
10
+ listQuery.sortFieldName = key
11
+ },
12
+ },
13
+ descend: {
14
+ title: '降序',
15
+ value: false,
16
+ Icon: <ChevronDown />,
17
+ fn: (listQuery) => {
18
+ listQuery.sortFieldName = ''
19
+ listQuery.desc = true
20
+ },
21
+ },
22
+ false: {
23
+ title: '默认',
24
+ value: null,
25
+ Icon: <Code style="transform:rotateZ(90deg)" />,
26
+ fn: (listQuery) => {
27
+ listQuery.desc = false
28
+ listQuery.sortFieldName = ''
29
+ },
30
+ },
31
+ }
@@ -0,0 +1,125 @@
1
+ <script setup>
2
+ import { NForm } from 'naive-ui'
3
+ import { ref, unref } from 'vue'
4
+
5
+ import Options from '../options/Options.jsx'
6
+ import {initRules} from '../dialog/utils/dialog.js'
7
+ import { toArray } from 'core'
8
+ const props = defineProps({
9
+ isNo: {
10
+ type: Boolean,
11
+ default: () => true
12
+ },
13
+ read: {
14
+ type: Boolean,
15
+ default: () => false
16
+ },
17
+ labelField: {
18
+ type: String,
19
+ default: () => 'label'
20
+ },
21
+ contentStyle: {
22
+ type: Object,
23
+ default: () => ({})
24
+ },
25
+ options: {
26
+ type: Array,
27
+ default: () => []
28
+ },
29
+ rules: {
30
+ type: Object,
31
+ default: () => ({})
32
+ },
33
+ formProps: {
34
+ type: Object,
35
+ default: () => ({})
36
+ },
37
+ formItemProps: {
38
+ type: Object,
39
+ default: () => ({})
40
+ },
41
+ dialog: {
42
+ type: Boolean,
43
+ default: () => false
44
+ }
45
+ })
46
+ const _options = computed(() => props.options)
47
+ // ====== 复制 initRules 逻辑 ======
48
+
49
+ const formRef = ref()
50
+
51
+ const _model = defineModel('value', {
52
+ type: Object,
53
+ default: () => ({})
54
+ })
55
+
56
+ // 自动生成 rules,优先用 props.rules
57
+ const autoRules = computed(() => {
58
+ return unref(
59
+ _options.value
60
+ ? initRules({
61
+ options: _options.value,
62
+ model: _model,
63
+ labelField: props.labelField,
64
+ formOpr: { formRef }
65
+ })
66
+ : {}
67
+ )
68
+ })
69
+ console.log(autoRules.value);
70
+
71
+ defineExpose({
72
+ formRef,
73
+ getRule: () => autoRules.value,
74
+ valid: (keyCode = []) =>{
75
+ console.log('?? valid',keyCode);
76
+ return new Promise((resolve, reject) => {
77
+ const arrCode = toArray(keyCode)
78
+ formRef.value?.validate((v) => {
79
+ if (v) return reject(v)
80
+ resolve()
81
+ },(v)=> arrCode.length ? arrCode.includes(v?.key) : true)
82
+ })
83
+ },
84
+ confirm: (fn) =>
85
+ new Promise((resolve, reject) => {
86
+ formRef.value?.validate((v) => {
87
+ if (v) return reject(v)
88
+ fn && fn(unref(_model))
89
+ resolve(unref(_model))
90
+ })
91
+ })
92
+ })
93
+ </script>
94
+
95
+ <template>
96
+ <NForm
97
+ ref="formRef"
98
+ :model="_model"
99
+ :rules="props.read ? {} : autoRules"
100
+ label-placement="left"
101
+ label-width="100px"
102
+ require-mark-placement="right-hanging"
103
+ :class="
104
+ props.dialog
105
+ ? props.read
106
+ ? 'core-dialog-content'
107
+ : 'core-dialog-main'
108
+ : ''
109
+ "
110
+ :style="{ minHeight: props.isNo ? 'unset' : null }"
111
+ v-bind="props.formProps"
112
+ >
113
+ <Options
114
+ v-model:value="_model"
115
+ :form-ref="formRef"
116
+ :option="props.options"
117
+ :label-field="props.labelField"
118
+ :read="props.read"
119
+ :style="props.contentStyle"
120
+ :form-props="props.formProps"
121
+ />
122
+ </NForm>
123
+ </template>
124
+
125
+ <style lang="less" scoped></style>
@@ -0,0 +1,268 @@
1
+ <script setup lang="jsx">
2
+ // import { FilePath } from '@/api/upload'
3
+ import dayjs from 'dayjs'
4
+ import { ref, watch } from 'vue'
5
+ import { customUpload,getFileUrl } from '../utils/upload'
6
+
7
+ const props = defineProps({
8
+ value: {
9
+ type: [Array, String],
10
+ default: () => [],
11
+ },
12
+ max: {
13
+ type: Number,
14
+ default: () => 5,
15
+ },
16
+ lib: {
17
+ type: Boolean,
18
+ default: () => true,
19
+ },
20
+ clip: {
21
+ type: Boolean,
22
+ default: () => false,
23
+ },
24
+ read: {
25
+ type: Boolean,
26
+ default: () => false,
27
+ },
28
+ size: {
29
+ type: Number,
30
+ default: () => 100,
31
+ },
32
+ width: {
33
+ type: Number,
34
+ default: () => 100,
35
+ },
36
+ height: {
37
+ type: Number,
38
+ default: () => 100,
39
+ },
40
+ mode: {
41
+ type: String,
42
+ default: () => 'fill',
43
+ },
44
+ formData:{
45
+ type: Object,
46
+ default: () => {},
47
+ }
48
+ })
49
+
50
+ const emit = defineEmits(['update:value', 'complete'])
51
+
52
+ const FilePath = '/admin/file'
53
+
54
+ const _value = ref([])
55
+ watch(
56
+ () => props.value,
57
+ (value) => {
58
+ console.log('props.value', value)
59
+ _value.value
60
+ = props.max === 1
61
+ ? value
62
+ ? typeof value !== 'string'
63
+ ? value?.length
64
+ ? [
65
+ {
66
+ id: dayjs().valueOf(),
67
+ name: `img${dayjs().valueOf()}`,
68
+ url: getFileUrl(value[0]),
69
+ thumbnailUrl: getFileUrl(value[0]),
70
+ fullPath: value[0],
71
+ status: 'finished',
72
+ },
73
+ ]
74
+ : []
75
+ : [
76
+ {
77
+ id: dayjs().valueOf(),
78
+ name: `img${dayjs().valueOf()}`,
79
+ url: getFileUrl(value),
80
+ fullPath: value,
81
+ thumbnailUrl: getFileUrl(value),
82
+ status: 'finished',
83
+ },
84
+ ]
85
+ : []
86
+ : value?.map((v, i) => ({
87
+ id: dayjs().valueOf() + i,
88
+ name: `img${dayjs().valueOf()}`,
89
+ url: getFileUrl(v),
90
+ fullPath: v,
91
+ thumbnailUrl: getFileUrl(v),
92
+ status: 'finished',
93
+ })) || []
94
+
95
+ console.log('1', _value.value)
96
+ },
97
+ { immediate: true },
98
+ )
99
+ function customRequestMethod(...arg) {
100
+ sendImgRequest(arg[0])
101
+ }
102
+
103
+ async function sendImgRequest({ file, onFinish, onError, onProgress }, fn) {
104
+ const formData = new FormData()
105
+ if (file.status === 'pending') {
106
+ formData.append('file', file.file)
107
+ if(props.formData && Object.keys(props.formData).length){
108
+ Object.keys(props.formData).forEach(key => {
109
+ formData.append(key, props.formData[key])
110
+ })
111
+ }
112
+ customUpload({
113
+ url: FilePath,
114
+ data: formData,
115
+ method: 'post',
116
+ onUploadProgress: ({ percent }) => onProgress({ percent }),
117
+ })
118
+ .then((res) => {
119
+ const { url } = res.data
120
+ file.url = getFileUrl(url)
121
+ file.fullPath = url
122
+ file.thumbnailUrl = getFileUrl(url)
123
+ // onError()
124
+ onFinish()
125
+ onSubmit()
126
+ })
127
+ .catch(() => {
128
+ file = null
129
+ onError()
130
+ })
131
+ .finally(() => {
132
+ fn && fn()
133
+ })
134
+ }
135
+ }
136
+
137
+ function onSubmit() {
138
+ console.log('onSubmit', _value.value)
139
+
140
+ const arr = _value.value.reduce((o, n) => {
141
+ if (n.status === 'finished' && n?.fullPath) {
142
+ o.push(n.fullPath)
143
+ }
144
+ return o
145
+ }, [])
146
+ if (props.max === 1 && arr.length === 1) {
147
+ emit('update:value', arr[0])
148
+ }
149
+ else if (arr.length) {
150
+ emit('update:value', arr)
151
+ }
152
+ else {
153
+ emit('update:value', props.max === 1 ? null : [])
154
+ }
155
+ }
156
+ </script>
157
+
158
+ <template>
159
+ <n-space align="end" :wrap-item="false">
160
+ <n-upload
161
+ v-model:file-list="_value"
162
+ accept=".jpeg,.jpg,.png"
163
+ list-type="image-card"
164
+ :custom-request="customRequestMethod"
165
+ :max="
166
+ props.read
167
+ ? Array.isArray(props.value)
168
+ ? props.value.length
169
+ : 1
170
+ : props.max
171
+ "
172
+ :show-retry-button="false"
173
+ :show-remove-button="!props.read"
174
+ class="upload-box"
175
+ :style="{
176
+ ...(props.size
177
+ ? { '--image-w': `${props.size}px`, '--image-h': `${props.size}px` }
178
+ : {
179
+ '--image-w': `${props.width}px`,
180
+ '--image-h': `${props.height}px`,
181
+ }),
182
+ '--image-mode': props.mode,
183
+ }"
184
+ @finish="
185
+ () => {
186
+ onSubmit();
187
+ emit('complete');
188
+ }
189
+ "
190
+ @remove="
191
+ (_, index) => {
192
+ _value.splice(index, 1);
193
+ onSubmit();
194
+
195
+ return false;
196
+ }
197
+ "
198
+ />
199
+ </n-space>
200
+ </template>
201
+
202
+ <style scoped lang="less">
203
+ .upload-box {
204
+ width: auto;
205
+ :deep(.n-upload-file-list.n-upload-file-list--grid) {
206
+ display: flex;
207
+ flex-wrap: wrap;
208
+ }
209
+ :deep(.n-upload-file.n-upload-file--image-card-type) {
210
+ width: var(--image-w);
211
+ height: var(--image-h);
212
+
213
+ & .n-image img {
214
+ object-fit: var(--image-mode) !important;
215
+ }
216
+ }
217
+ :deep(.n-upload-trigger--image-card) {
218
+ width: var(--image-w);
219
+ height: var(--image-h);
220
+ }
221
+
222
+ :deep(.n-upload-file--error-status:not(:hover)),
223
+ :deep(.n-upload-file--info-status:not(:hover)) {
224
+ .n-upload-file-info {
225
+ position: relative;
226
+ &::after {
227
+ content: '';
228
+ position: absolute;
229
+ top: 0;
230
+ left: 0;
231
+ right: 0;
232
+ bottom: 0;
233
+ z-index: 5;
234
+ display: block;
235
+ background-color: rgba(0, 0, 0, 0.4);
236
+ }
237
+ }
238
+ }
239
+ :deep(.n-upload-file--error-status:not(:hover)) {
240
+ &::after {
241
+ font-size: 12px;
242
+ white-space: nowrap;
243
+ content: '上传失败~';
244
+ position: absolute;
245
+ color: rgba(255, 255, 255, 0.75);
246
+ top: 50%;
247
+ left: 50%;
248
+ transform: translate(-50%, -50%);
249
+ z-index: 5;
250
+ display: block;
251
+ }
252
+ }
253
+ :deep(.n-upload-file--info-status:not(:hover)) {
254
+ &::after {
255
+ font-size: 12px;
256
+ white-space: nowrap;
257
+ content: '加载中~';
258
+ position: absolute;
259
+ color: rgba(255, 255, 255, 0.75);
260
+ top: 50%;
261
+ left: 50%;
262
+ transform: translate(-50%, -50%);
263
+ z-index: 5;
264
+ display: block;
265
+ }
266
+ }
267
+ }
268
+ </style>
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
4
+ const props = defineProps({
5
+ name: {
6
+ type: String,
7
+ required: true,
8
+ },
9
+ color: {
10
+ type: String,
11
+ default: '',
12
+ },
13
+ })
14
+ const iconName = computed(() => `#svg-${props.name}`)
15
+ </script>
16
+
17
+ <template>
18
+ <svg class="svg-icon" v-bind="$attrs" :style="{ color }" aria-hidden>
19
+ <use :xlink:href="iconName" :fill="color" />
20
+ </svg>
21
+ </template>
22
+
23
+ <style scoped>
24
+ .svg-icon {
25
+ width: inherit;
26
+ height: inherit;
27
+ fill: currentColor;
28
+ vertical-align: middle;
29
+ }
30
+ </style>
package/src/index.js ADDED
@@ -0,0 +1,46 @@
1
+ export { commonDialogMethod } from './dialog/commonDialog'
2
+
3
+ export { default as DataForm } from './form/DataForm.vue'
4
+ export {
5
+ getAllOptions,
6
+ getOptions,
7
+ setupOptions,
8
+ } from './options/defaultOptions'
9
+ export { default as Options } from './options/Options.jsx'
10
+ export { default as CommonQuery } from './query/CommonQuery.vue'
11
+
12
+ export { createActionColumnJsx } from './table/opr/useDataColumn'
13
+
14
+ export { default as OprButton } from './table/opr/useDataColumnButton.jsx'
15
+
16
+ export { default as Pop } from './table/opr/useDataColumnPop.jsx'
17
+
18
+ export { toArray } from './utils/array'
19
+
20
+ export {
21
+ cellectChildenPermission,
22
+ handleParams,
23
+ useApiConfig,
24
+ } from './utils/auth'
25
+
26
+ export { ObjectToArray } from './utils/object'
27
+
28
+ export { ArrayToObject } from './utils/array'
29
+
30
+
31
+
32
+ export { customUpload, registryUpload } from './utils/upload'
33
+
34
+ export { default as DataTable } from './table/DataTable.vue'
35
+
36
+
37
+ export { labelField as globalLabelField,valueField as globalValueField } from './enum/options'
38
+
39
+
40
+ export {initRules} from './dialog/utils/dialog.js'
41
+
42
+ export { ellipsis } from './table/utils/ellipsis.js'
43
+
44
+ export { initRouteMeta } from './plugin/vite/initRouteMeta'
45
+
46
+ export { orderEnum } from './enum/sort'
@@ -0,0 +1,99 @@
1
+ import { computed, ref, unref, watch } from 'vue'
2
+
3
+ export function useList(source = [], filterOptions = []) {
4
+ const loading = ref(false)
5
+ const data = ref([])
6
+ const sourceList = computed(() => unref(source))
7
+
8
+ const model = ref({
9
+ andQuery: {},
10
+ likeQuery: {},
11
+ })
12
+
13
+ function onSearch() {
14
+ loading.value = true
15
+ console.log(unref(model))
16
+
17
+ data.value = handleFilterOption(
18
+ handleFilterValue(unref(filterOptions), unref(model)),
19
+ unref(source),
20
+ )
21
+ console.log(data.value)
22
+
23
+ loading.value = false
24
+ }
25
+
26
+ function initData() {
27
+ data.value = sourceList.value
28
+ }
29
+
30
+ watch(
31
+ () => sourceList.value.length,
32
+ () => {
33
+ initData()
34
+ console.log('data')
35
+ },
36
+ {
37
+ once: true,
38
+ },
39
+ )
40
+
41
+ return {
42
+ loading,
43
+ data,
44
+ model,
45
+ initData,
46
+ onSearch,
47
+ onClear: () => {
48
+ model.value = {}
49
+ onSearch()
50
+ },
51
+ }
52
+ }
53
+
54
+ export const matchMethod = {
55
+ andQuery: (data, value) =>
56
+ Array.isArray(value) ? value.includes(data) : data === value,
57
+ likeQuery: (data, value) => data?.indexOf(value) > -1,
58
+ }
59
+
60
+ export function handleFilterValue(runOptions, model) {
61
+ console.log('handleFilterValue', runOptions)
62
+
63
+ return runOptions
64
+ .map((v) => {
65
+ const filedValue = v?.key || v?.value
66
+ const value = v?.queryType
67
+ ? model?.[v?.queryType]?.[filedValue]
68
+ : model?.[filedValue]
69
+ return typeof value === 'number' || value
70
+ ? {
71
+ ...v,
72
+ key: filedValue,
73
+ type: v?.queryType,
74
+ value,
75
+ }
76
+ : undefined
77
+ })
78
+ .filter(v => v)
79
+ }
80
+
81
+ export function handleFilterOption(runOption, options) {
82
+ console.log('runOption', runOption)
83
+
84
+ if (runOption.length) {
85
+ return options?.filter(item =>
86
+ runOption.length === 1
87
+ ? matchMethod?.[runOption?.[0].type](
88
+ item?.[runOption?.[0]?.key],
89
+ runOption?.[0]?.value,
90
+ )
91
+ : runOption?.every(v =>
92
+ matchMethod?.[v.type](item?.[v.key], v.value),
93
+ ),
94
+ )
95
+ }
96
+ else {
97
+ return options
98
+ }
99
+ }