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

@@ -7,35 +7,35 @@
<!-- #ifdef H5 -->
<template v-if="forceBindingMobileControl">
<view class="head">
<text class="title">检测到您还未绑定手机号</text>
<text class="color-tip tips">为了方便您接收订单等信息,需要绑定手机号</text>
<text class="title">{{ $lang('components.ns-login.bindMobileTitle') }}</text>
<text class="color-tip tips">{{ $lang('components.ns-login.bindMobileTip') }}</text>
<text class="iconfont icon-close color-tip" @click="cancelCompleteInfo"></text>
</view>
<view class="item-wrap">
<text class="label">手机号</text>
<input type="number" placeholder="请输入手机号" v-model="formData.mobile" maxlength="11" />
<text class="label">{{ $lang('components.ns-login.mobileLabel') }}</text>
<input type="number" :placeholder="$lang('components.ns-login.mobilePlaceholder')" v-model="formData.mobile" maxlength="11" />
</view>
<view class="item-wrap" v-if="isOpenCaptcha">
<text class="label">验证码</text>
<input type="number" placeholder="请输入验证码" v-model="formData.vercode" maxlength="4" />
<text class="label">{{ $lang('components.ns-login.captchaLabel') }}</text>
<input type="number" :placeholder="$lang('components.ns-login.captchaPlaceholder')" v-model="formData.vercode" maxlength="4" />
<image :src="captcha.img" class="captcha" @click="getCaptcha" show-menu-by-longpress></image>
</view>
<view class="item-wrap">
<text class="label">动态码</text>
<input type="number" placeholder="请输入动态码" v-model="formData.dynacode" maxlength="4" />
<text class="label">{{ $lang('components.ns-login.dynacodeLabel') }}</text>
<input type="number" :placeholder="$lang('components.ns-login.dynacodePlaceholder')" v-model="formData.dynacode" maxlength="4" />
<view class="send color-base-text" @click="sendMobileCode">{{ dynacodeData.codeText }}
</view>
</view>
</template>
<button type="default" class="save-btn" @click="saveH5" :disabled="isDisabled">保存</button>
<button type="default" class="save-btn" @click="saveH5" :disabled="isDisabled">{{ $lang('components.ns-login.save') }}</button>
<!-- #endif -->
<!-- #ifdef MP -->
<view class="head">
<text class="title">欢迎来到 {{ site_name }}</text>
<text class="title">{{ $lang('components.ns-login.welcomeTitle', { siteName: site_name }) }}</text>
<text class="color-tip tips">
<template>{{ forceBindingMobileControl ? '使用手机号登录,' : '注册登录,' }}</template>
获得订单、售后等服务。
<template>{{ forceBindingMobileControl ? $lang('components.ns-login.loginWithMobile') : $lang('components.ns-login.registerLogin') }}</template>
{{ $lang('components.ns-login.getServicesTip') }}
</text>
<text class="iconfont icon-close color-tip" @click="cancelCompleteInfo"></text>
</view>
@@ -46,11 +46,11 @@
:class="isAgree ? 'icon-fuxuankuang1 color-base-text' : 'icon-fuxuankuang2'"
@click="isAgree = !isAgree"></view>
<view style="text-align: left; margin-left: 10rpx; padding-top: 2rpx; font-size: 28rpx;">
我同意
{{ $lang('components.ns-login.agree') }}
<text style="color: #4395ff;"
@click="tourl('/pages_tool/agreement/contenr?type=0')">《隐私条款》</text>
@click="tourl('/pages_tool/agreement/contenr?type=0')">{{ $lang('components.ns-login.privacyPolicy') }}</text>
<text style="color: #4395ff;"
@click="tourl('/pages_tool/agreement/contenr?type=1')">《用户服务协议》</text>
@click="tourl('/pages_tool/agreement/contenr?type=1')">{{ $lang('components.ns-login.userServiceAgreement') }}</text>
</view>
</view>
@@ -58,25 +58,25 @@
<block v-if="isAgree">
<button class="auth-login save-btn border-0" style="border: none;" open-type="getPhoneNumber"
@getphonenumber="getPhoneNumber">
<text style="color: #fff; font-size: 30rpx;">同意隐私协议并授权手机号</text>
<text style="color: #fff; font-size: 30rpx;">{{ $lang('components.ns-login.agreeAndAuthorizeMobile') }}</text>
</button>
</block>
<block v-else>
<button class="auth-login save-btn border-0" style="border: none;" @click="authno">
<text style="color: #fff; font-size: 30rpx;">授权手机号码</text>
<text style="color: #fff; font-size: 30rpx;">{{ $lang('components.ns-login.authorizeMobile') }}</text>
</button>
</block>
<view @click="closeLogin"
style="font-size: 30rpx; color: #888; text-align: center; padding-top: 10rpx;">
暂不登录
{{ $lang('components.ns-login.notNow') }}
</view>
<!-- 昵称和头像模式 -->
<template v-if="enableNickAndAvatar">
<!-- #ifdef MP-WEIXIN -->
<view class="item-wrap">
<text class="label">头像</text>
<text class="label">{{ $lang('components.ns-login.avatarLabel') }}</text>
<button open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
<image :src="avatarUrl ? avatarUrl : $util.getDefaultImage().head"
@error="avatarUrl = $util.getDefaultImage().head" mode="aspectFill" show-menu-by-longpress/>
@@ -84,15 +84,15 @@
</button>
</view>
<view class="item-wrap">
<text class="label">昵称</text>
<input type="nickname" placeholder="请输入昵称" v-model="nickName" @blur="blurNickName"
<text class="label">{{ $lang('components.ns-login.nicknameLabel') }}</text>
<input type="nickname" :placeholder="$lang('components.ns-login.nicknamePlaceholder')" v-model="nickName" @blur="blurNickName"
maxlength="50" />
</view>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<view class="item-wrap">
<text class="label">头像</text>
<text class="label">{{ $lang('components.ns-login.avatarLabel') }}</text>
<button open-type="getAuthorize" scope="userInfo" @getAuthorize="aliappGetUserinfo"
:plain="true" class="border-0">
<image :src="avatarUrl ? avatarUrl : $util.getDefaultImage().head"
@@ -101,21 +101,21 @@
</button>
</view>
<view class="item-wrap">
<text class="label">昵称</text>
<input type="nickname" placeholder="请输入昵称" v-model="nickName" @blur="blurNickName"
<text class="label">{{ $lang('components.ns-login.nicknameLabel') }}</text>
<input type="nickname" :placeholder="$lang('components.ns-login.nicknamePlaceholder')" v-model="nickName" @blur="blurNickName"
maxlength="50" />
</view>
<!-- #endif -->
<view class="item-wrap" v-if="forceBindingMobileControl">
<text class="label">手机号</text>
<text class="label">{{ $lang('components.ns-login.mobileLabel') }}</text>
<button open-type="getPhoneNumber" :plain="true" class="auth-login border-0"
@getphonenumber="getPhoneNumber">
<text class="mobile" v-if="formData.mobile">{{ formData.mobile }}</text>
<text class="color-base-text" v-else>获取手机号</text>
<text class="color-base-text" v-else>{{ $lang('components.ns-login.getMobile') }}</text>
</button>
</view>
<button type="default" class="save-btn" @click="saveMp" :disabled="isDisabled">保存</button>
<button type="default" class="save-btn" @click="saveMp" :disabled="isDisabled">{{ $lang('components.ns-login.save') }}</button>
</template>
<!-- #endif -->
</view>
@@ -166,7 +166,7 @@ export default {
dynacodeData: {
seconds: 120,
timer: null,
codeText: '获取动态码',
codeText: '',
isSend: false
},
// 小程序获取手机号所需数据
@@ -223,12 +223,14 @@ export default {
if (siteInfo) {
this.site_name = siteInfo.site_name;
}
// 初始化动态码按钮文字
this.dynacodeData.codeText = this.$lang('components.ns-login.getDynacode');
},
methods: {
// 同意协议
authno() {
if (!this.isAgree) {
this.$util.showToast({ title: '请确认相关协议' });
this.$util.showToast({ title: this.$lang('components.ns-login.pleaseConfirmAgreement') });
}
},
@@ -324,7 +326,7 @@ export default {
},
fail: () => {
this.$util.showToast({
title: '上传失败'
title: this.$lang('components.ns-login.uploadFailed')
});
}
})
@@ -386,17 +388,17 @@ export default {
var rule = [{
name: 'mobile',
checkType: 'required',
errorMsg: '请输入手机号'
errorMsg: this.$lang('components.ns-login.pleaseEnterMobile')
}, {
name: 'mobile',
checkType: 'phoneno',
errorMsg: '请输入正确的手机号'
errorMsg: this.$lang('components.ns-login.pleaseEnterCorrectMobile')
}];
if (this.isOpenCaptcha == 1) {
rule.push({
name: 'captcha_code',
checkType: 'required',
errorMsg: '请输入验证码'
errorMsg: this.$lang('components.ns-login.pleaseEnterCaptcha')
});
}
var checkRes = validate.check(data, rule);
@@ -411,7 +413,7 @@ export default {
if (this.dynacodeData.seconds == 120) {
this.dynacodeData.timer = setInterval(() => {
this.dynacodeData.seconds--;
this.dynacodeData.codeText = this.dynacodeData.seconds + 's后可重新获取';
this.dynacodeData.codeText = this.$lang('components.ns-login.resendAfter', { seconds: this.dynacodeData.seconds });
}, 1000);
}
@@ -430,7 +432,7 @@ export default {
},
fail: () => {
this.$util.showToast({
title: 'request:fail'
title: this.$lang('components.ns-login.requestFail')
});
this.refreshDynacodeData();
}
@@ -444,7 +446,7 @@ export default {
this.dynacodeData = {
seconds: 120,
timer: null,
codeText: '获取动态码',
codeText: this.$lang('components.ns-login.getDynacode'),
isSend: false
};
},
@@ -455,23 +457,23 @@ export default {
let rule = [{
name: 'mobile',
checkType: 'required',
errorMsg: '请输入手机号'
errorMsg: this.$lang('components.ns-login.pleaseEnterMobile')
}, {
name: 'mobile',
checkType: 'phoneno',
errorMsg: '请输入正确的手机号'
errorMsg: this.$lang('components.ns-login.pleaseEnterCorrectMobile')
}];
if (this.isOpenCaptcha == 1) {
if (this.captcha.id != '') rule.push({
name: 'captcha_code',
checkType: 'required',
errorMsg: '请输入验证码'
errorMsg: this.$lang('components.ns-login.pleaseEnterCaptcha')
});
}
rule.push({
name: 'code',
checkType: 'required',
errorMsg: '请输入动态码'
errorMsg: this.$lang('components.ns-login.pleaseEnterDynacode')
});
var checkRes = validate.check(data, rule);
@@ -594,7 +596,7 @@ export default {
},
fail: res => {
this.$util.showToast({
title: 'request:fail'
title: this.$lang('components.ns-login.requestFail')
});
}
});
@@ -603,7 +605,7 @@ export default {
// 授权登录
authLogin(data, type = 'authLogin') {
uni.showLoading({
title: '登录中'
title: this.$lang('components.ns-login.loggingIn')
});
uni.setStorageSync('authInfo', data);
if (uni.getStorageSync('source_member')) data.source_member = uni.getStorageSync('source_member');
@@ -643,7 +645,7 @@ export default {
fail: () => {
uni.hideLoading();
this.$util.showToast({
title: '登录失败'
title: this.$lang('components.ns-login.loginFailed')
});
}
});
@@ -669,12 +671,12 @@ export default {
// 微信小程序保存数据
saveMp() {
if (this.formData.mobile === '') {
this.$util.showToast({ title: '请授权您的手机号码' });
this.$util.showToast({ title: this.$lang('components.ns-login.pleaseAuthorizeMobile') });
return;
}
if (this.nickName.length == 0 && this.enableNickAndAvatar) {
this.$util.showToast({ title: '请输入昵称' });
this.$util.showToast({ title: this.$lang('components.ns-login.pleaseEnterNickname') });
return;
}
@@ -715,7 +717,7 @@ export default {
},
fail: () => {
this.$util.showToast({
title: '头像拉取失败'
title: this.$lang('components.ns-login.avatarPullFailed')
});
}
})