Skip to content

Commit 2fb82d2

Browse files
feat: document preview
1 parent 4aee0bb commit 2fb82d2

26 files changed

Lines changed: 105 additions & 63 deletions

File tree

‎ui/src/api/admin/system/shared-resources/model.ts‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ const getModelList = (query?: Dict<unknown>) => {
1313
}
1414

1515
/** 获取 System 共享范围的模型选项,并标记共享来源。 */
16-
// TODO 资源共享的模型是不是都是共享的
1716
const getModelListWithShared = (query?: Dict<unknown>): Promise<ModelItem[]> =>
1817
getModelList(query).then((models) => models.map((model): ModelItem => ({ ...model, source: 'shared' })))
1918

@@ -57,7 +56,6 @@ const putPauseModelDownload = (modelId: string) => {
5756
return put<undefined, boolean>(`${prefix}/${modelId}/pause_download`)
5857
}
5958

60-
6159
/** 使用指定模型流式生成或优化系统提示词。 */
6260
const postPromptGenerate = (modelId: string, payload: PromptGeneratePayload) => {
6361
return postStream(ADMIN_API_BASE_PATH, `/system/shared/model/${modelId}/prompt_generate`, { ...payload })

‎ui/src/components/COMPONENT_README.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ Admin、Chat 入口调用 `configureMarkdownEditor()` 配置本地高亮、KaTeX
172172

173173
### MkDialog
174174

175+
Dialog 和 Drawer 的 `show-close` 不根据 loading 或提交状态动态判断,默认保留关闭按钮;
176+
业务需要固定隐藏关闭按钮时,可继续使用 `:show-close="false"`。
177+
175178
布尔 `v-model` 控制显示,默认宽度 `600`、挂载到 body、显示关闭按钮、关闭后销毁,
176179
禁止点击遮罩和 Escape 关闭。其余 Dialog 属性、事件通过 `$attrs` 透传。
177180
提供默认、`header`、`subtitle`、`footer` 插槽;`subtitle` 不替代标题,`header` 透出原生关闭与标题参数。
@@ -682,6 +685,7 @@ Logo 数据统一从 Theme Store 获取。
682685
多文件选择,拖拽区保持显示。`accept`、`limit` 直接传给上传控件,多文件模式内部也校验文件格式、
683686
空文件和重复文件;超出数量时提示并发出 `exceed`。`sizeLimit` 为多文件的单文件大小上限(MB),
684687
默认 100;超限保留 `fail` 卡片和大小错误提示,不允许重试。格式不支持、空文件及重复选择移除;
688+
重复选择保留列表中最先加入的文件,移除时同步清理上传控件内部列表,避免回写未上传的重复项。
685689
目录中的 `.DS_Store` 格式不支持时静默移除。
686690
`dragText`、`selectText`、`tipText` 和 `replaceText` 可替换默认文案,格式或限制说明通过
687691
`tipText` 展示。文件列表由各模式组件直接展示,多文件模式展示
@@ -773,6 +777,11 @@ JSON 专用输入框,通过 `v-model` 接收并回传解析后的 JSON 值,
773777
文件夹选择、进度、失败重试、取消和成功文件删除由 `MkDragUpload` 维护,文件值采用
774778
`DragUploadFile[]`,失败状态为 `fail`。
775779

780+
`LocalFileUpload` 和文档上传页共用 `mk-drag-upload/validation.ts` 的文件状态校验,失败统一
781+
使用 `MsgWarning`,文件字段不展示行内错误。存在待上传或上传中文件时阻止继续;必填且没有
782+
成功文件时提示重新上传,非必填字段允许空列表。动态表单保留配置的其他校验规则,文件字段
783+
仅在调用表单 `validate()` 时校验和提示,其他字段的校验展示方式不变。
784+
776785
`MkDynamicsForm` 根据字段配置渲染动态表单,统一维护字段值、默认值、显隐规则和表单校验;
777786
`MkDynamicsFormConstructor` 用于新增或编辑单个字段配置。该组件族位于 `components` 直属目录,
778787
使用方必须从 `@/components/mk-dynamics-form` 手动导入,不安装为 Vue 插件,也不全局注册其内部

‎ui/src/components/business/folder-tree/MoveToDialog.vue‎

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,7 @@ defineExpose({ close, open })
3838
</script>
3939

4040
<template>
41-
<MkDialog
42-
align-center
43-
v-model="visible"
44-
class="move-to-dialog"
45-
content-class="move-to-dialog__content"
46-
title="移动到"
47-
:show-close="!loading"
48-
@closed="resetData"
49-
>
41+
<MkDialog align-center v-model="visible" class="move-to-dialog" content-class="move-to-dialog__content" title="移动到" @closed="resetData">
5042
<FolderTree
5143
v-model="selectedTargetId"
5244
class="move-to-dialog__folder-tree"

‎ui/src/components/business/resource-authorization-drawer/PermissionConfigDialog.vue‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ defineExpose({ open, close })
4343
</script>
4444

4545
<template>
46-
<MkDialog v-model="visible" :title="scopeOnly ? '生效资源' : '配置权限'" :show-close="!loading" @closed="resetData">
46+
<MkDialog v-model="visible" :title="scopeOnly ? '生效资源' : '配置权限'" @closed="resetData">
4747
<el-radio-group v-if="!scopeOnly" v-model="permission" class="mk-radio-group-vertical" :disabled="loading">
4848
<el-radio v-for="option in options" :key="option.value" :value="option.value">
4949
<p>{{ option.label }}</p>

‎ui/src/components/business/resource-authorization-drawer/index.vue‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ defineExpose({ open })
153153
</script>
154154

155155
<template>
156-
<MkDrawer v-model="drawerVisible" title="资源授权" :size="920" :show-close="!submitting" @closed="handleClosed">
156+
<MkDrawer v-model="drawerVisible" title="资源授权" :size="920" @closed="handleClosed">
157157
<el-tabs v-model="targetType" :before-leave="() => !submitting">
158158
<el-tab-pane label="按用户组" name="user-group" />
159159
<el-tab-pane label="按用户" name="user" />

‎ui/src/components/mk-drag-upload/MultipleFileUpload.vue‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,11 @@ function validateFile(file: DragUploadFile) {
6464
handleRemove(file)
6565
return false
6666
}
67+
const fileIndex = fileList.value.findIndex((selected) => selected.uid === file.uid)
6768
if (
68-
fileList.value.some(
69-
(selected) =>
70-
selected.uid !== file.uid &&
71-
selected.name === file.name &&
72-
selected.size === file.size &&
73-
selected.raw?.lastModified === file.raw?.lastModified,
74-
)
69+
fileList.value
70+
.slice(0, fileIndex)
71+
.some((selected) => selected.name === file.name && selected.size === file.size && selected.raw?.lastModified === file.raw?.lastModified)
7572
) {
7673
handleRemove(file)
7774
return false
@@ -126,7 +123,6 @@ function handleUpload(file: DragUploadFile) {
126123
return request.then((response) => {
127124
if (file.status !== 'uploading') return
128125
const split_path = response.split('/')
129-
// TODO
130126
file.file_id = split_path[split_path.length - 1]
131127
file.percentage = 100
132128
file.status = 'success'
@@ -169,6 +165,12 @@ function handleRemove(file: DragUploadFile) {
169165
// 请求层统一提示删除失败,临时文件仍按有效期清理。
170166
})
171167
}
168+
// 同步清理 ElUpload 的内部列表,避免后续 change 回写已移除的重复文件。
169+
if (file.uid !== undefined) {
170+
void Promise.resolve(uploadRef.value?.handleRemove({ ...file, uid: file.uid, status: file.status ?? 'ready' })).catch(() => {
171+
// 控件已移除该文件时,仍以调用方列表的清理结果为准。
172+
})
173+
}
172174
fileList.value = fileList.value.filter((selected) => selected.uid !== file.uid)
173175
emit('remove', file)
174176
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { DragUploadFile } from './types'
2+
3+
/** 文件校验只返回文案,由页面或表单统一使用 MsgWarning 提示。 */
4+
export function getUploadValidationMessage(files: DragUploadFile[], required = true): string | undefined {
5+
if (files.some((file) => file.status === 'ready' || file.status === 'uploading')) {
6+
return '文件正在上传,请稍候'
7+
}
8+
if (!required && !files.length) return
9+
if (!files.some((file) => file.status === 'success')) {
10+
return '没有上传成功的文件,请重新上传'
11+
}
12+
}

‎ui/src/components/mk-dynamics-form/FormItem.vue‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { FormItemRule } from 'element-plus'
44
import { get } from 'lodash'
55
import type { Dict } from '@/api/types'
66
import bus from '@/utils/bus'
7+
import { getUploadValidationMessage } from '@/components/mk-drag-upload/validation'
78
import FormItemLabel from './FormItemLabel.vue'
89
import type { DynamicFormTriggerMap, DynamicFormTriggerSetting, DynamicFormValue, FormField, FormFieldLabel, SerializedFormRule } from './type'
910
@@ -95,7 +96,7 @@ const errorMessage = computed(() => {
9596
return fieldProps.value.err_msg
9697
}
9798
const label = isString(props.formField.label) ? props.formField.label : props.formField.label?.label
98-
return `${label || props.formField.field} 不能为空`
99+
return `请输入 ${label || props.formField.field}`
99100
})
100101
101102
function deserializeRule(rule: SerializedFormRule): FormItemRule {
@@ -110,6 +111,20 @@ function deserializeRule(rule: SerializedFormRule): FormItemRule {
110111
}
111112
112113
const validationRules = computed<FormItemRule | FormItemRule[]>(() => {
114+
if (props.formField.input_type === 'LocalFileUpload') {
115+
// 文件字段在提交时校验,错误统一由 MkDynamicsForm 使用 MsgWarning 提示。
116+
const uploadRules: FormItemRule[] = [
117+
{
118+
required: props.formField.required !== false,
119+
validator: (_rule, value, callback) => {
120+
const message = getUploadValidationMessage(Array.isArray(value) ? value : [], props.formField.required !== false)
121+
callback(message ? new Error(message) : undefined)
122+
},
123+
},
124+
...(fieldProps.value.rules?.map(deserializeRule) ?? []),
125+
]
126+
return uploadRules.map((rule) => ({ ...rule, trigger: [] }))
127+
}
113128
if (fieldProps.value.rules) {
114129
return fieldProps.value.rules.map(deserializeRule)
115130
}
@@ -183,6 +198,7 @@ defineExpose({ validate })
183198
:style="formItemStyle"
184199
:prop="formField.field"
185200
:rules="validationRules"
201+
:show-message="formField.input_type !== 'LocalFileUpload'"
186202
:class="fieldLabel && getFieldComponent(fieldLabel.input_type) ? 'mk-hide-asterisk' : ''"
187203
>
188204
<template v-if="formField.label" #label>

‎ui/src/components/mk-dynamics-form/index.vue‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { FormInstance } from 'element-plus'
44
import { cloneDeep, isEqual } from 'lodash'
55
import { del, get, post, put } from '@/api/admin/core/request'
66
import type { Dict } from '@/api/types'
7+
import { MsgWarning } from '@/utils/message'
78
import FormItem from './FormItem.vue'
89
import type {
910
DynamicFormResponse,
@@ -304,7 +305,18 @@ async function validate() {
304305
}
305306
}
306307
307-
return Promise.all([...formItemRefs.value.map((item) => item.validate()), ruleFormRef.value?.validate() ?? Promise.resolve()])
308+
const formValidation = ruleFormRef.value?.validate().catch((error: unknown) => {
309+
if (error && typeof error === 'object') {
310+
const invalidFields = error as Record<string, { message?: string }[]>
311+
const uploadField = formFieldList.value.find(
312+
(field) => field.input_type === 'LocalFileUpload' && isFieldVisible(field) && invalidFields[field.field]?.[0]?.message,
313+
)
314+
const message = uploadField && invalidFields[uploadField.field]?.[0]?.message
315+
if (message) MsgWarning(message)
316+
}
317+
throw error
318+
})
319+
return Promise.all([...formItemRefs.value.map((item) => item.validate()), formValidation ?? Promise.resolve()])
308320
}
309321
310322
defineExpose({ initDefaultData: initializeFieldDefault, render, ruleFormRef, validate })

‎ui/src/components/mk-dynamics-form/items/upload/LocalFileUpload.vue‎

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,25 @@ const accept = computed(() => fileTypes.value.map((type) => `.${type.toLowerCase
3939
const formats = computed(() => fileTypes.value.map((type) => type.toUpperCase()).join('、'))
4040
const fileSizeLimit = computed(() => Number(props.formField.attrs?.file_size_limit ?? attrs.file_size_limit) || 50)
4141
const fileCountLimit = computed(() => Number(props.formField.attrs?.file_count_limit ?? attrs.file_count_limit) || 100)
42-
const tipText = computed(
43-
() => `单次上传最多 ${fileCountLimit.value} 个文件,每个文件最大 ${fileSizeLimit.value} MB${formats.value ? `;支持格式:${formats.value}` : ''}`,
44-
)
4542
</script>
4643

4744
<template>
48-
<MkDragUpload
49-
v-model="selectedFiles"
50-
multiple
51-
:disabled="inputDisabled"
52-
:accept="accept"
53-
:limit="fileCountLimit"
54-
:size-limit="fileSizeLimit"
55-
:tip-text="tipText"
56-
/>
45+
<div class="w-full">
46+
<el-alert type="primary" :closable="false" show-icon class="mb-4!">
47+
<template #icon><MkIcon name="icon_info_filled" /></template>
48+
<ol class="list-inside list-decimal space-y-1">
49+
<li>文件上传前,建议规范文件的分段标识</li>
50+
<li>每次最多上传 {{ fileCountLimit }} 个文件,每个文件不超过 {{ fileSizeLimit }} MB</li>
51+
</ol>
52+
</el-alert>
53+
<MkDragUpload
54+
v-model="selectedFiles"
55+
multiple
56+
:disabled="inputDisabled"
57+
:accept="accept"
58+
:limit="fileCountLimit"
59+
:size-limit="fileSizeLimit"
60+
:tip-text="formats ? `支持格式:${formats}` : ''"
61+
/>
62+
</div>
5763
</template>

0 commit comments

Comments
 (0)