@wzyjs/uis 0.3.26 → 0.3.28
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wzyjs/uis",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.28",
|
|
4
4
|
"description": "description",
|
|
5
5
|
"author": "wzy",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"prismjs": "^1.29.0",
|
|
28
28
|
"react": "^19.0.0",
|
|
29
29
|
"react-beautiful-dnd": "^13.1.1",
|
|
30
|
+
"react-grid-layout": "^1.5.1",
|
|
30
31
|
"react-json-view": "^1.21.3",
|
|
31
32
|
"react-markdown": "^10.1.0",
|
|
32
33
|
"react-syntax-highlighter": "^15.5.0",
|
|
@@ -42,7 +43,11 @@
|
|
|
42
43
|
"@wzyjs/utils": "^0.2.37",
|
|
43
44
|
"antd": "^6.0.0"
|
|
44
45
|
},
|
|
45
|
-
"
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/js-beautify": "^1.14.3",
|
|
48
|
+
"@types/react-grid-layout": "1.3.5"
|
|
49
|
+
},
|
|
50
|
+
"gitHead": "cfb708a071a9f7f0e2c819760c95427d7196623b",
|
|
46
51
|
"publishConfig": {
|
|
47
52
|
"access": "public"
|
|
48
53
|
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Tabs, type TabsProps } from 'antd'
|
|
5
|
+
|
|
6
|
+
type SyncMode = 'replace' | 'push'
|
|
7
|
+
|
|
8
|
+
export interface TabsProProps extends TabsProps {
|
|
9
|
+
syncToUrl?: boolean
|
|
10
|
+
queryKey?: string
|
|
11
|
+
historyMode?: SyncMode
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const getItemKeys = (items?: TabsProps['items']): string[] => {
|
|
15
|
+
return (items || [])
|
|
16
|
+
.map(item => item?.key)
|
|
17
|
+
.filter((key): key is string => typeof key === 'string' && !!key)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const getUrlTabKey = (queryKey: string): string | undefined => {
|
|
21
|
+
if (typeof window === 'undefined') {
|
|
22
|
+
return undefined
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const value = new URLSearchParams(window.location.search).get(queryKey)
|
|
26
|
+
return value || undefined
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const updateUrlTabKey = (queryKey: string, key: string, mode: SyncMode) => {
|
|
30
|
+
if (typeof window === 'undefined') {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const url = new URL(window.location.href)
|
|
35
|
+
url.searchParams.set(queryKey, key)
|
|
36
|
+
|
|
37
|
+
const nextUrl = `${url.pathname}${url.search}${url.hash}`
|
|
38
|
+
if (mode === 'push') {
|
|
39
|
+
window.history.pushState(window.history.state, '', nextUrl)
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
window.history.replaceState(window.history.state, '', nextUrl)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const TabsPro = (props: TabsProProps) => {
|
|
47
|
+
const {
|
|
48
|
+
syncToUrl = false,
|
|
49
|
+
queryKey = 'tab',
|
|
50
|
+
historyMode = 'replace',
|
|
51
|
+
activeKey,
|
|
52
|
+
defaultActiveKey,
|
|
53
|
+
items,
|
|
54
|
+
onChange,
|
|
55
|
+
...rest
|
|
56
|
+
} = props
|
|
57
|
+
|
|
58
|
+
const itemKeys = React.useMemo(() => getItemKeys(items), [items])
|
|
59
|
+
|
|
60
|
+
const initialKey = React.useMemo(() => {
|
|
61
|
+
const urlKey = syncToUrl ? getUrlTabKey(queryKey) : undefined
|
|
62
|
+
if (urlKey && itemKeys.includes(urlKey)) {
|
|
63
|
+
return urlKey
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (typeof defaultActiveKey === 'string' && itemKeys.includes(defaultActiveKey)) {
|
|
67
|
+
return defaultActiveKey
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return itemKeys[0]
|
|
71
|
+
}, [defaultActiveKey, itemKeys, queryKey, syncToUrl])
|
|
72
|
+
|
|
73
|
+
const [innerActiveKey, setInnerActiveKey] = React.useState<string | undefined>(initialKey)
|
|
74
|
+
|
|
75
|
+
const mergedActiveKey = typeof activeKey === 'string' ? activeKey : innerActiveKey
|
|
76
|
+
|
|
77
|
+
React.useEffect(() => {
|
|
78
|
+
if (typeof activeKey === 'string') {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
setInnerActiveKey(prev => {
|
|
83
|
+
if (prev && itemKeys.includes(prev)) {
|
|
84
|
+
return prev
|
|
85
|
+
}
|
|
86
|
+
return initialKey
|
|
87
|
+
})
|
|
88
|
+
}, [activeKey, initialKey, itemKeys])
|
|
89
|
+
|
|
90
|
+
React.useEffect(() => {
|
|
91
|
+
if (!syncToUrl || !mergedActiveKey) {
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
updateUrlTabKey(queryKey, mergedActiveKey, historyMode)
|
|
96
|
+
}, [historyMode, mergedActiveKey, queryKey, syncToUrl])
|
|
97
|
+
|
|
98
|
+
React.useEffect(() => {
|
|
99
|
+
if (!syncToUrl) {
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const onPopState = () => {
|
|
104
|
+
const urlKey = getUrlTabKey(queryKey)
|
|
105
|
+
if (!urlKey || !itemKeys.includes(urlKey)) {
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (typeof activeKey !== 'string') {
|
|
110
|
+
setInnerActiveKey(urlKey)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
onChange?.(urlKey)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
window.addEventListener('popstate', onPopState)
|
|
117
|
+
return () => {
|
|
118
|
+
window.removeEventListener('popstate', onPopState)
|
|
119
|
+
}
|
|
120
|
+
}, [activeKey, itemKeys, onChange, queryKey, syncToUrl])
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<Tabs
|
|
124
|
+
{...rest}
|
|
125
|
+
items={items}
|
|
126
|
+
activeKey={mergedActiveKey}
|
|
127
|
+
onChange={key => {
|
|
128
|
+
if (typeof activeKey !== 'string') {
|
|
129
|
+
setInnerActiveKey(key)
|
|
130
|
+
}
|
|
131
|
+
onChange?.(key)
|
|
132
|
+
}}
|
|
133
|
+
/>
|
|
134
|
+
)
|
|
135
|
+
}
|
package/src/antd/pro/index.ts
CHANGED
|
@@ -1,13 +1,50 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useMemo, useState } from 'react'
|
|
1
4
|
import { Button, type DrawerProps, type ModalProps } from 'antd'
|
|
2
5
|
import { PlusOutlined, EditOutlined } from '@ant-design/icons'
|
|
3
6
|
import { BetaSchemaForm } from '@ant-design/pro-components'
|
|
4
7
|
|
|
5
|
-
import type { CreateUpdateProps } from '../../types'
|
|
8
|
+
import type { CreateUpdateProps, ProColumnsPro } from '../../types'
|
|
9
|
+
|
|
10
|
+
const isActionColumn = (column: ProColumnsPro) => (
|
|
11
|
+
column.valueType === 'option'
|
|
12
|
+
|| column.key === 'option'
|
|
13
|
+
|| column.key === 'action'
|
|
14
|
+
|| column.title === '操作'
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
const getFormColumns = (columns: ProColumnsPro[]) => {
|
|
18
|
+
return columns
|
|
19
|
+
.filter(column => !column.hideInForm && !isActionColumn(column) && column.key !== '__drag_sort__')
|
|
20
|
+
.map((column) => {
|
|
21
|
+
const {
|
|
22
|
+
fixed,
|
|
23
|
+
sorter,
|
|
24
|
+
sortOrder,
|
|
25
|
+
defaultSortOrder,
|
|
26
|
+
filters,
|
|
27
|
+
onFilter,
|
|
28
|
+
onCell,
|
|
29
|
+
onHeaderCell,
|
|
30
|
+
ellipsis,
|
|
31
|
+
copyable,
|
|
32
|
+
render,
|
|
33
|
+
renderText,
|
|
34
|
+
width,
|
|
35
|
+
...formColumn
|
|
36
|
+
} = column as ProColumnsPro & Record<string, unknown>
|
|
37
|
+
|
|
38
|
+
return formColumn as ProColumnsPro
|
|
39
|
+
})
|
|
40
|
+
}
|
|
6
41
|
|
|
7
42
|
export const CreateUpdate = (props: CreateUpdateProps) => {
|
|
8
43
|
const { crud, columns, config, record } = props
|
|
9
44
|
|
|
10
45
|
const isEdit = !!record
|
|
46
|
+
const [open, setOpen] = useState(false)
|
|
47
|
+
const [formRendered, setFormRendered] = useState(false)
|
|
11
48
|
|
|
12
49
|
const {
|
|
13
50
|
mode = 'drawer',
|
|
@@ -19,20 +56,49 @@ export const CreateUpdate = (props: CreateUpdateProps) => {
|
|
|
19
56
|
width,
|
|
20
57
|
} = config
|
|
21
58
|
|
|
22
|
-
const {
|
|
59
|
+
const {
|
|
60
|
+
drawerProps,
|
|
61
|
+
modalProps,
|
|
62
|
+
initialValues,
|
|
63
|
+
onOpenChange,
|
|
64
|
+
onVisibleChange,
|
|
65
|
+
open: _open,
|
|
66
|
+
visible: _visible,
|
|
67
|
+
...formSafeProps
|
|
68
|
+
} = formProps as unknown as {
|
|
69
|
+
drawerProps?: DrawerProps
|
|
70
|
+
modalProps?: ModalProps
|
|
71
|
+
initialValues?: Record<string, unknown>
|
|
72
|
+
onOpenChange?: (open: boolean) => void
|
|
73
|
+
onVisibleChange?: (open: boolean) => void
|
|
74
|
+
open?: boolean
|
|
75
|
+
visible?: boolean
|
|
76
|
+
} & Record<string, unknown>
|
|
23
77
|
|
|
24
78
|
const layoutType = mode === 'modal' ? 'ModalForm' : 'DrawerForm'
|
|
25
79
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
80
|
+
const formColumns = useMemo(() => getFormColumns(columns), [columns])
|
|
81
|
+
|
|
82
|
+
const handleOpenChange = (nextOpen: boolean) => {
|
|
83
|
+
setOpen(nextOpen)
|
|
84
|
+
if (nextOpen) {
|
|
85
|
+
setFormRendered(true)
|
|
86
|
+
}
|
|
87
|
+
onOpenChange?.(nextOpen)
|
|
88
|
+
onVisibleChange?.(nextOpen)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const openForm = (event: any) => {
|
|
92
|
+
buttonProps.onClick?.(event)
|
|
93
|
+
if (event.defaultPrevented) {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
setFormRendered(true)
|
|
97
|
+
setOpen(true)
|
|
98
|
+
}
|
|
33
99
|
|
|
34
100
|
const onFinish = async (values: Record<string, unknown>) => {
|
|
35
|
-
const finalValues = transformData ? transformData(values, record) : values
|
|
101
|
+
const finalValues = transformData ? await transformData(values, record) : values
|
|
36
102
|
|
|
37
103
|
if (isEdit) {
|
|
38
104
|
await crud.updateState.mutateAsync(record.id, finalValues)
|
|
@@ -47,7 +113,6 @@ export const CreateUpdate = (props: CreateUpdateProps) => {
|
|
|
47
113
|
return record.id
|
|
48
114
|
}
|
|
49
115
|
|
|
50
|
-
const initialValues: unknown = (formSafeProps as { initialValues?: unknown }).initialValues
|
|
51
116
|
if (!initialValues) {
|
|
52
117
|
return 'create'
|
|
53
118
|
}
|
|
@@ -63,37 +128,52 @@ export const CreateUpdate = (props: CreateUpdateProps) => {
|
|
|
63
128
|
}
|
|
64
129
|
})()
|
|
65
130
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}}
|
|
80
|
-
{...(drawerProps ? { drawerProps } : {})}
|
|
81
|
-
{...(modalProps ? { modalProps } : {})}
|
|
82
|
-
trigger={
|
|
83
|
-
isEdit ? (
|
|
84
|
-
<Button
|
|
85
|
-
type='link'
|
|
86
|
-
size='small'
|
|
87
|
-
icon={<EditOutlined />}
|
|
88
|
-
{...buttonProps}
|
|
89
|
-
/>
|
|
90
|
-
) : (
|
|
91
|
-
<Button type='primary' icon={<PlusOutlined />} {...buttonProps}>
|
|
92
|
-
新建
|
|
93
|
-
</Button>
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
{...formSafeProps}
|
|
131
|
+
const finalInitialValues = {
|
|
132
|
+
...(record ?? {}),
|
|
133
|
+
...(initialValues ?? {}),
|
|
134
|
+
...(coverData ? coverData(record) : {}),
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const trigger = isEdit ? (
|
|
138
|
+
<Button
|
|
139
|
+
type='link'
|
|
140
|
+
size='small'
|
|
141
|
+
icon={<EditOutlined />}
|
|
142
|
+
{...buttonProps}
|
|
143
|
+
onClick={openForm}
|
|
97
144
|
/>
|
|
145
|
+
) : (
|
|
146
|
+
<Button
|
|
147
|
+
type='primary'
|
|
148
|
+
icon={<PlusOutlined />}
|
|
149
|
+
{...buttonProps}
|
|
150
|
+
onClick={openForm}
|
|
151
|
+
>
|
|
152
|
+
新建
|
|
153
|
+
</Button>
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<>
|
|
158
|
+
{trigger}
|
|
159
|
+
{formRendered ? (
|
|
160
|
+
<BetaSchemaForm
|
|
161
|
+
key={formKey}
|
|
162
|
+
layoutType={layoutType as any}
|
|
163
|
+
title={title}
|
|
164
|
+
width={width}
|
|
165
|
+
columns={formColumns as any}
|
|
166
|
+
onFinish={onFinish}
|
|
167
|
+
layout='horizontal'
|
|
168
|
+
labelCol={{ span: 4 }}
|
|
169
|
+
initialValues={finalInitialValues}
|
|
170
|
+
open={open}
|
|
171
|
+
onOpenChange={handleOpenChange}
|
|
172
|
+
{...(drawerProps ? { drawerProps } : {})}
|
|
173
|
+
{...(modalProps ? { modalProps } : {})}
|
|
174
|
+
{...formSafeProps}
|
|
175
|
+
/>
|
|
176
|
+
) : null}
|
|
177
|
+
</>
|
|
98
178
|
)
|
|
99
179
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { type PropsWithChildren, useContext, useMemo } from 'react'
|
|
2
4
|
import { Tag, Switch } from 'antd'
|
|
3
5
|
import { ProProvider, ProFormSelect } from '@ant-design/pro-components'
|
|
6
|
+
import type { ProRenderFieldPropsType } from '@ant-design/pro-provider'
|
|
4
7
|
|
|
5
8
|
import type { Crud } from '../../types'
|
|
6
9
|
|
|
@@ -19,52 +22,59 @@ export const Provider = (props: ProviderProps) => {
|
|
|
19
22
|
}
|
|
20
23
|
}
|
|
21
24
|
|
|
25
|
+
const valueTypeMap = useMemo<Record<string, ProRenderFieldPropsType>>(() => ({
|
|
26
|
+
...defaultContext.valueTypeMap,
|
|
27
|
+
tags: {
|
|
28
|
+
renderFormItem: (_: unknown, props: any) => {
|
|
29
|
+
const { options, ...restFieldProps } = props.fieldProps || {}
|
|
30
|
+
|
|
31
|
+
let processedOptions = options
|
|
32
|
+
|
|
33
|
+
if (Array.isArray(options) && options.length > 0 && typeof options[0] === 'string') {
|
|
34
|
+
processedOptions = options.map((item: string) => ({
|
|
35
|
+
label: item,
|
|
36
|
+
value: item,
|
|
37
|
+
}))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<ProFormSelect
|
|
42
|
+
placeholder='请输入标签'
|
|
43
|
+
mode='tags'
|
|
44
|
+
options={processedOptions}
|
|
45
|
+
{...restFieldProps}
|
|
46
|
+
/>
|
|
47
|
+
)
|
|
48
|
+
},
|
|
49
|
+
render: (tags: string[]) => {
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
{tags?.map((tag: string) => (
|
|
53
|
+
<Tag key={tag}>{tag}</Tag>
|
|
54
|
+
))}
|
|
55
|
+
</>
|
|
56
|
+
)
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
enabled: {
|
|
60
|
+
render: (enabled: boolean, props: any) => {
|
|
61
|
+
return (
|
|
62
|
+
<Switch
|
|
63
|
+
loading={crud?.updateState.isLoading}
|
|
64
|
+
checked={enabled}
|
|
65
|
+
onChange={enabled => onSwitchChange(props.record?.id, enabled)}
|
|
66
|
+
disabled={!crud?.updateState}
|
|
67
|
+
/>
|
|
68
|
+
)
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
}), [crud?.updateState, defaultContext.valueTypeMap])
|
|
72
|
+
|
|
22
73
|
return (
|
|
23
74
|
<ProProvider.Provider
|
|
24
75
|
value={{
|
|
25
76
|
...defaultContext,
|
|
26
|
-
valueTypeMap
|
|
27
|
-
tags: {
|
|
28
|
-
renderFormItem: (_: unknown, props) => {
|
|
29
|
-
const { options, ...restFieldProps } = props.fieldProps || {}
|
|
30
|
-
|
|
31
|
-
let processedOptions = options
|
|
32
|
-
|
|
33
|
-
if (Array.isArray(options) && options.length > 0 && typeof options[0] === 'string') {
|
|
34
|
-
processedOptions = options.map((item: string) => ({
|
|
35
|
-
label: item,
|
|
36
|
-
value: item,
|
|
37
|
-
}))
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<ProFormSelect
|
|
42
|
-
placeholder='请输入标签'
|
|
43
|
-
mode='tags'
|
|
44
|
-
options={processedOptions}
|
|
45
|
-
{...restFieldProps}
|
|
46
|
-
/>
|
|
47
|
-
)
|
|
48
|
-
},
|
|
49
|
-
render: (tags: string[]) => {
|
|
50
|
-
return tags?.map((tag: string) => (
|
|
51
|
-
<Tag key={tag}>{tag}</Tag>
|
|
52
|
-
))
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
enabled: {
|
|
56
|
-
render: (enabled: boolean, props: any) => {
|
|
57
|
-
return (
|
|
58
|
-
<Switch
|
|
59
|
-
loading={crud?.updateState.isLoading}
|
|
60
|
-
checked={enabled}
|
|
61
|
-
onChange={enabled => onSwitchChange(props.record?.id, enabled)}
|
|
62
|
-
disabled={!crud?.updateState}
|
|
63
|
-
/>
|
|
64
|
-
)
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
},
|
|
77
|
+
valueTypeMap,
|
|
68
78
|
}}
|
|
69
79
|
>
|
|
70
80
|
{children}
|