diff --git a/docs/java/VelocityUtils.java b/docs/java/VelocityUtils.java index a64bcd63..73290c75 100644 --- a/docs/java/VelocityUtils.java +++ b/docs/java/VelocityUtils.java @@ -62,7 +62,7 @@ public class VelocityUtils { velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName())); velocityContext.put("businessName", genTable.getBusinessName()); velocityContext.put("business_name", StrUtil.toUnderlineCase(genTable.getBusinessName())); - velocityContext.put("business-name", StrUtil.toUnderlineCase(genTable.getBusinessName())); + velocityContext.put("business-name", StrUtil.toSymbolCase(genTable.getBusinessName(),'-')); velocityContext.put("businessname", StrUtil.toSymbolCase(genTable.getBusinessName(), ' ')); velocityContext.put("basePackage", getPackagePrefix(packageName)); velocityContext.put("packageName", packageName); diff --git a/src/components/custom/dict-tag.vue b/src/components/custom/dict-tag.vue index 894d4f06..cf8464e4 100644 --- a/src/components/custom/dict-tag.vue +++ b/src/components/custom/dict-tag.vue @@ -10,7 +10,7 @@ interface Props { value?: string[] | number[] | string | number; dictCode?: string; immediate?: boolean; - dictData?: Api.System.DictData[]; + dictData?: Api.System.DictData; [key: string]: any; } @@ -25,7 +25,7 @@ const attrs = useAttrs() as TagProps; const dictTagData = computed(() => { if (props.dictData) { - return props.dictData; + return [props.dictData]; } // 避免 props.value 为 0 时,无法触发 if (props.dictCode && isNotNull(props.value)) { @@ -42,7 +42,7 @@ const dictTagData = computed(() => { Promise import("@/views/system/dict/type/index.vue"), system_menu: () => import("@/views/system/menu/index.vue"), system_notice: () => import("@/views/system/notice/index.vue"), + system_oss: () => import("@/views/system/oss/index.vue"), system_post: () => import("@/views/system/post/index.vue"), system_tenant: () => import("@/views/system/tenant/index.vue"), system_user: () => import("@/views/system/user/index.vue"), diff --git a/src/router/elegant/routes.ts b/src/router/elegant/routes.ts index cca82f82..2f9938ff 100644 --- a/src/router/elegant/routes.ts +++ b/src/router/elegant/routes.ts @@ -202,6 +202,15 @@ export const generatedRoutes: GeneratedRoute[] = [ i18nKey: 'route.system_notice' } }, + { + name: 'system_oss', + path: '/system/oss', + component: 'view.system_oss', + meta: { + title: 'system_oss', + i18nKey: 'route.system_oss' + } + }, { name: 'system_post', path: '/system/post', diff --git a/src/router/elegant/transform.ts b/src/router/elegant/transform.ts index dcc5979e..a80a503a 100644 --- a/src/router/elegant/transform.ts +++ b/src/router/elegant/transform.ts @@ -182,6 +182,7 @@ const routeMap: RouteMap = { "system_dict_type": "/system/dict/type", "system_menu": "/system/menu", "system_notice": "/system/notice", + "system_oss": "/system/oss", "system_post": "/system/post", "system_tenant": "/system/tenant", "system_user": "/system/user", diff --git a/src/service/api/system/config.ts b/src/service/api/system/config.ts index 836b1791..c8548f1a 100644 --- a/src/service/api/system/config.ts +++ b/src/service/api/system/config.ts @@ -43,6 +43,14 @@ export function fetchBatchDeleteConfig(configIds: CommonType.IdType[]) { }); } +/** 根据Key获取值 */ +export function fetchGetConfigByKey(configKey: string) { + return request({ + url: `/system/config/configKey/${configKey}`, + method: 'get' + }); +} + /** 刷新缓存 */ export function fetchRefreshCache() { return request({ diff --git a/src/service/api/system/oss.ts b/src/service/api/system/oss.ts new file mode 100644 index 00000000..f8e0f39d --- /dev/null +++ b/src/service/api/system/oss.ts @@ -0,0 +1,18 @@ +import { request } from '@/service/request'; + +/** 获取文件管理列表 */ +export function fetchGetOssList(params?: Api.System.OssSearchParams) { + return request({ + url: '/resource/oss/list', + method: 'get', + params + }); +} + +/** 批量删除文件管理 */ +export function fetchBatchDeleteOss(ossIds: CommonType.IdType[]) { + return request({ + url: `/resource/oss/${ossIds.join(',')}`, + method: 'delete' + }); +} diff --git a/src/typings/api/system.api.d.ts b/src/typings/api/system.api.d.ts index 2a39c2cd..148c4ff1 100644 --- a/src/typings/api/system.api.d.ts +++ b/src/typings/api/system.api.d.ts @@ -612,5 +612,32 @@ declare namespace Api { | 'wechat_mp' | 'wechat_enterprise' | 'gitlab'; + + /** oss */ + type Oss = Common.CommonRecord<{ + /** 对象存储主键 */ + ossId: CommonType.IdType; + /** 租户编号 */ + tenantId: CommonType.IdType; + /** 文件名 */ + fileName: string; + /** 原名 */ + originalName: string; + /** 后缀名 */ + fileSuffix: string; + /** 文件预览 */ + url: string; + /** 服务商 */ + service: string; + /** 创建者 */ + createByName: string; + }>; + + /** oss search params */ + type OssSearchParams = CommonType.RecordNullable< + Pick & Api.Common.CommonSearchParams + >; + /** oss list */ + type OssList = Api.Common.PaginatingQueryRecord; } } diff --git a/src/typings/elegant-router.d.ts b/src/typings/elegant-router.d.ts index af5788cd..3ebcb8cc 100644 --- a/src/typings/elegant-router.d.ts +++ b/src/typings/elegant-router.d.ts @@ -36,6 +36,7 @@ declare module "@elegant-router/types" { "system_dict_type": "/system/dict/type"; "system_menu": "/system/menu"; "system_notice": "/system/notice"; + "system_oss": "/system/oss"; "system_post": "/system/post"; "system_tenant": "/system/tenant"; "system_user": "/system/user"; @@ -115,6 +116,7 @@ declare module "@elegant-router/types" { | "system_dict_type" | "system_menu" | "system_notice" + | "system_oss" | "system_post" | "system_tenant" | "system_user" diff --git a/src/utils/common.ts b/src/utils/common.ts index d7e9133c..231eb366 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -85,6 +85,12 @@ export function isNull(value: any) { return value === undefined || value === null || value === '' || value === 'undefined' || value === 'null'; } +/** 判断是否为图片类型 */ +export function isImage(suffix: string) { + const imgSuffixList = ['.jpg', '.jpeg', '.png', '.gif', '.webp']; + return imgSuffixList.includes(suffix.toLowerCase()); +} + /** * 构造树型结构数据 * diff --git a/src/views/monitor/oper-log/index.vue b/src/views/monitor/oper-log/index.vue index 4614a9e8..4268effc 100644 --- a/src/views/monitor/oper-log/index.vue +++ b/src/views/monitor/oper-log/index.vue @@ -163,30 +163,29 @@ async function handleCleanOperLog() { ) { +import { ref } from 'vue'; +import { NButton, NImage, NPopconfirm } from 'naive-ui'; +import { fetchBatchDeleteOss, fetchGetOssList } from '@/service/api/system/oss'; +import { fetchGetConfigByKey } from '@/service/api/system/config'; +import { useAppStore } from '@/store/modules/app'; +import { useAuth } from '@/hooks/business/auth'; +import { useTable, useTableOperate } from '@/hooks/common/table'; +import { useDownload } from '@/hooks/business/download'; +import { isImage } from '@/utils/common'; +import { $t } from '@/locales'; +import OssSearch from './modules/oss-search.vue'; +import type { TableDataWithIndex } from '~/packages/hooks/src'; + +defineOptions({ + name: 'OssList' +}); + +const appStore = useAppStore(); +const { hasAuth } = useAuth(); +const { oss } = useDownload(); +const preview = ref(false); + +const { + columns, + columnChecks, + data, + getData, + getDataByPage, + loading, + mobilePagination, + searchParams, + resetSearchParams +} = useTable({ + apiFn: fetchGetOssList, + apiParams: { + pageNum: 1, + pageSize: 10, + // if you want to use the searchParams in Form, you need to define the following properties, and the value is null + // the value can not be undefined, otherwise the property in Form will not be reactive + fileName: null, + originalName: null, + fileSuffix: null, + service: null + }, + columns: () => [ + { + type: 'selection', + align: 'center', + width: 48 + }, + { + key: 'index', + title: $t('common.index'), + align: 'center', + width: 64 + }, + { + key: 'fileName', + title: '文件名', + align: 'center', + ellipsis: { + tooltip: true + }, + minWidth: 120 + }, + { + key: 'originalName', + title: '原名', + align: 'center', + ellipsis: { + tooltip: true + }, + minWidth: 120 + }, + { + key: 'fileSuffix', + title: '后缀名', + align: 'center', + minWidth: 120 + }, + { + key: 'url', + title: '文件预览', + align: 'center', + ellipsis: { + tooltip: true + }, + minWidth: 120, + render: row => { + if (preview.value && isImage(row.fileSuffix)) { + return ; + } + return {row.url}; + } + }, + { + key: 'createTime', + title: '创建时间', + align: 'center', + minWidth: 120 + }, + { + key: 'createByName', + title: '上传人', + align: 'center', + minWidth: 120 + }, + { + key: 'service', + title: '服务商', + align: 'center', + minWidth: 120 + }, + { + key: 'operate', + title: $t('common.operate'), + align: 'center', + width: 130, + render: row => { + const downloadBtn = () => { + return ( + handleDownload(row)}> + 下载 + + ); + }; + + const deleteBtn = () => { + if (!hasAuth('system:oss:remove')) { + return null; + } + return ( + handleDelete(row.ossId!)}> + {{ + default: () => $t('common.confirmDelete'), + trigger: () => ( + + {$t('common.delete')} + + ) + }} + + ); + }; + + return ( +
+ {downloadBtn()} + {deleteBtn()} +
+ ); + } + } + ] +}); + +const { checkedRowKeys, onBatchDeleted, onDeleted } = useTableOperate(data, getData); + +async function handleBatchDelete() { + // request + const { error } = await fetchBatchDeleteOss(checkedRowKeys.value); + if (error) return; + onBatchDeleted(); +} + +async function handleDelete(ossId: CommonType.IdType) { + // request + const { error } = await fetchBatchDeleteOss([ossId]); + if (error) return; + onDeleted(); +} + +async function getConfigKey() { + const { data: previewStr, error } = await fetchGetConfigByKey('sys.oss.previewListResource'); + if (error) return; + preview.value = previewStr === 'true'; +} +getConfigKey(); + +function handleDownload(row: TableDataWithIndex) { + oss(row.ossId); +} + + + + + diff --git a/src/views/system/oss/modules/oss-search.vue b/src/views/system/oss/modules/oss-search.vue new file mode 100644 index 00000000..56be83e6 --- /dev/null +++ b/src/views/system/oss/modules/oss-search.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/src/views/system/tenant/index.vue b/src/views/system/tenant/index.vue index 583e8673..c191c951 100644 --- a/src/views/system/tenant/index.vue +++ b/src/views/system/tenant/index.vue @@ -201,31 +201,24 @@ async function handleExport() {