diff --git a/.pages-backup/pages.consumer.2026-06-03T00-41-33-509Z.json b/.pages-backup/pages.consumer.2026-06-03T00-41-33-509Z.json new file mode 100644 index 00000000..b2ea96e6 --- /dev/null +++ b/.pages-backup/pages.consumer.2026-06-03T00-41-33-509Z.json @@ -0,0 +1,464 @@ +{ + "pages": [ + { + "path": "pages/main/index", + "style": { + "navigationBarTitleText": "首页", + "navigationStyle": "custom", + "enablePullDownRefresh": false + } + }, + { + "path": "pages/user/boot", + "style": { + "navigationBarTitleText": "" + } + }, + { + "path": "pages/user/login", + "style": { + "navigationBarTitleText": "用户登录", + "navigationStyle": "custom" + } + }, + { + "path": "pages/user/register", + "style": { + "navigationBarTitleText": "注册" + } + }, + { + "path": "pages/user/forgot-password", + "style": { + "navigationBarTitleText": "忘记密码" + } + }, + { + "path": "pages/user/terms", + "style": { + "navigationBarTitleText": "用户协议与隐私政策" + } + }, + { + "path": "pages/user/center", + "style": { + "navigationBarTitleText": "用户中心" + } + }, + { + "path": "pages/user/profile", + "style": { + "navigationBarTitleText": "个人资料" + } + }, + { + "path": "pages/user/change-password", + "style": { + "navigationBarTitleText": "修改密码" + } + }, + { + "path": "pages/user/bind-phone", + "style": { + "navigationBarTitleText": "绑定手机" + } + }, + { + "path": "pages/user/bind-email", + "style": { + "navigationBarTitleText": "绑定邮箱" + } + }, + { + "path": "pages/main/messages", + "style": { + "navigationBarTitleText": "消息", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/main/cart", + "style": { + "navigationBarTitleText": "购物车", + "navigationStyle": "custom" + } + }, + { + "path": "pages/main/profile", + "style": { + "navigationBarTitleText": "我的", + "navigationStyle": "custom" + } + }, + { + "path": "pages/main/category", + "style": { + "navigationBarTitleText": "分类", + "navigationStyle": "custom" + } + } + ], + "subPackages": [ + { + "root": "pages/mall/consumer", + "pages": [ + { + "path": "settings", + "style": { + "navigationBarTitleText": "设置" + } + }, + { + "path": "edit-profile", + "style": { + "navigationBarTitleText": "编辑资料" + } + }, + { + "path": "wallet", + "style": { + "navigationBarTitleText": "我的钱包" + } + }, + { + "path": "withdraw", + "style": { + "navigationBarTitleText": "余额提现" + } + }, + { + "path": "search", + "style": { + "navigationBarTitleText": "搜索", + "navigationStyle": "custom" + } + }, + { + "path": "product-detail", + "style": { + "navigationBarTitleText": "", + "navigationStyle": "custom" + } + }, + { + "path": "channel-detail", + "style": { + "navigationBarTitleText": "频道详情", + "navigationStyle": "custom" + } + }, + { + "path": "shop-detail", + "style": { + "navigationBarTitleText": "店铺详情" + } + }, + { + "path": "coupons", + "style": { + "navigationBarTitleText": "我的优惠券" + } + }, + { + "path": "favorites", + "style": { + "navigationBarTitleText": "我的收藏" + } + }, + { + "path": "footprint", + "style": { + "navigationBarTitleText": "我的足迹" + } + }, + { + "path": "address", + "style": { + "navigationBarTitleText": "地址" + } + }, + { + "path": "address-list", + "style": { + "navigationBarTitleText": "收货地址" + } + }, + { + "path": "address-edit", + "style": { + "navigationBarTitleText": "编辑地址" + } + }, + { + "path": "checkout", + "style": { + "navigationBarTitleText": "确认订单" + } + }, + { + "path": "payment", + "style": { + "navigationBarTitleText": "", + "navigationStyle": "custom" + } + }, + { + "path": "payment-success", + "style": { + "navigationBarTitleText": "支付成功", + "navigationStyle": "custom" + } + }, + { + "path": "orders", + "style": { + "navigationBarTitleText": "", + "navigationStyle": "custom", + "enablePullDownRefresh": true, + "backgroundColor": "#f5f5f5" + } + }, + { + "path": "order-detail", + "style": { + "navigationBarTitleText": "订单详情" + } + }, + { + "path": "logistics", + "style": { + "navigationBarTitleText": "物流详情" + } + }, + { + "path": "review", + "style": { + "navigationBarTitleText": "评价晒单" + } + }, + { + "path": "refund", + "style": { + "navigationBarTitleText": "退款/售后" + } + }, + { + "path": "apply-refund", + "style": { + "navigationBarTitleText": "申请售后" + } + }, + { + "path": "refund-review", + "style": { + "navigationBarTitleText": "服务评价" + } + }, + { + "path": "chat", + "style": { + "navigationBarTitleText": "客服聊天", + "navigationStyle": "custom" + } + }, + { + "path": "chat_new", + "style": { + "navigationBarTitleText": "客服聊天(新版)" + } + }, + { + "path": "subscription/plan-list", + "style": { + "navigationBarTitleText": "软件订阅" + } + }, + { + "path": "subscription/plan-detail", + "style": { + "navigationBarTitleText": "订阅详情" + } + }, + { + "path": "subscription/subscribe-checkout", + "style": { + "navigationBarTitleText": "确认订阅" + } + }, + { + "path": "subscription/my-subscriptions", + "style": { + "navigationBarTitleText": "我的订阅" + } + }, + { + "path": "subscription/followed-shops", + "style": { + "navigationBarTitleText": "关注店铺" + } + }, + { + "path": "points/index", + "style": { + "navigationBarTitleText": "积分管理" + } + }, + { + "path": "points/signin", + "style": { + "navigationBarTitleText": "签到" + } + }, + { + "path": "points/exchange", + "style": { + "navigationBarTitleText": "积分兑换" + } + }, + { + "path": "points/exchange-records", + "style": { + "navigationBarTitleText": "兑换记录" + } + }, + { + "path": "red-packets/index", + "style": { + "navigationBarTitleText": "我的红包" + } + }, + { + "path": "bank-cards/index", + "style": { + "navigationBarTitleText": "银行卡管理" + } + }, + { + "path": "bank-cards/add", + "style": { + "navigationBarTitleText": "添加银行卡" + } + }, + { + "path": "home-service/index", + "style": { + "navigationBarTitleText": "居家上门服务", + "navigationStyle": "custom" + } + }, + { + "path": "home-service/apply", + "style": { + "navigationBarTitleText": "提交服务申请", + "navigationStyle": "custom" + } + }, + { + "path": "home-service/service-detail", + "style": { + "navigationBarTitleText": "预约服务", + "navigationStyle": "custom" + } + }, + { + "path": "home-service/order-detail", + "style": { + "navigationBarTitleText": "服务单详情", + "navigationStyle": "custom" + } + }, + { + "path": "home-service/feedback", + "style": { + "navigationBarTitleText": "验收反馈", + "navigationStyle": "custom" + } + }, + { + "path": "bank-cards/verify", + "style": { + "navigationBarTitleText": "银行卡验证" + } + }, + { + "path": "balance/index", + "style": { + "navigationBarTitleText": "余额" + } + }, + { + "path": "my-reviews", + "style": { + "navigationBarTitleText": "我的评价" + } + }, + { + "path": "message-detail", + "style": { + "navigationBarTitleText": "消息详情" + } + }, + { + "path": "member/index", + "style": { + "navigationBarTitleText": "会员中心" + } + }, + { + "path": "product-reviews", + "style": { + "navigationBarTitleText": "商品评价" + } + } + ] + } + ], + "tabBar": { + "color": "#999999", + "selectedColor": "#ff5000", + "backgroundColor": "#ffffff", + "borderStyle": "black", + "list": [ + { + "pagePath": "pages/main/index", + "text": "首页", + "iconPath": "static/tabbar/home.png", + "selectedIconPath": "static/tabbar/home-active.png" + }, + { + "pagePath": "pages/main/messages", + "text": "消息", + "iconPath": "static/tabbar/message.png", + "selectedIconPath": "static/tabbar/message.png" + }, + { + "pagePath": "pages/main/cart", + "text": "购物车", + "iconPath": "static/tabbar/cart.png", + "selectedIconPath": "static/tabbar/cart.png" + }, + { + "pagePath": "pages/main/profile", + "text": "我的", + "iconPath": "static/tabbar/user.png", + "selectedIconPath": "static/tabbar/user.png" + } + ] + }, + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "mall", + "navigationBarBackgroundColor": "#FFFFFF", + "backgroundColor": "#F8F8F8" + }, + "condition": { + "current": 0, + "list": [ + { + "name": "consumer端", + "path": "pages/main/index", + "query": "role=consumer" + } + ] + } +} diff --git a/components/supadb/aksupa.uts b/components/supadb/aksupa.uts index 679e6756..698f5a49 100644 --- a/components/supadb/aksupa.uts +++ b/components/supadb/aksupa.uts @@ -313,7 +313,6 @@ export class AkSupaQueryBuilder { params.push(`or=(${orStr})`); } if (this._orString!=null && this._orString !== "") { - console.log('[AkSupaQueryBuilder] or字符串:', this._orString) params.push(`or=(${this._orString!!})`); } return params.length > 0 ? params.join('&') : null; @@ -369,7 +368,6 @@ export class AkSupaQueryBuilder { async execute() : Promise> { //console.log('execute') const filter = this._buildFilter(); - console.log('[AkSupaQueryBuilder] execute - 表:', this._table, 'filter:', filter) let res : any; switch (this._action) { case 'select': { diff --git a/mall_sql/migrations/20260603_favorites_soft_delete_and_service.sql b/mall_sql/migrations/20260603_favorites_soft_delete_and_service.sql new file mode 100644 index 00000000..27ee745b --- /dev/null +++ b/mall_sql/migrations/20260603_favorites_soft_delete_and_service.sql @@ -0,0 +1,94 @@ +BEGIN; + +ALTER TABLE public.ml_user_favorites + ALTER COLUMN target_id TYPE TEXT USING target_id::text; + +ALTER TABLE public.ml_user_favorites + ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ; + +UPDATE public.ml_user_favorites +SET updated_at = COALESCE(updated_at, created_at, now()) +WHERE updated_at IS NULL; + +DO $$ +BEGIN + IF EXISTS ( + SELECT 1 + FROM information_schema.table_constraints + WHERE table_schema = 'public' + AND table_name = 'ml_user_favorites' + AND constraint_name = 'chk_ml_favorite_type' + ) THEN + ALTER TABLE public.ml_user_favorites DROP CONSTRAINT chk_ml_favorite_type; + END IF; +END $$; + +ALTER TABLE public.ml_user_favorites + ADD CONSTRAINT chk_ml_favorite_type CHECK (target_type IN (1, 2, 3)); + +ALTER TABLE public.ml_user_favorites + DROP CONSTRAINT IF EXISTS ml_user_favorites_user_id_target_type_target_id_key; + +CREATE UNIQUE INDEX IF NOT EXISTS uq_ml_user_favorites_user_target_active +ON public.ml_user_favorites(user_id, target_type, target_id) +WHERE deleted_at IS NULL; + +CREATE INDEX IF NOT EXISTS idx_ml_user_favorites_user_deleted_created +ON public.ml_user_favorites(user_id, deleted_at, created_at DESC); + +CREATE INDEX IF NOT EXISTS idx_ml_user_favorites_target_deleted +ON public.ml_user_favorites(target_type, target_id, deleted_at); + +COMMENT ON COLUMN public.ml_user_favorites.target_type IS '1=商品 2=店铺 3=服务'; +COMMENT ON COLUMN public.ml_user_favorites.target_id IS '收藏目标ID,兼容商品UUID、店铺UUID、服务文本ID'; +COMMENT ON COLUMN public.ml_user_favorites.updated_at IS '更新时间'; +COMMENT ON COLUMN public.ml_user_favorites.deleted_at IS '软删除时间,NULL为有效收藏'; + +ALTER TABLE public.ml_user_favorites ENABLE ROW LEVEL SECURITY; + +DROP POLICY IF EXISTS ml_user_favorites_select_policy ON public.ml_user_favorites; +CREATE POLICY ml_user_favorites_select_policy ON public.ml_user_favorites + FOR SELECT + USING ( + deleted_at IS NULL + AND auth.uid() = (SELECT auth_id FROM public.ak_users WHERE id = user_id) + ); + +DROP POLICY IF EXISTS ml_user_favorites_insert_policy ON public.ml_user_favorites; +CREATE POLICY ml_user_favorites_insert_policy ON public.ml_user_favorites + FOR INSERT + WITH CHECK ( + auth.uid() = (SELECT auth_id FROM public.ak_users WHERE id = user_id) + ); + +DROP POLICY IF EXISTS ml_user_favorites_update_policy ON public.ml_user_favorites; +CREATE POLICY ml_user_favorites_update_policy ON public.ml_user_favorites + FOR UPDATE + USING ( + auth.uid() = (SELECT auth_id FROM public.ak_users WHERE id = user_id) + ) + WITH CHECK ( + auth.uid() = (SELECT auth_id FROM public.ak_users WHERE id = user_id) + ); + +DROP POLICY IF EXISTS ml_user_favorites_delete_policy ON public.ml_user_favorites; +CREATE POLICY ml_user_favorites_delete_policy ON public.ml_user_favorites + FOR DELETE + USING ( + auth.uid() = (SELECT auth_id FROM public.ak_users WHERE id = user_id) + ); + +ALTER TABLE public.hss_service_catalog ENABLE ROW LEVEL SECURITY; + +DROP POLICY IF EXISTS hss_service_catalog_public_select ON public.hss_service_catalog; +CREATE POLICY hss_service_catalog_public_select ON public.hss_service_catalog + FOR SELECT + USING (deleted_at IS NULL AND status = 1); + +DROP POLICY IF EXISTS hss_service_catalog_authenticated_select_all_active_record ON public.hss_service_catalog; +CREATE POLICY hss_service_catalog_authenticated_select_all_active_record ON public.hss_service_catalog + FOR SELECT TO authenticated + USING (deleted_at IS NULL); + +COMMIT; \ No newline at end of file diff --git a/mall_sql/migrations/20260603_review_public_profiles.sql b/mall_sql/migrations/20260603_review_public_profiles.sql new file mode 100644 index 00000000..cac39b1f --- /dev/null +++ b/mall_sql/migrations/20260603_review_public_profiles.sql @@ -0,0 +1,14 @@ +-- 为商品评价提供最小公开用户资料视图,避免客户端直接访问 auth.users 或整表 ak_users。 + +create or replace view public.ak_user_public_profiles as +select + id, + coalesce(nullif(username, ''), '匿名用户') as username, + coalesce(avatar_url, '') as avatar_url +from public.ak_users; + +comment on view public.ak_user_public_profiles is '商品评价等前台展示使用的最小公开用户资料视图'; + +grant select on public.ak_user_public_profiles to anon; +grant select on public.ak_user_public_profiles to authenticated; +grant select on public.ak_user_public_profiles to service_role; \ No newline at end of file diff --git a/pages/main/index.uvue b/pages/main/index.uvue index af1c6f83..e6b4d08d 100644 --- a/pages/main/index.uvue +++ b/pages/main/index.uvue @@ -2094,13 +2094,23 @@ const familyItems = [ // 初始化页面 const initPage = () => { - const systemInfo = uni.getSystemInfoSync() - statusBarHeight.value = systemInfo.statusBarHeight != null ? systemInfo.statusBarHeight : 20 - const searchContentHeight = Math.round(68 * systemInfo.screenWidth / 750) - const searchTopGap = Math.round(14 * systemInfo.screenWidth / 750) - const headerBottomPadding = Math.round(10 * systemInfo.screenWidth / 750) - const moduleRowHeight = Math.round(62 * systemInfo.screenWidth / 750) - const categoryRowHeight = Math.round(56 * systemInfo.screenWidth / 750) + let screenWidth = 375 + let screenHeight = 667 + let safeAreaBottom = 0 + try { + const windowInfo = uni.getWindowInfo() + statusBarHeight.value = windowInfo.statusBarHeight != null ? windowInfo.statusBarHeight : 20 + screenWidth = windowInfo.screenWidth != null ? windowInfo.screenWidth : (windowInfo.windowWidth != null ? windowInfo.windowWidth : 375) + screenHeight = windowInfo.screenHeight != null ? windowInfo.screenHeight : (windowInfo.windowHeight != null ? windowInfo.windowHeight : 667) + safeAreaBottom = windowInfo.safeArea != null ? windowInfo.safeArea.bottom : 0 + } catch (e) { + statusBarHeight.value = 20 + } + const searchContentHeight = Math.round(68 * screenWidth / 750) + const searchTopGap = Math.round(14 * screenWidth / 750) + const headerBottomPadding = Math.round(10 * screenWidth / 750) + const moduleRowHeight = Math.round(62 * screenWidth / 750) + const categoryRowHeight = Math.round(56 * screenWidth / 750) let menuInfo: CapsuleButtonInfo | null = null // #ifdef MP-WEIXIN || MP-ALIPAY @@ -2116,7 +2126,7 @@ const initPage = () => { const navHeight = (menuInfo.top - statusBarHeight.value) * 2 + menuInfo.height navBarHeight.value = navHeight - const rightReserve = systemInfo.screenWidth - menuInfo.left + 8 + const rightReserve = screenWidth - menuInfo.left + 8 navBarRight.value = rightReserve const searchRowTotalH = statusBarHeight.value + Math.max(navHeight, moduleRowHeight) + searchTopGap + searchContentHeight + headerBottomPadding searchRowStyle.value = `padding-right:${rightReserve}px;` @@ -2132,10 +2142,9 @@ const initPage = () => { headerStyle.value = `` categoryBarHeightPx.value = categoryRowHeight headerPlaceholderHeight.value = navbarTotalHeight.value + categoryBarHeightPx.value - const safeBottom = systemInfo.safeArea != null ? systemInfo.screenHeight - systemInfo.safeArea.bottom : 20 + const safeBottom = safeAreaBottom > 0 ? (screenHeight - safeAreaBottom) : 20 bottomSafeArea.value = safeBottom > 0 ? safeBottom : 20 - const screenWidth = systemInfo.screenWidth isMobile.value = screenWidth < 768 } diff --git a/pages/mall/consumer/favorites.uvue b/pages/mall/consumer/favorites.uvue index cdceaa0c..ba09865d 100644 --- a/pages/mall/consumer/favorites.uvue +++ b/pages/mall/consumer/favorites.uvue @@ -1,597 +1,1770 @@ - + + +.checkout-btn-disabled, +.delete-btn-disabled, +.sku-confirm-btn-disabled { + background-color: #f3b9b5; + color: #ffffff; +} + +.sku-popup { + background-color: #ffffff; + border-top-left-radius: 18px; + border-top-right-radius: 18px; + max-height: 76vh; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.sku-popup-header { + padding: 16px 16px 12px; + display: flex; + flex-direction: row; + align-items: flex-start; + border-bottom: 1px solid #f1f1f1; + position: relative; +} + +.sku-popup-image { + width: 88px; + height: 88px; + border-radius: 10px; + background-color: #f5f5f5; + margin-right: 12px; + flex-shrink: 0; +} + +.sku-popup-summary { + flex: 1; + display: flex; + flex-direction: column; + padding-top: 4px; + min-width: 0; +} + +.sku-popup-price { + font-size: 20px; + font-weight: 700; + color: #e1251b; + margin-bottom: 8px; +} + +.popup-tag-row { + margin-bottom: 8px; +} + +.sku-popup-selected { + font-size: 12px; + line-height: 1.5; + color: #666666; +} + +.sku-popup-close { + position: absolute; + top: 14px; + right: 16px; + font-size: 20px; + line-height: 1; + color: #999999; +} + +.sku-popup-state { + padding: 30px 16px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 10px; +} + +.sku-popup-state-text { + font-size: 13px; + color: #666666; +} + +.sku-popup-retry { + font-size: 13px; + color: #d94841; +} + +.sku-popup-scroll { + flex: 1; + height: 0px; + padding: 0 16px; + box-sizing: border-box; +} + +.sku-section { + padding-top: 16px; + padding-bottom: 8px; +} + +.quantity-section { + padding-bottom: 18px; +} + +.sku-section-title { + font-size: 14px; + font-weight: 600; + color: #222222; + margin-bottom: 12px; + display: block; +} + +.sku-chip-row { + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 10px; +} + +.sku-chip { + padding: 8px 12px; + border-radius: 18px; + background-color: #f5f5f5; + border: 1px solid #f5f5f5; +} + +.sku-chip-active { + background-color: #fff4f2; + border-color: #f1b2ad; +} + +.sku-chip-disabled { + background-color: #f2f2f2; + border-color: #f2f2f2; +} + +.sku-chip-text { + font-size: 13px; + color: #333333; +} + +.sku-chip-text-disabled { + color: #b5b5b5; +} + +.popup-stock-text { + font-size: 12px; + color: #999999; + margin-top: 8px; + display: block; +} + +.sku-popup-footer { + padding: 10px 16px calc(10px + env(safe-area-inset-bottom)); + border-top: 1px solid #f1f1f1; + background-color: #ffffff; +} + +.sku-confirm-btn { + width: 100%; + border-radius: 22px; +} + +@media (min-width: 768px) { + .favorites-content { + max-width: 960px; + margin: 0 auto; + width: 100%; + } + + .purchase-bar, + .manage-bar { + left: 50%; + transform: translateX(-50%); + max-width: 960px; + } + } + \ No newline at end of file diff --git a/pages/mall/consumer/footprint.uvue b/pages/mall/consumer/footprint.uvue index 8b4a6872..7d0dcce5 100644 --- a/pages/mall/consumer/footprint.uvue +++ b/pages/mall/consumer/footprint.uvue @@ -1,757 +1,838 @@ - - diff --git a/pages/mall/consumer/home-service/service-detail.uvue b/pages/mall/consumer/home-service/service-detail.uvue index 8fd819d8..c69faba9 100644 --- a/pages/mall/consumer/home-service/service-detail.uvue +++ b/pages/mall/consumer/home-service/service-detail.uvue @@ -21,9 +21,14 @@ {{ tag.label }} - ¥ - {{ minPriceText }} - + + ¥ + {{ minPriceText }} + + + + {{ isFavorite ? '已收藏' : '收藏服务' }} + @@ -303,6 +308,7 @@ import { createHomeServiceApplication, fetchHomeServiceCatalog, fetchHomeService import { shouldUseCareTaskPath } from '@/services/serviceOrderService.uts' import { HomeServiceApplicationDraftType, HomeServiceCatalogType, HomeServicePackageType, HomeServiceSelectedAddressType } from '@/types/home-service.uts' import { getCurrentUser, getCurrentUserId } from '@/utils/store.uts' +import { supabaseService } from '@/utils/supabaseService.uts' import { goToLogin } from '@/utils/utils.uts' import { HomeServiceAgencyType, @@ -382,6 +388,7 @@ const serviceValidity = ref('预约后 30 天内可服务') const serviceSuitableFor = ref('行动不便、术后恢复、慢病随访老人') const serviceImageText = ref('照护') const serviceExcludeText = ref('高风险处置、住院陪护、急诊陪诊') +const isFavorite = ref(false) const bookingDays = ref>([]) const bookingSlots = ref>([]) @@ -782,6 +789,7 @@ async function loadData() { } if (matchedService == null) { setUnavailableServiceState() + await syncFavoriteState() return } serviceTitle.value = matchedService.name @@ -796,11 +804,34 @@ async function loadData() { servicePackages.value = mapServicePackages(packages) if (servicePackages.value.length == 0) { setUnavailableServiceState() + await syncFavoriteState() return } const firstPackage = servicePackages.value[0] servicePrice.value = firstPackage.price serviceDuration.value = firstPackage.duration + await syncFavoriteState() +} + +async function syncFavoriteState(): Promise { + const userId = getCurrentUserId() + if (userId == '') { + isFavorite.value = false + return + } + isFavorite.value = await supabaseService.checkFavorite(serviceId.value, 'service') +} + +async function toggleServiceFavorite(): Promise { + if (!(await ensureLogin())) { + return + } + const nextState = await supabaseService.toggleFavorite(serviceId.value, 'service') + isFavorite.value = nextState + uni.showToast({ + title: nextState ? '已收藏服务' : '已取消收藏', + icon: nextState ? 'success' : 'none' + }) } async function ensureLogin(): Promise { @@ -1105,6 +1136,7 @@ function refreshBookingSlots(): void { onShow(() => { loadCachedSelectedAddress() + syncFavoriteState() const now = new Date() const day = selectedDay.value if (day != null) { @@ -1358,6 +1390,12 @@ onUnload(() => { .summary-price-row { margin-top: 12rpx; + justify-content: space-between; + align-items: flex-end; +} + +.summary-price-main { + flex-direction: row; align-items: flex-end; } @@ -1377,6 +1415,26 @@ onUnload(() => { margin-bottom: 6rpx; } +.summary-favorite-btn { + min-width: 132rpx; + height: 56rpx; + padding: 0 22rpx; + border-radius: 999rpx; + background: #fff3ee; + border-width: 1rpx; + border-style: solid; + border-color: #ffd0c2; + align-items: center; + justify-content: center; + box-sizing: border-box; +} + +.summary-favorite-btn-text { + font-size: 22rpx; + color: #d85b34; + font-weight: 600; +} + .form-item { margin-bottom: 24rpx; } diff --git a/pages/mall/consumer/product-detail.uvue b/pages/mall/consumer/product-detail.uvue index cca06c36..01701c76 100644 --- a/pages/mall/consumer/product-detail.uvue +++ b/pages/mall/consumer/product-detail.uvue @@ -1,33 +1,57 @@