浏览代码

fix: 商品详情页

liangan 1 周之前
父节点
当前提交
bc20c7ce12

+ 47 - 0
src/api/product.ts

@@ -0,0 +1,47 @@
+import { http } from '@/utils/http'
+
+const pre = import.meta.env.VITE_SERVER_BASEURL_PREFIX
+/**
+ * 获取商品列表
+ * @returns data.list[]
+ */
+export function getList(data: any) {
+  return http.get<any>(`${pre}/app/combination/app/list`, data)
+}
+/**
+ * 获取商品排名列表
+ * @returns data.list[]
+ */
+export function getRankList(data: any) {
+  return http.get<any>(`${pre}/app/combination/rank`, data)
+}
+
+/**
+ * 获取商品分类
+ * @returns data.list[]
+ */
+export function categoryList(data: any) {
+  return http.post<any>(`${pre}/app/category/list`, data)
+}
+
+/**
+ * 获取商品详情
+ * @returns data.list[]
+ */
+export function getDetail(data: any) {
+  return http.get<any>(`${pre}/app/product/detail`, data)
+}
+/**
+ * 获取商品的拼团信息
+ * @returns data.list[]
+ */
+export function pinkList(data: any) {
+  return http.post<any>(`${pre}/app/pink/ongoing/list`, data)
+}
+/**
+ * 滚动消息轮播
+ * @returns data.list[]
+ */
+export function carousel(id: any) {
+  return http.get<any>(`${pre}/app/product/carousel/${id}`)
+}

+ 440 - 11
src/locale/bn.json

@@ -1,24 +1,453 @@
 {
+  "addressBook.title": "ঠিকানা বই",
+  "addressBook.operate.title.add": "ঠিকানা যোগ করুন",
+  "addressBook.operate.title.edit": "ঠিকানা সম্পাদনা করুন",
+  "addressBook.operate.loading": "লোড হচ্ছে...",
+  "addressBook.operate.saving": "সংরক্ষণ করা হচ্ছে...",
+  "addressBook.operate.form.fullName": "পুরো নাম",
+  "addressBook.operate.form.phone": "ফোন নম্বর",
+  "addressBook.operate.form.phone.placeholder": "+88",
+  "addressBook.operate.form.district": "প্রদেশ/জেলা",
+  "addressBook.operate.form.district.placeholder": "অনুগ্রহ করে চয়ন করুন",
+  "addressBook.operate.form.street": "তলা/ইউনিট/রাস্তা",
+  "addressBook.operate.form.street.placeholder": "বিস্তারিত ঠিকানা",
+  "addressBook.operate.form.postcode": "পোস্টকোড",
+  "addressBook.operate.form.postcode.placeholder": "আপনার পোস্টকোড",
+  "addressBook.operate.form.default": "ডিফল্ট",
+  "addressBook.operate.button.save": "সংরক্ষণ",
+  "addressBook.operate.button.update": "আপডেট",
+  "addressBook.operate.error.loadFailed": "ঠিকানার বিবরণ লোড করতে ব্যর্থ",
+  "addressBook.operate.error.emptyName": "পুরো নাম লিখুন",
+  "addressBook.operate.error.emptyPhone": "ফোন নম্বর লিখুন",
+  "addressBook.operate.error.emptyDistrict": "প্রদেশ/জেলা নির্বাচন করুন",
+  "addressBook.operate.error.emptyStreet": "বিস্তারিত ঠিকানা লিখুন",
+  "addressBook.operate.success.update": "ঠিকানা সফলভাবে আপডেট করা হয়েছে",
+  "addressBook.operate.success.save": "ঠিকানা সফলভাবে সংরক্ষিত হয়েছে",
+  "addressBook.operate.error.saveFailed": "সংরক্ষণ ব্যর্থ, আবার চেষ্টা করুন",
+  "addressBook.operate.error.loadPage": "পৃষ্ঠা লোড করতে ব্যর্থ",
+  "addressBook.delete.deleting": "মুছে ফেলা হচ্ছে...",
+  "addressBook.delete.success": "ঠিকানা সফলভাবে মুছে ফেলা হয়েছে",
+  "myOrders.title": "আমার অর্ডার",
+  "myOrders.tab.all": "সব",
+  "myOrders.tab.toPay": "পেমেন্ট বাকি",
+  "myOrders.tab.success": "সফল",
+  "myOrders.tab.failed": "ব্যর্থ",
+  "myOrders.tab.reward": "পুরস্কার",
+  "myOrders.order.id": "অর্ডার আইডি",
+  "myOrders.order.color": "রং",
+  "myOrders.order.quantity": "পরিমাণ",
+  "orderDetail.title": "অর্ডারের বিস্তারিত",
+  "orderDetail.loading": "লোড হচ্ছে...",
+  "orderDetail.congrats": "অভিনন্দন, আপনি এই গ্রুপে পুরস্কার জিতেছেন!",
+  "orderDetail.receiveReward": "আপনি গ্রুপ ওপেনিং রিওয়ার্ড পেয়েছেন",
+  "orderDetail.sorry": "দুঃখিত, আপনি এই গ্রুপে জিততে পারেননি",
+  "orderDetail.waiting": "অনুগ্রহ করে এই গ্রুপের ড্র এর জন্য অপেক্ষা করুন",
+  "orderDetail.paymentCountdown": "অনুগ্রহ করে এই সময়ের মধ্যে পেমেন্ট করুন:",
+  "orderDetail.address.add": "অনুগ্রহ করে আপনার শিপিং ঠিকানা প্রদান করুন",
+  "orderDetail.address.name": "প্রাপক",
+  "orderDetail.address.orderNo": "অর্ডার আইডি",
+  "orderDetail.address.color": "রং",
+  "orderDetail.address.quantity": "পরিমাণ",
+  "orderDetail.summary.title": "অর্ডার সারাংশ",
+  "orderDetail.summary.subtotal": "মোট",
+  "orderDetail.payment.title": "পেমেন্ট পদ্ধতি",
+  "orderDetail.payment.placedOn": "অর্ডারের তারিখ",
+  "orderDetail.button.cancel": "বাতিল করুন",
+  "orderDetail.button.share": "শেয়ার করুন",
+  "orderDetail.button.pay": "পেমেন্ট করুন",
+  "orderDetail.dialog.cancel.title": "আপনি কি এই অর্ডার বাতিল করতে চান?",
+  "orderDetail.dialog.cancel.confirm": "হ্যাঁ, বাতিল করুন",
+  "orderDetail.dialog.cancel.keep": "অর্ডার রাখুন",
+  "orderDetail.cancel.loading": "অর্ডার বাতিল করা হচ্ছে...",
+  "orderDetail.cancel.success": "অর্ডার সফলভাবে বাতিল করা হয়েছে!",
+  "orderDetail.cancel.error": "অর্ডার বাতিল করতে ব্যর্থ হয়েছে। আবার চেষ্টা করুন।",
+  "orderDetail.cancel.network": "নেটওয়ার্ক ত্রুটি। আপনার সংযোগ পরীক্ষা করে আবার চেষ্টা করুন।",
+  "orderDetail.payment.success": "পেমেন্ট সফল হয়েছে",
+  "wallet.withdraw.success": "উত্তোলনের অনুরোধ সফলভাবে জমা দেওয়া হয়েছে",
+  "wallet.withdraw.fail": "উত্তোলনের অনুরোধ জমা দিতে ব্যর্থ হয়েছে, অনুগ্রহ করে আবার চেষ্টা করুন",
+  "addressBook.delete.confirm": "মুছে ফেলা নিশ্চিত করুন",
+  "addressBook.delete.message": "আপনি কি এই ঠিকানাটি মুছে ফেলতে চান?",
+  "addressBook.delete.button": "মুছুন",
+  "addressBook.tag.default": "ডিফল্ট",
+  "addressBook.button.add": "নতুন ঠিকানা যোগ করুন",
+  "addressBook.select.binding": "ঠিকানা বাইন্ড করা হচ্ছে...",
+  "addressBook.select.success": "ঠিকানা সফলভাবে বাইন্ড হয়েছে!",
+  "addressBook.select.failed": "ঠিকানা বাইন্ড করতে ব্যর্থ। অনুগ্রহ করে আবার চেষ্টা করুন।",
+  "addressBook.select.networkError": "নেটওয়ার্ক ত্রুটি। অনুগ্রহ করে আপনার সংযোগ পরীক্ষা করে আবার চেষ্টা করুন।",
+  "myProfile.title": "আমার প্রোফাইল",
+  "myProfile.avatar": "অবতার",
+  "myProfile.userId": "ইউজার আইডি",
+  "myProfile.userName": "ব্যবহারকারীর নাম",
+  "myProfile.mobileNumber": "মোবাইল নম্বর",
+  "myProfile.bankName": "ব্যাংকের নাম",
+  "myProfile.bankAccountName": "ব্যাংক অ্যাকাউন্ট নাম",
+  "myProfile.bankAccountNo": "ব্যাংক অ্যাকাউন্ট নং",
+  "myProfile.upload.sizeLimit": "ছবির আকার 5MB এর বেশি হতে পারবে না",
+  "myProfile.upload.uploading": "আপলোড হচ্ছে...",
+  "myProfile.upload.success": "অবতার সফলভাবে আপডেট করা হয়েছে",
+  "myProfile.upload.error": "অবতার আপডেট করতে ব্যর্থ হয়েছে",
+  "setting.title": "সেটিং",
+  "setting.changePassword": "পাসওয়ার্ড পরিবর্তন",
+  "setting.language": "ভাষা",
+  "setting.policies": "গোপনীয়তা নীতি",
+  "setting.termsOfService": "পরিষেবার শর্তাবলী",
+  "setting.refund": "রিটার্ন ও ফেরত নীতি",
+  "setting.logout": "লগ আউট",
+  "setting.version": "ভার্সন {0}",
+  "setting.lang.en": "ইংরেজি",
+  "setting.lang.bn": "বাংলা",
+  "home.missionCenter": "মিশন\nসেন্টার",
+  "home.refer&earn": "রেফার\nএবং আয়",
+  "home.vip": "ভিআইপি\nসদস্যতা",
+  "home.bestSellers": "সেরা\nবিক্রেতা",
+  "home.topChampions": "শীর্ষ\nচ্যাম্পিয়ন",
+  "home.news": "খবর",
+  "mine.auth.register": "নিবন্ধন",
+  "mine.auth.login": "লগইন",
+  "mine.wallet.title": "BandhuBuy ওয়ালেট",
+  "mine.wallet.balance": "ওয়ালেট অ্যাকাউন্ট ব্যালেন্স",
+  "mine.wallet.recharge": "রিচার্জ",
+  "mine.group.title": "আমার গ্রুপ",
+  "mine.group.all": "সব গ্রুপ",
+  "mine.group.toPay": "পেমেন্ট বাকি",
+  "mine.group.success": "সফল",
+  "mine.group.failed": "ব্যর্থ",
+  "mine.group.reward": "পুরস্কার",
+  "mine.menu.profile": "আমার প্রোফাইল",
+  "mine.menu.address": "ঠিকানা বই",
+  "mine.menu.share": "শেয়ার",
+  "mine.menu.favorite": "আমার পছন্দ",
+  "mine.menu.chat": "লাইভ চ্যাট",
+  "mine.menu.activity": "কার্যকলাপ গ্রুপ",
+  "home.priceTab.allPrice": "সব দাম",
+  "home.priceTab.300spot": "৩০০স্পট",
+  "home.priceTab.500spot": "৫০০স্পট",
+  "home.priceTab.1000spot": "১০০০স্পট",
+  "home.priceTab.2000spot": "২০০০স্পট",
+  "home.priceTab.3000spot": "৩০০০স্পট",
+  "income.title": "রাজস্ব কেন্দ্র",
+  "income.totalEarnings": "মোট আয়",
+  "income.accountBalance": "রাজস্ব অ্যাকাউন্ট ব্যালেন্স",
+  "income.settledAmount": "নিষ্পত্তিকৃত পরিমাণ",
+  "income.pendingAmount": "অপেক্ষারত পরিমাণ",
+  "income.tdEarnings": "আজকের আয়",
+  "income.ydEarnings": "গতকালের আয়",
+  "income.mtdEarnings": "এই মাসের আয়",
+  "income.myGroupData": "আমার গ্রুপ ডেটা",
+  "income.withdrawNow": "এখনই উত্তোলন করুন",
+  "income.revenueRecord": "রাজস্ব রেকর্ড",
+  "income.filter.dt": "আজকে",
+  "income.filter.yt": "গতকাল",
+  "income.filter.l7d": "গত ৭ দিন",
+  "income.filter.mtd": "এই মাসে",
+  "income.filter.ytd": "এই বছরে",
+  "mine.pages.share.title": "শেয়ার",
+  "mine.pages.share.referrerCode": "আমার রেফারার কোড",
+  "mine.pages.share.qrCode": "কিউআর কোড",
+  "mine.pages.share.description": "আপনার বন্ধুদের সাথে আপনার কিউআর কোড শেয়ার করুন, তারা তাদের ক্যামেরা দিয়ে স্ক্যান করে আপনার ডাউনলাইন হিসাবে নিবন্ধন করতে পারবে।",
+  "mine.pages.share.copySuccess": "ক্লিপবোর্ডে অনুলিপি করা হয়েছে",
+  "mine.pages.share.shareTo": "{0} এ শেয়ার করুন",
+  "mine.pages.myFavorite.title": "আমার পছন্দ",
+  "mine.pages.myFavorite.empty": "এখনও পছন্দ নেই",
+  "wallet.withdraw.title": "উত্তোলন",
+  "wallet.withdraw.balance": "ওয়ালেট ব্যালেন্স",
+  "wallet.withdraw.info": "উত্তোলনের তথ্য",
+  "wallet.withdraw.form.bankName": "ব্যাংকের নাম",
+  "wallet.withdraw.form.bankAccountName": "ব্যাংক অ্যাকাউন্ট নাম",
+  "wallet.withdraw.form.bankAccountNo": "ব্যাংক অ্যাকাউন্ট নং",
+  "wallet.withdraw.form.amount": "উত্তোলনের পরিমাণ",
+  "wallet.withdraw.form.allAmount": "সব পরিমাণ",
+  "wallet.withdraw.form.submit": "জমা দিন",
+  "wallet.withdraw.record": "রেকর্ড",
+  "wallet.withdraw.error.bankName": "অনুগ্রহ করে ব্যাংক নির্বাচন করুন",
+  "wallet.withdraw.error.bankAccountName": "অনুগ্রহ করে ব্যাংক অ্যাকাউন্ট নাম লিখুন",
+  "wallet.withdraw.error.bankAccountNo": "অনুগ্রহ করে ব্যাংক অ্যাকাউন্ট নং লিখুন",
+  "wallet.withdraw.error.amount": "অনুগ্রহ করে উত্তোলনের পরিমাণ লিখুন",
+  "wallet.withdraw.notes.title": "দ্রষ্টব্য:",
+  "wallet.withdraw.notes.1": "উত্তোলনের পর্যালোচনা সময় সকাল ৯ টা থেকে রাত ১০ টা পর্যন্ত। উত্তোলনের পর ২ ঘন্টার মধ্যে পৌঁছানোর সম্ভাবনা, প্রকৃত পৌঁছানোর সময় চূড়ান্ত সফলভাবে প্রক্রিয়াকরণের সময়ের উপর নির্ভর করে",
+  "wallet.withdraw.notes.2": "আপনার ব্যাংক অ্যাকাউন্টের বিবরণ সঠিক কিনা তা নিশ্চিত করুন।",
+  "wallet.withdraw.notes.3": "উত্তোলনের ব্যাংক অ্যাকাউন্টের তথ্য নিবন্ধনের অ্যাকাউন্টের তথ্যের সাথে মেলানো প্রয়োজন।",
+  "wallet.withdraw.notes.4": "একক উত্তোলনের জন্য সর্বনিম্ন পরিমাণ ৳{0} এবং সর্বোচ্চ ৳{1} হবে;",
+  "wallet.withdraw.notes.5": "আপনার প্রতিটি উত্তোলনে {0}% উত্তোলন পরিচালনা ফি আরোপ করা হবে;",
+  "search.placeholder": "অনুসন্ধান",
+  "search.filterPrice": "সব দাম",
+  "search.filterCategory": "বিভাগ",
+  "search.filterSellers": "সেরা বিক্রেতা",
+  "search.filterSellers1": "সর্বশেষ",
+  "auth.login.title": "লগইন",
+  "auth.login.username.placeholder": "মোবাইল নম্বর / ব্যবহারকারীর নাম",
+  "auth.login.password.placeholder": "পাসওয়ার্ড ৬-২০ অক্ষর",
+  "auth.login.button": "লগইন",
+  "auth.login.noAccount": "এখনও অ্যাকাউন্ট নেই?",
+  "auth.login.register": "নিবন্ধন",
+  "auth.login.forgotPassword": "পাসওয়ার্ড ভুলে গেছেন?",
+  "auth.login.error.emptyUsername": "অনুগ্রহ করে ব্যবহারকারীর নাম বা ফোন নম্বর লিখুন",
+  "auth.login.error.emptyPassword": "অনুগ্রহ করে পাসওয়ার্ড লিখুন",
+  "auth.login.error.passwordLength": "পাসওয়ার্ড ৬-২০ অক্ষরের হতে হবে",
   "auth.register.title": "নিবন্ধন",
   "auth.register.username.placeholder": "ব্যবহারকারীর নাম",
-  "auth.register.phone.placeholder": "মোবাইল নম্বর",
-  "auth.register.verifyCode.placeholder": "ভেরিফিকেশন কোড",
-  "auth.register.password.placeholder": "পাসওয়ার্ড 6-20 অক্ষর",
+  "auth.register.phone.placeholder": "+88 মোবাইল নম্বর",
+  "auth.register.verifyCode.placeholder": "যাচাইকরণ কোড",
+  "auth.register.password.placeholder": "পাসওয়ার্ড ৬-২০ অক্ষর",
   "auth.register.referrerCode.placeholder": "রেফারার কোড",
   "auth.register.getCode": "কোড পান",
   "auth.register.button": "নিবন্ধন",
-  "auth.register.hasAccount": "ইতিমধ্যে একাউন্ট আছে?",
+  "auth.register.hasAccount": "ইতিমধ্যে অ্যাকাউন্ট আছে?",
   "auth.register.loginNow": "এখনই লগইন করুন",
   "auth.register.error.emptyUsername": "অনুগ্রহ করে ব্যবহারকারীর নাম লিখুন",
   "auth.register.error.emptyPhone": "অনুগ্রহ করে ফোন নম্বর লিখুন",
-  "auth.register.error.invalidPhone": "অনুগ্রহ করে বৈধ বাংলাদেশি ফোন নম্বর লিখুন",
-  "auth.register.error.emptyVerifyCode": "অনুগ্রহ করে ভেরিফিকেশন কোড লিখুন",
+  "auth.register.error.invalidPhone": "অনুগ্রহ করে একটি বৈধ বাংলাদেশ ফোন নম্বর লিখুন",
+  "auth.register.error.emptyVerifyCode": "অনুগ্রহ করে যাচাইকরণ কোড লিখুন",
   "auth.register.error.emptyPassword": "অনুগ্রহ করে পাসওয়ার্ড লিখুন",
-  "auth.register.error.passwordLength": "পাসওয়ার্ড 6-20 অক্ষরের মধ্যে হতে হবে",
-  "auth.register.success.codeSent": "ভেরিফিকেশন কোড সফলভাবে পাঠানো হয়েছে",
-  "auth.register.success.registered": "নিবন্ধন সফল হয়েছে",
-  "auth.register.error.registrationFailed": "নিবন্ধন ব্যর্থ হয়েছে",
+  "auth.register.error.passwordLength": "পাসওয়ার্ড ৬-২০ অক্ষরের হতে হবে",
+  "auth.register.success.codeSent": "যাচাইকরণ কোড সফলভাবে পাঠানো হয়েছে",
+  "auth.register.success.registered": "নিবন্ধন সফল",
+  "auth.register.error.registrationFailed": "নিবন্ধন ব্যর্থ",
+  "auth.forgotPassword.title": "পাসওয়ার্ড ভুলে গেছেন",
+  "auth.forgotPassword.phone.placeholder": "ফোন নম্বর",
+  "auth.forgotPassword.verifyCode.placeholder": "যাচাইকরণ কোড",
+  "auth.forgotPassword.newPassword.placeholder": "নতুন পাসওয়ার্ড",
+  "auth.forgotPassword.confirmPassword.placeholder": "পাসওয়ার্ড নিশ্চিত করুন",
+  "auth.forgotPassword.getCode": "কোড পান",
+  "auth.forgotPassword.button": "পাসওয়ার্ড রিসেট করুন",
+  "auth.forgotPassword.backToLogin": "লগইনে ফিরে যান",
+  "auth.forgotPassword.error.emptyPhone": "অনুগ্রহ করে ফোন নম্বর লিখুন",
+  "auth.forgotPassword.error.invalidPhone": "অনুগ্রহ করে বৈধ ফোন নম্বর লিখুন",
+  "auth.forgotPassword.error.emptyVerifyCode": "অনুগ্রহ করে যাচাইকরণ কোড লিখুন",
+  "auth.forgotPassword.error.emptyNewPassword": "অনুগ্রহ করে নতুন পাসওয়ার্ড লিখুন",
+  "auth.forgotPassword.error.passwordLength": "পাসওয়ার্ড ৬-২০ অক্ষরের হতে হবে",
+  "auth.forgotPassword.error.emptyConfirmPassword": "অনুগ্রহ করে আপনার পাসওয়ার্ড নিশ্চিত করুন",
+  "auth.forgotPassword.error.passwordMismatch": "পাসওয়ার্ড মিলছে না",
+  "auth.forgotPassword.success.codeSent": "যাচাইকরণ কোড সফলভাবে পাঠানো হয়েছে",
+  "auth.forgotPassword.success.passwordReset": "পাসওয়ার্ড সফলভাবে রিসেট হয়েছে",
+  "auth.forgotPassword.error.sendCodeFailed": "যাচাইকরণ কোড পাঠাতে ব্যর্থ",
+  "auth.forgotPassword.error.resetFailed": "পাসওয়ার্ড রিসেট করতে ব্যর্থ",
+  "auth.forgotPassword.passwordHint": "আপনার পাসওয়ার্ড পূর্বে ব্যবহৃত পাসওয়ার্ড থেকে আলাদা হতে হবে",
+  "auth.forgotPassword.hasAccount": "ইতিমধ্যে অ্যাকাউন্ট আছে?",
+  "auth.forgotPassword.loginNow": "এখনই লগইন করুন",
   "common.loading": "লোড হচ্ছে...",
   "common.saving": "সংরক্ষণ করা হচ্ছে...",
-  "login.slogan": "More group purchases, bigger rewards"
+  "common.success": "সফল",
+  "common.error": "ত্রুটি",
+  "common.confirm": "নিশ্চিত করুন",
+  "common.cancel": "বাতিল",
+  "common.submit": "জমা দিন",
+  "common.save": "সংরক্ষণ",
+  "common.edit": "সম্পাদনা",
+  "common.delete": "মুছুন",
+  "common.add": "যোগ করুন",
+  "common.search": "অনুসন্ধান",
+  "common.filter": "ফিল্টার",
+  "common.all": "সব",
+  "common.none": "কোনটি নয়",
+  "common.empty": "কোনো ডেটা নেই",
+  "common.retry": "আবার চেষ্টা করুন",
+  "common.back": "ফিরে যান",
+  "common.next": "পরবর্তী",
+  "common.previous": "পূর্ববর্তী",
+  "common.close": "বন্ধ করুন",
+  "common.open": "খুলুন",
+  "common.view": "দেখুন",
+  "common.more": "আরও",
+  "wallet.myWallet.title": "আমার ওয়ালেট",
+  "wallet.balance": "ওয়ালেট অ্যাকাউন্ট ব্যালেন্স",
+  "wallet.frozenBalance": "ওয়ালেট হিমায়িত ব্যালেন্স",
+  "wallet.recharge": "রিচার্জ",
+  "wallet.withdrawNow": "এখনই উত্তোলন করুন",
+  "wallet.record": "ওয়ালেট রেকর্ড",
+  "wallet.filter.all": "সব",
+  "wallet.filter.recharge": "রিচার্জ",
+  "wallet.filter.withdraw": "উত্তোলন",
+  "wallet.filter.commission": "কমিশন",
+  "wallet.rechargeRecord.title": "রিচার্জ রেকর্ড",
+  "wallet.withdrawRecord.title": "উত্তোলন রেকর্ড",
+  "missionCenter.title": "মিশন সেন্টার",
+  "referEarn.title": "রেফার এবং আয়",
+  "vipMembership.title": "ভিআইপি সদস্যতা",
+  "notifications.title": "বিজ্ঞপ্তি",
+  "notifications.tabs.all": "সব",
+  "notifications.tabs.orders": "অর্ডার",
+  "notifications.tabs.revenue": "রাজস্ব",
+  "notifications.tabs.account": "অ্যাকাউন্ট",
+  "notifications.tabs.promos": "প্রচার",
+  "notifications.time.sunday": "রবি",
+  "notifications.time.monday": "সোম",
+  "notifications.time.tuesday": "মঙ্গল",
+  "notifications.time.wednesday": "বুধ",
+  "notifications.time.thursday": "বৃহস্পতি",
+  "notifications.time.friday": "শুক্র",
+  "notifications.time.saturday": "শনি",
+  "notifications.order.paymentSuccess.title": "গ্রুপ বাই পেমেন্ট সফল",
+  "notifications.order.paymentSuccess.content": "আপনার অংশগ্রহণ করা গ্রুপ অর্ডার [{orderId}] সফলভাবে পেমেন্ট হয়েছে",
+  "notifications.order.groupBuyWin.title": "গ্রুপ বাই সফল",
+  "notifications.order.groupBuyWin.content": "আপনার অংশগ্রহণ করা গ্রুপ অর্ডার [{orderId}] নির্বাচিত হয়েছে",
+  "notifications.order.groupBuyLose.title": "গ্রুপ বাই সফল",
+  "notifications.order.groupBuyLose.content": "আপনার অংশগ্রহণ করা গ্রুপ অর্ডার [{orderId}] নির্বাচিত হয়নি",
+  "notifications.order.provideAddress.title": "অর্ডার শিপিং ঠিকানা প্রদান",
+  "notifications.order.provideAddress.content": "আপনার অংশগ্রহণ করা গ্রুপ অর্ডার [{orderId}] অনুগ্রহ করে আপনার শিপিং ঠিকানা প্রদান করুন",
+  "notifications.order.groupBuyFail.title": "গ্রুপ বাই ব্যর্থ",
+  "notifications.order.groupBuyFail.content": "আপনার অংশগ্রহণ করা গ্রুপ অর্ডার [{orderId}] ব্যর্থ হয়েছে",
+  "notifications.order.shipped.title": "অর্ডার সফলভাবে শিপ হয়েছে",
+  "notifications.order.shipped.content": "আপনার অংশগ্রহণ করা গ্রুপ অর্ডার [{orderId}] সফলভাবে শিপ হয়েছে",
+  "notifications.reward.referFriends.title": "বন্ধু রেফার পুরস্কার",
+  "notifications.reward.referFriends.content": "আপনি বন্ধু রেফারের জন্য পুরস্কার পেয়েছেন",
+  "notifications.reward.groupBuy.title": "গ্রুপ বাই যোগ দিন পুরস্কার",
+  "notifications.reward.groupBuy.content": "আপনি একটি পুরস্কার পেয়েছেন, অর্ডার আইডি [{orderId}]",
+  "notifications.reward.openGroupBuy.title": "গ্রুপ বাই খোলা পুরস্কার",
+  "notifications.reward.openGroupBuy.content": "আপনি একটি পুরস্কার পেয়েছেন, অর্ডার আইডি [{orderId}]",
+  "notifications.reward.directReferral.title": "সরাসরি রেফারেল পুরস্কার",
+  "notifications.reward.directReferral.content": "আপনি সরাসরি রেফারেলের জন্য পুরস্কার পেয়েছেন",
+  "notifications.reward.checkin.title": "চেক-ইন পুরস্কার",
+  "notifications.reward.checkin.content": "আপনি চেক-ইনের জন্য পুরস্কার পেয়েছেন",
+  "notifications.reward.firstCommission.title": "সরাসরি রেফারেল পুরস্কার",
+  "notifications.reward.firstCommission.content": "আপনি সরাসরি রেফারেলের জন্য পুরস্কার পেয়েছেন",
+  "notifications.reward.secondaryCommission.title": "সরাসরি রেফারেল পুরস্কার",
+  "notifications.reward.secondaryCommission.content": "আপনি সরাসরি রেফারেলের জন্য পুরস্কার পেয়েছেন",
+  "notifications.money.rechargeSuccess.title": "রিচার্জ সফল",
+  "notifications.money.rechargeSuccess.content": "আপনার KLICKwallet সফলভাবে রিচার্জ হয়েছে",
+  "notifications.money.withdrawalAccountSuccess.title": "উত্তোলন সফল",
+  "notifications.money.withdrawalAccountSuccess.content": "আপনার রাজস্ব অ্যাকাউন্ট উত্তোলনের অনুরোধ প্রক্রিয়াকরণ করা হয়েছে",
+  "notifications.money.withdrawalWalletSuccess.title": "উত্তোলন সফল",
+  "notifications.money.withdrawalWalletSuccess.content": "আপনার KLICK ওয়ালেট উত্তোলনের অনুরোধ প্রক্রিয়াকরণ করা হয়েছে",
+  "notifications.money.withdrawalFail.title": "উত্তোলন ব্যর্থ",
+  "notifications.money.withdrawalFail.content": "আপনার উত্তোলনের অনুরোধ ব্যর্থ হয়েছে",
+  "productDetail.title": "পণ্যের বিস্তারিত",
+  "productDetail.notification.message": "{name} এই গ্রুপ {time} সেকেন্ড আগে {action}!",
+  "productDetail.notification.opened": "খুলেছে",
+  "productDetail.notification.joined": "যোগ দিয়েছে",
+  "webLink.title": "ওয়েব লিংক",
+  "missionCenter.signIn.title": "পুরস্কার পেতে ধারাবাহিকভাবে সাইন ইন করুন",
+  "missionCenter.signIn.button": "চেক-ইন",
+  "missionCenter.dailyMission.title": "দৈনিক মিশন",
+  "missionCenter.dailyMission.startNow": "এখনই শুরু করুন",
+  "vipMembership.inviteProgress": "আমাদের এখনও {0} বন্ধুদের আমন্ত্রণ করতে হবে। V{1} এ আপগ্রেড করা যেতে পারে",
+  "vipMembership.invitedFriends": "আমন্ত্রিত বন্ধু",
+  "vipMembership.teamMembers": "দলের সদস্য",
+  "vipMembership.l7dEarnings": "গত ৭ দিনের আয়",
+  "vipMembership.benefitsTiers": "ভিআইপি সুবিধা/স্তর",
+  "vipMembership.table.vipLevel": "ভিআইপি\nস্তর",
+  "vipMembership.table.invitedNo": "আমন্ত্রিত\nনং",
+  "vipMembership.table.directReferralReward": "সরাসরি রেফারেল\nপুরস্কার",
+  "vipMembership.table.indirectReferralReward": "পরোক্ষ রেফারেল\nপুরস্কার",
+  "vipMembership.table.joinedGroupsNo": "যোগ দেওয়া গ্রুপ\nনং",
+  "referEarn.inviteFriends": "বন্ধুদের আমন্ত্রণ করুন",
+  "referEarn.earnCash": "নগদ টাকা উপার্জন করুন",
+  "referEarn.shareNow": "এখনই শেয়ার করুন",
+  "referEarn.howToShare": "- কীভাবে শেয়ার করে টাকা উপার্জন করবেন -",
+  "referEarn.step1": "আমন্ত্রণ বন্ধুদের শেয়ার করুন",
+  "referEarn.step2": "আপনার বন্ধু গ্রুপে যোগ দিন",
+  "referEarn.step3": "আপনি ৳{0} পুরস্কার পান",
+  "referEarn.invitedFriends": "আমন্ত্রিত বন্ধু",
+  "checkout.title": "চেকআউট",
+  "checkout.selected": "নির্বাচিত",
+  "checkout.quantity": "পরিমাণ",
+  "checkout.orderSummary": "অর্ডার সারাংশ",
+  "checkout.subTotal": "মোট",
+  "checkout.total": "মোট",
+  "checkout.selectPaymentMethod": "পেমেন্ট পদ্ধতি নির্বাচন করুন",
+  "checkout.walletBalance": "ব্যালেন্স",
+  "checkout.placeOrder": "অর্ডার করুন",
+  "checkout.dialog.insufficientBalance": "আপনার ওয়ালেট ব্যালেন্স অপর্যাপ্ত।\nঅনুগ্রহ করে রিচার্জ করুন!",
+  "checkout.dialog.rechargeDiscount": "রিচার্জ সর্বোচ্চ ছাড় ৫%",
+  "checkout.dialog.rechargeNow": "এখনই রিচার্জ করুন",
+  "checkout.dialog.paymentSuccess": "পেমেন্ট সফল!\nআপনার অর্ডার করা হয়েছে।",
+  "checkout.dialog.viewOrder": "অর্ডার দেখুন",
+  "checkout.dialog.paymentFailed": "পেমেন্ট ব্যর্থ!\nঅনুগ্রহ করে আবার চেষ্টা করুন বা সমর্থন যোগাযোগ করুন।",
+  "checkout.dialog.retryPayment": "পেমেন্ট আবার চেষ্টা করুন",
+  "checkout.dialog.networkError": "নেটওয়ার্ক সংযোগ ব্যর্থ।\nঅনুগ্রহ করে আপনার নেটওয়ার্ক সেটিংস পরীক্ষা করুন।",
+  "checkout.dialog.retry": "আবার চেষ্টা করুন",
+  "checkout.dialog.gotIt": "বুঝেছি",
+  "checkout.toast.redirecting": "অর্ডারে পুনঃনির্দেশিত হচ্ছে...",
+  "checkout.toast.retrying": "আবার চেষ্টা করা হচ্ছে...",
+  "bestSellers.title": "সেরা বিক্রেতা",
+  "bestSellers.successfullyGrouped": "গত ৭ দিনে {0} এর বেশি সফলভাবে গ্রুপ করা হয়েছে",
+  "productDetail.price": "দাম",
+  "productDetail.sold": "{0} বিক্রি হয়েছে",
+  "productDetail.groupRules": "গ্রুপ নিয়ম",
+  "productDetail.viewRules": "নিয়ম দেখুন",
+  "productDetail.viewRulesLinkTitle": "গ্রুপ ক্রয় নিয়ম",
+  "productDetail.ongoingGroup": "চলমান গ্রুপ",
+  "productDetail.need": "প্রয়োজন",
+  "productDetail.more": "আরও",
+  "productDetail.joinGroup": "গ্রুপে যোগ দিন",
+  "productDetail.details": "বিস্তারিত",
+  "productDetail.home": "হোম",
+  "productDetail.favorite": "পছন্দ",
+  "productDetail.favoriteSuccess": "পছন্দে যোগ করা হয়েছে",
+  "productDetail.unfavoriteSuccess": "পছন্দ থেকে সরানো হয়েছে",
+  "productDetail.favoriteError": "অপারেশন ব্যর্থ, অনুগ্রহ করে আবার চেষ্টা করুন",
+  "productDetail.openGroup": "গ্রুপ খুলুন",
+  "productDetail.quantity": "পরিমাণ",
+  "topChampions.title": "শীর্ষ চ্যাম্পিয়ন",
+  "topChampions.top": "শীর্ষ",
+  "topChampions.invitedFriends": "আমন্ত্রিত বন্ধু",
+  "topChampions.l7dEarnings": "গত ৭ দিনের আয়",
+  "topChampions.teamMembers": "দলের সদস্য",
+  "topChampions.joinedGroups": "যোগ দেওয়া গ্রুপ",
+  "wallet.recharge.title": "রিচার্জ",
+  "wallet.recharge.submit": "জমা দিন",
+  "orderDetail.deliveryPartner": "ডেলিভারি পার্টনার",
+  "orderDetail.subTotal": "মোট",
+  "orderDetail.bandhuBuyWallet": "BandhuBuy ওয়ালেট",
+  "orderDetail.paymentMethod": "পেমেন্ট",
+  "orderDetail.walletBalanceText": "ভারসাম্য",
+  "productDetail.fullRefundText": "জিততে না পারলে পুরো ফেরত + নগদ পুরস্কার",
+  "app.notificationPermission": "আপনি বিজ্ঞপ্তি অনুমতি খুলেননি",
+  "wallet.recharge.record": "রেকর্ড",
+  "wallet.recharge.selectProvider": "আপনার ওয়ালেট প্রোভাইডার নির্বাচন করুন",
+  "wallet.recharge.depositAmount": "জমা পরিমাণ",
+  "wallet.recharge.reminder": "স্মরণ: রিচার্জ সফল না হলে, অনুগ্রহ করে অন্য চ্যানেল নির্বাচন করুন। লেনদেন আইডি সঠিকভাবে পূরণ করতে হবে।",
+  "wallet.recharge.enterAmount": "অনুগ্রহ করে রিচার্জ পরিমাণ লিখুন",
+  "wallet.recharge.minAmount": "ন্যূনতম {minAmount}",
+  "wallet.recharge.maxAmount": "সর্বোচ্চ {maxAmount}",
+  "orderDetail.rechargeDialog.title": "আপনার ওয়ালেট ব্যালেন্স অপর্যাপ্ত।\nঅনুগ্রহ করে রিচার্জ করুন!",
+  "orderDetail.rechargeDialog.confirm": "এখনই রিচার্জ করুন",
+  "orderDetail.payDialog.title": "পেমেন্ট",
+  "orderDetail.payDialog.confirm": "এখনই পেমেন্ট করুন",
+  "orderDetail.time.placed": "অর্ডার করা হয়েছে",
+  "orderDetail.time.paid": "পেমেন্ট করা হয়েছে",
+  "orderDetail.time.shipped": "শিপ করা হয়েছে",
+  "orderDetail.time.completed": "সম্পন্ন হয়েছে",
+  "orderDetail.copy.success": "ক্লিপবোর্ডে অনুলিপি করা হয়েছে",
+  "wallet.unpaidOrderDialog.title": "আপনার কাছে অসম্পন্ন টপ আপ অর্ডার রয়েছে,\nআপনি কি চালিয়ে যেতে চান?",
+  "wallet.unpaidOrderDialog.confirm": "দেখুন",
+  "wallet.unpaidOrderDialog.cancel": "বাতিল",
+  "wallet.record.type.DT": "আজকে",
+  "wallet.record.type.YT": "গতকাল",
+  "wallet.record.type.L7D": "গত ৭ দিন",
+  "wallet.record.type.MTD": "এই মাসে",
+  "wallet.record.type.YTD": "এই বছরে",
+  "login.slogan": "আরও গ্রুপ ক্রয়, আরও বড় পুরস্কার",
+  "common.operate.success": "অপারেশন সফল",
+
+  "uni.app.quit": "অ্যাপ্লিকেশন থেকে আবার ক্লিক করুন",
+  "uni.async.error": "সার্ভারের সাথে সংযোগ সময়সীমা শেষ হয়েছে, স্ক্রিনে ক্লিক করে পুনরায় চেষ্টা করুন",
+  "uni.showActionSheet.cancel": "বাতিল করুন",
+  "uni.showToast.unpaired": "দয়া করে লক্ষ্য করুন showToast এবং hideToast অবশ্যই জোড়াযুক্তভাবে ব্যবহার করতে হবে",
+  "uni.showLoading.unpaired": "দয়া করে লক্ষ্য করুন showLoading এবং hideLoading অবশ্যই জোড়াযুক্তভাবে ব্যবহার করতে হবে",
+  "uni.showModal.cancel": "বাতিল করুন",
+  "uni.showModal.confirm": "নিশ্চিত করুন",
+  "uni.chooseImage.cancel": "বাতিল করুন",
+  "uni.chooseImage.sourceType.album": "আলবাম থেকে বেছে নিন",
+  "uni.chooseImage.sourceType.camera": "ছবি তুলুন",
+  "uni.chooseVideo.cancel": "বাতিল করুন",
+  "uni.chooseVideo.sourceType.album": "আলবাম থেকে বেছে নিন",
+  "uni.chooseVideo.sourceType.camera": "ভিডিও রেকর্ড করুন",
+  "uni.previewImage.cancel": "বাতিল করুন",
+  "uni.previewImage.button.save": "ছবি সংরক্ষণ করুন",
+  "uni.previewImage.save.success": "ছবি আলবামে সংরক্ষণ করা হয়েছে",
+  "uni.previewImage.save.fail": "ছবি আলবামে সংরক্ষণ করতে ব্যর্থ হয়েছে",
+  "uni.setClipboardData.success": "কন্টেন্ট কপি করা হয়েছে",
+  "uni.scanCode.title": "কোড স্ক্যান করুন",
+  "uni.scanCode.album": "আলবাম",
+  "uni.scanCode.fail": "সনাক্তকরণ ব্যর্থ হয়েছে",
+  "uni.scanCode.flash.on": "আলোক করার জন্য ট্যাপ করুন",
+  "uni.scanCode.flash.off": "বন্ধ করার জন্য ট্যাপ করুন",
+  "uni.startSoterAuthentication.authContent": "ফিঙ্গারপ্রিন্ট সনাক্তকরণ চলছে...",
+  "uni.picker.done": "সম্পন্ন",
+  "uni.picker.cancel": "বাতিল করুন",
+  "uni.video.danmu": "ড্যানমু (কমেন্ট স্ট্রিম)",
+  "uni.video.volume": "বল륮",
+  "uni.button.feedback.title": "문제 প্রতিক্রিয়া",
+  "uni.button.feedback.send": "পাঠান"
 }

+ 402 - 2
src/locale/en.json

@@ -1,7 +1,193 @@
 {
+  "addressBook.title": "Address Book",
+  "addressBook.operate.title.add": "Add Address",
+  "addressBook.operate.title.edit": "Edit Address",
+  "addressBook.operate.loading": "Loading...",
+  "addressBook.operate.saving": "Saving...",
+  "addressBook.operate.form.fullName": "Full Name",
+  "addressBook.operate.form.phone": "Phone Number",
+  "addressBook.operate.form.phone.placeholder": "+88",
+  "addressBook.operate.form.district": "Privince/District",
+  "addressBook.operate.form.district.placeholder": "Please Choose",
+  "addressBook.operate.form.street": "Floor/Unit No./Street",
+  "addressBook.operate.form.street.placeholder": "Detailed Address",
+  "addressBook.operate.form.postcode": "Postcode",
+  "addressBook.operate.form.postcode.placeholder": "Your Postcode",
+  "addressBook.operate.form.default": "Default",
+  "addressBook.operate.button.save": "Save",
+  "addressBook.operate.button.update": "Update",
+  "addressBook.operate.error.loadFailed": "Failed to load address details",
+  "addressBook.operate.error.emptyName": "Please enter full name",
+  "addressBook.operate.error.emptyPhone": "Please enter phone number",
+  "addressBook.operate.error.emptyDistrict": "Please select province/district",
+  "addressBook.operate.error.emptyStreet": "Please enter detailed address",
+  "addressBook.operate.success.update": "Address updated successfully",
+  "addressBook.operate.success.save": "Address saved successfully",
+  "addressBook.operate.error.saveFailed": "Save failed, please try again",
+  "addressBook.operate.error.loadPage": "Page load failed",
+  "addressBook.delete.deleting": "Deleting...",
+  "addressBook.delete.success": "Address deleted successfully",
+  "myOrders.title": "My Orders",
+  "myOrders.tab.all": "All",
+  "myOrders.tab.toPay": "To Pay",
+  "myOrders.tab.success": "Success",
+  "myOrders.tab.failed": "Failed",
+  "myOrders.tab.reward": "Reward",
+  "myOrders.order.id": "Order ID",
+  "myOrders.order.color": "Color",
+  "myOrders.order.quantity": "Quantity",
+  "orderDetail.title": "Order Detail",
+  "orderDetail.loading": "Loading...",
+  "orderDetail.congrats": "Congrats, You won the prize in this group!",
+  "orderDetail.receiveReward": "You have received group opening reward",
+  "orderDetail.sorry": "So sorry, You didn't win in this group",
+  "orderDetail.waiting": "Please wait for the draw of this group",
+  "orderDetail.paymentCountdown": "Please make payment within:",
+  "orderDetail.address.add": "Please provide your shipping address",
+  "orderDetail.address.name": "Recipient",
+  "orderDetail.address.orderNo": "Order ID",
+  "orderDetail.address.color": "Color",
+  "orderDetail.address.quantity": "Quantity",
+  "orderDetail.summary.title": "Order Summary",
+  "orderDetail.summary.subtotal": "SubTotal",
+  "orderDetail.payment.title": "Paid by",
+  "orderDetail.payment.placedOn": "Placed on",
+  "orderDetail.button.cancel": "Cancel",
+  "orderDetail.button.share": "Share Now",
+  "orderDetail.button.pay": "Pay Now",
+  "orderDetail.dialog.cancel.title": "Are you sure you want to cancel this order?",
+  "orderDetail.dialog.cancel.confirm": "Yes, Cancel",
+  "orderDetail.dialog.cancel.keep": "Keep Order",
+  "orderDetail.cancel.loading": "Cancelling order...",
+  "orderDetail.cancel.success": "Order cancelled successfully!",
+  "orderDetail.cancel.error": "Failed to cancel order. Please try again.",
+  "orderDetail.cancel.network": "Network error. Please check your connection and try again.",
+  "orderDetail.payment.success": "Payment Successful",
+  "wallet.withdraw.success": "Withdrawal request submitted successfully",
+  "wallet.withdraw.fail": "Failed to submit withdrawal request, please try again",
+  "addressBook.delete.confirm": "Confirm Delete",
+  "addressBook.delete.message": "Are you sure you want to delete this address?",
+  "addressBook.delete.button": "Delete",
+  "addressBook.tag.default": "Default",
+  "addressBook.button.add": "Add New Address",
+  "addressBook.select.binding": "Binding address...",
+  "addressBook.select.success": "Address bound successfully!",
+  "addressBook.select.failed": "Failed to bind address. Please try again.",
+  "addressBook.select.networkError": "Network error. Please check your connection and try again.",
+  "myProfile.title": "My Profile",
+  "myProfile.avatar": "Avatar",
+  "myProfile.userId": "User ID",
+  "myProfile.userName": "User Name",
+  "myProfile.mobileNumber": "Mobile Number",
+  "myProfile.bankName": "Bank Name",
+  "myProfile.bankAccountName": "Bank Account Name",
+  "myProfile.bankAccountNo": "Bank Account No.",
+  "myProfile.upload.sizeLimit": "Image size cannot exceed 5MB",
+  "myProfile.upload.uploading": "Uploading...",
+  "myProfile.upload.success": "Avatar updated successfully",
+  "myProfile.upload.error": "Failed to update avatar",
+  "setting.title": "Setting",
+  "setting.changePassword": "Change Password",
+  "setting.language": "Language",
+  "setting.policies": "Privacy Policy",
+  "setting.termsOfService": "Terms of Service",
+  "setting.refund": "Return & Refund Policy",
+  "setting.logout": "Logout",
+  "setting.version": "Version {0}",
+  "setting.lang.en": "English",
+  "setting.lang.bn": "Bengali",
+  "home.missionCenter": "Mission\nCenter",
+  "home.refer&earn": "Refer\n&Earn",
+  "home.vip": "VIP\nMembership",
+  "home.bestSellers": "Best\nSellers",
+  "home.topChampions": "Top\nChampions",
+  "home.news": "News",
+  "home.priceTab.allPrice": "All Price",
+  "home.priceTab.300spot": "300Spot",
+  "home.priceTab.500spot": "500Spot",
+  "home.priceTab.1000spot": "1000Spot",
+  "home.priceTab.2000spot": "2000Spot",
+  "home.priceTab.3000spot": "3000Spot",
+  "search.placeholder": "Search",
+  "search.filterPrice": "All Price",
+  "search.filterCategory": "Category",
+  "search.filterSellers": "BestSellers",
+  "search.filterSellers1": "Latest",
+  "app.name": "En Title",
+  "income.title": "Revenue Center",
+  "mine.auth.register": "Register",
+  "mine.auth.login": "Login",
+  "mine.wallet.title": "BandhuBuy Wallet",
+  "mine.wallet.balance": "Wallet Account Balance",
+  "mine.wallet.recharge": "Recharge",
+  "mine.group.title": "My Group",
+  "mine.group.all": "All Group",
+  "mine.group.toPay": "To Pay",
+  "mine.group.success": "Success",
+  "mine.group.failed": "Failed",
+  "mine.group.reward": "Reward",
+  "mine.menu.profile": "My Profile",
+  "mine.menu.address": "Address Book",
+  "mine.menu.share": "Share",
+  "mine.menu.favorite": "My Favorite",
+  "mine.menu.chat": "Live Chat",
+  "mine.menu.activity": "Activity Group",
+  "income.totalEarnings": "Total Earnings",
+  "income.accountBalance": "Revenue Account Balance",
+  "income.settledAmount": "Settled Amount",
+  "income.pendingAmount": "Pending Amount",
+  "income.tdEarnings": "TD Earnings",
+  "income.ydEarnings": "YD Earnings",
+  "income.mtdEarnings": "MTD Earnings",
+  "income.myGroupData": "My Group Data",
+  "wallet.withdraw.title": "Withdraw",
+  "wallet.withdraw.balance": "Wallet Balance",
+  "wallet.withdraw.info": "Withdrawal information",
+  "wallet.withdraw.form.bankName": "Bank Name",
+  "wallet.withdraw.form.bankAccountName": "Bank Account Name",
+  "wallet.withdraw.form.bankAccountNo": "Bank Account No.",
+  "wallet.withdraw.form.amount": "Withdrawal Amount",
+  "wallet.withdraw.form.allAmount": "All Amounts",
+  "wallet.withdraw.form.submit": "Submit",
+  "wallet.withdraw.record": "Record",
+  "wallet.withdraw.error.bankName": "Please select bank",
+  "wallet.withdraw.error.bankAccountName": "Please enter Bank Account Name",
+  "wallet.withdraw.error.bankAccountNo": "Please enter Bank Account No.",
+  "wallet.withdraw.error.amount": "Please enter Withdrawal Amount",
+  "wallet.withdraw.notes.title": "Notes:",
+  "wallet.withdraw.notes.1": "Withdrawal Review Hours Are From 9 AM To 10 PM. Expected to arrive within 2 hours after withdrawal, actual arrival time is subject to the final successful processing time",
+  "wallet.withdraw.notes.2": "Make sure your bank account details is correct.",
+  "wallet.withdraw.notes.3": "The withdrawal bank account information must be consistent with the registered account information.",
+  "wallet.withdraw.notes.4": "The minimum amount for a single withdrawal is ৳{0} and the maximum is ৳{1};",
+  "wallet.withdraw.notes.5": "Every withdrawal you make will incur a {0}% withdrawal handling fee;",
+  "income.withdrawNow": "Withdraw Now",
+  "income.revenueRecord": "Revenue Record",
+  "income.filter.dt": "DT",
+  "income.filter.yt": "YT",
+  "income.filter.l7d": "L7D",
+  "income.filter.mtd": "MTD",
+  "income.filter.ytd": "YTD",
+  "mine.pages.share.title": "Share",
+  "mine.pages.share.referrerCode": "My Referrer Code",
+  "mine.pages.share.qrCode": "QR Code",
+  "mine.pages.share.description": "Share your QR code with your friends, they can scan it with their camera to register as your downline.",
+  "mine.pages.share.copySuccess": "Copied to clipboard",
+  "mine.pages.share.shareTo": "Share to {0}",
+  "mine.pages.myFavorite.title": "My Favorite",
+  "mine.pages.myFavorite.empty": "No favorites yet",
+  "auth.login.title": "Login",
+  "auth.login.username.placeholder": "Mobile number / Username",
+  "auth.login.password.placeholder": "Password 6-20 characters",
+  "auth.login.button": "Login",
+  "auth.login.noAccount": "Do Not Have An Account Yet?",
+  "auth.login.register": "Register",
+  "auth.login.forgotPassword": "Forgot Password?",
+  "auth.login.error.emptyUsername": "Please enter username or phone number",
+  "auth.login.error.emptyPassword": "Please enter password",
+  "auth.login.error.passwordLength": "Password should be 6-20 characters",
   "auth.register.title": "Register",
   "auth.register.username.placeholder": "Username",
-  "auth.register.phone.placeholder": "Mobile number",
+  "auth.register.phone.placeholder": "+88 Mobile number",
   "auth.register.verifyCode.placeholder": "Verification Code",
   "auth.register.password.placeholder": "Password 6-20 characters",
   "auth.register.referrerCode.placeholder": "Referrer Code",
@@ -18,7 +204,221 @@
   "auth.register.success.codeSent": "Verification code sent successfully",
   "auth.register.success.registered": "Registration successful",
   "auth.register.error.registrationFailed": "Registration failed",
+  "auth.forgotPassword.title": "Forgot Password",
+  "auth.forgotPassword.phone.placeholder": "Phone number",
+  "auth.forgotPassword.verifyCode.placeholder": "Verification Code",
+  "auth.forgotPassword.newPassword.placeholder": "New Password",
+  "auth.forgotPassword.confirmPassword.placeholder": "Confirm Password",
+  "auth.forgotPassword.getCode": "Get Code",
+  "auth.forgotPassword.button": "Reset Password",
+  "auth.forgotPassword.backToLogin": "Back to Login",
+  "auth.forgotPassword.error.emptyPhone": "Please enter phone number",
+  "auth.forgotPassword.error.invalidPhone": "Please enter valid phone number",
+  "auth.forgotPassword.error.emptyVerifyCode": "Please enter verification code",
+  "auth.forgotPassword.error.emptyNewPassword": "Please enter new password",
+  "auth.forgotPassword.error.passwordLength": "Password should be 6-20 characters",
+  "auth.forgotPassword.error.emptyConfirmPassword": "Please confirm your password",
+  "auth.forgotPassword.error.passwordMismatch": "Passwords do not match",
+  "auth.forgotPassword.success.codeSent": "Verification code sent successfully",
+  "auth.forgotPassword.success.passwordReset": "Password reset successfully",
+  "auth.forgotPassword.error.sendCodeFailed": "Failed to send verification code",
+  "auth.forgotPassword.error.resetFailed": "Failed to reset password",
+  "auth.forgotPassword.passwordHint": "Your password must be different from previous used password",
+  "auth.forgotPassword.hasAccount": "Already have account?",
+  "auth.forgotPassword.loginNow": "Login Now",
   "common.loading": "Loading...",
   "common.saving": "Saving...",
-  "login.slogan": "More group purchases, bigger rewards"
+  "common.success": "Success",
+  "common.error": "Error",
+  "common.confirm": "Confirm",
+  "common.cancel": "Cancel",
+  "common.submit": "Submit",
+  "common.save": "Save",
+  "common.edit": "Edit",
+  "common.delete": "Delete",
+  "common.add": "Add",
+  "common.search": "Search",
+  "common.filter": "Filter",
+  "common.all": "All",
+  "common.none": "None",
+  "common.empty": "No data available",
+  "common.retry": "Retry",
+  "common.back": "Back",
+  "common.next": "Next",
+  "common.previous": "Previous",
+  "common.close": "Close",
+  "common.open": "Open",
+  "common.view": "View",
+  "common.more": "More",
+  "wallet.myWallet.title": "My Wallet",
+  "wallet.balance": "Wallet Account Balance",
+  "wallet.frozenBalance": "Wallet Frozen Balance",
+  "wallet.recharge": "Recharge",
+  "wallet.withdrawNow": "Withdraw Now",
+  "wallet.record": "Wallet Record",
+  "wallet.filter.all": "All",
+  "wallet.filter.recharge": "Recharge",
+  "wallet.filter.withdraw": "Withdraw",
+  "wallet.filter.commission": "Commission",
+  "wallet.rechargeRecord.title": "Recharge Record",
+  "wallet.withdrawRecord.title": "Withdraw Record",
+  "missionCenter.title": "Mission Center",
+  "referEarn.title": "Refer & Earn",
+  "vipMembership.title": "VIP Membership",
+  "notifications.title": "Notifications",
+  "notifications.tabs.all": "All",
+  "notifications.tabs.orders": "Orders",
+  "notifications.tabs.revenue": "Revenue",
+  "notifications.tabs.account": "Account",
+  "notifications.tabs.promos": "Promos",
+  "notifications.time.sunday": "Sun",
+  "notifications.time.monday": "Mon",
+  "notifications.time.tuesday": "Tue",
+  "notifications.time.wednesday": "Wed",
+  "notifications.time.thursday": "Thu",
+  "notifications.time.friday": "Fri",
+  "notifications.time.saturday": "Sat",
+  "notifications.order.paymentSuccess.title": "Group Buy Payment Successful",
+  "notifications.order.paymentSuccess.content": "The group order you participated in [{orderId}] has been successfully paid",
+  "notifications.order.groupBuyWin.title": "Group Buy Successful",
+  "notifications.order.groupBuyWin.content": "The group order you participated in [{orderId}] has been selected",
+  "notifications.order.groupBuyLose.title": "Group Buy Successful",
+  "notifications.order.groupBuyLose.content": "The group order you participated in [{orderId}] was not selected",
+  "notifications.order.provideAddress.title": "Order provide shipping address",
+  "notifications.order.provideAddress.content": "The group order you participated in [{orderId}] Please provide your shipping address",
+  "notifications.order.groupBuyFail.title": "Group Buy Failed",
+  "notifications.order.groupBuyFail.content": "The group order you participated in [{orderId}] has failed",
+  "notifications.order.shipped.title": "Order shipped successfully",
+  "notifications.order.shipped.content": "The group order you participated in [{orderId}] has been successfully shipped",
+  "notifications.reward.referFriends.title": "Refer Friends Reward",
+  "notifications.reward.referFriends.content": "You have received the reward for refer friends",
+  "notifications.reward.groupBuy.title": "Join Group Buy Reward",
+  "notifications.reward.groupBuy.content": "You have received a reward, order ID [{orderId}]",
+  "notifications.reward.openGroupBuy.title": "Open Group Buy Reward",
+  "notifications.reward.openGroupBuy.content": "You have received a reward, order ID [{orderId}]",
+  "notifications.reward.directReferral.title": "Direct Referral Reward",
+  "notifications.reward.directReferral.content": "You have received the reward for Direct Referral",
+  "notifications.reward.checkin.title": "Check-in Reward",
+  "notifications.reward.checkin.content": "You have received the reward for Check-in",
+  "notifications.reward.firstCommission.title": "Direct Referral Reward",
+  "notifications.reward.firstCommission.content": "You have received the reward for Direct Referral",
+  "notifications.reward.secondaryCommission.title": "Direct Referral Reward",
+  "notifications.reward.secondaryCommission.content": "You have received the reward for Direct Referral",
+  "notifications.money.rechargeSuccess.title": "Recharge Successful",
+  "notifications.money.rechargeSuccess.content": "Your KLICKwallet has been successfully recharged",
+  "notifications.money.withdrawalAccountSuccess.title": "Withdrawal Successful",
+  "notifications.money.withdrawalAccountSuccess.content": "Your Revenue Account withdrawal request has been processed",
+  "notifications.money.withdrawalWalletSuccess.title": "Withdrawal Successful",
+  "notifications.money.withdrawalWalletSuccess.content": "Your KLICK wallet withdrawal request has been processed",
+  "notifications.money.withdrawalFail.title": "Withdrawal Failed",
+  "notifications.money.withdrawalFail.content": "Your withdrawal request has been failed",
+  "productDetail.title": "Product Detail",
+  "productDetail.notification.message": "{name} {action} this group {time}s ago!",
+  "productDetail.notification.opened": "opened",
+  "productDetail.notification.joined": "joined",
+  "webLink.title": "Web Link",
+  "missionCenter.signIn.title": "Continuous sign in to receive rewards",
+  "missionCenter.signIn.button": "Check-in",
+  "missionCenter.dailyMission.title": "Daily Mission",
+  "missionCenter.dailyMission.startNow": "Start Now",
+  "vipMembership.inviteProgress": "We still need to invite {0} friends. Can upgrade to V{1}",
+  "vipMembership.invitedFriends": "Invited Friends",
+  "vipMembership.teamMembers": "Team Members",
+  "vipMembership.l7dEarnings": "L7D Earnings",
+  "vipMembership.benefitsTiers": "VIP Benefits/Tiers",
+  "vipMembership.table.vipLevel": "VIP\nLevel",
+  "vipMembership.table.invitedNo": "Invited\nNo",
+  "vipMembership.table.directReferralReward": "Direct Referral\nReward",
+  "vipMembership.table.indirectReferralReward": "Indirect Referral\nReward",
+  "vipMembership.table.joinedGroupsNo": "Joined Groups\nNo",
+  "referEarn.inviteFriends": "INVITE FRIENDS",
+  "referEarn.earnCash": "EARN CASH",
+  "referEarn.shareNow": "Share Now",
+  "referEarn.howToShare": "- How to Share and Earn Money -",
+  "referEarn.step1": "Share Invite Friends",
+  "referEarn.step2": "Your Friend Join Group",
+  "referEarn.step3": "You Get ৳{0} Reward",
+  "referEarn.invitedFriends": "Invited Friends",
+  "checkout.title": "Checkout",
+  "checkout.selected": "Selected",
+  "checkout.quantity": "Quantity",
+  "checkout.orderSummary": "Order Summary",
+  "checkout.subTotal": "SubTotal",
+  "checkout.total": "Total",
+  "checkout.selectPaymentMethod": "Select Payment Method",
+  "checkout.walletBalance": "Balance",
+  "checkout.placeOrder": "Place Order",
+  "checkout.dialog.insufficientBalance": "Your wallet balance is insufficient.\nPlease recharge!",
+  "checkout.dialog.rechargeDiscount": "Recharge Highest Discount 5%",
+  "checkout.dialog.rechargeNow": "Recharge Now",
+  "checkout.dialog.paymentSuccess": "Payment successful!\nYour order has been placed.",
+  "checkout.dialog.viewOrder": "View Order",
+  "checkout.dialog.paymentFailed": "Payment failed!\nPlease try again or contact support.",
+  "checkout.dialog.retryPayment": "Retry Payment",
+  "checkout.dialog.networkError": "Network connection failed.\nPlease check your network settings.",
+  "checkout.dialog.retry": "Retry",
+  "checkout.dialog.gotIt": "Got it",
+  "checkout.toast.redirecting": "Redirecting to orders...",
+  "checkout.toast.retrying": "Retrying...",
+  "bestSellers.title": "Best Sellers",
+  "bestSellers.successfullyGrouped": "Successfully grouped over {0} L7D",
+  "productDetail.price": "Price",
+  "productDetail.sold": "{0} sold",
+  "productDetail.groupRules": "Group Rules",
+  "productDetail.viewRules": "View Rules",
+  "productDetail.viewRulesLinkTitle": "Group Buying Rules",
+  "productDetail.ongoingGroup": "Ongoing Group",
+  "productDetail.need": "Need",
+  "productDetail.more": "More",
+  "productDetail.joinGroup": "Join Group",
+  "productDetail.details": "Details",
+  "productDetail.home": "Home",
+  "productDetail.favorite": "Favorite",
+  "productDetail.favoriteSuccess": "Added to favorites",
+  "productDetail.unfavoriteSuccess": "Removed from favorites",
+  "productDetail.favoriteError": "Operation failed, please try again",
+  "productDetail.openGroup": "Open Group",
+  "productDetail.quantity": "Quantity",
+  "topChampions.title": "Top Champions",
+  "topChampions.top": "TOP",
+  "topChampions.invitedFriends": "Invited Friends",
+  "topChampions.l7dEarnings": "L7D Earnings",
+  "topChampions.teamMembers": "Team Members",
+  "topChampions.joinedGroups": "Joined Groups",
+  "wallet.recharge.title": "Recharge",
+  "wallet.recharge.submit": "Submit",
+  "orderDetail.deliveryPartner": "Delivery Partner",
+  "orderDetail.subTotal": "SubTotal",
+  "orderDetail.bandhuBuyWallet": "BandhuBuy Wallet",
+  "orderDetail.paymentMethod": "Payment",
+  "orderDetail.walletBalanceText": "Balance",
+  "productDetail.fullRefundText": "Full refund if not won + cash reward",
+  "app.notificationPermission": "You have not opened notification permissions",
+  "wallet.recharge.record": "Record",
+  "wallet.recharge.selectProvider": "Select Your Wallet Provider",
+  "wallet.recharge.depositAmount": "Deposit Amount",
+  "wallet.recharge.reminder": "Reminder: If the recharge is not successful, please select another channel. Transaction ID must be filled in correctly.",
+  "wallet.recharge.enterAmount": "Please enter recharge amount",
+  "wallet.recharge.minAmount": "Min {minAmount}",
+  "wallet.recharge.maxAmount": "Max {maxAmount}",
+  "orderDetail.rechargeDialog.title": "Your wallet balance is insufficient.\\nPlease Recharge!",
+  "orderDetail.rechargeDialog.confirm": "Recharge Now",
+  "orderDetail.payDialog.title": "Payment",
+  "orderDetail.payDialog.confirm": "Pay Now",
+  "orderDetail.time.placed": "Placed On",
+  "orderDetail.time.paid": "Paid On",
+  "orderDetail.time.shipped": "Shipped On",
+  "orderDetail.time.completed": "Completed On",
+  "orderDetail.copy.success": "Copied to clipboard",
+  "wallet.unpaidOrderDialog.title": "You have unfinished top up orders,\\nDo you want to continue?",
+  "wallet.unpaidOrderDialog.confirm": "View",
+  "wallet.unpaidOrderDialog.cancel": "Cancel",
+  "wallet.record.type.DT": "DT",
+  "wallet.record.type.YT": "YT",
+  "wallet.record.type.L7D": "L7D",
+  "wallet.record.type.MTD": "MTD",
+  "wallet.record.type.YTD": "YTD",
+  "login.slogan": "More group purchases, bigger rewards",
+  "common.operate.success": "Operation successful"
+
 }

+ 400 - 2
src/locale/zh-Hans.json

@@ -1,7 +1,192 @@
 {
+  "addressBook.title": "地址簿",
+  "addressBook.operate.title.add": "添加地址",
+  "addressBook.operate.title.edit": "编辑地址",
+  "addressBook.operate.loading": "加载中...",
+  "addressBook.operate.saving": "保存中...",
+  "addressBook.operate.form.fullName": "姓名",
+  "addressBook.operate.form.phone": "手机号码",
+  "addressBook.operate.form.phone.placeholder": "+88",
+  "addressBook.operate.form.district": "省/区",
+  "addressBook.operate.form.district.placeholder": "请选择",
+  "addressBook.operate.form.street": "楼层/单元/街道",
+  "addressBook.operate.form.street.placeholder": "详细地址",
+  "addressBook.operate.form.postcode": "邮编",
+  "addressBook.operate.form.postcode.placeholder": "请输入邮编",
+  "addressBook.operate.form.default": "默认",
+  "addressBook.operate.button.save": "保存",
+  "addressBook.operate.button.update": "更新",
+  "addressBook.operate.error.loadFailed": "加载地址详情失败",
+  "addressBook.operate.error.emptyName": "请输入姓名",
+  "addressBook.operate.error.emptyPhone": "请输入手机号码",
+  "addressBook.operate.error.emptyDistrict": "请选择省/区",
+  "addressBook.operate.error.emptyStreet": "请输入详细地址",
+  "addressBook.operate.success.update": "地址更新成功",
+  "addressBook.operate.success.save": "地址保存成功",
+  "addressBook.operate.error.saveFailed": "保存失败,请重试",
+  "addressBook.operate.error.loadPage": "页面加载失败",
+  "addressBook.delete.deleting": "删除中...",
+  "addressBook.delete.success": "地址删除成功",
+  "myOrders.title": "我的订单",
+  "myOrders.tab.all": "全部",
+  "myOrders.tab.toPay": "待支付",
+  "myOrders.tab.success": "成功",
+  "myOrders.tab.failed": "失败",
+  "myOrders.tab.reward": "奖励",
+  "myOrders.order.id": "订单号",
+  "myOrders.order.color": "颜色",
+  "myOrders.order.quantity": "数量",
+  "orderDetail.title": "订单详情",
+  "orderDetail.loading": "加载中...",
+  "orderDetail.congrats": "恭喜,您在这个团中中奖了!",
+  "orderDetail.receiveReward": "您已收到团购开团奖励",
+  "orderDetail.sorry": "抱歉,您在这个团中未中奖",
+  "orderDetail.waiting": "请等待本团开奖",
+  "orderDetail.paymentCountdown": "请在以下时间内完成支付:",
+  "orderDetail.address.add": "请填写收货地址",
+  "orderDetail.address.name": "收件人",
+  "orderDetail.address.orderNo": "订单号",
+  "orderDetail.address.color": "颜色",
+  "orderDetail.address.quantity": "数量",
+  "orderDetail.summary.title": "订单汇总",
+  "orderDetail.summary.subtotal": "小计",
+  "orderDetail.payment.title": "支付方式",
+  "orderDetail.payment.placedOn": "下单时间",
+  "orderDetail.button.cancel": "取消",
+  "orderDetail.button.share": "立即分享",
+  "orderDetail.button.pay": "立即支付",
+  "orderDetail.dialog.cancel.title": "确定要取消此订单吗?",
+  "orderDetail.dialog.cancel.confirm": "是,取消订单",
+  "orderDetail.dialog.cancel.keep": "保留订单",
+  "orderDetail.cancel.loading": "正在取消订单...",
+  "orderDetail.cancel.success": "订单已成功取消!",
+  "orderDetail.cancel.error": "取消订单失败,请重试。",
+  "orderDetail.cancel.network": "网络错误,请检查网络连接后重试。",
+  "orderDetail.payment.success": "支付成功",
+  "wallet.withdraw.success": "提现申请提交成功",
+  "wallet.withdraw.fail": "提现申请提交失败,请重试",
+  "addressBook.delete.confirm": "确认删除",
+  "addressBook.delete.message": "确定要删除这个地址吗?",
+  "addressBook.delete.button": "删除",
+  "addressBook.tag.default": "默认",
+  "addressBook.button.add": "添加新地址",
+  "addressBook.select.binding": "正在绑定地址...",
+  "addressBook.select.success": "地址绑定成功!",
+  "addressBook.select.failed": "绑定地址失败,请重试。",
+  "addressBook.select.networkError": "网络错误,请检查网络连接后重试。",
+  "myProfile.title": "个人资料",
+  "myProfile.avatar": "头像",
+  "myProfile.userId": "用户ID",
+  "myProfile.userName": "用户名",
+  "myProfile.mobileNumber": "手机号",
+  "myProfile.bankName": "银行名称",
+  "myProfile.bankAccountName": "开户名",
+  "myProfile.bankAccountNo": "银行账号",
+  "myProfile.upload.sizeLimit": "图片大小不能超过5MB",
+  "myProfile.upload.uploading": "上传中...",
+  "myProfile.upload.success": "头像更新成功",
+  "myProfile.upload.error": "更新头像失败",
+  "setting.title": "设置",
+  "setting.changePassword": "修改密码",
+  "setting.language": "语言",
+  "setting.policies": "隐私政策",
+  "setting.termsOfService": "用户服务协议",
+  "setting.refund": "退货退款政策",
+  "setting.logout": "退出登录",
+  "setting.version": "版本 {0}",
+  "setting.lang.en": "英语",
+  "setting.lang.bn": "孟加拉语",
+  "home.missionCenter": "任务中心",
+  "home.refer&earn": "推荐赚钱",
+  "home.vip": "VIP会员",
+  "home.bestSellers": "热销商品",
+  "home.topChampions": "顶级冠军",
+  "home.news": "新品",
+  "mine.auth.register": "注册",
+  "mine.auth.login": "登录",
+  "mine.wallet.title": "BandhuBuy钱包",
+  "mine.wallet.balance": "钱包账户余额",
+  "mine.wallet.recharge": "充值",
+  "mine.group.title": "我的团队",
+  "mine.group.all": "全部团队",
+  "mine.group.toPay": "待支付",
+  "mine.group.success": "成功",
+  "mine.group.failed": "失败",
+  "mine.group.reward": "奖励",
+  "mine.menu.profile": "我的资料",
+  "mine.menu.address": "地址簿",
+  "mine.menu.share": "分享",
+  "mine.menu.favorite": "我的收藏",
+  "mine.menu.chat": "在线客服",
+  "mine.menu.activity": "活动群组",
+  "home.priceTab.allPrice": "全部价格",
+  "home.priceTab.300spot": "300积分",
+  "home.priceTab.500spot": "500积分",
+  "home.priceTab.1000spot": "1000积分",
+  "home.priceTab.2000spot": "2000积分",
+  "home.priceTab.3000spot": "3000积分",
+  "income.title": "收益中心",
+  "income.totalEarnings": "总收益",
+  "income.accountBalance": "收入账户余额",
+  "income.settledAmount": "已结算金额",
+  "income.pendingAmount": "待结算金额",
+  "income.tdEarnings": "今日收益",
+  "income.ydEarnings": "昨日收益",
+  "income.mtdEarnings": "本月收益",
+  "income.myGroupData": "我的团队数据",
+  "income.withdrawNow": "立即提现",
+  "income.revenueRecord": "收益记录",
+  "income.filter.dt": "今日",
+  "income.filter.yt": "昨日",
+  "income.filter.l7d": "近7天",
+  "income.filter.mtd": "本月",
+  "income.filter.ytd": "本年",
+  "mine.pages.share.title": "分享",
+  "mine.pages.share.referrerCode": "我的推荐码",
+  "mine.pages.share.qrCode": "二维码",
+  "mine.pages.share.description": "与您的朋友分享二维码,他们可以用相机扫描以注册成为您的下线。",
+  "mine.pages.share.copySuccess": "已复制到剪贴板",
+  "mine.pages.share.shareTo": "分享到{0}",
+  "mine.pages.myFavorite.title": "我的收藏",
+  "mine.pages.myFavorite.empty": "暂无收藏",
+  "wallet.withdraw.title": "提现",
+  "wallet.withdraw.balance": "钱包余额",
+  "wallet.withdraw.info": "提现信息",
+  "wallet.withdraw.form.bankName": "银行名称",
+  "wallet.withdraw.form.bankAccountName": "开户名",
+  "wallet.withdraw.form.bankAccountNo": "银行账号",
+  "wallet.withdraw.form.amount": "提现金额",
+  "wallet.withdraw.form.allAmount": "全部金额",
+  "wallet.withdraw.form.submit": "提交",
+  "wallet.withdraw.record": "记录",
+  "wallet.withdraw.error.bankName": "请选择银行",
+  "wallet.withdraw.error.bankAccountName": "请输入开户名",
+  "wallet.withdraw.error.bankAccountNo": "请输入银行账号",
+  "wallet.withdraw.error.amount": "请输入提现金额",
+  "wallet.withdraw.notes.title": "注意:",
+  "wallet.withdraw.notes.1": "提现审核时间为上午9点至晚上10点。预计提现后2小时内到账,实际到账时间以最终处理成功时间为准。",
+  "wallet.withdraw.notes.2": "请确保您的银行账户信息正确。",
+  "wallet.withdraw.notes.3": "提现银行账户信息必须与注册账户信息一致。",
+  "wallet.withdraw.notes.4": "单笔提现最低৳{0},最高৳{1};",
+  "wallet.withdraw.notes.5": "每笔提现将收取{0}%的提现手续费;",
+  "search.placeholder": "搜索",
+  "search.filterPrice": "全部价格",
+  "search.filterCategory": "全部分类",
+  "search.filterSellers": "热销",
+  "search.filterSellers1": "上新",
+  "auth.login.title": "登录",
+  "auth.login.username.placeholder": "手机号码 / 用户名",
+  "auth.login.password.placeholder": "密码 6-20位字符",
+  "auth.login.button": "登录",
+  "auth.login.noAccount": "还没有账户?",
+  "auth.login.register": "注册",
+  "auth.login.forgotPassword": "忘记密码?",
+  "auth.login.error.emptyUsername": "请输入用户名或手机号码",
+  "auth.login.error.emptyPassword": "请输入密码",
+  "auth.login.error.passwordLength": "密码应为6-20位字符",
   "auth.register.title": "注册",
   "auth.register.username.placeholder": "用户名",
-  "auth.register.phone.placeholder": "手机号码",
+  "auth.register.phone.placeholder": "+88 手机号码",
   "auth.register.verifyCode.placeholder": "验证码",
   "auth.register.password.placeholder": "密码 6-20位字符",
   "auth.register.referrerCode.placeholder": "推荐码",
@@ -18,7 +203,220 @@
   "auth.register.success.codeSent": "验证码发送成功",
   "auth.register.success.registered": "注册成功",
   "auth.register.error.registrationFailed": "注册失败",
+  "auth.forgotPassword.title": "忘记密码",
+  "auth.forgotPassword.phone.placeholder": "手机号码",
+  "auth.forgotPassword.verifyCode.placeholder": "验证码",
+  "auth.forgotPassword.newPassword.placeholder": "新密码",
+  "auth.forgotPassword.confirmPassword.placeholder": "确认密码",
+  "auth.forgotPassword.getCode": "获取验证码",
+  "auth.forgotPassword.button": "重置密码",
+  "auth.forgotPassword.backToLogin": "返回登录",
+  "auth.forgotPassword.error.emptyPhone": "请输入手机号码",
+  "auth.forgotPassword.error.invalidPhone": "请输入有效的手机号码",
+  "auth.forgotPassword.error.emptyVerifyCode": "请输入验证码",
+  "auth.forgotPassword.error.emptyNewPassword": "请输入新密码",
+  "auth.forgotPassword.error.passwordLength": "密码应为6-20位字符",
+  "auth.forgotPassword.error.emptyConfirmPassword": "请确认您的密码",
+  "auth.forgotPassword.error.passwordMismatch": "两次密码不一致",
+  "auth.forgotPassword.success.codeSent": "验证码发送成功",
+  "auth.forgotPassword.success.passwordReset": "密码重置成功",
+  "auth.forgotPassword.error.sendCodeFailed": "发送验证码失败",
+  "auth.forgotPassword.error.resetFailed": "重置密码失败",
+  "auth.forgotPassword.passwordHint": "您的密码必须与之前使用的密码不同",
+  "auth.forgotPassword.hasAccount": "已有账户?",
+  "auth.forgotPassword.loginNow": "立即登录",
   "common.loading": "加载中...",
   "common.saving": "保存中...",
-  "login.slogan": "More group purchases, bigger rewards"
+  "common.success": "成功",
+  "common.error": "错误",
+  "common.confirm": "确认",
+  "common.cancel": "取消",
+  "common.submit": "提交",
+  "common.save": "保存",
+  "common.edit": "编辑",
+  "common.delete": "删除",
+  "common.add": "添加",
+  "common.search": "搜索",
+  "common.filter": "筛选",
+  "common.all": "全部",
+  "common.none": "无",
+  "common.empty": "暂无数据",
+  "common.retry": "重试",
+  "common.back": "返回",
+  "common.next": "下一步",
+  "common.previous": "上一步",
+  "common.close": "关闭",
+  "common.open": "打开",
+  "common.view": "查看",
+  "common.more": "更多",
+  "wallet.myWallet.title": "我的钱包",
+  "wallet.balance": "钱包账户余额",
+  "wallet.frozenBalance": "钱包冻结余额",
+  "wallet.recharge": "充值",
+  "wallet.withdrawNow": "立即提现",
+  "wallet.record": "钱包记录",
+  "wallet.filter.all": "全部",
+  "wallet.filter.recharge": "充值",
+  "wallet.filter.withdraw": "提现",
+  "wallet.filter.commission": "佣金",
+  "wallet.rechargeRecord.title": "充值记录",
+  "wallet.withdrawRecord.title": "提现记录",
+  "missionCenter.title": "任务中心",
+  "referEarn.title": "推荐赚钱",
+  "vipMembership.title": "VIP会员",
+  "notifications.title": "通知",
+  "notifications.tabs.all": "全部",
+  "notifications.tabs.orders": "订单",
+  "notifications.tabs.revenue": "收益",
+  "notifications.tabs.account": "账户",
+  "notifications.tabs.promos": "促销",
+  "notifications.time.sunday": "周日",
+  "notifications.time.monday": "周一",
+  "notifications.time.tuesday": "周二",
+  "notifications.time.wednesday": "周三",
+  "notifications.time.thursday": "周四",
+  "notifications.time.friday": "周五",
+  "notifications.time.saturday": "周六",
+  "notifications.order.paymentSuccess.title": "团购支付成功",
+  "notifications.order.paymentSuccess.content": "您参与的团购订单[{orderId}]已支付成功",
+  "notifications.order.groupBuyWin.title": "团购成功",
+  "notifications.order.groupBuyWin.content": "您参与的团购订单[{orderId}]已中选",
+  "notifications.order.groupBuyLose.title": "团购成功",
+  "notifications.order.groupBuyLose.content": "您参与的团购订单[{orderId}]未中选",
+  "notifications.order.provideAddress.title": "订单提供收货地址",
+  "notifications.order.provideAddress.content": "您参与的团购订单[{orderId}]请提供收货地址",
+  "notifications.order.groupBuyFail.title": "团购失败",
+  "notifications.order.groupBuyFail.content": "您参与的团购订单[{orderId}]已失败",
+  "notifications.order.shipped.title": "订单发货成功",
+  "notifications.order.shipped.content": "您参与的团购订单[{orderId}]已成功发货",
+  "notifications.reward.referFriends.title": "推荐好友奖励",
+  "notifications.reward.referFriends.content": "您已获得推荐好友奖励",
+  "notifications.reward.groupBuy.title": "参团奖励",
+  "notifications.reward.groupBuy.content": "您已获得奖励,订单号[{orderId}]",
+  "notifications.reward.openGroupBuy.title": "开团奖励",
+  "notifications.reward.openGroupBuy.content": "您已获得开团奖励,订单号[{orderId}]",
+  "notifications.reward.directReferral.title": "直接推荐奖励",
+  "notifications.reward.directReferral.content": "您已获得直接推荐奖励",
+  "notifications.reward.checkin.title": "签到奖励",
+  "notifications.reward.checkin.content": "您已获得签到奖励",
+  "notifications.reward.firstCommission.title": "Direct Referral Reward",
+  "notifications.reward.firstCommission.content": "You have received the reward for Direct Referral",
+  "notifications.reward.secondaryCommission.title": "Direct Referral Reward",
+  "notifications.reward.secondaryCommission.content": "You have received the reward for Direct Referral",
+  "notifications.money.rechargeSuccess.title": "充值成功",
+  "notifications.money.rechargeSuccess.content": "您的KLICK钱包已成功充值",
+  "notifications.money.withdrawalAccountSuccess.title": "提现成功",
+  "notifications.money.withdrawalAccountSuccess.content": "您的收益账户提现请求已处理",
+  "notifications.money.withdrawalWalletSuccess.title": "提现成功",
+  "notifications.money.withdrawalWalletSuccess.content": "您的KLICK钱包提现请求已处理",
+  "notifications.money.withdrawalFail.title": "提现失败",
+  "notifications.money.withdrawalFail.content": "您的提现请求已失败",
+  "productDetail.title": "产品详情",
+  "productDetail.notification.message": "{name} {time}秒前{action}了这个团购",
+  "productDetail.notification.opened": "发起",
+  "productDetail.notification.joined": "加入",
+  "webLink.title": "网页链接",
+  "missionCenter.signIn.title": "连续签到获得奖励",
+  "missionCenter.signIn.button": "签到",
+  "missionCenter.dailyMission.title": "每日任务",
+  "missionCenter.dailyMission.startNow": "立即开始",
+  "vipMembership.inviteProgress": "还需要邀请 {0} 位朋友,可升级到 V{1}",
+  "vipMembership.invitedFriends": "邀请好友",
+  "vipMembership.teamMembers": "团队成员",
+  "vipMembership.l7dEarnings": "近7日收益",
+  "vipMembership.benefitsTiers": "VIP权益/等级",
+  "vipMembership.table.vipLevel": "VIP\n等级",
+  "vipMembership.table.invitedNo": "邀请\n人数",
+  "vipMembership.table.directReferralReward": "直接推荐\n奖励",
+  "vipMembership.table.indirectReferralReward": "间接推荐\n奖励",
+  "vipMembership.table.joinedGroupsNo": "加入群组\n数量",
+  "referEarn.inviteFriends": "邀请朋友",
+  "referEarn.earnCash": "赚取现金",
+  "referEarn.shareNow": "立即分享",
+  "referEarn.howToShare": "- 如何分享赚钱 -",
+  "referEarn.step1": "分享邀请朋友",
+  "referEarn.step2": "朋友加入群组",
+  "referEarn.step3": "您获得 ৳{0} 奖励",
+  "referEarn.invitedFriends": "邀请的朋友",
+  "checkout.title": "结账",
+  "checkout.selected": "已选择",
+  "checkout.quantity": "数量",
+  "checkout.orderSummary": "订单摘要",
+  "checkout.subTotal": "小计",
+  "checkout.total": "总计",
+  "checkout.selectPaymentMethod": "选择支付方式",
+  "checkout.walletBalance": "余额",
+  "checkout.placeOrder": "下单",
+  "checkout.dialog.insufficientBalance": "您的钱包余额不足。\n请充值!",
+  "checkout.dialog.rechargeDiscount": "充值最高优惠5%",
+  "checkout.dialog.rechargeNow": "立即充值",
+  "checkout.dialog.paymentSuccess": "支付成功!\n您的订单已下单。",
+  "checkout.dialog.viewOrder": "查看订单",
+  "checkout.dialog.paymentFailed": "支付失败!\n请重试或联系客服。",
+  "checkout.dialog.retryPayment": "重试支付",
+  "checkout.dialog.networkError": "网络连接失败。\n请检查您的网络设置。",
+  "checkout.dialog.retry": "重试",
+  "checkout.dialog.gotIt": "知道了",
+  "checkout.toast.redirecting": "正在跳转到订单...",
+  "checkout.toast.retrying": "重试中...",
+  "bestSellers.title": "热销榜",
+  "bestSellers.successfullyGrouped": "近7日成功拼团超过 {0}",
+  "productDetail.price": "价格",
+  "productDetail.sold": "已售 {0}",
+  "productDetail.groupRules": "拼团规则",
+  "productDetail.viewRules": "查看规则",
+  "productDetail.viewRulesLinkTitle": "拼团规则",
+  "productDetail.ongoingGroup": "进行中的拼团",
+  "productDetail.need": "还需",
+  "productDetail.more": "人",
+  "productDetail.joinGroup": "参团",
+  "productDetail.details": "详情",
+  "productDetail.home": "首页",
+  "productDetail.favorite": "收藏",
+  "productDetail.favoriteSuccess": "收藏成功",
+  "productDetail.unfavoriteSuccess": "已取消收藏",
+  "productDetail.favoriteError": "操作失败,请重试",
+  "productDetail.openGroup": "开团",
+  "productDetail.quantity": "数量",
+  "topChampions.title": "冠军榜",
+  "topChampions.top": "TOP",
+  "topChampions.invitedFriends": "邀请好友",
+  "topChampions.l7dEarnings": "近7日收益",
+  "topChampions.teamMembers": "团队成员",
+  "topChampions.joinedGroups": "加入群组",
+  "wallet.recharge.title": "充值",
+  "wallet.recharge.submit": "提交",
+  "orderDetail.deliveryPartner": "物流伙伴",
+  "orderDetail.subTotal": "小计",
+  "orderDetail.bandhuBuyWallet": "BandhuBuy 钱包",
+  "orderDetail.paymentMethod": "支付",
+  "orderDetail.walletBalanceText": "余额",
+  "productDetail.fullRefundText": "未中奖全额退款 + 现金奖励",
+  "app.notificationPermission": "您还没有打开通知权限",
+  "wallet.recharge.record": "记录",
+  "wallet.recharge.selectProvider": "选择您的钱包提供商",
+  "wallet.recharge.depositAmount": "存款金额",
+  "wallet.recharge.reminder": "提醒:如果充值不成功,请选择其他渠道。交易ID必须正确填写。",
+  "wallet.recharge.enterAmount": "请输入充值金额",
+  "wallet.recharge.minAmount": "最小值 {minAmount}",
+  "wallet.recharge.maxAmount": "最大值 {maxAmount}",
+  "orderDetail.rechargeDialog.title": "您的钱包余额不足。\n请充值!",
+  "orderDetail.rechargeDialog.confirm": "立即充值",
+  "orderDetail.payDialog.title": "支付",
+  "orderDetail.payDialog.confirm": "立即支付",
+  "orderDetail.time.placed": "下单时间",
+  "orderDetail.time.paid": "支付时间",
+  "orderDetail.time.shipped": "发货时间",
+  "orderDetail.time.completed": "完成时间",
+  "orderDetail.copy.success": "已复制到剪贴板",
+  "wallet.unpaidOrderDialog.title": "您有未完成的充值订单,\n是否继续?",
+  "wallet.unpaidOrderDialog.confirm": "查看",
+  "wallet.unpaidOrderDialog.cancel": "取消",
+  "wallet.record.type.DT": "今天",
+  "wallet.record.type.YT": "昨天",
+  "wallet.record.type.L7D": "近7天",
+  "wallet.record.type.MTD": "本月",
+  "wallet.record.type.YTD": "本年",
+  "login.slogan": "更多团购,更多奖励",
+  "common.operate.success": "操作成功"
 }

+ 8 - 0
src/pages.json

@@ -25,6 +25,14 @@
       "style": {
         "navigationStyle": "custom"
       }
+    },
+    {
+      "path": "pages/productDetail/productDetail",
+      "type": "page",
+      "layout": "default",
+      "style": {
+        "navigationStyle": "custom"
+      }
     }
   ],
   "subPackages": []

+ 123 - 0
src/pages/productDetail/components/CustomTooltip.vue

@@ -0,0 +1,123 @@
+<script lang="ts" setup>
+interface Props {
+  visible?: boolean
+  autoHide?: boolean
+  autoHideDelay?: number
+  icon?: string
+  iconSize?: string
+  width?: string
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  visible: false,
+  autoHide: true,
+  autoHideDelay: 10000,
+  icon: '/static/icons/gift.png',
+  width: '600rpx',
+})
+
+const emit = defineEmits<{
+  'update:visible': [value: boolean]
+  'hide': []
+}>()
+
+const internalVisible = ref(props.visible)
+let hideTimer: number | null = null
+
+// 监听 visible prop 变化
+watch(() => props.visible, (newVal) => {
+  internalVisible.value = newVal
+  if (newVal && props.autoHide) {
+    startAutoHideTimer()
+  }
+  else {
+    clearAutoHideTimer()
+  }
+})
+
+// 监听内部 visible 变化
+watch(internalVisible, (newVal) => {
+  emit('update:visible', newVal)
+  if (!newVal) {
+    emit('hide')
+    clearAutoHideTimer()
+  }
+})
+
+// 启动自动隐藏定时器
+function startAutoHideTimer() {
+  clearAutoHideTimer()
+  if (props.autoHide && props.autoHideDelay > 0) {
+    hideTimer = setTimeout(() => {
+      hide()
+    }, props.autoHideDelay)
+  }
+}
+
+// 清除自动隐藏定时器
+function clearAutoHideTimer() {
+  if (hideTimer) {
+    clearTimeout(hideTimer)
+    hideTimer = null
+  }
+}
+
+// 显示提示框
+function show() {
+  internalVisible.value = true
+  if (props.autoHide) {
+    startAutoHideTimer()
+  }
+}
+
+// 隐藏提示框
+function hide() {
+  internalVisible.value = false
+}
+
+// 切换显示状态
+function toggle() {
+  if (internalVisible.value) {
+    hide()
+  }
+  else {
+    show()
+  }
+}
+
+// 组件卸载时清除定时器
+onUnmounted(() => {
+  clearAutoHideTimer()
+})
+
+// 暴露方法给父组件
+defineExpose({
+  show,
+  hide,
+  toggle,
+})
+</script>
+
+<template>
+  <view
+    v-if="internalVisible"
+    class="absolute bottom-full left-1/2 mb-20rpx transform rounded-full bg-black bg-opacity-80 px-20rpx py-12rpx text-24rpx text-white -translate-x-1/2"
+    :style="{ width }"
+  >
+    <view class="flex items-end justify-center">
+      <image
+        v-if="icon"
+        :src="icon"
+        class="mr-12rpx h-35rpx w-32rpx flex-shrink-0"
+      />
+      <view class="text-center">
+        <text>{{ $t('productDetail.fullRefundText') }} </text>
+      </view>
+    </view>
+    <!-- 倒三角箭头 -->
+    <view
+      class="absolute left-445rpx top-full h-0 w-0 -translate-x-1/2"
+      style="border-left: 16rpx solid transparent; border-right: 16rpx solid transparent; border-top: 16rpx solid rgba(0, 0, 0, 0.8);"
+    />
+  </view>
+</template>

+ 122 - 0
src/pages/productDetail/components/NotificationCarousel.vue

@@ -0,0 +1,122 @@
+<script setup>
+import { t } from '@/locale'
+
+const props = defineProps({
+  notifications: {
+    type: Array,
+    default: () => [],
+  },
+  interval: {
+    type: Number,
+    default: 3000,
+  },
+  top: {
+    type: String,
+    default: '0px',
+  },
+})
+
+const currentIndex = ref(0)
+const isTransitioning = ref(false)
+let carouselTimer = null
+
+// 获取下一个索引
+function getNextIndex() {
+  return (currentIndex.value + 1) % props.notifications.length
+}
+
+// 切换到下一个通知
+function switchToNext() {
+  if (props.notifications.length <= 1)
+    return
+
+  isTransitioning.value = true
+
+  // 立即切换到下一个索引
+  currentIndex.value = getNextIndex()
+
+  // 动画完成后重置过渡状态
+  setTimeout(() => {
+    isTransitioning.value = false
+  }, 500)
+}
+
+// 启动轮播
+function startCarousel() {
+  if (props.notifications.length <= 1)
+    return
+
+  carouselTimer = setInterval(switchToNext, props.interval)
+}
+
+// 停止轮播
+function stopCarousel() {
+  if (carouselTimer) {
+    clearInterval(carouselTimer)
+    carouselTimer = null
+  }
+}
+
+// 重启轮播
+function restartCarousel() {
+  stopCarousel()
+  currentIndex.value = 0
+  isTransitioning.value = false
+
+  nextTick(() => {
+    startCarousel()
+  })
+}
+
+// 监听数据变化
+watch(() => props.notifications, restartCarousel, { deep: true })
+watch(() => props.interval, restartCarousel)
+
+// 生命周期
+onMounted(() => {
+  startCarousel()
+})
+
+onUnmounted(() => {
+  stopCarousel()
+})
+
+// 暴露方法
+defineExpose({
+  start: startCarousel,
+  stop: stopCarousel,
+  restart: restartCarousel,
+})
+</script>
+
+<template>
+  <view
+    v-if="notifications.length > 0"
+    class="absolute left-24rpx h-56rpx w-70% overflow-hidden rounded-full"
+    :style="{ top }"
+  >
+    <view
+      v-for="(notification, index) in notifications"
+      :key="`${notification.id}-${index}`"
+      class="absolute inset-0 flex items-center justify-start rounded-full bg-#000000/60 py-8rpx pl-8rpx pr-14rpx transition-all duration-500 ease-out"
+      :style="{
+        opacity: index === currentIndex ? 1 : 0,
+        transform: index === currentIndex
+          ? 'translateY(0)'
+          : (isTransitioning && index === (currentIndex - 1 + notifications.length) % notifications.length
+            ? 'translateY(-100%)'
+            : 'translateY(100%)'),
+        zIndex: index === currentIndex ? 2 : 1,
+      }"
+    >
+      <wd-img width="40rpx" round height="40rpx" :src="notification.headPic" />
+      <text class="ml-12rpx flex-1 truncate text-24rpx text-white">
+        {{ t('productDetail.notification.message', {
+          name: notification.name,
+          action: notification.kId === 0 ? t('productDetail.notification.opened') : t('productDetail.notification.joined'),
+          time: notification.time,
+        }) }}
+      </text>
+    </view>
+  </view>
+</template>

+ 210 - 0
src/pages/productDetail/components/README.md

@@ -0,0 +1,210 @@
+# ProductDetail 组件库
+
+商品详情页面的组件库,包含通知轮播和自定义提示框组件。
+
+## NotificationCarousel 组件
+
+通知轮播组件,用于在页面顶部显示滚动的通知消息。
+
+### 功能特性
+
+- 自动轮播通知消息
+- 平滑的动画过渡效果
+- 可自定义轮播间隔时间
+- 可自定义位置
+- 支持动态数据更新
+- 自动管理生命周期
+
+### 使用方法
+
+#### 基础用法
+
+```vue
+<template>
+  <NotificationCarousel :notifications="notifications" />
+</template>
+
+<script setup>
+import NotificationCarousel from './components/NotificationCarousel.vue'
+
+const notifications = ref([
+  { id: 1, name: 'Aamir Khan', time: '10s' },
+  { id: 2, name: 'John Smith', time: '30s' },
+  { id: 3, name: 'Maria Garcia', time: '1m' },
+])
+</script>
+```
+
+#### 自定义配置
+
+```vue
+<template>
+  <NotificationCarousel
+    :notifications="notifications"
+    :interval="5000"
+    :top="`${safeAreaInsets?.top + 52}px`"
+  />
+</template>
+```
+
+### Props
+
+| 参数 | 类型 | 默认值 | 说明 |
+|------|------|--------|------|
+| notifications | Array | 默认数据 | 通知数据数组 |
+| interval | Number | 3000 | 轮播间隔时间(毫秒) |
+| top | String | '0px' | 组件距离顶部的距离 |
+
+#### notifications 数据格式
+
+```typescript
+interface Notification {
+  id: number        // 唯一标识
+  name: string      // 用户名
+  time: string      // 时间描述
+}
+```
+
+### 方法
+
+组件暴露了以下方法,可通过 ref 调用:
+
+- `start()` - 开始轮播
+- `stop()` - 停止轮播
+- `restart()` - 重新开始轮播
+
+#### 使用示例
+
+```vue
+<template>
+  <NotificationCarousel ref="carouselRef" :notifications="notifications" />
+  <button @click="handleStop">停止轮播</button>
+  <button @click="handleStart">开始轮播</button>
+</template>
+
+<script setup>
+const carouselRef = ref()
+
+const handleStop = () => {
+  carouselRef.value?.stop()
+}
+
+const handleStart = () => {
+  carouselRef.value?.start()
+}
+</script>
+```
+
+### 注意事项
+
+1. 当 notifications 数组长度为 0 或 1 时,组件不会启动轮播
+2. 组件会自动监听 props 变化并重新启动轮播
+3. 组件会在卸载时自动清理定时器
+4. 使用了 UnoCSS 原子类进行样式设置
+
+---
+
+## CustomTooltip 组件
+
+自定义提示框组件,用于显示带箭头的气泡提示信息。
+
+### 功能特性
+
+- 支持自动显示/隐藏
+- 可自定义显示时长
+- 支持高亮文本
+- 可自定义图标和样式
+- 支持手动控制显示状态
+- 自动管理定时器
+
+### 使用方法
+
+#### 基础用法
+
+```vue
+<template>
+  <view class="relative">
+    <button>触发按钮</button>
+    <CustomTooltip v-model:visible="showTooltip" />
+  </view>
+</template>
+
+<script setup>
+import CustomTooltip from './components/CustomTooltip.vue'
+
+const showTooltip = ref(false)
+</script>
+```
+
+#### 自定义配置
+
+```vue
+<template>
+  <CustomTooltip
+    v-model:visible="showTooltip"
+    :auto-hide="true"
+    :auto-hide-delay="5000"
+    icon="shop"
+    icon-size="32rpx"
+    highlight-text1="$99.99"
+    highlight-text2="$1.8"
+    width="500rpx"
+    @hide="handleHide"
+  />
+</template>
+```
+
+### Props
+
+| 参数 | 类型 | 默认值 | 说明 |
+|------|------|--------|------|
+| visible | Boolean | false | 是否显示提示框(支持 v-model) |
+| autoHide | Boolean | true | 是否自动隐藏 |
+| autoHideDelay | Number | 10000 | 自动隐藏延迟时间(毫秒) |
+| icon | String | 'shop' | 图标名称 |
+| iconSize | String | '32rpx' | 图标大小 |
+| message | String | 默认消息 | 提示消息内容 |
+| highlightText1 | String | '$99.99' | 第一个高亮文本 |
+| highlightText2 | String | '$1.8' | 第二个高亮文本 |
+| width | String | '600rpx' | 提示框宽度 |
+
+### 事件
+
+| 事件名 | 说明 | 回调参数 |
+|--------|------|----------|
+| update:visible | 显示状态变化时触发 | (value: boolean) |
+| hide | 提示框隐藏时触发 | - |
+
+### 方法
+
+组件暴露了以下方法,可通过 ref 调用:
+
+- `show()` - 显示提示框
+- `hide()` - 隐藏提示框
+- `toggle()` - 切换显示状态
+
+#### 使用示例
+
+```vue
+<template>
+  <view class="relative">
+    <button @click="handleShow">显示提示</button>
+    <CustomTooltip ref="tooltipRef" />
+  </view>
+</template>
+
+<script setup>
+const tooltipRef = ref()
+
+const handleShow = () => {
+  tooltipRef.value?.show()
+}
+</script>
+```
+
+### 注意事项
+
+1. 组件使用绝对定位,需要在相对定位的容器中使用
+2. 组件会自动管理定时器,无需手动清理
+3. 支持双向绑定 visible 属性
+4. 使用了 UnoCSS 原子类进行样式设置

+ 642 - 0
src/pages/productDetail/productDetail.vue

@@ -0,0 +1,642 @@
+<route lang="json5" type="page">
+{
+  layout: 'default',
+  style: {
+    navigationStyle: 'custom',
+  },
+}
+</route>
+
+<script lang="ts" setup>
+// 必须导入需要用到的页面生命周期(即使在当前页面上没有直接使用到)
+// eslint-disable-next-line unused-imports/no-unused-imports
+import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
+import useZPaging from 'z-paging/components/z-paging/js/hooks/useZPaging.js'
+import { carousel, getDetail, pinkList } from '@/api/product'
+import { t } from '@/locale'
+import { formatNumber } from '@/utils/index'
+import CustomTooltip from './components/CustomTooltip.vue'
+import NotificationCarousel from './components/NotificationCarousel.vue'
+
+defineOptions({
+  name: 'ProductDetail', // 商品详情
+})
+
+// 获取屏幕边界到安全区域距离
+const systemInfo = uni.getSystemInfoSync()
+const safeAreaInsets = systemInfo.safeAreaInsets
+
+// z-paging
+const paging = ref(null)
+// 类似mixins,如果是页面滚动务必要写这一行,并传入当前ref绑定的paging,注意此处是paging,而非paging.value
+useZPaging(paging)
+function goHome() {
+  uni.switchTab({
+    url: '/pages/index/index',
+  })
+}
+// 添加导航栏背景色变量
+const navBgColor = ref('transparent')
+const changeNavbarThreshold = 300 // 滚动到这个高度时改变导航栏颜色
+
+const showTip = ref(false)
+
+onPageScroll((e) => {
+  // 根据滚动高度改变导航栏背景色
+  if (e.scrollTop > changeNavbarThreshold) {
+    navBgColor.value = '#ffffff'
+  }
+  else {
+    navBgColor.value = 'transparent'
+  }
+})
+const productId = ref('') // 商品id
+const isPageLoading = ref(true) // 页面加载状态
+const detail = ref<any>({
+  sliderImage: '',
+  flatPattern: '',
+})
+const pinkInfo = ref<any>([])
+// 添加通知轮播数据
+const notifications = ref([
+  { id: 1, name: 'Aamir Khan', time: '10s' },
+  { id: 2, name: 'John Smith', time: '30s' },
+  { id: 3, name: 'Maria Garcia', time: '1m' },
+])
+async function getCarousel() {
+  const res = await carousel(productId.value)
+  notifications.value = res.data
+}
+// 点击页面任意地方隐藏提示
+function handlePageClick() {
+  if (showTip.value) {
+    showTip.value = false
+  }
+}
+
+// 生命周期钩子
+onMounted(() => {
+  showTip.value = true // 显示提示
+})
+
+// 搜索结果
+// 轮播图
+const current = ref<number>(0)
+
+// 拼团类型 join-加团 open-开团
+const groupType = ref('open')
+const pinkId = ref('') // 拼团id
+const joinOrderId = ref('') // 加团的拼团-订单id
+
+// sku 逻辑
+const showSku = ref(false)
+function openSku(type: string, id?: string, pinkOrderId?: string) {
+  groupType.value = type
+
+  // 区分不同的入团场景
+  if (type === 'join') {
+    if (id && pinkOrderId) {
+      // 从拼团列表点击入团 - 加入指定拼团
+      pinkId.value = id
+      joinOrderId.value = pinkOrderId
+    }
+    else {
+      // 从底部按钮点击入团 - 清空之前的参数,避免参数混乱
+      pinkId.value = ''
+      joinOrderId.value = ''
+    }
+  }
+  else {
+    // 开团场景 - 清空拼团相关参数
+    pinkId.value = ''
+    joinOrderId.value = ''
+  }
+
+  showSku.value = true
+}
+const formData = ref({
+  productNum: 1,
+  selectedSpecs: {}, // 存储选中的规格 { 颜色: '红色', 尺寸: 'M' }
+})
+
+const matchedAttrValue = ref<any>({})
+
+// 计算选中规格的文案
+const selectedSpecsText = computed(() => {
+  if (!formData.value.selectedSpecs || Object.keys(formData.value.selectedSpecs).length === 0) {
+    return ''
+  }
+
+  // 按照attr的顺序生成文案
+  const specTexts = []
+  if (detail.value.attr) {
+    detail.value.attr.forEach((attr) => {
+      const selectedValue = formData.value.selectedSpecs[attr.attrName]
+      if (selectedValue) {
+        specTexts.push(`${attr.attrName}: ${selectedValue}`)
+      }
+    })
+  }
+
+  return specTexts.length > 0 ? ` ${specTexts.join(',')}` : ''
+})
+// 选择规格方法
+function selectSpec(attrName, specValue) {
+  formData.value.selectedSpecs[attrName] = specValue
+
+  // 按照attr的顺序重新构建对象
+  const orderedSpecs = {}
+  if (detail.value.attr) {
+    detail.value.attr.forEach((attr) => {
+      if (formData.value.selectedSpecs[attr.attrName]) {
+        orderedSpecs[attr.attrName] = formData.value.selectedSpecs[attr.attrName]
+      }
+    })
+  }
+
+  // 打印当前选中的规格
+  const selectedSpecsJson = JSON.stringify(orderedSpecs)
+  console.log('当前选中规格:', selectedSpecsJson)
+
+  // 检查是否所有规格都已选中
+  const totalAttrs = detail.value.attr ? detail.value.attr.length : 0
+  const selectedAttrs = Object.keys(orderedSpecs).length
+
+  if (selectedAttrs === totalAttrs && totalAttrs > 0) {
+    // 所有规格都选中了,匹配 attrValue
+    matchedAttrValue.value = findMatchingAttrValue(orderedSpecs)
+    if (matchedAttrValue.value) {
+      console.log('匹配到的规格组合:', matchedAttrValue.value)
+      console.log('对应的图片:', matchedAttrValue.value.image)
+    }
+    else {
+      console.log('未找到匹配的规格组合')
+    }
+  }
+}
+
+// 匹配 attrValue 中对应的规格组合
+function findMatchingAttrValue(selectedSpecs) {
+  if (!detail.value.attrValue || !Array.isArray(detail.value.attrValue)) {
+    return null
+  }
+
+  return detail.value.attrValue.find((attrValue) => {
+    // 将 attrValue 的规格转换为对象进行比较
+    const attrValueSpecs = {}
+    if (attrValue.suk) {
+      // 假设 suk 格式类似 "红色,M" 或者其他分隔符
+      const sukParts = attrValue.suk.split(',')
+      if (detail.value.attr && sukParts.length === detail.value.attr.length) {
+        detail.value.attr.forEach((attr, index) => {
+          attrValueSpecs[attr.attrName] = sukParts[index].trim()
+        })
+      }
+    }
+
+    // 比较选中的规格和当前 attrValue 的规格是否完全匹配
+    const selectedKeys = Object.keys(selectedSpecs)
+    const attrValueKeys = Object.keys(attrValueSpecs)
+
+    if (selectedKeys.length !== attrValueKeys.length) {
+      return false
+    }
+
+    return selectedKeys.every(key => selectedSpecs[key] === attrValueSpecs[key])
+  })
+}
+// 查询商品详情
+async function queryDetail() {
+  const res = await getDetail({ id: productId.value })
+  console.log(res)
+  detail.value = res.data
+  // 默认选择第一个规格
+  setDefaultSpecs()
+  paging.value.complete()
+}
+
+// 查询商品拼团信息
+async function queryPinkInfo() {
+  const res = await pinkList({ cid: detail.value.cid })
+  if (res.code === '200') {
+    const result = []
+    // 循环截取:每次从 i 开始,取 maxLength 个元素
+    for (let i = 0; i < res.data.list.length; i += 3) {
+      const subArr = res.data.list.slice(i, i + 3)
+      result.push(subArr)
+    }
+    console.log(result)
+
+    pinkInfo.value = result
+  }
+}
+
+// 设置默认规格选择
+function setDefaultSpecs() {
+  if (detail.value.attr && detail.value.attr.length > 0) {
+    const defaultSpecs = {}
+
+    // 为每个规格属性选择第一个值
+    detail.value.attr.forEach((attr) => {
+      if (attr.attrImgValues && attr.attrImgValues.length > 0) {
+        defaultSpecs[attr.attrName] = attr.attrImgValues[0].name
+      }
+    })
+
+    // 更新选中的规格
+    formData.value.selectedSpecs = defaultSpecs
+
+    // 按照attr的顺序重新构建对象
+    const orderedSpecs = {}
+    detail.value.attr.forEach((attr) => {
+      if (formData.value.selectedSpecs[attr.attrName]) {
+        orderedSpecs[attr.attrName] = formData.value.selectedSpecs[attr.attrName]
+      }
+    })
+
+    // 匹配对应的规格组合
+    matchedAttrValue.value = findMatchingAttrValue(orderedSpecs)
+    if (matchedAttrValue.value) {
+      console.log('默认选中规格:', JSON.stringify(orderedSpecs))
+      console.log('默认匹配到的规格组合:', matchedAttrValue.value)
+      console.log('默认对应的图片:', matchedAttrValue.value.image)
+    }
+  }
+}
+
+const loading = ref<boolean>(false)
+
+// 商品详情初始化
+onLoad((options) => {
+  productId.value = options.productId || ''
+})
+onShow(async () => {
+  try {
+    isPageLoading.value = true
+    getCarousel()
+    await queryDetail()
+    await queryPinkInfo()
+  }
+  finally {
+    isPageLoading.value = false
+  }
+})
+</script>
+
+<template>
+  <z-paging ref="paging" :use-page-scroll="!showSku" refresher-only @on-refresh="queryDetail" @click="handlePageClick">
+    <!-- <wd-navbar :bordered="false" safe-area-inset-top fixed :left-arrow="false" :custom-style="`background: ${navBgColor}; transition: background 0.3s;`" custom-class="h-auto!">
+      <template #title>
+        <view class="box-border h-full flex items-center justify-between p-24rpx">
+          <image :src="`/static/icons/left-icon${navBgColor === '#ffffff' ? '-tr' : ''}.png`" class="h-56rpx w-56rpx" @click="() => goBack()" />
+          <image :src="`/static/icons/share-icon${navBgColor === '#ffffff' ? '-tr' : ''}.png`" class="h-56rpx w-56rpx" @click="() => goBack()" />
+        </view>
+      </template>
+    </wd-navbar> -->
+
+    <!-- 页面加载时显示骨架屏 -->
+    <template v-if="isPageLoading">
+      <!-- 轮播图骨架屏 -->
+      <wd-skeleton
+        :row-col="[{ height: '750rpx' }]"
+        animation="gradient"
+      />
+
+      <!-- 价格区域骨架屏 -->
+      <view class="relative -top-24rpx">
+        <view class="rounded-t-24rpx bg-white px-24rpx pb-24rpx pt-18rpx">
+          <wd-skeleton
+            :row-col="[
+              { width: '200rpx', height: '40rpx' }, // 价格标签
+              { width: '300rpx', height: '60rpx', marginTop: '12rpx' }, // 价格数值
+              { width: '150rpx', height: '32rpx', marginTop: '16rpx' }, // 销量
+            ]"
+            animation="gradient"
+          />
+        </view>
+        <view class="bg-white px-24rpx pb-24rpx pt-20rpx">
+          <wd-skeleton
+            :row-col="[
+              { width: '100%', height: '60rpx' }, // 商品标题
+              { width: '200rpx', height: '40rpx', marginTop: '16rpx' }, // 规格选择
+            ]"
+            animation="gradient"
+          />
+        </view>
+      </view>
+
+      <!-- 拼团规则骨架屏 -->
+      <view class="mb-20rpx bg-white p-24rpx">
+        <wd-skeleton
+          :row-col="[
+            { width: '200rpx', height: '40rpx' }, // 标题
+            { width: '100%', height: '200rpx', marginTop: '20rpx' }, // 图片
+          ]"
+          animation="gradient"
+        />
+      </view>
+
+      <!-- 拼团信息骨架屏 -->
+      <view class="mb-20rpx bg-white px-24rpx pt-24rpx">
+        <wd-skeleton
+          :row-col="[
+            { width: '200rpx', height: '40rpx' }, // 标题
+            // 拼团列表项
+            [
+              [
+                { width: '56rpx', height: '56rpx', type: 'circle' },
+                { width: '56rpx', height: '56rpx', type: 'circle', marginLeft: '8rpx' },
+                { width: '56rpx', height: '56rpx', type: 'circle', marginLeft: '8rpx' },
+              ],
+              { width: '200rpx', height: '28rpx', marginLeft: '16rpx' },
+              { width: '120rpx', height: '60rpx', marginLeft: 'auto' },
+            ],
+            [
+              [
+                { width: '56rpx', height: '56rpx', type: 'circle' },
+                { width: '56rpx', height: '56rpx', type: 'circle', marginLeft: '8rpx' },
+              ],
+              { width: '200rpx', height: '28rpx', marginLeft: '16rpx' },
+              { width: '120rpx', height: '60rpx', marginLeft: 'auto' },
+            ],
+          ]"
+          animation="gradient"
+        />
+      </view>
+
+      <!-- 商品详情骨架屏 -->
+      <view class="bg-white p-24rpx">
+        <wd-skeleton
+          :row-col="[
+            { width: '200rpx', height: '40rpx' }, // 标题
+            { width: '100%', height: '400rpx', marginTop: '20rpx' }, // 详情图1
+            { width: '100%', height: '400rpx', marginTop: '20rpx' }, // 详情图2
+            { width: '100%', height: '400rpx', marginTop: '20rpx' }, // 详情图3
+          ]"
+          animation="gradient"
+        />
+      </view>
+    </template>
+
+    <!-- 实际内容 -->
+    <template v-else>
+      <view class="relative">
+        <wd-swiper
+          v-model:current="current" :list="detail.sliderImage.split(',')" autoplay height="750rpx"
+          custom-indicator-class="bottom-40rpx!" :indicator="{ type: 'fraction' }" indicator-position="bottom-right"
+          image-mode="aspectFit"
+        />
+        <NotificationCarousel
+          :notifications="notifications"
+          :top="`${safeAreaInsets?.top + 52}px`"
+        />
+      </view>
+      <view class="relative -top-24rpx">
+        <view
+          class="flex items-center justify-between rounded-t-24rpx from-[#FF3779] to-[#FF334A] bg-gradient-to-br px-24rpx pb-24rpx pt-18rpx text-white"
+        >
+          <view>
+            <view class="mb-12rpx flex items-baseline">
+              <text class="text-28rpx">
+                {{ t('productDetail.price') }}
+              </text>
+              <view class="ml-8rpx rounded-t-18rpx rounded-br-18rpx bg-#202221 px-12rpx text-24rpx">
+                {{ detail.people || 0 }}GB
+              </view>
+            </view>
+            <view>
+              <text class="text-48rpx">
+                <text class="text-28rpx">
+                  ৳
+                </text>{{ formatNumber(detail.price) }}
+              </text>
+              <text class="ml-22rpx text-28rpx line-through">
+                ৳{{ formatNumber(detail.otPrice) }}
+              </text>
+            </view>
+          </view>
+          <text class="text-28rpx">
+            {{ t('productDetail.sold', [detail.ficti]) }}
+          </text>
+        </view>
+        <view class="bg-white px-24rpx pb-24rpx pt-20rpx text-32rpx">
+          <view class="line-clamp-2font-bold mb-16rpx">
+            {{ detail.storeName }}
+          </view>
+          <view class="flex items-center justify-between" @click="openSku('open')">
+            <view>
+              <text class="text-28rpx text-#757575">
+                {{ selectedSpecsText }}
+              </text>
+            </view>
+            <wd-icon name="arrow-right" color="#7D7D7D" size="36rpx" />
+          </view>
+        </view>
+      </view>
+      <view class="mb-20rpx bg-white p-24rpx">
+        <view class="mb-20rpx flex items-center justify-between">
+          <view
+            class="flex items-center before:h-45rpx before:w-8rpx before:rounded-4rpx before:bg-#FF3778 before:content-empty"
+          >
+            <text class="ml-10rpx text-32rpx">
+              {{ t('productDetail.groupRules') }}
+            </text>
+          </view>
+          <view class="flex items-center">
+            <text class="mr-8rpx text-24rpx text-#3A444C">
+              {{ t('productDetail.viewRules') }}
+            </text>
+            <wd-icon name="arrow-right" color="#7D7D7D" size="24rpx" />
+          </view>
+        </view>
+        <image src="/static/images/buy-flow.png" class="w-full" mode="widthFix" />
+      </view>
+      <view v-if="pinkInfo && pinkInfo.length" class="mb-20rpx bg-white px-24rpx pt-24rpx">
+        <view
+          class="mb-20rpx flex items-center before:h-45rpx before:w-8rpx before:rounded-4rpx before:bg-#FF3778 before:content-empty"
+        >
+          <text class="ml-10rpx text-32rpx">
+            {{ t('productDetail.ongoingGroup') }}
+          </text>
+        </view>
+        <swiper
+          autoplay
+          vertical
+          circular
+          class="py-10rpx"
+          :style="{ height: pinkInfo[0].length <= 3 ? `${pinkInfo[0].length * 80}rpx` : '240rpx' }"
+        >
+          <swiper-item v-for="(list, y) in pinkInfo" :key="y">
+            <view class="flex flex-col gap-24rpx">
+              <view v-for="(item, index) in list" :key="index" class="flex items-center justify-between">
+                <view class="flex items-center">
+                  <view>
+                    <!-- 头像组 最多五个 -->
+                    <view class="mr-16rpx min-w-220rpx flex items-center">
+                      <view
+                        v-for="(e, i) in item.successAvatar.slice(0, 5)"
+                        :key="i"
+                        :style="{ marginLeft: i !== 0 ? '-20rpx' : '0', zIndex: 10 - i }"
+                        class="h-56rpx w-56rpx overflow-hidden border-2rpx border-white rounded-full border-solid"
+                      >
+                        <image :src="e ? e : '/static/images/default-avatar.png'" class="h-full w-full" mode="aspectFill" />
+                      </view>
+                    </view>
+                  </view>
+                  <view>
+                    <view class="text-28rpx">
+                      {{ t('productDetail.need') }}
+                      <text class="text-[var(--wot-color-theme)]">
+                        {{ item.totalNum - item.remainNum }}
+                      </text>
+                      {{ t('productDetail.more') }}
+                    </view>
+                  </view>
+                </view>
+                <wd-button size="small" @click="openSku('join', item.id, item.orderId)">
+                  {{ t('productDetail.joinGroup') }}
+                </wd-button>
+              </view>
+            </view>
+          </swiper-item>
+        </swiper>
+      </view>
+      <view class="bg-white p-24rpx">
+        <view
+          class="mb-20rpx flex items-center before:h-45rpx before:w-8rpx before:rounded-4rpx before:bg-#FF3778 before:content-empty"
+        >
+          <text class="ml-10rpx text-32rpx">
+            {{ t('productDetail.details') }}
+          </text>
+        </view>
+        <view v-for="i in detail.flatPattern.split(',')" :key="i">
+          <image
+            :src="i"
+            mode="widthFix"
+            class="w-full"
+          />
+        </view>
+      </view>
+    </template>
+
+    <!-- 底部按钮区域 -->
+    <template #bottom>
+      <view class="flex bg-white/60 px-28rpx py-30rpx backdrop-blur-20">
+        <view class="mr-30rpx flex flex-1 items-center justify-around gap-20rpx">
+          <view class="flex flex-col items-center justify-center">
+            <image
+              src="/static/icons/go-home.png"
+              class="h-40rpx w-40rpx"
+              @click="goHome"
+            />
+            <text class="text-18rpx text-#757575">
+              {{ t('productDetail.home') }}
+            </text>
+          </view>
+          <view class="flex flex-col items-center justify-center">
+            <image
+              v-if="detail.favoriteFlag"
+              src="/static/icons/favorite-active.png"
+              class="h-40rpx w-40rpx"
+            />
+            <image
+              v-else
+              src="/static/icons/favorite.png"
+              class="h-40rpx w-40rpx"
+            />
+            <text class="text-18rpx text-#757575">
+              {{ t('productDetail.favorite') }}
+            </text>
+          </view>
+        </view>
+        <view class="flex items-center justify-end text-32rpx">
+          <view class="relative">
+            <view class="rounded-l-full bg-#2F2D31 px-34rpx py-18rpx text-white" @click="openSku('open')">
+              {{ t('productDetail.openGroup') }}
+            </view>
+            <CustomTooltip
+              v-model:visible="showTip"
+            />
+          </view>
+          <view class="rounded-r-full bg-[var(--wot-color-theme)] px-34rpx py-18rpx text-white" @click="openSku('join')">
+            {{ t('productDetail.joinGroup') }}
+          </view>
+        </view>
+      </view>
+    </template>
+  </z-paging>
+  <wd-action-sheet v-model="showSku" :z-index="999">
+    <view class="px-24rpx">
+      <view class="mb-16rpx flex items-center gap-24rpx border-b-1 border-b-color-#e8e8e8 border-b-solid py-24rpx">
+        <image
+          :src="matchedAttrValue.image || detail?.image"
+          class="h-160rpx w-160rpx shrink-0"
+          mode="aspectFit"
+        />
+        <view class="flex-1">
+          <view class="line-clamp-2 mb-32rpx text-28rpx">
+            {{ detail.storeName }}
+          </view>
+          <view class="flex items-baseline">
+            <view class="text-#FF0010">
+              <text class="text-28rpx">
+                ৳
+              </text>
+              <text class="text-48rpx">
+                {{ formatNumber(matchedAttrValue.price || 0) }}
+              </text>
+            </view>
+            <view class="ml-20rpx text-28rpx text-#787878 line-through">
+              ৳{{ formatNumber(matchedAttrValue.otPrice || 0) }}
+            </view>
+          </view>
+        </view>
+      </view>
+      <view v-for="i in detail.attr" :key="i.id" class="mb-24rpx border-b-1 border-b-color-#e8e8e8 border-b-solid pb-40rpx">
+        <view class="mb-12rpx text-32rpx">
+          {{ i.attrName }}
+        </view>
+        <view class="grid grid-cols-4 gap-20rpx">
+          <view v-for="(e, j) in i.attrImgValues" :key="j" class="flex flex-col justify-end">
+            <view
+              class="box-border flex flex-col border-1 border-transparent border-dashed bg-#F5F5F7 text-center"
+              :style="{ borderColor: formData.selectedSpecs[i.attrName] === e.name ? 'var(--wot-color-theme)' : '' }"
+              @click="selectSpec(i.attrName, e.name)"
+            >
+              <view>
+                <view v-if="e.img" class="h-160rpx w-full">
+                  <image
+                    :src="e.img"
+                    class="h-full w-full"
+                    mode="aspectFit"
+                  />
+                </view>
+                <view class="py-12rpx text-22rpx text-#757575">
+                  {{ e.name }}
+                </view>
+              </view>
+            </view>
+          </view>
+        </view>
+      </view>
+      <view class="mb-100rpx flex items-center justify-between text-32rpx">
+        <view>{{ t('productDetail.quantity') }}</view>
+        <wd-input-number v-model="formData.productNum" :max="1" :min="1" />
+      </view>
+      <view class="py-24rpx">
+        <wd-button block :loading="loading" :style="{ backgroundColor: groupType === 'open' ? '#2F2D31' : 'var(--wot-color-theme)' }">
+          {{ groupType === 'open' ? t('productDetail.openGroup') : t('productDetail.joinGroup') }}
+        </wd-button>
+      </view>
+    </view>
+  </wd-action-sheet>
+</template>
+
+<style lang="scss" scoped>
+:deep() {
+  .wd-navbar__title {
+    margin: 0;
+    max-width: 100%;
+  }
+}
+</style>

+ 18 - 22
src/utils/page.ts

@@ -6,19 +6,24 @@ export function goBack(delta = 1) {
 }
 
 // uniapp 跳转页面 可携带参数
-// 示例: toPage('/pages/productDetail/productDetail', { id: 123 })
-export function toPage(url: string, params?: Record<string, any>, isRedirect = false) {
-  let targetUrl = url
+export function toPage({ url, params, isRedirect = false, isReLaunch = false }: any) {
+  let targetUrl = url + (isReLaunch ? '?isReLaunch=1' : '')
   const tabBarPages = ['/pages/index/index', '/pages/income/income', '/pages/mine/mine']
 
   if (params && Object.keys(params).length > 0) {
-    const data = JSON.stringify(params)
-    targetUrl = `${url}?params=${encodeURIComponent(data)}`
+    const strParams = stringifyQuery(params)
+    targetUrl = `${url}?${strParams + (isReLaunch ? '&isReLaunch=1' : '')}`
   }
+  console.log(targetUrl)
   if (tabBarPages.includes(url)) {
-    uni.switchTab({
-      url: targetUrl,
-    })
+    if (CUSTOM_TABBAR_NO_CACHE) {
+      uni.navigateTo({ url: targetUrl })
+    }
+    else {
+      uni.switchTab({
+        url: targetUrl,
+      })
+    }
   }
   else {
     if (isRedirect) {
@@ -26,6 +31,11 @@ export function toPage(url: string, params?: Record<string, any>, isRedirect = f
         url: targetUrl,
       })
     }
+    else if (isReLaunch) {
+      uni.reLaunch({
+        url: targetUrl,
+      })
+    }
     else {
       uni.navigateTo({
         url: targetUrl,
@@ -33,17 +43,3 @@ export function toPage(url: string, params?: Record<string, any>, isRedirect = f
     }
   }
 }
-
-// page参数解析方法
-export function getPageParams(options: any) {
-  if (options && options.params) {
-    try {
-      return JSON.parse(decodeURIComponent(options.params))
-    }
-    catch (e) {
-      console.error('解析页面参数失败:', e)
-      return {}
-    }
-  }
-  return {}
-}