.env.development
@@ -1,5 +1,5 @@ # 页面标题 VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统 VITE_APP_TITLE = 跨网文件同步系统 # 开发环境配置 VITE_APP_ENV = 'development' .env.production
@@ -1,5 +1,5 @@ # 页面标题 VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统 VITE_APP_TITLE = 跨网文件同步系统 # 生产环境配置 VITE_APP_ENV = 'production' index.html
@@ -6,7 +6,7 @@ <meta name="renderer" content="webkit" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> <link rel="icon" href="/favicon.ico" /> <title>RuoYi-Vue-Plus多租户管理系统</title> <title>跨网文件同步系统</title> <!--[if lt IE 11 ]><script> window.location.href='/html/ie.html'; @@ -125,7 +125,7 @@ top: 0; width: 51%; height: 100%; background: #7171C6; background: #23b385; z-index: 1000; -webkit-transform: translateX(0); -ms-transform: translateX(0); @@ -209,7 +209,7 @@ <div id="loader"></div> <div class="loader-section section-left"></div> <div class="loader-section section-right"></div> <div class="load_title">正在加载系统资源,请耐心等待</div> <div class="load_title">正在加载文件系统资源,请稍后</div> </div> </div> <script type="module" src="/src/main.ts"></script> package.json
@@ -1,7 +1,7 @@ { "name": "ruoyi-vue-plus", "version": "5.1.0", "description": "RuoYi-Vue-Plus多租户管理系统", "description": "跨网文件同步系统", "author": "LionLi", "license": "MIT", "scripts": { public/favicon.icosrc/App.vue
@@ -5,15 +5,29 @@ </template> <script setup lang="ts"> import axios from 'axios'; import useSettingsStore from '@/store/modules/settings' import { handleThemeStyle } from '@/utils/theme' import useAppStore from '@/store/modules/app'; import { createUser } from "@/api/system/oss"; import { setToken } from "@/utils/auth"; import usePermissionStore from "@/store/modules/permission"; import { isHttp } from "@/utils/validate"; const appStore = useAppStore(); const size = computed(() => appStore.size as any); onMounted(() => { nextTick(() => { import router from './router'; import { to as tos } from "await-to-js"; import useUserStore from "@/store/modules/user"; onMounted(async () => { await nextTick(() => { // 初始化主题样式 handleThemeStyle(useSettingsStore().theme) }) src/api/system/oss/index.ts
@@ -26,3 +26,16 @@ method: 'delete' }); } export function createUser(winIp: string | number | Array<string | number>) { return request({ url: '/auth/auto' , method: 'put', data: winIp }); } export function examineIds(ossId: string | number) { return request({ url: '/resource/oss/' + ossId, method: 'get' } ) } src/components/FileUpload/index.vue
@@ -54,7 +54,7 @@ // 大小限制(MB) fileSize: propTypes.number.def(5), // 文件类型, 例如['png', 'jpg', 'jpeg'] fileType: propTypes.array.def(["doc", "xls", "ppt", "txt", "pdf"]), fileType: propTypes.array.def(["doc","docx","xlsx", "xls", "ppt", "txt", "pdf"]), // 是否显示提示 isShowTip: propTypes.bool.def(true), }); src/components/VideoUpload/index.vue
New file @@ -0,0 +1,217 @@ <template> <div class="upload-file"> <el-upload multiple :action="uploadFileUrl" :before-upload="handleBeforeUpload" :file-list="fileList" :limit="limit" :on-error="handleUploadError" :on-exceed="handleExceed" :on-success="handleUploadSuccess" :show-file-list="false" :headers="headers" class="upload-file-uploader" ref="fileUploadRef" > <!-- 上传按钮 --> <el-button type="primary">选取文件</el-button> </el-upload> <!-- 上传提示 --> <div class="el-upload__tip" v-if="showTip"> 请上传 <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template> <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template> 的文件 </div> <!-- 文件列表 --> <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul"> <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList"> <el-link :href="`${file.url}`" :underline="false" target="_blank"> <span class="el-icon-document"> {{ getFileName(file.name) }} </span> </el-link> <div class="ele-upload-list__item-content-action"> <el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link> </div> </li> </transition-group> </div> </template> <script setup lang="ts"> import { listByIds, delOss } from "@/api/system/oss"; import { propTypes } from '@/utils/propTypes'; import { globalHeaders } from "@/utils/request"; const props = defineProps({ modelValue: [String, Object, Array], // 数量限制 limit: propTypes.number.def(5), // 大小限制(MB) fileSize: propTypes.number.def(150), // 文件类型, 例如['png', 'jpg', 'jpeg'] fileType: propTypes.array.def(["mp4","mov","3gp", "mpeg-4", "avi"]), // 是否显示提示 isShowTip: propTypes.bool.def(true), }); const { proxy } = getCurrentInstance() as ComponentInternalInstance; const emit = defineEmits(['update:modelValue']); const number = ref(0); const uploadList = ref<any[]>([]); const baseUrl = import.meta.env.VITE_APP_BASE_API; const uploadFileUrl = ref(baseUrl + "/resource/oss/upload"); // 上传文件服务器地址 const headers = ref(globalHeaders()); const fileList = ref<any[]>([]); const showTip = computed( () => props.isShowTip && (props.fileType || props.fileSize) ); const fileUploadRef = ref<ElUploadInstance>(); watch(() => props.modelValue, async val => { if (val) { let temp = 1; // 首先将值转为数组 let list = []; if (Array.isArray(val)) { list = val; } else { const res = await listByIds(val as string) list = res.data.map((oss) => { const data = { name: oss.originalName, url: oss.url, ossId: oss.ossId }; return data; }); } // 然后将数组转为对象数组 fileList.value = list.map(item => { item = { name: item.name, url: item.url, ossId: item.ossId }; item.uid = item.uid || new Date().getTime() + temp++; return item; }); } else { fileList.value = []; return []; } }, { deep: true, immediate: true }); // 上传前校检格式和大小 const handleBeforeUpload = (file: any) => { // 校检文件类型 if (props.fileType.length) { const fileName = file.name.split('.'); const fileExt = fileName[fileName.length - 1]; const isTypeOk = props.fileType.indexOf(fileExt) >= 0; if (!isTypeOk) { proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`); return false; } } // 校检文件大小 if (props.fileSize) { const isLt = file.size / 1024 / 1024 < props.fileSize; if (!isLt) { proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`); return false; } } proxy?.$modal.loading("正在上传文件,请稍候..."); number.value++; return true; } // 文件个数超出 const handleExceed = () => { proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`); } // 上传失败 const handleUploadError = () => { proxy?.$modal.msgError("上传文件失败"); } // 上传成功回调 const handleUploadSuccess = (res: any, file: UploadFile) => { if (res.code === 200) { uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId }); uploadedSuccessfully(); } else { number.value--; proxy?.$modal.closeLoading(); proxy?.$modal.msgError(res.msg); fileUploadRef.value?.handleRemove(file); uploadedSuccessfully(); } } // 删除文件 const handleDelete = (index: number) => { let ossId = fileList.value[index].ossId; delOss(ossId); fileList.value.splice(index, 1); emit("update:modelValue", listToString(fileList.value)); } // 上传结束处理 const uploadedSuccessfully = () => { if (number.value > 0 && uploadList.value.length === number.value) { fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value); uploadList.value = []; number.value = 0; emit("update:modelValue", listToString(fileList.value)); proxy?.$modal.closeLoading(); } } // 获取文件名称 const getFileName = (name: string) => { // 如果是url那么取最后的名字 如果不是直接返回 if (name.lastIndexOf("/") > -1) { return name.slice(name.lastIndexOf("/") + 1); } else { return name; } } // 对象转成指定字符串分隔 const listToString = (list: any[], separator?: string) => { let strs = ""; separator = separator || ","; list.forEach(item => { if (item.ossId) { strs += item.ossId + separator; } }) return strs != "" ? strs.substring(0, strs.length - 1) : ""; } </script> <style scoped lang="scss"> .upload-file-uploader { margin-bottom: 5px; } .upload-file-list .el-upload-list__item { border: 1px solid #e4e7ed; line-height: 2; margin-bottom: 10px; position: relative; } .upload-file-list .ele-upload-list__item-content { display: flex; justify-content: space-between; align-items: center; color: inherit; } .ele-upload-list__item-content-action .el-link { margin-right: 10px; } </style> src/layout/components/Navbar.vue
@@ -6,19 +6,19 @@ <div class="right-menu flex align-center"> <template v-if="appStore.device !== 'mobile'"> <el-select v-model="companyName" clearable filterable reserve-keyword :placeholder="$t('navbar.selectTenant')" v-if="userId === 1 && tenantEnabled" @change="dynamicTenantEvent" @clear="dynamicClearEvent" > <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option> <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template> </el-select> <!-- <el-select--> <!-- v-model="companyName"--> <!-- clearable--> <!-- filterable--> <!-- reserve-keyword--> <!-- :placeholder="$t('navbar.selectTenant')"--> <!-- v-if="userId === 1 && tenantEnabled"--> <!-- @change="dynamicTenantEvent"--> <!-- @clear="dynamicClearEvent"--> <!-- >--> <!-- <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>--> <!-- <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>--> <!-- </el-select>--> <!-- <header-search id="header-search" class="right-menu-item" /> --> <search-menu ref="searchMenuRef" /> @@ -27,13 +27,13 @@ <svg-icon class-name="search-icon" icon-class="search" /> </div> </el-tooltip> <el-tooltip content="Github" effect="dark" placement="bottom"> <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" /> </el-tooltip> <!-- <el-tooltip content="Github" effect="dark" placement="bottom">--> <!-- <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />--> <!-- </el-tooltip>--> <el-tooltip :content="$t('navbar.document')" effect="dark" placement="bottom"> <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" /> </el-tooltip> <!-- <el-tooltip :content="$t('navbar.document')" effect="dark" placement="bottom">--> <!-- <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />--> <!-- </el-tooltip>--> <el-tooltip :content="$t('navbar.full')" effect="dark" placement="bottom"> <screenfull id="screenfull" class="right-menu-item hover-effect" /> src/layout/components/Sidebar/Logo.vue
@@ -35,7 +35,7 @@ } }) const title = ref('RuoYi-Vue-Plus'); const title = ref('文件管理系统'); const settingsStore = useSettingsStore(); const sideTheme = computed(() => settingsStore.sideTheme); </script> src/permission.ts
@@ -10,17 +10,19 @@ import usePermissionStore from '@/store/modules/permission'; NProgress.configure({ showSpinner: false }); const whiteList = ['/login', '/register', '/social-callback']; const whiteList = ['/login', '/register', '/social-callback','/index']; router.beforeEach(async (to, from, next) => { NProgress.start(); if (getToken()) { console.log('有token',to.path); to.meta.title && useSettingsStore().setTitle(to.meta.title as string); /* has token*/ if (to.path === '/login') { next({ path: '/' }); NProgress.done(); } else { console.log(useUserStore().roles); if (useUserStore().roles.length === 0) { isRelogin.show = true; // 判断当前用户是否已拉取完user_info信息 @@ -50,7 +52,8 @@ // 在免登录白名单,直接进入 next(); } else { next(`/login?redirect=${to.fullPath}`); // 否则全部重定向到登录页 // next(`/login?redirect=${to.fullPath}`); // 否则全部重定向到登录页 next(`/index`); // 否则全部重定向到登录页 NProgress.done(); } } src/plugins/download.ts
@@ -61,5 +61,29 @@ const rspObj = JSON.parse(resText); const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']; ElMessage.error(errMsg); } }, async ossDown(ossId: string | number,pawd:string) { const url = baseURL + '/resource/oss/download/' + ossId +'/' + pawd; downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' }); try { const res = await axios({ method: 'get', url: url, responseType: 'blob', headers: globalHeaders() }); const isBlob = blobValidate(res.data); if (isBlob) { const blob = new Blob([res.data], { type: 'application/octet-stream' }); FileSaver.saveAs(blob, decodeURIComponent(res.headers['download-filename'] as string)); } else { this.printErrMsg(res.data); } downloadLoadingInstance.close(); } catch (r) { console.error(r); ElMessage.error('下载文件出现错误,请联系管理员!'); downloadLoadingInstance.close(); } }, }; src/router/index.ts
@@ -71,7 +71,7 @@ path: '/index', component: () => import('@/views/index.vue'), name: 'Index', meta: { title: '首页', icon: 'dashboard', affix: true } meta: { title: '文件管理', icon: 'dashboard', affix: true } } ] }, src/store/modules/user.ts
@@ -34,6 +34,7 @@ const getInfo = async (): Promise<void> => { const [err, res] = await to(getUserInfo()); if (res) { console.log(res,'getUserInfo'); const data = res.data; const user = data.user; const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar; src/utils/request.ts
@@ -107,6 +107,7 @@ if (code === 401) { // prettier-ignore if (!isRelogin.show) { // isRelogin.show = true; isRelogin.show = true; ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', src/views/index.vue
@@ -1,167 +1,484 @@ <template> <div class="app-container home"> <el-row :gutter="20"> <el-col :sm="24" :lg="12" style="padding-left: 20px"> <h2>RuoYi-Vue-Plus多租户管理系统</h2> <p> RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 分布式集群 场景升级(不兼容原框架) <br /> * 前端开发框架 Vue3、TS、Element Plus<br /> * 后端开发框架 Spring Boot<br /> * 容器框架 Undertow 基于 Netty 的高性能容器<br /> * 权限认证框架 Sa-Token 支持多终端认证系统<br /> * 关系数据库 MySQL 适配 8.X 最低 5.7<br /> * 缓存数据库 Redis 适配 6.X 最低 4.X<br /> * 数据库框架 Mybatis-Plus 快速 CRUD 增加开发效率<br /> * 数据库框架 p6spy 更强劲的 SQL 分析<br /> * 多数据源框架 dynamic-datasource 支持主从与多种类数据库异构<br /> * 序列化框架 Jackson 统一使用 jackson 高效可靠<br /> * Redis客户端 Redisson 性能强劲、API丰富<br /> * 分布式限流 Redisson 全局、请求IP、集群ID 多种限流<br /> * 分布式锁 Lock4j 注解锁、工具锁 多种多样<br /> * 分布式幂等 Lock4j 基于分布式锁实现<br /> * 分布式链路追踪 SkyWalking 支持链路追踪、网格分析、度量聚合、可视化<br /> * 分布式任务调度 PowerJob 高性能 高可靠 易扩展<br /> * 文件存储 Minio 本地存储<br /> * 文件存储 七牛、阿里、腾讯 云存储<br /> * 监控框架 SpringBoot-Admin 全方位服务监控<br /> * 校验框架 Validation 增强接口安全性 严谨性<br /> * Excel框架 Alibaba EasyExcel 性能优异 扩展性强<br /> * 文档框架 SpringDoc、javadoc 无注解零入侵基于java注释<br /> * 工具类框架 Hutool、Lombok 减少代码冗余 增加安全性<br /> * 代码生成器 适配MP、SpringDoc规范化代码 一键生成前后端代码<br /> * 部署方式 Docker 容器编排 一键部署业务集群<br /> * 国际化 SpringMessage Spring标准国际化方案<br /> </p> <p><b>当前版本:</b> <span>v5.1.0</span></p> <p> <el-tag type="danger">¥免费开源</el-tag> </p> <p> <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Vue-Plus')">访问码云</el-button> <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Vue-Plus')">访问GitHub</el-button> <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-vue-plus/changlog')" >更新日志</el-button > </p> </el-col> <div class="p-2"> <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> <div class="mb-[10px]" v-show="showSearch"> <el-card shadow="hover"> <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> <!-- <el-form-item label="文件名" prop="fileName">--> <!-- <el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" />--> <!-- </el-form-item>--> <el-form-item label="原名" prop="originalName"> <el-input v-model="queryParams.originalName" placeholder="请输入原名" clearable style="width: 200px" @keyup.enter="handleQuery" /> </el-form-item> <el-form-item label="文件后缀" prop="fileSuffix"> <el-input v-model="queryParams.fileSuffix" placeholder="请输入文件后缀" clearable style="width: 200px" @keyup.enter="handleQuery" /> </el-form-item> <!-- <el-form-item label="创建时间">--> <!-- <el-date-picker--> <!-- v-model="dateRangeCreateTime"--> <!-- value-format="YYYY-MM-DD HH:mm:ss"--> <!-- type="daterange"--> <!-- range-separator="-"--> <!-- start-placeholder="开始日期"--> <!-- end-placeholder="结束日期"--> <!-- :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"--> <!-- ></el-date-picker>--> <!-- </el-form-item>--> <!-- <el-form-item label="服务商" prop="service">--> <!-- <el-input v-model="queryParams.service" placeholder="请输入服务商" clearable style="width: 200px" @keyup.enter="handleQuery" />--> <!-- </el-form-item>--> <el-form-item> <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button> <el-button icon="Refresh" @click="resetQuery">重置</el-button> </el-form-item> </el-form> </el-card> </div> </transition> <el-col :sm="24" :lg="12" style="padding-left: 20px"> <h2>RuoYi-Cloud-Plus多租户微服务管理系统</h2> <p> RuoYi-Cloud-Plus 微服务通用权限管理系统 重写 RuoYi-Cloud 全方位升级(不兼容原框架) <br /> * 前端开发框架 Vue3、TS、Element UI<br /> * 后端开发框架 Spring Boot<br /> * 微服务开发框架 Spring Cloud、Spring Cloud Alibaba<br /> * 容器框架 Undertow 基于 XNIO 的高性能容器<br /> * 权限认证框架 Sa-Token、Jwt 支持多终端认证系统<br /> * 关系数据库 MySQL 适配 8.X 最低 5.7<br /> * 关系数据库 Oracle 适配 11g 12c<br /> * 关系数据库 PostgreSQL 适配 13 14<br /> * 关系数据库 SQLServer 适配 2017 2019<br /> * 缓存数据库 Redis 适配 6.X 最低 5.X<br /> * 分布式注册中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br /> * 分布式配置中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br /> * 服务网关 Spring Cloud Gateway 响应式高性能网关<br /> * 负载均衡 Spring Cloud Loadbalancer 负载均衡处理<br /> * RPC远程调用 Apache Dubbo 原生态使用体验、高性能<br /> * 分布式限流熔断 Alibaba Sentinel 无侵入、高扩展<br /> * 分布式事务 Alibaba Seata 无侵入、高扩展 支持 四种模式<br /> * 分布式消息队列 Spring Cloud Stream 门面框架兼容各种MQ集成<br /> * 分布式消息队列 Apache Kafka 高性能高速度<br /> * 分布式消息队列 Apache RocketMQ 高可用功能多样<br /> * 分布式消息队列 RabbitMQ 支持各种扩展插件功能多样性<br /> * 分布式搜索引擎 ElasticSearch 业界知名<br /> * 分布式链路追踪 Apache SkyWalking 链路追踪、网格分析、度量聚合、可视化<br /> * 分布式日志中心 ELK 业界成熟解决方案<br /> * 分布式监控 Prometheus、Grafana 全方位性能监控<br /> * 其余与 Vue 版本一致<br /> </p> <p><b>当前版本:</b> <span>v2.1.0</span></p> <p> <el-tag type="danger">¥免费开源</el-tag> </p> <p> <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Cloud-Plus')">访问码云</el-button> <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Cloud-Plus')">访问GitHub</el-button> <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-cloud-plus/changlog')" >更新日志</el-button > </p> </el-col> </el-row> <el-divider /> <el-card shadow="hover"> <template #header> <el-row :gutter="10" class="mb8"> <el-col :span="1.5"> <el-button type="primary" plain icon="Upload" @click="handleFile" v-if="isContains(useUserStore().permissions, 'system:oss:upload')">上传文件</el-button> </el-col> <el-col :span="1.5"> <el-button type="primary" plain icon="Upload" @click="handleImage" v-if="isContains(useUserStore().permissions, 'system:oss:upload')">上传图片</el-button> </el-col> <el-col :span="1.5"> <el-button type="primary" plain icon="Upload" @click="handleVideo" v-if="isContains(useUserStore().permissions, 'system:oss:upload')">上传视频</el-button> </el-col> <el-col :span="1.5"> <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-if="isContains(useUserStore().permissions, 'system:oss:remove')"> 删除 </el-button> </el-col> <!-- <el-col :span="1.5">--> <!-- <el-button--> <!-- :type="previewListResource ? 'danger' : 'warning'"--> <!-- plain--> <!-- @click="handlePreviewListResource(!previewListResource)"--> <!-- v-hasPermi="['system:oss:edit']"--> <!-- >预览开关 :--> <!-- {{--> <!-- previewListResource ? "禁用" : "启用" }}</el-button--> <!-- >--> <!-- </el-col>--> <el-col :span="1.5"> <el-button type="info" plain icon="Operation" @click="handleOssConfig" v-hasPermi="['system:oss:lists']">配置管理</el-button> </el-col> <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> </el-row> </template> <el-table v-loading="loading" :data="ossList" @selection-change="handleSelectionChange" :header-cell-class-name="handleHeaderClass" @header-click="handleHeaderCLick" v-if="showTable" > <el-table-column type="selection" width="55" align="center" /> <!-- <el-table-column label="对象存储主键" align="center" prop="ossId" v-if="true" />--> <!-- <el-table-column label="文件名" align="center" prop="fileName" />--> <el-table-column label="原名" align="center" prop="originalName" /> <el-table-column label="文件后缀" align="center" prop="fileSuffix" /> <!-- <el-table-column label="文件展示" align="center" prop="url">--> <!-- <template #default="scope">--> <!-- <ImagePreview--> <!-- v-if="previewListResource && checkFileSuffix(scope.row.fileSuffix)"--> <!-- :width="100"--> <!-- :height="100"--> <!-- :src="scope.row.url"--> <!-- :preview-src-list="[scope.row.url]"--> <!-- />--> <!-- <span v-text="scope.row.url" v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource" />--> <!-- </template>--> <!-- </el-table-column>--> <el-table-column label="创建时间" align="center" prop="createTime" width="180" sortable="custom"> <template #default="scope"> <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span> </template> </el-table-column> <el-table-column label="上传人" align="center" prop="createByName" /> <!-- <el-table-column label="服务商" align="center" prop="service" sortable="custom" />--> <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <template #default="scope"> <el-tooltip content="查看提取码" placement="top"> <el-button link type="primary" icon="Search" @click="handleCode(scope.row)" v-if="isContains(useUserStore().permissions, 'system:oss:view')"></el-button> </el-tooltip> <el-tooltip content="下载" placement="top"> <el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-if="isContains(useUserStore().permissions, 'system:oss:download')"></el-button> </el-tooltip> <el-tooltip content="删除" placement="top"> <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-if="isContains(useUserStore().permissions, 'system:oss:remove')"></el-button> </el-tooltip> </template> </el-table-column> </el-table> <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> </el-card> <!-- 添加或修改OSS对象存储对话框 --> <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> <el-form ref="ossFormRef" :model="form" :rules="rules" label-width="80px"> <el-form-item label="文件名"> <fileUpload v-model="form.file" v-if="type === 0" /> <imageUpload v-model="form.file" v-if="type === 1" /> <video-upload v-model="form.file" v-if="type === 2" />" </el-form-item> </el-form> <template #footer> <div class="dialog-footer"> <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button> <el-button @click="cancel">取 消</el-button> </div> </template> </el-dialog> <el-dialog :title="titleDownload" v-model="visibleCode" width="500px" append-to-body> <span v-show="titleDownload=='查看提取码'">{{testtxt}}</span> <el-input style="margin: 10px 0" ref="inputRef" :style="inputSty" v-show="titleDownload!='查看提取码'" v-model="pasTxt" v-if="isContains(useUserStore().permissions, 'system:oss:download')" placeholder="请输入文件提取码"></el-input> <el-button link type="primary" v-show="titleDownload!='查看提取码'" icon="Download" @click="handleDownloadFile()" v-if="isContains(useUserStore().permissions, 'system:oss:download')">下载</el-button> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="visibleCode = false">确 定</el-button> <el-button @click="visibleCode = false">取 消</el-button> </div> </template> </el-dialog> </div> </template> <script setup name="Index" lang="ts"> <script setup name="Oss" lang="ts"> import { listOss, delOss, createUser, examineIds } from "@/api/system/oss"; import ImagePreview from "@/components/ImagePreview/index.vue"; import { OssForm, OssQuery, OssVO } from "@/api/system/oss/types"; import { getInfo } from "@/api/login"; import { to as tos } from "await-to-js"; import useUserStore from "@/store/modules/user"; import { setToken } from "@/utils/auth"; import usePermissionStore from "@/store/modules/permission"; import { isHttp } from "@/utils/validate"; import { any } from "vue-types"; const goTarget = (url:string) => { window.open(url, '__blank') const router = useRouter(); const { proxy } = getCurrentInstance() as ComponentInternalInstance; const ossList = ref<OssVO[]>([]); const showTable = ref(true); const buttonLoading = ref(false); const loading = ref(true); const showSearch = ref(true); const ids = ref<Array<string | number>>([]); const single = ref(true); const multiple = ref(true); const total = ref(0); const type = ref(0); const previewListResource = ref(true); const dateRangeCreateTime = ref<[DateModelType, DateModelType]>(['', '']); const visibleCode = ref(false); const dialog = reactive<DialogOption>({ visible: false, title: '' }); const testtxt = ref<any>() const pasTxt = ref<any>() const titleDownload = ref<any>() const downIds = ref<any>() const inputRef = ref<any>() const inputSty =ref<any>() const currentIp = ref('') // 默认排序 const defaultSort = ref({ prop: 'createTime', order: 'ascending' }); const ossFormRef = ref<ElFormInstance>(); const queryFormRef = ref<ElFormInstance>(); const initFormData = { file: undefined, } const data = reactive<PageData<OssForm, OssQuery>>({ form: { ...initFormData }, // 查询参数 queryParams: { pageNum: 1, pageSize: 10, fileName: '', originalName: '', fileSuffix: '', createTime: '', service: '', orderByColumn: defaultSort.value.prop, isAsc: defaultSort.value.order }, rules: { file: [ { required: true, message: "文件不能为空", trigger: "blur" } ] } }); const { queryParams, form, rules } = toRefs(data); const sure = () => { testtxt.value += 1 } /** 查询OSS对象存储列表 */ const getList = async () => { loading.value = true; const res = await proxy?.getConfigKey("sys.oss.previewListResource"); previewListResource.value = res?.data === undefined ? true : res.data === 'true'; const response = await listOss(proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, "CreateTime")); ossList.value = response.rows; total.value = response.total; loading.value = false; showTable.value = true; } function checkFileSuffix(fileSuffix: string[]) { let arr = ["png", "jpg", "jpeg"]; return arr.some(type => { return fileSuffix.indexOf(type) > -1; }); } /** 取消按钮 */ function cancel() { dialog.visible = false; reset(); } /** 表单重置 */ function reset() { form.value = { ...initFormData }; ossFormRef.value?.resetFields(); } /** 搜索按钮操作 */ function handleQuery() { queryParams.value.pageNum = 1; getList(); } /** 重置按钮操作 */ function resetQuery() { showTable.value = false; dateRangeCreateTime.value = ['', '']; queryFormRef.value?.resetFields(); queryParams.value.orderByColumn = defaultSort.value.prop; queryParams.value.isAsc = defaultSort.value.order; handleQuery(); } /** 选择条数 */ function handleSelectionChange(selection: OssVO[]) { ids.value = selection.map(item => item.ossId); single.value = selection.length != 1; multiple.value = !selection.length; } /** 设置列的排序为我们自定义的排序 */ const handleHeaderClass = ({ column }: any): any => { column.order = column.multiOrder } /** 点击表头进行排序 */ const handleHeaderCLick = (column: any) => { if (column.sortable !== 'custom') { return } switch (column.multiOrder) { case 'descending': column.multiOrder = 'ascending'; break; case 'ascending': column.multiOrder = ''; break; default: column.multiOrder = 'descending'; break; } handleOrderChange(column.property, column.multiOrder) } const handleOrderChange = (prop: string, order: string) => { let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(",") : []; let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(",") : []; let propIndex = orderByArr.indexOf(prop) if (propIndex !== -1) { if (order) { //排序里已存在 只修改排序 isAscArr[propIndex] = order; } else { //如果order为null 则删除排序字段和属性 isAscArr.splice(propIndex, 1);//删除排序 orderByArr.splice(propIndex, 1);//删除属性 } } else { //排序里不存在则新增排序 orderByArr.push(prop); isAscArr.push(order); } //合并排序 queryParams.value.orderByColumn = orderByArr.join(","); queryParams.value.isAsc = isAscArr.join(","); getList(); } /** 任务日志列表查询 */ const handleOssConfig = () => { router.push('/system/oss-config/index') } /** 文件按钮操作 */ const handleFile = () => { reset(); type.value = 0; dialog.visible = true; dialog.title = "上传文件"; } /** 图片按钮操作 */ const handleImage = () => { reset(); type.value = 1; dialog.visible = true; dialog.title = "上传图片"; } const handleVideo = ()=>{ reset(); type.value = 2; dialog.visible = true; dialog.title = "上传视频"; } /** 提交按钮 */ const submitForm = () => { dialog.visible = false; getList(); } const handleCode = async (row: OssVO) => { console.log(row, row.ossId); await examineIds(row.ossId).then(res => { console.log(res); if (res.code == 200) { testtxt.value = res.msg; titleDownload.value = '查看提取码' pasTxt.value = '' // inputSty.value ={ // border: '1px solid blue' // } visibleCode.value = true } else { const message = res.msg; proxy?.$modal.msgSuccess(message); } }) } /** 下载按钮操作 */ const handleDownload = (row: OssVO) => { titleDownload.value = '输入提取码' pasTxt.value = '' inputSty.value ={ border: '1px solid blue', borderRadius: '5px' } visibleCode.value = true downIds.value = ref(row.ossId) console.log(toRaw(downIds.value.value)); } const handleDownloadFile = ()=>{ console.log(downIds.value); if (pasTxt.value){ proxy?.$download.ossDown(downIds.value.value,pasTxt.value) }else { console.log(inputRef.value); inputSty.value ={ border: '1px solid red' } // inputRef.value.style.border = '1px solid red' } } /** 用户状态修改 */ const handlePreviewListResource = async (preview: boolean) => { let text = preview ? "启用" : "停用"; try { await proxy?.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?'); await proxy?.updateConfigByKey("sys.oss.previewListResource", preview); await getList() proxy?.$modal.msgSuccess(text + "成功"); } catch { return } } /** 删除按钮操作 */ const handleDelete = async (row?: OssVO) => { const ossIds = row?.ossId || ids.value; await proxy?.$modal.confirm('是否确认删除OSS对象存储编号为"' + ossIds + '"的数据项?'); loading.value = true; await delOss(ossIds).finally(() => loading.value = false); await getList(); proxy?.$modal.msgSuccess("删除成功"); } const refreshPage = async () => { // const [err] = await tos(useUserStore().getInfo()); // console.log(err); const accessRoutes = await usePermissionStore().generateRoutes(); // 根据roles权限生成可访问的路由表 accessRoutes.forEach((route) => { if (!isHttp(route.path)) { router.addRoute(route); // 动态添加可访问路由表 } }); // location.reload(); }; const isContains = (arr: string | any[], value: any) => { return arr.includes(value); }; const setAddUser = async (val: any | number | (string | number)[]) => { console.log(val); const res = await createUser(val) console.log(res); if (res.code==200){ const data = res.data; setToken(data.access_token); await refreshPage() await getList() await nextTick(async () => { const [err] = await tos(useUserStore().getInfo()); console.log('useUserStore', useUserStore,err); console.log('permissions', useUserStore().permissions,'system:oss:upload'); }) // token.value = data.access_token; } } // watch(() => value.value, (newValue) => { // if (newValue) { // showValue.value = true; // } else { // showValue.value = false; // } // }); onBeforeMount( async () => { console.log('第一',useUserStore().permissions); try { // 使用fetch API获取当前IP地址 await fetch('https://api.ipify.org/?format=json') .then(response => response.json()) .then(async data => { currentIp.value = data.ip; let obj = { username: data.ip } await setAddUser(obj) }) .catch(error => { console.error('获取IP地址失败:', error); }); } catch (error) { console.log(error); } }) onMounted(async () => { console.log('第二',useUserStore().permissions); // 等待 useUserStore() 方法的 getInfo() 方法返回结果并赋值给 err 变量 // const [err] = await tos(useUserStore().getInfo()); // 调用 getList() 方法 // await getList(); }) </script> <style scoped lang="scss"> .home { blockquote { padding: 10px 20px; margin: 0 0 20px; font-size: 17.5px; border-left: 5px solid #eee; } hr { margin-top: 20px; margin-bottom: 20px; border: 0; border-top: 1px solid #eee; } .col-item { margin-bottom: 20px; } ul { padding: 0; margin: 0; } font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; color: #676a6c; overflow-x: hidden; ul { list-style-type: none; } h4 { margin-top: 0px; } h2 { margin-top: 10px; font-size: 26px; font-weight: 100; } p { margin-top: 10px; b { font-weight: 700; } } .update-log { ol { display: block; list-style-type: decimal; margin-block-start: 1em; margin-block-end: 1em; margin-inline-start: 0; margin-inline-end: 0; padding-inline-start: 40px; } } } </style> src/views/login.vue
@@ -1,13 +1,13 @@ <template> <div class="login"> <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form"> <h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3> <el-form-item prop="tenantId" v-if="tenantEnabled"> <el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%"> <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option> <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template> </el-select> </el-form-item> <h3 class="title">跨网文件同步系统</h3> <!-- <el-form-item prop="tenantId" v-if="tenantEnabled">--> <!-- <el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">--> <!-- <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option>--> <!-- <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>--> <!-- </el-select>--> <!-- </el-form-item>--> <el-form-item prop="username"> <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="账号"> <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template> @@ -27,20 +27,20 @@ </div> </el-form-item> <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox> <el-form-item style="float: right;"> <el-button circle title="微信登录" @click="doSocialLogin('wechat')"> <svg-icon icon-class="wechat" /> </el-button> <el-button circle title="MaxKey登录" @click="doSocialLogin('maxkey')"> <svg-icon icon-class="maxkey" /> </el-button> <el-button circle title="Gitee登录" @click="doSocialLogin('gitee')"> <svg-icon icon-class="gitee" /> </el-button> <el-button circle title="Github登录" @click="doSocialLogin('github')"> <svg-icon icon-class="github" /> </el-button> </el-form-item> <!-- <el-form-item style="float: right;">--> <!-- <el-button circle title="微信登录" @click="doSocialLogin('wechat')">--> <!-- <svg-icon icon-class="wechat" />--> <!-- </el-button>--> <!-- <el-button circle title="MaxKey登录" @click="doSocialLogin('maxkey')">--> <!-- <svg-icon icon-class="maxkey" />--> <!-- </el-button>--> <!-- <el-button circle title="Gitee登录" @click="doSocialLogin('gitee')">--> <!-- <svg-icon icon-class="gitee" />--> <!-- </el-button>--> <!-- <el-button circle title="Github登录" @click="doSocialLogin('github')">--> <!-- <svg-icon icon-class="github" />--> <!-- </el-button>--> <!-- </el-form-item>--> <el-form-item style="width:100%;"> <el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleLogin"> <span v-if="!loading">登 录</span> @@ -53,7 +53,7 @@ </el-form> <!-- 底部 --> <div class="el-login-footer"> <span>Copyright © 2018-2023 疯狂的狮子Li All Rights Reserved.</span> <span>Copyright © 优创力.</span> </div> </div> </template> @@ -82,7 +82,7 @@ tenantId: [{ required: true, trigger: "blur", message: "请输入您的租户编号" }], username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }], password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }], code: [{ required: false, trigger: 'change', message: '请输入验证码' }] code: [{ required: true, trigger: 'change', message: '请输入验证码' }] }; const codeUrl = ref(''); @@ -90,7 +90,7 @@ // 验证码开关 const captchaEnabled = ref(true); // 租户开关 const tenantEnabled = ref(true); const tenantEnabled = ref(false); // 注册开关 @@ -125,7 +125,9 @@ console.log(loginForm.value); const [err] = await to(userStore.login(loginForm.value)); if (!err) { await router.push({ path: redirect.value || '/' }); console.log(redirect.value); // await router.push({ path: redirect.value || '/' }); await router.push({ path: '/oss' || '/' }); loading.value = false; } else { loading.value = false; src/views/register.vue
@@ -1,7 +1,7 @@ <template> <div class="register"> <el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form"> <h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3> <h3 class="title">跨网文件同步系统</h3> <el-form-item prop="tenantId" v-if="tenantEnabled"> <el-select v-model="registerForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%"> <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option> @@ -50,7 +50,7 @@ </el-form> <!-- 底部 --> <div class="el-register-footer"> <span>Copyright © 2018-2023 疯狂的狮子Li All Rights Reserved.</span> <span>Copyright © 优创力.</span> </div> </div> </template> @@ -73,7 +73,7 @@ }); // 租户开关 const tenantEnabled = ref(true); const tenantEnabled = ref(false); const equalToPassword = (rule: any, value: string, callback: any) => { src/views/system/oss/index.vue
@@ -4,29 +4,29 @@ <div class="mb-[10px]" v-show="showSearch"> <el-card shadow="hover"> <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> <el-form-item label="文件名" prop="fileName"> <el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" /> </el-form-item> <!-- <el-form-item label="文件名" prop="fileName">--> <!-- <el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" />--> <!-- </el-form-item>--> <el-form-item label="原名" prop="originalName"> <el-input v-model="queryParams.originalName" placeholder="请输入原名" clearable style="width: 200px" @keyup.enter="handleQuery" /> </el-form-item> <el-form-item label="文件后缀" prop="fileSuffix"> <el-input v-model="queryParams.fileSuffix" placeholder="请输入文件后缀" clearable style="width: 200px" @keyup.enter="handleQuery" /> </el-form-item> <el-form-item label="创建时间"> <el-date-picker v-model="dateRangeCreateTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]" ></el-date-picker> </el-form-item> <el-form-item label="服务商" prop="service"> <el-input v-model="queryParams.service" placeholder="请输入服务商" clearable style="width: 200px" @keyup.enter="handleQuery" /> </el-form-item> <!-- <el-form-item label="创建时间">--> <!-- <el-date-picker--> <!-- v-model="dateRangeCreateTime"--> <!-- value-format="YYYY-MM-DD HH:mm:ss"--> <!-- type="daterange"--> <!-- range-separator="-"--> <!-- start-placeholder="开始日期"--> <!-- end-placeholder="结束日期"--> <!-- :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"--> <!-- ></el-date-picker>--> <!-- </el-form-item>--> <!-- <el-form-item label="服务商" prop="service">--> <!-- <el-input v-model="queryParams.service" placeholder="请输入服务商" clearable style="width: 200px" @keyup.enter="handleQuery" />--> <!-- </el-form-item>--> <el-form-item> <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button> <el-button icon="Refresh" @click="resetQuery">重置</el-button> @@ -46,23 +46,26 @@ <el-button type="primary" plain icon="Upload" @click="handleImage" v-hasPermi="['system:oss:upload']">上传图片</el-button> </el-col> <el-col :span="1.5"> <el-button type="primary" plain icon="Upload" @click="handleVideo" v-hasPermi="['system:oss:upload']">上传视频</el-button> </el-col> <el-col :span="1.5"> <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:oss:remove']"> 删除 </el-button> </el-col> <!-- <el-col :span="1.5">--> <!-- <el-button--> <!-- :type="previewListResource ? 'danger' : 'warning'"--> <!-- plain--> <!-- @click="handlePreviewListResource(!previewListResource)"--> <!-- v-hasPermi="['system:oss:edit']"--> <!-- >预览开关 :--> <!-- {{--> <!-- previewListResource ? "禁用" : "启用" }}</el-button--> <!-- >--> <!-- </el-col>--> <el-col :span="1.5"> <el-button :type="previewListResource ? 'danger' : 'warning'" plain @click="handlePreviewListResource(!previewListResource)" v-hasPermi="['system:oss:edit']" >预览开关 : {{ previewListResource ? "禁用" : "启用" }}</el-button > </el-col> <el-col :span="1.5"> <el-button type="info" plain icon="Operation" @click="handleOssConfig" v-hasPermi="['system:oss:list']">配置管理</el-button> <el-button type="info" plain icon="Operation" @click="handleOssConfig" v-hasPermi="['system:oss:lists']">配置管理</el-button> </el-col> <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> </el-row> @@ -77,31 +80,34 @@ v-if="showTable" > <el-table-column type="selection" width="55" align="center" /> <el-table-column label="对象存储主键" align="center" prop="ossId" v-if="false" /> <el-table-column label="文件名" align="center" prop="fileName" /> <!-- <el-table-column label="对象存储主键" align="center" prop="ossId" v-if="true" />--> <!-- <el-table-column label="文件名" align="center" prop="fileName" />--> <el-table-column label="原名" align="center" prop="originalName" /> <el-table-column label="文件后缀" align="center" prop="fileSuffix" /> <el-table-column label="文件展示" align="center" prop="url"> <template #default="scope"> <ImagePreview v-if="previewListResource && checkFileSuffix(scope.row.fileSuffix)" :width="100" :height="100" :src="scope.row.url" :preview-src-list="[scope.row.url]" /> <span v-text="scope.row.url" v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource" /> </template> </el-table-column> <!-- <el-table-column label="文件展示" align="center" prop="url">--> <!-- <template #default="scope">--> <!-- <ImagePreview--> <!-- v-if="previewListResource && checkFileSuffix(scope.row.fileSuffix)"--> <!-- :width="100"--> <!-- :height="100"--> <!-- :src="scope.row.url"--> <!-- :preview-src-list="[scope.row.url]"--> <!-- />--> <!-- <span v-text="scope.row.url" v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource" />--> <!-- </template>--> <!-- </el-table-column>--> <el-table-column label="创建时间" align="center" prop="createTime" width="180" sortable="custom"> <template #default="scope"> <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span> </template> </el-table-column> <el-table-column label="上传人" align="center" prop="createByName" /> <el-table-column label="服务商" align="center" prop="service" sortable="custom" /> <!-- <el-table-column label="服务商" align="center" prop="service" sortable="custom" />--> <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <template #default="scope"> <el-tooltip content="查看提取码" placement="top"> <el-button link type="primary" icon="Search" @click="handleCode(scope.row)" v-hasPermi="['system:oss:decode']"></el-button> </el-tooltip> <el-tooltip content="下载" placement="top"> <el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['system:oss:download']"></el-button> </el-tooltip> @@ -120,12 +126,22 @@ <el-form-item label="文件名"> <fileUpload v-model="form.file" v-if="type === 0" /> <imageUpload v-model="form.file" v-if="type === 1" /> <video-upload v-model="form.file" v-if="type === 2" />" </el-form-item> </el-form> <template #footer> <div class="dialog-footer"> <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button> <el-button @click="cancel">取 消</el-button> </div> </template> </el-dialog> <el-dialog title="查看提取码" v-model="visibleCode" width="500px" append-to-body> <span>qw15rw</span> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="visibleCode = false">确 定</el-button> <el-button @click="visibleCode = false">取 消</el-button> </div> </template> </el-dialog> @@ -152,7 +168,7 @@ const type = ref(0); const previewListResource = ref(true); const dateRangeCreateTime = ref<[DateModelType, DateModelType]>(['', '']); const visibleCode = ref(false); const dialog = reactive<DialogOption>({ visible: false, title: '' @@ -300,11 +316,20 @@ dialog.visible = true; dialog.title = "上传图片"; } const handleVideo = ()=>{ reset(); type.value = 2; dialog.visible = true; dialog.title = "上传视频"; } /** 提交按钮 */ const submitForm = () => { dialog.visible = false; getList(); } const handleCode = ()=>{ visibleCode.value = true } /** 下载按钮操作 */ const handleDownload = (row: OssVO) => { proxy?.$download.oss(row.ossId)