@ethan1979/jf-lib 0.0.32
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/.vscode/extensions.json +3 -0
- package/README.md +3 -0
- package/babel.config.js +3 -0
- package/dist/App.vue.d.ts +2 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/v-table/components/content/components/operations.vue.d.ts +47 -0
- package/dist/components/v-table/components/content/index.vue.d.ts +13 -0
- package/dist/components/v-table/components/modal-form.vue.d.ts +30 -0
- package/dist/components/v-table/components/search.vue.d.ts +12 -0
- package/dist/components/v-table/components/toolbar.vue.d.ts +11 -0
- package/dist/components/v-table/get-render-function.d.ts +6 -0
- package/dist/components/v-table/hooks.d.ts +80 -0
- package/dist/components/v-table/index.vue.d.ts +17 -0
- package/dist/components/v-table/util.d.ts +2 -0
- package/dist/favicon.ico +0 -0
- package/dist/jf-lib.es.js +6553 -0
- package/dist/jf-lib.umd.js +27 -0
- package/dist/main.d.ts +1 -0
- package/dist/style.css +1 -0
- package/dist/types/global.d.ts +43 -0
- package/dist/utils/utils.d.ts +11 -0
- package/docs/superpowers/plans/2026-09-19-collapsible-table-search.md +194 -0
- package/docs/superpowers/specs/2026-09-19-collapsible-table-search-design.md +80 -0
- package/index.html +13 -0
- package/package.json +31 -0
- package/public/favicon.ico +0 -0
- package/scripts/check-collapsible-search.mjs +67 -0
- package/src/App.vue +98 -0
- package/src/assets/logo.png +0 -0
- package/src/components/index.ts +18 -0
- package/src/components/v-table/components/content/components/operations.vue +119 -0
- package/src/components/v-table/components/content/index.vue +295 -0
- package/src/components/v-table/components/modal-form.vue +111 -0
- package/src/components/v-table/components/search.vue +181 -0
- package/src/components/v-table/components/toolbar.vue +121 -0
- package/src/components/v-table/get-render-function.ts +15 -0
- package/src/components/v-table/hooks.ts +128 -0
- package/src/components/v-table/index.vue +338 -0
- package/src/components/v-table/typings.d.ts +164 -0
- package/src/components/v-table/util.ts +14 -0
- package/src/env.d.ts +12 -0
- package/src/main.ts +13 -0
- package/src/types/global.ts +48 -0
- package/src/utils/utils.ts +77 -0
- package/tsconfig.json +38 -0
- package/tsconfig.node.json +8 -0
- package/vite.config.ts +47 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<a-card
|
|
3
|
+
:id="tableId"
|
|
4
|
+
:style="{ width: '100%', ...(config?.style || {}) }"
|
|
5
|
+
:title="config?.title"
|
|
6
|
+
:bordered="Boolean(config?.card)"
|
|
7
|
+
class="v-table"
|
|
8
|
+
:class="[!config?.card && 'general-card']"
|
|
9
|
+
>
|
|
10
|
+
<template #title v-if="config?.cardSlots?.title">
|
|
11
|
+
<component :is="config?.cardSlots?.title" />
|
|
12
|
+
</template>
|
|
13
|
+
<template #extra v-if="config?.cardSlots?.extra">
|
|
14
|
+
<component :is="config?.cardSlots?.extra" />
|
|
15
|
+
</template>
|
|
16
|
+
<!-- 777 -->
|
|
17
|
+
<v-search
|
|
18
|
+
v-if="!config?.hiddenSearch"
|
|
19
|
+
ref="searchRef"
|
|
20
|
+
:config="config"
|
|
21
|
+
@search="search"
|
|
22
|
+
/>
|
|
23
|
+
<v-toolbar
|
|
24
|
+
v-if="!config?.hiddenToolbar"
|
|
25
|
+
:config="config"
|
|
26
|
+
@add="add"
|
|
27
|
+
@batch-delete="batchDelete"
|
|
28
|
+
>
|
|
29
|
+
<template #toolbar-left>
|
|
30
|
+
<slot name="toolbar-left"></slot>
|
|
31
|
+
</template>
|
|
32
|
+
<template #toolbar-left-extend>
|
|
33
|
+
<slot name="toolbar-left-extend"></slot>
|
|
34
|
+
</template>
|
|
35
|
+
<template #toolbar-right>
|
|
36
|
+
<slot name="toolbar-right"></slot>
|
|
37
|
+
</template>
|
|
38
|
+
</v-toolbar>
|
|
39
|
+
<v-content
|
|
40
|
+
ref="contentRef"
|
|
41
|
+
:config="config"
|
|
42
|
+
@update="update"
|
|
43
|
+
@delete-data="deleteData"
|
|
44
|
+
@get="get"
|
|
45
|
+
/>
|
|
46
|
+
</a-card>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<script lang="ts">
|
|
50
|
+
import { defineComponent, watch } from 'vue'
|
|
51
|
+
|
|
52
|
+
export default defineComponent({
|
|
53
|
+
name: 'VTable',
|
|
54
|
+
})
|
|
55
|
+
</script>
|
|
56
|
+
<script setup lang="ts">
|
|
57
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
58
|
+
import { computed, provide, Ref, ref, toRefs, PropType } from 'vue'
|
|
59
|
+
// import { number } from 'echarts/core'
|
|
60
|
+
import { uniqueId } from 'lodash'
|
|
61
|
+
import { Message } from '@arco-design/web-vue'
|
|
62
|
+
import { TableConfig } from './typings'
|
|
63
|
+
import VSearch from './components/search.vue'
|
|
64
|
+
import VToolbar from './components/toolbar.vue'
|
|
65
|
+
import VContent from './components/content/index.vue'
|
|
66
|
+
import { BaseGetData, BaseObj } from '../../types/global'
|
|
67
|
+
import { setSelectedRowKeys } from './util'
|
|
68
|
+
|
|
69
|
+
const tableId = uniqueId('v-table-')
|
|
70
|
+
provide('tableId', tableId)
|
|
71
|
+
|
|
72
|
+
const props = defineProps({
|
|
73
|
+
config: Object as PropType<TableConfig>,
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
const { config } = toRefs(props)
|
|
77
|
+
|
|
78
|
+
// watch(()=>config,(newVal)=>{
|
|
79
|
+
// console.log('change',newVal);
|
|
80
|
+
// },{
|
|
81
|
+
// deep:true
|
|
82
|
+
// })
|
|
83
|
+
|
|
84
|
+
provide('config', config && config.value)
|
|
85
|
+
|
|
86
|
+
const pagination = computed(() => {
|
|
87
|
+
return config?.value?.table?.pagination as {
|
|
88
|
+
size: 'mini' | 'small' | 'medium' | 'large'
|
|
89
|
+
disabled: boolean
|
|
90
|
+
defaultCurrent: number
|
|
91
|
+
total: number
|
|
92
|
+
defaultPageSize: number
|
|
93
|
+
hideOnSinglePage: boolean
|
|
94
|
+
simple: boolean
|
|
95
|
+
showTotal: boolean
|
|
96
|
+
showMore: boolean
|
|
97
|
+
showJumper: boolean
|
|
98
|
+
showPageSize: boolean
|
|
99
|
+
pageSizeOptions: number[]
|
|
100
|
+
baseSize: number
|
|
101
|
+
bufferSize: number
|
|
102
|
+
current: number
|
|
103
|
+
pageSize: number
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
const setLoading = (bool: boolean) => {
|
|
108
|
+
if (config?.value?.table) config.value.table.loading = bool
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const selectedRowKeys = computed({
|
|
112
|
+
get: () => props.config?.table.rowSelection?.selectedRowKeys || [],
|
|
113
|
+
set: (val) => {
|
|
114
|
+
if (props.config?.table.rowSelection?.selectedRowKeys) {
|
|
115
|
+
// eslint-disable-next-line vue/no-mutating-props
|
|
116
|
+
props.config.table.rowSelection.selectedRowKeys = val
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
provide('selectedRowKeys', selectedRowKeys)
|
|
121
|
+
|
|
122
|
+
const searchParams = ref<BaseObj>({})
|
|
123
|
+
const apis = ref(config?.value?.apis)
|
|
124
|
+
const get = async () => {
|
|
125
|
+
if (!config?.value) return
|
|
126
|
+
if (config.value?.loadingOnGet !== false) setLoading(true)
|
|
127
|
+
try {
|
|
128
|
+
if (apis.value?.get) {
|
|
129
|
+
// const pagination = config.value?.table.pagination as PaginationProps
|
|
130
|
+
let params = {
|
|
131
|
+
...searchParams.value,
|
|
132
|
+
}
|
|
133
|
+
if (pagination.value) {
|
|
134
|
+
const { current, pageSize } = pagination.value
|
|
135
|
+
params = {
|
|
136
|
+
current,
|
|
137
|
+
pageSize,
|
|
138
|
+
...params,
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const result = (await apis.value?.get(params as any)) as any
|
|
142
|
+
const isBaseGetData = !((result?.total ?? true) === true)
|
|
143
|
+
if (isBaseGetData && pagination.value) {
|
|
144
|
+
const { data, total } = result as BaseGetData<BaseObj>
|
|
145
|
+
pagination.value.total = total ?? data.length
|
|
146
|
+
config.value.table.data = data
|
|
147
|
+
} else {
|
|
148
|
+
const data = result as BaseObj[]
|
|
149
|
+
config.value.table.data = data
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
} catch (error) {
|
|
153
|
+
// console.log('error', error)
|
|
154
|
+
} finally {
|
|
155
|
+
setLoading(false)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const crud = async (
|
|
160
|
+
apiName: 'update' | 'delete' | 'add',
|
|
161
|
+
params: BaseObj | any[]
|
|
162
|
+
) => {
|
|
163
|
+
const map = {
|
|
164
|
+
update: '编辑',
|
|
165
|
+
add: '新增',
|
|
166
|
+
delete: '删除',
|
|
167
|
+
}
|
|
168
|
+
const paramsIsArray = params instanceof Array
|
|
169
|
+
const filterParams: BaseObj = {}
|
|
170
|
+
if (!paramsIsArray) {
|
|
171
|
+
const filterThisValue = ['filter this value']
|
|
172
|
+
Object.keys(params).forEach((key) => {
|
|
173
|
+
// ''??true ->'' false??true -> false
|
|
174
|
+
if (
|
|
175
|
+
(params[key] ?? filterThisValue) !== filterThisValue &&
|
|
176
|
+
params[key] !== ''
|
|
177
|
+
)
|
|
178
|
+
filterParams[key] = params[key]
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
if (apis.value && apis.value[apiName]) {
|
|
182
|
+
// eslint-disable-next-line no-useless-catch
|
|
183
|
+
try {
|
|
184
|
+
const requestFunction = apis.value[apiName] as any
|
|
185
|
+
// await ()(filterParams)
|
|
186
|
+
if (paramsIsArray) {
|
|
187
|
+
// console.log('params', params)
|
|
188
|
+
await requestFunction.call(null, ...params)
|
|
189
|
+
} else {
|
|
190
|
+
await requestFunction(filterParams)
|
|
191
|
+
}
|
|
192
|
+
Message.success(`${map[apiName]}成功`)
|
|
193
|
+
get()
|
|
194
|
+
} catch (error) {
|
|
195
|
+
// console.trace(`${map[apiName]}失败`)
|
|
196
|
+
throw error
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const add = async (params: BaseObj) => {
|
|
202
|
+
// if (apis.value?.add) {
|
|
203
|
+
// await apis.value?.add(params)
|
|
204
|
+
// get()
|
|
205
|
+
// }
|
|
206
|
+
crud('add', params)
|
|
207
|
+
}
|
|
208
|
+
const update = async (params: BaseObj) => {
|
|
209
|
+
// if (apis.value?.update) {
|
|
210
|
+
// await apis.value?.update(params)
|
|
211
|
+
// get()
|
|
212
|
+
// }
|
|
213
|
+
crud('update', params)
|
|
214
|
+
}
|
|
215
|
+
const deleteData = async (params: BaseObj) => {
|
|
216
|
+
// if (apis.value?.delete) {
|
|
217
|
+
// await apis.value?.delete(params)
|
|
218
|
+
// get()
|
|
219
|
+
// }
|
|
220
|
+
// console.log(
|
|
221
|
+
// 'config?.value?.table?.rowKey',
|
|
222
|
+
// config?.value?.table?.rowKey,
|
|
223
|
+
// params
|
|
224
|
+
// )
|
|
225
|
+
const rowKey =
|
|
226
|
+
(params[config?.value?.table?.rowKey as string] as number) || null
|
|
227
|
+
// const rowKey = 12333
|
|
228
|
+
crud('delete', [rowKey, params]).then(() => {
|
|
229
|
+
const index = selectedRowKeys.value.indexOf(rowKey as never)
|
|
230
|
+
if (index !== -1) {
|
|
231
|
+
selectedRowKeys.value.splice(index, 1)
|
|
232
|
+
// setSelectedRowKeys((config as Ref<TableConfig>).value, [
|
|
233
|
+
// ...(selectedRowKeys.value as string[]),
|
|
234
|
+
// ])
|
|
235
|
+
}
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const batchDelete = async () => {
|
|
240
|
+
const keys = selectedRowKeys.value
|
|
241
|
+
crud('delete', [keys]).then(() => {
|
|
242
|
+
selectedRowKeys.value = []
|
|
243
|
+
// setSelectedRowKeys((config as Ref<TableConfig>).value, [])
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const search = (params: BaseObj) => {
|
|
248
|
+
searchParams.value = {}
|
|
249
|
+
Object.keys(params).forEach((key) => {
|
|
250
|
+
if ((params[key] ?? '') !== '') {
|
|
251
|
+
searchParams.value[key] = params[key]
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
|
+
// searchParams.value = params
|
|
255
|
+
if (pagination.value) pagination.value.current = 1
|
|
256
|
+
get()
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const contentRef = ref<{
|
|
260
|
+
getTableHeight: () => number
|
|
261
|
+
}>()
|
|
262
|
+
const searchRef = ref<{
|
|
263
|
+
reset: () => void
|
|
264
|
+
search: () => void
|
|
265
|
+
}>()
|
|
266
|
+
|
|
267
|
+
// setTimeout(()=>{
|
|
268
|
+
// console.log('contentRef',contentRef);
|
|
269
|
+
|
|
270
|
+
// },1000)
|
|
271
|
+
// provide('setGetTableHeight', (fn: () => number) => {
|
|
272
|
+
// getTableHeight.value = fn
|
|
273
|
+
// console.log('getTableHeight', getTableHeight.value)
|
|
274
|
+
// })
|
|
275
|
+
const _setSelectedRowKeys = (keys: string[]) =>
|
|
276
|
+
setSelectedRowKeys((config as Ref<TableConfig>).value, keys)
|
|
277
|
+
defineExpose({
|
|
278
|
+
contentRef,
|
|
279
|
+
searchRef,
|
|
280
|
+
get,
|
|
281
|
+
resetSearchParams: searchRef.value?.reset,
|
|
282
|
+
setSelectedRowKeys: _setSelectedRowKeys,
|
|
283
|
+
getSelectedRowKeys: () => selectedRowKeys.value,
|
|
284
|
+
})
|
|
285
|
+
</script>
|
|
286
|
+
|
|
287
|
+
<style lang="less">
|
|
288
|
+
.v-table {
|
|
289
|
+
height: 100%;
|
|
290
|
+
// height: var(--container-height);
|
|
291
|
+
overflow-y: hidden;
|
|
292
|
+
display: flex;
|
|
293
|
+
flex-direction: column;
|
|
294
|
+
overflow: hidden;
|
|
295
|
+
|
|
296
|
+
.arco-card-body {
|
|
297
|
+
flex: 1;
|
|
298
|
+
display: flex;
|
|
299
|
+
flex-direction: column;
|
|
300
|
+
overflow: hidden;
|
|
301
|
+
padding-top: 0 !important;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.arco-table-border {
|
|
305
|
+
.arco-table-container {
|
|
306
|
+
border-right: 1px solid var(--color-neutral-3);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.arco-table-scroll-y
|
|
310
|
+
.arco-table-body
|
|
311
|
+
.arco-table-tr:not(.arco-table-tr-empty):last-of-type
|
|
312
|
+
.arco-table-td,
|
|
313
|
+
.arco-table-border
|
|
314
|
+
.arco-table-scroll-y
|
|
315
|
+
tfoot
|
|
316
|
+
.arco-table-tr:last-of-type
|
|
317
|
+
.arco-table-td {
|
|
318
|
+
border-bottom: 1px solid var(--color-border-2);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.arco-table-border-cell
|
|
323
|
+
.arco-table-tr
|
|
324
|
+
.arco-table-td:last-child:not(.arco-table-tr-expand) {
|
|
325
|
+
border-right: none;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// .arco-card-body {
|
|
329
|
+
// padding-bottom: 0 !important;
|
|
330
|
+
// }
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.table-modal {
|
|
334
|
+
.arco-modal-title {
|
|
335
|
+
display: block;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
</style>
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { CSSProperties, VNode } from 'vue'
|
|
3
|
+
import type _Table from '@arco-design/web-vue/es/table'
|
|
4
|
+
import type _TableColumn from '@arco-design/web-vue/es/table/table-column'
|
|
5
|
+
import { FieldRule } from '@arco-design/web-vue/es/form/interface'
|
|
6
|
+
import { BaseGetData, BaseObj } from '../../types/global'
|
|
7
|
+
import { TableColumnData } from '@arco-design/web-vue/es/table'
|
|
8
|
+
|
|
9
|
+
// export type TableColumn = InstanceType<typeof _TableColumn>
|
|
10
|
+
|
|
11
|
+
// export type TableColumnProps = TableColumn['$props']
|
|
12
|
+
type Table = InstanceType<typeof _Table>['$props']
|
|
13
|
+
|
|
14
|
+
type FormRenderType =
|
|
15
|
+
| 'a-input'
|
|
16
|
+
| 'a-input-number'
|
|
17
|
+
| 'a-time-picker'
|
|
18
|
+
| 'a-select'
|
|
19
|
+
| 'v-select'
|
|
20
|
+
|
|
21
|
+
export type FormRender<T = BaseObj> =
|
|
22
|
+
| {
|
|
23
|
+
type: FormRenderType
|
|
24
|
+
props: {
|
|
25
|
+
[key: string]: unknown
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
| ((params: T | undefined) => VNode)
|
|
29
|
+
|
|
30
|
+
// export type BaseObj = { [key: string]: unknown }
|
|
31
|
+
|
|
32
|
+
export type CellRenderFN<T = BaseObj> = (
|
|
33
|
+
record: T,
|
|
34
|
+
column: TableColumnData,
|
|
35
|
+
rowIndex: number
|
|
36
|
+
) => VNode
|
|
37
|
+
|
|
38
|
+
export type OperationsButtonConfig = {
|
|
39
|
+
hidden?: boolean
|
|
40
|
+
disabled?: boolean
|
|
41
|
+
onClick?: (params?: BaseObj) => void | boolean
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type OperationsProps<T = BaseObj> = {
|
|
45
|
+
extend?: CellRenderFN<T>
|
|
46
|
+
extendPostion?: 'center' | 'left' | 'right'
|
|
47
|
+
updateButton?: OperationsButtonConfig
|
|
48
|
+
deleteButton?: OperationsButtonConfig
|
|
49
|
+
}
|
|
50
|
+
type CellComponentOperate<T = BaseObj> = {
|
|
51
|
+
type: 'operations'
|
|
52
|
+
props?: OperationsProps<T> | ((params: T) => OperationsProps<T>)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type CellComponents<T> = CellComponentOperate<T>
|
|
56
|
+
|
|
57
|
+
type TableFormItemConfig<T> = {
|
|
58
|
+
render?: FormRender<T>
|
|
59
|
+
yIndex?: number
|
|
60
|
+
rule?: FieldRule | FieldRule[]
|
|
61
|
+
required?: boolean
|
|
62
|
+
defaultValue?: unknown
|
|
63
|
+
tooltip?: string
|
|
64
|
+
title?: string
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type SearchColSpan =
|
|
68
|
+
| number
|
|
69
|
+
| {
|
|
70
|
+
span: number
|
|
71
|
+
formItem?: {
|
|
72
|
+
labelColSpan?: number
|
|
73
|
+
wrapperColSpan?: number
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type Columns<T = BaseObj> = TableColumnData & {
|
|
78
|
+
dataIndex: string | keyof T
|
|
79
|
+
hidden?: boolean
|
|
80
|
+
titleRender?: () => VNode
|
|
81
|
+
cellRender?: CellRenderFN<T> | CellComponents<T>
|
|
82
|
+
children?:Columns<T>[]
|
|
83
|
+
form?:
|
|
84
|
+
| ({
|
|
85
|
+
hiddenSearch?: boolean
|
|
86
|
+
hiddenAdd?: boolean
|
|
87
|
+
hiddenUpdate?: boolean
|
|
88
|
+
searchColSpan?: SearchColSpan
|
|
89
|
+
// [
|
|
90
|
+
// key: 'addConfig' | 'updateConfig' | 'searchConfig'
|
|
91
|
+
// ]: TableFormItemConfig
|
|
92
|
+
addConfig?: TableFormItemConfig<T>
|
|
93
|
+
updateConfig?: TableFormItemConfig<T>
|
|
94
|
+
searchConfig?: TableFormItemConfig<T>
|
|
95
|
+
} & TableFormItemConfig<T>)
|
|
96
|
+
| boolean
|
|
97
|
+
| (() => VNode)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// type BaseGetData = {
|
|
101
|
+
// data: Array<BaseObj>
|
|
102
|
+
// total: number
|
|
103
|
+
// page: number
|
|
104
|
+
// pageSize: number
|
|
105
|
+
// }
|
|
106
|
+
|
|
107
|
+
export interface TableConfig<T = BaseObj> {
|
|
108
|
+
title?: string
|
|
109
|
+
card?: boolean
|
|
110
|
+
batchDelete?: boolean
|
|
111
|
+
hiddenSearch?: boolean
|
|
112
|
+
hiddenToolbar?: boolean
|
|
113
|
+
style?: CSSProperties
|
|
114
|
+
loadingOnGet?:boolean
|
|
115
|
+
|
|
116
|
+
cardSlots?:{
|
|
117
|
+
[key in 'title'|'extra']?:()=>VNode
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
toolbar?: {
|
|
121
|
+
onBeforeAddModalOpen?: () => void | boolean
|
|
122
|
+
}
|
|
123
|
+
search?: {
|
|
124
|
+
hiddenReset?: boolean
|
|
125
|
+
searchOnchange?:boolean
|
|
126
|
+
collapsible?: boolean
|
|
127
|
+
defaultVisibleFields?: string[]
|
|
128
|
+
}
|
|
129
|
+
table: Omit<Table, 'columns'> & {
|
|
130
|
+
data: Array<BaseObj>
|
|
131
|
+
'v-slots'?:{
|
|
132
|
+
[key:string]:()=>VNode
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
columns: Array<Columns<T>>
|
|
136
|
+
apis?: {
|
|
137
|
+
get?: (params: {
|
|
138
|
+
current: number
|
|
139
|
+
pageSize: number
|
|
140
|
+
[key: string]: unknown
|
|
141
|
+
}) =>
|
|
142
|
+
| BaseGetData<T>
|
|
143
|
+
| Promise<T[]>
|
|
144
|
+
| Promise<BaseGetData<T>>
|
|
145
|
+
| Promise<BaseGetData<BaseObj>>
|
|
146
|
+
update?: (formData: T) => void | Promise<unknown>
|
|
147
|
+
add?: (formData: T) => void | Promise<unknown>
|
|
148
|
+
delete?: (
|
|
149
|
+
id: number | number[],
|
|
150
|
+
formData?: T | T[]
|
|
151
|
+
) => void | Promise<unknown>
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface FormGenerate {
|
|
156
|
+
form: Array<{
|
|
157
|
+
formItem: {
|
|
158
|
+
title: string
|
|
159
|
+
dataIndex: string
|
|
160
|
+
}
|
|
161
|
+
render: FormRender
|
|
162
|
+
}>
|
|
163
|
+
formData: BaseObj
|
|
164
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { TableConfig } from './typings'
|
|
2
|
+
|
|
3
|
+
export const setSelectedRowKeys = (
|
|
4
|
+
config: TableConfig,
|
|
5
|
+
value: string[] | undefined
|
|
6
|
+
) => {
|
|
7
|
+
if (config?.table.rowSelection) {
|
|
8
|
+
const rowSelection = config?.table.rowSelection
|
|
9
|
+
// console.log('rowSelection', rowSelection)
|
|
10
|
+
if (rowSelection) {
|
|
11
|
+
rowSelection.selectedRowKeys = value
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
package/src/env.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
|
|
3
|
+
declare module '*.vue' {
|
|
4
|
+
import type { DefineComponent } from 'vue'
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
|
6
|
+
const component: DefineComponent<{}, {}, any>
|
|
7
|
+
export default component
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface Window {
|
|
11
|
+
containerHeight?: number
|
|
12
|
+
}
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createApp } from 'vue'
|
|
2
|
+
import App from './App.vue'
|
|
3
|
+
|
|
4
|
+
import ArcoVue from '@arco-design/web-vue'
|
|
5
|
+
import ArcoVueIcon from '@arco-design/web-vue/es/icon'
|
|
6
|
+
import '@arco-design/web-vue/dist/arco.css'
|
|
7
|
+
|
|
8
|
+
const app=createApp(App)
|
|
9
|
+
|
|
10
|
+
app.use(ArcoVue, {})
|
|
11
|
+
app.use(ArcoVueIcon)
|
|
12
|
+
|
|
13
|
+
app.mount('#app')
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface AnyObject {
|
|
2
|
+
[key: string]: unknown
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export interface Options {
|
|
6
|
+
value: unknown
|
|
7
|
+
label: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface NodeOptions extends Options {
|
|
11
|
+
children?: NodeOptions[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface GetParams {
|
|
15
|
+
body: null
|
|
16
|
+
type: string
|
|
17
|
+
url: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PostData {
|
|
21
|
+
body: string
|
|
22
|
+
type: string
|
|
23
|
+
url: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface Pagination {
|
|
27
|
+
current: number
|
|
28
|
+
pageSize: number
|
|
29
|
+
total?: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type TimeRanger = [string, string]
|
|
33
|
+
|
|
34
|
+
export interface GeneralChart {
|
|
35
|
+
xAxis: string[]
|
|
36
|
+
data: Array<{ name: string; value: number[] }>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
40
|
+
export type BaseObj = { [key: string]: any }
|
|
41
|
+
|
|
42
|
+
export type BaseGetData<T = BaseObj> = {
|
|
43
|
+
data: Array<T>
|
|
44
|
+
total: number
|
|
45
|
+
page?: number
|
|
46
|
+
pageSize?: number
|
|
47
|
+
idList?: number[]
|
|
48
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { FormRender } from '../components/v-table/typings'
|
|
3
|
+
|
|
4
|
+
const clearAndUpper = (text: string) => text.replace(/-/, '').toUpperCase()
|
|
5
|
+
|
|
6
|
+
export const toPascalCase = (text: string) =>
|
|
7
|
+
text.replace(/(^\w|-\w)/g, clearAndUpper)
|
|
8
|
+
|
|
9
|
+
export const filterTree = (
|
|
10
|
+
_tree: any[],
|
|
11
|
+
filterValue: string | boolean | number,
|
|
12
|
+
fields: {
|
|
13
|
+
filterField: string
|
|
14
|
+
children: string
|
|
15
|
+
key?: string
|
|
16
|
+
}
|
|
17
|
+
) => {
|
|
18
|
+
const getTreeKey = (data: any) => {
|
|
19
|
+
const key = fields.key as string
|
|
20
|
+
const keys: any[] = []
|
|
21
|
+
keys.push(data[key])
|
|
22
|
+
if (data[fields.children]?.length > 0) {
|
|
23
|
+
data[fields.children].forEach((item: any) => {
|
|
24
|
+
keys.push(...getTreeKey(item))
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
return keys
|
|
28
|
+
}
|
|
29
|
+
const isMatch = (value: any) => {
|
|
30
|
+
if (typeof filterValue === 'string') return value.includes(filterValue)
|
|
31
|
+
return value === filterValue
|
|
32
|
+
}
|
|
33
|
+
const tree: any[] = []
|
|
34
|
+
const keys: any[] = []
|
|
35
|
+
_tree.forEach((item) => {
|
|
36
|
+
if (isMatch(item[fields.filterField])) {
|
|
37
|
+
tree.push(item)
|
|
38
|
+
if (fields.key) {
|
|
39
|
+
keys.push(...getTreeKey(item))
|
|
40
|
+
}
|
|
41
|
+
} else if (item[fields.children]?.length > 0) {
|
|
42
|
+
const { tree: fTree, keys: fKeys } = filterTree(
|
|
43
|
+
item[fields.children],
|
|
44
|
+
filterValue,
|
|
45
|
+
fields
|
|
46
|
+
)
|
|
47
|
+
if (fTree.length > 0) {
|
|
48
|
+
tree.push(...fTree)
|
|
49
|
+
keys.push(...fKeys)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
tree,
|
|
56
|
+
keys,
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const getFormInput = (props: string | any): FormRender => {
|
|
61
|
+
let baseProps: any = {
|
|
62
|
+
allowClear: true,
|
|
63
|
+
maxLength: 100,
|
|
64
|
+
}
|
|
65
|
+
if (typeof props === 'string') {
|
|
66
|
+
baseProps.placeholder = props
|
|
67
|
+
} else {
|
|
68
|
+
baseProps = {
|
|
69
|
+
...baseProps,
|
|
70
|
+
...props,
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
type: 'a-input',
|
|
75
|
+
props: baseProps,
|
|
76
|
+
}
|
|
77
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "esnext",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"module": "esnext",
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"jsx": "preserve",
|
|
9
|
+
"sourceMap": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"lib": [
|
|
14
|
+
"esnext",
|
|
15
|
+
"dom"
|
|
16
|
+
],
|
|
17
|
+
"skipLibCheck": true,
|
|
18
|
+
"allowJs": true,
|
|
19
|
+
"outDir": "dist",
|
|
20
|
+
"declaration": true,
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": [
|
|
23
|
+
"./src/*"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
"include": [
|
|
28
|
+
"src/**/*.ts",
|
|
29
|
+
"src/**/*.d.ts",
|
|
30
|
+
"src/**/*.tsx",
|
|
31
|
+
"src/**/*.vue"
|
|
32
|
+
],
|
|
33
|
+
"references": [
|
|
34
|
+
{
|
|
35
|
+
"path": "./tsconfig.node.json"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|