@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.
Files changed (31) hide show
  1. package/bin/bunker.js +2 -0
  2. package/config.js +2 -0
  3. package/package.json +1 -1
  4. package/src/constitution/inspector.js +20 -0
  5. package/src/constitution/system.js +2 -8
  6. package/src/dialogues/EN-US.js +8 -0
  7. package/src/dialogues/FR-FR.js +8 -0
  8. package/src/dialogues/JA-JP.js +8 -0
  9. package/src/dialogues/RU-RU.js +8 -0
  10. package/src/dialogues/ZH-CN.js +8 -0
  11. package/src/gateway/client.js +1 -1
  12. package/src/gateway/index.js +17 -7
  13. package/src/labs/index.js +5 -1
  14. package/src/labs/inspector.js +183 -0
  15. package/src/labs/scout.js +0 -2
  16. package/src/logistics/formatter.js +32 -0
  17. package/src/workshop/react/builder/index.js +1 -1
  18. package/src/workshop/react/extensions/useTableQuery.js +0 -51
  19. package/src/workshop/react/kit/utils.js +51 -102
  20. package/src/workshop/react/standardParts/AliyunOSSUpload.js +0 -45
  21. package/src/workshop/react/standardParts/DraggableContainer.js +1 -1
  22. package/src/workshop/react/standardParts/EditableCell.js +31 -73
  23. package/src/workshop/react/standardParts/MyBaseForm.js +1 -48
  24. package/src/workshop/react/standardParts/MyDescription.js +2 -2
  25. package/src/workshop/react/standardParts/MyForm.js +41 -15
  26. package/src/workshop/react/standardParts/MyModalForm.js +3 -84
  27. package/src/workshop/react/standardParts/MyModalTable.js +0 -53
  28. package/src/workshop/react/standardParts/MyPopoverTable.js +23 -0
  29. package/src/workshop/react/standardParts/MySearchForm.js +2 -60
  30. package/src/workshop/react/standardParts/MyTable.js +38 -122
  31. 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
- if (!col.editType) {
118
- let currentCol = { ...col }
119
- if (col.renderAction && renderAction?.[col.dataIndex]) {
120
- currentCol.render = renderAction[col.dataIndex]
121
- }
122
- if (col.search) {
123
- currentCol = {
124
- ...currentCol,
125
- filterSearch: true,
126
- onFilter: (value, record) => col.remote ? undefined : col.customFilter({ value, record, dataIndex: col.dataIndex }),
127
- filterDropdown: ({ close, confirm, selectedKeys, clearFilters, setSelectedKeys }) => (
128
- <Space direction='vertical' style={{ padding: 12 }}>
129
- {col.customFilterDropdown({ dataIndex: col.dataIndex, selectedKeys, setSelectedKeys })}
130
- <div style={{ display: 'flex' }}>
131
- <a style={{ marginLeft: 'auto', marginRight: 8 }} onClick={() => {
132
- if (col.remote) {
133
- setSearch(prev => ({ ...prev, pageNo: 1, [col.dataIndex]: col.formatFilter?.(selectedKeys) ?? selectedKeys?.toString() }))
134
- }
135
- confirm()
136
- }}>确定</a>
137
- <a onClick={() => {
138
- if (col.remote) {
139
- setSearch(prev => ({ ...prev, pageNo: 1, [col.dataIndex]: undefined }))
140
- }
141
- clearFilters()
142
- }}>重置</a>
143
- </div>
144
- </Space>
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
- ...col,
77
+ ...currentCol,
152
78
  onCell: (record) => ({
153
- ...col,
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
- // 💡 信号注入:将行监听协议绑定至底层 tr
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} name={subItem.name} rules={subItem.rules} initialValue={subItem.value}>
26
- {formNode({ item: subItem })}
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>