@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.
- package/dist/index.cjs +2 -0
- package/dist/index.mjs +2145 -0
- package/dist/style.css +1 -0
- package/docs/components/dataform.md +61 -0
- package/docs/components/datatable.md +77 -0
- package/docs/components/dialog.md +78 -0
- package/docs/components/options.md +55 -0
- package/docs/components/query.md +49 -0
- package/docs/components/utils.md +56 -0
- package/docs/guide/demo.md +213 -0
- package/docs/guide/quickstart.md +77 -0
- package/docs/index.md +25 -0
- package/docs/usage.md +61 -0
- package/examples/demo.vue +224 -0
- package/package.json +64 -0
- package/src/dialog/commonDialog.jsx +230 -0
- package/src/dialog/style/commonDialog.less +40 -0
- package/src/dialog/utils/dialog.js +82 -0
- package/src/enum/options.js +3 -0
- package/src/enum/sort.jsx +31 -0
- package/src/form/DataForm.vue +125 -0
- package/src/image/ImagesUpload.vue +268 -0
- package/src/image/SvgIcon.vue +30 -0
- package/src/index.js +46 -0
- package/src/list/useList.jsx +99 -0
- package/src/options/Options.jsx +338 -0
- package/src/options/defaultOptions.jsx +580 -0
- package/src/options/options.md +77 -0
- package/src/plugin/vite/initRouteMeta.js +54 -0
- package/src/query/CommonQuery.vue +272 -0
- package/src/store/utils/index.js +6 -0
- package/src/table/DataTable.vue +315 -0
- package/src/table/FilterDialog.vue +157 -0
- package/src/table/opr/DataColumnCollet.jsx +127 -0
- package/src/table/opr/useDataColumn.jsx +196 -0
- package/src/table/opr/useDataColumnButton.jsx +56 -0
- package/src/table/opr/useDataColumnPop.jsx +57 -0
- package/src/table/test.md +248 -0
- package/src/table/utils/ellipsis.js +22 -0
- package/src/utils/array.js +26 -0
- package/src/utils/auth.js +118 -0
- package/src/utils/object.js +32 -0
- package/src/utils/time.js +7 -0
- package/src/utils/upload.js +46 -0
- package/types/index.d.ts +67 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
<script setup lang="jsx">
|
|
2
|
+
import { RefreshOutline, SearchOutline } from '@vicons/ionicons5'
|
|
3
|
+
import { DataForm } from 'core'
|
|
4
|
+
import { getOptions } from 'core/options/defaultOptions.jsx'
|
|
5
|
+
import { ObjectToArray } from 'core/utils/object.js'
|
|
6
|
+
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
7
|
+
|
|
8
|
+
// 防抖函数
|
|
9
|
+
function debounce(func, delay) {
|
|
10
|
+
let timeoutId
|
|
11
|
+
return function (...args) {
|
|
12
|
+
clearTimeout(timeoutId)
|
|
13
|
+
timeoutId = setTimeout(() => {
|
|
14
|
+
func.apply(this, args)
|
|
15
|
+
}, delay)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const emit = defineEmits(['update:query', 'submit', 'reset'])
|
|
19
|
+
|
|
20
|
+
const props = defineProps({
|
|
21
|
+
inlineText: {
|
|
22
|
+
type: Boolean,
|
|
23
|
+
default: () => true,
|
|
24
|
+
},
|
|
25
|
+
options: {
|
|
26
|
+
type: Array,
|
|
27
|
+
default: () => [],
|
|
28
|
+
},
|
|
29
|
+
query: {
|
|
30
|
+
type: Object,
|
|
31
|
+
default: () => ({}),
|
|
32
|
+
},
|
|
33
|
+
selectCount: {
|
|
34
|
+
type: Number,
|
|
35
|
+
default: () => 1,
|
|
36
|
+
},
|
|
37
|
+
type: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: () => 'primary',
|
|
40
|
+
},
|
|
41
|
+
noButton: {
|
|
42
|
+
type: Boolean,
|
|
43
|
+
default: () => false,
|
|
44
|
+
},
|
|
45
|
+
isRead: {
|
|
46
|
+
type: Boolean,
|
|
47
|
+
default: () => false,
|
|
48
|
+
},
|
|
49
|
+
btn: {
|
|
50
|
+
type: Array,
|
|
51
|
+
default: () => ['reset', 'search'],
|
|
52
|
+
},
|
|
53
|
+
size: {
|
|
54
|
+
type: String,
|
|
55
|
+
default: () => 'medium',
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
function onBeforeOptions(arr){
|
|
61
|
+
return arr.map(v=>({
|
|
62
|
+
...v,
|
|
63
|
+
props:{
|
|
64
|
+
...v.props,
|
|
65
|
+
...((!v.way ||v.way==='input')? {
|
|
66
|
+
onUpdateValue: (...v) => {
|
|
67
|
+
v.props?.onUpdateValue?.(...v)
|
|
68
|
+
debouncedSubmit()
|
|
69
|
+
}
|
|
70
|
+
}: {}),
|
|
71
|
+
...(v?.way === 'select' ? {
|
|
72
|
+
onUpdateValue: (...v) => {
|
|
73
|
+
v.props?.onUpdateValue?.(...v)
|
|
74
|
+
debouncedSubmit()
|
|
75
|
+
}
|
|
76
|
+
}: {})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 创建防抖的提交函数(500ms延迟)
|
|
83
|
+
const debouncedSubmit = debounce(() => {
|
|
84
|
+
emit('submit')
|
|
85
|
+
}, 500)
|
|
86
|
+
|
|
87
|
+
function onSubmit() {
|
|
88
|
+
// loading.value = true
|
|
89
|
+
debouncedSubmit()
|
|
90
|
+
// loading.value = false
|
|
91
|
+
// return false
|
|
92
|
+
}
|
|
93
|
+
const loading = ref(false)
|
|
94
|
+
const _query = defineModel('query', {
|
|
95
|
+
type: Object,
|
|
96
|
+
default: () => ({}),
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
const defaultFormItemProps = {
|
|
100
|
+
style: {
|
|
101
|
+
width: '33%',
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
const _queryOptionsKey = computed(() =>
|
|
105
|
+
props.options?.map(v => v?.way || 'input'),
|
|
106
|
+
)
|
|
107
|
+
const defaultOptions = getOptions(_queryOptionsKey.value)
|
|
108
|
+
|
|
109
|
+
const _queryOptions = computed(() => {
|
|
110
|
+
try {
|
|
111
|
+
const arr = []
|
|
112
|
+
for (let i = 0; i < props.options.length; i++) {
|
|
113
|
+
const v = props.options[i]
|
|
114
|
+
if (v?.enum && !v?.options)
|
|
115
|
+
v.options = ObjectToArray(v.enum)
|
|
116
|
+
if (!v?.props) {
|
|
117
|
+
v.props = {
|
|
118
|
+
size: props.size,
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!v?.formItemProps) {
|
|
123
|
+
v.formItemProps = { ...defaultFormItemProps }
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
v.formItemProps = {
|
|
127
|
+
...defaultFormItemProps,
|
|
128
|
+
...v.formItemProps,
|
|
129
|
+
style: { ...defaultFormItemProps.style, ...v.formItemProps.style },
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const key = v?.key || v?.value
|
|
134
|
+
if (!key)
|
|
135
|
+
throw new Error('key no set')
|
|
136
|
+
arr.push({
|
|
137
|
+
...v,
|
|
138
|
+
|
|
139
|
+
key,
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
return onBeforeOptions(arr)
|
|
143
|
+
}
|
|
144
|
+
catch (e) {
|
|
145
|
+
console.warn('error', e)
|
|
146
|
+
return []
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
const classComponent = {
|
|
151
|
+
input: '',
|
|
152
|
+
select: '',
|
|
153
|
+
dateRange: 'input-range',
|
|
154
|
+
dateRangeTime: 'input-range-time',
|
|
155
|
+
}
|
|
156
|
+
const defaultBtnProps = {
|
|
157
|
+
style: {
|
|
158
|
+
borderRadius: '3px',
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
const defaultBtn = {
|
|
162
|
+
search: () => (
|
|
163
|
+
<NButton
|
|
164
|
+
type={props.type}
|
|
165
|
+
loading={loading.value}
|
|
166
|
+
default-props={{ attrType: 'submit' }}
|
|
167
|
+
onClick={() => onSubmit()}
|
|
168
|
+
{...defaultBtnProps}
|
|
169
|
+
>
|
|
170
|
+
{{
|
|
171
|
+
default: () => '搜索',
|
|
172
|
+
icon: () => <SearchOutline />,
|
|
173
|
+
}}
|
|
174
|
+
</NButton>
|
|
175
|
+
),
|
|
176
|
+
reset: () => (
|
|
177
|
+
<NButton
|
|
178
|
+
type="default"
|
|
179
|
+
onClick={() => {
|
|
180
|
+
clearQuery()
|
|
181
|
+
}}
|
|
182
|
+
{...defaultBtnProps}
|
|
183
|
+
>
|
|
184
|
+
{{
|
|
185
|
+
default: () => '重置',
|
|
186
|
+
icon: () => <RefreshOutline />,
|
|
187
|
+
}}
|
|
188
|
+
</NButton>
|
|
189
|
+
),
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function clearQuery() {
|
|
193
|
+
props.options.forEach((v) => {
|
|
194
|
+
const key = v?.key || v?.value
|
|
195
|
+
if (key) {
|
|
196
|
+
if (v?.queryType)
|
|
197
|
+
_query.value[v.queryType][key] = null
|
|
198
|
+
else _query.value[key] = null
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
emit('reset')
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// 全局监听 Enter 键的方法
|
|
205
|
+
function handleGlobalEnter(event) {
|
|
206
|
+
// 检查是否按下了 Enter 键
|
|
207
|
+
if (event.key === 'Enter') {
|
|
208
|
+
// 检查是否在输入框、选择框等表单元素中
|
|
209
|
+
// const target = event.target
|
|
210
|
+
// const isFormElement = target.tagName === 'INPUT' ||
|
|
211
|
+
// target.tagName === 'SELECT' ||
|
|
212
|
+
// target.tagName === 'TEXTAREA' ||
|
|
213
|
+
// target.contentEditable === 'true'
|
|
214
|
+
|
|
215
|
+
// if (isFormElement) {
|
|
216
|
+
// // 阻止默认行为(如换行)
|
|
217
|
+
// event.preventDefault()
|
|
218
|
+
// // 触发搜索
|
|
219
|
+
|
|
220
|
+
// }
|
|
221
|
+
onSubmit()
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// 组件挂载时添加全局监听
|
|
226
|
+
onMounted(() => {
|
|
227
|
+
document.addEventListener('keydown', handleGlobalEnter)
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
// 组件卸载时移除全局监听
|
|
231
|
+
onUnmounted(() => {
|
|
232
|
+
document.removeEventListener('keydown', handleGlobalEnter)
|
|
233
|
+
})
|
|
234
|
+
</script>
|
|
235
|
+
|
|
236
|
+
<template>
|
|
237
|
+
<n-space
|
|
238
|
+
:wrap-item="false"
|
|
239
|
+
justify="space-between"
|
|
240
|
+
align="center"
|
|
241
|
+
:wrap="false"
|
|
242
|
+
>
|
|
243
|
+
<div class="flex-1">
|
|
244
|
+
<DataForm
|
|
245
|
+
v-model:value="_query"
|
|
246
|
+
:options="_queryOptions"
|
|
247
|
+
:form-props="{ showFeedback: false }"
|
|
248
|
+
/>
|
|
249
|
+
</div>
|
|
250
|
+
<n-space v-if="!props.noButton" align="center" :wrap="false">
|
|
251
|
+
<slot name="left-btn" />
|
|
252
|
+
<template v-for="(itm, idx) in props.btn" :key="idx">
|
|
253
|
+
<component :is="defaultBtn?.[itm]?.()" />
|
|
254
|
+
</template>
|
|
255
|
+
<slot name="right-btn" />
|
|
256
|
+
</n-space>
|
|
257
|
+
</n-space>
|
|
258
|
+
</template>
|
|
259
|
+
|
|
260
|
+
<style scoped lang="less">
|
|
261
|
+
.select-text {
|
|
262
|
+
min-width: 100px;
|
|
263
|
+
max-width: 240px;
|
|
264
|
+
text-align: center;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.select-line-text {
|
|
268
|
+
text-align: center;
|
|
269
|
+
white-space: nowrap;
|
|
270
|
+
display: inline;
|
|
271
|
+
}
|
|
272
|
+
</style>
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
<script setup lang="jsx">
|
|
2
|
+
import { ChevronDown, ChevronUp, Code, Funnel } from '@vicons/ionicons5'
|
|
3
|
+
import { commonDialogMethod, toArray } from 'core'
|
|
4
|
+
import { ellipsis } from 'core/table/utils/ellipsis'
|
|
5
|
+
import dayjs from 'dayjs'
|
|
6
|
+
import { uniqueId } from 'lodash-es'
|
|
7
|
+
import { NButton, NTooltip } from 'naive-ui'
|
|
8
|
+
import { computed, onMounted, ref, unref, watch ,isProxy} from 'vue'
|
|
9
|
+
import { useRoute } from 'vue-router'
|
|
10
|
+
import FilterDialog from './FilterDialog.vue'
|
|
11
|
+
import { orderEnum } from 'core'
|
|
12
|
+
|
|
13
|
+
const props = defineProps({
|
|
14
|
+
data: {
|
|
15
|
+
type: Array,
|
|
16
|
+
default: () => [],
|
|
17
|
+
},
|
|
18
|
+
pagination: {
|
|
19
|
+
type: [Object, null],
|
|
20
|
+
default: () => undefined,
|
|
21
|
+
},
|
|
22
|
+
columns: {
|
|
23
|
+
type: Array,
|
|
24
|
+
default: () => [
|
|
25
|
+
{
|
|
26
|
+
title: '测试案例',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
oprColumns: {
|
|
31
|
+
type: [Object, null],
|
|
32
|
+
default: () => null,
|
|
33
|
+
},
|
|
34
|
+
selectColumns: {
|
|
35
|
+
type: [Object, null],
|
|
36
|
+
default: () => null,
|
|
37
|
+
},
|
|
38
|
+
defaultColumns: {
|
|
39
|
+
type: Array,
|
|
40
|
+
default: () => [],
|
|
41
|
+
},
|
|
42
|
+
summaryColumns: {
|
|
43
|
+
type: null,
|
|
44
|
+
default: () => null,
|
|
45
|
+
},
|
|
46
|
+
emptyText: {
|
|
47
|
+
type: String,
|
|
48
|
+
default: () => '没有数据',
|
|
49
|
+
},
|
|
50
|
+
emptyIcon: {
|
|
51
|
+
type: String,
|
|
52
|
+
default: () => '',
|
|
53
|
+
},
|
|
54
|
+
isFilter: {
|
|
55
|
+
type: Boolean,
|
|
56
|
+
default: () => false,
|
|
57
|
+
},
|
|
58
|
+
isEllipsis: {
|
|
59
|
+
type: Boolean,
|
|
60
|
+
default: () => true,
|
|
61
|
+
},
|
|
62
|
+
virtual: {
|
|
63
|
+
type: null,
|
|
64
|
+
default: () => {},
|
|
65
|
+
},
|
|
66
|
+
singleColumn: {
|
|
67
|
+
type: Boolean,
|
|
68
|
+
default: () => false,
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
const route = useRoute()
|
|
72
|
+
const FilterKey = 'filter_key'
|
|
73
|
+
const emit = defineEmits(['sorted'])
|
|
74
|
+
const _data = computed(() => {
|
|
75
|
+
console.log('table -data', props.data)
|
|
76
|
+
|
|
77
|
+
return props.data
|
|
78
|
+
})
|
|
79
|
+
function setHeadFilter(val) {
|
|
80
|
+
window.localStorage.setItem(FilterKey, JSON.stringify(val))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getHeadFilter() {
|
|
84
|
+
return JSON.parse(window.localStorage.getItem(FilterKey)) || {}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const getFilterAll = ref(getHeadFilter())
|
|
88
|
+
const headDefault = ref([])
|
|
89
|
+
|
|
90
|
+
const scrollX = ref(0)
|
|
91
|
+
|
|
92
|
+
function _summary(pageData) {
|
|
93
|
+
if (!props.summaryColumns)
|
|
94
|
+
return
|
|
95
|
+
return [
|
|
96
|
+
props.selectColumns,
|
|
97
|
+
...unref(props.columns),
|
|
98
|
+
props.oprColumns,
|
|
99
|
+
]?.reduce((o, n) => {
|
|
100
|
+
if (n?.key)
|
|
101
|
+
o[n.key] = props.summaryColumns?.(pageData)?.[n.key] || { value: null }
|
|
102
|
+
else o[uniqueId('table')] = { value: null }
|
|
103
|
+
return o
|
|
104
|
+
}, {})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const _columns = ref([])
|
|
108
|
+
|
|
109
|
+
watch(
|
|
110
|
+
() => unref(props.columns),
|
|
111
|
+
() => {
|
|
112
|
+
init()
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
immediate: true,
|
|
116
|
+
},
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
watch(
|
|
120
|
+
() => props.oprColumns,
|
|
121
|
+
(v) => {
|
|
122
|
+
console.log('oprColumns', v)
|
|
123
|
+
},
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
function init() {
|
|
127
|
+
const columns = unref(props.columns)
|
|
128
|
+
headDefault.value
|
|
129
|
+
= getFilterAll.value?.[route.fullPath]
|
|
130
|
+
|| columns?.map((v, i) => v?.key || dayjs().valueOf() + i)
|
|
131
|
+
|
|
132
|
+
const arr = props.isFilter
|
|
133
|
+
? columns.filter(item => headDefault.value?.includes(item.key))
|
|
134
|
+
: [...columns]
|
|
135
|
+
if (props.selectColumns)
|
|
136
|
+
arr.unshift({ key: 'selectKey', ...props.selectColumns })
|
|
137
|
+
if (props.oprColumns)
|
|
138
|
+
arr.push(props.oprColumns)
|
|
139
|
+
let scrollNum = 0
|
|
140
|
+
_columns.value = arr.reduce((o, obj) => {
|
|
141
|
+
if (obj?.display)
|
|
142
|
+
console.log('display', obj?.display)
|
|
143
|
+
if (!(obj?.display ?? true))
|
|
144
|
+
return o
|
|
145
|
+
const v = {
|
|
146
|
+
'align': 'center',
|
|
147
|
+
'width': 120,
|
|
148
|
+
...obj,
|
|
149
|
+
'key': obj?.key || uniqueId('table'),
|
|
150
|
+
'ellipsis':
|
|
151
|
+
obj?.ellipsis || props.isEllipsis
|
|
152
|
+
? obj?.ellipsisProp
|
|
153
|
+
? obj?.ellipsisProp(ellipsis)
|
|
154
|
+
: ellipsis
|
|
155
|
+
: false,
|
|
156
|
+
'ellipsis-component': 'ellipsis' || 'performant-ellipsis',
|
|
157
|
+
'title': () => {
|
|
158
|
+
const title = obj?.label || obj?.title || ''
|
|
159
|
+
return (
|
|
160
|
+
<div style={{ width: '100%', whiteSpace: 'pre-wrap' }}>
|
|
161
|
+
{typeof title === 'string' ? title : title?.()}
|
|
162
|
+
</div>
|
|
163
|
+
)
|
|
164
|
+
},
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (obj?.sorter) {
|
|
168
|
+
v.renderSorterIcon = ({ order }) => {
|
|
169
|
+
const { Icon, title } = orderEnum[order]
|
|
170
|
+
return (
|
|
171
|
+
<NTooltip>
|
|
172
|
+
{{
|
|
173
|
+
trigger: () => Icon,
|
|
174
|
+
default: () => title,
|
|
175
|
+
}}
|
|
176
|
+
</NTooltip>
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
v.sorter = {
|
|
180
|
+
multiple: 1,
|
|
181
|
+
fn:obj.sorter
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
scrollNum += v?.width
|
|
187
|
+
? Number.parseInt(v?.width)
|
|
188
|
+
: null || v?.title?.length * v.length + 30 || 0
|
|
189
|
+
|
|
190
|
+
o.push(v)
|
|
191
|
+
return o
|
|
192
|
+
}, [])
|
|
193
|
+
scrollX.value = scrollNum
|
|
194
|
+
console.log('计算')
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function filterButton() {
|
|
198
|
+
return (
|
|
199
|
+
<NButton type="info" onClick={() => filterHandle()}>
|
|
200
|
+
{{
|
|
201
|
+
default: () => '筛选字段',
|
|
202
|
+
icon: () => <Funnel />,
|
|
203
|
+
}}
|
|
204
|
+
</NButton>
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function filterHandle() {
|
|
209
|
+
const { cancel } = commonDialogMethod(
|
|
210
|
+
{
|
|
211
|
+
title: '筛选字段',
|
|
212
|
+
read: true,
|
|
213
|
+
options: [
|
|
214
|
+
{
|
|
215
|
+
render: () => (
|
|
216
|
+
<FilterDialog
|
|
217
|
+
style={{
|
|
218
|
+
width: '100%',
|
|
219
|
+
margin: '0',
|
|
220
|
+
padding: 0,
|
|
221
|
+
}}
|
|
222
|
+
filterItem={unref(props.columns)}
|
|
223
|
+
selectItem={headDefault.value}
|
|
224
|
+
defaultItem={props.defaultColumns}
|
|
225
|
+
onSubmit={(v) => {
|
|
226
|
+
getFilterAll.value[route.fullPath] = v
|
|
227
|
+
setHeadFilter(getFilterAll.value)
|
|
228
|
+
init()
|
|
229
|
+
cancel()
|
|
230
|
+
}}
|
|
231
|
+
/>
|
|
232
|
+
),
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
closable: false,
|
|
238
|
+
style: {
|
|
239
|
+
width: '500px',
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function onSorter(e) {
|
|
246
|
+
console.log('onSorter', e)
|
|
247
|
+
if (!e)
|
|
248
|
+
return
|
|
249
|
+
const sortArr = toArray(e)
|
|
250
|
+
|
|
251
|
+
sortArr.forEach(v => {
|
|
252
|
+
console.log('v', v)
|
|
253
|
+
|
|
254
|
+
if (v?.sorter) {
|
|
255
|
+
v?.sorter?.fn
|
|
256
|
+
((listQuery, pageState, key) => {
|
|
257
|
+
orderEnum[v.order]?.fn(listQuery, key)
|
|
258
|
+
pageState.fetchData()
|
|
259
|
+
},{
|
|
260
|
+
field: v?.columnKey,
|
|
261
|
+
value: orderEnum[v?.order]?.value,
|
|
262
|
+
isClick : !isProxy(v)
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
emit('sorted')
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
defineExpose({
|
|
271
|
+
filterHandle,
|
|
272
|
+
filterButton,
|
|
273
|
+
initColumns: init,
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
onMounted(() => {})
|
|
277
|
+
</script>
|
|
278
|
+
|
|
279
|
+
<template>
|
|
280
|
+
<n-data-table
|
|
281
|
+
:data="_data"
|
|
282
|
+
:columns="_columns"
|
|
283
|
+
:scroll-x="scrollX"
|
|
284
|
+
:single-column="props.singleColumn"
|
|
285
|
+
:summary="props.summaryColumns ? _summary : undefined"
|
|
286
|
+
summary-placement="bottom"
|
|
287
|
+
:pagination="props.pagination"
|
|
288
|
+
:row-props="() => ({ style: { height: '60px' } })"
|
|
289
|
+
flex-height
|
|
290
|
+
remote
|
|
291
|
+
:virtual-scroll="props.virtual ?? props.data.length > 1000"
|
|
292
|
+
style="flex: 1"
|
|
293
|
+
@update:sorter="onSorter"
|
|
294
|
+
>
|
|
295
|
+
<!-- props.data.length > 30 -->
|
|
296
|
+
<template #empty>
|
|
297
|
+
<slot name="empty">
|
|
298
|
+
<n-empty>{{ emptyText }}</n-empty>
|
|
299
|
+
</slot>
|
|
300
|
+
</template>
|
|
301
|
+
</n-data-table>
|
|
302
|
+
</template>
|
|
303
|
+
|
|
304
|
+
<style scoped lang="less">
|
|
305
|
+
:deep(.n-data-table-tr--summary) {
|
|
306
|
+
position: sticky;
|
|
307
|
+
bottom: 0;
|
|
308
|
+
left: 0;
|
|
309
|
+
right: 0;
|
|
310
|
+
z-index: 2;
|
|
311
|
+
.n-data-table-td--summary {
|
|
312
|
+
border-top: 1px solid var(--n-merged-border-color);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
</style>
|