@veltra/desktop 1.7.13 → 1.7.15
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/components/batch-edit/batch-edit-form.js +9 -3
- package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
- package/dist/components/batch-edit/batch-edit-list.js +2 -1
- package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
- package/dist/components/batch-edit/batch-edit.js +57 -30
- package/dist/components/batch-edit/batch-edit.js.map +1 -1
- package/dist/components/batch-edit/style.d.ts +1 -0
- package/dist/components/batch-edit/style.js +1 -0
- package/dist/components/batch-edit/style2.css +14 -0
- package/dist/components/batch-edit/use-dialog-effect.js +20 -0
- package/dist/components/batch-edit/use-dialog-effect.js.map +1 -0
- package/dist/components/batch-edit/use-edit-state.js +22 -3
- package/dist/components/batch-edit/use-edit-state.js.map +1 -1
- package/dist/components/batch-edit/use-handlers.js +5 -0
- package/dist/components/batch-edit/use-handlers.js.map +1 -1
- package/dist/components/batch-edit/use-shortcut-key.js +5 -2
- package/dist/components/batch-edit/use-shortcut-key.js.map +1 -1
- package/dist/components/file-viewer/file-viewer.js +21 -14
- package/dist/components/file-viewer/file-viewer.js.map +1 -1
- package/dist/components/file-viewer/helper.js +2 -0
- package/dist/components/file-viewer/helper.js.map +1 -1
- package/dist/components/file-viewer/previewers/ofd-previewer.js +196 -0
- package/dist/components/file-viewer/previewers/ofd-previewer.js.map +1 -0
- package/dist/components/file-viewer/style2.css +27 -0
- package/dist/components/table-editor/style2.css +23 -3
- package/dist/components/table-editor/table-editor.js +213 -63
- package/dist/components/table-editor/table-editor.js.map +1 -1
- package/dist/components/tip/style2.css +63 -0
- package/dist/components/tip/tip.js +6 -1
- package/dist/components/tip/tip.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/packages/ofd-core/dist/color.js +69 -0
- package/dist/packages/ofd-core/dist/color.js.map +1 -0
- package/dist/packages/ofd-core/dist/ctm.js +55 -0
- package/dist/packages/ofd-core/dist/ctm.js.map +1 -0
- package/dist/packages/ofd-core/dist/error.js +14 -0
- package/dist/packages/ofd-core/dist/error.js.map +1 -0
- package/dist/packages/ofd-core/dist/font.js +384 -0
- package/dist/packages/ofd-core/dist/font.js.map +1 -0
- package/dist/packages/ofd-core/dist/index.js +6 -0
- package/dist/packages/ofd-core/dist/number.js +13 -0
- package/dist/packages/ofd-core/dist/number.js.map +1 -0
- package/dist/packages/ofd-core/dist/page-objects.js +181 -0
- package/dist/packages/ofd-core/dist/page-objects.js.map +1 -0
- package/dist/packages/ofd-core/dist/parse.js +65 -0
- package/dist/packages/ofd-core/dist/parse.js.map +1 -0
- package/dist/packages/ofd-core/dist/render.js +361 -0
- package/dist/packages/ofd-core/dist/render.js.map +1 -0
- package/dist/packages/ofd-core/dist/xml.js +199 -0
- package/dist/packages/ofd-core/dist/xml.js.map +1 -0
- package/dist/packages/ofd-core/dist/zip.js +93 -0
- package/dist/packages/ofd-core/dist/zip.js.map +1 -0
- package/dist/style.d.ts +1 -1
- package/dist/style.js +1 -1
- package/dist/types/batch-edit.d.ts +6 -0
- package/dist/types/file-viewer.d.ts +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/table-editor.d.ts +28 -7
- package/dist/types/tip.d.ts +5 -1
- package/package.json +8 -7
- package/src/components/batch-edit/__test__/batch-edit.test.ts +191 -4
- package/src/components/batch-edit/batch-edit-form.vue +17 -3
- package/src/components/batch-edit/batch-edit-list.vue +2 -1
- package/src/components/batch-edit/batch-edit.vue +22 -4
- package/src/components/batch-edit/style.scss +20 -0
- package/src/components/batch-edit/style.ts +1 -0
- package/src/components/batch-edit/use-dialog-effect.ts +9 -3
- package/src/components/batch-edit/use-edit-state.ts +32 -4
- package/src/components/batch-edit/use-handlers.ts +10 -0
- package/src/components/batch-edit/use-shortcut-key.ts +6 -2
- package/src/components/file-viewer/__test__/helper.test.ts +13 -0
- package/src/components/file-viewer/file-viewer.vue +23 -16
- package/src/components/file-viewer/helper.ts +2 -0
- package/src/components/file-viewer/previewers/ofd-previewer.vue +216 -0
- package/src/components/file-viewer/style.scss +33 -0
- package/src/components/table-editor/__test__/table-editor.test.ts +471 -0
- package/src/components/table-editor/style.scss +42 -4
- package/src/components/table-editor/table-editor.vue +265 -38
- package/src/components/tip/style.scss +15 -0
- package/src/components/tip/tip.vue +1 -1
- package/src/types/batch-edit.ts +6 -0
- package/src/types/file-viewer.ts +1 -1
- package/src/types/table-editor.ts +29 -7
- package/src/types/tip.ts +6 -1
|
@@ -1,101 +1,328 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<u-table
|
|
3
|
+
v-bind="tableProps"
|
|
3
4
|
:columns="internalColumns"
|
|
4
|
-
:data="modelValue
|
|
5
|
+
:data="modelValue"
|
|
5
6
|
:class="cls.b"
|
|
6
7
|
:stripe="false"
|
|
7
8
|
show-index
|
|
8
|
-
:slots="$slots"
|
|
9
9
|
>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<u-button :icon="Plus" @click="handleCreate(row.index)" title="新增到下一行" />
|
|
14
|
-
<u-button :icon="Copy" @click="handleCopy(row)" title="复制到下一行" />
|
|
15
|
-
</ButtonCommonProps>
|
|
10
|
+
<!-- 其余插槽(header:* / row:expand / foot / append 等)透传给 u-table;column:* 与 empty 由组件接管 -->
|
|
11
|
+
<template v-for="name in passSlotNames" :key="name" #[name]="scope">
|
|
12
|
+
<slot :name="name" v-bind="scope" />
|
|
16
13
|
</template>
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
<template #column:__operation="{ row }">
|
|
16
|
+
<div :class="cls.e('operations')">
|
|
17
|
+
<u-button
|
|
18
|
+
text
|
|
19
|
+
size="small"
|
|
20
|
+
type="danger"
|
|
21
|
+
:icon="Minus"
|
|
22
|
+
title="移除"
|
|
23
|
+
@click="handleDelete(row.index)"
|
|
24
|
+
/>
|
|
25
|
+
<u-button
|
|
26
|
+
text
|
|
27
|
+
size="small"
|
|
28
|
+
:icon="Plus"
|
|
29
|
+
title="新增到下一行"
|
|
30
|
+
@click="handleCreate(row.index)"
|
|
31
|
+
/>
|
|
32
|
+
<u-button text size="small" :icon="Copy" title="复制到下一行" @click="handleCopy(row)" />
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
19
35
|
|
|
20
36
|
<template #empty>
|
|
21
37
|
<div style="text-align: center; padding: 4px 0">
|
|
22
38
|
<u-button
|
|
39
|
+
v-if="!props.readonly"
|
|
23
40
|
text
|
|
24
41
|
size="small"
|
|
25
42
|
type="primary"
|
|
26
|
-
v-if="!modelValue.length"
|
|
27
43
|
:icon="Plus"
|
|
28
44
|
@click="handleCreate()"
|
|
29
|
-
>添加</u-button
|
|
30
45
|
>
|
|
46
|
+
添加
|
|
47
|
+
</u-button>
|
|
31
48
|
</div>
|
|
32
49
|
</template>
|
|
33
50
|
</u-table>
|
|
34
51
|
</template>
|
|
35
52
|
|
|
36
53
|
<script lang="ts" setup>
|
|
37
|
-
import {
|
|
38
|
-
import { Copy, Minus, Plus } from '@veltra/icons/normal'
|
|
54
|
+
import { o } from '@cat-kit/core'
|
|
55
|
+
import { Copy, Minus, Plus, Warning } from '@veltra/icons/normal'
|
|
39
56
|
import { bem } from '@veltra/utils'
|
|
40
|
-
import { computed } from 'vue'
|
|
57
|
+
import { computed, h, shallowRef, toRaw, triggerRef, useSlots, watch } from 'vue'
|
|
41
58
|
|
|
42
|
-
import type {
|
|
59
|
+
import type {
|
|
60
|
+
TableEditorProps,
|
|
61
|
+
TableEditorEmits,
|
|
62
|
+
TableEditorColumn,
|
|
63
|
+
_TableEditorExposed,
|
|
64
|
+
TableColumn,
|
|
65
|
+
TableColumnNode,
|
|
66
|
+
TableColumnRenderContext,
|
|
67
|
+
TableColumnSlotsScope,
|
|
68
|
+
RenderReturn
|
|
69
|
+
} from '../../types'
|
|
43
70
|
import { UButton } from '../button'
|
|
71
|
+
import { validateField } from '../form-item/validate'
|
|
72
|
+
import { UIcon } from '../icon'
|
|
44
73
|
import { UTable } from '../table'
|
|
45
74
|
import type { TableRowNode } from '../table/node/row'
|
|
75
|
+
import { UTip } from '../tip'
|
|
46
76
|
|
|
47
77
|
defineOptions({ name: 'UTableEditor' })
|
|
48
78
|
|
|
49
|
-
|
|
79
|
+
defineSlots<{
|
|
80
|
+
[key: `column:${string}`]: (props: TableColumnSlotsScope) => any
|
|
81
|
+
[key: `header:${string}`]: (props: { column: TableColumnNode }) => any
|
|
82
|
+
}>()
|
|
83
|
+
|
|
84
|
+
const props = defineProps<TableEditorProps>()
|
|
50
85
|
const emit = defineEmits<TableEditorEmits>()
|
|
51
86
|
|
|
52
|
-
const
|
|
87
|
+
const columns = computed(() => props.columns ?? [])
|
|
88
|
+
const modelValue = computed(() => props.modelValue ?? [])
|
|
53
89
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
90
|
+
/** 转发给 u-table 的表格属性;columns / modelValue / readonly 为编辑器自用,stripe / showIndex 被覆盖 */
|
|
91
|
+
const tableProps = computed(() => {
|
|
92
|
+
const rest: Record<string, any> = { ...props }
|
|
93
|
+
delete rest.columns
|
|
94
|
+
delete rest.modelValue
|
|
95
|
+
delete rest.readonly
|
|
96
|
+
return rest
|
|
59
97
|
})
|
|
60
98
|
|
|
99
|
+
const cls = bem('table-editor')
|
|
100
|
+
|
|
101
|
+
const slots = useSlots()
|
|
102
|
+
|
|
61
103
|
const actionColumn: TableColumn = {
|
|
62
104
|
key: '__operation',
|
|
63
|
-
name: '操作',
|
|
64
|
-
width:
|
|
105
|
+
name: '操作',
|
|
106
|
+
width: 104,
|
|
65
107
|
align: 'center',
|
|
66
108
|
fixed: 'right',
|
|
67
109
|
resizable: false
|
|
68
110
|
}
|
|
69
111
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
112
|
+
/**
|
|
113
|
+
* 内部列定义:单元格渲染挂在列的 render 上(用户列自带的 render 优先),
|
|
114
|
+
* 配置了 rules 的列包装 nameRender 追加校验标识,非只读时末尾追加操作列。
|
|
115
|
+
* 列 key 带上只读态后缀:u-table 行内单元格在 props 值相等时可能跳过子组件补丁,
|
|
116
|
+
* 只读切换改用挂载键直接重挂单元格,确保控件在编辑/只读形态间可靠切换。
|
|
117
|
+
*/
|
|
118
|
+
const internalColumns = computed<TableColumn[]>(() => {
|
|
119
|
+
const list = columns.value.map((column) => ({
|
|
120
|
+
...column,
|
|
121
|
+
key: `${column.key}${props.readonly ? ':ro' : ''}`,
|
|
122
|
+
nameRender: column.rules ? headerCell(column) : column.nameRender,
|
|
123
|
+
render: column.render ?? ((ctx: TableColumnRenderContext) => editCell(column, ctx))
|
|
124
|
+
}))
|
|
125
|
+
return props.readonly ? list : [...list, actionColumn]
|
|
73
126
|
})
|
|
74
127
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
128
|
+
/** 透传给 u-table 的插槽名:column:* 经 editCell 注入 model、empty 由组件接管,其余透传 */
|
|
129
|
+
const passSlotNames = Object.keys(slots).filter(
|
|
130
|
+
(name) => !name.startsWith('column:') && name !== 'empty'
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 带校验的列表头包装:required 时列名前渲染红星;该列存在未通过项时文字标红并追加
|
|
135
|
+
* 感叹号图标,悬停经 UTip 气泡展示各行错误明细;`#header:key` 插槽 / nameRender 内容替代列名。
|
|
136
|
+
* 渲染函数内读取 columnErrors 建立响应依赖,错误出现/消失即时更新表头。
|
|
137
|
+
*/
|
|
138
|
+
function headerCell(column: TableEditorColumn) {
|
|
139
|
+
return (ctx: { column: TableColumnNode }): RenderReturn => {
|
|
140
|
+
const messages = columnErrors.value.get(column.key)
|
|
141
|
+
const nodes = [
|
|
142
|
+
h(
|
|
143
|
+
'span',
|
|
144
|
+
{ class: [cls.e('header-text'), bem.is('error', !!messages?.length)] },
|
|
145
|
+
slots[`header:${column.key}`]?.(ctx) ?? column.nameRender?.(ctx) ?? column.name
|
|
146
|
+
)
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
if (column.rules?.required) {
|
|
150
|
+
nodes.unshift(h('span', { class: cls.e('required-mark'), 'aria-hidden': 'true' }, '*'))
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (messages?.length) {
|
|
154
|
+
nodes.push(
|
|
155
|
+
h(
|
|
156
|
+
UTip,
|
|
157
|
+
{ key: 'header-error-tip' },
|
|
158
|
+
{
|
|
159
|
+
default: () =>
|
|
160
|
+
h(UIcon, { size: 14, class: cls.e('header-icon') }, { default: () => h(Warning) }),
|
|
161
|
+
content: () => messages.map((message) => h('div', { key: message }, message))
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return nodes
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// --- 按列校验 ---
|
|
172
|
+
|
|
173
|
+
/** 行数据(以原始对象为键)→ 列 key → 错误信息 */
|
|
174
|
+
const cellErrors = shallowRef(new Map<Record<string, any>, Map<string, string>>())
|
|
175
|
+
|
|
176
|
+
/** 行节点 data 可能是响应式代理,统一取原始对象作为键 */
|
|
177
|
+
const errorRowKey = (rowData: Record<string, any>) => toRaw(rowData) as Record<string, any>
|
|
178
|
+
|
|
179
|
+
function setCellError(rowData: Record<string, any>, key: string, message: string | undefined) {
|
|
180
|
+
const row = errorRowKey(rowData)
|
|
181
|
+
const rowErrors = cellErrors.value.get(row)
|
|
182
|
+
|
|
183
|
+
if (!message) {
|
|
184
|
+
if (!rowErrors?.delete(key)) return
|
|
82
185
|
} else {
|
|
83
|
-
|
|
186
|
+
if (rowErrors?.get(key) === message) return
|
|
187
|
+
if (rowErrors) rowErrors.set(key, message)
|
|
188
|
+
else cellErrors.value.set(row, new Map([[key, message]]))
|
|
84
189
|
}
|
|
190
|
+
|
|
191
|
+
triggerRef(cellErrors)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** 丢弃同一单元格过期的异步校验结果 */
|
|
195
|
+
const validateSeqs = new WeakMap<Record<string, any>, Map<string, number>>()
|
|
196
|
+
|
|
197
|
+
/** 单元格级校验:以行数据为 formData、列 key 为 field,结果同步到错误状态 */
|
|
198
|
+
async function validateCell(
|
|
199
|
+
rowData: Record<string, any>,
|
|
200
|
+
key: string,
|
|
201
|
+
rules: TableEditorColumn['rules']
|
|
202
|
+
) {
|
|
203
|
+
if (!rules) return
|
|
204
|
+
|
|
205
|
+
const row = errorRowKey(rowData)
|
|
206
|
+
let seqs = validateSeqs.get(row)
|
|
207
|
+
if (!seqs) {
|
|
208
|
+
seqs = new Map()
|
|
209
|
+
validateSeqs.set(row, seqs)
|
|
210
|
+
}
|
|
211
|
+
const seq = (seqs.get(key) ?? 0) + 1
|
|
212
|
+
seqs.set(key, seq)
|
|
213
|
+
|
|
214
|
+
const message = await validateField(rowData, key, rules)
|
|
215
|
+
if (seqs.get(key) !== seq) return
|
|
216
|
+
// 校验是异步的,期间行可能已被移出模型(整体替换/删除);
|
|
217
|
+
// 把结果写回「死行」会绕过清理 watch 永久残留,直接丢弃
|
|
218
|
+
if (!modelValue.value.some((item) => errorRowKey(item) === row)) return
|
|
219
|
+
|
|
220
|
+
setCellError(row, key, message)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* 整表校验:自上而下逐行校验,某行存在未通过项即停止校验其后的行(懒校验)。
|
|
225
|
+
* 全部通过 resolve true,否则 resolve false。
|
|
226
|
+
*/
|
|
227
|
+
async function validate() {
|
|
228
|
+
const ruleColumns = columns.value.filter((column) => column.rules)
|
|
229
|
+
|
|
230
|
+
for (const row of modelValue.value) {
|
|
231
|
+
await Promise.all(ruleColumns.map((column) => validateCell(row, column.key, column.rules)))
|
|
232
|
+
if (cellErrors.value.get(errorRowKey(row))?.size) return false
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return true
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// 行删除(或整体替换)后,同步清理已不存在的行数据上的错误
|
|
239
|
+
watch(modelValue, (rows) => {
|
|
240
|
+
if (!cellErrors.value.size) return
|
|
241
|
+
|
|
242
|
+
const aliveRows = new Set(rows.map(errorRowKey))
|
|
243
|
+
const next = new Map<Record<string, any>, Map<string, string>>()
|
|
244
|
+
let changed = false
|
|
245
|
+
|
|
246
|
+
for (const [row, errors] of cellErrors.value) {
|
|
247
|
+
if (aliveRows.has(row)) next.set(row, errors)
|
|
248
|
+
else changed = true
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (changed) cellErrors.value = next
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
/** 列 key → 该列全部未通过信息(带行序号),驱动表头错误标识 */
|
|
255
|
+
const columnErrors = computed(() => {
|
|
256
|
+
const map = new Map<string, string[]>()
|
|
257
|
+
if (!cellErrors.value.size) return map
|
|
258
|
+
|
|
259
|
+
for (const [row, errors] of cellErrors.value) {
|
|
260
|
+
const index = modelValue.value.findIndex((item) => errorRowKey(item) === row)
|
|
261
|
+
const label = index >= 0 ? `第 ${index + 1} 行:` : ''
|
|
262
|
+
for (const [key, message] of errors) {
|
|
263
|
+
const list = map.get(key) ?? []
|
|
264
|
+
list.push(`${label}${message}`)
|
|
265
|
+
map.set(key, list)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return map
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
// --- 单元格渲染 ---
|
|
272
|
+
|
|
273
|
+
/** 声明了 `#column:key` 插槽的列调用编辑插槽(注入 model),未声明的渲染字段原始值 */
|
|
274
|
+
function editCell(column: TableEditorColumn, ctx: TableColumnRenderContext): RenderReturn {
|
|
275
|
+
const editSlot = slots[`column:${column.key}`]
|
|
276
|
+
// 内部列 key 带只读态后缀,u-table 按 key 取到的 val 失效,这里按原始列 key 重取
|
|
277
|
+
const val = o(ctx.rowData).get(column.key)
|
|
278
|
+
if (!editSlot) return val
|
|
279
|
+
const scope = { ...ctx, val }
|
|
280
|
+
return editSlot({ ...scope, model: createCellModel(column, scope) })
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* 单元格编辑 model:值先原地写回行数据(行节点与 DOM 得以复用,输入不丢焦点),
|
|
285
|
+
* 再以浅拷贝数组经 update:modelValue 通知宿主,维持 v-model 契约。
|
|
286
|
+
* 只读下注入 readonly: true 且不提供写回通道,值不可修改;
|
|
287
|
+
* 列配置了 rules 时,控件的 change 事件(如失焦提交)触发单元格级校验,输入过程不校验。
|
|
288
|
+
*/
|
|
289
|
+
function createCellModel(column: TableEditorColumn, ctx: TableColumnRenderContext) {
|
|
290
|
+
const { rowData, val } = ctx
|
|
291
|
+
const key = column.key
|
|
292
|
+
const rules = column.rules
|
|
293
|
+
return {
|
|
294
|
+
modelValue: val,
|
|
295
|
+
...(props.readonly
|
|
296
|
+
? { readonly: true }
|
|
297
|
+
: {
|
|
298
|
+
'onUpdate:modelValue': (value: any) => {
|
|
299
|
+
rowData[key] = value
|
|
300
|
+
emit('update:modelValue', [...modelValue.value])
|
|
301
|
+
}
|
|
302
|
+
}),
|
|
303
|
+
...(rules ? { onChange: () => void validateCell(rowData, key, rules) } : {})
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function handleCreate(index?: number) {
|
|
308
|
+
const at = index !== undefined ? index + 1 : modelValue.value.length
|
|
309
|
+
emit('update:modelValue', [...modelValue.value.slice(0, at), {}, ...modelValue.value.slice(at)])
|
|
85
310
|
}
|
|
86
311
|
|
|
87
312
|
function handleCopy(row: TableRowNode) {
|
|
88
313
|
emit('update:modelValue', [
|
|
89
|
-
...modelValue.slice(0, row.index + 1),
|
|
314
|
+
...modelValue.value.slice(0, row.index + 1),
|
|
90
315
|
JSON.parse(JSON.stringify(row.data)),
|
|
91
|
-
...modelValue.slice(row.index + 1)
|
|
316
|
+
...modelValue.value.slice(row.index + 1)
|
|
92
317
|
])
|
|
93
318
|
}
|
|
94
319
|
|
|
95
320
|
function handleDelete(index: number) {
|
|
96
321
|
emit(
|
|
97
322
|
'update:modelValue',
|
|
98
|
-
modelValue.filter((_, i) => i !== index)
|
|
323
|
+
modelValue.value.filter((_, i) => i !== index)
|
|
99
324
|
)
|
|
100
325
|
}
|
|
326
|
+
|
|
327
|
+
defineExpose<_TableEditorExposed>({ validate })
|
|
101
328
|
</script>
|
|
@@ -40,6 +40,21 @@ $root-name: tip;
|
|
|
40
40
|
font-size: fn.use-var(font-size, main, $size);
|
|
41
41
|
padding: fn.use-var(gap, $size);
|
|
42
42
|
}
|
|
43
|
+
|
|
44
|
+
// 类型配色
|
|
45
|
+
@each $type, $_ in vars.$color-types {
|
|
46
|
+
@include m.m(color-#{$type}) {
|
|
47
|
+
color: fn.use-var(text-color, white);
|
|
48
|
+
|
|
49
|
+
&::after {
|
|
50
|
+
background-color: fn.use-var(color, $type);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@include m.bem($root-name, arrow) {
|
|
54
|
+
background-color: fn.use-var(color, $type);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
43
58
|
}
|
|
44
59
|
|
|
45
60
|
.#{$root-name}-enter-active,
|
|
@@ -55,7 +55,7 @@ const slots = useSlots()
|
|
|
55
55
|
const { size } = useFallbackProps([props], { size: 'default' as ComponentSize })
|
|
56
56
|
|
|
57
57
|
const contentClass = computed(() => {
|
|
58
|
-
const fixed = [cls.e('content'), cls.m(size.value)]
|
|
58
|
+
const fixed = [cls.e('content'), cls.m(size.value), props.type && cls.m('color-' + props.type)]
|
|
59
59
|
const className = props.class
|
|
60
60
|
if (!Array.isArray(className)) {
|
|
61
61
|
return [...fixed, className]
|
package/src/types/batch-edit.ts
CHANGED
|
@@ -43,6 +43,12 @@ export interface BatchEditProps extends TableProps {
|
|
|
43
43
|
cols?: string | [string, string]
|
|
44
44
|
/** 只读模式 */
|
|
45
45
|
readonly?: boolean
|
|
46
|
+
/**
|
|
47
|
+
* 表单交互模式
|
|
48
|
+
* @description `'panel'`:右侧面板(默认);`'dialog'`:编辑 / 新增 / 查看 / 添加子级时以弹框呈现表单
|
|
49
|
+
* @default 'panel'
|
|
50
|
+
*/
|
|
51
|
+
formMode?: 'panel' | 'dialog'
|
|
46
52
|
/**
|
|
47
53
|
* 开启快速编辑
|
|
48
54
|
* @description 开启后,编辑行时表单实时写回 `row.data`(经 `model` 中转),且不调用 `saveMethod`
|
package/src/types/file-viewer.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { DeconstructValue } from '@veltra/utils'
|
|
|
2
2
|
import type { ShallowRef } from 'vue'
|
|
3
3
|
|
|
4
4
|
/** 预览器类别:xlsx 与 csv 归一为 sheet */
|
|
5
|
-
export type FileViewerKind = 'image' | 'video' | 'pdf' | 'sheet' | 'docx' | 'text'
|
|
5
|
+
export type FileViewerKind = 'image' | 'video' | 'pdf' | 'sheet' | 'docx' | 'ofd' | 'text'
|
|
6
6
|
|
|
7
7
|
/** 单个预览文件定义 */
|
|
8
8
|
export interface FileViewerItem {
|
|
@@ -1,20 +1,42 @@
|
|
|
1
|
-
import type { DeconstructValue } from '@veltra/utils'
|
|
1
|
+
import type { DeconstructValue, ValidateRule } from '@veltra/utils'
|
|
2
2
|
|
|
3
|
-
import type { TableProps } from './table'
|
|
3
|
+
import type { TableProps, TableColumn } from './table'
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
export interface
|
|
5
|
+
/** 表格编辑器列:在 TableColumn 基础上扩展按列校验 */
|
|
6
|
+
export interface TableEditorColumn extends TableColumn {
|
|
7
|
+
/** 列校验规则:配置后该列控件的 change 事件触发单元格校验,`required` 非空时表头列名前渲染红星 */
|
|
8
|
+
rules?: ValidateRule
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 表格型编辑器组件属性
|
|
13
|
+
*
|
|
14
|
+
* 单元格常驻渲染:声明了 `#column:key` 插槽的列,输入控件常驻挂载;
|
|
15
|
+
* 未声明编辑插槽的列渲染字段原始值。
|
|
16
|
+
*/
|
|
17
|
+
export interface TableEditorProps extends Omit<TableProps, 'data' | 'columns'> {
|
|
7
18
|
/** 表格数据 */
|
|
8
|
-
modelValue?: any[]
|
|
19
|
+
modelValue?: Record<string, any>[]
|
|
20
|
+
/** 表格列 */
|
|
21
|
+
columns?: TableEditorColumn[]
|
|
22
|
+
/**
|
|
23
|
+
* 只读模式
|
|
24
|
+
* @default false
|
|
25
|
+
* @description 只读下输入控件经插槽 model 收到 readonly: true(值不可修改),操作列与空态「添加」按钮不渲染
|
|
26
|
+
*/
|
|
27
|
+
readonly?: boolean
|
|
9
28
|
}
|
|
10
29
|
|
|
11
30
|
/** 表格型编辑器组件定义的事件 */
|
|
12
31
|
export interface TableEditorEmits {
|
|
13
|
-
(e: 'update:modelValue', value: any[]): void
|
|
32
|
+
(e: 'update:modelValue', value: Record<string, any>[]): void
|
|
14
33
|
}
|
|
15
34
|
|
|
16
35
|
/** 表格型编辑器组件暴露的属性和方法(组件内部使用) */
|
|
17
|
-
export interface _TableEditorExposed {
|
|
36
|
+
export interface _TableEditorExposed {
|
|
37
|
+
/** 校验全表配置了 rules 的列,全部通过 resolve true,任一失败 resolve false */
|
|
38
|
+
validate(): Promise<boolean>
|
|
39
|
+
}
|
|
18
40
|
|
|
19
41
|
/** 表格型编辑器组件暴露的属性和方法(组件外部使用, 引用的值会被自动解构) */
|
|
20
42
|
export type TableEditorExposed = DeconstructValue<_TableEditorExposed>
|
package/src/types/tip.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import type { DeconstructValue } from '@veltra/utils'
|
|
1
|
+
import type { ColorType, DeconstructValue } from '@veltra/utils'
|
|
2
2
|
import type { CSSProperties } from 'vue'
|
|
3
3
|
|
|
4
4
|
export type TipDirection = 'top' | 'bottom' | 'left' | 'right'
|
|
5
5
|
|
|
6
6
|
export type TipAlign = 'center' | 'start' | 'end'
|
|
7
7
|
|
|
8
|
+
/** tip类型 */
|
|
9
|
+
export type TipType = ColorType
|
|
10
|
+
|
|
8
11
|
/** tip提示组件组件属性 */
|
|
9
12
|
export interface TipProps {
|
|
10
13
|
/** 控制显影 */
|
|
11
14
|
visible?: boolean
|
|
15
|
+
/** tip类型 */
|
|
16
|
+
type?: TipType
|
|
12
17
|
/**提示内容 */
|
|
13
18
|
content?: string
|
|
14
19
|
/** 自定义tip样式 */
|