From 78bca3b3d5e84adca88aa4513b2c7dc591c1a394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=8C=E5=85=88=E8=88=9C?= <2499071264@qq.com> Date: Tue, 28 Jul 2026 10:08:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=95=86=E5=93=81=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 6 + supplied-h5/package-lock.json | 7 + supplied-h5/package.json | 1 + supplied-h5/src/router/index.js | 4 + supplied-h5/src/store/cart.js | 8 + .../joyful-selection/address/address-data.js | 48 ++ .../joyful-selection/address/edit/index.vue | 132 ++++++ .../view/joyful-selection/address/index.vue | 94 ++++ .../joyful-selection/cart/checkout/index.vue | 409 ++++++++++++++++-- .../cart/components/JoyfulCartPanel.vue | 324 ++++++++++++++ .../view/joyful-selection/cart/edit/index.vue | 227 +++++++++- .../src/view/joyful-selection/cart/index.vue | 61 +-- .../cart/payment-confirm/index.vue | 56 ++- .../cart/payment-success/index.vue | 59 ++- .../joyful-selection/cart/payment/index.vue | 223 +++++++++- .../cart/payment/payment-data.js | 23 + .../src/view/joyful-selection/index.vue | 2 +- .../src/view/joyful-selection/layout.vue | 15 +- .../src/view/joyful-selection/product-data.js | 84 +++- .../joyful-selection/product-detail/index.vue | 69 ++- .../components/JoyfulSkuPopup.vue | 123 ++++-- .../view/joyful-selection/products/index.vue | 103 +---- .../joyful-selection/profile/orders/index.vue | 3 +- .../joyful-selection/profile/points/index.vue | 2 +- 24 files changed, 1849 insertions(+), 234 deletions(-) create mode 100644 package-lock.json create mode 100644 supplied-h5/src/view/joyful-selection/address/address-data.js create mode 100644 supplied-h5/src/view/joyful-selection/address/edit/index.vue create mode 100644 supplied-h5/src/view/joyful-selection/address/index.vue create mode 100644 supplied-h5/src/view/joyful-selection/cart/components/JoyfulCartPanel.vue create mode 100644 supplied-h5/src/view/joyful-selection/cart/payment/payment-data.js rename supplied-h5/src/view/joyful-selection/{ => products}/components/JoyfulSkuPopup.vue (62%) diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..d0d75c7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "points-mall", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/supplied-h5/package-lock.json b/supplied-h5/package-lock.json index 589a31a..6a1a02e 100644 --- a/supplied-h5/package-lock.json +++ b/supplied-h5/package-lock.json @@ -8,6 +8,7 @@ "name": "supplied-h5", "version": "1.0.0", "dependencies": { + "@vant/area-data": "^1.5.2", "core-js": "^3.37.1", "pinia": "^2.3.1", "vant": "^2.13.9", @@ -1851,6 +1852,12 @@ "@types/node": "*" } }, + "node_modules/@vant/area-data": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vant/area-data/-/area-data-1.5.2.tgz", + "integrity": "sha512-Gtxgt6Rjgopt6234ANpO0bBsSwtjZ23lBlVDHIy8Mi2NJqyoj1vgVWY0dri8/2LCZAWzQ6EnwRrUVViUZ0cvMA==", + "license": "MIT" + }, "node_modules/@vant/icons": { "version": "3.0.2", "license": "MIT" diff --git a/supplied-h5/package.json b/supplied-h5/package.json index 52e330d..74b1e31 100644 --- a/supplied-h5/package.json +++ b/supplied-h5/package.json @@ -7,6 +7,7 @@ "build": "vue-cli-service build" }, "dependencies": { + "@vant/area-data": "^1.5.2", "core-js": "^3.37.1", "pinia": "^2.3.1", "vant": "^2.13.9", diff --git a/supplied-h5/src/router/index.js b/supplied-h5/src/router/index.js index 0e4df03..6673e53 100644 --- a/supplied-h5/src/router/index.js +++ b/supplied-h5/src/router/index.js @@ -11,6 +11,8 @@ import JoyfulSelectionCheckout from '@/view/joyful-selection/cart/checkout/index import JoyfulSelectionPayment from '@/view/joyful-selection/cart/payment/index.vue' import JoyfulSelectionPaymentConfirm from '@/view/joyful-selection/cart/payment-confirm/index.vue' import JoyfulSelectionPaymentSuccess from '@/view/joyful-selection/cart/payment-success/index.vue' +import JoyfulSelectionAddressList from '@/view/joyful-selection/address/index.vue' +import JoyfulSelectionAddressEdit from '@/view/joyful-selection/address/edit/index.vue' import JoyfulSelectionOrders from '@/view/joyful-selection/profile/orders/index.vue' import JoyfulSelectionProfile from '@/view/joyful-selection/profile/index.vue' import JoyfulSelectionPoints from '@/view/joyful-selection/profile/points/index.vue' @@ -38,6 +40,8 @@ export default new Router({ { path: 'payment', component: JoyfulSelectionPayment }, { path: 'payment-confirm', component: JoyfulSelectionPaymentConfirm }, { path: 'payment-success', component: JoyfulSelectionPaymentSuccess }, + { path: 'address', component: JoyfulSelectionAddressList }, + { path: 'address/edit', component: JoyfulSelectionAddressEdit }, { path: 'orders', component: JoyfulSelectionOrders }, { path: 'profile', component: JoyfulSelectionProfile }, { path: 'points', component: JoyfulSelectionPoints } diff --git a/supplied-h5/src/store/cart.js b/supplied-h5/src/store/cart.js index 4e9dc8b..7005886 100644 --- a/supplied-h5/src/store/cart.js +++ b/supplied-h5/src/store/cart.js @@ -45,6 +45,14 @@ export const useCartStore = defineStore('joyfulSelectionCart', { this.items.unshift(item) } + this.persistCart() + }, + removeItems(cartIds) { + if (!this.loaded) { + this.loadCart() + } + + this.items = this.items.filter(item => !cartIds.includes(item.cartId)) this.persistCart() } } diff --git a/supplied-h5/src/view/joyful-selection/address/address-data.js b/supplied-h5/src/view/joyful-selection/address/address-data.js new file mode 100644 index 0000000..a2ca581 --- /dev/null +++ b/supplied-h5/src/view/joyful-selection/address/address-data.js @@ -0,0 +1,48 @@ +const ADDRESS_KEY = 'joyful-selection-addresses' +const CHOSEN_ADDRESS_KEY = 'joyful-selection-chosen-address-id' + +const defaultAddresses = [ + { + id: 'addr-1', + name: '张三', + tel: '13888888888', + province: '浙江省', + city: '杭州市', + county: '余杭区', + addressDetail: '文一西路 888 号未来科技城海创园5幢1203室', + areaCode: '330110', + postalCode: '310000', + isDefault: true + } +] + +export const readAddresses = () => { + try { + const addresses = JSON.parse(localStorage.getItem(ADDRESS_KEY) || '[]') + return addresses.length ? addresses : defaultAddresses + } catch (error) { + return defaultAddresses + } +} + +export const saveAddresses = addresses => { + localStorage.setItem(ADDRESS_KEY, JSON.stringify(addresses)) +} + +export const readChosenAddressId = () => { + return localStorage.getItem(CHOSEN_ADDRESS_KEY) || readAddresses().find(item => item.isDefault)?.id || readAddresses()[0]?.id || '' +} + +export const saveChosenAddressId = id => { + localStorage.setItem(CHOSEN_ADDRESS_KEY, id) +} + +export const formatAddress = address => { + if (!address) { + return '' + } + + return `${address.province}${address.city}${address.county}${address.addressDetail}` +} + +export const createAddressId = () => `addr-${Date.now()}` diff --git a/supplied-h5/src/view/joyful-selection/address/edit/index.vue b/supplied-h5/src/view/joyful-selection/address/edit/index.vue new file mode 100644 index 0000000..9171c57 --- /dev/null +++ b/supplied-h5/src/view/joyful-selection/address/edit/index.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/supplied-h5/src/view/joyful-selection/address/index.vue b/supplied-h5/src/view/joyful-selection/address/index.vue new file mode 100644 index 0000000..71e9abe --- /dev/null +++ b/supplied-h5/src/view/joyful-selection/address/index.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/supplied-h5/src/view/joyful-selection/cart/checkout/index.vue b/supplied-h5/src/view/joyful-selection/cart/checkout/index.vue index 32b44e3..6c63a15 100644 --- a/supplied-h5/src/view/joyful-selection/cart/checkout/index.vue +++ b/supplied-h5/src/view/joyful-selection/cart/checkout/index.vue @@ -1,50 +1,393 @@ - diff --git a/supplied-h5/src/view/joyful-selection/cart/components/JoyfulCartPanel.vue b/supplied-h5/src/view/joyful-selection/cart/components/JoyfulCartPanel.vue new file mode 100644 index 0000000..6f1275f --- /dev/null +++ b/supplied-h5/src/view/joyful-selection/cart/components/JoyfulCartPanel.vue @@ -0,0 +1,324 @@ + + + + + diff --git a/supplied-h5/src/view/joyful-selection/cart/edit/index.vue b/supplied-h5/src/view/joyful-selection/cart/edit/index.vue index 1aad777..cc860b3 100644 --- a/supplied-h5/src/view/joyful-selection/cart/edit/index.vue +++ b/supplied-h5/src/view/joyful-selection/cart/edit/index.vue @@ -1,42 +1,227 @@ - diff --git a/supplied-h5/src/view/joyful-selection/cart/index.vue b/supplied-h5/src/view/joyful-selection/cart/index.vue index 3787e61..3ae4454 100644 --- a/supplied-h5/src/view/joyful-selection/cart/index.vue +++ b/supplied-h5/src/view/joyful-selection/cart/index.vue @@ -1,57 +1,40 @@ diff --git a/supplied-h5/src/view/joyful-selection/cart/payment-confirm/index.vue b/supplied-h5/src/view/joyful-selection/cart/payment-confirm/index.vue index 766a75c..abecfca 100644 --- a/supplied-h5/src/view/joyful-selection/cart/payment-confirm/index.vue +++ b/supplied-h5/src/view/joyful-selection/cart/payment-confirm/index.vue @@ -1,3 +1,53 @@ - - - + + + + + diff --git a/supplied-h5/src/view/joyful-selection/cart/payment-success/index.vue b/supplied-h5/src/view/joyful-selection/cart/payment-success/index.vue index 8567e5b..43673d2 100644 --- a/supplied-h5/src/view/joyful-selection/cart/payment-success/index.vue +++ b/supplied-h5/src/view/joyful-selection/cart/payment-success/index.vue @@ -1,4 +1,57 @@ - - - + + + + diff --git a/supplied-h5/src/view/joyful-selection/cart/payment/index.vue b/supplied-h5/src/view/joyful-selection/cart/payment/index.vue index 709950a..ece2de0 100644 --- a/supplied-h5/src/view/joyful-selection/cart/payment/index.vue +++ b/supplied-h5/src/view/joyful-selection/cart/payment/index.vue @@ -1,3 +1,220 @@ - - - + + + + + diff --git a/supplied-h5/src/view/joyful-selection/cart/payment/payment-data.js b/supplied-h5/src/view/joyful-selection/cart/payment/payment-data.js new file mode 100644 index 0000000..94599a0 --- /dev/null +++ b/supplied-h5/src/view/joyful-selection/cart/payment/payment-data.js @@ -0,0 +1,23 @@ +const PAYMENT_KEY = 'joyful-selection-payment-info' + +export const createOrderNo = () => { + const now = new Date() + const pad = value => String(value).padStart(2, '0') + const timestamp = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}` + + return `YX${timestamp}` +} + +export const savePaymentInfo = info => { + sessionStorage.setItem(PAYMENT_KEY, JSON.stringify(info)) +} + +export const readPaymentInfo = () => { + try { + return JSON.parse(sessionStorage.getItem(PAYMENT_KEY) || '{}') + } catch (error) { + return {} + } +} + +export const formatYuan = price => (Number(price || 0) / 100).toFixed(2) diff --git a/supplied-h5/src/view/joyful-selection/index.vue b/supplied-h5/src/view/joyful-selection/index.vue index af349dc..164c771 100644 --- a/supplied-h5/src/view/joyful-selection/index.vue +++ b/supplied-h5/src/view/joyful-selection/index.vue @@ -68,7 +68,7 @@ export default { { name: '超值专区', icon: 'label', color: '#ec8c3d', background: '#fff4e9' }, { name: '全部分类', icon: 'apps-o', color: '#989898', background: '#f5f5f5' } ], - flashProducts: joyfulProducts, + flashProducts: joyfulProducts.slice(0, 4), hotProducts: [joyfulProducts[2], joyfulProducts[0], joyfulProducts[1], joyfulProducts[3]] } }, diff --git a/supplied-h5/src/view/joyful-selection/layout.vue b/supplied-h5/src/view/joyful-selection/layout.vue index e8f787f..26694d3 100644 --- a/supplied-h5/src/view/joyful-selection/layout.vue +++ b/supplied-h5/src/view/joyful-selection/layout.vue @@ -4,19 +4,32 @@ 首页 分类 - 购物车 + 购物车 我的 diff --git a/supplied-h5/src/view/joyful-selection/product-data.js b/supplied-h5/src/view/joyful-selection/product-data.js index 1c3badf..64e08ff 100644 --- a/supplied-h5/src/view/joyful-selection/product-data.js +++ b/supplied-h5/src/view/joyful-selection/product-data.js @@ -3,6 +3,87 @@ import miniOvenImage from '@/assets/joyful-selection/products/mini-oven.png' import smartSpeakerImage from '@/assets/joyful-selection/products/smart-speaker.png' import giftBoxImage from '@/assets/joyful-selection/products/gift-box.png' +const productImages = { + bluetoothEarbuds: bluetoothEarbudsImage, + miniOven: miniOvenImage, + smartSpeaker: smartSpeakerImage, + giftBox: giftBoxImage +} + +const createProduct = ({ id, name, desc, detail, price, sales, image, categoryId, category, tag = '赠品' }) => ({ + id, + name, + desc, + detail: detail || desc, + price, + originPrice: (Number(price) * 1.25).toFixed(2), + sales, + image, + categoryId, + category, + tag +}) + +export const joyfulCategories = [ + { id: 'recommend', name: '推荐' }, + { id: 'homeLiving', name: '居家生活' }, + { id: 'digitalAppliance', name: '数码家电' }, + { id: 'beautyCare', name: '美妆个护' }, + { id: 'foodDrink', name: '食品饮料' }, + { id: 'motherBaby', name: '母婴玩具' }, + { id: 'fashionBag', name: '服饰鞋包' }, + { id: 'sportsOutdoor', name: '运动户外' } +] + +const categoryNameMap = joyfulCategories.reduce((map, category) => { + map[category.id] = category.name + return map +}, {}) + +const rawProducts = [ + ['cream-oven', '奶油白家用迷你烤箱', '小巧不占地,早餐烘焙好帮手', '129.00', '1.2万件', productImages.miniOven, 'homeLiving'], + ['cotton-bedding', '100%纯棉舒适四件套', '柔软亲肤,安心睡眠', '179.00', '6453件', productImages.miniOven, 'homeLiving'], + ['aroma-gift', '橙意香薰礼盒套装', '淡雅留香,装点居家空间', '59.90', '8321件', productImages.giftBox, 'homeLiving'], + ['desktop-vase', '简约北欧陶瓷花瓶', '清新配色,点亮桌面角落', '39.90', '3180件', productImages.giftBox, 'homeLiving'], + ['earbuds-air2', '小米蓝牙耳机 Air2 SE', '轻盈半入耳,通勤运动都好听', '69.90', '1.2万件', productImages.bluetoothEarbuds, 'digitalAppliance'], + ['smart-speaker-pro', '黑曜智能音箱 Pro', '语音唤醒,沉浸听感', '99.00', '2.1万件', productImages.smartSpeaker, 'digitalAppliance'], + ['electric-toothbrush', '智能声波电动牙刷', '高频洁净,呵护口腔', '129.00', '2.1万件', productImages.bluetoothEarbuds, 'digitalAppliance'], + ['dual-charger', '双口快充充电器 30W', '小巧便携,多设备快充', '69.00', '5632件', productImages.smartSpeaker, 'digitalAppliance'], + ['skin-care-box', '植萃保湿护肤礼盒', '水润修护,清爽不粘腻', '99.90', '4820件', productImages.giftBox, 'beautyCare'], + ['aroma-wash', '香氛洗护旅行套装', '温和清洁,清新留香', '59.90', '7932件', productImages.giftBox, 'beautyCare'], + ['makeup-mirror', '便携补光化妆镜', '高清镜面,随时补妆', '49.90', '3651件', productImages.smartSpeaker, 'beautyCare'], + ['hand-cream', '滋润护手霜三支装', '细腻滋养,轻柔香气', '39.90', '5280件', productImages.giftBox, 'beautyCare'], + ['orange-gift', '橙意惊喜零食礼盒', '精致包装,送礼更有心意', '59.90', '6324件', productImages.giftBox, 'foodDrink'], + ['coffee-cup', '咖啡随行杯组合', '锁温防漏,醇香随行', '49.90', '3520件', productImages.bluetoothEarbuds, 'foodDrink'], + ['tea-snack', '下午茶点心礼盒', '多种风味,一盒满足', '69.90', '4891件', productImages.giftBox, 'foodDrink'], + ['fruit-drink', '轻享果饮礼盒', '清爽酸甜,聚会常备', '79.90', '2976件', productImages.giftBox, 'foodDrink'], + ['baby-bottle', '安心防摔儿童水杯', '轻巧易握,出门好携带', '39.90', '4250件', productImages.bluetoothEarbuds, 'motherBaby'], + ['toy-blocks', '益智拼搭积木套装', '色彩柔和,陪伴成长', '89.00', '2186件', productImages.giftBox, 'motherBaby'], + ['kids-night-light', '柔光儿童陪伴夜灯', '温和光线,安心入睡', '69.90', '3548件', productImages.smartSpeaker, 'motherBaby'], + ['baby-towel', '纯棉柔软浴巾两件装', '亲肤吸水,日常必备', '59.90', '2761件', productImages.miniOven, 'motherBaby'], + ['laptop-backpack', '大容量双肩电脑背包', '分区收纳,通勤出行轻松装', '149.00', '1.6万件', productImages.giftBox, 'fashionBag'], + ['mini-bag', '轻巧通勤斜挎小包', '简洁百搭,日常实用', '79.90', '5321件', productImages.giftBox, 'fashionBag'], + ['silk-scarf', '柔软撞色丝巾礼盒', '细腻亲肤,点亮穿搭', '69.90', '2680件', productImages.giftBox, 'fashionBag'], + ['canvas-tote', '简约帆布托特包', '大容量开口,随手能装', '49.90', '6412件', productImages.giftBox, 'fashionBag'], + ['sport-bottle', '运动便携保温水杯', '长效锁温,户外随行', '49.90', '7342件', productImages.bluetoothEarbuds, 'sportsOutdoor'], + ['neck-massager', '筋膜放松按摩仪 Mini', '轻巧便携,舒缓酸胀', '99.00', '3921件', productImages.smartSpeaker, 'sportsOutdoor'], + ['camping-light', '户外便携露营灯', '多档照明,夜晚更安心', '79.00', '2568件', productImages.smartSpeaker, 'sportsOutdoor'], + ['fitness-band', '弹力健身拉力带套装', '居家训练,轻松塑形', '29.90', '4396件', productImages.miniOven, 'sportsOutdoor'] +] + +export const joyfulProductList = rawProducts.map(([id, name, desc, price, sales, image, categoryId]) => + createProduct({ + id, + name, + desc, + price, + sales, + image, + categoryId, + category: categoryNameMap[categoryId] + }) +) + export const joyfulProducts = [ { id: 'bluetooth-earbuds', @@ -47,7 +128,8 @@ export const joyfulProducts = [ category: '食品饮料', tag: '品质精选', image: giftBoxImage - } + }, + ...joyfulProductList ] export const getJoyfulProduct = id => joyfulProducts.find(item => item.id === id) || joyfulProducts[0] diff --git a/supplied-h5/src/view/joyful-selection/product-detail/index.vue b/supplied-h5/src/view/joyful-selection/product-detail/index.vue index 9b28095..0d01ad5 100644 --- a/supplied-h5/src/view/joyful-selection/product-detail/index.vue +++ b/supplied-h5/src/view/joyful-selection/product-detail/index.vue @@ -59,13 +59,24 @@ - + + +
+ 购物车 + +
+ +
@@ -73,14 +84,17 @@ import { mapActions, mapState } from 'pinia' import { useCartStore } from '@/store/cart' import { getJoyfulProduct } from '../product-data' -import JoyfulSkuPopup from '../components/JoyfulSkuPopup.vue' +import JoyfulSkuPopup from '../products/components/JoyfulSkuPopup.vue' +import JoyfulCartPanel from '../cart/components/JoyfulCartPanel.vue' export default { name: 'JoyfulSelectionProductDetail', components: { - JoyfulSkuPopup + JoyfulSkuPopup, + JoyfulCartPanel }, data: () => ({ + showCartPopup: false, count: 1, features: [ { icon: 'music-o', title: '舒适半入耳设计', desc: '长时间佩戴更舒适' }, @@ -101,6 +115,20 @@ export default { }, methods: { ...mapActions(useCartStore, ['loadCart']), + openCartPopup() { + this.loadCart() + this.showCartPopup = true + this.$nextTick(() => { + if (this.$refs.cartPanel) { + this.$refs.cartPanel.selectAllItems() + } + }) + }, + goCheckout(items) { + sessionStorage.setItem('joyful-selection-checkout-items', JSON.stringify(items)) + this.showCartPopup = false + this.$router.push({ path: '/joyful-selection/checkout', query: { source: 'cart' } }) + }, openSku(mode) { this.$refs.skuPopup.open(this.product, mode) } @@ -357,4 +385,39 @@ export default { -webkit-box-orient: vertical; -webkit-line-clamp: 2; } + +.cart-popup { + display: flex; + height: 76vh; + flex-direction: column; + overflow: hidden; +} + +.cart-popup-head { + display: flex; + height: 48px; + flex: none; + align-items: center; + justify-content: center; + border-bottom: 1px solid #f2f2f2; + background: #fff; +} + +.cart-popup-head b { + color: #222; + font-size: 16px; + font-weight: 700; +} + +.cart-popup-head .van-icon { + position: absolute; + right: 16px; + color: #999; + font-size: 20px; +} + +.cart-popup-panel { + flex: 1; + min-height: 0; +} diff --git a/supplied-h5/src/view/joyful-selection/components/JoyfulSkuPopup.vue b/supplied-h5/src/view/joyful-selection/products/components/JoyfulSkuPopup.vue similarity index 62% rename from supplied-h5/src/view/joyful-selection/components/JoyfulSkuPopup.vue rename to supplied-h5/src/view/joyful-selection/products/components/JoyfulSkuPopup.vue index b85b859..e7870d4 100644 --- a/supplied-h5/src/view/joyful-selection/components/JoyfulSkuPopup.vue +++ b/supplied-h5/src/view/joyful-selection/products/components/JoyfulSkuPopup.vue @@ -1,13 +1,15 @@ +