diff --git a/web-api/src/main/java/com/jeesite/modules/app/utils/DateUtils.java b/web-api/src/main/java/com/jeesite/modules/app/utils/DateUtils.java deleted file mode 100644 index 044bc668..00000000 --- a/web-api/src/main/java/com/jeesite/modules/app/utils/DateUtils.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.jeesite.modules.app.utils; - - -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.Date; - -public class DateUtils { - - -} diff --git a/web-api/src/main/java/com/jeesite/modules/app/utils/FileDownloadUtils.java b/web-api/src/main/java/com/jeesite/modules/app/utils/FileDownloadUtils.java index 0c45944b..39745991 100644 --- a/web-api/src/main/java/com/jeesite/modules/app/utils/FileDownloadUtils.java +++ b/web-api/src/main/java/com/jeesite/modules/app/utils/FileDownloadUtils.java @@ -42,17 +42,12 @@ public class FileDownloadUtils { // 1. 构建完整文件路径 Path fullFilePath = Paths.get(orgFileName); File file = fullFilePath.toFile(); - // 2. 校验文件合法性 validateFile(file); - // 3. 清理并编码文件名(避免特殊字符导致的解析异常) String encodedFileName = encodeFileName(fileName); - // 4. 设置响应头(核心修复:解决下划线/乱码问题) setDownloadResponseHeader(response, encodedFileName, file.length()); - - // 5. 读取文件并写入响应输出流(try-with-resources自动关闭流) try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(fullFilePath)); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) { FileCopyUtils.copy(inputStream, outputStream); @@ -74,16 +69,12 @@ public class FileDownloadUtils { // 1. 构建完整文件路径 Path fullFilePath = Paths.get(orgFileName); File file = fullFilePath.toFile(); - // 2. 校验文件合法性 validateFile(file); - // 3. 读取文件字节数组 byte[] fileBytes = Files.readAllBytes(fullFilePath); - // 4. 清理并编码文件名 String encodedFileName = encodeFileName(fileName); - HttpHeaders headers = new HttpHeaders(); // 核心修复:使用RFC 5987标准,移除多余双引号,避免下划线问题 headers.set(HttpHeaders.CONTENT_DISPOSITION, @@ -149,14 +140,8 @@ public class FileDownloadUtils { * @return 编码后的文件名 */ private static String encodeFileName(String fileName) { - try { - // 修复:将空格编码为%20而非+,避免浏览器解析为下划线 - return URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()) - .replace("+", "%20"); - } catch (UnsupportedEncodingException e) { - // 理论上UTF-8不会抛出此异常,兜底返回原文件名 - return fileName; - } + return URLEncoder.encode(fileName, StandardCharsets.UTF_8) + .replace("+", "%20"); } } \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/app/utils/MailSendUtils.java b/web-api/src/main/java/com/jeesite/modules/app/utils/MailSendUtils.java index aad23e77..8a8fb689 100644 --- a/web-api/src/main/java/com/jeesite/modules/app/utils/MailSendUtils.java +++ b/web-api/src/main/java/com/jeesite/modules/app/utils/MailSendUtils.java @@ -14,7 +14,7 @@ import java.util.concurrent.Executors; public class MailSendUtils { private static final ExecutorService MAIL_EXECUTOR = Executors.newFixedThreadPool(5); - private static String FILE_PATH = "/ogsapp/files"; + private static final String FILE_PATH = "/ogsapp/files"; /** * 同步发送HTML格式邮件 diff --git a/web-api/src/main/java/com/jeesite/modules/app/utils/MyFileUtils.java b/web-api/src/main/java/com/jeesite/modules/app/utils/MyFileUtils.java new file mode 100644 index 00000000..1fd4ea22 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/app/utils/MyFileUtils.java @@ -0,0 +1,48 @@ +package com.jeesite.modules.app.utils; + +import java.nio.file.*; +import java.text.DecimalFormat; + +public class MyFileUtils { + + private static final long UNIT_BASE = 1024; + private static final String[] UNITS = {"B", "KB", "MB", "GB", "TB"}; + + private static final LoggerUtils logger = LoggerUtils.getInstance(); + + + public static String formatFileSize(long sizeInBytes, int decimalPlaces) { + if (sizeInBytes == 0) { + return "0 " + UNITS[0]; + } + + long absSize = Math.abs(sizeInBytes); + String negativeFlag = sizeInBytes < 0 ? "-" : ""; + + int validDecimalPlaces = Math.max(0, Math.min(decimalPlaces, 4)); + String formatPattern = validDecimalPlaces == 0 ? "#0" : "#0." + "0".repeat(validDecimalPlaces); + DecimalFormat df = new DecimalFormat(formatPattern); + + int unitIndex = 0; + double formattedSize = absSize; + while (formattedSize >= UNIT_BASE && unitIndex < UNITS.length - 1) { + formattedSize /= UNIT_BASE; + unitIndex++; + } + + return negativeFlag + df.format(formattedSize) + " " + UNITS[unitIndex]; + } + + public static void moveFile(String sourceName, String targetName, boolean overwrite) { + try { + Path sourcePath = Paths.get(sourceName); + Path targetPath = Paths.get(targetName); + CopyOption[] options = overwrite + ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE} + : new CopyOption[]{StandardCopyOption.ATOMIC_MOVE}; + Files.move(sourcePath, targetPath, options); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } +} diff --git a/web-api/src/main/java/com/jeesite/modules/app/utils/vId.java b/web-api/src/main/java/com/jeesite/modules/app/utils/vId.java index a596096f..e8575bf4 100644 --- a/web-api/src/main/java/com/jeesite/modules/app/utils/vId.java +++ b/web-api/src/main/java/com/jeesite/modules/app/utils/vId.java @@ -32,4 +32,17 @@ public class vId { long rand = Math.abs(RAND.nextLong()) % (long) Math.pow(3, 6); return tm + String.format("%04d", rand); } + + public static long getLongId() { + String tm = LocalDateTime.now().format(DF); + int rand = RAND.nextInt(100); + String randStr = String.format("%02d", rand); + String cidStr = tm + randStr; + try { + return Long.parseLong(cidStr); + } catch (NumberFormatException e) { + // 兜底处理:若意外超出范围,抛出明确异常 + throw new RuntimeException("生成的CID超出long类型范围:" + cidStr, e); + } + } } diff --git a/web-api/src/main/java/com/jeesite/modules/biz/web/BizFoldersController.java b/web-api/src/main/java/com/jeesite/modules/biz/web/BizFoldersController.java index 53e9f3e1..e7d32a9f 100644 --- a/web-api/src/main/java/com/jeesite/modules/biz/web/BizFoldersController.java +++ b/web-api/src/main/java/com/jeesite/modules/biz/web/BizFoldersController.java @@ -139,6 +139,12 @@ public class BizFoldersController extends BaseController { return renderResult(Global.TRUE, text("删除文件夹信息成功!")); } + @RequestMapping(value = "listAll") + @ResponseBody + public List listAll(BizFolders bizFolders) { + return bizFoldersService.findList(bizFolders); + } + @RequestMapping(value = "foldersAll") @ResponseBody public List foldersAll(BizFolders bizFolders) { diff --git a/web-api/src/main/java/com/jeesite/modules/biz/web/BizMyfilesController.java b/web-api/src/main/java/com/jeesite/modules/biz/web/BizMyfilesController.java index 872e0410..a729d1db 100644 --- a/web-api/src/main/java/com/jeesite/modules/biz/web/BizMyfilesController.java +++ b/web-api/src/main/java/com/jeesite/modules/biz/web/BizMyfilesController.java @@ -1,7 +1,12 @@ package com.jeesite.modules.biz.web; +import java.util.Date; import java.util.List; +import cn.hutool.core.net.multipart.UploadFile; +import com.jeesite.modules.app.utils.MyFileUtils; +import com.jeesite.modules.app.utils.vId; +import com.jeesite.modules.file.entity.FileUpload; import com.jeesite.modules.file.utils.FileUploadUtils; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -36,6 +41,8 @@ import com.jeesite.modules.biz.service.BizMyfilesService; @RequestMapping(value = "${adminPath}/biz/myfiles") public class BizMyfilesController extends BaseController { + private static final String FILE_PATH = "/ogsapp/files"; + private final BizMyfilesService bizMyfilesService; public BizMyfilesController(BizMyfilesService bizMyfilesService) { @@ -85,8 +92,19 @@ public class BizMyfilesController extends BaseController { @PostMapping(value = "save") @ResponseBody public String save(@Validated BizMyfiles bizMyfiles) { -// bizMyfilesService.save(bizMyfiles); FileUploadUtils.saveFileUpload(bizMyfiles, bizMyfiles.getId(), "bizMyfiles_file"); + List fileList = FileUploadUtils.findFileUpload(bizMyfiles.getId(), "bizMyfiles_file"); + for (FileUpload fileUpload : fileList) { + bizMyfiles.setCreateTime(new Date()); + bizMyfiles.setTid(vId.getLongId()); + bizMyfiles.setFileName(fileUpload.getFileName()); + bizMyfiles.setFilePath(FILE_PATH + fileUpload.getFileUrl()); + bizMyfiles.setFileHash(fileUpload.getFileEntity().getFileMd5()); + bizMyfiles.setFileSize(MyFileUtils.formatFileSize(fileUpload.getFileEntity().getFileSize(), 2)); + bizMyfiles.setFileExt(fileUpload.getFileEntity().getFileExtension()); + bizMyfiles.setMimeType(fileUpload.getFileEntity().getFileContentType()); + bizMyfilesService.save(bizMyfiles); + } return renderResult(Global.TRUE, text("保存文件信息成功!")); } diff --git a/web-vue/packages/biz/api/biz/folders.ts b/web-vue/packages/biz/api/biz/folders.ts index 98b7f65d..7905835d 100644 --- a/web-vue/packages/biz/api/biz/folders.ts +++ b/web-vue/packages/biz/api/biz/folders.ts @@ -37,7 +37,10 @@ export interface FolderItem { export const bizFoldersList = (params?: BizFolders | any) => defHttp.get({ url: adminPath + '/biz/folders/list', params }); - + +export const bizFoldersListAll = (params?: BizFolders | any) => + defHttp.get({ url: adminPath + '/biz/folders/listAll', params }); + export const bizFolderItemAll = (params?: BizFolders | any) => defHttp.get({ url: adminPath + '/biz/folders/foldersAll', params }); diff --git a/web-vue/packages/biz/views/biz/municipalities/form.vue b/web-vue/packages/biz/views/biz/municipalities/form.vue index 6d704ba5..adf94742 100644 --- a/web-vue/packages/biz/views/biz/municipalities/form.vue +++ b/web-vue/packages/biz/views/biz/municipalities/form.vue @@ -51,11 +51,11 @@ field: 'provinceCode', component: 'Select', componentProps: { - api: bizProvinceListAll, - params: {}, - fieldNames: { label: 'provinceName', value: 'provinceCode' }, - immediate: true, - allowClear: true, + api: bizProvinceListAll, + params: {}, + fieldNames: { label: 'provinceName', value: 'provinceCode' }, + immediate: true, + allowClear: true, onChange: (value: string) => { provListParams.value.provinceCode = value; }, diff --git a/web-vue/packages/core/layouts/views/desktop/analysis/components/DynamicInfo.vue b/web-vue/packages/core/layouts/views/desktop/analysis/components/DynamicInfo.vue index 0f306b63..4909d5b0 100644 --- a/web-vue/packages/core/layouts/views/desktop/analysis/components/DynamicInfo.vue +++ b/web-vue/packages/core/layouts/views/desktop/analysis/components/DynamicInfo.vue @@ -119,8 +119,8 @@ export default defineComponent({ return { listData, - register, - openModal, + register, + openModal, getUsageClass, getProgressClass, }; diff --git a/web-vue/packages/core/layouts/views/desktop/myfiles/components/upload.vue b/web-vue/packages/core/layouts/views/desktop/myfiles/components/upload.vue index fc4427de..8810f707 100644 --- a/web-vue/packages/core/layouts/views/desktop/myfiles/components/upload.vue +++ b/web-vue/packages/core/layouts/views/desktop/myfiles/components/upload.vue @@ -17,8 +17,10 @@ import { BasicForm, FormSchema, useForm } from '@jeesite/core/components/Form'; import { useMessage } from '@jeesite/core/hooks/web/useMessage'; import { BasicModal, useModalInner } from '@jeesite/core/components/Modal'; + import { BizMyfiles, bizMyfilesSave, bizMyfilesForm } from '@jeesite/biz/api/biz/myfiles'; - + import { FolderItem, bizFoldersListAll } from '@jeesite/biz/api/biz/folders'; + export default defineComponent({ components: { BasicModal, BasicForm }, emits: ['modalClose'], @@ -29,28 +31,56 @@ const record = ref({} as BizMyfiles); const inputFormSchemas: FormSchema[] = [ + { + label: t('上级目录'), + field: 'parentId', + component: 'Select', + componentProps: { + api: bizFoldersListAll, + params: { parentId : '0' }, + fieldNames: { label: 'folderName', value: 'folderId' }, + immediate: true, + allowClear: true, + }, + required: true, + dynamicDisabled: true, + }, { - label: t('文件夹标识'), + label: t('目录名称'), field: 'folderId', - component: 'Input', + component: 'Select', componentProps: { - maxlength: 52, + api: bizFoldersListAll, + params: {}, + fieldNames: { label: 'folderName', value: 'folderId' }, + immediate: true, + allowClear: true, }, - required: true, - dynamicDisabled: true, + required: true, + dynamicDisabled: true, }, + { + label: t('用户编码'), + field: 'loginCode', + component: 'Input', + componentProps: { + maxlength: 52, + }, + required: true, + dynamicDisabled: true, + }, + { + label: t('用户名称'), + field: 'userName', + component: 'Input', + componentProps: { + maxlength: 52, + }, + required: true, + dynamicDisabled: true, + }, { - label: t('文件夹名称'), - field: 'folderName', - component: 'Input', - componentProps: { - maxlength: 52, - }, - required: true, - dynamicDisabled: true, - }, - { - label: t('附件上传'), + label: t('上传文件'), field: 'dataMap', component: 'Upload', componentProps: { @@ -59,6 +89,7 @@ bizType: 'bizMyfiles_file', uploadType: 'all', }, + required: true, colProps: { md: 24, lg: 24 }, }, ]; @@ -72,36 +103,40 @@ const { createMessage } = useMessage(); - const [register, { closeModal }] = useModalInner(async (data: any) => { - const dddd = { - ... data - } - console.log(dddd) - resetFields(); + const [register, { setModalProps, closeModal }] = useModalInner(async (data: any) => { + setModalProps({ loading: true }); + await resetFields(); + record.value = (data || {}) as BizMyfiles; + record.value.__t = new Date().getTime(); if (data) { - setFieldsValue({ ...data }); + await setFieldsValue(record.value); } + setModalProps({ loading: false }); }); async function handleSubmit() { try { const data = await validate(); + setModalProps({ confirmLoading: true }); const params: any = { isNewRecord: true, + tid : Date.now(), }; const res = await bizMyfilesSave(params, data); showMessage(res.message); - handleCancel(data); + handleCancel(); } catch (error: any) { console.error('上传文件保存失败:', error); - } + } finally { + setModalProps({ confirmLoading: false }); + } } // 取消按钮逻辑 - const handleCancel = (data: any) => { - resetFields(); // 取消时重置表单 - emit('modalClose',data); - closeModal(); // 关闭模态框 + const handleCancel = () => { + resetFields(); + emit('modalClose'); + closeModal(); }; return { @@ -110,11 +145,11 @@ handleCancel, registerForm, inputFormSchemas, - handleSubmit + handleSubmit, }; }, }); \ No newline at end of file + diff --git a/web-vue/packages/core/layouts/views/desktop/myfiles/index.vue b/web-vue/packages/core/layouts/views/desktop/myfiles/index.vue index 7e355745..bd34fb93 100644 --- a/web-vue/packages/core/layouts/views/desktop/myfiles/index.vue +++ b/web-vue/packages/core/layouts/views/desktop/myfiles/index.vue @@ -68,8 +68,8 @@ v-model:value="fileSearchText" placeholder="文件搜索框" class="file-search-input" - enter-button - @search="onSearch" + enter-button + @search="onSearch" />
新建文件夹 @@ -88,7 +88,7 @@
- 📄 + {{ file.fileName }}
{{ file.fileSize }} @@ -105,7 +105,7 @@
- + @@ -121,6 +121,10 @@ import FolderModal from './components/folder.vue'; import { FolderItem, bizFolderItemAll } from '@jeesite/biz/api/biz/folders'; import { BizMyfiles, bizMyfilesListAll } from '@jeesite/biz/api/biz/myfiles'; +import { useUserStore } from '@jeesite/core/store/modules/user'; +const userStore = useUserStore(); +const userinfo = computed(() => userStore.getUserInfo); + const [uploadregister, { openModal: openUploadModal }] = useModal(); const [folderregister, { openModal: openfolderModal }] = useModal(); @@ -217,34 +221,47 @@ watch(folderSearchText, (newVal) => { searchAndExpandParents(newVal); }); -const getDataList = async () => { +const getDataList = async (params: {}) => { try { - const result = await bizFolderItemAll(); + const reqParams = { + ... params, + loginCode :userinfo.value.loginCode, + } + const result = await bizFolderItemAll(reqParams); const folders = (result || []) as FolderItem[]; folders.forEach(folder => { folder.expanded = false; }); bindParentReferences(folders); // 绑定父级引用 folderList.value = folders; - getFileList({}); + getFileList({}); } catch (error) { console.error('获取文件夹信息失败:', error); folderList.value = []; } }; + + const getFileList = async (params: {}) => { try { - const result = await bizMyfilesListAll(params); - fileList.value = result || []; + const reqParams = { + ... params, + folderId: ParamsFolders?.value?.folderId || '', + loginCode :userinfo.value.loginCode, + } + const result = await bizMyfilesListAll(reqParams); + fileList.value = result || []; } catch (error) { - console.error('获取文件信息失败:', error); - fileList.value = []; + console.error('获取文件信息失败:', error); + fileList.value = []; } }; const onSearch = (searchValue: string) => { + UploadFile = true; + ParamsFolders.value = {}; const params = { fileName: searchValue, } @@ -275,6 +292,8 @@ const handleChildClick = (child: ChildFolder) => { ParamsFolders.value = child; const params = { folderId: child.id, + userName: userinfo.value.userName, + loginCode :userinfo.value.loginCode, } getFileList(params); }; @@ -289,7 +308,7 @@ watch(folderSearchText, () => { }); onMounted(() => { - getDataList(); + getDataList({}); }); @@ -687,4 +706,4 @@ onMounted(() => { * { box-sizing: border-box; } - \ No newline at end of file +