feat: 积分商城-供应商-对账-发票3

This commit is contained in:
2026-09-08 16:41:48 +08:00
parent 3abe4ce9c9
commit f42ea5b270
47 changed files with 1211 additions and 285 deletions
+3 -3
View File
@@ -14,7 +14,7 @@
<van-notice-bar class="notice" left-icon="volume-o" :text="shop.notice" />
<van-search v-model="keyword" placeholder="搜索商品" shape="round" />
<van-tabs v-model="activeCategory" sticky :color="shop.theme" title-active-color="var(--theme)">
<van-tabs v-model:active="activeCategory" sticky :color="shop.theme" title-active-color="var(--theme)">
<van-tab v-for="category in categories" :key="category" :title="category" />
</van-tabs>
@@ -44,7 +44,7 @@
<span class="selected">已选 {{ totalCount }} 件</span>
</van-submit-bar>
<van-popup v-model="checkoutVisible" round position="bottom" :style="{ minHeight: '68%' }" closeable>
<van-popup v-model:show="checkoutVisible" round position="bottom" :style="{ minHeight: '68%' }" closeable>
<section class="checkout">
<h2>确认订单</h2>
<van-contact-card type="add" name="商城收货人" tel="138****8888" @click="Toast('当前使用默认收货地址')" />
@@ -66,7 +66,7 @@
</section>
</van-popup>
<van-popup v-model="successVisible" round closeable class="result-popup">
<van-popup v-model:show="successVisible" round closeable class="result-popup">
<van-icon name="checked" color="#23b65d" size="62" />
<h2>订单提交成功</h2>
<p>订单号:{{ submittedOrderId }}</p>
+3 -12
View File
@@ -1,20 +1,11 @@
import Vue from 'vue'
import { createApp } from 'vue'
import Vant from 'vant'
import { Skeleton } from 'vant'
import { createPinia, PiniaVuePlugin } from 'pinia'
import { createPinia } from 'pinia'
import 'vant/lib/index.css'
import App from './App.vue'
import router from './router'
Vue.use(Vant)
Vue.use(Skeleton)
Vue.use(PiniaVuePlugin)
Vue.config.productionTip = false
const pinia = createPinia()
new Vue({
router,
pinia,
render: h => h(App)
}).$mount('#app')
createApp(App).use(pinia).use(router).use(Vant).mount('#app')
+4 -6
View File
@@ -1,5 +1,4 @@
import Vue from 'vue'
import Router from 'vue-router'
import { createRouter, createWebHashHistory } from 'vue-router'
import SupplierHome from '@/view/index.vue'
import JoyfulSelectionLayout from '@/view/joyful-selection/layout.vue'
import JoyfulSelectionHome from '@/view/joyful-selection/index.vue'
@@ -29,16 +28,15 @@ import HappyShopping from '@/view/happy-shopping/index.vue'
import FreshFruit from '@/view/fresh-fruit/index.vue'
import CuteSelection from '@/view/cute-selection/index.vue'
Vue.use(Router)
export default new Router({
export default createRouter({
history: createWebHashHistory(),
routes: [
{ path: '/', component: SupplierHome },
{
path: '/joyful-selection',
component: JoyfulSelectionLayout,
children: [
{ path: '', redirect: 'home' },
{ path: '', redirect: '/joyful-selection/home' },
{ path: 'home', component: JoyfulSelectionHome },
{ path: 'products', component: JoyfulSelectionProductList },
{ path: 'product-detail', component: JoyfulSelectionProductDetail },
+7
View File
@@ -20,6 +20,7 @@ const saveUser = data => {
export const useUserStore = defineStore('joyfulSelectionUser', {
state: () => ({
userId: '',
nickname: '',
supplierIdentification: '',
supplierId: '',
supplierName: '',
@@ -34,6 +35,7 @@ export const useUserStore = defineStore('joyfulSelectionUser', {
loadUser() {
const data = readUser()
this.userId = data.userId || ''
this.nickname = data.nickname || ''
const supplierIdentification = DEFAULT_SUPPLIER_IDENTIFICATION || data.supplierIdentification || ''
const supplierChanged = Boolean(data.supplierIdentification && supplierIdentification !== data.supplierIdentification)
@@ -46,6 +48,7 @@ export const useUserStore = defineStore('joyfulSelectionUser', {
persistUser() {
saveUser({
userId: this.userId,
nickname: this.nickname,
supplierIdentification: this.supplierIdentification,
supplierId: this.supplierId,
supplierName: this.supplierName,
@@ -60,6 +63,7 @@ export const useUserStore = defineStore('joyfulSelectionUser', {
const keyword = query.keyword || new URLSearchParams(window.location.search).get('keyword') || ''
let nextUserId = query.userId || ''
let nextNickname
if (keyword) {
const sessionKeyword = String(keyword).replace(/ /g, '+')
@@ -70,12 +74,15 @@ export const useUserStore = defineStore('joyfulSelectionUser', {
})
const data = await postFunction('supplier-session', { keyword: sessionKeyword })
nextUserId = data?.userId || ''
nextNickname = data?.userInfo?.nickname || ''
}
if (nextUserId && nextUserId !== this.userId) {
this.userId = nextUserId
this.nickname = ''
this.pointsBalance = 0
}
if (nextNickname !== undefined) this.nickname = nextNickname
if (!this.supplierIdentification) {
this.supplierIdentification = DEFAULT_SUPPLIER_IDENTIFICATION
}
@@ -87,7 +87,7 @@
<button v-else type="button" class="primary" @click="contactService">联系客服</button>
</footer>
<van-popup v-model="showLogisticsPopup" round position="bottom">
<van-popup v-model:show="showLogisticsPopup" round position="bottom">
<section class="logistics-popup">
<h3>填写物流单号</h3>
<van-field v-model="logisticsCompany" label="快递公司" placeholder="请输入快递公司" />
@@ -96,7 +96,7 @@
</section>
<van-button v-show="!loading" class="submit-button" block :loading="submitting" @click="submitReturn">提交申请</van-button>
<van-popup v-model="showReasonPopup" round position="bottom">
<van-popup v-model:show="showReasonPopup" round position="bottom">
<section class="reason-popup">
<h3>请选择换货原因</h3>
<van-radio-group v-model="selectedReason">
@@ -116,7 +116,7 @@
</van-radio-group>
</section>
</van-popup>
<van-popup v-model="showExchangeGoodsPopup" round position="bottom" :style="{ height: '80vh' }">
<van-popup v-model:show="showExchangeGoodsPopup" round position="bottom" :style="{ height: '80vh' }">
<section class="exchange-popup">
<h3>选择换货商品</h3>
<p>仅可选择价格为 ¥{{ originalProductPrice }} 的商品</p>
@@ -3,7 +3,7 @@
<van-nav-bar title="退款/售后" left-arrow @click-left="$router.replace('/joyful-selection/profile')" />
<van-pull-refresh v-model="refreshing" class="after-sale-list" @refresh="onRefresh">
<van-tabs v-model="activeTab" color="#ff5b20">
<van-tabs v-model:active="activeTab" color="#ff5b20">
<van-tab title="处理中" name="processing" />
<van-tab title="历史" name="history" />
</van-tabs>
@@ -76,7 +76,7 @@
</section>
<van-button v-show="!loading" class="submit-button" block :loading="submitting" @click="submitReturn">提交申请</van-button>
<van-popup v-model="showReasonPopup" round position="bottom">
<van-popup v-model:show="showReasonPopup" round position="bottom">
<section class="reason-popup">
<h3>请选择退货原因</h3>
<van-radio-group v-model="selectedReason">
@@ -18,10 +18,10 @@
class="cart-item"
>
<van-checkbox
:value="isItemChecked(item)"
:model-value="isItemChecked(item)"
class="item-check"
checked-color="#ff5b20"
@input="toggleItem(item, $event)"
@update:model-value="toggleItem(item, $event)"
/>
<van-image class="item-thumb" :src="item.image" fit="cover" />
<div class="item-info">
@@ -52,10 +52,10 @@
@submit="handleCheckout"
>
<van-checkbox
:value="isAllChecked"
:model-value="isAllChecked"
:indeterminate="isPartChecked"
checked-color="#ff5b20"
@input="toggleAll"
@update:model-value="toggleAll"
>全选</van-checkbox>
</van-submit-bar>
</section>
@@ -7,10 +7,10 @@
<van-empty v-if="!items.length" description="购物车还是空的" />
<article v-for="item in items" :key="item.cartId" class="edit-item">
<van-checkbox
:value="isItemChecked(item)"
:model-value="isItemChecked(item)"
class="item-check"
checked-color="#ff5b20"
@input="toggleItem(item, $event)"
@update:model-value="toggleItem(item, $event)"
/>
<van-image class="item-thumb" :src="item.image" fit="cover" />
<div class="item-info">
@@ -26,10 +26,10 @@
</section>
<van-submit-bar class="edit-submit" button-text="删除" @submit="remove">
<van-checkbox
:value="isAllChecked"
:model-value="isAllChecked"
:indeterminate="isPartChecked"
checked-color="#ff5b20"
@input="toggleAll"
@update:model-value="toggleAll"
>全选</van-checkbox>
</van-submit-bar>
</main>
@@ -91,7 +91,7 @@
</button>
</footer>
<van-popup v-model="showExchangeShipPopup" round position="bottom">
<van-popup v-model:show="showExchangeShipPopup" round position="bottom">
<section class="action-popup">
<h3>填写换货发货信息</h3>
<van-field v-model="exchangeShipForm.logisticsCompany" label="快递公司" placeholder="请输入快递公司" />
@@ -3,7 +3,7 @@
<van-nav-bar title="商家处理台" left-arrow @click-left="$router.back()" />
<van-pull-refresh v-model="refreshing" class="merchant-refresh" @refresh="onRefresh">
<van-tabs v-model="activeTab" sticky offset-top="46" color="#ff5b20" @change="loadCurrentTab">
<van-tabs v-model:active="activeTab" sticky offset-top="46" color="#ff5b20" @change="loadCurrentTab">
<van-tab title="待发货" name="ship" :badge="tabBadge('ship')">
<section class="list-panel">
<button v-if="orderItems.length" type="button" class="batch-ship-button" @click="quickShipAll">一键发货</button>
@@ -161,7 +161,7 @@
</van-tabs>
</van-pull-refresh>
<van-popup v-model="showShipPopup" round position="bottom">
<van-popup v-model:show="showShipPopup" round position="bottom">
<section class="action-popup">
<h3>填写发货信息</h3>
<van-field v-model="shipForm.crrgBsnNm" label="快递公司" placeholder="请输入快递公司" />
@@ -170,7 +170,7 @@
</section>
</van-popup>
<van-popup v-model="showExchangeShipPopup" round position="bottom">
<van-popup v-model:show="showExchangeShipPopup" round position="bottom">
<section class="action-popup">
<h3>填写换货发货信息</h3>
<van-field v-model="exchangeShipForm.logisticsCompany" label="快递公司" placeholder="请输入快递公司" />
@@ -43,7 +43,7 @@
立即支付 ¥{{ amountText }}
</van-button>
<van-popup v-model="showConfirm" class="pay-popup" round position="bottom">
<van-popup v-model:show="showConfirm" class="pay-popup" round position="bottom">
<article class="pay-panel">
<header>
<van-icon name="cross" @click="showConfirm = false" />
@@ -59,16 +59,16 @@
</div>
</section>
<van-goods-action>
<van-goods-action-icon icon="chat-o" text="客服" dot />
<van-goods-action-icon icon="cart-o" text="购物车" :badge="cartBadge" @click="openCartPopup" />
<van-goods-action-icon icon="star" text="已收藏" color="#ff5000" />
<van-goods-action-button type="warning" text="加入购物车" @click="openSku('cart')" />
<van-goods-action-button type="danger" text="立即购买" @click="openSku('buy')" />
</van-goods-action>
<van-action-bar>
<van-action-bar-icon icon="chat-o" text="客服" dot />
<van-action-bar-icon icon="cart-o" text="购物车" :badge="cartBadge" @click="openCartPopup" />
<van-action-bar-icon icon="star" text="已收藏" color="#ff5000" />
<van-action-bar-button type="warning" text="加入购物车" @click="openSku('cart')" />
<van-action-bar-button type="danger" text="立即购买" @click="openSku('buy')" />
</van-action-bar>
<joyful-sku-popup ref="skuPopup" @add-cart="loadCart" />
<van-popup v-model="showCartPopup" class="cart-popup" position="bottom" round>
<van-popup v-model:show="showCartPopup" class="cart-popup" position="bottom" round>
<header class="cart-popup-head">
<b>购物车</b>
<van-icon name="cross" @click="showCartPopup = false" />
@@ -251,7 +251,7 @@ export default {
}
.product-info {
margin-top: -4px;
margin-top: 12px;
padding: 18px 16px 16px;
}
@@ -1,26 +1,70 @@
<template>
<van-sku
:key="skuKey"
v-model="show"
<van-popup
v-model:show="show"
:class="`sku-popup--${mode}`"
:sku="sku"
:goods="skuGoods"
:goods-id="currentGoods.id"
:initial-sku="initialSku"
:hide-stock="sku.hide_stock"
:show-stepper="false"
:show-add-cart-btn="mode !== 'buy'"
:show-buy-btn="true"
:preview-on-click-image="true"
add-cart-text="加入购物车"
buy-text="立即购买"
@add-cart="onAddCartClicked"
@buy-clicked="onBuyClicked"
/>
class="van-sku-container"
position="bottom"
round
closeable
safe-area-inset-bottom
>
<div class="sku-content">
<div class="van-sku-header">
<div class="van-sku-header__goods-info">
<div class="van-sku__goods-price">
<span class="van-sku__price-symbol">¥</span>
<span class="van-sku__price-num">{{ sku.price }}</span>
</div>
<div class="van-sku__goods-name">{{ skuGoods.title }}</div>
<div class="van-sku__stock">库存 {{ sku.stock_num }} 件</div>
</div>
</div>
<van-cell-group class="van-sku-body" :border="false">
<div v-for="group in sku.tree" :key="group.k_s" class="van-sku-row">
<div class="van-sku-row__title">{{ group.k }}</div>
<div class="sku-options" :class="{ 'sku-options--colors': group.k_s === 's1' }">
<van-button
v-for="option in group.v"
:key="option.id"
size="small"
class="van-sku-row__item"
:class="{ 'van-sku-row__item--active': selectedSku[group.k_s] === option.id, 'sku-color-card': group.k_s === 's1' }"
@click="selectedSku[group.k_s] = option.id"
>
<span v-if="group.k_s === 's1'" class="sku-color-card__picture">
<van-image class="sku-color-card__image" :src="option.imgUrl" width="100%" height="100%" fit="cover" />
<van-icon
v-if="option.previewImgUrl"
name="expand-o"
class="sku-color-card__preview"
role="button"
tabindex="0"
aria-label="预览商品图片"
@click.stop="previewImage(option.previewImgUrl)"
@keydown.enter.stop.prevent="previewImage(option.previewImgUrl)"
@keydown.space.stop.prevent="previewImage(option.previewImgUrl)"
/>
</span>
<span :class="{ 'sku-color-card__name': group.k_s === 's1' }">{{ option.name }}</span>
</van-button>
</div>
</div>
<van-cell title="购买数量" class="sku-quantity" center>
<template #right-icon>
<van-stepper v-model="selectedNum" integer :min="1" :max="sku.stock_num" />
</template>
</van-cell>
</van-cell-group>
<div class="sku-actions">
<van-button v-if="mode !== 'buy'" round type="warning" @click="onAddCartClicked(selectionData())">加入购物车</van-button>
<van-button round type="danger" @click="onBuyClicked(selectionData())">立即购买</van-button>
</div>
</div>
</van-popup>
</template>
<script>
import { Toast } from 'vant'
import { ImagePreview, Toast } from 'vant'
import { useCartStore } from '@/store/cart'
const colorOptions = [
@@ -47,7 +91,8 @@ export default {
data: () => ({
show: false,
mode: 'cart',
skuKey: 0,
selectedSku: {},
selectedNum: 1,
currentGoods: emptyGoods
}),
computed: {
@@ -105,9 +150,19 @@ export default {
open(goods, mode = 'cart') {
this.currentGoods = goods
this.mode = mode
this.skuKey += 1
this.selectedSku = { ...this.initialSku }
this.selectedNum = 1
this.show = true
},
previewImage(image) {
if (image) ImagePreview([image])
},
selectionData() {
return {
selectedSkuComb: this.sku.list.find(item => item.s1 === this.selectedSku.s1 && item.s2 === this.selectedSku.s2),
selectedNum: Math.min(this.sku.stock_num, Math.max(1, Math.floor(Number(this.selectedNum) || 1)))
}
},
getCartPayload(data) {
const selectedSku = data.selectedSkuComb || {}
const selectedColor = colorOptions.find(item => item.id === selectedSku.s1) || colorOptions[0]
@@ -153,14 +208,110 @@ export default {
</script>
<style scoped lang="less">
::v-deep .van-sku-container {
.sku-content {
padding: 15px 15px 0;
}
.sku-options .van-sku-row__item.sku-color-card {
width: 100%;
min-width: 0;
overflow: hidden;
padding: 0;
border: 1px solid transparent;
border-radius: 3px;
background: #f6f7f9;
}
.sku-color-card :deep(.van-button__content),
.sku-color-card :deep(.van-button__text) {
display: block;
width: 100%;
}
.sku-color-card__picture {
position: relative;
display: block;
width: 100%;
aspect-ratio: 1 / 1;
overflow: hidden;
line-height: 0;
background: #f1f1f3;
}
.sku-color-card__image {
position: absolute;
inset: 0;
display: block;
}
.sku-color-card__preview {
position: absolute;
top: 3px;
right: 3px;
padding: 2px;
border-radius: 2px;
background: rgba(0, 0, 0, .4);
color: #fff;
font-size: 14px;
}
.sku-color-card__name {
display: block;
padding: 10px 4px;
color: #333;
font-size: 12px;
line-height: 18px;
text-align: center;
}
.sku-color-card.van-sku-row__item--active .sku-color-card__name {
color: #ff5b20;
}
.sku-options,
.sku-actions {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.sku-options.sku-options--colors {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 10px;
}
.sku-options .van-sku-row__item {
height: auto;
min-height: 36px;
padding: 6px 12px;
}
.sku-quantity {
padding: 12px 0;
}
.sku-actions {
padding: 15px 0;
}
.sku-actions .van-button {
flex: 1;
}
.van-sku-container {
max-height: 85vh;
overflow-y: auto;
border-radius: 14px 14px 0 0;
}
.van-sku-container.van-popup--safe-area-inset-bottom {
padding-bottom: env(safe-area-inset-bottom);
}
::v-deep .van-sku-header {
min-height: 96px;
padding: 18px 42px 12px 16px;
padding: 0 30px 15px 0;
}
::v-deep .van-sku-header__img-wrap {
@@ -210,7 +361,7 @@ export default {
}
::v-deep .van-sku-body {
padding: 0 16px;
padding: 0;
}
::v-deep .van-sku-group-container {
@@ -236,7 +387,7 @@ export default {
::v-deep .van-sku-row:not(:first-child) .van-sku-row__item {
height: 31px;
margin: 0 10px 8px 0;
margin: 0;
padding: 0 14px;
border: 0;
border-radius: 4px;
@@ -4,7 +4,7 @@
<main v-else class="orders-page">
<van-nav-bar title="我的订单" left-arrow @click-left="$router.replace('/joyful-selection/profile')" />
<van-tabs
v-model="active"
v-model:active="active"
class="order-tabs"
line-width="18"
line-height="2"
@@ -50,7 +50,7 @@ export default {
this.loadLogs()
this.startListening()
},
beforeDestroy() {
beforeUnmount() {
this.stopListening()
},
methods: {