From 3fe0a930c7bda66e1ef99c89bc28aa0551d506ff Mon Sep 17 00:00:00 2001 From: mahmood Date: Sat, 14 Nov 2026 15:07:11 +0330 Subject: [PATCH] feat: compress uploads and serve resized image variants via /api/img Co-authored-by: Cursor --- .../components/upload/GalleryUploadInput.vue | 14 +- .../components/upload/ImageUploadInput.vue | 24 +- apps/admin-panel/src/utils/image.ts | 21 ++ apps/admin-panel/src/utils/upload.ts | 37 +++ apps/admin-panel/src/views/Dashboard.vue | 3 +- .../src/views/apps/category/List.vue | 3 +- .../src/views/apps/product/ProductList.vue | 3 +- .../src/views/apps/product/ProductSurvey.vue | 5 +- .../src/views/branch/order/create.vue | 5 +- .../src/views/invoice/AddInvoice.vue | 7 +- .../offersIgnore/offersIgnore-add-edit.vue | 3 +- apps/admin-panel/src/views/order/create.vue | 5 +- apps/api/esbuild.release.config.cjs | 2 + apps/api/package.json | 3 +- .../admin-uploads/admin-uploads.module.ts | 8 +- .../admin-uploads.service.spec.ts | 77 +++++ .../admin-uploads/admin-uploads.service.ts | 27 +- .../image-variants.service.spec.ts | 139 ++++++++ .../admin-uploads/image-variants.service.ts | 205 ++++++++++++ .../admin-uploads/public-images.controller.ts | 45 +++ apps/user-app-v2/src/api/client.ts | 18 +- .../src/components/product/OrderItemCard.vue | 5 +- .../src/components/product/SingleProduct.vue | 10 +- .../components/upload/SingleImageUploader.vue | 21 +- .../user-app-v2/src/composables/useProduct.ts | 4 +- apps/user-app-v2/src/utils/image.ts | 16 + apps/user-app-v2/src/views/HomeView.vue | 3 +- .../src/views/user/MakeOrderStatusView.vue | 3 +- .../src/views/user/SurveyFeedView.vue | 3 +- .../src/views/user/SurveyMineView.vue | 3 +- pnpm-lock.yaml | 305 ++++++++++++++++++ scripts/generate-city-migration.cjs | 1 + 32 files changed, 976 insertions(+), 52 deletions(-) create mode 100644 apps/admin-panel/src/utils/image.ts create mode 100644 apps/admin-panel/src/utils/upload.ts create mode 100644 apps/api/src/modules/admin-uploads/admin-uploads.service.spec.ts create mode 100644 apps/api/src/modules/admin-uploads/image-variants.service.spec.ts create mode 100644 apps/api/src/modules/admin-uploads/image-variants.service.ts create mode 100644 apps/api/src/modules/admin-uploads/public-images.controller.ts create mode 100644 apps/user-app-v2/src/utils/image.ts create mode 100644 scripts/generate-city-migration.cjs diff --git a/apps/admin-panel/src/components/upload/GalleryUploadInput.vue b/apps/admin-panel/src/components/upload/GalleryUploadInput.vue index 5fb5d8a..931bea1 100644 --- a/apps/admin-panel/src/components/upload/GalleryUploadInput.vue +++ b/apps/admin-panel/src/components/upload/GalleryUploadInput.vue @@ -29,7 +29,7 @@ class="tile" :class="{ 'is-uploading': item.status === 'uploading' }" > - +
@@ -64,6 +64,8 @@ import { computed, onBeforeUnmount, ref, watch } from 'vue'; import { message, Upload } from 'ant-design-vue'; import { CloudUploadOutlined, DeleteOutlined, EyeOutlined, LoadingOutlined } from '@ant-design/icons-vue'; import api from '../../api/client'; +import { imageUrl } from '../../utils/image'; +import { checkImageFile, uploadErrorMessage } from '../../utils/upload'; const props = withDefaults( defineProps<{ @@ -116,8 +118,9 @@ watch( ); function beforeUpload(file: File) { - if (!file.type.startsWith('image/')) { - message.error(`«${file.name}» تصویر نیست`); + const problem = checkImageFile(file); + if (problem) { + message.error(problem); return Upload.LIST_IGNORE; } return true; @@ -171,10 +174,7 @@ function doUpload({ file }: { file: File & { uid?: string } }) { sync(); }) .catch((e) => { - const msg = - (e as { response?: { data?: { message?: string } } })?.response?.data?.message ?? - `بارگذاری «${file.name}» ناموفق بود`; - message.error(msg); + message.error(uploadErrorMessage(e, file.name)); dropItem(uid); }); } diff --git a/apps/admin-panel/src/components/upload/ImageUploadInput.vue b/apps/admin-panel/src/components/upload/ImageUploadInput.vue index 76f4a3c..a4d5f0f 100644 --- a/apps/admin-panel/src/components/upload/ImageUploadInput.vue +++ b/apps/admin-panel/src/components/upload/ImageUploadInput.vue @@ -17,6 +17,7 @@ :max-count="1" accept="image/*" :custom-request="doUpload" + :before-upload="beforeUpload" @remove="handleRemove" @preview="handlePreview" > @@ -37,9 +38,11 @@