refactor: 完成多语言国际化全量替换与补充
1. 新增大量中英文语言包文件,覆盖自定义组件、页面、工具类的文案 2. 替换硬编码文本为多语言调用,统一全局文案管理 3. 优化语言包结构,拆分公共模块与业务模块 4. 修复部分语言加载与国际化适配问题
This commit is contained in:
8
App.vue
8
App.vue
@@ -91,8 +91,8 @@
|
||||
|
||||
updateManager.onUpdateReady(function(res) {
|
||||
uni.showModal({
|
||||
title: '更新提示',
|
||||
content: '新版本已经准备好,是否重启应用?',
|
||||
title: Lang.lang('common.updateTip'),
|
||||
content: Lang.lang('common.updateReady'),
|
||||
success(res) {
|
||||
if (res.confirm) {
|
||||
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
@@ -118,8 +118,8 @@
|
||||
uni.onNetworkStatusChange(function(res) {
|
||||
if (!res.isConnected) {
|
||||
uni.showModal({
|
||||
title: '网络失去链接',
|
||||
content: '请检查网络链接',
|
||||
title: Lang.lang('common.networkLost'),
|
||||
content: Lang.lang('common.networkCheck'),
|
||||
showCancel: false
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
export const langConfig = {
|
||||
// 语言列表 — 与后端 Lang.php::overrides() 白名单对齐
|
||||
// 增删需要后端同步改 LangOverrideModel::normalizeAppType 旁的 $allow_lang
|
||||
langList: ['zh-cn', 'en-us', 'zh-tw', 'ja-jp', 'ko-kr', 'th-th', 'vi-vn', 'id-id', 'es-es', 'fr-fr', 'de-de', 'ru-ru', 'ar-sa', 'pt-pt', 'it-it', 'tr-tr'],
|
||||
langList: ['zh-cn', 'en-us'],
|
||||
// 默认语言
|
||||
defaultLang: 'zh-cn',
|
||||
// 语言包加载方式:'lazy'(按需加载)或 'preload'(预加载)
|
||||
|
||||
@@ -11,7 +11,13 @@ try {
|
||||
uniacid: site.uniacid,
|
||||
}
|
||||
} else {
|
||||
console.warn('小程序发行环境下,必须配置site.js文件, 不然将使用默认配置,影响小程序定制分发!');
|
||||
// 惰性加载 Lang 避免循环依赖(lang.js 引用了 config.js)
|
||||
try {
|
||||
const Lang = require('@/common/js/lang.js').default;
|
||||
console.warn(Lang.lang('common.config.siteJsNotConfigured'));
|
||||
} catch (e) {
|
||||
console.warn('小程序发行环境下,必须配置site.js文件,不然将使用默认配置,影响小程序定制分发!');
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
// #endif
|
||||
|
||||
@@ -100,7 +100,7 @@ export class CustomerService {
|
||||
|
||||
if (!config || !config.type) {
|
||||
result.isValid = false;
|
||||
result.errors.push('客服类型未配置');
|
||||
result.errors.push(this.vm.$lang('customerService.serviceTypeNotConfigured'));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,10 @@ export default {
|
||||
isEnEnv() {
|
||||
return this.$langConfig.getCurrentLocale() === 'en-us';
|
||||
},
|
||||
// 是否是非中文环境(用于多语言商品名/字段切换)
|
||||
isNotZhEnv() {
|
||||
return this.$langConfig.getCurrentLocale() !== 'zh-cn';
|
||||
},
|
||||
// 动态判断:当前页面是否是 TabBar 根页面(tab 根页不应显示返回按钮)
|
||||
isTabRootPage() {
|
||||
const tabBarList = this.$store.state.tabBarList;
|
||||
|
||||
@@ -261,7 +261,7 @@ export class NavigationHelper {
|
||||
}
|
||||
|
||||
// 显示用户友好的错误信息
|
||||
this.showError(Lang.lang('navigation.serviceUnavailable'))
|
||||
this.showError(Lang.lang('common.navigation.serviceUnavailable'))
|
||||
}
|
||||
|
||||
// 显示错误提示
|
||||
|
||||
@@ -149,28 +149,28 @@ export const Platform = {
|
||||
// #ifdef H5
|
||||
if (platform === 'h5') {
|
||||
cachedAppTypeName = this.isWeiXin()
|
||||
? _t('platform.wechatOfficialAccount', '微信公众号')
|
||||
: _t('platform.h5', 'H5');
|
||||
? _t('common.platform.wechatOfficialAccount', '微信公众号')
|
||||
: _t('common.platform.h5', 'H5');
|
||||
return cachedAppTypeName;
|
||||
}
|
||||
// #endif
|
||||
|
||||
const platformNameMap = {
|
||||
weapp: _t('platform.wechatMiniProgram', '微信小程序'),
|
||||
alipay: _t('platform.alipayMiniProgram', '支付宝小程序'),
|
||||
baidu: _t('platform.baiduMiniProgram', '百度小程序'),
|
||||
toutiao: _t('platform.toutiaoMiniProgram', '头条小程序'),
|
||||
qq: _t('platform.qqMiniProgram', 'QQ小程序'),
|
||||
kuaishou: _t('platform.kuaishouMiniProgram', '快手小程序'),
|
||||
jd: _t('platform.jdMiniProgram', '京东小程序'),
|
||||
'360': _t('platform.miniProgram360', '360小程序'),
|
||||
xhs: _t('platform.xhsMiniProgram', '小红书小程序'),
|
||||
harmony: _t('platform.harmonyService', '鸿蒙元服务'),
|
||||
app: _t('platform.app', 'APP'),
|
||||
pc: _t('platform.pc', 'PC端'),
|
||||
weapp: _t('common.platform.wechatMiniProgram', '微信小程序'),
|
||||
alipay: _t('common.platform.alipayMiniProgram', '支付宝小程序'),
|
||||
baidu: _t('common.platform.baiduMiniProgram', '百度小程序'),
|
||||
toutiao: _t('common.platform.toutiaoMiniProgram', '头条小程序'),
|
||||
qq: _t('common.platform.qqMiniProgram', 'QQ小程序'),
|
||||
kuaishou: _t('common.platform.kuaishouMiniProgram', '快手小程序'),
|
||||
jd: _t('common.platform.jdMiniProgram', '京东小程序'),
|
||||
'360': _t('common.platform.miniProgram360', '360小程序'),
|
||||
xhs: _t('common.platform.xhsMiniProgram', '小红书小程序'),
|
||||
harmony: _t('common.platform.harmonyService', '鸿蒙元服务'),
|
||||
app: _t('common.platform.app', 'APP'),
|
||||
pc: _t('common.platform.pc', 'PC端'),
|
||||
};
|
||||
|
||||
cachedAppTypeName = platformNameMap[platform] || _t('platform.unknown', '未知平台');
|
||||
cachedAppTypeName = platformNameMap[platform] || _t('common.platform.unknown', '未知平台');
|
||||
return cachedAppTypeName;
|
||||
},
|
||||
|
||||
|
||||
@@ -433,21 +433,46 @@ export default {
|
||||
* @param {string} mode 模式 navigateTo、redirectTo、reLaunch、tabbar, 默认navigateTo
|
||||
*/
|
||||
redirectTo(to, param = {}, mode = 'navigateTo') {
|
||||
let url = to;
|
||||
// 1. 拆分 path 与已有 query,避免后面 indexOf('?') 误判
|
||||
const queryIdx = to.indexOf('?');
|
||||
let path = queryIdx === -1 ? to : to.substring(0, queryIdx);
|
||||
const existingParams = {};
|
||||
|
||||
if (queryIdx !== -1) {
|
||||
to.substring(queryIdx + 1).split('&').forEach(kv => {
|
||||
if (!kv) return;
|
||||
// 用 indexOf('=') 取首个等号,兼容 value 里带 '=' 的场景
|
||||
const eqIdx = kv.indexOf('=');
|
||||
const k = eqIdx === -1 ? kv : kv.substring(0, eqIdx);
|
||||
const v = eqIdx === -1 ? '' : kv.substring(eqIdx + 1);
|
||||
if (k) existingParams[k] = v;
|
||||
});
|
||||
}
|
||||
|
||||
// 2. 合并 param:同 key 时新值覆盖旧值,杜绝 ?name=A&name=B 这种重复
|
||||
const merged = Object.assign({}, existingParams, param || {});
|
||||
|
||||
// 3. 统一编码。decode -> encode 双向 roundtrip 兼具两种语义:
|
||||
// - 调用方传原始值(/pages_tool/index/diy?name=XXX) -> encode 后 %2F%3F...
|
||||
// - 调用方已传编码值(%2F%3F...) -> decode 还原 -> encode 还原回去,不会被二次编码
|
||||
// - 任何不能 decode 的非法序列(如裸 %) 走 catch 路径,直接 encode
|
||||
const safeEncode = (v) => {
|
||||
const s = v == null ? '' : String(v);
|
||||
try {
|
||||
return encodeURIComponent(decodeURIComponent(s));
|
||||
} catch (e) {
|
||||
return encodeURIComponent(s);
|
||||
}
|
||||
};
|
||||
const queryStr = Object.keys(merged)
|
||||
.map(k => safeEncode(k) + '=' + safeEncode(merged[k]))
|
||||
.join('&');
|
||||
|
||||
let url = path + (queryStr ? '?' + queryStr : '');
|
||||
|
||||
// 替换url中的前缀
|
||||
url = adaptSubpackageUrl(url);
|
||||
|
||||
if (param != undefined) {
|
||||
Object.keys(param).forEach(function (key) {
|
||||
if (url.indexOf('?') != -1) {
|
||||
url += "&" + key + "=" + param[key];
|
||||
} else {
|
||||
url += "?" + key + "=" + param[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 针对tabBar.list中的路径,直接切换tabBar
|
||||
for (let i = 0; i < systemTabBarList.length; i++) {
|
||||
const tabBarUrl = systemTabBarList[i];
|
||||
@@ -897,7 +922,7 @@ export default {
|
||||
}
|
||||
|
||||
if (!isObject(obj)) {
|
||||
throw new Error('obj 不是一个对象!')
|
||||
throw new Error(Lang.lang('util.deepCloneNotObject'))
|
||||
}
|
||||
//判断传进来的是对象还是数组
|
||||
let isArray = Array.isArray(obj)
|
||||
@@ -968,7 +993,7 @@ export default {
|
||||
// #ifdef MP
|
||||
this.redirectTo('/pages_tool/webview/webview', {
|
||||
...link,
|
||||
src: encodeURIComponent(url)
|
||||
src: url
|
||||
});
|
||||
// #endif
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
</view>
|
||||
<view class="sale" v-if="goodsValue.saleStyle.control"
|
||||
:style="{ color: goodsValue.theme == 'diy' ? goodsValue.saleStyle.color : '' }">
|
||||
已售{{ item.sale_num }}{{ item.unit ? item.unit : '件' }}
|
||||
{{ $lang('components-diy.diyGoodsList.soldCount', { count: item.sale_num, unit: item.unit || $lang('components-diy.diyGoodsList.soldUnit') }) }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
</view>
|
||||
<view class="sale" v-if="goodsValue.saleStyle.control"
|
||||
:style="{ color: goodsValue.theme == 'diy' ? goodsValue.saleStyle.color : '' }">
|
||||
已售{{ item.sale_num }}{{ item.unit ? item.unit : '件' }}
|
||||
{{ $lang('components-diy.diyGoodsList.soldCount', { count: item.sale_num, unit: item.unit || $lang('components-diy.diyGoodsList.soldUnit') }) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -238,7 +238,7 @@
|
||||
</view>
|
||||
<view class="sale" v-if="goodsValue.saleStyle.control"
|
||||
:style="{ color: goodsValue.theme == 'diy' ? goodsValue.saleStyle.color : '' }">
|
||||
已售{{ dataItem.sale_num }}{{ dataItem.unit ? dataItem.unit : '件' }}
|
||||
{{ $lang('components-diy.diyGoodsList.soldCount', { count: dataItem.sale_num, unit: dataItem.unit || $lang('components-diy.diyGoodsList.soldUnit') }) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -146,14 +146,14 @@
|
||||
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text>{{ showMarketPrice(item) }}</text>
|
||||
</view>
|
||||
<view class="sale font-size-activity-tag color-tip">已售{{
|
||||
item.sale_num }}{{ item.unit ? item.unit : '件' }}</view>
|
||||
<view class="sale font-size-activity-tag color-tip">{{
|
||||
$lang('components-diy.diyIndexPage.soldCount', { count: item.sale_num, unit: item.unit || $lang('components-diy.diyIndexPage.soldUnit') }) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="!isloading && goodsList[pageIndex].list.length == 0">
|
||||
<ns-empty text="该分类下暂无商品" :isIndex="false"></ns-empty>
|
||||
<ns-empty :text="$lang('components-diy.diyIndexPage.noGoodsInCategory')" :isIndex="false"></ns-empty>
|
||||
</view>
|
||||
</block>
|
||||
</mescroll-uni>
|
||||
@@ -193,7 +193,7 @@ export default {
|
||||
pageIndex: 0, //当前选中分类id
|
||||
cateList: [{
|
||||
//header分类
|
||||
category_name: '首页'
|
||||
category_name: ''
|
||||
}],
|
||||
twoCategorylist: [], //二级分类
|
||||
twoCategorylistId: 0, //二级分类所在的swiper
|
||||
@@ -258,6 +258,9 @@ export default {
|
||||
return data;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.cateList[0].category_name = this.$lang('components-diy.diyIndexPage.home');
|
||||
},
|
||||
watch: {
|
||||
type(newVal, oldVal) {
|
||||
if (newVal) {
|
||||
@@ -323,7 +326,7 @@ export default {
|
||||
let obj = {
|
||||
list: []
|
||||
};
|
||||
obj.category_name = this.value.title ? this.value.title : '首页';
|
||||
obj.category_name = this.value.title ? this.value.title : this.$lang('components-diy.diyIndexPage.home');
|
||||
arr.push(obj);
|
||||
this.cateList = arr.concat(res.data);
|
||||
Object.keys(this.cateList).forEach((key, index) => {
|
||||
|
||||
@@ -42,11 +42,11 @@
|
||||
<uni-popup ref="noticePopup" type="center">
|
||||
<view class="notice-popup">
|
||||
<view class="head-wrap" @tap.stop="closeNoticePopup">
|
||||
<text>公告</text>
|
||||
<text>{{ $lang('components-diy.diyNotice.notice') }}</text>
|
||||
<text class="iconfont icon-close"></text>
|
||||
</view>
|
||||
<view class="content-wrap">{{ notice }}</view>
|
||||
<button type="primary" @tap.stop="closeNoticePopup">我知道了</button>
|
||||
<button type="primary" @tap.stop="closeNoticePopup">{{ $lang('components-diy.diyNotice.gotIt') }}</button>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
|
||||
@@ -143,7 +143,7 @@ export default {
|
||||
});
|
||||
|
||||
video.addEventListener('error', (e) => {
|
||||
console.error('H5端预加载视频失败:', e);
|
||||
console.error(this.$lang('components-diy.diyVideo.h5PreloadFailed') + ':', e);
|
||||
});
|
||||
|
||||
// 触发加载
|
||||
@@ -184,7 +184,7 @@ export default {
|
||||
|
||||
// 视频错误事件
|
||||
onVideoError(event) {
|
||||
console.error('视频加载失败:', event);
|
||||
console.error(this.$lang('components-diy.diyVideo.videoLoadFailed') + ':', event);
|
||||
},
|
||||
|
||||
async handlerClick(videoUrl) {
|
||||
|
||||
@@ -1,35 +1,37 @@
|
||||
// 全局配置
|
||||
// mescroll-body 和 mescroll-uni 通用
|
||||
const GlobalOption = {
|
||||
down: {
|
||||
// 其他down的配置参数也可以写,这里只展示了常用的配置:
|
||||
textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本
|
||||
textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本
|
||||
textLoading: '加载中 ...', // 加载中的提示文本
|
||||
offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调
|
||||
native: false // 是否使用系统自带的下拉刷新; 默认false; 仅在mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例)
|
||||
},
|
||||
up: {
|
||||
// 其他up的配置参数也可以写,这里只展示了常用的配置:
|
||||
textLoading: '加载中 ...', // 加载中的提示文本
|
||||
textNoMore: '', // 没有更多数据的提示文本
|
||||
// textNoMore: '— 我是有底线的 —', // 没有更多数据的提示文本
|
||||
offset: 80, // 距底部多远时,触发upCallback
|
||||
isBounce: false, // 默认禁止橡皮筋的回弹效果, 必读事项: http://www.mescroll.com/qa.html?v=190725#q25
|
||||
toTop: {
|
||||
// 回到顶部按钮,需配置src才显示
|
||||
src: "https://www.mescroll.com/img/mescroll-totop.png?v=1", // 图片路径 (建议放入static目录, 如 /static/img/mescroll-totop.png )
|
||||
offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000px
|
||||
right: 20, // 到右边的距离, 默认20 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
|
||||
bottom: 120, // 到底部的距离, 默认120 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
|
||||
width: 72 // 回到顶部图标的宽度, 默认72 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
|
||||
},
|
||||
empty: {
|
||||
use: true, // 是否显示空布局
|
||||
icon: "https://www.mescroll.com/img/mescroll-empty.png?v=1", // 图标路径 (建议放入static目录, 如 /static/img/mescroll-empty.png )
|
||||
tip: '~ 暂无相关数据 ~' // 提示
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default GlobalOption
|
||||
// 全局配置
|
||||
// mescroll-body 和 mescroll-uni 通用
|
||||
import Lang from '@/common/js/lang.js';
|
||||
|
||||
const GlobalOption = {
|
||||
down: {
|
||||
// 其他down的配置参数也可以写,这里只展示了常用的配置:
|
||||
textInOffset: Lang.lang('components.mescroll.down.textInOffset', '下拉刷新'), // 下拉的距离在offset范围内的提示文本
|
||||
textOutOffset: Lang.lang('components.mescroll.down.textOutOffset', '释放更新'), // 下拉的距离大于offset范围的提示文本
|
||||
textLoading: Lang.lang('components.mescroll.down.textLoading', '加载中 ...'), // 加载中的提示文本
|
||||
offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调
|
||||
native: false // 是否使用系统自带的下拉刷新; 默认false; 仅在mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例)
|
||||
},
|
||||
up: {
|
||||
// 其他up的配置参数也可以写,这里只展示了常用的配置:
|
||||
textLoading: Lang.lang('components.mescroll.up.textLoading', '加载中 ...'), // 加载中的提示文本
|
||||
textNoMore: '', // 没有更多数据的提示文本
|
||||
// textNoMore: '— 我是有底线的 —', // 没有更多数据的提示文本
|
||||
offset: 80, // 距底部多远时,触发upCallback
|
||||
isBounce: false, // 默认禁止橡皮筋的回弹效果, 必读事项: http://www.mescroll.com/qa.html?v=190725#q25
|
||||
toTop: {
|
||||
// 回到顶部按钮,需配置src才显示
|
||||
src: "https://www.mescroll.com/img/mescroll-totop.png?v=1", // 图片路径 (建议放入static目录, 如 /static/img/mescroll-totop.png )
|
||||
offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000px
|
||||
right: 20, // 到右边的距离, 默认20 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
|
||||
bottom: 120, // 到底部的距离, 默认120 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
|
||||
width: 72 // 回到顶部图标的宽度, 默认72 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
|
||||
},
|
||||
empty: {
|
||||
use: true, // 是否显示空布局
|
||||
icon: "https://www.mescroll.com/img/mescroll-empty.png?v=1", // 图标路径 (建议放入static目录, 如 /static/img/mescroll-empty.png )
|
||||
tip: Lang.lang('components.mescroll.empty.tip', '~ 暂无相关数据 ~') // 提示
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default GlobalOption
|
||||
|
||||
@@ -4,6 +4,18 @@
|
||||
* http://www.mescroll.com
|
||||
*/
|
||||
|
||||
import Lang from '@/common/js/lang.js';
|
||||
|
||||
// 国际化文本获取:优先从语言包读取,失败则使用默认值(向后兼容)
|
||||
function __i18n(key, defaultVal) {
|
||||
try {
|
||||
var val = Lang.lang(key, defaultVal);
|
||||
return val || defaultVal;
|
||||
} catch (e) {
|
||||
return defaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
export default function MeScroll(options, isScrollBody) {
|
||||
let me = this;
|
||||
me.version = '1.2.3'; // mescroll版本号
|
||||
@@ -52,9 +64,9 @@ MeScroll.prototype.extendDownScroll = function(optDown) {
|
||||
outOffsetRate: 0.2, // 在列表顶部,下拉的距离大于offset时,改变下拉区域高度比例;值小于1且越接近0,高度变化越小,表现为越往下越难拉
|
||||
bottomOffset: 20, // 当手指touchmove位置在距离body底部20px范围内的时候结束上拉刷新,避免Webview嵌套导致touchend事件不执行
|
||||
minAngle: 45, // 向下滑动最少偏移的角度,取值区间 [0,90];默认45度,即向下滑动的角度大于45度则触发下拉;而小于45度,将不触发下拉,避免与左右滑动的轮播等组件冲突;
|
||||
textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本
|
||||
textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本
|
||||
textLoading: '加载中 ...', // 加载中的提示文本
|
||||
textInOffset: __i18n('components.mescroll.down.textInOffset', '下拉刷新'), // 下拉的距离在offset范围内的提示文本
|
||||
textOutOffset: __i18n('components.mescroll.down.textOutOffset', '释放更新'), // 下拉的距离大于offset范围的提示文本
|
||||
textLoading: __i18n('components.mescroll.down.textLoading', '加载中 ...'), // 加载中的提示文本
|
||||
inited: null, // 下拉刷新初始化完毕的回调
|
||||
inOffset: null, // 下拉的距离进入offset范围内那一刻的回调
|
||||
outOffset: null, // 下拉的距离大于offset那一刻的回调
|
||||
@@ -87,7 +99,7 @@ MeScroll.prototype.extendUpScroll = function(optUp) {
|
||||
},
|
||||
noMoreSize: 5, // 如果列表已无数据,可设置列表的总数量要大于等于5条才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看
|
||||
offset: 80, // 距底部多远时,触发upCallback
|
||||
textLoading: '加载中 ...', // 加载中的提示文本
|
||||
textLoading: __i18n('components.mescroll.up.textLoading', '加载中 ...'), // 加载中的提示文本
|
||||
textNoMore: '-- END --', // 没有更多数据的提示文本
|
||||
inited: null, // 初始化完毕的回调
|
||||
showLoading: null, // 显示加载中的回调
|
||||
@@ -112,7 +124,7 @@ MeScroll.prototype.extendUpScroll = function(optUp) {
|
||||
empty: {
|
||||
use: true, // 是否显示空布局
|
||||
icon: null, // 图标路径
|
||||
tip: '~ 暂无相关数据 ~', // 提示
|
||||
tip: __i18n('components.mescroll.empty.tip', '~ 暂无相关数据 ~'), // 提示
|
||||
btnText: '', // 按钮
|
||||
btnClick: null, // 点击按钮的回调
|
||||
onShow: null, // 是否显示的回调
|
||||
|
||||
@@ -198,6 +198,23 @@
|
||||
? this.undisableText
|
||||
: this.$lang('components.yuyueDate.available');
|
||||
},
|
||||
// 周几名称数组(索引 0-6 对应周日到周六,与 Date.getDay() 返回值一致)
|
||||
// 用于显示层(Toast 等),会随语言切换
|
||||
weekBox() {
|
||||
return [
|
||||
this.$lang('components.yuyueDate.weekSunday'),
|
||||
this.$lang('components.yuyueDate.weekMonday'),
|
||||
this.$lang('components.yuyueDate.weekTuesday'),
|
||||
this.$lang('components.yuyueDate.weekWednesday'),
|
||||
this.$lang('components.yuyueDate.weekThursday'),
|
||||
this.$lang('components.yuyueDate.weekFriday'),
|
||||
this.$lang('components.yuyueDate.weekSaturday'),
|
||||
];
|
||||
},
|
||||
// 中文周几名称数组(用于与 disableWeek prop 做数据匹配,保持兼容性)
|
||||
weekBoxCn() {
|
||||
return ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
},
|
||||
},
|
||||
created(props) {
|
||||
this.selectDate = this.nowDate = currentTime().date;
|
||||
@@ -221,11 +238,10 @@
|
||||
let date = e.split("-");
|
||||
date = date[1] + "-" + date[2];
|
||||
if (this.disableWeek.length && date >= weekDate()[0] && date <= weekDate()[1]) {
|
||||
let weekBox = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
let index = new Date(e).getDay();
|
||||
if (this.disableWeek.indexOf(weekBox[index]) != -1) {
|
||||
let dayIndex = new Date(e).getDay();
|
||||
if (this.disableWeek.indexOf(this.weekBoxCn[dayIndex]) != -1) {
|
||||
uni.showToast({
|
||||
title: this.$lang('components.yuyueDate.weekdayCannotBook', { weekday: weekBox[index] }),
|
||||
title: this.$lang('components.yuyueDate.weekdayCannotBook', { weekday: this.weekBox[dayIndex] }),
|
||||
icon: 'none'
|
||||
})
|
||||
return false;
|
||||
@@ -243,10 +259,9 @@
|
||||
// 判断默认是不能选择的周,则都禁止选中
|
||||
if (this.disableWeek.length && this.selectDate >= weekDate()[0] && this.selectDate <=
|
||||
weekDate()[1]) {
|
||||
let weekBox = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
let date = currentTime().year + '-' + this.selectDate;
|
||||
let index = new Date(date).getDay();
|
||||
if (this.disableWeek.indexOf(weekBox[index]) != -1) {
|
||||
let dayIndex = new Date(date).getDay();
|
||||
if (this.disableWeek.indexOf(this.weekBoxCn[dayIndex]) != -1) {
|
||||
item.disable = true;
|
||||
}
|
||||
}
|
||||
@@ -309,11 +324,10 @@
|
||||
// 日期选择事件
|
||||
selectDateEvent(index, item) {
|
||||
if (this.disableWeek.length && item.date >= weekDate()[0] && item.date <= weekDate()[1]) {
|
||||
let weekBox = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
let index = new Date(item.timeStamp).getDay();
|
||||
if (this.disableWeek.indexOf(weekBox[index]) != -1) {
|
||||
let dayIndex = new Date(item.timeStamp).getDay();
|
||||
if (this.disableWeek.indexOf(this.weekBoxCn[dayIndex]) != -1) {
|
||||
uni.showToast({
|
||||
title: this.$lang('components.yuyueDate.weekdayCannotBook', { weekday: weekBox[index] }),
|
||||
title: this.$lang('components.yuyueDate.weekdayCannotBook', { weekday: this.weekBox[dayIndex] }),
|
||||
icon: 'none'
|
||||
})
|
||||
return false;
|
||||
|
||||
@@ -42,6 +42,14 @@ export const lang = {
|
||||
loadHistoryFail: 'Failed to load history',
|
||||
about: '0B',
|
||||
|
||||
// ====== ai-chat-message - Auto Reply Templates ======
|
||||
autoReplyGreeting: 'Hello! I am the AI customer service assistant, glad to serve you! How can I help you?',
|
||||
autoReplyPrice: 'Our product prices vary by model and configuration. Please check the product detail page for specific prices.',
|
||||
autoReplyShipping: 'Generally, orders are shipped within 24 hours. Please check the logistics information for specific timelines.',
|
||||
autoReplyReturn: '7-day no-reason return is supported. Please ensure the product is in good condition.',
|
||||
autoReplyService: 'Our customer service hours are 9:00-18:00. Feel free to contact us if you have any questions.',
|
||||
autoReplyDefault: 'Thank you for your inquiry! Regarding your question about "{question}", our professional customer service will answer you as soon as possible. You can also check our help documentation for more information.',
|
||||
|
||||
// ====== ai-chat-search ======
|
||||
searchEntrance: 'Search',
|
||||
searchPlaceholder: 'Search chat history',
|
||||
@@ -118,5 +126,14 @@ export const lang = {
|
||||
menuClearChat: 'Clear Chat',
|
||||
menuExport: 'Export Records',
|
||||
menuSettings: 'Settings',
|
||||
menuHelp: 'Help'
|
||||
menuHelp: 'Help',
|
||||
|
||||
// ====== index.vue - Console Logs (for debugging) ======
|
||||
logOnShowTriggered: '[AI Chat Page] onShow triggered',
|
||||
logOnUnloadTriggered: '[AI Chat Page] onUnload triggered',
|
||||
logKeyboardChangeUnavailable: 'onKeyboardHeightChange unavailable',
|
||||
logEventHandleError: 'Event handling error',
|
||||
logInitNavbarFailed: 'Failed to initialize navigation bar',
|
||||
logChatComponentNotInit: 'Chat component not initialized',
|
||||
logServicerConfigNotLoaded: '[AI Customer Service] servicerConfig not loaded, retrying after 200ms...'
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: 'Article Details'
|
||||
}
|
||||
title: 'Article Details',
|
||||
// publish time label
|
||||
publishTime: 'Published:',
|
||||
// read count label
|
||||
readCount: 'Views: ',
|
||||
// liked suffix (count + people liked)
|
||||
likedSuffix: ' likes'
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
//title is the title of each page
|
||||
title: 'Article List',
|
||||
emptyText: "No article information available currently"
|
||||
}
|
||||
emptyText: 'No articles'
|
||||
}
|
||||
|
||||
@@ -18,7 +18,40 @@ export const lang = {
|
||||
goodsRecommendTitle: 'Guess you like',
|
||||
currencySymbol: '¥',
|
||||
submit: 'Submit',
|
||||
searchTip: 'Please enter search keywords'
|
||||
searchTip: 'Please enter search keywords',
|
||||
// version update
|
||||
updateTip: 'Update Available',
|
||||
updateReady: 'A new version is ready, restart the app now?',
|
||||
// network status
|
||||
networkLost: 'Network Disconnected',
|
||||
networkCheck: 'Please check your network connection',
|
||||
// config related
|
||||
config: {
|
||||
siteJsNotConfigured: 'In the mini-program release environment, the site.js file must be configured, otherwise the default configuration will be used, which affects mini-program custom distribution!'
|
||||
},
|
||||
// platform detection
|
||||
platform: {
|
||||
wechatOfficialAccount: 'WeChat Official Account',
|
||||
wechatMiniProgram: 'WeChat Mini Program',
|
||||
alipayMiniProgram: 'Alipay Mini Program',
|
||||
baiduMiniProgram: 'Baidu Mini Program',
|
||||
toutiaoMiniProgram: 'Toutiao Mini Program',
|
||||
qqMiniProgram: 'QQ Mini Program',
|
||||
kuaishouMiniProgram: 'Kuaishou Mini Program',
|
||||
jdMiniProgram: 'JD Mini Program',
|
||||
miniProgram360: '360 Mini Program',
|
||||
xhsMiniProgram: 'Xiaohongshu Mini Program',
|
||||
harmonyService: 'Harmony Service',
|
||||
app: 'APP',
|
||||
pc: 'PC',
|
||||
h5: 'H5',
|
||||
unknown: 'Unknown Platform',
|
||||
},
|
||||
},
|
||||
|
||||
// navigation utility
|
||||
navigation: {
|
||||
serviceUnavailable: 'Navigation service temporarily unavailable',
|
||||
},
|
||||
|
||||
// diy custom page
|
||||
@@ -58,6 +91,7 @@ export const lang = {
|
||||
serviceUnavailable: 'Customer service temporarily unavailable',
|
||||
wxworkLinkNotConfigured: 'WeChat Work link not configured',
|
||||
fromFloatButton: 'Inquiry from floating button',
|
||||
serviceTypeNotConfigured: 'Customer service type not configured',
|
||||
},
|
||||
|
||||
// WeChat Work JS-SDK
|
||||
@@ -153,6 +187,8 @@ export const lang = {
|
||||
weekThursday: 'Thu',
|
||||
weekFriday: 'Fri',
|
||||
weekSaturday: 'Sat',
|
||||
// error messages
|
||||
deepCloneNotObject: 'obj is not an object!',
|
||||
},
|
||||
|
||||
// AI service
|
||||
@@ -215,11 +251,6 @@ export const lang = {
|
||||
logoutTitle: 'Tip',
|
||||
logoutContent: 'Are you sure you want to log out?',
|
||||
|
||||
// navigation utility
|
||||
navigation: {
|
||||
serviceUnavailable: 'Navigation service temporarily unavailable',
|
||||
},
|
||||
|
||||
// WeChat Map JSSDK
|
||||
mapWxJssdk: {
|
||||
// error messages
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
export const lang = {
|
||||
expand: 'Expand',
|
||||
clickToCollapse: 'Click to collapse',
|
||||
reachedBottom: 'Reached the bottom~',
|
||||
noCategory: 'No categories yet!',
|
||||
pieceUnit: 'pc(s)',
|
||||
'components-diy': {
|
||||
diyCategory: {
|
||||
// Expand all categories (button on the right of horizontal scroll)
|
||||
expand: 'Expand',
|
||||
// Click to collapse (button at the bottom of expanded popup)
|
||||
clickToCollapse: 'Click to collapse',
|
||||
// Scroll to bottom tip
|
||||
reachedBottom: 'Reached the bottom~',
|
||||
// No categories (empty state tip)
|
||||
noCategory: 'No categories yet!',
|
||||
// Product unit: piece
|
||||
pieceUnit: 'pc(s)',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
7
lang/en-us/components-diy/diy-goods-list.js
Normal file
7
lang/en-us/components-diy/diy-goods-list.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export const lang = {
|
||||
// Sales text: Sold X units
|
||||
soldCount: 'Sold {count}{unit}',
|
||||
|
||||
// Sales unit: piece
|
||||
soldUnit: 'pcs',
|
||||
}
|
||||
14
lang/en-us/components-diy/diy-index-page.js
Normal file
14
lang/en-us/components-diy/diy-index-page.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export const lang = {
|
||||
'components-diy': {
|
||||
diyIndexPage: {
|
||||
// Home (default category name)
|
||||
home: 'Home',
|
||||
// Sales text: Sold X units
|
||||
soldCount: 'Sold {count}{unit}',
|
||||
// Sales unit: piece
|
||||
soldUnit: 'pcs',
|
||||
// Empty state prompt when no goods in category
|
||||
noGoodsInCategory: 'No goods in this category',
|
||||
},
|
||||
},
|
||||
}
|
||||
4
lang/en-us/components-diy/diy-notice.js
Normal file
4
lang/en-us/components-diy/diy-notice.js
Normal file
@@ -0,0 +1,4 @@
|
||||
export const lang = {
|
||||
notice: 'Notice',
|
||||
gotIt: 'Got it',
|
||||
}
|
||||
@@ -1,6 +1,14 @@
|
||||
export const lang = {
|
||||
switchStore: 'Switch',
|
||||
locating: 'Locating...',
|
||||
gettingLocation: 'Getting current location...',
|
||||
searchPlaceholder: 'Search products',
|
||||
}
|
||||
'components-diy': {
|
||||
diyStore: {
|
||||
// Switch store button text
|
||||
switchStore: 'Switch Store',
|
||||
// Locating status text
|
||||
locating: 'Locating',
|
||||
// Getting location status text for address
|
||||
gettingLocation: 'Getting location',
|
||||
// Search input placeholder
|
||||
searchPlaceholder: 'Search',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
6
lang/en-us/components-diy/diy-video.js
Normal file
6
lang/en-us/components-diy/diy-video.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export const lang = {
|
||||
// H5 video preload failed
|
||||
h5PreloadFailed: 'H5 video preload failed',
|
||||
// Video load failed
|
||||
videoLoadFailed: 'Video load failed',
|
||||
}
|
||||
22
lang/en-us/components/mescroll.js
Normal file
22
lang/en-us/components/mescroll.js
Normal file
@@ -0,0 +1,22 @@
|
||||
export const lang = {
|
||||
// mescroll pull-down refresh / pull-up load component
|
||||
components: {
|
||||
mescroll: {
|
||||
// pull-down refresh text
|
||||
down: {
|
||||
textInOffset: 'Pull to refresh',
|
||||
textOutOffset: 'Release to update',
|
||||
textLoading: 'Loading ...',
|
||||
},
|
||||
// pull-up load text
|
||||
up: {
|
||||
textLoading: 'Loading ...',
|
||||
textNoMore: '-- END --',
|
||||
},
|
||||
// empty layout tip
|
||||
empty: {
|
||||
tip: '~ No data ~',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,4 +1,18 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: 'Distributors',
|
||||
|
||||
// Member info
|
||||
joinTime: 'Join Date: ',
|
||||
|
||||
// Stats units
|
||||
peopleUnit: ' people',
|
||||
orderUnit: ' orders',
|
||||
currencyUnit: ' Yuan',
|
||||
|
||||
// Empty state
|
||||
noData: 'No data',
|
||||
|
||||
// Toast messages
|
||||
merchantNotOpenFenxiao: 'Merchant has not enabled distribution',
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: 'View Files',
|
||||
searchPlaceholder: 'Please enter the file name you want to search',
|
||||
viewPdf: 'View PDF File',
|
||||
emptyText: 'No files yet',
|
||||
loading: 'Loading',
|
||||
fileNotExist: 'File does not exist',
|
||||
}
|
||||
|
||||
15
lang/en-us/form/form.js
Normal file
15
lang/en-us/form/form.js
Normal file
@@ -0,0 +1,15 @@
|
||||
export const lang = {
|
||||
|
||||
// Form page
|
||||
form: {
|
||||
form: {
|
||||
// Page title
|
||||
title: 'Please fill in the form information',
|
||||
// Submit success message
|
||||
submitSuccess: 'Submitted successfully',
|
||||
// Form information not available
|
||||
noFormInfo: 'Form information not available',
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
48
lang/en-us/member/bind_mobile.js
Normal file
48
lang/en-us/member/bind_mobile.js
Normal file
@@ -0,0 +1,48 @@
|
||||
export const lang = {
|
||||
// title is the page title
|
||||
title: 'Bind Mobile',
|
||||
|
||||
bindMobile: {
|
||||
// One-click authorization binding
|
||||
oneClickAuthBind: 'One-Click Authorization Binding',
|
||||
// Manual binding
|
||||
manualBind: 'Manual Binding',
|
||||
|
||||
// Phone number
|
||||
phoneNumber: 'Phone Number',
|
||||
// Please enter phone number
|
||||
pleInputMobile: 'Please enter phone number',
|
||||
// Please enter a valid phone number
|
||||
surePhoneNumber: 'Please enter a valid phone number',
|
||||
|
||||
// Verification code
|
||||
confirmCode: 'Verification Code',
|
||||
// Please enter verification code
|
||||
confirmCodeInput: 'Please enter verification code',
|
||||
|
||||
// SMS verification code
|
||||
smsCode: 'SMS Verification Code',
|
||||
// Please enter dynamic code
|
||||
animateCodeInput: 'Please enter dynamic code',
|
||||
// Get dynamic code
|
||||
findanimateCode: 'Get Dynamic Code',
|
||||
// Code sent
|
||||
codeSent: 'Sent ({seconds}s)',
|
||||
// Do not click repeatedly
|
||||
doNotRepeatedlyClick: 'Do not click repeatedly',
|
||||
|
||||
// Save / Bind
|
||||
save: 'Bind',
|
||||
// Binding successful
|
||||
bindSuccess: 'Binding Successful',
|
||||
// Same as original phone number, no need to modify
|
||||
alikePhone: 'Same as original phone number, no need to modify',
|
||||
|
||||
// Tip text
|
||||
tipTitle: 'Notice',
|
||||
// Enjoy more services after binding your mobile number
|
||||
bindBenefitTip: 'Enjoy more services after binding your mobile number',
|
||||
// Send code tip
|
||||
sendCodeTip: 'Click "Get Dynamic Code" and a verification code will be sent to your mobile number {mobile}',
|
||||
},
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
export const lang = {
|
||||
title: 'Account Cancellation',
|
||||
}
|
||||
agreeTermsText: 'Check to indicate you have read and agree to this agreement',
|
||||
nextStep: 'Next',
|
||||
pleaseAgreeFirst: 'Please check to agree to the agreement first',
|
||||
}
|
||||
|
||||
25
lang/en-us/member/card_log.js
Normal file
25
lang/en-us/member/card_log.js
Normal file
@@ -0,0 +1,25 @@
|
||||
export const lang = {
|
||||
//title is the title of each page
|
||||
title: 'Membership Card Log',
|
||||
|
||||
// Stats header
|
||||
totalConsume: 'Total Consume',
|
||||
cardBalance: 'Balance',
|
||||
totalRecharge: 'Total Recharge',
|
||||
yuanSuffix: ' Yuan',
|
||||
statUnit: ' ({unit})',
|
||||
|
||||
// Filter tabs
|
||||
filterAll: 'All',
|
||||
filterIncome: 'Income',
|
||||
filterExpense: 'Expense',
|
||||
filterRecharge: 'Recharge',
|
||||
filterConsume: 'Consume',
|
||||
filterGift: 'Gift',
|
||||
|
||||
// Empty state
|
||||
emptyTips: 'No membership card records',
|
||||
|
||||
// Amount format
|
||||
amountWithUnit: '{amount} Yuan',
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: 'My Favorites'
|
||||
}
|
||||
title: 'My Favorites',
|
||||
emptyText: 'No favorite products yet',
|
||||
emptySubText: 'Go shopping and follow products you like!',
|
||||
deleteSuccess: 'Deleted successfully'
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: 'Modify Avatar'
|
||||
}
|
||||
title: 'Modify Avatar',
|
||||
clickToUpload: 'Click to Upload',
|
||||
confirmSave: 'Confirm Save',
|
||||
reupload: 'Reupload',
|
||||
uploadFailed: 'Avatar upload failed',
|
||||
modifySuccess: 'Avatar modified successfully'
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: 'Withdrawal Records'
|
||||
title: 'Withdrawal Records',
|
||||
emptyTips: 'No withdrawal records'
|
||||
}
|
||||
@@ -1,7 +1,38 @@
|
||||
export const lang = {
|
||||
// title is the title of each page
|
||||
title: 'Product List',
|
||||
|
||||
// Search box placeholder
|
||||
searchPlaceholder: 'Please enter the product you want to search for',
|
||||
|
||||
// Default button text
|
||||
buyText: 'Buy',
|
||||
|
||||
// Sort options
|
||||
sort: {
|
||||
comprehensive: 'Comprehensive',
|
||||
sales: 'Sales',
|
||||
price: 'Price',
|
||||
filter: 'Filter',
|
||||
},
|
||||
|
||||
// Goods list
|
||||
goods: {
|
||||
consultNow: 'Consult Now',
|
||||
sold: 'Sold {num}{unit}',
|
||||
defaultUnit: 'pcs',
|
||||
noGoods: 'No products',
|
||||
},
|
||||
|
||||
// Filter drawer
|
||||
filter: {
|
||||
title: 'Filter',
|
||||
allCategories: 'All Categories',
|
||||
all: 'All',
|
||||
reset: 'Reset',
|
||||
confirm: 'Confirm',
|
||||
},
|
||||
|
||||
// Modal dialog
|
||||
modal: {
|
||||
title: 'Notice',
|
||||
|
||||
@@ -15,5 +15,10 @@ export const lang = {
|
||||
// Toast messages
|
||||
toast: {
|
||||
cancelSuccess: 'Cancelled successfully'
|
||||
},
|
||||
// Cancel refund modal
|
||||
cancelRefund: {
|
||||
content: 'After cancellation, this application will be closed. You can reapply if needed.',
|
||||
cancelText: 'Not Now'
|
||||
}
|
||||
}
|
||||
|
||||
91
lang/en-us/order/invoice.js
Normal file
91
lang/en-us/order/invoice.js
Normal file
@@ -0,0 +1,91 @@
|
||||
export const lang = {
|
||||
//title for each page
|
||||
title: 'Invoice Application',
|
||||
|
||||
// ====== Header ======
|
||||
header: {
|
||||
title: 'Invoice Information',
|
||||
desc: 'Please fill in the invoice information'
|
||||
},
|
||||
|
||||
// ====== Invoice Type ======
|
||||
invoiceType: {
|
||||
title: 'Invoice Type',
|
||||
paper: 'Paper Invoice',
|
||||
paperDesc: 'Invoice will be mailed to the specified address',
|
||||
electronic: 'Electronic Invoice',
|
||||
electronicDesc: 'Invoice will be sent to your email'
|
||||
},
|
||||
|
||||
// ====== Invoice Title ======
|
||||
invoiceTitle: {
|
||||
title: 'Invoice Title',
|
||||
personal: 'Personal',
|
||||
company: 'Company',
|
||||
label: 'Invoice Title',
|
||||
personalPlaceholder: 'Please enter your name',
|
||||
companyPlaceholder: 'Please enter company name',
|
||||
taxpayerId: 'Taxpayer ID',
|
||||
taxpayerIdPlaceholder: 'Please enter taxpayer ID'
|
||||
},
|
||||
|
||||
// ====== Invoice Content ======
|
||||
invoiceContent: {
|
||||
title: 'Invoice Content',
|
||||
label: 'Invoice Content',
|
||||
placeholder: 'Please select invoice content'
|
||||
},
|
||||
|
||||
// ====== Mail Info (Paper Invoice) ======
|
||||
mailInfo: {
|
||||
title: 'Mailing Information',
|
||||
receiver: 'Recipient',
|
||||
receiverPlaceholder: 'Please enter recipient name',
|
||||
mobile: 'Contact Phone',
|
||||
mobilePlaceholder: 'Please enter phone number',
|
||||
address: 'Mailing Address',
|
||||
regionPlaceholder: 'Please select region',
|
||||
detailAddress: 'Detailed Address',
|
||||
detailAddressPlaceholder: 'Please enter detailed address'
|
||||
},
|
||||
|
||||
// ====== Email Info (Electronic Invoice) ======
|
||||
emailInfo: {
|
||||
title: 'Email Information',
|
||||
receiverEmail: 'Receiver Email',
|
||||
emailPlaceholder: 'Please enter the email address to receive the invoice'
|
||||
},
|
||||
|
||||
// ====== Fee Section ======
|
||||
fee: {
|
||||
taxFee: 'Invoice Tax',
|
||||
deliveryFee: 'Delivery Fee'
|
||||
},
|
||||
|
||||
// ====== Footer Submit Section ======
|
||||
footer: {
|
||||
tip: 'Tip: Invoice applications will be processed within {days} working days',
|
||||
submit: 'Submit Application'
|
||||
},
|
||||
|
||||
// ====== Form Validation Messages ======
|
||||
validation: {
|
||||
pleaseEnterTitle: 'Please enter invoice title',
|
||||
pleaseEnterTaxpayerId: 'Please enter taxpayer ID',
|
||||
pleaseSelectContent: 'Please select invoice content',
|
||||
pleaseEnterReceiver: 'Please enter recipient name',
|
||||
pleaseEnterMobile: 'Please enter phone number',
|
||||
pleaseSelectRegion: 'Please select region',
|
||||
pleaseEnterAddress: 'Please enter detailed address',
|
||||
pleaseEnterEmail: 'Please enter receiver email',
|
||||
invalidEmail: 'Please enter a valid email address'
|
||||
},
|
||||
|
||||
// ====== API Messages ======
|
||||
api: {
|
||||
getConfigFailed: 'Failed to get invoice configuration',
|
||||
submitSuccess: 'Invoice application submitted successfully',
|
||||
submitFailed: 'Submission failed, please try again later',
|
||||
networkError: 'Network error, please try again later'
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,16 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: 'Logistics Information'
|
||||
}
|
||||
//title is the title of each page
|
||||
title: 'Logistics Information',
|
||||
|
||||
// Order logistics info
|
||||
order: {
|
||||
logistics: {
|
||||
// Express company info
|
||||
expressCompany: 'Carrier: ',
|
||||
trackingNo: 'Tracking No.: ',
|
||||
|
||||
// Toast messages
|
||||
orderInfoNotFound: 'Order information not found!'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,12 @@ export const lang = {
|
||||
cancelSuccess: 'Cancelled successfully'
|
||||
},
|
||||
|
||||
// ====== Cancel Refund Modal ======
|
||||
cancelRefund: {
|
||||
content: 'After cancellation, this application will be closed. You can reapply if needed.',
|
||||
cancelText: 'Not Now'
|
||||
},
|
||||
|
||||
// ====== Form Validation ======
|
||||
validate: {
|
||||
pleaseInputExpressCompany: 'Please enter logistics company',
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
export const lang = {
|
||||
// page title
|
||||
title: 'Search Results',
|
||||
|
||||
// action buttons
|
||||
exportImage: 'Export Image',
|
||||
exportPdf: 'Export PDF',
|
||||
// Seal detail
|
||||
seal: {
|
||||
medium: {
|
||||
detail: {
|
||||
// Page title
|
||||
title: 'Seal Details',
|
||||
// Export image
|
||||
exportImage: 'Export Image',
|
||||
// Export PDF
|
||||
exportPdf: 'Export PDF',
|
||||
// Loading
|
||||
loading: 'Loading',
|
||||
// File does not exist
|
||||
fileNotExist: 'File does not exist',
|
||||
// Save success
|
||||
saveSuccess: 'Saved successfully',
|
||||
// Save failed
|
||||
saveFailed: 'Save failed',
|
||||
// Download failed
|
||||
downloadFailed: 'Download failed',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loading tips
|
||||
loading: 'Loading',
|
||||
|
||||
// toast messages
|
||||
fileNotExist: 'File does not exist',
|
||||
saveSuccess: 'Saved successfully',
|
||||
saveFailed: 'Save failed, please try again later',
|
||||
downloadFailed: 'Download failed',
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: 'Material Search',
|
||||
|
||||
// Seal search page
|
||||
seal: {
|
||||
medium: {
|
||||
search: {
|
||||
// Search input placeholder
|
||||
placeholder: "Enter medium name e.g. 'gasoline'",
|
||||
placeholder: 'Enter keywords to search',
|
||||
// Search results title
|
||||
searchResult: 'Search Results',
|
||||
// Empty state text
|
||||
// Empty data tip
|
||||
noData: 'No Data',
|
||||
// Modal title
|
||||
tip: 'Tip',
|
||||
// Delete all history confirmation
|
||||
confirmDeleteAllHistory: 'Confirm delete all history?',
|
||||
// Delete single history record confirmation
|
||||
confirmDeleteHistory: 'Confirm delete this history record?',
|
||||
// Confirm delete all history
|
||||
confirmDeleteAllHistory: 'Are you sure you want to delete all search history?',
|
||||
// Confirm delete single history item
|
||||
confirmDeleteHistory: 'Are you sure you want to delete this search history?',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,6 +42,14 @@ export const lang = {
|
||||
loadHistoryFail: '加载历史失败',
|
||||
about: '0B',
|
||||
|
||||
// ====== ai-chat-message - 自动回复模板 ======
|
||||
autoReplyGreeting: '您好!我是AI智能客服,很高兴为您服务!有什么可以帮助您的吗?',
|
||||
autoReplyPrice: '我们的产品价格根据型号和配置有所不同,具体价格请查看商品详情页面。',
|
||||
autoReplyShipping: '一般情况下,订单会在24小时内发货,具体时效请查看物流信息。',
|
||||
autoReplyReturn: '支持7天无理由退货,请确保商品完好无损。',
|
||||
autoReplyService: '我们的客服工作时间是9:00-18:00,有问题可以随时联系我们。',
|
||||
autoReplyDefault: '感谢您的咨询!关于"{question}"的问题,我们的专业客服会尽快为您解答。您也可以查看我们的帮助文档获取更多信息。',
|
||||
|
||||
// ====== ai-chat-search ======
|
||||
searchEntrance: '搜索',
|
||||
searchPlaceholder: '搜索聊天记录',
|
||||
@@ -118,5 +126,14 @@ export const lang = {
|
||||
menuClearChat: '清空聊天',
|
||||
menuExport: '导出记录',
|
||||
menuSettings: '设置',
|
||||
menuHelp: '帮助'
|
||||
menuHelp: '帮助',
|
||||
|
||||
// ====== index.vue - 控制台日志(调试用) ======
|
||||
logOnShowTriggered: '[AI Chat Page] onShow 触发',
|
||||
logOnUnloadTriggered: '[AI Chat Page] onUnload 触发',
|
||||
logKeyboardChangeUnavailable: 'onKeyboardHeightChange 不可用',
|
||||
logEventHandleError: '事件处理错误',
|
||||
logInitNavbarFailed: '初始化导航栏失败',
|
||||
logChatComponentNotInit: '聊天组件未初始化',
|
||||
logServicerConfigNotLoaded: '【AI客服】servicerConfig 未加载,200ms后重试...'
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '文章详情'
|
||||
title: '文章详情',
|
||||
// 发表时间标签
|
||||
publishTime: '发表时间:',
|
||||
// 阅读数标签
|
||||
readCount: '阅读:',
|
||||
// 点赞数后缀(人数+人已赞)
|
||||
likedSuffix: '人已赞'
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '文章列表',
|
||||
emptyText:"当前暂无文章信息"
|
||||
emptyText: '暂无文章'
|
||||
}
|
||||
|
||||
@@ -8,19 +8,52 @@ export const lang = {
|
||||
member: '个人中心'
|
||||
},
|
||||
|
||||
//公共
|
||||
common: {
|
||||
//语言包名称
|
||||
name: '中文',
|
||||
mescrollTextInOffset: '下拉刷新',
|
||||
mescrollTextOutOffset: '释放更新',
|
||||
mescrollEmpty: "暂无相关数据",
|
||||
goodsRecommendTitle: '猜你喜欢',
|
||||
currencySymbol: '¥',
|
||||
submit: '提交',
|
||||
searchTip: '请输入搜索关键词'
|
||||
},
|
||||
|
||||
//公共
|
||||
common: {
|
||||
//语言包名称
|
||||
name: '中文',
|
||||
mescrollTextInOffset: '下拉刷新',
|
||||
mescrollTextOutOffset: '释放更新',
|
||||
mescrollEmpty: "暂无相关数据",
|
||||
goodsRecommendTitle: '猜你喜欢',
|
||||
currencySymbol: '¥',
|
||||
submit: '提交',
|
||||
searchTip: '请输入搜索关键词',
|
||||
// 版本更新
|
||||
updateTip: '更新提示',
|
||||
updateReady: '新版本已经准备好,是否重启应用?',
|
||||
// 网络状态
|
||||
networkLost: '网络失去链接',
|
||||
networkCheck: '请检查网络链接',
|
||||
// 配置相关
|
||||
config: {
|
||||
siteJsNotConfigured: '小程序发行环境下,必须配置site.js文件,不然将使用默认配置,影响小程序定制分发!'
|
||||
},
|
||||
// 平台检测
|
||||
platform: {
|
||||
wechatOfficialAccount: '微信公众号',
|
||||
wechatMiniProgram: '微信小程序',
|
||||
alipayMiniProgram: '支付宝小程序',
|
||||
baiduMiniProgram: '百度小程序',
|
||||
toutiaoMiniProgram: '头条小程序',
|
||||
qqMiniProgram: 'QQ小程序',
|
||||
kuaishouMiniProgram: '快手小程序',
|
||||
jdMiniProgram: '京东小程序',
|
||||
miniProgram360: '360小程序',
|
||||
xhsMiniProgram: '小红书小程序',
|
||||
harmonyService: '鸿蒙元服务',
|
||||
app: 'APP',
|
||||
pc: 'PC端',
|
||||
h5: 'H5',
|
||||
unknown: '未知平台',
|
||||
},
|
||||
},
|
||||
|
||||
// 导航工具
|
||||
navigation: {
|
||||
serviceUnavailable: '导航服务暂时不可用',
|
||||
},
|
||||
|
||||
//客服
|
||||
customer: {
|
||||
weChatKefu: '微信客服',
|
||||
@@ -58,6 +91,7 @@ export const lang = {
|
||||
serviceUnavailable: '客服暂不可用',
|
||||
wxworkLinkNotConfigured: '企业微信链接未配置',
|
||||
fromFloatButton: '来自悬浮按钮的咨询',
|
||||
serviceTypeNotConfigured: '客服类型未配置',
|
||||
},
|
||||
|
||||
// 企业微信JS-SDK
|
||||
@@ -153,6 +187,8 @@ export const lang = {
|
||||
weekThursday: '周四',
|
||||
weekFriday: '周五',
|
||||
weekSaturday: '周六',
|
||||
// 错误消息
|
||||
deepCloneNotObject: 'obj 不是一个对象!',
|
||||
},
|
||||
|
||||
// AI 客服服务
|
||||
@@ -212,11 +248,6 @@ export const lang = {
|
||||
logoutTitle: '提示',
|
||||
logoutContent: '确定要退出登录吗',
|
||||
|
||||
// 导航工具
|
||||
navigation: {
|
||||
serviceUnavailable: '导航服务暂时不可用',
|
||||
},
|
||||
|
||||
// 微信地图JSSDK
|
||||
mapWxJssdk: {
|
||||
// 错误提示
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
export const lang = {
|
||||
expand: '展开',
|
||||
clickToCollapse: '点击收起',
|
||||
reachedBottom: '已经到底了~',
|
||||
noCategory: '暂时没有分类哦!',
|
||||
pieceUnit: '件',
|
||||
'components-diy': {
|
||||
diyCategory: {
|
||||
// 展开全部分类(横向滚动右侧展开按钮)
|
||||
expand: '展开',
|
||||
// 点击收起(展开弹窗底部收起按钮)
|
||||
clickToCollapse: '点击收起',
|
||||
// 滚动到底部提示
|
||||
reachedBottom: '已经到底了~',
|
||||
// 暂无分类(空状态提示)
|
||||
noCategory: '暂时没有分类哦!',
|
||||
// 商品单位:件
|
||||
pieceUnit: '件',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
7
lang/zh-cn/components-diy/diy-goods-list.js
Normal file
7
lang/zh-cn/components-diy/diy-goods-list.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export const lang = {
|
||||
// 销量文案:已售X件
|
||||
soldCount: '已售{count}{unit}',
|
||||
|
||||
// 销量单位:件
|
||||
soldUnit: '件',
|
||||
}
|
||||
14
lang/zh-cn/components-diy/diy-index-page.js
Normal file
14
lang/zh-cn/components-diy/diy-index-page.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export const lang = {
|
||||
'components-diy': {
|
||||
diyIndexPage: {
|
||||
// 首页(默认分类名称)
|
||||
home: '首页',
|
||||
// 销量文案:已售X件
|
||||
soldCount: '已售{count}{unit}',
|
||||
// 销量单位:件
|
||||
soldUnit: '件',
|
||||
// 分类下无商品的空状态提示
|
||||
noGoodsInCategory: '该分类下暂无商品',
|
||||
},
|
||||
},
|
||||
}
|
||||
4
lang/zh-cn/components-diy/diy-notice.js
Normal file
4
lang/zh-cn/components-diy/diy-notice.js
Normal file
@@ -0,0 +1,4 @@
|
||||
export const lang = {
|
||||
notice: '公告',
|
||||
gotIt: '我知道了',
|
||||
}
|
||||
@@ -1,6 +1,14 @@
|
||||
export const lang = {
|
||||
switchStore: '切换',
|
||||
locating: '定位中...',
|
||||
gettingLocation: '获取当前位置...',
|
||||
searchPlaceholder: '商品搜索',
|
||||
}
|
||||
'components-diy': {
|
||||
diyStore: {
|
||||
// 切换门店(按钮文案)
|
||||
switchStore: '切换门店',
|
||||
// 定位中(加载状态提示)
|
||||
locating: '定位中',
|
||||
// 获取位置中(地址加载状态提示)
|
||||
gettingLocation: '获取位置中',
|
||||
// 搜索框占位符
|
||||
searchPlaceholder: '搜索',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
6
lang/zh-cn/components-diy/diy-video.js
Normal file
6
lang/zh-cn/components-diy/diy-video.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export const lang = {
|
||||
// H5端预加载视频失败
|
||||
h5PreloadFailed: 'H5端预加载视频失败',
|
||||
// 视频加载失败
|
||||
videoLoadFailed: '视频加载失败',
|
||||
}
|
||||
22
lang/zh-cn/components/mescroll.js
Normal file
22
lang/zh-cn/components/mescroll.js
Normal file
@@ -0,0 +1,22 @@
|
||||
export const lang = {
|
||||
// mescroll 下拉刷新/上拉加载组件
|
||||
components: {
|
||||
mescroll: {
|
||||
// 下拉刷新提示文本
|
||||
down: {
|
||||
textInOffset: '下拉刷新',
|
||||
textOutOffset: '释放更新',
|
||||
textLoading: '加载中 ...',
|
||||
},
|
||||
// 上拉加载提示文本
|
||||
up: {
|
||||
textLoading: '加载中 ...',
|
||||
textNoMore: '-- END --',
|
||||
},
|
||||
// 空布局提示
|
||||
empty: {
|
||||
tip: '~ 暂无相关数据 ~',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,4 +1,18 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '分销商',
|
||||
|
||||
// 会员信息
|
||||
joinTime: '加入时间:',
|
||||
|
||||
// 统计单位
|
||||
peopleUnit: '人',
|
||||
orderUnit: '单',
|
||||
currencyUnit: '元',
|
||||
|
||||
// 空状态
|
||||
noData: '暂无数据',
|
||||
|
||||
// Toast 提示
|
||||
merchantNotOpenFenxiao: '商家未开启分销',
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '查看文件',
|
||||
searchPlaceholder: '请输入您要搜索的文件名称',
|
||||
viewPdf: '查看PDF文件',
|
||||
emptyText: '暂无文件',
|
||||
loading: '正在加载',
|
||||
fileNotExist: '文件不存在',
|
||||
}
|
||||
|
||||
15
lang/zh-cn/form/form.js
Normal file
15
lang/zh-cn/form/form.js
Normal file
@@ -0,0 +1,15 @@
|
||||
export const lang = {
|
||||
|
||||
// 表单页面
|
||||
form: {
|
||||
form: {
|
||||
// 页面标题
|
||||
title: '请填写表单所需信息',
|
||||
// 提交成功提示
|
||||
submitSuccess: '提交成功',
|
||||
// 未获取到表单信息
|
||||
noFormInfo: '未获取到表单信息',
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
48
lang/zh-cn/member/bind_mobile.js
Normal file
48
lang/zh-cn/member/bind_mobile.js
Normal file
@@ -0,0 +1,48 @@
|
||||
export const lang = {
|
||||
// title为每个页面的标题
|
||||
title: '绑定手机号',
|
||||
|
||||
bindMobile: {
|
||||
// 一键授权绑定
|
||||
oneClickAuthBind: '一键授权绑定',
|
||||
// 手动绑定
|
||||
manualBind: '手动绑定',
|
||||
|
||||
// 手机号
|
||||
phoneNumber: '手机号',
|
||||
// 请输入手机号
|
||||
pleInputMobile: '请输入手机号',
|
||||
// 请输入正确的手机号
|
||||
surePhoneNumber: '请输入正确的手机号',
|
||||
|
||||
// 验证码
|
||||
confirmCode: '验证码',
|
||||
// 请输入验证码
|
||||
confirmCodeInput: '请输入验证码',
|
||||
|
||||
// 短信验证码
|
||||
smsCode: '短信验证码',
|
||||
// 请输入动态码
|
||||
animateCodeInput: '请输入动态码',
|
||||
// 获取动态码
|
||||
findanimateCode: '获取动态码',
|
||||
// 已发送
|
||||
codeSent: '已发送({seconds}s)',
|
||||
// 请勿重复点击
|
||||
doNotRepeatedlyClick: '请勿重复点击',
|
||||
|
||||
// 保存/绑定
|
||||
save: '绑定',
|
||||
// 绑定成功
|
||||
bindSuccess: '绑定成功',
|
||||
// 与原手机号一致,无需修改
|
||||
alikePhone: '与原手机号一致,无需修改',
|
||||
|
||||
// 提示文案
|
||||
tipTitle: '温馨提示',
|
||||
// 绑定手机号后可享受更多服务
|
||||
bindBenefitTip: '绑定手机号后可享受更多服务',
|
||||
// 发送动态码提示
|
||||
sendCodeTip: '点击"获取动态码",将会向您的手机号{mobile}发送验证码',
|
||||
},
|
||||
}
|
||||
@@ -1,3 +1,10 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '账号注销',
|
||||
}
|
||||
// 协议勾选提示
|
||||
agreeTermsText: '勾选即表示您已阅读并同意本协议',
|
||||
// 下一步按钮
|
||||
nextStep: '下一步',
|
||||
// 未勾选协议提示
|
||||
pleaseAgreeFirst: '请先勾选同意协议',
|
||||
}
|
||||
|
||||
25
lang/zh-cn/member/card_log.js
Normal file
25
lang/zh-cn/member/card_log.js
Normal file
@@ -0,0 +1,25 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '会员卡记录',
|
||||
|
||||
// 顶部统计
|
||||
totalConsume: '累计消费',
|
||||
cardBalance: '卡余额',
|
||||
totalRecharge: '累计充值',
|
||||
yuanSuffix: '元',
|
||||
statUnit: '({unit})',
|
||||
|
||||
// 筛选 tab
|
||||
filterAll: '全部',
|
||||
filterIncome: '收入',
|
||||
filterExpense: '支出',
|
||||
filterRecharge: '充值',
|
||||
filterConsume: '消费',
|
||||
filterGift: '赠送',
|
||||
|
||||
// 空状态
|
||||
emptyTips: '暂无会员卡记录',
|
||||
|
||||
// 金额格式
|
||||
amountWithUnit: '{amount}元',
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '我的关注'
|
||||
title: '我的关注',
|
||||
emptyText: '暂无关注的商品',
|
||||
emptySubText: '赶紧去逛逛, 关注心仪的商品吧',
|
||||
deleteSuccess: '删除成功'
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '修改头像'
|
||||
title: '修改头像',
|
||||
clickToUpload: '点击上传',
|
||||
confirmSave: '确认保存',
|
||||
reupload: '重新上传',
|
||||
uploadFailed: '头像上传失败',
|
||||
modifySuccess: '头像修改成功'
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '提现记录'
|
||||
title: '提现记录',
|
||||
emptyTips: '暂无提现记录'
|
||||
}
|
||||
|
||||
@@ -1,7 +1,38 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '商品列表',
|
||||
|
||||
// 搜索框 placeholder
|
||||
searchPlaceholder: '请输入您要搜索的商品',
|
||||
|
||||
// 按钮默认文本
|
||||
buyText: '购买',
|
||||
|
||||
// 排序
|
||||
sort: {
|
||||
comprehensive: '综合',
|
||||
sales: '销量',
|
||||
price: '价格',
|
||||
filter: '筛选',
|
||||
},
|
||||
|
||||
// 商品列表
|
||||
goods: {
|
||||
consultNow: '立即咨询',
|
||||
sold: '已售{num}{unit}',
|
||||
defaultUnit: '件',
|
||||
noGoods: '暂无商品',
|
||||
},
|
||||
|
||||
// 筛选弹窗
|
||||
filter: {
|
||||
title: '筛选',
|
||||
allCategories: '全部分类',
|
||||
all: '全部',
|
||||
reset: '重置',
|
||||
confirm: '确定',
|
||||
},
|
||||
|
||||
// 弹窗提示
|
||||
modal: {
|
||||
title: '提示',
|
||||
|
||||
@@ -15,5 +15,10 @@ export const lang = {
|
||||
// 提示信息
|
||||
toast: {
|
||||
cancelSuccess: '撤销成功'
|
||||
},
|
||||
// 撤销退款弹窗
|
||||
cancelRefund: {
|
||||
content: '撤销之后本次申请将会关闭,如后续仍有问题可再次发起申请。',
|
||||
cancelText: '暂不撤销'
|
||||
}
|
||||
}
|
||||
|
||||
91
lang/zh-cn/order/invoice.js
Normal file
91
lang/zh-cn/order/invoice.js
Normal file
@@ -0,0 +1,91 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '发票申请',
|
||||
|
||||
// ====== 页头区 ======
|
||||
header: {
|
||||
title: '发票信息',
|
||||
desc: '请填写发票相关信息'
|
||||
},
|
||||
|
||||
// ====== 发票类型 ======
|
||||
invoiceType: {
|
||||
title: '发票类型',
|
||||
paper: '纸质发票',
|
||||
paperDesc: '发票将邮寄到指定地址',
|
||||
electronic: '电子发票',
|
||||
electronicDesc: '发票将发送至您的邮箱'
|
||||
},
|
||||
|
||||
// ====== 发票抬头 ======
|
||||
invoiceTitle: {
|
||||
title: '发票抬头',
|
||||
personal: '个人',
|
||||
company: '企业',
|
||||
label: '发票抬头',
|
||||
personalPlaceholder: '请输入个人姓名',
|
||||
companyPlaceholder: '请输入企业名称',
|
||||
taxpayerId: '纳税人识别号',
|
||||
taxpayerIdPlaceholder: '请输入纳税人识别号'
|
||||
},
|
||||
|
||||
// ====== 发票内容 ======
|
||||
invoiceContent: {
|
||||
title: '发票内容',
|
||||
label: '发票内容',
|
||||
placeholder: '请选择发票内容'
|
||||
},
|
||||
|
||||
// ====== 邮寄信息(纸质发票) ======
|
||||
mailInfo: {
|
||||
title: '邮寄信息',
|
||||
receiver: '收件人',
|
||||
receiverPlaceholder: '请输入收件人姓名',
|
||||
mobile: '联系电话',
|
||||
mobilePlaceholder: '请输入联系电话',
|
||||
address: '邮寄地址',
|
||||
regionPlaceholder: '请选择所在地区',
|
||||
detailAddress: '详细地址',
|
||||
detailAddressPlaceholder: '请输入详细地址'
|
||||
},
|
||||
|
||||
// ====== 邮箱信息(电子发票) ======
|
||||
emailInfo: {
|
||||
title: '邮箱信息',
|
||||
receiverEmail: '接收邮箱',
|
||||
emailPlaceholder: '请输入接收发票的邮箱地址'
|
||||
},
|
||||
|
||||
// ====== 费用区 ======
|
||||
fee: {
|
||||
taxFee: '发票税费',
|
||||
deliveryFee: '邮寄费用'
|
||||
},
|
||||
|
||||
// ====== 底部提交区 ======
|
||||
footer: {
|
||||
tip: '温馨提示:发票申请提交后将在{days}个工作日内处理',
|
||||
submit: '提交申请'
|
||||
},
|
||||
|
||||
// ====== 表单校验提示 ======
|
||||
validation: {
|
||||
pleaseEnterTitle: '请输入发票抬头',
|
||||
pleaseEnterTaxpayerId: '请输入纳税人识别号',
|
||||
pleaseSelectContent: '请选择发票内容',
|
||||
pleaseEnterReceiver: '请输入收件人姓名',
|
||||
pleaseEnterMobile: '请输入联系电话',
|
||||
pleaseSelectRegion: '请选择所在地区',
|
||||
pleaseEnterAddress: '请输入详细地址',
|
||||
pleaseEnterEmail: '请输入接收邮箱',
|
||||
invalidEmail: '请输入正确的邮箱地址'
|
||||
},
|
||||
|
||||
// ====== 接口消息 ======
|
||||
api: {
|
||||
getConfigFailed: '获取发票配置失败',
|
||||
submitSuccess: '发票申请提交成功',
|
||||
submitFailed: '提交失败,请稍后重试',
|
||||
networkError: '网络错误,请稍后重试'
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,16 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '物流信息'
|
||||
title: '物流信息',
|
||||
|
||||
// 订单物流信息
|
||||
order: {
|
||||
logistics: {
|
||||
// 快递公司信息
|
||||
expressCompany: '承运公司:',
|
||||
trackingNo: '运单号:',
|
||||
|
||||
// 提示消息
|
||||
orderInfoNotFound: '未获取到订单信息!'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,12 @@ export const lang = {
|
||||
cancelSuccess: '撤销成功'
|
||||
},
|
||||
|
||||
// ====== 撤销退款弹窗 ======
|
||||
cancelRefund: {
|
||||
content: '撤销之后本次申请将会关闭,如后续仍有问题可再次发起申请。',
|
||||
cancelText: '暂不撤销'
|
||||
},
|
||||
|
||||
// ====== 表单验证 ======
|
||||
validate: {
|
||||
pleaseInputExpressCompany: '请输入物流公司',
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
export const lang = {
|
||||
// 页面标题
|
||||
title: '搜索结果',
|
||||
|
||||
// 操作按钮
|
||||
exportImage: '导出图片',
|
||||
exportPdf: '导出PDF',
|
||||
// 印章详情
|
||||
seal: {
|
||||
medium: {
|
||||
detail: {
|
||||
// 页面标题
|
||||
title: '印章详情',
|
||||
// 导出图片
|
||||
exportImage: '导出图片',
|
||||
// 导出PDF
|
||||
exportPdf: '导出PDF',
|
||||
// 加载中
|
||||
loading: '加载中',
|
||||
// 文件不存在
|
||||
fileNotExist: '文件不存在',
|
||||
// 保存成功
|
||||
saveSuccess: '保存成功',
|
||||
// 保存失败
|
||||
saveFailed: '保存失败',
|
||||
// 下载失败
|
||||
downloadFailed: '下载失败',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 加载提示
|
||||
loading: '正在加载',
|
||||
|
||||
// 提示消息
|
||||
fileNotExist: '文件不存在',
|
||||
saveSuccess: '保存成功',
|
||||
saveFailed: '保存失败,请稍后重试',
|
||||
downloadFailed: '下载失败',
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '介质材料搜索',
|
||||
|
||||
// 印章搜索页
|
||||
seal: {
|
||||
medium: {
|
||||
search: {
|
||||
// 搜索框占位符
|
||||
placeholder: "请输入介质名称 '如汽油'",
|
||||
placeholder: '请输入关键词搜索',
|
||||
// 搜索结果标题
|
||||
searchResult: '搜索结果',
|
||||
// 空状态文案
|
||||
// 空数据提示
|
||||
noData: '暂无数据',
|
||||
// 弹窗标题
|
||||
tip: '提示',
|
||||
// 删除全部历史记录确认
|
||||
confirmDeleteAllHistory: '确认删除全部历史记录?',
|
||||
// 删除单条历史记录确认
|
||||
confirmDeleteHistory: '确认删除该条历史记录?',
|
||||
// 确认删除全部历史记录
|
||||
confirmDeleteAllHistory: '确定要删除全部搜索历史吗?',
|
||||
// 确认删除单条历史记录
|
||||
confirmDeleteHistory: '确定要删除这条搜索历史吗?',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -289,27 +289,27 @@ export default {
|
||||
getOrderStatus() {
|
||||
this.statusList = [{
|
||||
status: 'all',
|
||||
name: '全部',
|
||||
name: this.$lang('status.all'),
|
||||
id: 'status_0'
|
||||
},
|
||||
{
|
||||
status: 'waitpay',
|
||||
name: '待付款',
|
||||
name: this.$lang('status.waitpay'),
|
||||
id: 'status_1'
|
||||
},
|
||||
{
|
||||
status: 'waitsend',
|
||||
name: '待发货',
|
||||
name: this.$lang('status.waitsend'),
|
||||
id: 'status_2'
|
||||
},
|
||||
{
|
||||
status: 'waitconfirm',
|
||||
name: '待收货',
|
||||
name: this.$lang('status.waitconfirm'),
|
||||
id: 'status_3'
|
||||
},
|
||||
{
|
||||
status: 'waitrate',
|
||||
name: '已完成',
|
||||
name: this.$lang('status.waitrate'),
|
||||
id: 'status_4'
|
||||
},
|
||||
/*{
|
||||
|
||||
@@ -16,20 +16,20 @@
|
||||
<view v-if="item.level_name" class="title color-base-border color-base-text">{{
|
||||
item.level_name }}</view>
|
||||
</view>
|
||||
<view class="color-tip font-size-goods-tag">加入时间:{{
|
||||
<view class="color-tip font-size-goods-tag">{{ $lang('joinTime') }}{{
|
||||
$util.timeStampTurnTime(item.bind_fenxiao_time).substring(0, 10) }}</view>
|
||||
</view>
|
||||
<view class="consume-info">
|
||||
<view><text>{{ item.one_child_fenxiao_num + item.one_child_num }}</text> 人</view>
|
||||
<view><text>{{ item.order_num }}</text> 单</view>
|
||||
<view><text>{{ item.order_money | moneyFormat }}</text> 元</view>
|
||||
<view><text>{{ item.one_child_fenxiao_num + item.one_child_num }}</text>{{ $lang('peopleUnit') }}</view>
|
||||
<view><text>{{ item.order_num }}</text>{{ $lang('orderUnit') }}</view>
|
||||
<view><text>{{ item.order_money | moneyFormat }}</text>{{ $lang('currencyUnit') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<block v-if="teamList.length == 0 && emptyShow">
|
||||
<ns-empty text="暂无数据" :isIndex="false"></ns-empty>
|
||||
<ns-empty :text="$lang('noData')" :isIndex="false"></ns-empty>
|
||||
</block>
|
||||
</block>
|
||||
</mescroll-uni>
|
||||
@@ -54,7 +54,7 @@ export default {
|
||||
setTimeout(() => {
|
||||
if (!this.addonIsExist.fenxiao) {
|
||||
this.$util.showToast({
|
||||
title: '商家未开启分销',
|
||||
title: this.$lang('merchantNotOpenFenxiao'),
|
||||
mask: true,
|
||||
duration: 2000
|
||||
});
|
||||
|
||||
289
pages_promotion/merch/list.vue
Normal file
289
pages_promotion/merch/list.vue
Normal file
@@ -0,0 +1,289 @@
|
||||
<template>
|
||||
<view class="content" :style="themeColor">
|
||||
<view class="head-wrap">
|
||||
<!-- 搜索区域 -->
|
||||
<view class="search-wrap uni-flex uni-row">
|
||||
<view class="flex-item input-wrap">
|
||||
<input class="uni-input" maxlength="50" v-model="keyword" @confirm="search()"
|
||||
:placeholder="$lang('searchPlaceholder')" />
|
||||
<text class="iconfont icon-sousuo3" @click.stop="search()"></text>
|
||||
</view>
|
||||
<view class="iconfont" :class="{ 'icon-apps': isList, 'icon-list': !isList }"
|
||||
@click="changeListStyle()"></view>
|
||||
</view>
|
||||
|
||||
<!-- 排序 -->
|
||||
<view class="sort-wrap">
|
||||
<view class="comprehensive-wrap" :class="{ 'color-base-text': orderType === '' }"
|
||||
@click="sortTabClick('')">
|
||||
<text :class="{ 'color-base-text': orderType === '' }">{{ $lang('sort.comprehensive') }}</text>
|
||||
</view>
|
||||
|
||||
<view :class="{ 'color-base-text': orderType === 'sale_num' }" @click="sortTabClick('sale_num')">{{ $lang('sort.sales') }}
|
||||
</view>
|
||||
|
||||
<view class="price-wrap" @click="sortTabClick('discount_price')">
|
||||
<text
|
||||
:class="{ 'color-base-text': orderType === 'discount_price' }">{{ $lang('sort.price') }}</text>
|
||||
<view class="iconfont-wrap">
|
||||
<view class="iconfont icon-iconangledown-copy asc"
|
||||
:class="{ 'color-base-text': priceOrder === 'asc' && orderType === 'discount_price' }">
|
||||
</view>
|
||||
<view class="iconfont icon-iconangledown desc"
|
||||
:class="{ 'color-base-text': priceOrder === 'desc' && orderType === 'discount_price' }">
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view :class="{ 'color-base-text': orderType === 'screen' }" class="screen-wrap" @click="sortTabClick('screen')">
|
||||
<text @click="sortTabClick('screen')">{{ $lang('sort.filter') }}</text>
|
||||
<view @click="sortTabClick('screen')" class="iconfont-wrap">
|
||||
<view class="iconfont icon-shaixuan color-tip"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<mescroll-uni top="180" ref="mescroll" @getData="getGoodsList">
|
||||
<block slot="list">
|
||||
<view v-if="isList" class="goods-list single-column" :class="{ show: isList }">
|
||||
<view class="goods-item margin-bottom" v-for="(item, index) in goodsList" :key="item.id"
|
||||
@click="toDetail(item)">
|
||||
<view class="goods-img">
|
||||
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)" show-menu-by-longpress ></image>
|
||||
<view class="color-base-bg goods-tag" v-if="goodsTag(item) != ''">{{ goodsTag(item) }}
|
||||
</view>
|
||||
<view class="sell-out" v-if="item.stock <= 0">
|
||||
<text class="iconfont icon-shuqing"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-wrap">
|
||||
<view class="name-wrap">
|
||||
<view class="goods-name"
|
||||
:class="[{ 'using-hidden': config.nameLineMode == 'single' }, { 'multi-hidden': config.nameLineMode == 'multiple' }]">
|
||||
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="lineheight-clear">
|
||||
<view class="discount-price" v-if="item.isinformation == 0">
|
||||
<text class="unit price-style small">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="price price-style large">{{
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[0] }}</text>
|
||||
<text class="unit price-style small">.{{
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||
</view>
|
||||
<view class="discount-price" v-else>
|
||||
<text class="price price-style large">{{ $lang('goods.consultNow') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pro-info" v-if="item.isinformation == 0">
|
||||
<view class="delete-price color-tip price-font" v-if="showMarketPrice(item)">
|
||||
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text>{{ showMarketPrice(item) }}</text>
|
||||
</view>
|
||||
<view class="block-wrap">
|
||||
<view class="sale color-tip" v-if="item.sale_show">{{ $lang('goods.sold', { num: item.sale_num, unit: item.unit || $lang('goods.defaultUnit') }) }}</view>
|
||||
</view>
|
||||
<view class="cart-action-wrap" v-if="config.control && item.is_virtual == 0">
|
||||
<!-- 购物车图标 -->
|
||||
<view v-if="config.style == 'icon-cart'" :style="{
|
||||
color: config.theme == 'diy' ? config.textColor : '',
|
||||
borderColor: config.theme == 'diy' ? config.textColor : ''
|
||||
}" class="cart shopping-cart-btn iconfont icon-gouwuche click-wrap" :id="'goods-' + item.id"
|
||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
||||
<view class="click-event"></view>
|
||||
</view>
|
||||
|
||||
<!--加号图标 -->
|
||||
<view v-else-if="config.style == 'icon-add'" :style="{
|
||||
color: config.theme == 'diy' ? config.textColor : '',
|
||||
borderColor: config.theme == 'diy' ? config.textColor : ''
|
||||
}" class="cart plus-sign-btn iconfont icon-add1 click-wrap" :id="'goods-' + item.id"
|
||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
||||
<view class="click-event"></view>
|
||||
</view>
|
||||
|
||||
<!-- 按钮 -->
|
||||
<view v-else-if="config.style == 'button'" :style="{
|
||||
backgroundColor: config.theme == 'diy' ? config.bgColor : '',
|
||||
color: config.theme == 'diy' ? config.textColor : '',
|
||||
fontWeight: config.theme == 'diy' ? (config.fontWeight ? 'bold' : 'normal') : '',
|
||||
padding: config.theme == 'diy' ? '12rpx ' + config.padding * 2 + 'rpx' : ''
|
||||
}" class="cart buy-btn click-wrap" :id="'goods-' + item.id"
|
||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
||||
{{ config.text }}
|
||||
<view class="click-event"></view>
|
||||
</view>
|
||||
|
||||
<!--自定义图标 -->
|
||||
<view v-else-if="config.style == 'icon-diy'" :style="{
|
||||
color: config.theme == 'diy' ? config.textColor : ''
|
||||
}" class="icon-diy click-wrap" :id="'goods-' + item.id"
|
||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
||||
<view class="click-event"></view>
|
||||
<diy-icon :icon="config.iconDiy.icon"
|
||||
:value="config.iconDiy.style ? config.iconDiy.style : null"></diy-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="goods-list double-column" :class="{ show: !isList }">
|
||||
<view class="goods-item margin-bottom" v-for="(item, index) in goodsList" :key="item.id"
|
||||
@click="toDetail(item)"
|
||||
:style="{ left: listPosition[index] ? listPosition[index].left : '', top: listPosition[index] ? listPosition[index].top : '' }">
|
||||
<view class="goods-img">
|
||||
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)" show-menu-by-longpress></image>
|
||||
<view class="color-base-bg goods-tag" v-if="goodsTag(item) != ''">{{ goodsTag(item) }}
|
||||
</view>
|
||||
<view class="sell-out" v-if="item.stock <= 0">
|
||||
<text class="iconfont icon-shuqing"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-wrap">
|
||||
<view class="goods-name"
|
||||
:class="[{ 'using-hidden': config.nameLineMode == 'single' }, { 'multi-hidden': config.nameLineMode == 'multiple' }]">
|
||||
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
|
||||
</view>
|
||||
|
||||
<view class="lineheight-clear">
|
||||
<view class="discount-price" v-if="item.isinformation == 0">
|
||||
<text class="unit price-style small">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="price price-style large">{{
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[0] }}</text>
|
||||
<text class="unit price-style small">.{{
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||
</view>
|
||||
<view class="discount-price" v-else>
|
||||
<text class="price price-style large">{{ $lang('goods.consultNow') }}</text>
|
||||
</view>
|
||||
<view class="member-price-tag"
|
||||
v-if="item.member_price && item.member_price == showPrice(item)">
|
||||
<image :src="$util.img('public/uniapp/index/VIP.png')" mode="widthFix" show-menu-by-longpress></image>
|
||||
</view>
|
||||
<view class="member-price-tag" v-else-if="item.promotion_type == 1">
|
||||
<image :src="$util.img('public/uniapp/index/discount.png')" mode="widthFix" show-menu-by-longpress></image>
|
||||
</view>
|
||||
<view class="delete-price color-tip price-font" v-if="showMarketPrice(item)">
|
||||
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text>{{ showMarketPrice(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pro-info" v-if="item.isinformation == 0">
|
||||
<view class="block-wrap">
|
||||
<view class="sale color-tip" v-if="item.sale_show">{{ $lang('goods.sold', { num: item.sale_num, unit: item.unit || $lang('goods.defaultUnit') }) }}</view>
|
||||
</view>
|
||||
<view class="cart-action-wrap" v-if="config.control && item.is_virtual == 0">
|
||||
<!-- 购物车图标 -->
|
||||
<view v-if="config.style == 'icon-cart'" :style="{
|
||||
color: config.theme == 'diy' ? config.textColor : '',
|
||||
borderColor: config.theme == 'diy' ? config.textColor : ''
|
||||
}" class="cart shopping-cart-btn iconfont icon-gouwuche click-wrap" :id="'goods-' + item.id"
|
||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
||||
<view class="click-event"></view>
|
||||
</view>
|
||||
|
||||
<!--加号图标 -->
|
||||
<view v-else-if="config.style == 'icon-add'" :style="{
|
||||
color: config.theme == 'diy' ? config.textColor : '',
|
||||
borderColor: config.theme == 'diy' ? config.textColor : ''
|
||||
}" class="cart plus-sign-btn iconfont icon-add1 click-wrap" :id="'goods-' + item.id"
|
||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
||||
<view class="click-event"></view>
|
||||
</view>
|
||||
|
||||
<!-- 按钮 -->
|
||||
<view v-else-if="config.style == 'button'" :style="{
|
||||
backgroundColor: config.theme == 'diy' ? config.bgColor : '',
|
||||
color: config.theme == 'diy' ? config.textColor : '',
|
||||
fontWeight: config.theme == 'diy' ? (config.fontWeight ? 'bold' : 'normal') : '',
|
||||
padding: config.theme == 'diy' ? '12rpx ' + config.padding * 2 + 'rpx' : ''
|
||||
}" class="cart buy-btn click-wrap" :id="'goods-' + item.id"
|
||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
||||
{{ config.text }}
|
||||
<view class="click-event"></view>
|
||||
</view>
|
||||
|
||||
<!--自定义图标 -->
|
||||
<view v-else-if="config.style == 'icon-diy'" :style="{
|
||||
color: config.theme == 'diy' ? config.textColor : ''
|
||||
}" class="icon-diy click-wrap" :id="'goods-' + item.id"
|
||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
||||
<view class="click-event"></view>
|
||||
<diy-icon :icon="config.iconDiy.icon"
|
||||
:value="config.iconDiy.style ? config.iconDiy.style : null"></diy-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="goodsList.length == 0 && emptyShow"><ns-empty :text="$lang('goods.noGoods')"></ns-empty></view>
|
||||
</block>
|
||||
</mescroll-uni>
|
||||
|
||||
<ns-goods-sku-index ref="goodsSkuIndex" @addCart="addCart"></ns-goods-sku-index>
|
||||
|
||||
<!-- 筛选弹出框 -->
|
||||
<uni-drawer :visible="showScreen" mode="right" @close="showScreen = false" class="screen-wrap">
|
||||
<view class="title color-tip">{{ $lang('filter.title') }}</view>
|
||||
<scroll-view scroll-y>
|
||||
<!-- 分类筛选项 -->
|
||||
<view class="category-list-wrap">
|
||||
<text class="first">{{ $lang('filter.allCategories') }}</text>
|
||||
<view class="class-box">
|
||||
<view @click="selectedCategory('')" class="list-wrap">
|
||||
<text :class="{ selected: !categoryId, 'color-base-text': !categoryId }">{{ $lang('filter.all') }}</text>
|
||||
</view>
|
||||
<view @click="selectedCategory(item.category_id)" v-for="(item, index) in categoryList"
|
||||
:key="index" class="list-wrap">
|
||||
<text
|
||||
:class="{ selected: item.category_id == categoryId, 'color-base-text': item.category_id == categoryId }">{{
|
||||
item.category_name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="footer" :class="{ 'safe-area': isIphoneX }">
|
||||
<button type="default" class="footer-box" @click="resetData">{{ $lang('filter.reset') }}</button>
|
||||
<button type="primary" class="footer-box1" @click="screenData">{{ $lang('filter.confirm') }}</button>
|
||||
</view>
|
||||
</uni-drawer>
|
||||
<loading-cover ref="loadingCover"></loading-cover>
|
||||
|
||||
<!-- 隐私弹窗 -->
|
||||
<privacy-popup ref="privacyPopup"></privacy-popup>
|
||||
|
||||
<!-- 底部tabBar -->
|
||||
<view id="tab-bar">
|
||||
<diy-bottom-nav></diy-bottom-nav>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import list from './public/js/list.js';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
mixins: [list],
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './public/css/list.scss';
|
||||
</style>
|
||||
<style scoped>
|
||||
>>>.uni-tag--primary.uni-tag--inverted {
|
||||
background-color: #f5f5f5 !important;
|
||||
}
|
||||
|
||||
::v-deep .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
max-height: unset !important;
|
||||
}
|
||||
</style>
|
||||
@@ -1125,18 +1125,18 @@ _handleStreamError(msg) {
|
||||
|
||||
generateAIResponse(userMessage) {
|
||||
const responses = {
|
||||
'你好': '您好!我是AI智能客服,很高兴为您服务!有什么可以帮助您的吗?',
|
||||
'价格': '我们的产品价格根据型号和配置有所不同,具体价格请查看商品详情页面。',
|
||||
'发货': '一般情况下,订单会在24小时内发货,具体时效请查看物流信息。',
|
||||
'退货': '支持7天无理由退货,请确保商品完好无损。',
|
||||
'客服': '我们的客服工作时间是9:00-18:00,有问题可以随时联系我们。'
|
||||
'你好': this.$lang('autoReplyGreeting'),
|
||||
'价格': this.$lang('autoReplyPrice'),
|
||||
'发货': this.$lang('autoReplyShipping'),
|
||||
'退货': this.$lang('autoReplyReturn'),
|
||||
'客服': this.$lang('autoReplyService')
|
||||
};
|
||||
for (let key in responses) {
|
||||
if (userMessage.includes(key)) {
|
||||
return responses[key];
|
||||
}
|
||||
}
|
||||
return `感谢您的咨询!关于"${userMessage}"的问题,我们的专业客服会尽快为您解答。您也可以查看我们的帮助文档获取更多信息。`;
|
||||
return this.$lang('autoReplyDefault', { question: userMessage });
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ export default {
|
||||
},
|
||||
|
||||
onShow() {
|
||||
console.log('[AI Chat Page] onShow 触发');
|
||||
console.log(this.$lang('logOnShowTriggered'));
|
||||
// 监听键盘高度变化(H5 可能不支持,try-catch 保护)
|
||||
try {
|
||||
this._keyboardChangeHandler = (res) => {
|
||||
@@ -154,7 +154,7 @@ export default {
|
||||
};
|
||||
uni.onKeyboardHeightChange(this._keyboardChangeHandler);
|
||||
} catch (e) {
|
||||
console.warn('onKeyboardHeightChange 不可用:', e.message);
|
||||
console.warn(this.$lang('logKeyboardChangeUnavailable') + ':', e.message);
|
||||
}
|
||||
// 每次页面显示时尝试加载历史记录(H5可能组件尚未创建,用 nextTick 确保 ref 就绪)
|
||||
this.$nextTick(() => {
|
||||
@@ -177,7 +177,7 @@ export default {
|
||||
},
|
||||
|
||||
onUnload() {
|
||||
console.log('[AI Chat Page] onUnload 触发');
|
||||
console.log(this.$lang('logOnUnloadTriggered'));
|
||||
this.cleanup();
|
||||
aiService.disconnectWebSocket();
|
||||
},
|
||||
@@ -233,7 +233,7 @@ export default {
|
||||
},
|
||||
|
||||
handleEventError(error, event) {
|
||||
console.error('事件处理错误:', {
|
||||
console.error(this.$lang('logEventHandleError') + ':', {
|
||||
error: error.message,
|
||||
eventType: event?.type,
|
||||
component: this. $options.name
|
||||
@@ -263,7 +263,7 @@ export default {
|
||||
this.calculateScrollViewHeight();
|
||||
this.setupNavigationEvents();
|
||||
} catch (error) {
|
||||
console.error('初始化导航栏失败:', error);
|
||||
console.error(this.$lang('logInitNavbarFailed') + ':', error);
|
||||
this.setFallbackNavigationValues();
|
||||
}
|
||||
},
|
||||
@@ -459,7 +459,7 @@ export default {
|
||||
|
||||
sendProductToAI(product) {
|
||||
if (!this.$refs.chat) {
|
||||
console.error('聊天组件未初始化')
|
||||
console.error(this.$lang('logChatComponentNotInit'))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -503,7 +503,7 @@ export default {
|
||||
|
||||
// 如果配置未加载,延迟重试(最多3次,防白屏)
|
||||
if (!servicerConfig) {
|
||||
console.warn('【AI客服】servicerConfig 未加载,200ms后重试...');
|
||||
console.warn(this.$lang('logServicerConfigNotLoaded'));
|
||||
setTimeout(() => {
|
||||
this.checkAccessPermission();
|
||||
}, 200);
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
<view class="page" :style="themeColor">
|
||||
<view class="help-title">{{ detail.article_title }}</view>
|
||||
<view class="help-meta" v-if="detail.is_show_release_time == 1">
|
||||
<text class="help-time">发表时间: {{ $util.timeStampTurnTime(detail.create_time) }}</text>
|
||||
<text class="help-time">{{ $lang('publishTime') }} {{ $util.timeStampTurnTime(detail.create_time) }}</text>
|
||||
</view>
|
||||
<view class="help-content"><rich-text :nodes="content"></rich-text></view>
|
||||
<view class="bottom-area">
|
||||
<view v-if="detail.is_show_read_num == 1">
|
||||
阅读:
|
||||
{{ $lang('readCount') }}
|
||||
<text class="price-font">{{ detail.read_num + detail.initial_read_num }}</text>
|
||||
</view>
|
||||
<view v-if="detail.is_show_dianzan_num == 1">
|
||||
<text class="price-font">{{ detail.dianzan_num + detail.initial_dianzan_num }}</text>
|
||||
人已赞
|
||||
{{ $lang('likedSuffix') }}
|
||||
</view>
|
||||
</view>
|
||||
<loading-cover ref="loadingCover"></loading-cover>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="empty-wrap"><ns-empty text="暂无文章" :isIndex="false"></ns-empty></view>
|
||||
<view v-else class="empty-wrap"><ns-empty :text="$lang('emptyText')" :isIndex="false"></ns-empty></view>
|
||||
<loading-cover ref="loadingCover"></loading-cover>
|
||||
</block>
|
||||
</mescroll-uni>
|
||||
@@ -88,7 +88,7 @@ export default {
|
||||
setPublicShare() {
|
||||
let shareUrl = this.$config.h5Domain + '/pages_tool/article/list';
|
||||
this.$util.setPublicShare({
|
||||
title: '文章列表',
|
||||
title: this.$lang('title'),
|
||||
desc: '',
|
||||
link: shareUrl,
|
||||
imgUrl: this.siteInfo ? this.$util.img(this.siteInfo.logo_square) : ''
|
||||
@@ -96,7 +96,7 @@ export default {
|
||||
}
|
||||
},
|
||||
onShareAppMessage(res) {
|
||||
var title = '文章列表';
|
||||
var title = this.$lang('title');
|
||||
var path = '/pages_tool/article/list';
|
||||
return {
|
||||
title: title,
|
||||
@@ -107,7 +107,7 @@ export default {
|
||||
},
|
||||
//分享到朋友圈
|
||||
onShareTimeline() {
|
||||
var title = '文章列表';
|
||||
var title = this.$lang('title');
|
||||
var query = '/pages_tool/article/list';
|
||||
return {
|
||||
title: title,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<view>
|
||||
<view class="search-wrap uni-flex uni-row">
|
||||
<view class="flex-item input-wrap">
|
||||
<input class="uni-input" maxlength="50" placeholder="请输入您要搜索的文件名称" v-model="keyword" @confirm="search"
|
||||
<input class="uni-input" maxlength="50" :placeholder="$lang('searchPlaceholder')" v-model="keyword" @confirm="search"
|
||||
@input="__set_model($event, 'keyword')" />
|
||||
<text class="iconfont icon-sousuo3" @tap="search"></text>
|
||||
</view>
|
||||
@@ -20,7 +20,7 @@
|
||||
<view class="info-wrap">
|
||||
<view class="title">{{ item.$orig.files_title }}</view>
|
||||
<view class="read-wrap">
|
||||
<text>查看PDF文件</text>
|
||||
<text>{{ $lang('viewPdf') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -29,7 +29,7 @@
|
||||
</block>
|
||||
<block v-else>
|
||||
<view class="empty-wrap">
|
||||
<ns-empty text="暂无文件" :isIndex="false"></ns-empty>
|
||||
<ns-empty :text="$lang('emptyText')" :isIndex="false"></ns-empty>
|
||||
</view>
|
||||
</block>
|
||||
<loading-cover ref="loadingCover"></loading-cover>
|
||||
@@ -116,7 +116,7 @@ export default {
|
||||
},
|
||||
toDetail(item) {
|
||||
uni.showLoading({
|
||||
title: '正在加载'
|
||||
title: this.$lang('loading')
|
||||
})
|
||||
try {
|
||||
uni.downloadFile({
|
||||
@@ -141,7 +141,7 @@ export default {
|
||||
complete: res => {
|
||||
if (res.statusCode === 404) {
|
||||
uni.showToast({
|
||||
title: '文件不存在',
|
||||
title: this.$lang('fileNotExist'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
<image :src="$util.img('public/uniapp/form/banner.png')" mode="widthFix"></image>
|
||||
</view>
|
||||
<view class="system-form-wrap">
|
||||
<view class="form-title">请填写表单所需信息</view>
|
||||
<view class="form-title">{{ $lang('form.form.title') }}</view>
|
||||
<ns-form :data="detail.json_data" :formConfig="detail.form_config" ref="form"></ns-form>
|
||||
<button type="primary" size="mini" class="button mini" @click="create()">提交</button>
|
||||
<button type="primary" size="mini" class="button mini" @click="create()">{{ $lang('common.submit') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
<ns-empty :text="complete ? '提交成功' : '未获取到表单信息'" v-else></ns-empty>
|
||||
<ns-empty :text="complete ? $lang('form.form.submitSuccess') : $lang('form.form.noFormInfo')" v-else></ns-empty>
|
||||
|
||||
<loading-cover ref="loadingCover"></loading-cover>
|
||||
<ns-login ref="login"></ns-login>
|
||||
@@ -88,7 +88,7 @@
|
||||
},
|
||||
success: res => {
|
||||
if (res.code == 0) {
|
||||
this.$util.showToast({ title: '提交成功' })
|
||||
this.$util.showToast({ title: this.$lang('form.form.submitSuccess') })
|
||||
setTimeout(() => {
|
||||
this.complete = true;
|
||||
this.detail = null;
|
||||
|
||||
380
pages_tool/member/bind_mobile.vue
Normal file
380
pages_tool/member/bind_mobile.vue
Normal file
@@ -0,0 +1,380 @@
|
||||
<template>
|
||||
<view :style="themeColor">
|
||||
<template v-if="memberInfo">
|
||||
<!-- 一键授权绑定区域(小程序环境) -->
|
||||
<!-- #ifdef MP -->
|
||||
<view v-if="!showManualForm" class="bind-wrap">
|
||||
<view class="bind-tip">
|
||||
<view class="tip-title">{{ $lang('bindMobile.tipTitle') }}</view>
|
||||
<view class="tip-desc">{{ $lang('bindMobile.bindBenefitTip') }}</view>
|
||||
</view>
|
||||
<view class="save-item bind-mobile">
|
||||
<button type="primary" open-type="getPhoneNumber" @getphonenumber="mobileAuth">{{ $lang('bindMobile.oneClickAuthBind') }}</button>
|
||||
</view>
|
||||
<view class="save-item bind-mobile">
|
||||
<button type="primary" @click="showManualForm = true">{{ $lang('bindMobile.manualBind') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- 手动绑定表单 -->
|
||||
<view class="edit-info">
|
||||
<!-- #ifdef MP -->
|
||||
<view v-if="showManualForm" class="form-switch-back" @click="showManualForm = false">
|
||||
<text>{{ $lang('bindMobile.oneClickAuthBind') }}</text>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<view class="edit-info-box">
|
||||
<text class="info-name">{{ $lang('bindMobile.phoneNumber') }}</text>
|
||||
<input class="uni-input info-content" type="number" maxlength="11" :placeholder="$lang('bindMobile.pleInputMobile')" v-model="formData.mobile" />
|
||||
</view>
|
||||
<view class="edit-info-box">
|
||||
<text class="info-name">{{ $lang('bindMobile.confirmCode') }}</text>
|
||||
<input class="uni-input info-content" type="number" maxlength="4" :placeholder="$lang('bindMobile.confirmCodeInput')" v-model="formData.mobileVercode" />
|
||||
<image :src="captcha.img" class="captcha" @click="getCaptcha" show-menu-by-longpress></image>
|
||||
</view>
|
||||
<view class="edit-info-box">
|
||||
<text class="info-name">{{ $lang('bindMobile.smsCode') }}</text>
|
||||
<input class="uni-input info-content" type="number" maxlength="6" :placeholder="$lang('bindMobile.animateCodeInput')" v-model="formData.mobileDynacode" />
|
||||
<button type="primary" class="dynacode" @click="bindMoblieCode()">{{ formData.mobileCodeText }}</button>
|
||||
</view>
|
||||
<view class="save-item" @click="bindMobile">
|
||||
<button type="primary">{{ $lang('bindMobile.save') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<ns-login ref="login"></ns-login>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import validate from '@/common/js/validate.js';
|
||||
import auth from '@/common/js/auth.js';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
showManualForm: false,
|
||||
formData: {
|
||||
mobile: '',
|
||||
mobileVercode: '',
|
||||
mobileDynacode: '',
|
||||
mobileCodeText: '',
|
||||
},
|
||||
seconds: 120,
|
||||
timer: null,
|
||||
isSend: false,
|
||||
captcha: {
|
||||
id: '',
|
||||
img: ''
|
||||
},
|
||||
};
|
||||
},
|
||||
mixins: [auth],
|
||||
onLoad() {
|
||||
this.formData.mobileCodeText = this.$lang('bindMobile.findanimateCode');
|
||||
this.getCaptcha();
|
||||
// #ifdef MP-WEIXIN
|
||||
this.getCode();
|
||||
// #endif
|
||||
},
|
||||
onShow() {
|
||||
if (!this.storeToken) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.login.open('/pages_tool/member/index');
|
||||
});
|
||||
}
|
||||
},
|
||||
onHide() {
|
||||
this.seconds = 120;
|
||||
this.formData.mobileCodeText = this.$lang('bindMobile.findanimateCode');
|
||||
this.isSend = false;
|
||||
clearInterval(this.timer);
|
||||
},
|
||||
watch: {
|
||||
seconds(value) {
|
||||
if (value == 0) {
|
||||
this.seconds = 120;
|
||||
this.formData.mobileCodeText = this.$lang('bindMobile.findanimateCode');
|
||||
this.isSend = false;
|
||||
clearInterval(this.timer);
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
themeColor() {
|
||||
return this.$store.state.themeStyle ? `--main_color:${this.$store.state.themeStyle.main_color}` : '';
|
||||
},
|
||||
themeStyle() {
|
||||
return this.$store.state.themeStyle || {};
|
||||
},
|
||||
memberInfo() {
|
||||
return this.$store.state.memberInfo || {};
|
||||
},
|
||||
storeToken() {
|
||||
return this.$store.state.token;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 获取图形验证码
|
||||
getCaptcha() {
|
||||
this.$api.sendRequest({
|
||||
url: '/api/captcha/captcha',
|
||||
data: {
|
||||
captcha_id: this.captcha.id
|
||||
},
|
||||
success: res => {
|
||||
if (res.code >= 0) {
|
||||
this.captcha = res.data;
|
||||
this.captcha.img = this.captcha.img.replace(/\r\n/g, '');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// 验证手机号
|
||||
vertifyMobile() {
|
||||
var rule = [{
|
||||
name: 'mobile',
|
||||
checkType: 'required',
|
||||
errorMsg: this.$lang('bindMobile.pleInputMobile')
|
||||
}, {
|
||||
name: 'mobile',
|
||||
checkType: 'phoneno',
|
||||
errorMsg: this.$lang('bindMobile.surePhoneNumber')
|
||||
}];
|
||||
var checkRes = validate.check(this.formData, rule);
|
||||
if (!checkRes) {
|
||||
this.$util.showToast({
|
||||
title: validate.error
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// 发送短信动态码
|
||||
async bindMoblieCode() {
|
||||
if (this.seconds != 120) return;
|
||||
var rule = [{
|
||||
name: 'mobile',
|
||||
checkType: 'phoneno',
|
||||
errorMsg: this.$lang('bindMobile.surePhoneNumber')
|
||||
},
|
||||
{
|
||||
name: 'mobileVercode',
|
||||
checkType: 'required',
|
||||
errorMsg: this.$lang('bindMobile.confirmCodeInput')
|
||||
},
|
||||
];
|
||||
|
||||
var checkRes = validate.check(this.formData, rule);
|
||||
|
||||
if (checkRes && !this.isSend) {
|
||||
this.isSend = true;
|
||||
this.$api.sendRequest({
|
||||
url: '/api/member/bindmobliecode',
|
||||
data: {
|
||||
mobile: this.formData.mobile,
|
||||
captcha_id: this.captcha.id,
|
||||
captcha_code: this.formData.mobileVercode
|
||||
},
|
||||
success: res => {
|
||||
let data = res.data;
|
||||
if (data.key) {
|
||||
if (this.seconds == 120 && this.timer == null) {
|
||||
this.timer = setInterval(() => {
|
||||
this.seconds--;
|
||||
this.formData.mobileCodeText = this.$lang('bindMobile.codeSent', { seconds: this.seconds });
|
||||
}, 1000);
|
||||
}
|
||||
uni.setStorageSync('mobile_key', data.key);
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
this.isSend = false;
|
||||
}
|
||||
},
|
||||
fail: res => {
|
||||
this.isSend = false;
|
||||
this.getCaptcha();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: validate.error ? validate.error : this.$lang('bindMobile.doNotRepeatedlyClick')
|
||||
});
|
||||
}
|
||||
},
|
||||
// 绑定手机号
|
||||
bindMobile() {
|
||||
if (!this.vertifyMobile()) return;
|
||||
|
||||
var mobileRule = [{
|
||||
name: 'mobileVercode',
|
||||
checkType: 'required',
|
||||
errorMsg: this.$lang('bindMobile.confirmCodeInput')
|
||||
},
|
||||
{
|
||||
name: 'mobileDynacode',
|
||||
checkType: 'required',
|
||||
errorMsg: this.$lang('bindMobile.animateCodeInput')
|
||||
},
|
||||
];
|
||||
var checkRes = validate.check(this.formData, mobileRule);
|
||||
|
||||
if (checkRes) {
|
||||
if (this.memberInfo.mobile && this.formData.mobile == this.memberInfo.mobile) {
|
||||
this.$util.showToast({
|
||||
title: this.$lang('bindMobile.alikePhone')
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.$api.sendRequest({
|
||||
url: '/api/member/modifymobile',
|
||||
data: {
|
||||
mobile: this.formData.mobile,
|
||||
captcha_id: this.captcha.id,
|
||||
captcha_code: this.formData.mobileVercode,
|
||||
code: this.formData.mobileDynacode,
|
||||
key: uni.getStorageSync("mobile_key"),
|
||||
},
|
||||
success: res => {
|
||||
if (res.code == 0) {
|
||||
this.memberInfo.mobile = this.formData.mobile;
|
||||
this.$store.commit('setMemberInfo', this.memberInfo);
|
||||
this.$util.showToast({
|
||||
title: this.$lang('bindMobile.bindSuccess')
|
||||
});
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
this.getCaptcha();
|
||||
}
|
||||
},
|
||||
fail: res => {
|
||||
this.isSend = false;
|
||||
this.getCaptcha();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: validate.error
|
||||
});
|
||||
}
|
||||
},
|
||||
// 一键授权绑定(小程序)
|
||||
mobileAuth(e) {
|
||||
if (e.detail.errMsg == 'getPhoneNumber:ok') {
|
||||
let data = e.detail
|
||||
// #ifdef MP-WEIXIN
|
||||
Object.assign(data, this.authInfo)
|
||||
// #endif
|
||||
this.$api.sendRequest({
|
||||
url: '/api/member/mobileauth',
|
||||
data,
|
||||
success: res => {
|
||||
if (res.code == 0) {
|
||||
this.$util.showToast({
|
||||
title: this.$lang('bindMobile.bindSuccess')
|
||||
});
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.bind-wrap {
|
||||
padding: 60rpx 40rpx;
|
||||
}
|
||||
|
||||
.bind-tip {
|
||||
text-align: center;
|
||||
margin-bottom: 60rpx;
|
||||
|
||||
.tip-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.tip-desc {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-info-box {
|
||||
margin-top: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx 40rpx;
|
||||
min-height: 50rpx;
|
||||
background-color: #fff;
|
||||
|
||||
.info-name {
|
||||
width: 150rpx;
|
||||
font-size: 28rpx;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.info-content {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
font-size: 28rpx;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.dynacode {
|
||||
margin: 0;
|
||||
padding: 0 10rpx;
|
||||
width: 250rpx;
|
||||
height: 60rpx;
|
||||
font-size: 24rpx;
|
||||
line-height: 60rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.captcha {
|
||||
width: 170rpx;
|
||||
height: 50rpx;
|
||||
}
|
||||
|
||||
.save-item {
|
||||
margin-top: 50rpx;
|
||||
|
||||
button {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.bind-mobile {
|
||||
button {
|
||||
border-radius: 60rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.form-switch-back {
|
||||
text-align: center;
|
||||
padding: 20rpx;
|
||||
font-size: 26rpx;
|
||||
color: var(--main_color);
|
||||
}
|
||||
</style>
|
||||
@@ -10,9 +10,9 @@
|
||||
<view class="align-center agreement-btn-select">
|
||||
<text v-if="isSelect" class="iconfont icon-dui color-base-text" @click="changeSelect"></text>
|
||||
<text v-else class="iconfont icon-yuan_checkbox" @click="changeSelect"></text>
|
||||
<text class="agreement-text" @click="changeSelect">勾选即表示您已阅读并同意本协议</text>
|
||||
<text class="agreement-text" @click="changeSelect">{{ $lang('agreeTermsText') }}</text>
|
||||
</view>
|
||||
<button class="btn color-base-bg" @click="next">下一步</button>
|
||||
<button class="btn color-base-bg" @click="next">{{ $lang('nextStep') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -60,7 +60,7 @@ export default {
|
||||
this.$util.redirectTo('/pages_tool/member/assets');
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: '请先勾选同意协议'
|
||||
title: this.$lang('pleaseAgreeFirst')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
314
pages_tool/member/card_log.vue
Normal file
314
pages_tool/member/card_log.vue
Normal file
@@ -0,0 +1,314 @@
|
||||
<template>
|
||||
<view :style="themeColor">
|
||||
<!-- 顶部统计 -->
|
||||
<view class="stat-header">
|
||||
<view class="stat-item">
|
||||
<view class="stat-value">{{ cardStat.total_consume }}</view>
|
||||
<view class="stat-label">{{ $lang('totalConsume') }}{{ $lang('statUnit', { unit: $lang('yuanSuffix') }) }}</view>
|
||||
</view>
|
||||
<view class="stat-divider"></view>
|
||||
<view class="stat-item">
|
||||
<view class="stat-value">{{ cardStat.balance }}</view>
|
||||
<view class="stat-label">{{ $lang('cardBalance') }}{{ $lang('statUnit', { unit: $lang('yuanSuffix') }) }}</view>
|
||||
</view>
|
||||
<view class="stat-divider"></view>
|
||||
<view class="stat-item">
|
||||
<view class="stat-value">{{ cardStat.total_recharge }}</view>
|
||||
<view class="stat-label">{{ $lang('totalRecharge') }}{{ $lang('statUnit', { unit: $lang('yuanSuffix') }) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 筛选 tab -->
|
||||
<scroll-view class="filter-tab" :scroll-x="true" :show-scrollbar="false">
|
||||
<view v-for="(item, index) in filterList" :key="index"
|
||||
class="tab-item" :class="{ active: currentFilter === item.value }"
|
||||
@click="onFilterChange(item.value)">
|
||||
<text>{{ item.label }}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 列表 -->
|
||||
<mescroll-uni @getData="getData" ref="mescroll">
|
||||
<block slot="list">
|
||||
<block v-if="logList.length > 0">
|
||||
<view class="log-list">
|
||||
<view class="log-item" v-for="(item, index) in logList" :key="index" @click="goDetail(item)">
|
||||
<view class="log-icon" :class="item.type">
|
||||
<text class="iconfont" :class="getIconClass(item.type)"></text>
|
||||
</view>
|
||||
<view class="log-info">
|
||||
<view class="log-title">{{ item.title }}</view>
|
||||
<view class="log-desc">{{ item.desc }}</view>
|
||||
<view class="log-time">{{ formatTime(item.create_time) }}</view>
|
||||
</view>
|
||||
<view class="log-amount">
|
||||
<text :class="item.amount > 0 ? 'income' : 'expense'">
|
||||
{{ item.amount > 0 ? '+' : '' }}{{ $lang('amountWithUnit', { amount: item.amount }) }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<ns-empty :isIndex="false" :text="$lang('emptyTips')"></ns-empty>
|
||||
</block>
|
||||
</block>
|
||||
</mescroll-uni>
|
||||
|
||||
<ns-login ref="login"></ns-login>
|
||||
<loading-cover ref="loadingCover"></loading-cover>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
cardStat: {
|
||||
total_consume: '0.00',
|
||||
balance: '0.00',
|
||||
total_recharge: '0.00'
|
||||
},
|
||||
logList: [],
|
||||
filterList: [
|
||||
{ label: this.$lang('filterAll'), value: 'all' },
|
||||
{ label: this.$lang('filterIncome'), value: 'income' },
|
||||
{ label: this.$lang('filterExpense'), value: 'expense' },
|
||||
{ label: this.$lang('filterRecharge'), value: 'recharge' },
|
||||
{ label: this.$lang('filterConsume'), value: 'consume' },
|
||||
{ label: this.$lang('filterGift'), value: 'gift' }
|
||||
],
|
||||
currentFilter: 'all'
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
if (!this.storeToken) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.login.open('/pages_tool/member/card_log');
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.loadStat();
|
||||
},
|
||||
methods: {
|
||||
// 加载统计数据
|
||||
loadStat() {
|
||||
this.$api.sendRequest({
|
||||
url: '/api/membercard/stat',
|
||||
success: res => {
|
||||
if (res.code == 0 && res.data) {
|
||||
this.cardStat = res.data;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// 筛选切换
|
||||
onFilterChange(value) {
|
||||
this.currentFilter = value;
|
||||
this.$refs.mescroll.refresh();
|
||||
},
|
||||
// 获取图标 class
|
||||
getIconClass(type) {
|
||||
const iconMap = {
|
||||
recharge: 'icon-chongzhi',
|
||||
consume: 'icon-xiaofei',
|
||||
gift: 'icon-liwu',
|
||||
refund: 'icon-tuikuan'
|
||||
};
|
||||
return iconMap[type] || 'icon-jifen';
|
||||
},
|
||||
// 格式化时间
|
||||
formatTime(timestamp) {
|
||||
return this.$util.timeStampTurnTime(timestamp);
|
||||
},
|
||||
// 跳转详情
|
||||
goDetail(item) {
|
||||
if (item.related_type === 'order') {
|
||||
this.$util.redirectTo('/pages_order/detail', { order_id: item.related_id });
|
||||
}
|
||||
},
|
||||
// 获取列表数据
|
||||
getData(mescroll) {
|
||||
this.$api.sendRequest({
|
||||
url: '/api/membercard/logPage',
|
||||
data: {
|
||||
page_size: mescroll.size,
|
||||
page: mescroll.num,
|
||||
type: this.currentFilter
|
||||
},
|
||||
success: res => {
|
||||
let newArr = [];
|
||||
if (res.code == 0 && res.data) {
|
||||
newArr = res.data.list;
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
}
|
||||
mescroll.endSuccess(newArr.length);
|
||||
if (mescroll.num == 1) {
|
||||
this.logList = [];
|
||||
}
|
||||
this.logList = this.logList.concat(newArr);
|
||||
if (this.$refs.loadingCover) this.$refs.loadingCover.hide();
|
||||
},
|
||||
fail: res => {
|
||||
mescroll.endErr();
|
||||
if (this.$refs.loadingCover) this.$refs.loadingCover.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.stat-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
background: linear-gradient(135deg, #e3b66b 0%, #d4a04a 100%);
|
||||
color: #fff;
|
||||
|
||||
.stat-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
|
||||
.stat-value {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
opacity: 0.85;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-divider {
|
||||
width: 1rpx;
|
||||
height: 60rpx;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.filter-tab {
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
background: #fff;
|
||||
border-bottom: 1rpx solid $color-line;
|
||||
|
||||
.tab-item {
|
||||
display: inline-block;
|
||||
padding: 24rpx 32rpx;
|
||||
font-size: $font-size-base;
|
||||
color: $color-tip;
|
||||
position: relative;
|
||||
|
||||
&.active {
|
||||
color: $color-base-text;
|
||||
font-weight: 500;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 40rpx;
|
||||
height: 4rpx;
|
||||
background: $color-base-text;
|
||||
border-radius: 2rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.log-list {
|
||||
padding: 0 32rpx;
|
||||
background: #fff;
|
||||
|
||||
.log-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 28rpx 0;
|
||||
border-bottom: 1rpx solid $color-line;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.log-icon {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 24rpx;
|
||||
font-size: 32rpx;
|
||||
|
||||
&.recharge {
|
||||
background: rgba(76, 175, 80, 0.1);
|
||||
color: #4caf50;
|
||||
}
|
||||
|
||||
&.consume {
|
||||
background: rgba(244, 67, 54, 0.1);
|
||||
color: #f44336;
|
||||
}
|
||||
|
||||
&.gift {
|
||||
background: rgba(255, 152, 0, 0.1);
|
||||
color: #ff9800;
|
||||
}
|
||||
|
||||
&.refund {
|
||||
background: rgba(33, 150, 243, 0.1);
|
||||
color: #2196f3;
|
||||
}
|
||||
}
|
||||
|
||||
.log-info {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.log-title {
|
||||
font-size: $font-size-base;
|
||||
color: $color-base-text;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.log-desc {
|
||||
font-size: $font-size-activity-tag;
|
||||
color: $color-tip;
|
||||
margin-bottom: 8rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.log-time {
|
||||
font-size: $font-size-activity-tag;
|
||||
color: $color-tip;
|
||||
}
|
||||
}
|
||||
|
||||
.log-amount {
|
||||
margin-left: 20rpx;
|
||||
font-size: $font-size-toolbar;
|
||||
font-weight: 500;
|
||||
|
||||
.income {
|
||||
color: #4caf50;
|
||||
}
|
||||
|
||||
.expense {
|
||||
color: $color-base-text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -13,7 +13,7 @@
|
||||
<view class="goods_name font-size-base">{{ item.sku_name }}</view>
|
||||
<view class="goods_opection">
|
||||
<view class="left lineheight-clear ">
|
||||
<text class="symbol price-style small">¥</text>
|
||||
<text class="symbol price-style small">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="price price-style large">{{
|
||||
parseFloat(item.discount_price).toFixed(2).split('.')[0] }}</text>
|
||||
<text class="symbol price-style small">.{{
|
||||
@@ -30,7 +30,7 @@
|
||||
</block>
|
||||
<!-- 第一个列表为空时 -->
|
||||
<view class="collection-empty" v-else>
|
||||
<ns-empty v-if="collectionList.length == 0 && isShowEmpty" text="暂无关注的商品" subText="赶紧去逛逛, 关注心仪的商品吧"
|
||||
<ns-empty v-if="collectionList.length == 0 && isShowEmpty" :text="$lang('member.collection.emptyText')" :subText="$lang('member.collection.emptySubText')"
|
||||
: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') }}</button>
|
||||
|
||||
@@ -11,16 +11,16 @@
|
||||
<view class="opection-box">
|
||||
<block v-if="newImg == ''">
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<button type="primary" @click="uploadFace()">点击上传</button>
|
||||
<button type="primary" @click="uploadFace()">{{$lang('member.modifyFace.clickToUpload')}}</button>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef MP-ALIPAY -->
|
||||
<button type="primary" @click="chooseImage()">点击上传</button>
|
||||
<button type="primary" @click="chooseImage()">{{$lang('member.modifyFace.clickToUpload')}}</button>
|
||||
<!-- #endif -->
|
||||
</block>
|
||||
<block v-else>
|
||||
<view class="opec">
|
||||
<button size="mini" class="mini" type="primary" @click="save()">确认保存</button>
|
||||
<button size="mini" class="mini" type="primary" @click="chooseImage()">重新上传</button>
|
||||
<button size="mini" class="mini" type="primary" @click="save()">{{$lang('member.modifyFace.confirmSave')}}</button>
|
||||
<button size="mini" class="mini" type="primary" @click="chooseImage()">{{$lang('member.modifyFace.reupload')}}</button>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
@@ -92,7 +92,7 @@ export default {
|
||||
},
|
||||
fail: () => {
|
||||
this.$util.showToast({
|
||||
title: '头像上传失败'
|
||||
title: this.$lang('member.modifyFace.uploadFailed')
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -114,7 +114,7 @@ export default {
|
||||
this.memberInfo.headimg = this.imgurl;
|
||||
this.$store.commit('setMemberInfo', this.memberInfo);
|
||||
this.$util.showToast({
|
||||
title: '头像修改成功'
|
||||
title: this.$lang('member.modifyFace.modifySuccess')
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.$util.redirectTo('/pages_tool/member/info', {}, 'redirectTo');
|
||||
|
||||
@@ -53,7 +53,7 @@ export default {
|
||||
success: res => {
|
||||
if (res.code == 0) {
|
||||
this.$util.showToast({
|
||||
title: "删除成功"
|
||||
title: this.$lang('member.collection.deleteSuccess')
|
||||
})
|
||||
let array = this.collectionList;
|
||||
let newArray = array.filter((v) => {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<ns-empty :isIndex="false" text="暂无提现记录"></ns-empty>
|
||||
<ns-empty :isIndex="false" :text="$lang('emptyTips')"></ns-empty>
|
||||
</block>
|
||||
</view>
|
||||
</mescroll-uni>
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
<view class="goods-num">
|
||||
<view class="num-text color-base-text">{{ item.refund_status_name }}</view>
|
||||
<view class="num-price">
|
||||
<text>¥{{ item.price }}</text>
|
||||
<text>{{ $lang('common.currencySymbol') }}{{ item.price }}</text>
|
||||
<text class="num">×{{ item.num }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="goods-btn">
|
||||
<view class="btn-text">
|
||||
<text>{{ $lang('totalItems', { num: item.num }) }}</text>
|
||||
|
||||
518
pages_tool/order/invoice.vue
Normal file
518
pages_tool/order/invoice.vue
Normal file
@@ -0,0 +1,518 @@
|
||||
<template>
|
||||
<view :style="themeColor" class="invoice-container">
|
||||
<view class="invoice-header">
|
||||
<view class="header-title">{{ $lang('header.title') }}</view>
|
||||
<view class="header-desc">{{ $lang('header.desc') }}</view>
|
||||
</view>
|
||||
|
||||
<view class="invoice-section">
|
||||
<view class="section-title">{{ $lang('invoiceType.title') }}</view>
|
||||
<view class="invoice-type-list">
|
||||
<view
|
||||
class="type-item"
|
||||
:class="{ active: formData.invoice_type == 1 }"
|
||||
@click="selectType(1)"
|
||||
>
|
||||
<view class="type-icon">
|
||||
<text class="iconfont icon-zhifubao"></text>
|
||||
</view>
|
||||
<view class="type-name">{{ $lang('invoiceType.paper') }}</view>
|
||||
<view class="type-desc">{{ $lang('invoiceType.paperDesc') }}</view>
|
||||
</view>
|
||||
<view
|
||||
class="type-item"
|
||||
:class="{ active: formData.invoice_type == 2 }"
|
||||
@click="selectType(2)"
|
||||
>
|
||||
<view class="type-icon">
|
||||
<text class="iconfont icon-weixinzhifu"></text>
|
||||
</view>
|
||||
<view class="type-name">{{ $lang('invoiceType.electronic') }}</view>
|
||||
<view class="type-desc">{{ $lang('invoiceType.electronicDesc') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="invoice-section">
|
||||
<view class="section-title">{{ $lang('invoiceTitle.title') }}</view>
|
||||
<view class="title-type-switch">
|
||||
<view
|
||||
class="switch-item"
|
||||
:class="{ active: formData.invoice_title_type == 1 }"
|
||||
@click="selectTitleType(1)"
|
||||
>
|
||||
{{ $lang('invoiceTitle.personal') }}
|
||||
</view>
|
||||
<view
|
||||
class="switch-item"
|
||||
:class="{ active: formData.invoice_title_type == 2 }"
|
||||
@click="selectTitleType(2)"
|
||||
>
|
||||
{{ $lang('invoiceTitle.company') }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
{{ $lang('invoiceTitle.label') }}
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
type="text"
|
||||
v-model="formData.invoice_title"
|
||||
:placeholder="formData.invoice_title_type == 1 ? $lang('invoiceTitle.personalPlaceholder') : $lang('invoiceTitle.companyPlaceholder')"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item" v-if="formData.invoice_title_type == 2">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
{{ $lang('invoiceTitle.taxpayerId') }}
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
type="text"
|
||||
v-model="formData.taxpayer_id"
|
||||
:placeholder="$lang('invoiceTitle.taxpayerIdPlaceholder')"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="invoice-section">
|
||||
<view class="section-title">{{ $lang('invoiceContent.title') }}</view>
|
||||
<view class="form-item">
|
||||
<view class="form-label">{{ $lang('invoiceContent.label') }}</view>
|
||||
<picker mode="selector" :range="invoiceContentList" range-key="name" @change="onContentChange">
|
||||
<view class="picker-value">
|
||||
<text v-if="formData.invoice_content">{{ formData.invoice_content }}</text>
|
||||
<text class="placeholder" v-else>{{ $lang('invoiceContent.placeholder') }}</text>
|
||||
<text class="iconfont icon-youjiantou"></text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="invoice-section" v-if="formData.invoice_type == 1">
|
||||
<view class="section-title">{{ $lang('mailInfo.title') }}</view>
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
{{ $lang('mailInfo.receiver') }}
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
type="text"
|
||||
v-model="formData.receiver_name"
|
||||
:placeholder="$lang('mailInfo.receiverPlaceholder')"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
{{ $lang('mailInfo.mobile') }}
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
type="number"
|
||||
v-model="formData.receiver_mobile"
|
||||
:placeholder="$lang('mailInfo.mobilePlaceholder')"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
{{ $lang('mailInfo.address') }}
|
||||
</view>
|
||||
<pick-regions :level="3" @finish="onRegionFinish">
|
||||
<view class="picker-value">
|
||||
<text v-if="formData.region">{{ formData.region }}</text>
|
||||
<text class="placeholder" v-else>{{ $lang('mailInfo.regionPlaceholder') }}</text>
|
||||
<text class="iconfont icon-youjiantou"></text>
|
||||
</view>
|
||||
</pick-regions>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
{{ $lang('mailInfo.detailAddress') }}
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
type="text"
|
||||
v-model="formData.address"
|
||||
:placeholder="$lang('mailInfo.detailAddressPlaceholder')"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="invoice-section" v-if="formData.invoice_type == 2">
|
||||
<view class="section-title">{{ $lang('emailInfo.title') }}</view>
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
{{ $lang('emailInfo.receiverEmail') }}
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
type="text"
|
||||
v-model="formData.invoice_email"
|
||||
:placeholder="$lang('emailInfo.emailPlaceholder')"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="invoice-fee" v-if="invoiceData && invoiceData.invoice_money > 0">
|
||||
<view class="fee-item">
|
||||
<text class="fee-label">{{ $lang('fee.taxFee') }}</text>
|
||||
<text class="fee-value">¥{{ invoiceData.invoice_money }}</text>
|
||||
</view>
|
||||
<view class="fee-item" v-if="formData.invoice_type == 1 && invoiceData.invoice_delivery_money > 0">
|
||||
<text class="fee-label">{{ $lang('fee.deliveryFee') }}</text>
|
||||
<text class="fee-value">¥{{ invoiceData.invoice_delivery_money }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="invoice-footer">
|
||||
<view class="footer-tip">{{ $lang('footer.tip', { days: 3 }) }}</view>
|
||||
<view class="submit-btn" @click="submitInvoice">{{ $lang('footer.submit') }}</view>
|
||||
</view>
|
||||
|
||||
<loading-cover ref="loadingCover"></loading-cover>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
orderId: 0,
|
||||
formData: {
|
||||
invoice_type: 2,
|
||||
invoice_title_type: 1,
|
||||
invoice_title: '',
|
||||
taxpayer_id: '',
|
||||
invoice_content: '',
|
||||
receiver_name: '',
|
||||
receiver_mobile: '',
|
||||
region: '',
|
||||
region_id: '',
|
||||
address: '',
|
||||
invoice_email: ''
|
||||
},
|
||||
invoiceContentList: [],
|
||||
invoiceData: null
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.order_id) {
|
||||
this.orderId = options.order_id;
|
||||
}
|
||||
this.getInvoiceConfig();
|
||||
},
|
||||
methods: {
|
||||
selectType(type) {
|
||||
this.formData.invoice_type = type;
|
||||
},
|
||||
selectTitleType(type) {
|
||||
this.formData.invoice_title_type = type;
|
||||
this.formData.invoice_title = '';
|
||||
this.formData.taxpayer_id = '';
|
||||
},
|
||||
onContentChange(e) {
|
||||
const index = e.detail.value;
|
||||
if (this.invoiceContentList[index]) {
|
||||
this.formData.invoice_content = this.invoiceContentList[index].name;
|
||||
}
|
||||
},
|
||||
onRegionFinish(region) {
|
||||
this.formData.region = region.name;
|
||||
this.formData.region_id = region.id;
|
||||
},
|
||||
getInvoiceConfig() {
|
||||
this.$api.sendRequest({
|
||||
url: '/api/orderinvoice/config',
|
||||
data: {
|
||||
order_id: this.orderId
|
||||
},
|
||||
success: res => {
|
||||
if (res.code == 0 && res.data) {
|
||||
this.invoiceData = res.data;
|
||||
this.invoiceContentList = res.data.content_list || [];
|
||||
if (res.data.invoice_info) {
|
||||
Object.assign(this.formData, res.data.invoice_info);
|
||||
}
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message || this.$lang('api.getConfigFailed')
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
validateForm() {
|
||||
if (!this.formData.invoice_title) {
|
||||
this.$util.showToast({
|
||||
title: this.$lang('validation.pleaseEnterTitle')
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (this.formData.invoice_title_type == 2 && !this.formData.taxpayer_id) {
|
||||
this.$util.showToast({
|
||||
title: this.$lang('validation.pleaseEnterTaxpayerId')
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!this.formData.invoice_content) {
|
||||
this.$util.showToast({
|
||||
title: this.$lang('validation.pleaseSelectContent')
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (this.formData.invoice_type == 1) {
|
||||
if (!this.formData.receiver_name) {
|
||||
this.$util.showToast({
|
||||
title: this.$lang('validation.pleaseEnterReceiver')
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!this.formData.receiver_mobile) {
|
||||
this.$util.showToast({
|
||||
title: this.$lang('validation.pleaseEnterMobile')
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!this.formData.region_id) {
|
||||
this.$util.showToast({
|
||||
title: this.$lang('validation.pleaseSelectRegion')
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!this.formData.address) {
|
||||
this.$util.showToast({
|
||||
title: this.$lang('validation.pleaseEnterAddress')
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (this.formData.invoice_type == 2) {
|
||||
if (!this.formData.invoice_email) {
|
||||
this.$util.showToast({
|
||||
title: this.$lang('validation.pleaseEnterEmail')
|
||||
});
|
||||
return false;
|
||||
}
|
||||
const emailReg = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/;
|
||||
if (!emailReg.test(this.formData.invoice_email)) {
|
||||
this.$util.showToast({
|
||||
title: this.$lang('validation.invalidEmail')
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
submitInvoice() {
|
||||
if (!this.validateForm()) return;
|
||||
this.$refs.loadingCover.show();
|
||||
this.$api.sendRequest({
|
||||
url: '/api/orderinvoice/submit',
|
||||
data: {
|
||||
order_id: this.orderId,
|
||||
...this.formData
|
||||
},
|
||||
success: res => {
|
||||
this.$refs.loadingCover.hide();
|
||||
if (res.code >= 0) {
|
||||
this.$util.showToast({
|
||||
title: this.$lang('api.submitSuccess')
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message || this.$lang('api.submitFailed')
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
this.$refs.loadingCover.hide();
|
||||
this.$util.showToast({
|
||||
title: this.$lang('api.networkError')
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.invoice-container {
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
padding-bottom: 200rpx;
|
||||
}
|
||||
.invoice-header {
|
||||
background: #fff;
|
||||
padding: 40rpx 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
.header-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.header-desc {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
.invoice-section {
|
||||
background: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
padding: 30rpx;
|
||||
.section-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
}
|
||||
.invoice-type-list {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
.type-item {
|
||||
flex: 1;
|
||||
border: 2rpx solid #e5e5e5;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx 20rpx;
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
&.active {
|
||||
border-color: #ff6a3d;
|
||||
background: #fff5f0;
|
||||
}
|
||||
.type-icon {
|
||||
font-size: 48rpx;
|
||||
margin-bottom: 10rpx;
|
||||
color: #ff6a3d;
|
||||
}
|
||||
.type-name {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.type-desc {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
.title-type-switch {
|
||||
display: flex;
|
||||
border: 2rpx solid #e5e5e5;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 30rpx;
|
||||
overflow: hidden;
|
||||
.switch-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
&.active {
|
||||
background: #ff6a3d;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.form-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 24rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.form-label {
|
||||
width: 200rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
flex-shrink: 0;
|
||||
.required {
|
||||
color: #ff4d4f;
|
||||
margin-right: 4rpx;
|
||||
}
|
||||
}
|
||||
.form-input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
text-align: right;
|
||||
}
|
||||
.picker-value {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
.placeholder {
|
||||
color: #ccc;
|
||||
}
|
||||
.icon-youjiantou {
|
||||
font-size: 24rpx;
|
||||
color: #ccc;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.invoice-fee {
|
||||
background: #fff;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
.fee-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10rpx 0;
|
||||
.fee-label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
.fee-value {
|
||||
font-size: 28rpx;
|
||||
color: #ff4d4f;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
.invoice-footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
padding: 20rpx 30rpx;
|
||||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
.footer-tip {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.submit-btn {
|
||||
background: linear-gradient(90deg, #ff8a3d, #ff6a3d);
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
text-align: center;
|
||||
padding: 24rpx 0;
|
||||
border-radius: 40rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -34,11 +34,11 @@
|
||||
<view class="company-logo"><image :src="$util.img(packageItem.express_company_image)" show-menu-by-longpress></image></view>
|
||||
<view class="info">
|
||||
<view class="company">
|
||||
<text>承运公司: {{ packageItem.express_company_name }}</text>
|
||||
<text>{{ $lang('order.logistics.expressCompany') }}{{ packageItem.express_company_name }}</text>
|
||||
</view>
|
||||
<view class="no">
|
||||
<text>
|
||||
运单号:
|
||||
{{ $lang('order.logistics.trackingNo') }}
|
||||
<text class="color-tip">{{ packageItem.delivery_no }}</text>
|
||||
</text>
|
||||
<text class="iconfont icon-fuzhi" @click="copyDeliveryNo(packageItem.delivery_no)"></text>
|
||||
@@ -124,7 +124,7 @@ export default {
|
||||
if (this.$refs.loadingCover) this.$refs.loadingCover.hide();
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: '未获取到订单信息!'
|
||||
title: this.$lang('order.logistics.orderInfoNotFound')
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.$util.redirectTo('/pages_order/list');
|
||||
|
||||
@@ -7,8 +7,8 @@ export default {
|
||||
*/
|
||||
cancleRefund(order_goods_id, callback) {
|
||||
uni.showModal({
|
||||
content: '撤销之后本次申请将会关闭,如后续仍有问题可再次发起申请。',
|
||||
cancelText: '暂不撤销',
|
||||
content: this.$lang('cancelRefund.content'),
|
||||
cancelText: this.$lang('cancelRefund.cancelText'),
|
||||
cancelColor: '#898989',
|
||||
success: res => {
|
||||
if (res.confirm) {
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
</view>
|
||||
<block v-if="g0>0">
|
||||
<view class="foot">
|
||||
<view @tap="generateImage" class="item" style="margin-right:30rpx;">{{ $lang('exportImage') }}</view>
|
||||
<view @tap="generatePdf" class="item">{{ $lang('exportPdf') }}</view>
|
||||
<view @tap="generateImage" class="item" style="margin-right:30rpx;">{{ $lang('seal.medium.detail.exportImage') }}</view>
|
||||
<view @tap="generatePdf" class="item">{{ $lang('seal.medium.detail.exportPdf') }}</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
@@ -39,7 +39,7 @@ export default {
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
this.title = this.$lang('title');
|
||||
this.title = this.$lang('seal.medium.detail.title');
|
||||
if (options.keyword) {
|
||||
this.keyword = options.keyword;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ export default {
|
||||
methods: {
|
||||
generatePdf() {
|
||||
const url = this.$util.img(this.info.files_url);
|
||||
uni.showLoading({ title: this.$lang('loading') });
|
||||
uni.showLoading({ title: this.$lang('seal.medium.detail.loading') });
|
||||
try {
|
||||
uni.downloadFile({
|
||||
url: url,
|
||||
@@ -71,7 +71,7 @@ export default {
|
||||
},
|
||||
complete: (res) => {
|
||||
if (res.statusCode === 404) {
|
||||
uni.showToast({ title: this.$lang('fileNotExist'), icon: 'none' });
|
||||
uni.showToast({ title: this.$lang('seal.medium.detail.fileNotExist'), icon: 'none' });
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -81,7 +81,7 @@ export default {
|
||||
},
|
||||
generateImage() {
|
||||
const url = this.$util.img(this.info.img_url);
|
||||
uni.showLoading({ title: this.$lang('loading') });
|
||||
uni.showLoading({ title: this.$lang('seal.medium.detail.loading') });
|
||||
uni.downloadFile({
|
||||
url: url,
|
||||
success: (res) => {
|
||||
@@ -90,21 +90,21 @@ export default {
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: res.tempFilePath,
|
||||
success: () => {
|
||||
this.$util.showToast({ title: this.$lang('saveSuccess') });
|
||||
this.$util.showToast({ title: this.$lang('seal.medium.detail.saveSuccess') });
|
||||
},
|
||||
fail: (err) => {
|
||||
if (err.errMsg !== 'saveImageToPhotosAlbum:fail auth deny' && err.errMsg !== 'saveImageToPhotosAlbum:fail:auth denied') {
|
||||
this.$util.showToast({ title: this.$lang('saveFailed') });
|
||||
this.$util.showToast({ title: this.$lang('seal.medium.detail.saveFailed') });
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$util.showToast({ title: this.$lang('downloadFailed') });
|
||||
this.$util.showToast({ title: this.$lang('seal.medium.detail.downloadFailed') });
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading();
|
||||
this.$util.showToast({ title: this.$lang('downloadFailed') });
|
||||
this.$util.showToast({ title: this.$lang('seal.medium.detail.downloadFailed') });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -367,10 +367,12 @@ function main() {
|
||||
return { text: result, inBlockComment };
|
||||
}
|
||||
|
||||
// 判断一行是否是 $lang 调用(已经国际化)
|
||||
// 判断一行是否是国际化调用(已经国际化)
|
||||
function isLangCall(line) {
|
||||
// 匹配 $lang(' 或 $lang("
|
||||
return /\$lang\(\s*['"]/.test(line);
|
||||
// 匹配 $lang(' 或 $lang(" 或 _t(' 或 _t(" 或 _getLang().lang(' 或 _getLang().lang("
|
||||
return /\$lang\(\s*['"]/.test(line)
|
||||
|| /_t\(\s*['"]/.test(line)
|
||||
|| /_getLang\(\)\.lang\(\s*['"]/.test(line);
|
||||
}
|
||||
|
||||
const hardcodeResults = [];
|
||||
|
||||
Reference in New Issue
Block a user