diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b214862 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,420 @@ +{ + "name": "yunzer_go", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "docx-preview": "^0.3.7", + "vue3-pdf-app": "^1.0.3" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT", + "peer": true + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.22", + "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.22.tgz", + "integrity": "sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/parser": "^7.28.4", + "@vue/shared": "3.5.22", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.22", + "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.22.tgz", + "integrity": "sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/compiler-core": "3.5.22", + "@vue/shared": "3.5.22" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.22", + "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.22.tgz", + "integrity": "sha512-tbTR1zKGce4Lj+JLzFXDq36K4vcSZbJ1RBu8FxcDv1IGRz//Dh2EBqksyGVypz3kXpshIfWKGOCcqpSbyGWRJQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/parser": "^7.28.4", + "@vue/compiler-core": "3.5.22", + "@vue/compiler-dom": "3.5.22", + "@vue/compiler-ssr": "3.5.22", + "@vue/shared": "3.5.22", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.19", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.22", + "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.22.tgz", + "integrity": "sha512-GdgyLvg4R+7T8Nk2Mlighx7XGxq/fJf9jaVofc3IL0EPesTE86cP/8DD1lT3h1JeZr2ySBvyqKQJgbS54IX1Ww==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/compiler-dom": "3.5.22", + "@vue/shared": "3.5.22" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.22", + "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.22.tgz", + "integrity": "sha512-f2Wux4v/Z2pqc9+4SmgZC1p73Z53fyD90NFWXiX9AKVnVBEvLFOWCEgJD3GdGnlxPZt01PSlfmLqbLYzY/Fw4A==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/shared": "3.5.22" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.22", + "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.22.tgz", + "integrity": "sha512-EHo4W/eiYeAzRTN5PCextDUZ0dMs9I8mQ2Fy+OkzvRPUYQEyK9yAjbasrMCXbLNhF7P0OUyivLjIy0yc6VrLJQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/reactivity": "3.5.22", + "@vue/shared": "3.5.22" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.22", + "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.22.tgz", + "integrity": "sha512-Av60jsryAkI023PlN7LsqrfPvwfxOd2yAwtReCjeuugTJTkgrksYJJstg1e12qle0NarkfhfFu1ox2D+cQotww==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/reactivity": "3.5.22", + "@vue/runtime-core": "3.5.22", + "@vue/shared": "3.5.22", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.22", + "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.22.tgz", + "integrity": "sha512-gXjo+ao0oHYTSswF+a3KRHZ1WszxIqO7u6XwNHqcqb9JfyIL/pbWrrh/xLv7jeDqla9u+LK7yfZKHih1e1RKAQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/compiler-ssr": "3.5.22", + "@vue/shared": "3.5.22" + }, + "peerDependencies": { + "vue": "3.5.22" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.22", + "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.22.tgz", + "integrity": "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==", + "license": "MIT", + "peer": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT", + "peer": true + }, + "node_modules/docx-preview": { + "version": "0.3.7", + "resolved": "https://registry.npmmirror.com/docx-preview/-/docx-preview-0.3.7.tgz", + "integrity": "sha512-Lav69CTA/IYZPJTsKH7oYeoZjyg96N0wEJMNslGJnZJ+dMUZK85Lt5ASC79yUlD48ecWjuv+rkcmFt6EVPV0Xg==", + "license": "Apache-2.0", + "dependencies": { + "jszip": ">=3.0.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT", + "peer": true + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC", + "peer": true + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.22", + "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.22.tgz", + "integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/compiler-dom": "3.5.22", + "@vue/compiler-sfc": "3.5.22", + "@vue/runtime-dom": "3.5.22", + "@vue/server-renderer": "3.5.22", + "@vue/shared": "3.5.22" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue3-pdf-app": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/vue3-pdf-app/-/vue3-pdf-app-1.0.3.tgz", + "integrity": "sha512-qegWTIF4wYKiocZ3KreB70wRXhqSdXWbdERDyyKzT7d5PbjKbS9tD6vaKkCqh3PzTM84NyKPYrQ3iuwJb60YPQ==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.0.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..4bfae15 --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "docx-preview": "^0.3.7", + "vue3-pdf-app": "^1.0.3" + } +} diff --git a/pc/src/api/file.js b/pc/src/api/file.js index 0fe41ae..a277bd7 100644 --- a/pc/src/api/file.js +++ b/pc/src/api/file.js @@ -98,3 +98,42 @@ export function searchFiles(keyword) { params: { keyword }, }); } + +/** + * 下载文件 + * @param {number|string} id 文件ID + * @returns {string} 下载URL + */ +export function downloadFile(id) { + return `/api/files/download/${id}`; +} + +/** + * 预览文件 + * @param {number|string} id 文件ID + * @returns {string} 预览URL + */ +export function previewFile(id) { + return `/api/files/preview/${id}`; +} + +/** + * 检查文件是否可预览 + * @param {string} fileExt 文件扩展名 + * @returns {boolean} + */ +export function canPreview(fileExt) { + const previewableExts = [ + // 图片格式 + '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg', + // 文档格式 + '.pdf', '.txt', + // Office文档格式(仅支持 .docx,不支持旧的 .doc、Excel、PPT) + '.docx', + // 视频格式 + '.mp4', '.webm', + // 音频格式 + '.mp3', '.wav' + ]; + return previewableExts.includes(fileExt.toLowerCase()); +} \ No newline at end of file diff --git a/pc/src/api/user.js b/pc/src/api/user.js index fae3459..9c43526 100644 --- a/pc/src/api/user.js +++ b/pc/src/api/user.js @@ -16,6 +16,14 @@ export function getUserInfo(userId) { }); } +//获取租户用户信息 +export function getTenantUsers(tenantId) { + return request({ + url: `/api/tenantUsers/${tenantId}`, + method: 'get', + }); +} + // 添加用户 export function addUser(data) { return request({ diff --git a/pc/src/views/Main.vue b/pc/src/views/Main.vue index 8f1d2a2..77d4609 100644 --- a/pc/src/views/Main.vue +++ b/pc/src/views/Main.vue @@ -4,7 +4,7 @@ import CommonHeader from '@/components/CommonHeader.vue'; import { useTabsStore } from '@/stores'; import { useRouter, useRoute } from 'vue-router'; import { ref, watch, reactive, nextTick, onMounted, computed } from 'vue'; -import { More, Close, CircleClose } from '@element-plus/icons-vue' +import { More, Close, CircleClose, ArrowUp } from '@element-plus/icons-vue' const tabsStore = useTabsStore(); const router = useRouter(); @@ -451,6 +451,15 @@ const canCloseRight = computed(() => { + + + + + + + + + @@ -606,6 +615,31 @@ const canCloseRight = computed(() => { :deep(.el-menu){ border-right: none !important; } + +// 回到顶部按钮样式 +.backtop-button { + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + background: var(--el-color-primary); + color: #fff; + border-radius: 50%; + box-shadow: 0 4px 12px rgba(64, 129, 255, 0.4); + transition: all 0.3s ease; + cursor: pointer; + + &:hover { + background: var(--el-color-primary-light-3); + box-shadow: 0 6px 16px rgba(64, 129, 255, 0.5); + transform: translateY(-2px); + } + + &:active { + transform: translateY(0); + } +} + diff --git a/pc/src/views/system/files/FileList.vue b/pc/src/views/system/files/FileList.vue new file mode 100644 index 0000000..d4a9cf2 --- /dev/null +++ b/pc/src/views/system/files/FileList.vue @@ -0,0 +1,909 @@ + + + + + + + + + + + + + + + + + 快速上传 + + + + + 刷新 + + + + + + + + + + + + {{ row.original_name }} + + + + + + {{ row.file_type }} + + + + + {{ formatFileSize(row.file_size) }} + + + + + {{ row.category }} + + + + + + {{ formatDate(row.upload_time) }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ previewFile?.original_name || '文件预览' }} + + + + + + + + + + + + + + + + + + + + + + + {{ getOfficeFileTypeName(previewFile.file_ext) }} 文件暂不支持在线预览 + + + 下载文件 + + + + + + 该文件类型不支持在线预览 + + + 下载文件 + + + + + + + + + + + + + 将文件拖到此处,或点击上传 + + + + 支持批量上传,单文件大小不超过 + 10MB + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pc/src/views/system/files/FileUpload.vue b/pc/src/views/system/files/FileUpload.vue new file mode 100644 index 0000000..ca1c01f --- /dev/null +++ b/pc/src/views/system/files/FileUpload.vue @@ -0,0 +1,539 @@ + + + + + + + + + + 将文件拖到此处,或点击选择文件 + + + + 支持批量上传,单个文件大小不超过 + 10MB + ,支持拖拽排序 + + + + + + + + + + + 上传设置 + + + + + + + + + + + + + + + + 开启后选择文件即自动上传 + + + + + + + + + + + 待上传文件列表({{ fileList.length }}个文件) + + 清空列表 + + + + + + + + + {{ formatFileSize(row.size) }} + + + + + {{ getFileType(row.name) }} + + + + + + {{ getStatusText(row.status) }} + + + + + + + 移除 + + + + + + + + + {{ uploading ? '上传中...' : '开始上传' }} + + + + + + + + + + 上传进度 + + + + 已上传: {{ uploadedCount }}/{{ totalCount }} + 成功: {{ successCount }} 个 + 失败: {{ failedCount }} 个 + 成功率: {{ successRate }}% + + + + + + + + + 支持批量拖拽上传文件 + 单个文件大小不超过 10MB + 支持的文件类型:图片、文档、视频、音频等 + 建议先选择分类再上传文件 + 上传大文件时请保持网络稳定 + + + + + + + + + + diff --git a/pc/src/views/system/files/categories.vue b/pc/src/views/system/files/category.vue similarity index 100% rename from pc/src/views/system/files/categories.vue rename to pc/src/views/system/files/category.vue diff --git a/pc/src/views/system/files/index.vue b/pc/src/views/system/files/index.vue index 921a53a..a3e082a 100644 --- a/pc/src/views/system/files/index.vue +++ b/pc/src/views/system/files/index.vue @@ -1,872 +1,130 @@ - - - 文件管理 - - - - - 正在加载程序数据... - - - - - - 重试 - - - - - - - - - - - - - - 文件列表 - 查看和管理所有文件 - - - - - - - - - - - - 批量上传 - 批量上传文件至系统 - - - - - - - - - - - - 分类管理 - 管理分类/标签 - - - - - + + + + + + 文件管理系统 + + - - - - - - - - - - - - - - - - - - - - - - - {{ row.file_name }} - - - - - - - {{ row.category }} - - - - - {{ - formatFileSize(row.file_size) - }} - - - - - - - {{ - formatDate(row.upload_time) - }} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 将文件拖到此处,或点击上传 - - - - 支持单个或批量上传,单文件大小不超过 - 10MB - - - - - - - - - - - - - - - - - - - - - - - 取 消 - 上传 + + + + + + + + 文件列表 - + + - - - - - - {{ currentFile.id }} - - - {{ currentFile.file_name }} - - {{ - currentFile.original_name - }} - - {{ - formatFileSize(currentFile.file_size) - }} - - {{ - currentFile.file_type - }} - {{ - currentFile.file_ext - }} - - {{ - currentFile.category - }} - - - {{ currentFile.upload_by }} - - {{ - formatDate(currentFile.upload_time) - }} - - - {{ currentFile.status === 1 ? "正常" : "已删除" }} - - - - - {{ currentFile.is_public === 1 ? "公开" : "私有" }} - - - - - - - 下载文件 - - - 复制链接 - - - - - - - 关闭 + + + + + + 批量上传 - - + + + + + + + + + 分类管理 + + + + + diff --git a/pc/src/views/system/menus/manager.vue b/pc/src/views/system/menus/manager.vue index aa02e29..ddef715 100644 --- a/pc/src/views/system/menus/manager.vue +++ b/pc/src/views/system/menus/manager.vue @@ -145,8 +145,8 @@ 权限按钮 - • 页面菜单:有路由和组件地址,可访问完整功能页面 - • 目录菜单:只有路由地址,用于组织结构,无实际页面 + • 页面菜单:有路由和组件地址,用于页面管理 + • 目录菜单:只有路由地址,用于接口管理和目录管理 • 权限按钮:无路由和组件,仅用于权限控制 diff --git a/pc/src/views/system/users/index.vue b/pc/src/views/system/users/index.vue index 9b953fa..0fefe78 100644 --- a/pc/src/views/system/users/index.vue +++ b/pc/src/views/system/users/index.vue @@ -128,7 +128,7 @@ { const fetchUsers = async () => { loading.value = true; + // 传tenantid给接口 + let tenantId = getCurrentTenantId ? getCurrentTenantId() : null; try { - const res = await getAllUsers(); + const res = await getTenantUsers(tenantId); // 兼容接口返回的数据结构 let userList: any[] = []; if (Array.isArray(res)) { @@ -286,14 +289,12 @@ const fetchUsers = async () => { users.value = userList.map((item: any) => { // 查找角色名称 let roleName = ''; - let roleId = item.role_id || item.roleId || null; - if (roleId) { - const role = roleList.value.find(r => r.roleId === roleId); - roleName = role ? role.roleName : ''; - } else if (item.role) { - // 兼容旧的role字段,尝试从roleList中查找 - const role = roleList.value.find(r => r.roleCode === item.role); - roleName = role ? role.roleName : (item.role === 'admin' ? '管理员' : '普通用户'); + let roleValue = item.role || null; // role 字段存储的是角色ID(数字) + + if (roleValue) { + // 通过角色ID查找角色信息 + const roleInfo = roleList.value.find(r => r.roleId === roleValue); + roleName = roleInfo ? roleInfo.roleName : ''; } return { @@ -301,8 +302,7 @@ const fetchUsers = async () => { username: item.username, nickname: item.nickname, email: item.email, - role: item.role || '', - roleId: roleId, + role: roleValue, // role 字段存储角色ID roleName: roleName, status: item.status || "active", lastLoginTime: item.lastLoginTime @@ -343,13 +343,12 @@ const dialogVisible = ref(false); const dialogTitle = ref(""); const isEdit = ref(false); const form = ref({ - id: 0, + id: null, username: "", nickname: "", password: "", email: "", - roleId: null, - role: "", + role: null, // role 字段存储角色ID status: "active", tenant_id: null, }); @@ -397,13 +396,12 @@ const handleAddUser = () => { } form.value = { - id: 0, + id: 0, // 添加用户时ID为0 username: "", nickname: "", password: "", email: "", - roleId: null, - role: "", + role: null, // role 字段存储角色ID status: "active", tenant_id: tenantId, }; @@ -420,12 +418,15 @@ const handleEdit = async (user: User) => { // 获取当前租户ID const tenantId = getCurrentTenantId(); - // 处理角色ID,兼容旧数据 - let roleId = data.role_id || data.roleId || null; - if (!roleId && data.role) { - // 如果只有role代码,尝试从roleList中查找对应的roleId - const role = roleList.value.find(r => r.roleCode === data.role); - roleId = role ? role.roleId : null; + // 处理角色:data.role 存储的是角色ID(数字) + let roleValue = data.role || null; + + // 处理状态:后端返回的是数字(0或1),前端使用字符串("active"或"inactive") + let statusStr = "active"; + if (typeof data.status === 'number') { + statusStr = data.status === 1 ? "active" : "inactive"; + } else if (typeof data.status === 'string') { + statusStr = data.status; } form.value = { @@ -434,9 +435,8 @@ const handleEdit = async (user: User) => { nickname: data.nickname, password: "", email: data.email, - roleId: roleId, - role: data.role || "", - status: data.status || "active", + role: roleValue, // role 字段存储角色ID + status: statusStr, tenant_id: data.tenant_id || tenantId, }; } catch (e) { @@ -502,25 +502,31 @@ const submitForm = async () => { passwordError.value = res.message || "密码修改失败"; } } else if (isEdit.value) { - // 构建提交数据,优先使用roleId + // 检查ID是否存在 + if (!form.value.id || form.value.id === 0) { + ElMessage.error("用户ID不能为空,请重新选择用户"); + return; + } + + // 构建提交数据 const submitData: any = { + id: form.value.id, username: form.value.username, nickname: form.value.nickname, email: form.value.email, status: form.value.status, }; - if (form.value.roleId) { - submitData.roleId = form.value.roleId; - } else if (form.value.role) { - // 兼容旧数据,如果没有roleId但有role代码,也传递 - submitData.role = form.value.role; + // role 字段存储角色ID + if (form.value.role) { + submitData.role = form.value.role; // 后端接收 role 参数 } if (form.value.tenant_id) { submitData.tenant_id = form.value.tenant_id; } + console.log('编辑用户提交数据:', submitData); // 调试日志 await editUser(form.value.id, submitData); ElMessage.success({ message: "更新成功", @@ -533,7 +539,7 @@ const submitForm = async () => { dialogVisible.value = false; fetchUsers(); } else { - // 构建提交数据,优先使用roleId + // 构建提交数据 const submitData: any = { username: form.value.username, nickname: form.value.nickname, @@ -542,16 +548,16 @@ const submitForm = async () => { status: form.value.status, }; - if (form.value.roleId) { - submitData.roleId = form.value.roleId; - } else if (form.value.role) { - submitData.role = form.value.role; + // role 字段存储角色ID + if (form.value.role) { + submitData.role = form.value.role; // 后端接收 role 参数 } if (form.value.tenant_id) { submitData.tenant_id = form.value.tenant_id; } + console.log('添加用户提交数据:', submitData); // 调试日志 await addUser(submitData); ElMessage.success({ message: "添加成功", diff --git a/server/controllers/file.go b/server/controllers/file.go index 276c972..2e78d2e 100644 --- a/server/controllers/file.go +++ b/server/controllers/file.go @@ -1,7 +1,12 @@ package controllers import ( + "crypto/md5" + "encoding/hex" "encoding/json" + "io" + "net/http" + "net/url" "os" "path" "path/filepath" @@ -455,6 +460,12 @@ func (c *FileController) Post() { username = "unknown" } + // 从JWT中间件获取租户ID + tenantID := "default" + if tid, ok := c.Ctx.Input.GetData("tenantId").(int); ok && tid > 0 { + tenantID = strconv.Itoa(tid) + } + // 获取上传的文件 file, header, err := c.GetFile("file") if err != nil { @@ -473,18 +484,91 @@ func (c *FileController) Post() { fileExt := strings.ToLower(filepath.Ext(originalName)) fileName := strings.TrimSuffix(originalName, fileExt) + // 读取文件内容到内存以计算MD5(对于大文件可能需要优化) + fileData := make([]byte, fileSize) + n, err := file.Read(fileData) + if err != nil && err != io.EOF { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "读取文件失败: " + err.Error(), + } + c.ServeJSON() + return + } + if int64(n) != fileSize { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "读取文件不完整", + } + c.ServeJSON() + return + } + + // 计算文件MD5值 + hash := md5.New() + hash.Write(fileData) + fileMD5 := hex.EncodeToString(hash.Sum(nil)) + + // 检查是否已存在相同MD5的文件 + existingFile, err := models.GetFileByMD5AndTenant(fileMD5, tenantID) + if err == nil && existingFile != nil { + // 文件已存在,不保存文件,只创建数据库记录 + // 生成日期路径(年/月/日) + now := time.Now() + + // 创建文件信息记录(使用已存在的文件路径) + fileInfo := models.FileInfo{ + TenantID: tenantID, + UserID: userID, + FileName: fileName, + OriginalName: originalName, + FilePath: existingFile.FilePath, // 使用已存在文件的路径 + FileURL: existingFile.FileURL, // 使用已存在文件的URL + FileSize: fileSize, + FileType: getFileTypeByExt(fileExt), + FileExt: fileExt, + MD5: fileMD5, + Category: c.GetString("category"), + Status: 1, + UploadBy: username, + UploadTime: now, + } + + // 如果分类为空,使用默认分类 + if fileInfo.Category == "" { + fileInfo.Category = "未分类" + } + + // 保存到数据库(只保存记录,不保存文件) + id, err := models.AddFile(&fileInfo) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "保存文件信息失败: " + err.Error(), + } + c.ServeJSON() + return + } + + fileInfo.ID = id + + // 返回成功响应 + c.Data["json"] = map[string]interface{}{ + "success": true, + "message": "文件上传成功(重复文件,使用已有文件)", + "data": fileInfo, + } + c.ServeJSON() + return + } + + // 文件不存在,正常上传流程 // 获取分类(可选) category := c.GetString("category") if category == "" { category = "未分类" } - // 获取租户ID(可选,从请求参数或中间件获取) - tenantID := c.GetString("tenant_id") - if tenantID == "" { - tenantID = "default" - } - // 生成日期路径(年/月/日) now := time.Now() datePath := now.Format("2006/01/02") @@ -513,8 +597,8 @@ func (c *FileController) Post() { // 计算相对路径(用于存储到数据库) relativePath := path.Join("uploads", datePath, uniqueFileName) - // 保存文件 - if err := c.SaveToFile("file", savePath); err != nil { + // 保存文件(将已读取的数据写入文件) + if err := os.WriteFile(savePath, fileData, 0644); err != nil { c.Data["json"] = map[string]interface{}{ "success": false, "message": "保存文件失败: " + err.Error(), @@ -524,19 +608,7 @@ func (c *FileController) Post() { } // 获取文件类型 - fileType := "other" - switch fileExt { - case ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp": - fileType = "image" - case ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".txt": - fileType = "document" - case ".mp4", ".avi", ".mov", ".wmv": - fileType = "video" - case ".mp3", ".wav", ".flac": - fileType = "audio" - case ".zip", ".rar", ".7z": - fileType = "archive" - } + fileType := getFileTypeByExt(fileExt) // 构造文件URL(相对路径) fileURL := "/" + relativePath @@ -552,7 +624,9 @@ func (c *FileController) Post() { FileSize: fileSize, FileType: fileType, FileExt: fileExt, + MD5: fileMD5, Category: category, + Status: 1, // 设置为正常状态 UploadBy: username, UploadTime: now, } @@ -580,3 +654,351 @@ func (c *FileController) Post() { } c.ServeJSON() } + +// DownloadFile 下载文件 +func (c *FileController) DownloadFile() { + idStr := c.Ctx.Input.Param(":id") + id, err := strconv.ParseInt(idStr, 10, 64) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "参数错误", + } + c.ServeJSON() + return + } + + // 获取文件信息 + file, err := models.GetFileById(id) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "文件不存在", + } + c.ServeJSON() + return + } + + // 获取实际的文件记录(如果文件不存在,通过MD5查找) + actualFile, err := getActualFile(file) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "获取文件信息失败", + } + c.ServeJSON() + return + } + + // 检查文件是否存在(尝试多个可能的路径) + var filePath string + possiblePaths := []string{ + actualFile.FilePath, // 直接使用相对路径 + filepath.Join("server", actualFile.FilePath), // server目录前缀 + filepath.Join(".", actualFile.FilePath), // 当前目录 + } + + for _, path := range possiblePaths { + if _, err := os.Stat(path); err == nil { + filePath = path + break + } + } + + if filePath == "" { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "文件不存在于服务器", + } + c.ServeJSON() + return + } + + // 设置响应头 + c.Ctx.Output.Header("Content-Description", "File Transfer") + c.Ctx.Output.Header("Content-Type", "application/octet-stream") + c.Ctx.Output.Header("Content-Disposition", "attachment; filename="+url.QueryEscape(actualFile.OriginalName)) + c.Ctx.Output.Header("Content-Transfer-Encoding", "binary") + c.Ctx.Output.Header("Expires", "0") + c.Ctx.Output.Header("Cache-Control", "must-revalidate") + c.Ctx.Output.Header("Pragma", "public") + + // 输出文件 + http.ServeFile(c.Ctx.ResponseWriter, c.Ctx.Request, filePath) +} + +// PreviewFile 预览文件 +func (c *FileController) PreviewFile() { + idStr := c.Ctx.Input.Param(":id") + id, err := strconv.ParseInt(idStr, 10, 64) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "参数错误", + } + c.ServeJSON() + return + } + + // 获取文件信息 + file, err := models.GetFileById(id) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "文件不存在", + } + c.ServeJSON() + return + } + + // 获取实际的文件记录(如果文件不存在,通过MD5查找) + actualFile, err := getActualFile(file) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "获取文件信息失败", + } + c.ServeJSON() + return + } + + // 检查文件是否可预览 + if !actualFile.CanPreview() { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "该文件类型不支持预览", + } + c.ServeJSON() + return + } + + // 检查文件是否存在(尝试多个可能的路径) + var filePath string + possiblePaths := []string{ + actualFile.FilePath, // 直接使用相对路径 + filepath.Join("server", actualFile.FilePath), // server目录前缀 + filepath.Join(".", actualFile.FilePath), // 当前目录 + } + + for _, path := range possiblePaths { + if _, err := os.Stat(path); err == nil { + filePath = path + break + } + } + + if filePath == "" { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "文件不存在于服务器", + } + c.ServeJSON() + return + } + + // 设置正确的 Content-Type + contentType := getContentType(actualFile.FileExt) + c.Ctx.Output.Header("Content-Type", contentType) + c.Ctx.Output.Header("Content-Disposition", "inline; filename="+url.QueryEscape(actualFile.OriginalName)) + + // 打开文件 + fileHandle, err := os.Open(filePath) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "打开文件失败: " + err.Error(), + } + c.ServeJSON() + return + } + defer fileHandle.Close() + + // 复制文件内容到响应 + io.Copy(c.Ctx.ResponseWriter, fileHandle) +} + +// PublicPreviewFile 公开预览文件(用于 Office Online Viewer,无需认证但仅用于预览) +func (c *FileController) PublicPreviewFile() { + idStr := c.Ctx.Input.Param(":id") + id, err := strconv.ParseInt(idStr, 10, 64) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "参数错误", + } + c.ServeJSON() + return + } + + // 获取文件信息 + file, err := models.GetFileById(id) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "文件不存在", + } + c.ServeJSON() + return + } + + // 获取实际的文件记录 + actualFile, err := getActualFile(file) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "获取文件信息失败", + } + c.ServeJSON() + return + } + + // 检查文件是否可预览 + if !actualFile.CanPreview() { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "该文件类型不支持预览", + } + c.ServeJSON() + return + } + + // 检查文件是否存在 + var filePath string + possiblePaths := []string{ + actualFile.FilePath, + filepath.Join("server", actualFile.FilePath), + filepath.Join(".", actualFile.FilePath), + } + + for _, path := range possiblePaths { + if _, err := os.Stat(path); err == nil { + filePath = path + break + } + } + + if filePath == "" { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "文件不存在于服务器", + } + c.ServeJSON() + return + } + + // 设置正确的 Content-Type + contentType := getContentType(actualFile.FileExt) + c.Ctx.Output.Header("Content-Type", contentType) + c.Ctx.Output.Header("Content-Disposition", "inline; filename="+url.QueryEscape(actualFile.OriginalName)) + // 允许跨域访问(Office Online Viewer 需要) + c.Ctx.Output.Header("Access-Control-Allow-Origin", "*") + + // 打开文件 + fileHandle, err := os.Open(filePath) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "success": false, + "message": "打开文件失败: " + err.Error(), + } + c.ServeJSON() + return + } + defer fileHandle.Close() + + // 复制文件内容到响应 + io.Copy(c.Ctx.ResponseWriter, fileHandle) +} + +// getFileTypeByExt 根据文件扩展名获取文件类型 +func getFileTypeByExt(ext string) string { + ext = strings.ToLower(ext) + switch ext { + case ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp": + return "image" + case ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".txt": + return "document" + case ".mp4", ".avi", ".mov", ".wmv": + return "video" + case ".mp3", ".wav", ".flac": + return "audio" + case ".zip", ".rar", ".7z": + return "archive" + default: + return "other" + } +} + +// getContentType 根据文件扩展名获取 Content-Type +func getContentType(ext string) string { + ext = strings.ToLower(ext) + contentTypes := map[string]string{ + // 图片 + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".png": "image/png", + ".gif": "image/gif", + ".bmp": "image/bmp", + ".webp": "image/webp", + ".svg": "image/svg+xml", + // 文档 + ".pdf": "application/pdf", + ".txt": "text/plain; charset=utf-8", + ".doc": "application/msword", + ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ".xls": "application/vnd.ms-excel", + ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ".ppt": "application/vnd.ms-powerpoint", + ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", + // 视频 + ".mp4": "video/mp4", + ".webm": "video/webm", + // 音频 + ".mp3": "audio/mpeg", + ".wav": "audio/wav", + } + + if contentType, ok := contentTypes[ext]; ok { + return contentType + } + return "application/octet-stream" +} + +// getActualFile 获取实际的文件记录(如果当前记录的文件不存在,通过MD5查找唯一文件) +func getActualFile(file *models.FileInfo) (*models.FileInfo, error) { + // 检查当前记录的文件是否存在(尝试多个可能的路径) + possiblePaths := []string{ + file.FilePath, // 直接使用相对路径 + filepath.Join("server", file.FilePath), // server目录前缀 + filepath.Join(".", file.FilePath), // 当前目录 + } + + for _, path := range possiblePaths { + if _, err := os.Stat(path); err == nil { + // 文件存在,返回当前记录 + return file, nil + } + } + + // 文件不存在,通过MD5查找唯一文件 + if file.MD5 == "" { + return file, nil + } + + actualFile, err := models.GetFileByMD5(file.MD5) + if err == nil && actualFile != nil { + // 检查找到的文件是否存在 + possiblePaths = []string{ + actualFile.FilePath, + filepath.Join("server", actualFile.FilePath), + filepath.Join(".", actualFile.FilePath), + } + for _, path := range possiblePaths { + if _, err := os.Stat(path); err == nil { + return actualFile, nil + } + } + } + + // 如果找不到,返回原始记录 + return file, nil +} diff --git a/server/controllers/user.go b/server/controllers/user.go index e1baf2a..5e5c7c8 100644 --- a/server/controllers/user.go +++ b/server/controllers/user.go @@ -25,6 +25,8 @@ func (c *UserController) GetAllUsers() { "avatar": user.Avatar, "nickname": user.Nickname, "tenant_id": user.TenantId, + "status": user.Status, + "role": user.Role, "lastLoginTime": user.LastLoginTime, }) } @@ -37,6 +39,56 @@ func (c *UserController) GetAllUsers() { c.ServeJSON() } +// GetTenantUsers 获取指定租户下的所有用户(排除已删除的用户) +func (c *UserController) GetTenantUsers() { + // 从URL参数获取租户ID + tenantId, err := c.GetInt(":tenantId") + if err != nil || tenantId <= 0 { + c.Data["json"] = map[string]interface{}{ + "code": 1, + "message": "租户ID无效", + "data": nil, + } + c.ServeJSON() + return + } + + // 调用模型层方法查询 + users, err := models.GetTenantUsers(tenantId) + if err != nil { + c.Data["json"] = map[string]interface{}{ + "code": 1, + "message": err.Error(), + "data": nil, + } + c.ServeJSON() + return + } + + // 格式化返回数据 + userList := make([]map[string]interface{}, 0) + for _, user := range users { + userList = append(userList, map[string]interface{}{ + "id": user.Id, + "username": user.Username, + "email": user.Email, + "avatar": user.Avatar, + "nickname": user.Nickname, + "tenant_id": user.TenantId, + "status": user.Status, + "role": user.Role, + "last_login_time": user.LastLoginTime, + }) + } + + c.Data["json"] = map[string]interface{}{ + "code": 0, + "message": "获取租户用户列表成功", + "data": userList, + } + c.ServeJSON() +} + // ChangePassword 修改用户密码 func (c *UserController) ChangePassword() { // 从URL获取用户ID @@ -144,6 +196,8 @@ func (c *UserController) GetUserInfo() { "avatar": user.Avatar, "nickname": user.Nickname, "tenant_id": user.TenantId, + "role": user.Role, + "status": user.Status, }, } c.ServeJSON() @@ -159,6 +213,7 @@ func (c *UserController) AddUser() { Nickname string `json:"nickname"` Avatar string `json:"avatar"` TenantId int `json:"tenant_id"` + Role int `json:"role"` // 角色ID } // 解析请求体JSON数据 @@ -210,6 +265,7 @@ func (c *UserController) AddUser() { userData.Nickname, userData.Avatar, userData.TenantId, + userData.Role, // 添加 role 参数 ) if err != nil { c.Data["json"] = map[string]interface{}{ @@ -243,6 +299,8 @@ func (c *UserController) EditUser() { Email string `json:"email"` Nickname string `json:"nickname"` Avatar string `json:"avatar"` + Status string `json:"status"` + Role int `json:"role"` // 改为 role,存储角色ID } // 解析请求体JSON @@ -275,6 +333,8 @@ func (c *UserController) EditUser() { updateData.Email, updateData.Nickname, updateData.Avatar, + updateData.Status, + updateData.Role, // 改为 Role ) if err != nil { c.Data["json"] = map[string]interface{}{ diff --git a/server/middleware/jwt.go b/server/middleware/jwt.go index 66a5da2..4fc3429 100644 --- a/server/middleware/jwt.go +++ b/server/middleware/jwt.go @@ -60,8 +60,9 @@ func JWTAuthMiddleware() web.FilterFunc { return } - // 将用户信息存储在上下文 - ctx.Input.SetData("userId", claims.UserID) - ctx.Input.SetData("username", claims.Username) - } + // 将用户信息存储在上下文 + ctx.Input.SetData("userId", claims.UserID) + ctx.Input.SetData("username", claims.Username) + ctx.Input.SetData("tenantId", claims.TenantId) +} } diff --git a/server/models/file.go b/server/models/file.go index ec51b1b..02d7967 100644 --- a/server/models/file.go +++ b/server/models/file.go @@ -1,42 +1,46 @@ package models import ( + "strings" "time" + "github.com/beego/beego/v2/client/orm" ) // FileInfo 文件信息模型 // 对应 yz_files 表结构 type FileInfo struct { - ID int64 `orm:"column(id);auto" json:"id"` - TenantID string `orm:"column(tenant_id);size(64)" json:"tenant_id"` - + ID int64 `orm:"column(id);auto" json:"id"` + TenantID string `orm:"column(tenant_id);size(64)" json:"tenant_id"` + // 用户关联信息(通过JWT认证获取) - UserID int `orm:"column(user_id);default(0)" json:"user_id"` - + UserID int `orm:"column(user_id);default(0)" json:"user_id"` + // 文件基础信息 - FileName string `orm:"column(file_name);size(255)" json:"file_name"` - OriginalName string `orm:"column(original_name);size(255)" json:"original_name"` - FilePath string `orm:"column(file_path);size(500)" json:"file_path"` - FileURL string `orm:"column(file_url);size(500);null" json:"file_url"` - FileSize int64 `orm:"column(file_size);default(0)" json:"file_size"` - FileType string `orm:"column(file_type);size(50)" json:"file_type"` - FileExt string `orm:"column(file_ext);size(20)" json:"file_ext"` - + FileName string `orm:"column(file_name);size(255)" json:"file_name"` + OriginalName string `orm:"column(original_name);size(255)" json:"original_name"` + FilePath string `orm:"column(file_path);size(500)" json:"file_path"` + FileURL string `orm:"column(file_url);size(500);null" json:"file_url"` + FileSize int64 `orm:"column(file_size);default(0)" json:"file_size"` + FileType string `orm:"column(file_type);size(50)" json:"file_type"` + FileExt string `orm:"column(file_ext);size(20)" json:"file_ext"` + MD5 string `orm:"column(md5);size(32);null" json:"md5"` + // 分类信息 - Category string `orm:"column(category);size(100)" json:"category"` - SubCategory string `orm:"column(sub_category);size(100);null" json:"sub_category"` - + Category string `orm:"column(category);size(100)" json:"category"` + SubCategory string `orm:"column(sub_category);size(100);null" json:"sub_category"` + // 状态信息 - Status int8 `orm:"column(status);default(1)" json:"status"` - IsPublic int8 `orm:"column(is_public);default(0)" json:"is_public"` - + Status int8 `orm:"column(status);default(1)" json:"status"` + IsPublic int8 `orm:"column(is_public);default(0)" json:"is_public"` + // 上传信息 - UploadBy string `orm:"column(upload_by);size(100)" json:"upload_by"` - UploadTime time.Time `orm:"column(upload_time);type(datetime);auto_now_add" json:"upload_time"` - + UploadBy string `orm:"column(upload_by);size(100)" json:"upload_by"` + UploadTime time.Time `orm:"column(upload_time);type(datetime);auto_now_add" json:"upload_time"` + DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time,omitempty"` + // 关联的用户信息(非数据库字段) - User *User `orm:"-" json:"user,omitempty"` + User *User `orm:"-" json:"user,omitempty"` } // TableName 设置表名 @@ -44,6 +48,31 @@ func (f *FileInfo) TableName() string { return "yz_files" } +// CanPreview 判断文件是否可以在线预览 +func (f *FileInfo) CanPreview() bool { + previewableExts := map[string]bool{ + // 图片格式 + ".jpg": true, + ".jpeg": true, + ".png": true, + ".gif": true, + ".bmp": true, + ".webp": true, + ".svg": true, + // 文档格式(仅支持 .docx,不支持旧的 .doc、Excel、PPT) + ".pdf": true, + ".txt": true, + ".docx": true, + // 视频格式 + ".mp4": true, + ".webm": true, + // 音频格式 + ".mp3": true, + ".wav": true, + } + return previewableExts[strings.ToLower(f.FileExt)] +} + // GetAllFiles 获取所有文件信息 func GetAllFiles() ([]*FileInfo, error) { o := orm.NewOrm() @@ -109,7 +138,7 @@ func UpdateFile(file *FileInfo) error { return err } -// DeleteFile 删除文件信息(软删除,设置状态为0) +// DeleteFile 删除文件信息(软删除,设置状态为0并记录删除时间) func DeleteFile(id int64) error { o := orm.NewOrm() file := &FileInfo{ID: id} @@ -117,7 +146,9 @@ func DeleteFile(id int64) error { return err } file.Status = 0 - _, err := o.Update(file, "Status") + now := time.Now() + file.DeleteTime = &now + _, err := o.Update(file, "Status", "DeleteTime") return err } @@ -131,50 +162,73 @@ func HardDeleteFile(id int64) error { // GetFileStatistics 获取文件统计信息 func GetFileStatistics(tenantID string) (map[string]interface{}, error) { o := orm.NewOrm() - + // 总文件数 totalCount, err := o.QueryTable("yz_files").Filter("tenant_id", tenantID).Filter("status", 1).Count() if err != nil { return nil, err } - + // 总文件大小 var totalSize int64 err = o.Raw("SELECT COALESCE(SUM(file_size), 0) FROM yz_files WHERE tenant_id = ? AND status = 1", tenantID).QueryRow(&totalSize) if err != nil { return nil, err } - + // 按分类统计 var categoryStats []orm.Params _, err = o.Raw("SELECT category, COUNT(*) as count, COALESCE(SUM(file_size), 0) as size FROM yz_files WHERE tenant_id = ? AND status = 1 GROUP BY category", tenantID).Values(&categoryStats) if err != nil { return nil, err } - + return map[string]interface{}{ - "total_count": totalCount, - "total_size": totalSize, + "total_count": totalCount, + "total_size": totalSize, "category_stats": categoryStats, }, nil } -// SearchFiles 搜索文件 +// SearchFiles 搜索文件(通过原始文件名搜索) func SearchFiles(keyword string, tenantID string) ([]*FileInfo, error) { o := orm.NewOrm() var files []*FileInfo - - // 构建查询条件 + + // 构建查询条件 - 只通过原始文件名搜索 qs := o.QueryTable("yz_files").Filter("tenant_id", tenantID).Filter("status", 1) - - // 搜索文件名、原始文件名、分类(使用or条件) - cond := orm.NewCondition() - cond = cond.Or("file_name__icontains", keyword). - Or("original_name__icontains", keyword). - Or("category__icontains", keyword) - - qs = qs.SetCond(cond) - + + // 搜索原始文件名 + qs = qs.Filter("original_name__icontains", keyword) + _, err := qs.OrderBy("-upload_time").All(&files) return files, err -} \ No newline at end of file +} + +// GetFileByMD5 根据MD5获取文件信息(获取唯一的文件记录) +func GetFileByMD5(md5 string) (*FileInfo, error) { + o := orm.NewOrm() + var file FileInfo + err := o.QueryTable("yz_files").Filter("md5", md5).Filter("status", 1).OrderBy("upload_time").One(&file) + if err == orm.ErrNoRows { + return nil, nil + } + if err != nil { + return nil, err + } + return &file, nil +} + +// GetFileByMD5AndTenant 根据MD5和租户ID获取文件信息 +func GetFileByMD5AndTenant(md5 string, tenantID string) (*FileInfo, error) { + o := orm.NewOrm() + var file FileInfo + err := o.QueryTable("yz_files").Filter("md5", md5).Filter("tenant_id", tenantID).Filter("status", 1).OrderBy("upload_time").One(&file) + if err == orm.ErrNoRows { + return nil, nil + } + if err != nil { + return nil, err + } + return &file, nil +} diff --git a/server/models/user.go b/server/models/user.go index a79decb..572ee13 100644 --- a/server/models/user.go +++ b/server/models/user.go @@ -24,6 +24,8 @@ type User struct { Email string Avatar string Nickname string + Status int `orm:"column(status);default(1)" json:"status"` + Role int `orm:"column(role);default(0)" json:"role"` DeleteTime *time.Time `orm:"column(delete_time);null;type(datetime)" json:"delete_time"` LastLoginTime *time.Time `orm:"column(last_login_time);null;type(datetime)" json:"last_login_time"` } @@ -147,6 +149,20 @@ func GetAllUsers(tenantId int) []*User { return users } +// GetTenantUsers 获取指定租户下的所有用户(排除已删除的用户) +func GetTenantUsers(tenantId int) ([]*User, error) { + o := orm.NewOrm() + var users []*User + + // 查询指定租户下未删除的用户 + _, err := o.Raw("SELECT * FROM yz_users WHERE tenant_id = ? AND delete_time IS NULL ORDER BY id DESC", tenantId).QueryRows(&users) + if err != nil { + return nil, fmt.Errorf("查询租户用户失败: %v", err) + } + + return users, nil +} + // GetUserInfo 根据用户ID或用户名获取用户 func GetUserInfo(userId int, username string, tenantId int) (*User, error) { o := orm.NewOrm() @@ -221,7 +237,7 @@ func ValidateUser(username, password string, tenantName string) (*User, error) { } // AddUser 向数据库添加新用户 -func AddUser(username, password, email, nickname, avatar string, tenantId int) (*User, error) { +func AddUser(username, password, email, nickname, avatar string, tenantId, role int) (*User, error) { // 1. 验证租户是否存在且有效 o := orm.NewOrm() var tenantExists bool @@ -258,11 +274,12 @@ func AddUser(username, password, email, nickname, avatar string, tenantId int) ( user := &User{ TenantId: tenantId, Username: username, - Password: hashedPassword, // 存储加密后的密码 - Salt: salt, // 存储盐值(用于后续验证) + Password: hashedPassword, + Salt: salt, Email: email, Nickname: nickname, Avatar: avatar, + Role: role, // 设置角色ID } // 5. 插入数据库(使用之前定义的 o) @@ -276,7 +293,7 @@ func AddUser(username, password, email, nickname, avatar string, tenantId int) ( } // EditUser 更新用户信息 -func EditUser(id int, username, email, nickname, avatar string) (*User, error) { +func EditUser(id int, username, email, nickname, avatar, status string, roleId int) (*User, error) { // 根据ID查询用户 o := orm.NewOrm() user := &User{} @@ -307,6 +324,20 @@ func EditUser(id int, username, email, nickname, avatar string) (*User, error) { user.Avatar = avatar } + // 更新状态(将字符串转换为数字) + if status != "" { + if status == "active" { + user.Status = 1 + } else if status == "inactive" { + user.Status = 0 + } + } + + // 更新角色ID + if roleId > 0 { + user.Role = roleId + } + // 执行数据库更新 _, err = o.Update(user) if err != nil { diff --git a/server/package-lock.json b/server/package-lock.json new file mode 100644 index 0000000..99ef3d8 --- /dev/null +++ b/server/package-lock.json @@ -0,0 +1,1640 @@ +{ + "name": "server", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "vue-office": "^0.0.5" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "2.7.16", + "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz", + "integrity": "sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==", + "dependencies": { + "@babel/parser": "^7.23.5", + "postcss": "^8.4.14", + "source-map": "^0.6.1" + }, + "optionalDependencies": { + "prettier": "^1.18.2 || ^2.0.0" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.11", + "resolved": "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.11.tgz", + "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC", + "optional": true + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "license": "ISC", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT", + "optional": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmmirror.com/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT", + "optional": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", + "optional": true + }, + "node_modules/core-js": { + "version": "3.46.0", + "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.46.0.tgz", + "integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", + "optional": true + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dingbat-to-unicode": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz", + "integrity": "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==", + "license": "BSD-2-Clause" + }, + "node_modules/docx-preview": { + "version": "0.1.20", + "resolved": "https://registry.npmmirror.com/docx-preview/-/docx-preview-0.1.20.tgz", + "integrity": "sha512-YfmRI6wdq5n2uh7Oi6Gk7FszDV+OysA6Gs5ZoLmSZPJrTOrgUmiEVZ87iJDAUxNIJENua/Tj7H7IYmpNEbFzlw==", + "license": "Apache-2.0", + "dependencies": { + "jszip": ">=3.0.0" + } + }, + "node_modules/duck": { + "version": "0.1.12", + "resolved": "https://registry.npmmirror.com/duck/-/duck-0.1.12.tgz", + "integrity": "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==", + "license": "BSD", + "dependencies": { + "underscore": "^1.13.1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "optional": true + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC", + "optional": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", + "optional": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "optional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lop": { + "version": "0.4.2", + "resolved": "https://registry.npmmirror.com/lop/-/lop-0.4.2.tgz", + "integrity": "sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw==", + "license": "BSD-2-Clause", + "dependencies": { + "duck": "^0.1.12", + "option": "~0.2.1", + "underscore": "^1.13.1" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/mammoth": { + "version": "1.11.0", + "resolved": "https://registry.npmmirror.com/mammoth/-/mammoth-1.11.0.tgz", + "integrity": "sha512-BcEqqY/BOwIcI1iR5tqyVlqc3KIaMRa4egSoK83YAVrBf6+yqdAAbtUcFDCWX8Zef8/fgNZ6rl4VUv+vVX8ddQ==", + "license": "BSD-2-Clause", + "dependencies": { + "@xmldom/xmldom": "^0.8.6", + "argparse": "~1.0.3", + "base64-js": "^1.5.1", + "bluebird": "~3.4.0", + "dingbat-to-unicode": "^1.0.1", + "jszip": "^3.7.1", + "lop": "^0.4.2", + "path-is-absolute": "^1.0.0", + "underscore": "^1.13.1", + "xmlbuilder": "^10.0.0" + }, + "bin": { + "mammoth": "bin/mammoth" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "optional": true + }, + "node_modules/nan": { + "version": "2.23.0", + "resolved": "https://registry.npmmirror.com/nan/-/nan-2.23.0.tgz", + "integrity": "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==", + "license": "MIT", + "optional": true + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "optional": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "optional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/option": { + "version": "0.2.4", + "resolved": "https://registry.npmmirror.com/option/-/option-0.2.4.tgz", + "integrity": "sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==", + "license": "BSD-2-Clause" + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/path": { + "version": "0.12.7", + "resolved": "https://registry.npmmirror.com/path/-/path-0.12.7.tgz", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", + "license": "MIT", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "license": "ISC" + }, + "node_modules/path/node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmmirror.com/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/path2d-polyfill": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", + "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pdfjs-dist": { + "version": "3.11.174", + "resolved": "https://registry.npmmirror.com/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", + "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "canvas": "^2.11.2", + "path2d-polyfill": "^2.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "license": "MIT", + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmmirror.com/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC", + "optional": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC", + "optional": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", + "optional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT", + "optional": true + }, + "node_modules/underscore": { + "version": "1.13.7", + "resolved": "https://registry.npmmirror.com/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "license": "MIT" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmmirror.com/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/vue": { + "version": "2.7.16", + "resolved": "https://registry.npmmirror.com/vue/-/vue-2.7.16.tgz", + "integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==", + "deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.", + "license": "MIT", + "dependencies": { + "@vue/compiler-sfc": "2.7.16", + "csstype": "^3.1.0" + } + }, + "node_modules/vue-office": { + "version": "0.0.5", + "resolved": "https://registry.npmmirror.com/vue-office/-/vue-office-0.0.5.tgz", + "integrity": "sha512-KVqmPwinTwzkDKYiyJ/iNw/IiFRDDC+DZr2ysXhuN2322d0hBp4LUUDrhtU2B0hyDSqxFsHsI/6pwMlvq5KFsg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT", + "dependencies": { + "core-js": "^3.8.3", + "docx-preview": "^0.1.14", + "lodash": "^4.17.21", + "mammoth": "^1.5.1", + "path": "^0.12.7", + "pdfjs-dist": "^3.0.279", + "stream-browserify": "^3.0.0", + "util": "^0.12.5", + "vue": "^2.6.14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause", + "optional": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC", + "optional": true + }, + "node_modules/xmlbuilder": { + "version": "10.1.1", + "resolved": "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-10.1.1.tgz", + "integrity": "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", + "optional": true + } + } +} diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..3e8823a --- /dev/null +++ b/server/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "vue-office": "^0.0.5" + } +} diff --git a/server/routers/router.go b/server/routers/router.go index c2b949b..44f7e46 100644 --- a/server/routers/router.go +++ b/server/routers/router.go @@ -3,6 +3,7 @@ package routers import ( "server/controllers" "server/middleware" + "strings" beego "github.com/beego/beego/v2/server/web" "github.com/beego/beego/v2/server/web/context" @@ -44,6 +45,11 @@ func init() { } } + // 检查是否为公开预览接口(/api/files/public-preview/:id) + if strings.HasPrefix(path, "/api/files/public-preview/") { + skipAuth = true + } + if !skipAuth { middleware.JWTAuthMiddleware()(ctx) } @@ -63,6 +69,7 @@ func init() { beego.Router("/api/deleteUser/:id", &controllers.UserController{}, "delete:DeleteUser") beego.Router("/api/changePassword/:id", &controllers.UserController{}, "post:ChangePassword") beego.Router("/api/reset-password", &controllers.UserController{}, "post:ResetPassword") + beego.Router("/api/tenantUsers/:tenantId", &controllers.UserController{}, "get:GetTenantUsers") // 认证路由 beego.Router("/api/login", &controllers.AuthController{}, "post:Login") @@ -84,6 +91,9 @@ func init() { beego.Router("/api/files", &controllers.FileController{}, "get:GetAllFiles") beego.Router("/api/files", &controllers.FileController{}, "post:Post") beego.Router("/api/files/my", &controllers.FileController{}, "get:GetMyFiles") + beego.Router("/api/files/download/:id", &controllers.FileController{}, "get:DownloadFile") + beego.Router("/api/files/preview/:id", &controllers.FileController{}, "get:PreviewFile") + beego.Router("/api/files/public-preview/:id", &controllers.FileController{}, "get:PublicPreviewFile") beego.Router("/api/files/:id", &controllers.FileController{}, "get:GetFileById") beego.Router("/api/files/tenant", &controllers.FileController{}, "get:GetFilesByTenant") beego.Router("/api/files/:id", &controllers.FileController{}, "put:UpdateFile") diff --git a/server/tests/default_test.go b/server/tests/default_test.go deleted file mode 100644 index 4191173..0000000 --- a/server/tests/default_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package test - -import ( - "net/http" - "net/http/httptest" - "testing" - "runtime" - "path/filepath" - - "github.com/beego/beego/v2/core/logs" - - _ "server/routers" - - beego "github.com/beego/beego/v2/server/web" - . "github.com/smartystreets/goconvey/convey" -) - -func init() { - _, file, _, _ := runtime.Caller(0) - apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator)))) - beego.TestBeegoInit(apppath) -} - - -// TestBeego is a sample to run an endpoint test -func TestBeego(t *testing.T) { - r, _ := http.NewRequest("GET", "/", nil) - w := httptest.NewRecorder() - beego.BeeApp.Handlers.ServeHTTP(w, r) - - logs.Trace("testing", "TestBeego", "Code[%d]\n%s", w.Code, w.Body.String()) - - Convey("Subject: Test Station Endpoint\n", t, func() { - Convey("Status Code Should Be 200", func() { - So(w.Code, ShouldEqual, 200) - }) - Convey("The Result Should Not Be Empty", func() { - So(w.Body.Len(), ShouldBeGreaterThan, 0) - }) - }) -} - diff --git a/server/tests/file_test.go b/server/tests/file_test.go deleted file mode 100644 index d7c055c..0000000 --- a/server/tests/file_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package tests - -import ( - "testing" - "server/models" -) - -func TestFileModel(t *testing.T) { - // 测试创建文件信息 - file := &models.FileInfo{ - TenantID: "test-tenant-001", - FileName: "test-file.txt", - OriginalName: "original-test-file.txt", - FilePath: "/uploads/test/test-file.txt", - FileURL: "http://localhost:8080/uploads/test/test-file.txt", - FileSize: 1024, - FileType: "text/plain", - FileExt: "txt", - Category: "test", - SubCategory: "unit-test", - Status: 1, - IsPublic: 0, - UploadBy: "test-user", - } - - // 测试添加文件 - id, err := models.AddFile(file) - if err != nil { - t.Errorf("添加文件失败: %v", err) - } - t.Logf("文件添加成功,ID: %d", id) - - // 测试根据ID获取文件 - retrievedFile, err := models.GetFileById(id) - if err != nil { - t.Errorf("获取文件失败: %v", err) - } - if retrievedFile.FileName != file.FileName { - t.Errorf("文件名不匹配,期望: %s, 实际: %s", file.FileName, retrievedFile.FileName) - } - - // 测试更新文件 - retrievedFile.FileName = "updated-test-file.txt" - err = models.UpdateFile(retrievedFile) - if err != nil { - t.Errorf("更新文件失败: %v", err) - } - - // 测试根据租户获取文件 - files, err := models.GetFilesByTenant("test-tenant-001") - if err != nil { - t.Errorf("根据租户获取文件失败: %v", err) - } - if len(files) == 0 { - t.Error("根据租户获取文件为空") - } - - // 测试根据分类获取文件 - filesByCategory, err := models.GetFilesByCategory("test") - if err != nil { - t.Errorf("根据分类获取文件失败: %v", err) - } - if len(filesByCategory) == 0 { - t.Error("根据分类获取文件为空") - } - - // 测试搜索文件 - searchFiles, err := models.SearchFiles("test", "test-tenant-001") - if err != nil { - t.Errorf("搜索文件失败: %v", err) - } - if len(searchFiles) == 0 { - t.Error("搜索文件结果为空") - } - - // 测试文件统计 - stats, err := models.GetFileStatistics("test-tenant-001") - if err != nil { - t.Errorf("获取文件统计失败: %v", err) - } - t.Logf("文件统计: %+v", stats) - - // 测试软删除文件 - err = models.DeleteFile(id) - if err != nil { - t.Errorf("软删除文件失败: %v", err) - } - - // 验证软删除后的状态 - deletedFile, err := models.GetFileById(id) - if err != nil { - t.Errorf("获取软删除后的文件失败: %v", err) - } - if deletedFile.Status != 0 { - t.Errorf("软删除后文件状态应为0,实际为: %d", deletedFile.Status) - } - - // 测试硬删除文件 - err = models.HardDeleteFile(id) - if err != nil { - t.Errorf("硬删除文件失败: %v", err) - } - - t.Log("文件模型测试完成") -} \ No newline at end of file
{{ getOfficeFileTypeName(previewFile.file_ext) }} 文件暂不支持在线预览
该文件类型不支持在线预览
正在加载程序数据...