feat:增加 fileConfig 文件配置(全部)、file 文件(部分)
parent
1a3657b2bf
commit
b4d1c678fd
|
@ -0,0 +1,68 @@
|
||||||
|
import { requestClient } from '#/api/request';
|
||||||
|
import type { PageParam, PageResult } from '@vben/request';
|
||||||
|
|
||||||
|
export namespace InfraFileConfigApi {
|
||||||
|
/** 文件客户端配置 */
|
||||||
|
export interface FileClientConfig {
|
||||||
|
basePath: string;
|
||||||
|
host?: string;
|
||||||
|
port?: number;
|
||||||
|
username?: string;
|
||||||
|
password?: string;
|
||||||
|
mode?: string;
|
||||||
|
endpoint?: string;
|
||||||
|
bucket?: string;
|
||||||
|
accessKey?: string;
|
||||||
|
accessSecret?: string;
|
||||||
|
domain: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 文件配置信息 */
|
||||||
|
export interface InfraFileConfig {
|
||||||
|
id?: number;
|
||||||
|
name: string;
|
||||||
|
storage?: number;
|
||||||
|
master: boolean;
|
||||||
|
visible: boolean;
|
||||||
|
config: FileClientConfig;
|
||||||
|
remark: string;
|
||||||
|
createTime?: Date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 查询文件配置列表 */
|
||||||
|
export function getFileConfigPage(params: PageParam) {
|
||||||
|
return requestClient.get<PageResult<InfraFileConfigApi.InfraFileConfig>>('/infra/file-config/page', {
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 查询文件配置详情 */
|
||||||
|
export function getFileConfig(id: number) {
|
||||||
|
return requestClient.get<InfraFileConfigApi.InfraFileConfig>(`/infra/file-config/get?id=${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新文件配置为主配置 */
|
||||||
|
export function updateFileConfigMaster(id: number) {
|
||||||
|
return requestClient.put(`/infra/file-config/update-master?id=${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 新增文件配置 */
|
||||||
|
export function createFileConfig(data: InfraFileConfigApi.InfraFileConfig) {
|
||||||
|
return requestClient.post('/infra/file-config/create', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 修改文件配置 */
|
||||||
|
export function updateFileConfig(data: InfraFileConfigApi.InfraFileConfig) {
|
||||||
|
return requestClient.put('/infra/file-config/update', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除文件配置 */
|
||||||
|
export function deleteFileConfig(id: number) {
|
||||||
|
return requestClient.delete(`/infra/file-config/delete?id=${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 测试文件配置 */
|
||||||
|
export function testFileConfig(id: number) {
|
||||||
|
return requestClient.get(`/infra/file-config/test?id=${id}`);
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { requestClient } from '#/api/request';
|
||||||
|
import type { PageParam, PageResult } from '@vben/request';
|
||||||
|
|
||||||
|
export namespace InfraFileApi {
|
||||||
|
/** 文件信息 */
|
||||||
|
export interface InfraFile {
|
||||||
|
id?: number;
|
||||||
|
configId?: number;
|
||||||
|
path: string;
|
||||||
|
name?: string;
|
||||||
|
url?: string;
|
||||||
|
size?: number;
|
||||||
|
type?: string;
|
||||||
|
createTime?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 文件预签名地址 */
|
||||||
|
export interface FilePresignedUrlRespVO {
|
||||||
|
configId: number; // 文件配置编号
|
||||||
|
uploadUrl: string; // 文件上传 URL
|
||||||
|
url: string; // 文件 URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 查询文件列表 */
|
||||||
|
export function getFilePage(params: PageParam) {
|
||||||
|
return requestClient.get<PageResult<InfraFileApi.InfraFile>>('/infra/file/page', {
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除文件 */
|
||||||
|
export function deleteFile(id: number) {
|
||||||
|
return requestClient.delete(`/infra/file/delete?id=${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取文件预签名地址 */
|
||||||
|
export function getFilePresignedUrl(path: string) {
|
||||||
|
return requestClient.get<InfraFileApi.FilePresignedUrlRespVO>('/infra/file/presigned-url', {
|
||||||
|
params: { path }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 创建文件 */
|
||||||
|
export function createFile(data: InfraFileApi.InfraFile) {
|
||||||
|
return requestClient.post('/infra/file/create', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 上传文件 */
|
||||||
|
export function uploadFile(data: any) {
|
||||||
|
return requestClient.upload('/infra/file/upload', data);
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ import type { OnActionClickParams, VxeTableGridOptions } from '#/adapter/vxe-tab
|
||||||
import type { InfraApiErrorLogApi } from '#/api/infra/api-error-log';
|
import type { InfraApiErrorLogApi } from '#/api/infra/api-error-log';
|
||||||
|
|
||||||
import { Page, useVbenModal } from '@vben/common-ui';
|
import { Page, useVbenModal } from '@vben/common-ui';
|
||||||
import {Button, message, Modal} from 'ant-design-vue';
|
import { Button, message, Modal } from 'ant-design-vue';
|
||||||
import { Download } from '@vben/icons';
|
import { Download } from '@vben/icons';
|
||||||
import Detail from './modules/detail.vue';
|
import Detail from './modules/detail.vue';
|
||||||
import { DocAlert } from '#/components/doc-alert';
|
import { DocAlert } from '#/components/doc-alert';
|
||||||
|
|
|
@ -14,7 +14,6 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
{
|
{
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
label: 'id',
|
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: [''],
|
triggerFields: [''],
|
||||||
show: () => false,
|
show: () => false,
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
import { type VbenFormSchema, z } from '#/adapter/form';
|
||||||
|
import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
|
import type { InfraFileApi } from '#/api/infra/file';
|
||||||
|
|
||||||
|
import { useAccess } from '@vben/access';
|
||||||
|
import { getRangePickerDefaultProps } from '#/utils/date';
|
||||||
|
|
||||||
|
const { hasAccessByCodes } = useAccess();
|
||||||
|
|
||||||
|
/** 列表的搜索表单 */
|
||||||
|
export function useGridFormSchema(): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'path',
|
||||||
|
label: '文件路径',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入文件路径',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'type',
|
||||||
|
label: '文件类型',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入文件类型',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'createTime',
|
||||||
|
label: '创建时间',
|
||||||
|
component: 'RangePicker',
|
||||||
|
componentProps: {
|
||||||
|
...getRangePickerDefaultProps(),
|
||||||
|
allowClear: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 列表的字段 */
|
||||||
|
export function useGridColumns<T = InfraFileApi.InfraFile>(
|
||||||
|
onActionClick: OnActionClickFn<T>,
|
||||||
|
): VxeTableGridOptions['columns'] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
field: 'name',
|
||||||
|
title: '文件名',
|
||||||
|
minWidth: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'path',
|
||||||
|
title: '文件路径',
|
||||||
|
minWidth: 200,
|
||||||
|
showOverflow: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'url',
|
||||||
|
title: 'URL',
|
||||||
|
minWidth: 200,
|
||||||
|
showOverflow: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'size',
|
||||||
|
title: '文件大小',
|
||||||
|
minWidth: 80,
|
||||||
|
formatter: ({ cellValue }) => {
|
||||||
|
// TODO @芋艿:后续优化下
|
||||||
|
if (!cellValue) return '0 B';
|
||||||
|
const unitArr = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||||
|
const index = Math.floor(Math.log(cellValue) / Math.log(1024));
|
||||||
|
const size = cellValue / Math.pow(1024, index);
|
||||||
|
const formattedSize = size.toFixed(2);
|
||||||
|
return formattedSize + ' ' + unitArr[index];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'type',
|
||||||
|
title: '文件类型',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'url',
|
||||||
|
title: '文件内容',
|
||||||
|
minWidth: 120,
|
||||||
|
slots: {
|
||||||
|
default: 'file-content',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'createTime',
|
||||||
|
title: '上传时间',
|
||||||
|
minWidth: 180,
|
||||||
|
formatter: 'formatDateTime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'operation',
|
||||||
|
title: '操作',
|
||||||
|
width: 160,
|
||||||
|
fixed: 'right',
|
||||||
|
align: 'center',
|
||||||
|
cellRender: {
|
||||||
|
attrs: {
|
||||||
|
nameField: 'name',
|
||||||
|
nameTitle: '文件',
|
||||||
|
onClick: onActionClick,
|
||||||
|
},
|
||||||
|
name: 'CellOperation',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
code: 'copyUrl',
|
||||||
|
text: '复制链接',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'delete',
|
||||||
|
show: hasAccessByCodes(['infra:file:delete']),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { OnActionClickParams, VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
|
import type { InfraFileApi } from '#/api/infra/file';
|
||||||
|
|
||||||
|
import { Page, useVbenModal } from '@vben/common-ui';
|
||||||
|
import { Button, message, Image } from 'ant-design-vue';
|
||||||
|
import { Plus } from '@vben/icons';
|
||||||
|
import Form from './modules/form.vue';
|
||||||
|
|
||||||
|
import { $t } from '#/locales';
|
||||||
|
import { useClipboard } from '@vueuse/core';
|
||||||
|
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||||
|
import { getFilePage, deleteFile } from '#/api/infra/file';
|
||||||
|
import { useGridColumns, useGridFormSchema } from './data';
|
||||||
|
|
||||||
|
const [FormModal, formModalApi] = useVbenModal({
|
||||||
|
connectedComponent: Form,
|
||||||
|
destroyOnClose: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 刷新表格 */
|
||||||
|
function onRefresh() {
|
||||||
|
gridApi.query();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 上传文件 */
|
||||||
|
function onUpload() {
|
||||||
|
formModalApi.setData(null).open();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 复制链接到剪贴板 */
|
||||||
|
const { copy } = useClipboard({ legacy: true });
|
||||||
|
async function onCopyUrl(row: InfraFileApi.InfraFile) {
|
||||||
|
if (!row.url) {
|
||||||
|
message.error('文件 URL 为空');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await copy(row.url);
|
||||||
|
message.success('复制成功');
|
||||||
|
} catch (error) {
|
||||||
|
message.error('复制失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 打开 URL */
|
||||||
|
function openUrl(url?: string) {
|
||||||
|
if (url) {
|
||||||
|
window.open(url, '_blank');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除文件 */
|
||||||
|
async function onDelete(row: InfraFileApi.InfraFile) {
|
||||||
|
const hideLoading = message.loading({
|
||||||
|
content: $t('ui.actionMessage.deleting', [row.name || row.path]),
|
||||||
|
duration: 0,
|
||||||
|
key: 'action_process_msg',
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await deleteFile(row.id as number);
|
||||||
|
message.success({
|
||||||
|
content: $t('ui.actionMessage.deleteSuccess', [row.name || row.path]),
|
||||||
|
key: 'action_process_msg',
|
||||||
|
});
|
||||||
|
onRefresh();
|
||||||
|
} catch (error) {
|
||||||
|
hideLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 表格操作按钮的回调函数 */
|
||||||
|
function onActionClick({
|
||||||
|
code,
|
||||||
|
row,
|
||||||
|
}: OnActionClickParams<InfraFileApi.InfraFile>) {
|
||||||
|
switch (code) {
|
||||||
|
case 'delete': {
|
||||||
|
onDelete(row);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'copyUrl': {
|
||||||
|
onCopyUrl(row);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
|
formOptions: {
|
||||||
|
schema: useGridFormSchema()
|
||||||
|
},
|
||||||
|
gridOptions: {
|
||||||
|
columns: useGridColumns(onActionClick),
|
||||||
|
height: 'auto',
|
||||||
|
keepSource: true,
|
||||||
|
proxyConfig: {
|
||||||
|
ajax: {
|
||||||
|
query: async ({ page }, formValues) => {
|
||||||
|
return await getFilePage({
|
||||||
|
pageNo: page.currentPage,
|
||||||
|
pageSize: page.pageSize,
|
||||||
|
...formValues,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rowConfig: {
|
||||||
|
keyField: 'id',
|
||||||
|
},
|
||||||
|
toolbarConfig: {
|
||||||
|
refresh: { code: 'query' },
|
||||||
|
search: true,
|
||||||
|
},
|
||||||
|
} as VxeTableGridOptions<InfraFileApi.InfraFile>,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Page auto-content-height>
|
||||||
|
<FormModal @success="onRefresh" />
|
||||||
|
<Grid table-title="文件列表">
|
||||||
|
<template #toolbar-tools>
|
||||||
|
<Button type="primary" @click="onUpload">
|
||||||
|
<Plus class="size-5" />
|
||||||
|
{{ $t('ui.actionTitle.upload', ['文件']) }}
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
<template #file-content="{ row }">
|
||||||
|
<Image v-if="row.type && row.type.includes('image')" :src="row.url" />
|
||||||
|
<Button v-else-if="row.type && row.type.includes('pdf')" type="link" @click="() => openUrl(row.url)"> 预览 </Button>
|
||||||
|
<Button v-else type="link" @click="() => openUrl(row.url)"> 下载 </Button>
|
||||||
|
</template>
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
|
</template>
|
|
@ -0,0 +1,96 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { InfraFileApi } from '#/api/infra/file';
|
||||||
|
|
||||||
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useVbenForm } from '#/adapter/form';
|
||||||
|
import { uploadFile } from '#/api/infra/file';
|
||||||
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
|
const emit = defineEmits(['success']);
|
||||||
|
const fileList = ref<any[]>([]);
|
||||||
|
const uploadData = ref({ path: '' });
|
||||||
|
|
||||||
|
// 表单内容
|
||||||
|
const formSchema = [
|
||||||
|
{
|
||||||
|
fieldName: 'file',
|
||||||
|
component: 'Upload',
|
||||||
|
label: '文件上传',
|
||||||
|
componentProps: {
|
||||||
|
fileList: fileList.value,
|
||||||
|
name: 'file',
|
||||||
|
maxCount: 1,
|
||||||
|
accept: '.jpg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx',
|
||||||
|
beforeUpload: (file: File) => {
|
||||||
|
uploadData.value.path = file.name;
|
||||||
|
return false; // 阻止自动上传
|
||||||
|
},
|
||||||
|
onChange: ({ fileList }: any) => {
|
||||||
|
fileList.value = fileList;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 表单实例
|
||||||
|
const [Form, formApi] = useVbenForm({
|
||||||
|
layout: 'horizontal',
|
||||||
|
schema: formSchema,
|
||||||
|
showDefaultActions: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 模态框实例
|
||||||
|
const [Modal, modalApi] = useVbenModal({
|
||||||
|
async onConfirm() {
|
||||||
|
const { valid } = await formApi.validate();
|
||||||
|
if (!valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fileList.value.length === 0) {
|
||||||
|
message.error('请上传文件');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modalApi.lock();
|
||||||
|
// 提交表单
|
||||||
|
try {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', fileList.value[0].originFileObj);
|
||||||
|
formData.append('path', uploadData.value.path);
|
||||||
|
|
||||||
|
await uploadFile(formData);
|
||||||
|
|
||||||
|
// 关闭并提示
|
||||||
|
await modalApi.close();
|
||||||
|
emit('success');
|
||||||
|
message.success({
|
||||||
|
content: $t('ui.actionMessage.uploadSuccess'),
|
||||||
|
key: 'action_process_msg',
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
modalApi.lock(false);
|
||||||
|
fileList.value = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async onOpenChange(isOpen: boolean) {
|
||||||
|
if (!isOpen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 重置表单
|
||||||
|
fileList.value = [];
|
||||||
|
uploadData.value = { path: '' };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const getTitle = computed(() => $t('ui.actionTitle.upload', ['文件']));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal :title="getTitle">
|
||||||
|
<Form class="mx-4" />
|
||||||
|
</Modal>
|
||||||
|
</template>
|
|
@ -0,0 +1,322 @@
|
||||||
|
import { type VbenFormSchema, z } from '#/adapter/form';
|
||||||
|
import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
|
import type { InfraFileConfigApi } from '#/api/infra/file-config';
|
||||||
|
|
||||||
|
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
|
||||||
|
import { getRangePickerDefaultProps } from '#/utils/date';
|
||||||
|
import { useAccess } from '@vben/access';
|
||||||
|
|
||||||
|
const { hasAccessByCodes } = useAccess();
|
||||||
|
|
||||||
|
/** 新增/修改的表单 */
|
||||||
|
export function useFormSchema(): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'id',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: [''],
|
||||||
|
show: () => false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'name',
|
||||||
|
label: '配置名',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入配置名',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'storage',
|
||||||
|
label: '存储器',
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
options: getDictOptions(DICT_TYPE.INFRA_FILE_STORAGE, 'number'),
|
||||||
|
placeholder: '请选择存储器',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: ['id'],
|
||||||
|
show: (formValues) => !formValues.id
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'remark',
|
||||||
|
label: '备注',
|
||||||
|
component: 'Textarea',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入备注',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// DB / Local / FTP / SFTP
|
||||||
|
{
|
||||||
|
fieldName: 'config.basePath',
|
||||||
|
label: '基础路径',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入基础路径',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: ['storage'],
|
||||||
|
show: (formValues) => formValues.storage >= 10 && formValues.storage <= 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'config.host',
|
||||||
|
label: '主机地址',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入主机地址',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: ['storage'],
|
||||||
|
show: (formValues) => formValues.storage >= 11 && formValues.storage <= 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'config.port',
|
||||||
|
label: '主机端口',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
min: 0,
|
||||||
|
class: 'w-full',
|
||||||
|
controlsPosition: 'right',
|
||||||
|
placeholder: '请输入主机端口',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: ['storage'],
|
||||||
|
show: (formValues) => formValues.storage >= 11 && formValues.storage <= 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'config.username',
|
||||||
|
label: '用户名',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入用户名',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: ['storage'],
|
||||||
|
show: (formValues) => formValues.storage >= 11 && formValues.storage <= 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'config.password',
|
||||||
|
label: '密码',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入密码',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: ['storage'],
|
||||||
|
show: (formValues) => formValues.storage >= 11 && formValues.storage <= 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'config.mode',
|
||||||
|
label: '连接模式',
|
||||||
|
component: 'RadioGroup',
|
||||||
|
componentProps: {
|
||||||
|
options: [
|
||||||
|
{ label: '主动模式', value: 'Active' },
|
||||||
|
{ label: '被动模式', value: 'Passive' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: ['storage'],
|
||||||
|
show: (formValues) => formValues.storage === 11,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// S3
|
||||||
|
{
|
||||||
|
fieldName: 'config.endpoint',
|
||||||
|
label: '节点地址',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入节点地址',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: ['storage'],
|
||||||
|
show: (formValues) => formValues.storage === 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'config.bucket',
|
||||||
|
label: '存储 bucket',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入 bucket',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: ['storage'],
|
||||||
|
show: (formValues) => formValues.storage === 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'config.accessKey',
|
||||||
|
label: 'accessKey',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入 accessKey',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: ['storage'],
|
||||||
|
show: (formValues) => formValues.storage === 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'config.accessSecret',
|
||||||
|
label: 'accessSecret',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入 accessSecret',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: ['storage'],
|
||||||
|
show: (formValues) => formValues.storage === 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 通用
|
||||||
|
{
|
||||||
|
fieldName: 'config.domain',
|
||||||
|
label: '自定义域名',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入自定义域名',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: ['storage'],
|
||||||
|
show: (formValues) => !!formValues.storage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 列表的搜索表单 */
|
||||||
|
export function useGridFormSchema(): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'name',
|
||||||
|
label: '配置名',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入配置名',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'storage',
|
||||||
|
label: '存储器',
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
options: getDictOptions(DICT_TYPE.INFRA_FILE_STORAGE, 'number'),
|
||||||
|
placeholder: '请选择存储器',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'createTime',
|
||||||
|
label: '创建时间',
|
||||||
|
component: 'RangePicker',
|
||||||
|
componentProps: {
|
||||||
|
...getRangePickerDefaultProps(),
|
||||||
|
allowClear: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 列表的字段 */
|
||||||
|
export function useGridColumns<T = InfraFileConfigApi.InfraFileConfig>(
|
||||||
|
onActionClick: OnActionClickFn<T>,
|
||||||
|
): VxeTableGridOptions['columns'] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
field: 'id',
|
||||||
|
title: '编号',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'name',
|
||||||
|
title: '配置名',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'storage',
|
||||||
|
title: '存储器',
|
||||||
|
width: 100,
|
||||||
|
cellRender: {
|
||||||
|
name: 'CellDict',
|
||||||
|
props: { type: DICT_TYPE.INFRA_FILE_STORAGE },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'remark',
|
||||||
|
title: '备注',
|
||||||
|
minWidth: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'master',
|
||||||
|
title: '主配置',
|
||||||
|
width: 100,
|
||||||
|
cellRender: {
|
||||||
|
name: 'CellDict',
|
||||||
|
props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'createTime',
|
||||||
|
title: '创建时间',
|
||||||
|
width: 180,
|
||||||
|
formatter: 'formatDateTime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'operation',
|
||||||
|
title: '操作',
|
||||||
|
width: 280,
|
||||||
|
fixed: 'right',
|
||||||
|
align: 'center',
|
||||||
|
cellRender: {
|
||||||
|
attrs: {
|
||||||
|
nameField: 'name',
|
||||||
|
nameTitle: '文件配置',
|
||||||
|
onClick: onActionClick,
|
||||||
|
},
|
||||||
|
name: 'CellOperation',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
code: 'edit',
|
||||||
|
show: hasAccessByCodes(['infra:file-config:update']),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'delete',
|
||||||
|
show: hasAccessByCodes(['infra:file-config:delete']),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'master',
|
||||||
|
text: '主配置',
|
||||||
|
disabled: (row: any) => row.master,
|
||||||
|
show: (_row: any) => hasAccessByCodes(['infra:file-config:update']),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'test',
|
||||||
|
text: '测试',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,165 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { OnActionClickParams, VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
|
import type { InfraFileConfigApi } from '#/api/infra/file-config';
|
||||||
|
|
||||||
|
import { Page, useVbenModal } from '@vben/common-ui';
|
||||||
|
import { Button, message, Modal } from 'ant-design-vue';
|
||||||
|
import { Plus } from '@vben/icons';
|
||||||
|
import Form from './modules/form.vue';
|
||||||
|
|
||||||
|
import { $t } from '#/locales';
|
||||||
|
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||||
|
import { getFileConfigPage, deleteFileConfig, updateFileConfigMaster, testFileConfig } from '#/api/infra/file-config';
|
||||||
|
import { useGridColumns, useGridFormSchema } from './data';
|
||||||
|
|
||||||
|
const [FormModal, formModalApi] = useVbenModal({
|
||||||
|
connectedComponent: Form,
|
||||||
|
destroyOnClose: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 刷新表格 */
|
||||||
|
function onRefresh() {
|
||||||
|
gridApi.query();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 创建文件配置 */
|
||||||
|
function onCreate() {
|
||||||
|
formModalApi.setData(null).open();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 编辑文件配置 */
|
||||||
|
function onEdit(row: InfraFileConfigApi.InfraFileConfig) {
|
||||||
|
formModalApi.setData(row).open();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 设为主配置 */
|
||||||
|
async function onMaster(row: InfraFileConfigApi.InfraFileConfig) {
|
||||||
|
const hideLoading = message.loading({
|
||||||
|
content: $t('ui.actionMessage.updating', [row.name]),
|
||||||
|
duration: 0,
|
||||||
|
key: 'action_process_msg',
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await updateFileConfigMaster(row.id as number);
|
||||||
|
message.success({
|
||||||
|
content: $t('ui.actionMessage.operationSuccess'),
|
||||||
|
key: 'action_process_msg',
|
||||||
|
});
|
||||||
|
onRefresh();
|
||||||
|
} catch (error) {
|
||||||
|
hideLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 测试文件配置 */
|
||||||
|
async function onTest(row: InfraFileConfigApi.InfraFileConfig) {
|
||||||
|
const hideLoading = message.loading({
|
||||||
|
content: '测试上传中...',
|
||||||
|
duration: 0,
|
||||||
|
key: 'action_process_msg',
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
const response = await testFileConfig(row.id as number);
|
||||||
|
hideLoading();
|
||||||
|
// 确认是否访问该文件
|
||||||
|
Modal.confirm({
|
||||||
|
title: '测试上传成功',
|
||||||
|
content: '是否要访问该文件?',
|
||||||
|
okText: '访问',
|
||||||
|
cancelText: '取消',
|
||||||
|
onOk: () => {
|
||||||
|
window.open(response, '_blank');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
hideLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除文件配置 */
|
||||||
|
async function onDelete(row: InfraFileConfigApi.InfraFileConfig) {
|
||||||
|
const hideLoading = message.loading({
|
||||||
|
content: $t('ui.actionMessage.deleting', [row.name]),
|
||||||
|
duration: 0,
|
||||||
|
key: 'action_process_msg',
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await deleteFileConfig(row.id as number);
|
||||||
|
message.success({
|
||||||
|
content: $t('ui.actionMessage.deleteSuccess', [row.name]),
|
||||||
|
key: 'action_process_msg',
|
||||||
|
});
|
||||||
|
onRefresh();
|
||||||
|
} catch (error) {
|
||||||
|
hideLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 表格操作按钮的回调函数 */
|
||||||
|
function onActionClick({
|
||||||
|
code,
|
||||||
|
row,
|
||||||
|
}: OnActionClickParams<InfraFileConfigApi.InfraFileConfig>) {
|
||||||
|
switch (code) {
|
||||||
|
case 'edit': {
|
||||||
|
onEdit(row);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'master': {
|
||||||
|
onMaster(row);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'test': {
|
||||||
|
onTest(row);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'delete': {
|
||||||
|
onDelete(row);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
|
formOptions: {
|
||||||
|
schema: useGridFormSchema()
|
||||||
|
},
|
||||||
|
gridOptions: {
|
||||||
|
columns: useGridColumns(onActionClick),
|
||||||
|
height: 'auto',
|
||||||
|
keepSource: true,
|
||||||
|
proxyConfig: {
|
||||||
|
ajax: {
|
||||||
|
query: async ({ page }, formValues) => {
|
||||||
|
return await getFileConfigPage({
|
||||||
|
pageNo: page.currentPage,
|
||||||
|
pageSize: page.pageSize,
|
||||||
|
...formValues,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rowConfig: {
|
||||||
|
keyField: 'id',
|
||||||
|
},
|
||||||
|
toolbarConfig: {
|
||||||
|
refresh: { code: 'query' },
|
||||||
|
search: true,
|
||||||
|
},
|
||||||
|
} as VxeTableGridOptions<InfraFileConfigApi.InfraFileConfig>,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Page auto-content-height>
|
||||||
|
<FormModal @success="onRefresh" />
|
||||||
|
<Grid table-title="文件配置列表">
|
||||||
|
<template #toolbar-tools>
|
||||||
|
<Button type="primary" @click="onCreate" v-access:code="['infra:file-config:create']">
|
||||||
|
<Plus class="size-5" />
|
||||||
|
{{ $t('ui.actionTitle.create', ['文件配置']) }}
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
|
</template>
|
|
@ -0,0 +1,75 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { InfraFileConfigApi } from '#/api/infra/file-config';
|
||||||
|
|
||||||
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useVbenForm } from '#/adapter/form';
|
||||||
|
import { createFileConfig, updateFileConfig, getFileConfig } from '#/api/infra/file-config';
|
||||||
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
|
import { useFormSchema } from '../data';
|
||||||
|
|
||||||
|
const emit = defineEmits(['success']);
|
||||||
|
const formData = ref<InfraFileConfigApi.InfraFileConfig>();
|
||||||
|
const getTitle = computed(() => {
|
||||||
|
return formData.value?.id
|
||||||
|
? $t('ui.actionTitle.edit', ['文件配置'])
|
||||||
|
: $t('ui.actionTitle.create', ['文件配置']);
|
||||||
|
});
|
||||||
|
|
||||||
|
const [Form, formApi] = useVbenForm({
|
||||||
|
layout: 'horizontal',
|
||||||
|
schema: useFormSchema(),
|
||||||
|
showDefaultActions: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [Modal, modalApi] = useVbenModal({
|
||||||
|
async onConfirm() {
|
||||||
|
const { valid } = await formApi.validate();
|
||||||
|
if (!valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modalApi.lock();
|
||||||
|
// 提交表单
|
||||||
|
const data = (await formApi.getValues()) as InfraFileConfigApi.InfraFileConfig;
|
||||||
|
try {
|
||||||
|
await (formData.value?.id ? updateFileConfig(data) : createFileConfig(data));
|
||||||
|
// 关闭并提示
|
||||||
|
await modalApi.close();
|
||||||
|
emit('success');
|
||||||
|
message.success({
|
||||||
|
content: $t('ui.actionMessage.operationSuccess'),
|
||||||
|
key: 'action_process_msg',
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
modalApi.lock(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async onOpenChange(isOpen: boolean) {
|
||||||
|
if (!isOpen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 加载数据
|
||||||
|
const data = modalApi.getData<InfraFileConfigApi.InfraFileConfig>();
|
||||||
|
if (!data || !data.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modalApi.lock();
|
||||||
|
try {
|
||||||
|
formData.value = await getFileConfig(data.id as number);
|
||||||
|
// 设置到 values
|
||||||
|
await formApi.setValues(formData.value);
|
||||||
|
} finally {
|
||||||
|
modalApi.lock(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal :title="getTitle">
|
||||||
|
<Form class="mx-4" />
|
||||||
|
</Modal>
|
||||||
|
</template>
|
|
@ -13,7 +13,6 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
label: 'id',
|
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: [''],
|
triggerFields: [''],
|
||||||
|
|
|
@ -16,7 +16,6 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
label: 'id',
|
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: [''],
|
triggerFields: [''],
|
||||||
|
|
|
@ -13,7 +13,6 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
label: 'id',
|
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: [''],
|
triggerFields: [''],
|
||||||
|
|
|
@ -13,7 +13,6 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
label: 'id',
|
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: [''],
|
triggerFields: [''],
|
||||||
|
|
|
@ -14,7 +14,6 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
{
|
{
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
label: 'id',
|
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: [''],
|
triggerFields: [''],
|
||||||
show: () => false,
|
show: () => false,
|
||||||
|
|
|
@ -13,7 +13,6 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
label: 'id',
|
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: [''],
|
triggerFields: [''],
|
||||||
|
|
|
@ -20,7 +20,6 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
{
|
{
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
label: 'id',
|
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: [''],
|
triggerFields: [''],
|
||||||
show: () => false,
|
show: () => false,
|
||||||
|
@ -143,7 +142,6 @@ export function useResetPasswordFormSchema(): VbenFormSchema[] {
|
||||||
{
|
{
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
label: 'id',
|
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: [''],
|
triggerFields: [''],
|
||||||
show: () => false,
|
show: () => false,
|
||||||
|
@ -185,7 +183,6 @@ export function useAssignRoleFormSchema(): VbenFormSchema[] {
|
||||||
{
|
{
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
label: 'id',
|
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: [''],
|
triggerFields: [''],
|
||||||
show: () => false,
|
show: () => false,
|
||||||
|
|
|
@ -25,7 +25,8 @@
|
||||||
"operationFailed": "Operation failed",
|
"operationFailed": "Operation failed",
|
||||||
"importSuccess": "Import succeeded",
|
"importSuccess": "Import succeeded",
|
||||||
"importFail": "Import failed",
|
"importFail": "Import failed",
|
||||||
"downloadTemplateFail": "Download template failed"
|
"downloadTemplateFail": "Download template failed",
|
||||||
|
"updating": "Updating {0}..."
|
||||||
},
|
},
|
||||||
"placeholder": {
|
"placeholder": {
|
||||||
"input": "Please enter",
|
"input": "Please enter",
|
||||||
|
|
|
@ -25,7 +25,8 @@
|
||||||
"operationFailed": "操作失败",
|
"operationFailed": "操作失败",
|
||||||
"importSuccess": "导入成功",
|
"importSuccess": "导入成功",
|
||||||
"importFail": "导入失败",
|
"importFail": "导入失败",
|
||||||
"downloadTemplateFail": "下载模板失败"
|
"downloadTemplateFail": "下载模板失败",
|
||||||
|
"updating": "正在更新 {0}..."
|
||||||
},
|
},
|
||||||
"placeholder": {
|
"placeholder": {
|
||||||
"input": "请输入",
|
"input": "请输入",
|
||||||
|
|
Loading…
Reference in New Issue