diff --git a/apps/web-antd/src/api/infra/file-config/index.ts b/apps/web-antd/src/api/infra/file-config/index.ts new file mode 100644 index 000000000..d5992d3f0 --- /dev/null +++ b/apps/web-antd/src/api/infra/file-config/index.ts @@ -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>('/infra/file-config/page', { + params + }); +} + +/** 查询文件配置详情 */ +export function getFileConfig(id: number) { + return requestClient.get(`/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}`); +} diff --git a/apps/web-antd/src/api/infra/file/index.ts b/apps/web-antd/src/api/infra/file/index.ts new file mode 100644 index 000000000..577b2000d --- /dev/null +++ b/apps/web-antd/src/api/infra/file/index.ts @@ -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>('/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('/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); +} diff --git a/apps/web-antd/src/views/infra/apiErrorLog/index.vue b/apps/web-antd/src/views/infra/apiErrorLog/index.vue index b996e0608..ea390b4c1 100644 --- a/apps/web-antd/src/views/infra/apiErrorLog/index.vue +++ b/apps/web-antd/src/views/infra/apiErrorLog/index.vue @@ -3,7 +3,7 @@ import type { OnActionClickParams, VxeTableGridOptions } from '#/adapter/vxe-tab import type { InfraApiErrorLogApi } from '#/api/infra/api-error-log'; 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 Detail from './modules/detail.vue'; import { DocAlert } from '#/components/doc-alert'; diff --git a/apps/web-antd/src/views/infra/config/data.ts b/apps/web-antd/src/views/infra/config/data.ts index b54d02afe..2a53dfe5f 100644 --- a/apps/web-antd/src/views/infra/config/data.ts +++ b/apps/web-antd/src/views/infra/config/data.ts @@ -14,7 +14,6 @@ export function useFormSchema(): VbenFormSchema[] { { component: 'Input', fieldName: 'id', - label: 'id', dependencies: { triggerFields: [''], show: () => false, diff --git a/apps/web-antd/src/views/infra/file/data.ts b/apps/web-antd/src/views/infra/file/data.ts new file mode 100644 index 000000000..cff729781 --- /dev/null +++ b/apps/web-antd/src/views/infra/file/data.ts @@ -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( + onActionClick: OnActionClickFn, +): 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']), + }, + ], + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/infra/file/index.vue b/apps/web-antd/src/views/infra/file/index.vue new file mode 100644 index 000000000..8491ce700 --- /dev/null +++ b/apps/web-antd/src/views/infra/file/index.vue @@ -0,0 +1,137 @@ + + + diff --git a/apps/web-antd/src/views/infra/file/modules/form.vue b/apps/web-antd/src/views/infra/file/modules/form.vue new file mode 100644 index 000000000..78d9ca6b9 --- /dev/null +++ b/apps/web-antd/src/views/infra/file/modules/form.vue @@ -0,0 +1,96 @@ + + + diff --git a/apps/web-antd/src/views/infra/fileConfig/data.ts b/apps/web-antd/src/views/infra/fileConfig/data.ts new file mode 100644 index 000000000..35131835c --- /dev/null +++ b/apps/web-antd/src/views/infra/fileConfig/data.ts @@ -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( + onActionClick: OnActionClickFn, +): 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: '测试', + }, + ], + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/infra/fileConfig/index.vue b/apps/web-antd/src/views/infra/fileConfig/index.vue new file mode 100644 index 000000000..d52ee8dc9 --- /dev/null +++ b/apps/web-antd/src/views/infra/fileConfig/index.vue @@ -0,0 +1,165 @@ + + + diff --git a/apps/web-antd/src/views/infra/fileConfig/modules/form.vue b/apps/web-antd/src/views/infra/fileConfig/modules/form.vue new file mode 100644 index 000000000..55c123982 --- /dev/null +++ b/apps/web-antd/src/views/infra/fileConfig/modules/form.vue @@ -0,0 +1,75 @@ + + + diff --git a/apps/web-antd/src/views/system/mail/account/data.ts b/apps/web-antd/src/views/system/mail/account/data.ts index ba90f4ac0..2919dfe97 100644 --- a/apps/web-antd/src/views/system/mail/account/data.ts +++ b/apps/web-antd/src/views/system/mail/account/data.ts @@ -13,7 +13,6 @@ export function useFormSchema(): VbenFormSchema[] { return [ { fieldName: 'id', - label: 'id', component: 'Input', dependencies: { triggerFields: [''], diff --git a/apps/web-antd/src/views/system/mail/template/data.ts b/apps/web-antd/src/views/system/mail/template/data.ts index aff719a5c..c0ba19069 100644 --- a/apps/web-antd/src/views/system/mail/template/data.ts +++ b/apps/web-antd/src/views/system/mail/template/data.ts @@ -16,7 +16,6 @@ export function useFormSchema(): VbenFormSchema[] { return [ { fieldName: 'id', - label: 'id', component: 'Input', dependencies: { triggerFields: [''], diff --git a/apps/web-antd/src/views/system/notice/data.ts b/apps/web-antd/src/views/system/notice/data.ts index 2e1bfb626..0f7d8fccf 100644 --- a/apps/web-antd/src/views/system/notice/data.ts +++ b/apps/web-antd/src/views/system/notice/data.ts @@ -13,7 +13,6 @@ export function useFormSchema(): VbenFormSchema[] { return [ { fieldName: 'id', - label: 'id', component: 'Input', dependencies: { triggerFields: [''], diff --git a/apps/web-antd/src/views/system/oauth2/client/data.ts b/apps/web-antd/src/views/system/oauth2/client/data.ts index f77eb99ad..fbe586410 100644 --- a/apps/web-antd/src/views/system/oauth2/client/data.ts +++ b/apps/web-antd/src/views/system/oauth2/client/data.ts @@ -13,7 +13,6 @@ export function useFormSchema(): VbenFormSchema[] { return [ { fieldName: 'id', - label: 'id', component: 'Input', dependencies: { triggerFields: [''], diff --git a/apps/web-antd/src/views/system/post/data.ts b/apps/web-antd/src/views/system/post/data.ts index 167bd2e69..7045bdce8 100644 --- a/apps/web-antd/src/views/system/post/data.ts +++ b/apps/web-antd/src/views/system/post/data.ts @@ -14,7 +14,6 @@ export function useFormSchema(): VbenFormSchema[] { { component: 'Input', fieldName: 'id', - label: 'id', dependencies: { triggerFields: [''], show: () => false, diff --git a/apps/web-antd/src/views/system/social/client/data.ts b/apps/web-antd/src/views/system/social/client/data.ts index 9d6bc8f57..46937214e 100644 --- a/apps/web-antd/src/views/system/social/client/data.ts +++ b/apps/web-antd/src/views/system/social/client/data.ts @@ -13,7 +13,6 @@ export function useFormSchema(): VbenFormSchema[] { return [ { fieldName: 'id', - label: 'id', component: 'Input', dependencies: { triggerFields: [''], diff --git a/apps/web-antd/src/views/system/user/data.ts b/apps/web-antd/src/views/system/user/data.ts index 30c84b9e6..e97acef05 100644 --- a/apps/web-antd/src/views/system/user/data.ts +++ b/apps/web-antd/src/views/system/user/data.ts @@ -20,7 +20,6 @@ export function useFormSchema(): VbenFormSchema[] { { component: 'Input', fieldName: 'id', - label: 'id', dependencies: { triggerFields: [''], show: () => false, @@ -143,7 +142,6 @@ export function useResetPasswordFormSchema(): VbenFormSchema[] { { component: 'Input', fieldName: 'id', - label: 'id', dependencies: { triggerFields: [''], show: () => false, @@ -185,7 +183,6 @@ export function useAssignRoleFormSchema(): VbenFormSchema[] { { component: 'Input', fieldName: 'id', - label: 'id', dependencies: { triggerFields: [''], show: () => false, diff --git a/packages/locales/src/langs/en-US/ui.json b/packages/locales/src/langs/en-US/ui.json index abcac6950..768dd798e 100644 --- a/packages/locales/src/langs/en-US/ui.json +++ b/packages/locales/src/langs/en-US/ui.json @@ -25,7 +25,8 @@ "operationFailed": "Operation failed", "importSuccess": "Import succeeded", "importFail": "Import failed", - "downloadTemplateFail": "Download template failed" + "downloadTemplateFail": "Download template failed", + "updating": "Updating {0}..." }, "placeholder": { "input": "Please enter", diff --git a/packages/locales/src/langs/zh-CN/ui.json b/packages/locales/src/langs/zh-CN/ui.json index c604078bb..8bd7f65d7 100644 --- a/packages/locales/src/langs/zh-CN/ui.json +++ b/packages/locales/src/langs/zh-CN/ui.json @@ -25,7 +25,8 @@ "operationFailed": "操作失败", "importSuccess": "导入成功", "importFail": "导入失败", - "downloadTemplateFail": "下载模板失败" + "downloadTemplateFail": "下载模板失败", + "updating": "正在更新 {0}..." }, "placeholder": { "input": "请输入",