diff --git a/components.d.ts b/components.d.ts index a6b2624..3503511 100644 --- a/components.d.ts +++ b/components.d.ts @@ -119,6 +119,7 @@ declare module 'vue' { GradientText: typeof import('./src/components/MyUI/GradientText/GradientText.vue')['default'] HeatmapPro: typeof import('./src/components/HeatmapPro/HeatmapPro.vue')['default'] ImageEnhancer: typeof import('./src/components/ImageEnhancer/ImageEnhancer.vue')['default'] + ImageList: typeof import('./src/views/Photograph/PrivacySpace/ImageList.vue')['default'] ImageShare: typeof import('./src/views/Share/ImageShare/ImageShare.vue')['default'] ImageToolbar: typeof import('./src/components/ImageToolbar/ImageToolbar.vue')['default'] ImageUpload: typeof import('./src/components/ImageUpload/ImageUpload.vue')['default'] @@ -138,6 +139,7 @@ declare module 'vue' { Login: typeof import('./src/views/Admin/Auth/Login.vue')['default'] LoginFooter: typeof import('./src/views/Login/LoginFooter.vue')['default'] LoginPage: typeof import('./src/views/Login/LoginPage.vue')['default'] + LogoutOutlined: typeof import('@ant-design/icons-vue')['LogoutOutlined'] MainPage: typeof import('./src/views/Main/MainPage.vue')['default'] MessageReport: typeof import('./src/components/CommentReply/src/MessageReport/MessageReport.vue')['default'] NotFound: typeof import('./src/views/404/NotFound.vue')['default'] @@ -161,6 +163,7 @@ declare module 'vue' { Popover: typeof import('./src/components/MyUI/Popover/Popover.vue')['default'] PreviewBlurDetect: typeof import('./src/views/Preview/PreviewBlurDetect/PreviewBlurDetect.vue')['default'] PreviewOCR: typeof import('./src/views/Preview/PreviewOCR/PreviewOCR.vue')['default'] + PrivacyImageList: typeof import('./src/views/Photograph/PrivacySpace/PrivacyImageList.vue')['default'] PrivacySpace: typeof import('./src/views/Photograph/PrivacySpace/PrivacySpace.vue')['default'] QrcodeOutlined: typeof import('@ant-design/icons-vue')['QrcodeOutlined'] QRLogin: typeof import('./src/views/QRLogin/QRLogin.vue')['default'] diff --git a/package.json b/package.json index 842f3e6..7839c69 100644 --- a/package.json +++ b/package.json @@ -37,13 +37,13 @@ "@types/node": "^22.13.10", "@types/nprogress": "^0.2.3", "@vladmandic/face-api": "^1.7.15", - "@vuepic/vue-datepicker": "^11.0.1", + "@vuepic/vue-datepicker": "^11.0.2", "@vueuse/core": "^13.0.0", "@vueuse/integrations": "^13.0.0", "alova": "^3.2.10", "animejs": "^3.2.2", "ant-design-vue": "^4.2.6", - "axios": "^1.8.3", + "axios": "^1.8.4", "browser-image-compression": "^2.0.2", "buffer": "^6.0.3", "crypto-js": "^4.2.0", @@ -70,7 +70,7 @@ "qr-scanner-wechat": "^0.1.3", "rimraf": "^6.0.1", "seedrandom": "^3.0.5", - "swiper": "^11.2.5", + "swiper": "^11.2.6", "unplugin-auto-import": "^19.1.1", "upscaler": "^1.0.0-beta.19", "vite-plugin-compression": "^0.5.1", @@ -86,12 +86,12 @@ }, "devDependencies": { "@eslint/js": "^9.22.0", - "@vitejs/plugin-vue": "^5.2.1", + "@vitejs/plugin-vue": "^5.2.3", "eslint-plugin-vue": "^10.0.0", "globals": "^16.0.0", - "sass": "^1.85.1", + "sass": "^1.86.0", "typescript": "^5.8.2", - "typescript-eslint": "^8.26.1", + "typescript-eslint": "^8.27.0", "unplugin-vue-components": "^28.4.1", "vite": "^6.2.2", "vite-plugin-bundle-obfuscator": "1.4.2", diff --git a/src/App.vue b/src/App.vue index 9c16d65..acbdc12 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,9 +4,9 @@ :theme="app.themeConfig" > - - - + + + diff --git a/src/api/admin/index.ts b/src/api/admin/index.ts new file mode 100644 index 0000000..7de578a --- /dev/null +++ b/src/api/admin/index.ts @@ -0,0 +1,22 @@ +import {service} from "@/utils/alova/service.ts"; + +/** + * 管理员登录接口 + * @param param + */ +export const adminAccountLoginApi = (param: any) => { + return service.Post('/api/user/admin/login', { + account: param.account, + password: param.password, + dots: param.dots, + key: param.key + }, + { + meta: { + ignoreToken: true, + authRole: 'admin', + signature: true + } + } + ); +}; diff --git a/src/api/captcha/index.ts b/src/api/captcha/index.ts index bc04735..539d479 100644 --- a/src/api/captcha/index.ts +++ b/src/api/captcha/index.ts @@ -21,3 +21,14 @@ export const getSlideCaptchaDataApi = () => { }); }; +/** + * 获取文字验证码图片数据 + */ +export const getTextCaptchaDataApi = () => { + return service.Get('/api/captcha/text/generate', { + meta: { + ignoreToken: false + }, + }); + +}; diff --git a/src/api/storage/index.ts b/src/api/storage/index.ts index 25ec6b2..61c80b2 100644 --- a/src/api/storage/index.ts +++ b/src/api/storage/index.ts @@ -600,12 +600,16 @@ export const getShareStatisticsInfoApi = () => { * @param provider * @param bucket * @param password + * @param key + * @param dots */ -export const getPrivateImageListApi = (provider: string, bucket: string, password: string) => { +export const getPrivateImageListApi = (provider: string, bucket: string, password: string, key: string, dots: any) => { return service.Post('/api/auth/storage/image/private/list', { provider: provider, bucket: bucket, password: password, + key: key, + dots: dots, }, { cacheFor: { expire: 60 * 5, @@ -625,7 +629,7 @@ export const getPrivateImageListApi = (provider: string, bucket: string, passwor export const getCoordinateListApi = () => { return service.Post('/api/auth/storage/coordinate/list', {}, { cacheFor: { - expire:60 * 60 * 24 * 7, + expire: 60 * 60 * 24 * 7, mode: "restore", }, meta: { @@ -636,3 +640,28 @@ export const getCoordinateListApi = () => { hitSource: ["upload-file", "delete-images"], }); }; +/** + * 获取单个隐私照片url + * @param id + * @param provider + * @param bucket + * @param password + */ +export const getPrivateImageSingleUrlApi = (id: number,password: string, provider: string, bucket: string, ) => { + return service.Post('/api/auth/storage/image/private/url/single', { + id: id, + provider: provider, + bucket: bucket, + password: password, + }, { + cacheFor: { + expire: 60 * 60 * 24, + mode: "restore", + }, + meta: { + ignoreToken: false, + signature: false, + }, + name: "get-private-image-single-url", + }); +}; diff --git a/src/assets/images/bg_1.png b/src/assets/images/bg_1.png new file mode 100644 index 0000000..e8a06ee Binary files /dev/null and b/src/assets/images/bg_1.png differ diff --git a/src/assets/svgs/cover_image.svg b/src/assets/svgs/cover_image.svg new file mode 100644 index 0000000..58a2c09 --- /dev/null +++ b/src/assets/svgs/cover_image.svg @@ -0,0 +1 @@ + diff --git a/src/assets/svgs/tool-box.svg b/src/assets/svgs/tool-box.svg new file mode 100644 index 0000000..bfc3128 --- /dev/null +++ b/src/assets/svgs/tool-box.svg @@ -0,0 +1 @@ + diff --git a/src/components/ImageUpload/ImageUpload.vue b/src/components/ImageUpload/ImageUpload.vue index 29d5172..5ff442b 100644 --- a/src/components/ImageUpload/ImageUpload.vue +++ b/src/components/ImageUpload/ImageUpload.vue @@ -152,18 +152,19 @@ const {uploading, send: submitFile, abort} = useRequest(uploadFile, { * @param file */ async function customUploadRequest(file: any) { + const formData = new FormData(); + const compressedFile = await imageCompression(file.file, upload.options); - // 生成缩略图 const {binaryData, width, height, size} = await generateThumbnail(compressedFile); upload.predictResult.thumb_w = width; upload.predictResult.thumb_h = height; upload.predictResult.thumb_size = size; - - const formData = new FormData(); - formData.append("file", file.file); if (binaryData) { formData.append("thumbnail", binaryData); } + + + formData.append("file", file.file); formData.append("data", JSON.stringify({ provider: upload.storageSelected?.[0], bucket: upload.storageSelected?.[1], diff --git a/src/components/ImageWaterfallList/ImageWaterfallList.vue b/src/components/ImageWaterfallList/ImageWaterfallList.vue index d3321f9..e712ac4 100644 --- a/src/components/ImageWaterfallList/ImageWaterfallList.vue +++ b/src/components/ImageWaterfallList/ImageWaterfallList.vue @@ -1,6 +1,7 @@ diff --git a/src/views/Photograph/PrivacySpace/PrivacySpace.vue b/src/views/Photograph/PrivacySpace/PrivacySpace.vue index 3e2f241..f993790 100644 --- a/src/views/Photograph/PrivacySpace/PrivacySpace.vue +++ b/src/views/Photograph/PrivacySpace/PrivacySpace.vue @@ -1,24 +1,167 @@ diff --git a/src/views/Photograph/RecentUpload/RecentUpload.vue b/src/views/Photograph/RecentUpload/RecentUpload.vue index dd4e6ea..468a537 100644 --- a/src/views/Photograph/RecentUpload/RecentUpload.vue +++ b/src/views/Photograph/RecentUpload/RecentUpload.vue @@ -55,6 +55,10 @@ const imageList = ref([]); const getRecentImages = async () => { + if (!upload.storageSelected?.[0] || !upload.storageSelected?.[1]) { + message.error("请选择存储配置"); + return; + } imageStore.imageListLoading = true; const res: any = await queryRecentImagesApi(upload.storageSelected?.[0], upload.storageSelected?.[1]); if (res && res.code === 200) { diff --git a/src/views/User/PersonalCenter/PersonalCenter.vue b/src/views/User/PersonalCenter/PersonalCenter.vue index 972b886..9193aad 100644 --- a/src/views/User/PersonalCenter/PersonalCenter.vue +++ b/src/views/User/PersonalCenter/PersonalCenter.vue @@ -77,7 +77,7 @@ function handleClick({key}) { .personal-center-header { width: 100%; height: 200px; - background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.2)), url("@/assets/images/bg.webp"); + background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.2)), url("@/assets/images/bg_1.png"); background-size: cover; background-position: center; position: relative;