11 changed files with 1238 additions and 1 deletions
@ -0,0 +1,60 @@ |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
import { applyTempToken } from '@/utils/auth'; |
|||
|
|||
enum Api { |
|||
list = 'smart/file/list', |
|||
getById = 'smart/file/getById', |
|||
delete = 'smart/file/batchDeleteFile', |
|||
uploadFile = 'smart/file/upload', |
|||
download = '/public/file/download/', |
|||
} |
|||
|
|||
export const listApi = (params) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_FILE, |
|||
url: Api.list, |
|||
data: { |
|||
...params, |
|||
}, |
|||
}); |
|||
}; |
|||
|
|||
export const uploadFileApi = (data, file: File) => { |
|||
return defHttp.uploadFile( |
|||
{ |
|||
service: ApiServiceEnum.SMART_FILE, |
|||
url: Api.uploadFile, |
|||
}, |
|||
{ |
|||
data: data, |
|||
file: { |
|||
file: file, |
|||
}, |
|||
}, |
|||
); |
|||
}; |
|||
|
|||
export const deleteApi = (removeRecords: Recordable[]) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_FILE, |
|||
url: Api.delete, |
|||
data: removeRecords.map((item) => item.fileId), |
|||
}); |
|||
}; |
|||
|
|||
export const getByIdApi = (model: Recordable) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_FILE, |
|||
url: Api.getById, |
|||
data: model.fileId, |
|||
}); |
|||
}; |
|||
|
|||
export const downloadApi = async (id) => { |
|||
let url = `${defHttp.getApiUrlByService(ApiServiceEnum.SMART_FILE)}/${Api.download}${id}`; |
|||
|
|||
// 申请临时token
|
|||
const tempToken = await applyTempToken('smart:file:download'); |
|||
url = url + '?access-token=' + tempToken; |
|||
window.open(url); |
|||
}; |
|||
@ -0,0 +1,180 @@ |
|||
import type { SmartColumn, SmartSearchFormSchema } from '@/components/SmartTable'; |
|||
import type { FormSchema } from '@/components/Form'; |
|||
|
|||
/** |
|||
* 表格列表 |
|||
*/ |
|||
export const getTableColumns = (): SmartColumn[] => { |
|||
return [ |
|||
{ |
|||
type: 'checkbox', |
|||
width: 60, |
|||
align: 'center', |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
field: 'fileId', |
|||
visible: false, |
|||
title: '{system.views.file.title.fileId}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'fileStorageId', |
|||
title: '{system.views.file.title.fileStorageId}', |
|||
width: 160, |
|||
fixed: 'left', |
|||
formatter: ({ row }) => { |
|||
return row.fileStorage?.storageName; |
|||
}, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
field: 'filename', |
|||
title: '{system.views.file.title.fileName}', |
|||
width: 160, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
field: 'type', |
|||
title: '{system.views.file.title.type}', |
|||
width: 120, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
field: 'contentType', |
|||
title: '{system.views.file.title.contentType}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'fileSize', |
|||
title: '{system.views.file.title.fileSize}', |
|||
width: 120, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
field: 'seq', |
|||
title: '{common.table.seq}', |
|||
width: 120, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
field: 'createTime', |
|||
title: '{common.table.createTime}', |
|||
width: 160, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
field: 'createBy', |
|||
title: '{common.table.createUser}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{common.table.operation}', |
|||
field: 'operation', |
|||
width: 120, |
|||
fixed: 'right', |
|||
slots: { |
|||
default: 'table-operation', |
|||
}, |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
/** |
|||
* 添加修改表单 |
|||
*/ |
|||
export const getFormSchemas = (t: Function): FormSchema[] => { |
|||
return [ |
|||
{ |
|||
field: 'fileId', |
|||
show: false, |
|||
label: t('system.views.file.title.fileId'), |
|||
component: 'Input', |
|||
componentProps: {}, |
|||
}, |
|||
{ |
|||
field: 'fileStorageId', |
|||
label: t('system.views.file.title.fileStorageId'), |
|||
component: 'SmartApiSelectTable', |
|||
componentProps: { |
|||
modelClassName: 'com.smart.file.manager.model.SmartFileStoragePO', |
|||
valueFieldName: 'id', |
|||
labelFieldName: 'storageName', |
|||
params: { |
|||
sortName: 'seq', |
|||
parameter: { |
|||
'deleteYn@<>': true, |
|||
'useYn@=': true, |
|||
}, |
|||
}, |
|||
}, |
|||
required: true, |
|||
}, |
|||
{ |
|||
field: 'fileName', |
|||
label: t('system.views.file.title.fileName'), |
|||
component: 'Input', |
|||
componentProps: {}, |
|||
}, |
|||
{ |
|||
field: 'type', |
|||
label: t('system.views.file.title.type'), |
|||
component: 'SmartApiSelectDict', |
|||
componentProps: { |
|||
dictCode: 'FILE_TYPE', |
|||
}, |
|||
}, |
|||
{ |
|||
field: 'seq', |
|||
label: t('common.table.seq'), |
|||
component: 'InputNumber', |
|||
defaultValue: 1, |
|||
componentProps: {}, |
|||
required: true, |
|||
}, |
|||
{ |
|||
field: 'fileList', |
|||
label: '文件', |
|||
slot: 'form-upload', |
|||
required: true, |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
export const getSearchFormSchemas = (t: Function): SmartSearchFormSchema[] => { |
|||
return [ |
|||
{ |
|||
field: 'fileName', |
|||
label: t('system.views.file.title.fileName'), |
|||
component: 'Input', |
|||
searchSymbol: '=', |
|||
}, |
|||
{ |
|||
field: 'type', |
|||
label: t('system.views.file.title.type'), |
|||
component: 'Input', |
|||
searchSymbol: '=', |
|||
}, |
|||
{ |
|||
field: 'fileStorageId', |
|||
label: t('system.views.file.title.fileStorageId'), |
|||
component: 'SmartApiSelectTable', |
|||
componentProps: { |
|||
style: { |
|||
width: '150px', |
|||
}, |
|||
modelClassName: 'com.smart.file.manager.model.SmartFileStoragePO', |
|||
valueFieldName: 'id', |
|||
labelFieldName: 'storageName', |
|||
params: { |
|||
sortName: 'seq', |
|||
parameter: { |
|||
'deleteYn@<>': true, |
|||
'useYn@=': true, |
|||
}, |
|||
}, |
|||
}, |
|||
searchSymbol: '=', |
|||
}, |
|||
]; |
|||
}; |
|||
@ -0,0 +1,134 @@ |
|||
<template> |
|||
<div class="full-height page-container"> |
|||
<SmartTable @register="registerTable" :size="getTableSize"> |
|||
<template #table-operation="{ row }"> |
|||
<SmartVxeTableAction :actions="getActions(row)" /> |
|||
</template> |
|||
<template #form-upload="{ model }"> |
|||
<Upload v-model:fileList="model.fileList" :max-count="1" :beforeUpload="() => false"> |
|||
<a-button>Upload</a-button> |
|||
</Upload> |
|||
</template> |
|||
</SmartTable> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
import { Upload } from 'ant-design-vue'; |
|||
|
|||
import { |
|||
ActionItem, |
|||
SmartTable, |
|||
SmartVxeTableAction, |
|||
useSmartTable, |
|||
} from '@/components/SmartTable'; |
|||
|
|||
import { |
|||
getTableColumns, |
|||
getFormSchemas, |
|||
getSearchFormSchemas, |
|||
} from './SmartFileListView.config'; |
|||
import { |
|||
listApi, |
|||
deleteApi, |
|||
getByIdApi, |
|||
uploadFileApi, |
|||
downloadApi, |
|||
} from './SmartFileListView.api'; |
|||
|
|||
const { t } = useI18n(); |
|||
const { getTableSize } = useSizeSetting(); |
|||
|
|||
const getActions = (row: Recordable): ActionItem[] => { |
|||
return [ |
|||
{ |
|||
label: t('common.button.delete'), |
|||
onClick: () => deleteByRow(row), |
|||
danger: true, |
|||
}, |
|||
{ |
|||
label: t('common.button.download'), |
|||
preIcon: 'ant-design:download-outlined', |
|||
auth: 'smart:file:download', |
|||
onClick: async () => { |
|||
await downloadApi(row.fileId); |
|||
}, |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
const [registerTable, { deleteByRow }] = useSmartTable({ |
|||
id: 'smart-file-fileList', |
|||
columns: getTableColumns(), |
|||
height: 'auto', |
|||
border: true, |
|||
pagerConfig: true, |
|||
useSearchForm: true, |
|||
rowConfig: { |
|||
keyField: 'fileId', |
|||
isCurrent: true, |
|||
}, |
|||
customConfig: { |
|||
storage: true, |
|||
}, |
|||
columnConfig: { |
|||
resizable: true, |
|||
}, |
|||
searchFormConfig: { |
|||
schemas: getSearchFormSchemas(t), |
|||
searchWithSymbol: true, |
|||
colon: true, |
|||
layout: 'inline', |
|||
actionColOptions: { |
|||
span: undefined, |
|||
}, |
|||
compact: true, |
|||
}, |
|||
addEditConfig: { |
|||
formConfig: { |
|||
schemas: getFormSchemas(t), |
|||
baseColProps: { span: 24 }, |
|||
labelCol: { span: 6 }, |
|||
wrapperCol: { span: 17 }, |
|||
}, |
|||
}, |
|||
proxyConfig: { |
|||
ajax: { |
|||
query: (params) => listApi(params.ajaxParameter), |
|||
save: ({ body: { insertRecords } }) => { |
|||
const dataList = [...insertRecords]; |
|||
if (dataList.length === 0) { |
|||
return Promise.resolve(); |
|||
} |
|||
const { fileStorageId, fileName, type, seq, fileList } = dataList[0]; |
|||
return uploadFileApi( |
|||
{ |
|||
fileStorageId, |
|||
fileName, |
|||
type, |
|||
seq, |
|||
}, |
|||
fileList[0].originFileObj, |
|||
); |
|||
}, |
|||
delete: ({ body: { removeRecords } }) => deleteApi(removeRecords), |
|||
getById: (params) => getByIdApi(params.id), |
|||
}, |
|||
}, |
|||
toolbarConfig: { |
|||
zoom: true, |
|||
refresh: true, |
|||
column: { columnOrder: true }, |
|||
buttons: [ |
|||
{ |
|||
code: 'ModalAdd', |
|||
}, |
|||
{ |
|||
code: 'delete', |
|||
}, |
|||
], |
|||
}, |
|||
}); |
|||
</script> |
|||
@ -0,0 +1,29 @@ |
|||
/** |
|||
* 文件表 国际化信息 |
|||
*/ |
|||
export default { |
|||
trans: true, |
|||
key: 'system.views.file', |
|||
data: { |
|||
title: { |
|||
fileId: '文件ID', |
|||
fileStorageId: '文件存储器', |
|||
fileName: '文件名', |
|||
type: '类型', |
|||
contentType: '文件类型', |
|||
fileSize: '文件大小', |
|||
}, |
|||
validate: { |
|||
fileId: '请输入文件ID', |
|||
fileStorageId: '请输入文件存储器', |
|||
fileName: '请输入文件名', |
|||
type: '请输入类型', |
|||
}, |
|||
rules: {}, |
|||
search: { |
|||
fileName: '请输入文件名', |
|||
type: '请输入类型', |
|||
fileStorageId: '请输入文件存储器', |
|||
}, |
|||
}, |
|||
}; |
|||
@ -0,0 +1,29 @@ |
|||
/** |
|||
* 文件表 国际化信息 |
|||
*/ |
|||
export default { |
|||
trans: true, |
|||
key: 'system.views.file', |
|||
data: { |
|||
title: { |
|||
fileId: '文件ID', |
|||
fileStorageId: '文件存储器', |
|||
fileName: '文件名', |
|||
type: '类型', |
|||
contentType: '文件类型', |
|||
fileSize: '文件大小', |
|||
}, |
|||
validate: { |
|||
fileId: '请输入文件ID', |
|||
fileStorageId: '请输入文件存储器', |
|||
fileName: '请输入文件名', |
|||
type: '请输入类型', |
|||
}, |
|||
rules: {}, |
|||
search: { |
|||
fileName: '请输入文件名', |
|||
type: '请输入类型', |
|||
fileStorageId: '请输入文件存储器', |
|||
}, |
|||
}, |
|||
}; |
|||
@ -0,0 +1,53 @@ |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
enum Api { |
|||
list = '/smart/fileStorage/list', |
|||
getById = '/smart/fileStorage/getById', |
|||
batchSaveUpdate = '/smart/fileStorage/saveUpdateBatch', |
|||
delete = '/smart/fileStorage/batchDeleteById', |
|||
setDefault = '/smart/fileStorage/setDefault', |
|||
} |
|||
|
|||
export const listApi = (params) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_FILE, |
|||
url: Api.list, |
|||
data: { |
|||
...params, |
|||
}, |
|||
}); |
|||
}; |
|||
|
|||
export const batchSaveUpdateApi = (modelList: any[]) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_FILE, |
|||
url: Api.batchSaveUpdate, |
|||
data: modelList, |
|||
}); |
|||
}; |
|||
|
|||
export const deleteApi = (removeRecords: Recordable[]) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_FILE, |
|||
url: Api.delete, |
|||
data: removeRecords.map((item) => item.id), |
|||
}); |
|||
}; |
|||
|
|||
export const getByIdApi = (model: Recordable) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_FILE, |
|||
url: Api.getById, |
|||
data: model.id, |
|||
}); |
|||
}; |
|||
|
|||
export const setDefaultApi = (id) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_FILE, |
|||
url: Api.setDefault, |
|||
data: { |
|||
id, |
|||
}, |
|||
}); |
|||
}; |
|||
@ -0,0 +1,459 @@ |
|||
import type { SmartColumn, SmartSearchFormSchema } from '@/components/SmartTable'; |
|||
import type { FormSchema } from '@/components/Form'; |
|||
|
|||
/** |
|||
* 表格列表 |
|||
*/ |
|||
export const getTableColumns = (): SmartColumn[] => { |
|||
return [ |
|||
{ |
|||
type: 'checkbox', |
|||
width: 60, |
|||
align: 'center', |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
field: 'id', |
|||
visible: false, |
|||
title: '{smart.file.storage.title.id}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'storageCode', |
|||
title: '{smart.file.storage.title.storageCode}', |
|||
width: 160, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
field: 'storageName', |
|||
title: '{smart.file.storage.title.storageName}', |
|||
width: 160, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
field: 'storageType', |
|||
sortable: true, |
|||
title: '{smart.file.storage.title.storageType}', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-storageType', |
|||
}, |
|||
}, |
|||
{ |
|||
field: 'seq', |
|||
sortable: true, |
|||
title: '{common.table.seq}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'remark', |
|||
title: '{common.table.remark}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'defaultStorage', |
|||
title: '{smart.file.storage.title.defaultStorage}', |
|||
width: 140, |
|||
component: 'switch', |
|||
componentProps: { |
|||
disabled: true, |
|||
}, |
|||
}, |
|||
// {
|
|||
// field: 'storageConfig',
|
|||
// title: '{smart.file.storage.title.storageConfig}',
|
|||
// width: 120,
|
|||
// },
|
|||
{ |
|||
field: 'createTime', |
|||
title: '{common.table.createTime}', |
|||
width: 160, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
field: 'createBy', |
|||
title: '{common.table.createUser}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'updateTime', |
|||
title: '{common.table.updateTime}', |
|||
width: 160, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
field: 'updateBy', |
|||
title: '{common.table.updateUser}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{common.table.useYn}', |
|||
field: 'useYn', |
|||
width: 100, |
|||
component: 'booleanTag', |
|||
}, |
|||
{ |
|||
title: '{common.table.operation}', |
|||
field: 'operation', |
|||
width: 150, |
|||
fixed: 'right', |
|||
slots: { |
|||
default: 'table-operation', |
|||
}, |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
/** |
|||
* 添加修改表单 |
|||
*/ |
|||
export const getFormSchemas = (t: Function): FormSchema[] => { |
|||
return [ |
|||
{ |
|||
field: 'id', |
|||
show: false, |
|||
label: t('smart.file.storage.title.id'), |
|||
component: 'Input', |
|||
componentProps: {}, |
|||
}, |
|||
{ |
|||
field: 'storageCode', |
|||
label: t('smart.file.storage.title.storageCode'), |
|||
component: 'Input', |
|||
componentProps: {}, |
|||
required: true, |
|||
}, |
|||
{ |
|||
field: 'storageName', |
|||
label: t('smart.file.storage.title.storageName'), |
|||
component: 'Input', |
|||
componentProps: {}, |
|||
required: true, |
|||
}, |
|||
// {
|
|||
// field: 'defaultStorage',
|
|||
// label: t('smart.file.storage.title.defaultStorage'),
|
|||
// component: 'Switch',
|
|||
// componentProps: {},
|
|||
// colProps: {
|
|||
// span: 12,
|
|||
// },
|
|||
// },
|
|||
{ |
|||
field: 'useYn', |
|||
label: t('common.table.useYn'), |
|||
component: 'Switch', |
|||
componentProps: {}, |
|||
defaultValue: true, |
|||
}, |
|||
{ |
|||
field: 'seq', |
|||
label: t('common.table.seq'), |
|||
component: 'InputNumber', |
|||
componentProps: {}, |
|||
required: true, |
|||
defaultValue: 1, |
|||
}, |
|||
{ |
|||
field: 'remark', |
|||
label: t('common.table.remark'), |
|||
component: 'InputTextArea', |
|||
componentProps: {}, |
|||
}, |
|||
{ |
|||
field: 'storageType', |
|||
label: t('smart.file.storage.title.storageType'), |
|||
component: 'SmartApiSelectDict', |
|||
componentProps: { |
|||
dictCode: 'FILE_STORAGE_TYPE', |
|||
}, |
|||
required: true, |
|||
}, |
|||
// --------------自定义配置信息
|
|||
// 磁盘存储配置
|
|||
{ |
|||
field: 'storageConfig.DISK.basePath', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.basePath'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'DISK'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'DISK', |
|||
}, |
|||
// ---------- minio配置
|
|||
{ |
|||
field: 'storageConfig.MINIO.endpoint', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.endpoint'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'MINIO'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'MINIO', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.MINIO.accessKey', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.accessKey'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'MINIO'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'MINIO', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.MINIO.secretKey', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.secretKey'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'MINIO'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'MINIO', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.MINIO.bucketName', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.bucketName'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'MINIO'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'MINIO', |
|||
}, |
|||
// ------------- sftp
|
|||
{ |
|||
field: 'storageConfig.SFTP.host', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.host'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'SFTP'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'SFTP', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.SFTP.port', |
|||
component: 'InputNumber', |
|||
label: t('smart.file.storage.title.port'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'SFTP'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'SFTP', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.SFTP.basePath', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.basePath'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'SFTP'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'SFTP', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.SFTP.username', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.username'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'SFTP'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'SFTP', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.SFTP.password', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.password'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'SFTP'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'SFTP', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.SFTP.privateKey', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.privateKey'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'SFTP'; |
|||
}, |
|||
}, |
|||
// --------------- 阿里云OSS
|
|||
...getAliyunOssFormSchemas(t), |
|||
// --------------- 七牛云
|
|||
...getQiniuFormSchemas(t), |
|||
...getFtpFormSchemas(t), |
|||
]; |
|||
}; |
|||
|
|||
export const getSearchFormSchemas = (t: Function): SmartSearchFormSchema[] => { |
|||
return [ |
|||
{ |
|||
field: 'storageCode', |
|||
label: t('smart.file.storage.title.storageCode'), |
|||
component: 'Input', |
|||
searchSymbol: 'like', |
|||
}, |
|||
{ |
|||
field: 'storageName', |
|||
label: t('smart.file.storage.title.storageName'), |
|||
component: 'Input', |
|||
searchSymbol: 'like', |
|||
}, |
|||
{ |
|||
field: 'storageType', |
|||
label: t('smart.file.storage.title.storageType'), |
|||
component: 'SmartApiSelectDict', |
|||
componentProps: { |
|||
dictCode: 'FILE_STORAGE_TYPE', |
|||
style: { width: '140px' }, |
|||
}, |
|||
searchSymbol: '=', |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
/** |
|||
* 获取阿里云OSS表单配置 |
|||
* @param t |
|||
*/ |
|||
const getAliyunOssFormSchemas = (t: Function): FormSchema[] => { |
|||
return [ |
|||
{ |
|||
field: 'storageConfig.ALIYUN_OSS.endpoint', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.endpoint'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'ALIYUN_OSS'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'ALIYUN_OSS', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.ALIYUN_OSS.accessKey', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.accessKey'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'ALIYUN_OSS'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'ALIYUN_OSS', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.ALIYUN_OSS.secretKey', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.secretKey'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'ALIYUN_OSS'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'ALIYUN_OSS', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.ALIYUN_OSS.bucketName', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.bucketName'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'ALIYUN_OSS'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'ALIYUN_OSS', |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
const getQiniuFormSchemas = (t: Function): FormSchema[] => { |
|||
return [ |
|||
{ |
|||
field: 'storageConfig.QINIU.accessKey', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.accessKey'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'QINIU'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'QINIU', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.QINIU.secretKey', |
|||
component: 'InputPassword', |
|||
label: t('smart.file.storage.title.secretKey'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'QINIU'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'QINIU', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.QINIU.bucketName', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.bucketName'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'QINIU'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'QINIU', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.QINIU.region', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.region'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'QINIU'; |
|||
}, |
|||
}, |
|||
{ |
|||
field: 'storageConfig.QINIU.url', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.url'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'QINIU'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'QINIU', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.QINIU.useHttps', |
|||
component: 'Switch', |
|||
label: t('smart.file.storage.title.useHttps'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'QINIU'; |
|||
}, |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
const getFtpFormSchemas = (t: Function): FormSchema[] => { |
|||
return [ |
|||
{ |
|||
field: 'storageConfig.FTP.host', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.host'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'FTP'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'FTP', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.FTP.port', |
|||
component: 'InputNumber', |
|||
label: t('smart.file.storage.title.port'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'FTP'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'FTP', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.FTP.basePath', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.basePath'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'FTP'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'FTP', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.FTP.username', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.username'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'FTP'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'FTP', |
|||
}, |
|||
{ |
|||
field: 'storageConfig.FTP.password', |
|||
component: 'Input', |
|||
label: t('smart.file.storage.title.password'), |
|||
show: ({ model }) => { |
|||
return model.storageType === 'FTP'; |
|||
}, |
|||
required: ({ model }) => model.storageType === 'FTP', |
|||
}, |
|||
]; |
|||
}; |
|||
@ -0,0 +1,193 @@ |
|||
<template> |
|||
<div class="full-height page-container"> |
|||
<SmartTable @register="registerTable" :size="getTableSize"> |
|||
<template #table-operation="{ row }"> |
|||
<SmartVxeTableAction |
|||
:actions="getActions(row)" |
|||
:drop-down-actions="getDropDownActions(row)" |
|||
/> |
|||
</template> |
|||
<template #table-storageType="{ row }"> |
|||
<span>{{ getDictItemMap[row.storageType] }}</span> |
|||
</template> |
|||
</SmartTable> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
import { replace } from 'lodash-es'; |
|||
import { Modal } from 'ant-design-vue'; |
|||
import { hasPermission } from '@/utils/auth'; |
|||
|
|||
import { |
|||
ActionItem, |
|||
SmartTable, |
|||
SmartVxeTableAction, |
|||
useSmartTable, |
|||
} from '@/components/SmartTable'; |
|||
import { useLoadDictItem } from '@/modules/system/hooks/SysDictHooks'; |
|||
|
|||
import { |
|||
getTableColumns, |
|||
getFormSchemas, |
|||
getSearchFormSchemas, |
|||
} from './SmartFileStorageListView.config'; |
|||
import { |
|||
listApi, |
|||
deleteApi, |
|||
getByIdApi, |
|||
batchSaveUpdateApi, |
|||
setDefaultApi, |
|||
} from './SmartFileStorageListView.api'; |
|||
import { createVNode } from 'vue'; |
|||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'; |
|||
|
|||
const { t } = useI18n(); |
|||
const { getTableSize } = useSizeSetting(); |
|||
|
|||
const storageConfigPrefix = 'storageConfig'; |
|||
const { getDictItemMap } = useLoadDictItem('FILE_STORAGE_TYPE'); |
|||
|
|||
const getActions = (row: Recordable): ActionItem[] => { |
|||
return [ |
|||
{ |
|||
label: t('common.button.edit'), |
|||
auth: 'smart:fileStorage:edit', |
|||
onClick: () => editByRowModal(row), |
|||
}, |
|||
{ |
|||
label: t('common.button.delete'), |
|||
onClick: () => deleteByRow(row), |
|||
auth: 'smart:fileStorage:delete', |
|||
danger: true, |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
const getDropDownActions = (row: Recordable): ActionItem[] => { |
|||
return [ |
|||
{ |
|||
label: t('smart.file.storage.button.setDefault'), |
|||
preIcon: 'ant-design:check-outlined', |
|||
disabled: row.defaultStorage === true, |
|||
auth: 'smart:fileStorage:setDefault', |
|||
onClick: () => { |
|||
Modal.confirm({ |
|||
title: t('common.notice.confirm'), |
|||
icon: createVNode(ExclamationCircleOutlined), |
|||
content: t('smart.file.storage.message.setDefault'), |
|||
onOk: async () => { |
|||
await setDefaultApi(row.id); |
|||
query(); |
|||
}, |
|||
}); |
|||
}, |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
const [registerTable, { editByRowModal, deleteByRow, query }] = useSmartTable({ |
|||
columns: getTableColumns(), |
|||
height: 'auto', |
|||
pagerConfig: true, |
|||
useSearchForm: true, |
|||
searchFormConfig: { |
|||
schemas: getSearchFormSchemas(t), |
|||
searchWithSymbol: true, |
|||
colon: true, |
|||
compact: true, |
|||
layout: 'inline', |
|||
actionColOptions: { |
|||
span: undefined, |
|||
}, |
|||
}, |
|||
addEditConfig: { |
|||
modalConfig: { |
|||
// width: '800px', |
|||
height: 800, |
|||
}, |
|||
formConfig: { |
|||
colon: true, |
|||
schemas: getFormSchemas(t), |
|||
baseColProps: { span: 24 }, |
|||
labelCol: { style: { width: '120px' } }, |
|||
wrapperCol: { span: 17 }, |
|||
}, |
|||
}, |
|||
sortConfig: { |
|||
remote: true, |
|||
}, |
|||
columnConfig: { |
|||
resizable: true, |
|||
}, |
|||
border: true, |
|||
proxyConfig: { |
|||
ajax: { |
|||
query: ({ ajaxParameter }) => { |
|||
const params = { |
|||
sortName: 'seq', |
|||
...ajaxParameter, |
|||
}; |
|||
return listApi(params); |
|||
}, |
|||
save: ({ body: { insertRecords, updateRecords } }) => { |
|||
const saveDatList = [...insertRecords, ...updateRecords]; |
|||
const formatDataList = saveDatList.map((item) => { |
|||
const result: any = {}; |
|||
const storageConfig: Recordable = {}; |
|||
const configKeyPrefix = storageConfigPrefix + '.' + item.storageType + '.'; |
|||
Object.keys(item).forEach((key) => { |
|||
if (!key.startsWith(storageConfigPrefix)) { |
|||
result[key] = item[key]; |
|||
} else if (key.startsWith(configKeyPrefix)) { |
|||
storageConfig[replace(key, configKeyPrefix, '')] = item[key]; |
|||
} |
|||
}); |
|||
result.storageConfig = JSON.stringify(storageConfig); |
|||
return result; |
|||
}); |
|||
return batchSaveUpdateApi(formatDataList); |
|||
}, |
|||
delete: ({ body: { removeRecords } }) => deleteApi(removeRecords), |
|||
getById: async (params) => { |
|||
const result = await getByIdApi(params); |
|||
if (result.storageConfig) { |
|||
const storageConfig = JSON.parse(result.storageConfig); |
|||
const storageType = result.storageType; |
|||
const formatData: Recordable = {}; |
|||
Object.keys(storageConfig).forEach((item) => { |
|||
formatData[`${storageConfigPrefix}.${storageType}.${item}`] = storageConfig[item]; |
|||
}); |
|||
return { |
|||
...result, |
|||
...formatData, |
|||
}; |
|||
} |
|||
return result; |
|||
}, |
|||
}, |
|||
}, |
|||
authConfig: { |
|||
authHandler: hasPermission, |
|||
toolbar: { |
|||
ModalAdd: 'smart:fileStorage:save', |
|||
delete: 'smart:fileStorage:delete', |
|||
}, |
|||
}, |
|||
toolbarConfig: { |
|||
zoom: true, |
|||
refresh: true, |
|||
column: { columnOrder: true }, |
|||
buttons: [ |
|||
{ |
|||
code: 'ModalAdd', |
|||
}, |
|||
{ |
|||
code: 'delete', |
|||
}, |
|||
], |
|||
}, |
|||
}); |
|||
</script> |
|||
@ -0,0 +1,50 @@ |
|||
/** |
|||
* 文件存储器配置 国际化信息 |
|||
*/ |
|||
export default { |
|||
trans: true, |
|||
key: 'smart.file.storage', |
|||
data: { |
|||
title: { |
|||
id: 'id', |
|||
storageCode: 'Storage code', |
|||
storageName: 'Storage name', |
|||
storageType: 'Storage type', |
|||
defaultStorage: 'Default', |
|||
storageConfig: 'config', |
|||
basePath: 'Bash path', |
|||
endpoint: 'End point', |
|||
accessKey: 'Access key', |
|||
secretKey: 'Secret key', |
|||
bucketName: 'Bucket name', |
|||
host: 'Host', |
|||
port: 'Port', |
|||
username: 'Username', |
|||
password: 'Password', |
|||
privateKey: 'Private key', |
|||
region: 'Region', |
|||
url: 'URL', |
|||
useHttps: 'Use https', |
|||
}, |
|||
validate: { |
|||
storageCode: 'Please enter storage code', |
|||
storageName: 'Please enter storage name', |
|||
storageType: 'Please select storage type', |
|||
defaultStorage: 'Please enter storage default', |
|||
storageConfig: 'Please enter storage config', |
|||
}, |
|||
message: { |
|||
setDefault: |
|||
'Only one default memory can be set. Are you sure you want to set it as the default memory?', |
|||
}, |
|||
rules: {}, |
|||
search: { |
|||
storageCode: 'Please enter storage code', |
|||
storageName: 'Please enter storage name', |
|||
storageType: 'Please select storage type', |
|||
}, |
|||
button: { |
|||
setDefault: 'Set default', |
|||
}, |
|||
}, |
|||
}; |
|||
@ -0,0 +1,49 @@ |
|||
/** |
|||
* 文件存储器配置 国际化信息 |
|||
*/ |
|||
export default { |
|||
trans: true, |
|||
key: 'smart.file.storage', |
|||
data: { |
|||
title: { |
|||
id: 'id', |
|||
storageCode: '存储器编码', |
|||
storageName: '存储器名称', |
|||
storageType: '存储器类型', |
|||
defaultStorage: '默认存储器', |
|||
storageConfig: '存储器配置信息', |
|||
basePath: '基础路径', |
|||
endpoint: 'Endpoint', |
|||
accessKey: 'AccessKey', |
|||
secretKey: 'SecretKey', |
|||
bucketName: 'BucketName', |
|||
host: '主机地址', |
|||
port: '端口', |
|||
username: '用户名', |
|||
password: '密码', |
|||
privateKey: '私钥', |
|||
region: '区域', |
|||
url: 'URL', |
|||
useHttps: '启用https', |
|||
}, |
|||
validate: { |
|||
storageCode: '请输入存储器编码', |
|||
storageName: '请输入存储器名称', |
|||
storageType: '请输入存储器类型', |
|||
defaultStorage: '请输入是否是默认存储器', |
|||
storageConfig: '请输入存储器配置信息', |
|||
}, |
|||
message: { |
|||
setDefault: '只能设置一个默认存储器,确定要设为默认存储器吗?', |
|||
}, |
|||
rules: {}, |
|||
search: { |
|||
storageCode: '请输入存储器编码', |
|||
storageName: '请输入存储器名称', |
|||
storageType: '请输入存储器类型', |
|||
}, |
|||
button: { |
|||
setDefault: '设为默认', |
|||
}, |
|||
}, |
|||
}; |
|||
Loading…
Reference in new issue