feat: 新增多语言文案、优化导航及工具函数,修复部分业务逻辑

1. 新增多语言资源文件,覆盖文章、预约日期、会员信息、优惠券、表单、购物车、积分商城、分销、AI聊天等多个模块
2. 优化底部导航组件,使用多语言配置替代硬编码文案
3. 重构工具函数,新增从后端数据提取多语言文案的工具方法
4. 修复邀请好友页面的保存提示文案,替换为多语言版本
5. 修复商品SKU组件的提示文案,使用多语言配置
6. 重构AI聊天页面的帮助文档和回复模板,使用多语言配置
7. 优化空状态组件,支持多语言默认文案
8. 修复跳转逻辑,补全参数传递
9. 新增本地开发环境配置
This commit is contained in:
2026-06-25 18:15:31 +08:00
parent ca4e7fd170
commit 2d8846c64c
82 changed files with 3497 additions and 1062 deletions

View File

@@ -5,7 +5,7 @@
:refresher-triggered="refresherTriggered" @refresherrefresh="onRefresh">
<block v-if="hasData">
<view class="cart-header" v-if="cartData.length">
<view class="num-wrap">共{{ cartData[0].cartList.length }}种商品</view>
<view class="num-wrap">{{ $lang('goods.cart.totalKinds', { count: cartData[0].cartList.length }) }}</view>
<view class="cart-action" @click="changeAction">
{{ isAction ? $lang('complete') : $lang('edit') }}
</view>
@@ -13,11 +13,11 @@
<view class="cart-wrap" v-for="(siteItem, siteIndex) in cartData" :key="siteIndex">
<view class="coupon-use-tips" v-if="discount.coupon_info">
<view>
<text class="title color-base-text">优惠券</text>
<text class="desc">领券结算最高可减{{ discount.coupon_info.coupon_money | moneyFormat }}元</text>
<text class="title color-base-text">{{ $lang('goods.cart.coupon') }}</text>
<text class="desc">{{ $lang('goods.cart.couponMaxDiscount', { money: discount.coupon_info.coupon_money | moneyFormat }) }}</text>
</view>
<view class="color-base-text" @click="$refs.couponPopup.open()">
点击{{ discount.coupon_info.receive_type == 'wait' ? '领取' : '查看' }}
{{ discount.coupon_info.receive_type == 'wait' ? $lang('goods.cart.clickToReceive') : $lang('goods.cart.clickToView') }}
<text class="iconfont icon-right"></text>
</view>
</view>
@@ -120,15 +120,14 @@
@limit="goodsLimit($event, { siteIndex, cartIndex })" />
</view>
<view class="discount-wrap" v-if="manjian && manjian['sku_' + item.sku_id]">
<text class="discount-tag">满减</text>
<scroll-view scroll-x="true" class="scroll-view">
<block v-for="(mitem, key) in manjian['sku_' + item.sku_id]" :key="key">
<text v-if="mitem.discount_money">{{ Number(mitem.limit) }}减{{
mitem.discount_money }}</text>
<text class="interval" v-if="mitem.discount_money"></text>
</block>
</scroll-view>
</view>
<text class="discount-tag">{{ $lang('goods.cart.fullReduction') }}</text>
<scroll-view scroll-x="true" class="scroll-view">
<block v-for="(mitem, key) in manjian['sku_' + item.sku_id]" :key="key">
<text v-if="mitem.discount_money">{{ $lang('goods.cart.fullReductionItem', { limit: Number(mitem.limit), discount: mitem.discount_money }) }}</text>
<text class="interval" v-if="mitem.discount_money"></text>
</block>
</scroll-view>
</view>
</view>
</view>
<view class="item-del color-base-bg" :class="{ show: item.edit }"
@@ -140,9 +139,9 @@
<view class="cart-wrap invalid" v-if="invalidGoods.length">
<view class="cart-header">
<view class="num-wrap">
<text class="font-size-base">失效商品{{ invalidGoods.length }}件</text>
<text class="font-size-base">{{ $lang('goods.cart.invalidGoods', { count: invalidGoods.length }) }}</text>
</view>
<view class="cart-action color-base-text" @click="clearInvalidGoods">清空</view>
<view class="cart-action color-base-text" @click="clearInvalidGoods">{{ $lang('goods.cart.clear') }}</view>
</view>
<block v-for="(goodsItem, goodsIndex) in invalidGoods" :key="goodsIndex">
<view class="cart-goods invalid-goods">
@@ -189,7 +188,7 @@
</template>
</text>
</view>
<text class="invalid-mark">已失效</text>
<text class="invalid-mark">{{ $lang('goods.cart.invalid') }}</text>
</view>
</view>
</view>
@@ -199,7 +198,7 @@
</block>
<block v-else>
<view class="cart-empty">
<ns-empty text="购物车为空" subText="赶紧去逛逛, 购买心仪的商品吧" :isIndex="Boolean(storeToken)"
<ns-empty :text="$lang('goods.cart.cartEmpty')" :subText="$lang('goods.cart.cartEmptySubText')" :isIndex="Boolean(storeToken)"
:emptyBtn="{ text: $lang('toGoodsCategoryPage'), url: '/pages_goods/category' }"></ns-empty>
<button type="primary" size="mini" class="button mini" v-if="!storeToken" @click="toLogin">{{
$lang('toLogin')
@@ -218,26 +217,26 @@
<uni-popup ref="discountPopup" custom-class="uni-popup-discount" type="bottom">
<view class="discount-popup popup" v-if="Object.keys(discount).length">
<view class="popup-header">
<text class="tit">优惠明细</text>
<text class="tit">{{ $lang('goods.cart.discountDetail') }}</text>
<text class="iconfont icon-close" @click="toggleDiscountPopup"></text>
</view>
<view class="popup-body" :class="{ 'safe-area': isIphoneX }" @click="toggleDiscountPopup">
<view class="detail-item">
<view class="title">商品总额</view>
<view class="money price-font">¥{{ discount.goods_money | moneyFormat }}</view>
<view class="title">{{ $lang('goods.cart.goodsTotal') }}</view>
<view class="money price-font">{{ $lang('common.currencySymbol') }}{{ discount.goods_money | moneyFormat }}</view>
</view>
<view class="detail-item" v-if="discount.coupon_money > 0">
<view class="title">优惠券</view>
<view class="money price-font reduce">-¥{{ discount.coupon_money | moneyFormat }}</view>
<view class="title">{{ $lang('goods.cart.coupon') }}</view>
<view class="money price-font reduce">-{{ $lang('common.currencySymbol') }}{{ discount.coupon_money | moneyFormat }}</view>
</view>
<view class="detail-item" v-if="discount.promotion_money > 0">
<view class="title">满减</view>
<view class="money reduce price-font">-¥{{ discount.promotion_money | moneyFormat }}
<view class="title">{{ $lang('goods.cart.fullReduction') }}</view>
<view class="money reduce price-font">-{{ $lang('common.currencySymbol') }}{{ discount.promotion_money | moneyFormat }}
</view>
</view>
<view class="detail-item total">
<view class="title">合计</view>
<view class="money price-font ">¥{{ discount.order_money | moneyFormat }}</view>
<view class="title">{{ $lang('total') }}</view>
<view class="money price-font ">{{ $lang('common.currencySymbol') }}{{ discount.order_money | moneyFormat }}</view>
</view>
</view>
<view :style="{ height: tabBarHeight }"></view>
@@ -247,7 +246,7 @@
<uni-popup ref="couponPopup" custom-class="uni-popup-discount" type="bottom" v-if="discount.coupon_info">
<view class="coupon-popup popup">
<view class="popup-header">
<text class="tit">优惠券</text>
<text class="tit">{{ $lang('goods.cart.coupon') }}</text>
<text class="iconfont icon-close" @click="$refs.couponPopup.close()"></text>
</view>
<view class="popup-body" :class="{ 'safe-area': isIphoneX }" @click="$refs.couponPopup.close()">
@@ -264,14 +263,14 @@
</template>
<template v-else-if="discount.coupon_info.type == 'discount'">
<text class="money">{{ parseFloat(discount.coupon_info.discount) }}</text>
<text class="unit">折</text>
<text class="unit">{{ $lang('goods.cart.discountLabel') }}</text>
</template>
<view class="at-least">
<template v-if="discount.coupon_info.at_least > 0">
满{{ discount.coupon_info.at_least }}可用
{{ $lang('goods.cart.minSpend', { amount: discount.coupon_info.at_least }) }}
</template>
<template v-else>
无门槛
{{ $lang('goods.cart.noThreshold') }}
</template>
</view>
</view>
@@ -281,23 +280,23 @@
<view
v-if="discount.coupon_info.type == 'discount' && discount.coupon_info.discount_limit > 0"
class="limit">
最多可抵¥{{ discount.coupon_info.discount_limit }}
{{ $lang('goods.cart.maxDiscount', { symbol: $lang('common.currencySymbol'), limit: discount.coupon_info.discount_limit }) }}
</view>
<view class="time font-size-goods-tag"
v-if="discount.coupon_info.validity_type == 0">
有效期:{{ $util.timeStampTurnTime(discount.coupon_info.end_time) }}
{{ $lang('goods.cart.validityPeriod') }}{{ $util.timeStampTurnTime(discount.coupon_info.end_time) }}
</view>
<view class="time font-size-goods-tag"
v-else-if="discount.coupon_info.validity_type == 1">
有效期:领取之日起{{ discount.coupon_info.fixed_term }}天内有效
{{ $lang('goods.cart.validityPeriod') }}{{ $lang('goods.cart.validFromReceive', { days: discount.coupon_info.fixed_term }) }}
</view>
<view class="time font-size-goods-tag" v-else>有效期:长期有效</view>
<view class="time font-size-goods-tag" v-else>{{ $lang('goods.cart.validityPeriod') }}{{ $lang('goods.cart.longTermValid') }}</view>
</view>
<button type="primary" v-if="discount.coupon_info.receive_type != 'wait'"
disabled>已领取</button>
disabled>{{ $lang('goods.cart.received') }}</button>
<button type="primary" v-else
@click.stop="receiveCoupon(discount.coupon_info.coupon_type_id)">领取</button>
@click.stop="receiveCoupon(discount.coupon_info.coupon_type_id)">{{ $lang('goods.cart.receive') }}</button>
</view>
</view>
</view>
@@ -329,7 +328,7 @@
</block>
</view>
<view class="detail" @click="toggleDiscountPopup" v-if="Object.keys(discount).length">
优惠明细
{{ $lang('goods.cart.discountDetail') }}
<text class="iconfont icon-unfold" :class="{ open: !discountPopupShow }"></text>
</view>
</view>
@@ -338,8 +337,7 @@
</view>
<view class="action-btn" v-else>
<button type="primary" size="mini" class="mini" @click="settlement" v-if="totalCount != 0">
{{ discount.coupon_info && discount.coupon_info.receive_type == 'wait' ? '领券' : '立即' }}结算({{
totalCount }})
{{ discount.coupon_info && discount.coupon_info.receive_type == 'wait' ? $lang('goods.cart.receiveCouponSettle', { count: totalCount }) : $lang('goods.cart.settleImmediately', { count: totalCount }) }}
</button>
<button type="primary" size="mini" class="mini" @click="settlement" disabled v-else>{{
$lang('settlement') }}({{

View File

@@ -14,13 +14,13 @@
<view class="price-info">
<view class="icon-box"><text class="iconfont icon-tutechan"></text></view>
<view class="price-box">
<view class="promotion-text">限时折扣</view>
<view class="sale-num" v-if="goodsSkuDetail.sale_show">已售{{ goodsSkuDetail.sale_num }}{{ goodsSkuDetail.unit }}</view>
<view class="promotion-text">{{ $lang('limitedTimeDiscount') }}</view>
<view class="sale-num" v-if="goodsSkuDetail.sale_show">{{ $lang('sold') }}{{ goodsSkuDetail.sale_num }}{{ goodsSkuDetail.unit }}</view>
</view>
</view>
<view class="countdown">
<view class="txt">距结束仅剩</view>
<view class="txt">{{ $lang('countdownEndsIn') }}</view>
<view class="clockrun">
<uni-count-down
:day="goodsSkuDetail.discountTimeMachine.d"
@@ -52,7 +52,7 @@
<image :src="$util.img('public/uniapp/goods/member_vip.png')" mode="aspectFit" show-menu-by-longpress/>
</view>
<view class="member-price-wrap" v-if="!goodsSkuDetail.market_price_show">
<text class="unit price-font">原价</text>
<text class="unit price-font">{{ $lang('originalPrice') }}</text>
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
<text class="money price-font">{{ goodsSkuDetail.price }}</text>
</view>
@@ -117,7 +117,7 @@
<view class="item">
<view>One {{$lang('commissiontext')}}</view>
<view class="price-color">
<text class="unit">¥</text>
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
<text class="money">{{ parseFloat(goodsSkuDetail.fenxiao_detail.commission_money).toFixed(2).split('.')[0] }}</text>
<text class="unit">.{{ parseFloat(goodsSkuDetail.fenxiao_detail.commission_money).toFixed(2).split('.')[1] }}</text>
</view>
@@ -217,7 +217,7 @@
<view class="group-wrap" @click="openBundlingPopup()">
<view class="goods-cell" @click="openBundlingPopup()">
<view class="box">
<text class="tit">组合套餐</text>
<text class="tit">{{ $lang('comboPackage') }}</text>
<text>{{ bundling[0].bl_name }}</text>
</view>
<text class="iconfont icon-right"></text>
@@ -257,7 +257,7 @@
<uni-popup ref="bundlingPopup" type="bottom">
<view class="bundling-popup-layer popup-layer">
<view class="head-wrap" @click="closeBundlingPopup()">
<text>组合套餐</text>
<text>{{ $lang('comboPackage') }}</text>
<text class="iconfont icon-close"></text>
</view>
<scroll-view scroll-y class="bundling-body">
@@ -297,10 +297,10 @@
</view>
</scroll-view>
<view class="bundling-price-wrap">
<text class="label">套餐价</text>
<text class="label">{{ $lang('comboPrice') }}</text>
<text class="unit price-color">{{ $lang('common.currencySymbol') }}</text>
<text class="price price-color">{{ item.bl_price }}</text>
<button type="primary" size="mini" class="mini" @click="toComoDetail(item.bl_id)">立即购买</button>
<button type="primary" size="mini" class="mini" @click="toComoDetail(item.bl_id)">{{ $lang('buynow') }}</button>
</view>
</view>
</block>
@@ -316,7 +316,7 @@
<uni-popup ref="couponPopup" type="bottom">
<view class="goods-coupon-popup-layer popup-layer">
<view class="head-wrap" @click="closeCouponPopup()">
<text>优惠券</text>
<text>{{ $lang('coupons') }}</text>
<text class="iconfont icon-close"></text>
</view>
<scroll-view class="coupon-body" scroll-y>
@@ -331,33 +331,33 @@
</template>
<template v-else-if="item.type == 'discount'">
<text class="money">{{ parseFloat(item.discount) }}</text>
<text class="unit">折</text>
<text class="unit">{{ $lang('discountOff') }}</text>
</template>
<view class="at-least">
<template v-if="item.at_least > 0">
满{{ item.at_least }}可用
{{ $lang('minSpendAvailable', { amount: item.at_least }) }}
</template>
<template v-else>
无门槛
{{ $lang('noThreshold') }}
</template>
</view>
</view>
</view>
<view class="desc-wrap">
<view class="coupon-name">{{ item.coupon_name }}</view>
<view v-if="item.type == 'discount' && item.discount_limit > 0" class="limit">最多可抵¥{{ item.discount_limit }}</view>
<view class="time font-size-goods-tag" v-if="item.validity_type == 0">有效期:{{ $util.timeStampTurnTime(item.end_time) }}</view>
<view class="time font-size-goods-tag" v-else-if="item.validity_type == 1">有效期:领取之日起{{ item.fixed_term }}天内有效</view>
<view class="time font-size-goods-tag" v-else>有效期:长期有效</view>
<view v-if="item.type == 'discount' && item.discount_limit > 0" class="limit">{{ $lang('maxDiscount', { symbol: $lang('common.currencySymbol'), amount: item.discount_limit }) }}</view>
<view class="time font-size-goods-tag" v-if="item.validity_type == 0">{{ $lang('validUntilDate', { date: $util.timeStampTurnTime(item.end_time) }) }}</view>
<view class="time font-size-goods-tag" v-else-if="item.validity_type == 1">{{ $lang('validForDays', { days: item.fixed_term }) }}</view>
<view class="time font-size-goods-tag" v-else>{{ $lang('validPermanent') }}</view>
</view>
<button type="primary" v-if="item.useState == 2" disabled>已抢光</button>
<button type="primary" v-else-if="item.useState == 1" disabled>已领取</button>
<button type="primary" v-else @click="receiveCoupon(item)">领取</button>
<button type="primary" v-if="item.useState == 2" disabled>{{ $lang('couponSoldOut') }}</button>
<button type="primary" v-else-if="item.useState == 1" disabled>{{ $lang('couponClaimed') }}</button>
<button type="primary" v-else @click="receiveCoupon(item)">{{ $lang('couponReceive') }}</button>
</view>
</view>
</scroll-view>
<view class="button-box"><button type="primary" @click="closeCouponPopup()">确定</button></view>
<view class="button-box"><button type="primary" @click="closeCouponPopup()">{{ $lang('confirm') }}</button></view>
</view>
</uni-popup>
</view>
@@ -367,24 +367,24 @@
<uni-popup ref="manjianPopup" type="bottom">
<view class="manjian-popup-layer popup-layer">
<view class="head-wrap" @click="closeManjianPopup()">
<text>促销</text>
<text>{{ $lang('promotion') }}</text>
<text class="iconfont icon-close"></text>
</view>
<scroll-view scroll-y class="manjian-body">
<view class="item" v-if="manjian.manjian != undefined" style="display: flex;">
<view class="free-tip color-base-text color-base-border">满减</view>
<view class="free-tip color-base-text color-base-border">{{ $lang('fullReduction') }}</view>
<text class="font-size-base">{{ manjian.manjian }}</text>
</view>
<view class="item" v-if="manjian.mansong != undefined">
<text class="free-tip color-base-text color-base-border">满送</text>
<text class="free-tip color-base-text color-base-border">{{ $lang('fullGift') }}</text>
<text class="font-size-base">{{ manjian.mansong }}</text>
</view>
<view class="item" v-if="manjian.free_shipping != undefined" style="display: flex;">
<view class="free-tip color-base-text color-base-border">包邮</view>
<view class="free-tip color-base-text color-base-border">{{ $lang('freeShipping') }}</view>
<text class="font-size-base">{{ manjian.free_shipping }}</text>
</view>
</scroll-view>
<view class="button-box"><button type="primary" @click="closeManjianPopup()">确定</button></view>
<view class="button-box"><button type="primary" @click="closeManjianPopup()">{{ $lang('confirm') }}</button></view>
</view>
</uni-popup>
</view>
@@ -393,7 +393,7 @@
<uni-popup ref="informationPopup" type="bottom">
<view class="manjian-popup-layer popup-layer" :style="{ height: FormHeight }">
<view class="head-wrap" @click="closeinformationPopup()">
<text>商品留言</text>
<text>{{ $lang('productMessage') }}</text>
<text class="iconfont icon-close"></text>
</view>
<scroll-view scroll-y class="manjian-body" >
@@ -414,7 +414,7 @@
<ns-form :data="informationform" ref="form"></ns-form>
</view>
</scroll-view>
<view class="button-box"><button type="primary" @click="saveubfirnation()">确定</button></view>
<view class="button-box"><button type="primary" @click="saveubfirnation()">{{ $lang('confirm') }}</button></view>
</view>
</uni-popup>
<!-- <uni-popup ref="informationPopup" type="bottom" class="sku-layer" @change="popclose">
@@ -463,7 +463,7 @@
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 1" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="phoneClick(goodsSkuDetail.goods_mobile)" :text="$lang('make')" :disabled="false" />
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 2" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="showinformation" :text="$lang('leave')" :disabled="false" />
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 3" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="goToAIChat" text="智能客服" :disabled="false" />
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 3" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="goToAIChat" :text="$lang('aiCustomerService')" :disabled="false" />
<!-- <ns-goods-action-button v-if="goodsSkuDetail.isinformation == 2" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="buyNow" text="商品留言" :disabled="false" /> -->
</block>
@@ -520,11 +520,11 @@
<uni-popup ref="contactPopup" type="center">
<view class="contact-popup">
<view class="contact-content">
<text class="contact-text">可在手机端拨打 021-51815181</text>
<text class="contact-text">{{ $lang('dialOnMobile', { phone: '021-51815181' }) }}</text>
</view>
<view class="contact-buttons">
<button class="contact-btn cancel-btn" @click="closeContactPopup">取消</button>
<button class="contact-btn copy-btn" @click="copyPhoneNumber">复制到剪切板</button>
<button class="contact-btn cancel-btn" @click="closeContactPopup">{{ $lang('cancel') }}</button>
<button class="contact-btn copy-btn" @click="copyPhoneNumber">{{ $lang('copyToClipboard') }}</button>
</view>
</view>
</uni-popup>
@@ -588,7 +588,7 @@ export default {
data: '021-51815181',
success: () => {
uni.showToast({
title: '复制成功',
title: this.$lang('copySuccess'),
icon: 'success'
});
this.closeContactPopup();