refactor: 完成多语言国际化全量替换与补充
1. 新增大量中英文语言包文件,覆盖自定义组件、页面、工具类的文案 2. 替换硬编码文本为多语言调用,统一全局文案管理 3. 优化语言包结构,拆分公共模块与业务模块 4. 修复部分语言加载与国际化适配问题
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user