@yorha2b-lab/autodev 7.7.8 → 7.8.0
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/bin/bunker.js +2 -0
- package/config.js +2 -0
- package/package.json +1 -1
- package/src/constitution/inspector.js +20 -0
- package/src/constitution/system.js +2 -8
- package/src/dialogues/EN-US.js +8 -0
- package/src/dialogues/FR-FR.js +8 -0
- package/src/dialogues/JA-JP.js +8 -0
- package/src/dialogues/RU-RU.js +8 -0
- package/src/dialogues/ZH-CN.js +8 -0
- package/src/gateway/client.js +1 -1
- package/src/gateway/index.js +17 -7
- package/src/labs/index.js +5 -1
- package/src/labs/inspector.js +183 -0
- package/src/labs/scout.js +0 -2
- package/src/logistics/formatter.js +32 -0
- package/src/workshop/react/builder/index.js +1 -1
- package/src/workshop/react/extensions/useTableQuery.js +0 -51
- package/src/workshop/react/kit/utils.js +51 -102
- package/src/workshop/react/standardParts/AliyunOSSUpload.js +0 -45
- package/src/workshop/react/standardParts/DraggableContainer.js +1 -1
- package/src/workshop/react/standardParts/EditableCell.js +31 -73
- package/src/workshop/react/standardParts/MyBaseForm.js +1 -48
- package/src/workshop/react/standardParts/MyDescription.js +2 -2
- package/src/workshop/react/standardParts/MyForm.js +41 -15
- package/src/workshop/react/standardParts/MyModalForm.js +3 -84
- package/src/workshop/react/standardParts/MyModalTable.js +0 -53
- package/src/workshop/react/standardParts/MyPopoverTable.js +23 -0
- package/src/workshop/react/standardParts/MySearchForm.js +2 -60
- package/src/workshop/react/standardParts/MyTable.js +38 -122
- package/src/workshop/react/standardParts/index.js +5 -18
|
@@ -1,80 +1,18 @@
|
|
|
1
|
-
import { Table } from 'antd'
|
|
1
|
+
import { Table, Space } from 'antd'
|
|
2
2
|
import { DraggableContainer } from './DraggableContainer'
|
|
3
3
|
import { EditableRow, EditableCell } from './EditableCell'
|
|
4
4
|
import { useRef, useMemo, useEffect, useCallback } from 'react'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
* @component MyTable
|
|
8
|
-
* @description [地堡核心战术平台] 高级数据表格组件。
|
|
9
|
-
* 它是地堡系统的“火力中心”,集成了行内编辑、自动滚动定位、动态分页协议及 Optimistic UI (乐观更新) 等工业级特性。
|
|
10
|
-
*
|
|
11
|
-
* @param {Object} props - 平台配置参数
|
|
12
|
-
* @param {number} props.total - 物资总量:用于构筑分页器的刻度
|
|
13
|
-
* @param {Object} [props.rowSelection] - 战术勾选:配置行选择逻辑
|
|
14
|
-
* @param {string} [props.rowKey='id'] - 唯一标识:每一行物资的数字指纹
|
|
15
|
-
* @param {boolean} [props.loading=false] - 战场负载状态:显示加载动画
|
|
16
|
-
* @param {Array} [props.dataSource=[]] - 物理物资包:表格展示的原始数据
|
|
17
|
-
* @param {Object} props.search - 当前物流状态:包含 pageNo 和 pageSize
|
|
18
|
-
* @param {Object} [props.query] - 侦察参数:包含 rowIndex 用于执行物理追踪定位
|
|
19
|
-
* @param {boolean} [props.autoScroll] - 视觉引导开关:是否开启自动滚动至目标行逻辑
|
|
20
|
-
* @param {Function} [props.lineFormChange] - 行级信号监听:捕获行内表单的实时变动
|
|
21
|
-
* @param {Function} props.onChange - 战位协同回调:分页、排序、筛选变动时的通信协议
|
|
22
|
-
* @param {boolean|Object} [props.pagination] - 分页配置:支持布尔开关或物理对象覆盖
|
|
23
|
-
* @param {Function} [props.customSave] - 物理封存协议:行内编辑保存后的外部持久化回调
|
|
24
|
-
* @param {Array} props.columns - 零部件清单:定义列的构筑协议,支持 editType 等扩展属性
|
|
25
|
-
* @param {Object} [props.scroll={x:'max-content'}] - 滚动配置:默认开启横向物理溢出防护
|
|
26
|
-
* @param {string} [props.size='middle'] - 视觉能级:表格的物理尺寸 (small/middle/large)
|
|
27
|
-
* @param {Function} props.setDataSource - 状态设置器:直接操作地堡的原始数据流(支持函数式更新)
|
|
28
|
-
* @param {string|Function} [props.rowClassName] - 行视觉涂装:支持静态字符串或基于逻辑的动态类名
|
|
29
|
-
*
|
|
30
|
-
* @param {Object} [props.renderAction] - [后期物理绑定协议] 运行时逻辑注入仓库。
|
|
31
|
-
* @description
|
|
32
|
-
* 这是地堡系统的“黑客骇入”接口。
|
|
33
|
-
* 由于 resource.js 必须保持纯净的静态 JSON 格式以确保主权安全性,
|
|
34
|
-
* 凡是涉及“查看图片”、“跳转链接”等需要运行时函数支持的列,
|
|
35
|
-
* 统一通过该协议在渲染阶段执行“逻辑对冲”。
|
|
36
|
-
*
|
|
37
|
-
* @logic
|
|
38
|
-
* 1. 物理寻址:通过 col.dataIndex 锁定目标零部件位点。
|
|
39
|
-
* 2. 逻辑脱壳:删除临时标记字段 [renderAction: true]。
|
|
40
|
-
* 3. 语义注入:将 index.js 中定义的真实 Action 物理焊接到 columns.render 属性上。
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* // 1. 在 resource.js 中标记:
|
|
44
|
-
* { title: '图片', dataIndex: 'imgUrl', renderAction: true }
|
|
45
|
-
*
|
|
46
|
-
* // 2. 在 index.js 中提供弹药:
|
|
47
|
-
* <MyTable
|
|
48
|
-
* total={100}
|
|
49
|
-
* columns={columns}
|
|
50
|
-
* dataSource={data}
|
|
51
|
-
* setDataSource={setData}
|
|
52
|
-
* customSave={(row) => saveApi(row)}
|
|
53
|
-
* renderAction={{
|
|
54
|
-
* imgUrl: (text, record) => <a onClick={() => showImg(record)}>查看物资</a>
|
|
55
|
-
* }}
|
|
56
|
-
* />
|
|
57
|
-
*/
|
|
58
|
-
export const MyTable = ({ size, query, total, search, options, autoScroll, onChange, setSearch, pagination, editRender = {}, renderAction, rowClassName, customSave, setDataSource, lineFormChange, columns = [], rowSelection, rowKey = 'id', loading = false, dataSource = [], draggable = false, scroll = { x: 'max-content' }, isLocalPaging = false, ...restProps }) => {
|
|
6
|
+
export const MyTable = ({ size, query, total, search, options, autoScroll, onChange, editingKey, setSearch, pagination, editRender = {}, renderAction, rowClassName, customSave, setDataSource, lineFormChange, columns = [], rowSelection, rowKey = 'id', editMode = 'cellEdit', loading = false, dataSource = [], draggable = false, scroll = { x: 'max-content' }, isLocalPaging = false, ...restProps }) => {
|
|
59
7
|
|
|
60
8
|
const tableRef = useRef(null)
|
|
61
9
|
const hasScrolledRef = useRef(false)
|
|
62
10
|
const dataSourceRef = useRef(dataSource)
|
|
63
11
|
dataSourceRef.current = dataSource
|
|
64
12
|
|
|
65
|
-
/**
|
|
66
|
-
* @description [权限侦察] 自动扫描列配置。若存在 editType 型号,则激活“骇入模式(编辑模式)”。
|
|
67
|
-
*/
|
|
68
13
|
const isEditable = useMemo(() => columns.some(col => col.editType), [columns])
|
|
69
14
|
const hasCustomComponents = isEditable || draggable
|
|
70
15
|
|
|
71
|
-
/**
|
|
72
|
-
* @function handleSave
|
|
73
|
-
* @description [原子级物理封存] 执行数据更新协议。
|
|
74
|
-
* 采用函数式状态更新(prev => ...)以彻底消除闭航陷阱(Stale Closure),确保数据高频修改时的绝对准确。
|
|
75
|
-
*
|
|
76
|
-
* @param {Object} row - 修改后的行片段
|
|
77
|
-
*/
|
|
78
16
|
const handleSave = useCallback((row) => {
|
|
79
17
|
const prev = dataSourceRef.current
|
|
80
18
|
const index = prev.findIndex(item => row[rowKey] === item[rowKey])
|
|
@@ -87,75 +25,65 @@ export const MyTable = ({ size, query, total, search, options, autoScroll, onCha
|
|
|
87
25
|
customSave?.(updatedRow, newData)
|
|
88
26
|
}, [rowKey, customSave, setDataSource])
|
|
89
27
|
|
|
90
|
-
/**
|
|
91
|
-
* @constant components
|
|
92
|
-
* @description [零部件注册] 注入地堡特有的可编辑 Row 和 Cell 单元。
|
|
93
|
-
*/
|
|
94
28
|
const components = useMemo(() => {
|
|
95
29
|
if (!hasCustomComponents) return undefined
|
|
96
30
|
const c = { body: {} }
|
|
97
|
-
// 1. 只有有编辑列时,才挂载行内编辑单元
|
|
98
31
|
if (isEditable) {
|
|
99
32
|
c.body.row = EditableRow
|
|
100
33
|
c.body.cell = EditableCell
|
|
101
34
|
}
|
|
102
|
-
// 2. 只有开启了拖拽,才挂载拖拽容器
|
|
103
35
|
if (draggable) {
|
|
104
36
|
c.body.wrapper = props => <DraggableContainer props={props} customSave={customSave} setDataSource={setDataSource} dataSourceRef={dataSourceRef} />
|
|
105
37
|
}
|
|
106
38
|
return c
|
|
107
39
|
}, [isEditable, draggable, customSave, setDataSource])
|
|
108
40
|
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* @constant mergedColumns
|
|
112
|
-
* @description [元数据重组] 将指挥官的静态列定义转化为带逻辑注入的“动态作战列”。
|
|
113
|
-
* 自动处理 Cell 级的 disabled 状态和 editable 权限。
|
|
114
|
-
*/
|
|
115
41
|
const mergedColumns = useMemo(() => {
|
|
116
42
|
return columns.map(col => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
currentCol
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
),
|
|
146
|
-
}
|
|
43
|
+
let currentCol = { ...col }
|
|
44
|
+
if (col.renderAction && renderAction?.[col.dataIndex]) {
|
|
45
|
+
currentCol.render = renderAction[col.dataIndex]
|
|
46
|
+
}
|
|
47
|
+
if (col.search) {
|
|
48
|
+
currentCol = {
|
|
49
|
+
...currentCol,
|
|
50
|
+
filterSearch: true,
|
|
51
|
+
onFilter: (value, record) => col.remote ? undefined : col.customFilter({ value, record, dataIndex: col.dataIndex }),
|
|
52
|
+
filterDropdown: ({ close, confirm, selectedKeys, clearFilters, setSelectedKeys }) => (
|
|
53
|
+
<Space direction='vertical' style={{ padding: 12 }}>
|
|
54
|
+
{col.customFilterDropdown({ dataIndex: col.dataIndex, selectedKeys, setSelectedKeys })}
|
|
55
|
+
<div style={{ display: 'flex' }}>
|
|
56
|
+
<a style={{ marginLeft: 'auto', marginRight: 8 }} onClick={() => {
|
|
57
|
+
if (col.remote) {
|
|
58
|
+
setSearch(prev => ({ ...prev, pageNo: 1, [col.dataIndex]: col.formatFilter?.(selectedKeys) ?? selectedKeys?.toString() }))
|
|
59
|
+
}
|
|
60
|
+
confirm()
|
|
61
|
+
}}>确定</a>
|
|
62
|
+
<a onClick={() => {
|
|
63
|
+
if (col.remote) {
|
|
64
|
+
setSearch(prev => ({ ...prev, pageNo: 1, [col.dataIndex]: undefined }))
|
|
65
|
+
}
|
|
66
|
+
clearFilters()
|
|
67
|
+
}}>重置</a>
|
|
68
|
+
</div>
|
|
69
|
+
</Space>
|
|
70
|
+
),
|
|
147
71
|
}
|
|
72
|
+
}
|
|
73
|
+
if (!col.editType) {
|
|
148
74
|
return currentCol
|
|
149
75
|
}
|
|
150
76
|
return {
|
|
151
|
-
...
|
|
77
|
+
...currentCol,
|
|
152
78
|
onCell: (record) => ({
|
|
153
|
-
...
|
|
79
|
+
...currentCol,
|
|
154
80
|
record,
|
|
81
|
+
rowKey,
|
|
82
|
+
editMode,
|
|
155
83
|
handleSave,
|
|
84
|
+
editingKey,
|
|
156
85
|
editRender: editRender?.[col.dataIndex],
|
|
157
86
|
options: col.options ?? options?.[col.dataIndex],
|
|
158
|
-
// 💡 条件防御逻辑:支持针对单行的物理锁定
|
|
159
87
|
disabled: col.specialDisabled ? record.disabled : col.disabled,
|
|
160
88
|
editable: col.specialEditType ? record.needEdit && !!col.editType : !!col.editType,
|
|
161
89
|
}),
|
|
@@ -163,11 +91,6 @@ export const MyTable = ({ size, query, total, search, options, autoScroll, onCha
|
|
|
163
91
|
})
|
|
164
92
|
}, [columns, options, handleSave, editRender, renderAction])
|
|
165
93
|
|
|
166
|
-
/**
|
|
167
|
-
* @constant paginationConfig
|
|
168
|
-
* @description [后勤对齐协议] 自动将地堡的 search 状态映射为 Antd 分页模型。
|
|
169
|
-
* 具备类型自适应能力:支持 boolean 开关或 Object 属性覆盖。
|
|
170
|
-
*/
|
|
171
94
|
const paginationConfig = useMemo(() => {
|
|
172
95
|
|
|
173
96
|
if (!pagination) return false
|
|
@@ -184,21 +107,15 @@ export const MyTable = ({ size, query, total, search, options, autoScroll, onCha
|
|
|
184
107
|
}
|
|
185
108
|
}, [total, search, pagination, isLocalPaging])
|
|
186
109
|
|
|
187
|
-
/**
|
|
188
|
-
* @description [视觉追踪协议] 当检测到 query.rowIndex 信号时,执行“物理重定向”。
|
|
189
|
-
* 表格将自动平滑滚动至目标行并注入高亮背景(#e6f4ff)。
|
|
190
|
-
*/
|
|
191
110
|
useEffect(() => {
|
|
192
111
|
if (!autoScroll || !dataSource?.length || query?.rowIndex === undefined) return
|
|
193
112
|
if (hasScrolledRef.current === query.rowIndex) return
|
|
194
113
|
const timer = setTimeout(() => {
|
|
195
114
|
const tableElement = tableRef.current
|
|
196
115
|
if (!tableElement) return
|
|
197
|
-
// 物理侦察:查找底层 Antd 生成的行节点
|
|
198
116
|
const trList = tableElement.getElementsByClassName('ant-table-row')
|
|
199
117
|
const tr = trList[Number(query.rowIndex)]
|
|
200
118
|
if (tr) {
|
|
201
|
-
// 物理定位:平滑引导视觉中心
|
|
202
119
|
tr.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
|
203
120
|
tr.style.backgroundColor = '#e6f4ff'
|
|
204
121
|
hasScrolledRef.current = query.rowIndex
|
|
@@ -221,8 +138,7 @@ export const MyTable = ({ size, query, total, search, options, autoScroll, onCha
|
|
|
221
138
|
components={components}
|
|
222
139
|
rowSelection={rowSelection}
|
|
223
140
|
pagination={paginationConfig}
|
|
224
|
-
|
|
225
|
-
onRow={(record, index) => ({ record, index, draggable, ...(typeof lineFormChange === 'function' ? { onValuesChange: lineFormChange } : {}) })}
|
|
141
|
+
onRow={(record, index) => ({ record, index, draggable, columns: mergedColumns, ...(typeof lineFormChange === 'function' ? { onValuesChange: lineFormChange } : {}) })}
|
|
226
142
|
rowClassName={(record, index) => {
|
|
227
143
|
const externalClass = typeof rowClassName === 'function' ? rowClassName(record, index) : rowClassName
|
|
228
144
|
const classes = [externalClass]
|
|
@@ -1,29 +1,16 @@
|
|
|
1
|
+
import { MyBaseForm } from './MyBaseForm'
|
|
1
2
|
import { AliyunOSSUpload } from './AliyunOSSUpload'
|
|
2
3
|
import { Tree, Form, Radio, Input, Upload, Select, Cascader, Checkbox, DatePicker, InputNumber, TreeSelect, AutoComplete } from 'antd'
|
|
3
4
|
|
|
4
|
-
/**
|
|
5
|
-
* @function formNode
|
|
6
|
-
* @description 智能零部件装配器:根据构筑协议(item.type)动态产出对应的 Ant Design 交互单元。
|
|
7
|
-
*
|
|
8
|
-
* @param {Object} params - 装配参数
|
|
9
|
-
* @param {Object} params.item - 零部件配置对象
|
|
10
|
-
* @param {string|number} [params.item.width] - 宽度校准
|
|
11
|
-
* @param {boolean} [params.item.readOnly] - 物理锁定开关
|
|
12
|
-
* @param {string} [params.item.placeholder] - 视觉占位提示
|
|
13
|
-
* @param {Object} [params.item.props] - 透传给底层组件的原始控制参数
|
|
14
|
-
* @param {Array} [params.item.options] - 数据字典(用于 select/radio/tree 等)
|
|
15
|
-
* @param {string} params.item.type - 构筑类型(date/number/ossUpload/select/daterange 等)
|
|
16
|
-
*
|
|
17
|
-
* @returns {React.ReactNode} 物理装配完成的 UI 单元
|
|
18
|
-
*/
|
|
19
5
|
export const formNode = ({ item }) => {
|
|
20
6
|
|
|
21
7
|
if (item.type === 'group' && Array.isArray(item.groups)) {
|
|
22
8
|
return (
|
|
23
9
|
<Input.Group compact style={{ width: item.width ?? '100%', display: 'flex', ...item.style }}>
|
|
24
|
-
{item.groups.map(subItem => (
|
|
25
|
-
<Form.Item noStyle key={subItem.name}
|
|
26
|
-
{
|
|
10
|
+
{item.groups.map((subItem, ind) => (
|
|
11
|
+
<Form.Item noStyle key={subItem.name}>
|
|
12
|
+
<div style={{ flex: 1, minWidth: 0, marginRight: 8 }}><MyBaseForm item={subItem} key={subItem.name} /></div>
|
|
13
|
+
{ind < item.groups.length - 1 && <span style={{ color: '#888', whiteSpace: 'nowrap', marginRight: 8 }}>{item.separator}</span>}
|
|
27
14
|
</Form.Item>
|
|
28
15
|
))}
|
|
29
16
|
</Input.Group>
|