feat(用户界面): 添加客服功能并优化格口选择界面

- 新增微信客服功能入口及处理逻辑
- 添加不同尺寸格口的SVG图标资源
- 重构格口类型选择为卡片式布局,增加视觉反馈
- 简化取件流程,取消自动清空格口步骤
- 调整页面按钮布局,优化用户体验
This commit is contained in:
dzq 2025-12-20 15:17:15 +08:00
parent 8239ed657f
commit 364cba07b9
6 changed files with 210 additions and 26 deletions

View File

@ -216,32 +216,41 @@ async function handleRetrieveFlow() {
password: String(password)
})
// 4.
// 4.
uni.showToast({
title: '格口已打开',
icon: 'success'
})
//
/*
//
await message.alert({
title: '格口已打开',
msg: '柜子已开,请取物品!如不再使用柜子请点击 “清空” 。',
msg: '柜子已开,请取物品!如不再使用柜子请点击 "清空" 。',
confirmButtonText: '清空',
closeOnClickModal: false
})
// 5.
//
await message.confirm({
title: '确认清空',
msg: '清空后密码将不能再次使用,确认清空?',
closeOnClickModal: false
})
// 6.
//
await resetByPassword({
shopId: props.shopId,
password: String(password)
})
// 7.
//
uni.showToast({
title: '格口已清空',
icon: 'success'
})
*/
} catch (error) {
//
// message.prompt/confirm/alert 'cancel' cancel
@ -265,6 +274,42 @@ async function handleRetrieveFlow() {
}
}
//
const CELL_TYPE_ICON_MAP = {
1: 'box', //
2: 'archive', //
3: 'package', //
4: 'cube' //
} as const
function getCellImg(type: number): string {
switch (type) {
case 1:
return '/static/svg/small-cell.svg'
case 2:
return '/static/svg/medium-cell.svg'
case 3:
return '/static/svg/large-cell.svg'
case 4:
return '/static/svg/extra-large-cell.svg'
default:
return '/static/svg/small-cell.svg'
}
}
//
function handleCellTypeSelect(stat: { type: number; count: number }) {
if (stat.count === 0) {
uni.showToast({
title: '该类型格口暂不可用',
icon: 'none',
duration: 1500
})
return
}
selectedCellType.value = stat.type
}
//
onMounted(() => {
if (props.autoLoad !== false) {
@ -310,16 +355,28 @@ onMounted(() => {
<!-- 格口类型选择区域 -->
<view v-else class="cell-type-selection">
<wd-radio-group v-model="selectedCellType" shape="button" size="large" inline>
<wd-radio
v-for="stat in cellTypeStats"
:key="stat.type"
:value="stat.type"
:disabled="stat.count === 0"
<view class="cell-type-grid">
<view
v-for="stat in cellTypeStats"
:key="stat.type"
class="cell-type-card"
:class="{
'cell-type-card--selected': selectedCellType === stat.type,
'cell-type-card--disabled': stat.count === 0
}"
@click="handleCellTypeSelect(stat)"
>
{{ stat.name }} ({{ stat.count }})
</wd-radio>
</wd-radio-group>
<view class="cell-type-icon">
<image :src="getCellImg(stat.type)" class="product-image">
</image>
</view>
<text class="cell-type-name">{{ stat.name }}</text>
<text class="cell-type-count">剩余{{ stat.count }}个可用</text>
<!-- <view v-if="selectedCellType === stat.type" class="cell-type-selected-indicator">
<wd-icon name="check" size="16px" color="#fff" />
</view> -->
</view>
</view>
</view>
<!-- 操作按钮区域 -->
@ -384,8 +441,83 @@ onMounted(() => {
.cell-type-selection {
margin-bottom: 48rpx;
.wd-radio {
margin-bottom: 16rpx;
.cell-type-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16rpx;
.cell-type-card {
position: relative;
padding: 32rpx 24rpx;
background: #fff;
border: 1px solid #e0e0e0;
border-radius: 16rpx;
text-align: center;
transition: all 0.3s ease;
&:active:not(.cell-type-card--disabled) {
transform: translateY(2px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
&--selected {
border-color: #2979ff;
background: rgba(41, 121, 255, 0.04);
box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.15);
.cell-type-name {
color: #2979ff;
font-weight: 500;
}
.cell-type-count {
color: #2979ff;
}
}
&--disabled {
background: #f9f9f9;
border-color: #f0f0f0;
opacity: 0.6;
.cell-type-name,
.cell-type-count {
color: #ccc;
}
}
.cell-type-icon {
margin-bottom: 16rpx;
}
.cell-type-name {
display: block;
font-size: 28rpx;
font-weight: 400;
color: #333;
margin-bottom: 8rpx;
}
.cell-type-count {
display: block;
font-size: 24rpx;
color: #666;
}
.cell-type-selected-indicator {
position: absolute;
top: -8rpx;
right: -8rpx;
width: 32rpx;
height: 32rpx;
background: #2979ff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2rpx 8rpx rgba(41, 121, 255, 0.3);
}
}
}
}
@ -424,5 +556,11 @@ onMounted(() => {
/* 保留空白,自动换行 */
white-space: pre-wrap;
}
.product-image {
width: 80rpx;
height: 80rpx;
border-radius: 4px;
}
}
</style>

View File

@ -9,7 +9,7 @@ import { generateDynamicCode, getWxUserByOpenid } from '@/api/users'
import { DynamicCodeResponse } from '@/api/users/types'
import { bindWxMpUserByOpenid } from '@/api/ab98'
import { BindWxMpUserByOpenidCommand } from '@/api/ab98/types'
import { useToast } from 'wot-design-uni'
import { useToast, useMessage } from 'wot-design-uni'
definePage({
style: {
@ -43,6 +43,7 @@ const showProfileSetupButton = computed(() => {
const dynamicCodeActionSheet = ref<boolean>(false)
const dynamicCodeData = ref<DynamicCodeResponse | null>(null)
const toast = useToast()
const message = useMessage()
//
const hbLoginPopupVisible = ref<boolean>(false)
@ -111,6 +112,32 @@ const navigateToPage = (pagePath: string, options: { type?: 'navigateTo' | 'swit
}
}
const openWxService = async () => {
try {
//
await message.confirm({
title: '客服咨询',
msg: '确认离开小程序,前往客服中心?',
closeOnClickModal: false
})
wx.openCustomerServiceChat({
extInfo: {
url: 'https://work.weixin.qq.com/kfid/kfce354fbeb3c58be22',
},
corpId: 'ww25c80308cbccc46a',
});
} catch (error) {
//
if (error === 'cancel' || (error as any)?.message?.includes?.('cancel')) {
return
}
console.error('打开客服失败:', error)
toast.show('打开客服失败')
}
}
onMounted(() => {
wxStore.refreshBalance();
});
@ -246,32 +273,35 @@ const handleHbLoginSubmit = async () => {
<wd-icon name="star" size="20px" color="#fff"></wd-icon>
<text>我的柜子</text>
</view>
<view class="button-item" @click="openWxService()">
<wd-icon name="user-talk" size="20px" color="#fff"></wd-icon>
<text>系统客服</text>
</view>
<view v-if="!wxUserDTO?.ab98UserId" class="button-item" @click="handleGenerateDynamicCode">
<wd-icon name="qrcode" size="20px" color="#fff"></wd-icon>
<text>动态码</text>
</view>
<view v-else class="button-placeholder"></view>
<view v-if="!wxUserDTO?.ab98UserId" class="button-item" @click="hbLoginPopupVisible = true">
<wd-icon name="login" size="20px" color="#fff"></wd-icon>
<text>绑定汇邦云</text>
</view>
<view v-else class="button-placeholder"></view>
<!-- <view v-if="wxStore.isCabinetAdmin" class="button-item" @click="navigateToPage('/pages/cabinet/index')">
<wd-icon name="tools" size="20px" color="#fff"></wd-icon>
<text>柜机管理</text>
</view> -->
</view>
<!-- <view class="button-row">
<view v-if="wxStore.isCabinetAdmin" class="button-item" @click="navigateToPage('/pages/approval/list/index')">
<view class="button-row">
<view v-if="!wxUserDTO?.ab98UserId" class="button-item" @click="hbLoginPopupVisible = true">
<wd-icon name="login" size="20px" color="#fff"></wd-icon>
<text>绑定汇邦云</text>
</view>
<!-- <view v-if="wxStore.isCabinetAdmin" class="button-item" @click="navigateToPage('/pages/approval/list/index')">
<wd-icon name="secured" size="20px" color="#fff"></wd-icon>
<text>审批中心</text>
</view>
<view v-if="wxStore.isCabinetAdmin" class="button-item" @click="navigateToPage('/pages/approvalAsset/list/index')">
<wd-icon name="edit-1" size="20px" color="#fff"></wd-icon>
<text>耗材核销</text>
</view>
</view> -->
<view class="button-placeholder"></view>
</view> -->
</view>
</view>
<!-- 动态码弹窗 -->

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256">
<path fill="currentColor"
d="M200 24H56a12 12 0 0 0-12 12v184a12 12 0 0 0 12 12h144a12 12 0 0 0 12-12V36a12 12 0 0 0-12-12m4 196a4 4 0 0 1-4 4H56a4 4 0 0 1-4-4V36a4 4 0 0 1 4-4h144a4 4 0 0 1 4 4v184Zm-64-92a4 4 0 0 1-4 4h-16a4 4 0 0 1 0-8h16a4 4 0 0 1 4 4" />
</svg>

After

Width:  |  Height:  |  Size: 367 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256">
<path fill="currentColor"
d="M200 48H56a12 12 0 0 0-12 12v136a12 12 0 0 0 12 12h144a12 12 0 0 0 12-12V60a12 12 0 0 0-12-12m4 148a4 4 0 0 1-4 4H56a4 4 0 0 1-4-4V60a4 4 0 0 1 4-4h144a4 4 0 0 1 4 4v136Zm-64-68a4 4 0 0 1-4 4h-16a4 4 0 0 1 0-8h16a4 4 0 0 1 4 4" />
</svg>

After

Width:  |  Height:  |  Size: 367 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256">
<path fill="currentColor"
d="M200 72H56a12 12 0 0 0-12 12v88a12 12 0 0 0 12 12h144a12 12 0 0 0 12-12V84a12 12 0 0 0-12-12m4 100a4 4 0 0 1-4 4H56a4 4 0 0 1-4-4V84a4 4 0 0 1 4-4h144a4 4 0 0 1 4 4v88Zm-64-44a4 4 0 0 1-4 4h-16a4 4 0 0 1 0-8h16a4 4 0 0 1 4 4" />
</svg>

After

Width:  |  Height:  |  Size: 365 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256">
<path fill="currentColor"
d="M200 96H56a12 12 0 0 0-12 12v40a12 12 0 0 0 12 12h144a12 12 0 0 0 12-12v-40a12 12 0 0 0-12-12m4 52a4 4 0 0 1-4 4H56a4 4 0 0 1-4-4v-40a4 4 0 0 1 4-4h144a4 4 0 0 1 4 4v40Zm-64-20a4 4 0 0 1-4 4h-16a4 4 0 0 1 0-8h16a4 4 0 0 1 4 4" />
</svg>

After

Width:  |  Height:  |  Size: 366 B