refactor: 国际化文本迁移至全局 locales/messages.js
将组件级 i18n 对象重构为统一由全局 locales/messages.js 管理,确保中英文语言切换时正确显示对应文本。 - 新增 utils/i18n.js 国际化工具函数 - 更新 store/$t.mixin.js 翻译混入逻辑 - 迁移 pkgService、pkgBooking、pkgAccount、pkgExplore、pages 等共 58 个组件的中英文文本至全局消息表
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<view class="application-detail-page tn-safe-area-inset-bottom">
|
||||
<tn-nav-bar :isBack="true" :bottomShadow="false" backgroundColor="transparent">
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ t('navTitle') }}</view>
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ $tr('申请详情') }}</view>
|
||||
</tn-nav-bar>
|
||||
|
||||
<view class="page-main tn-padding" :style="{ paddingTop: vuex_custom_bar_height + 'px', paddingBottom: '48rpx' }">
|
||||
@@ -35,54 +35,54 @@
|
||||
<text :class="shouldPayDeposit(detail) ? 'tn-icon-warning-fill' : 'tn-icon-time-fill'"></text>
|
||||
</view>
|
||||
<view class="status-reminder-panel__content">
|
||||
<view class="status-reminder-panel__title">{{ t('statusReminderTitle') }}</view>
|
||||
<view class="status-reminder-panel__title">{{ $tr('当前进度提醒') }}</view>
|
||||
<view class="status-reminder-panel__text">{{ statusReminderText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="content-panel tn-margin-bottom-lg">
|
||||
<view class="panel-title">{{ t('basicInfoTitle') }}</view>
|
||||
<view class="panel-title">{{ $tr('基础信息') }}</view>
|
||||
<view class="meta-row tn-margin-top">
|
||||
<text class="meta-label">{{ t('applicationCodeLabel') }}</text>
|
||||
<text class="meta-label">{{ $tr('申请编号') }}</text>
|
||||
<view class="meta-action-wrap">
|
||||
<text class="meta-value">{{ detail.detailCode || '--' }}</text>
|
||||
<view v-if="detail.detailCode" class="copy-btn" @click="copyCode">
|
||||
<text class="tn-text-xs tn-text-bold">{{ t('copy') }}</text>
|
||||
<text class="tn-text-xs tn-text-bold">{{ $tr('复制') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="meta-row">
|
||||
<text class="meta-label">{{ t('applicationTypeLabel') }}</text>
|
||||
<text class="meta-label">{{ $tr('申请类型') }}</text>
|
||||
<text class="meta-value">{{ applicationTypeText }}</text>
|
||||
</view>
|
||||
<view class="meta-row">
|
||||
<text class="meta-label">{{ t('statusLabel') }}</text>
|
||||
<text class="meta-label">{{ $tr('当前状态') }}</text>
|
||||
<text class="meta-value">{{ statusText }}</text>
|
||||
</view>
|
||||
<view class="meta-row">
|
||||
<text class="meta-label">{{ t('applicantLabel') }}</text>
|
||||
<text class="meta-label">{{ $tr('申请人') }}</text>
|
||||
<text class="meta-value">{{ detail.userName || detail.phone || '--' }}</text>
|
||||
</view>
|
||||
<view class="meta-row">
|
||||
<text class="meta-label">{{ t('apartmentLabel') }}</text>
|
||||
<text class="meta-label">{{ $tr('所属公寓') }}</text>
|
||||
<text class="meta-value">{{ detail.intendedAreaName || '--' }}</text>
|
||||
</view>
|
||||
<view class="meta-row" v-if="detail.intendedRoomTypeName">
|
||||
<text class="meta-label">{{ isViewingApplication ? t('intendedRoomTypeLabel') : t('appliedRoomTypeLabel') }}</text>
|
||||
<text class="meta-label">{{ isViewingApplication ? $tr('意向房型') : $tr('申请房型') }}</text>
|
||||
<text class="meta-value">{{ detail.intendedRoomTypeName }}</text>
|
||||
</view>
|
||||
<view class="meta-row">
|
||||
<text class="meta-label">{{ isViewingApplication ? t('viewingTimeLabel') : t('leaseTermLabel') }}</text>
|
||||
<text class="meta-label">{{ isViewingApplication ? $tr('预约时间') : $tr('预计租期') }}</text>
|
||||
<text class="meta-value">{{ displayDateRange }}</text>
|
||||
</view>
|
||||
<view class="meta-row">
|
||||
<text class="meta-label">{{ t('submittedAtLabel') }}</text>
|
||||
<text class="meta-label">{{ $tr('提交时间') }}</text>
|
||||
<text class="meta-value">{{ formatDateTime(detail.createTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="content-panel tn-margin-bottom-lg" v-if="viewingMeta.length">
|
||||
<view class="panel-title">{{ t('viewingInfoTitle') }}</view>
|
||||
<view class="panel-title">{{ $tr('带看信息') }}</view>
|
||||
<view
|
||||
v-for="item in viewingMeta"
|
||||
:key="item.label"
|
||||
@@ -94,7 +94,7 @@
|
||||
</view>
|
||||
|
||||
<view class="content-panel tn-margin-bottom-lg">
|
||||
<view class="panel-title">{{ isViewingApplication ? t('applicationRemarkTitle') : t('remarkTitle') }}</view>
|
||||
<view class="panel-title">{{ isViewingApplication ? $tr('申请说明') : $tr('补充说明') }}</view>
|
||||
<view class="remark-panel tn-margin-top">
|
||||
<view
|
||||
v-for="(line, index) in remarkLines"
|
||||
@@ -108,7 +108,7 @@
|
||||
|
||||
<view class="action-row">
|
||||
<view class="ghost-btn" @click="goBackList">
|
||||
<text class="tn-text-bold">{{ t('backList') }}</text>
|
||||
<text class="tn-text-bold">{{ $tr('返回列表') }}</text>
|
||||
</view>
|
||||
<view
|
||||
v-if="canCancelOrder"
|
||||
@@ -116,7 +116,7 @@
|
||||
:class="{ 'danger-btn--loading': canceling }"
|
||||
@click.stop="handleCancelOrder"
|
||||
>
|
||||
<text class="tn-text-bold">{{ canceling ? t('cancelOrderLoading') : t('cancelOrder') }}</text>
|
||||
<text class="tn-text-bold">{{ canceling ? $tr('取消中...') : $tr('取消订单') }}</text>
|
||||
</view>
|
||||
<view
|
||||
v-if="currentStepActionText"
|
||||
@@ -130,14 +130,14 @@
|
||||
class="action-btn action-btn--ghost"
|
||||
@click.stop="refreshCurrentPage"
|
||||
>
|
||||
<text class="tn-text-bold">{{ t('refreshAction') }}</text>
|
||||
<text class="tn-text-bold">{{ $tr('刷新') }}</text>
|
||||
</view>
|
||||
<view
|
||||
v-else-if="canViewBill"
|
||||
class="action-btn"
|
||||
@click.stop="goToBillPage"
|
||||
>
|
||||
<text class="tn-text-bold">{{ t('viewBill') }}</text>
|
||||
<text class="tn-text-bold">{{ $tr('查看关联账单') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -221,112 +221,6 @@ function parseJsonStringMaybe(value) {
|
||||
}
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
zh: {
|
||||
navTitle: '申请详情',
|
||||
basicInfoTitle: '基础信息',
|
||||
applicationCodeLabel: '申请编号',
|
||||
copy: '复制',
|
||||
applicationTypeLabel: '申请类型',
|
||||
statusLabel: '当前状态',
|
||||
applicantLabel: '申请人',
|
||||
apartmentLabel: '所属公寓',
|
||||
intendedRoomTypeLabel: '意向房型',
|
||||
appliedRoomTypeLabel: '申请房型',
|
||||
viewingTimeLabel: '预约时间',
|
||||
leaseTermLabel: '预计租期',
|
||||
submittedAtLabel: '提交时间',
|
||||
viewingInfoTitle: '带看信息',
|
||||
applicationRemarkTitle: '申请说明',
|
||||
remarkTitle: '补充说明',
|
||||
backList: '返回列表',
|
||||
viewBill: '查看关联账单',
|
||||
viewingApplicationTitle: '预约看房申请',
|
||||
stayApplicationTitle: '入住申请',
|
||||
viewingApplicationType: '预约看房',
|
||||
stayApplicationType: '入住申请',
|
||||
statusPending: '待审核',
|
||||
statusApproved: '已通过',
|
||||
statusRejected: '已拒绝',
|
||||
statusFinished: '已结束',
|
||||
statusProcessing: '处理中',
|
||||
statusPendingPayment: '请支付定金',
|
||||
statusWaitingRoomAssign: '等待预订中心分配房间',
|
||||
statusReminderTitle: '当前进度提醒',
|
||||
emptyRemark: '暂无补充说明',
|
||||
codeCopied: '申请编号已复制',
|
||||
missingBillCode: '申请单编号缺失',
|
||||
missingContractNo: '合同编号缺失',
|
||||
checkinPendingHint: '宿管正在办理入住,请耐心等待',
|
||||
refreshAction: '刷新',
|
||||
cancelOrder: '取消订单',
|
||||
cancelOrderLoading: '取消中...',
|
||||
cancelOrderTitle: '取消订单',
|
||||
cancelOrderContent: '取消后将关闭当前未支付的定金订单,是否继续?',
|
||||
cancelOrderSuccess: '订单已取消',
|
||||
cancelOrderFailed: '取消订单失败',
|
||||
viewingTimeKey: '看房时间',
|
||||
leaseDurationKey: '预计租住时长',
|
||||
budgetKey: '租金预算',
|
||||
commuteKey: '工作/通勤地点',
|
||||
preferredAreaKey: '意向区域',
|
||||
preferredRoomTypeKey: '意向房型',
|
||||
paymentMethodKey: '支付方式',
|
||||
dateRangeJoiner: ' 至 '
|
||||
},
|
||||
en: {
|
||||
navTitle: 'Application Detail',
|
||||
basicInfoTitle: 'Basic Information',
|
||||
applicationCodeLabel: 'Application No.',
|
||||
copy: 'Copy',
|
||||
applicationTypeLabel: 'Application Type',
|
||||
statusLabel: 'Status',
|
||||
applicantLabel: 'Applicant',
|
||||
apartmentLabel: 'Apartment',
|
||||
intendedRoomTypeLabel: 'Preferred Room Type',
|
||||
appliedRoomTypeLabel: 'Requested Room Type',
|
||||
viewingTimeLabel: 'Viewing Time',
|
||||
leaseTermLabel: 'Lease Term',
|
||||
submittedAtLabel: 'Submitted At',
|
||||
viewingInfoTitle: 'Viewing Details',
|
||||
applicationRemarkTitle: 'Application Notes',
|
||||
remarkTitle: 'Remarks',
|
||||
backList: 'Back to List',
|
||||
viewBill: 'View Related Bill',
|
||||
viewingApplicationTitle: 'Viewing Request',
|
||||
stayApplicationTitle: 'Stay Application',
|
||||
viewingApplicationType: 'Viewing Request',
|
||||
stayApplicationType: 'Stay Application',
|
||||
statusPending: 'Pending',
|
||||
statusApproved: 'Approved',
|
||||
statusRejected: 'Rejected',
|
||||
statusFinished: 'Closed',
|
||||
statusProcessing: 'Processing',
|
||||
statusPendingPayment: 'Please Pay Deposit',
|
||||
statusWaitingRoomAssign: 'Waiting for Room Assignment',
|
||||
statusReminderTitle: 'Current Progress',
|
||||
emptyRemark: 'No additional remarks',
|
||||
codeCopied: 'Application number copied',
|
||||
missingBillCode: 'Missing application bill number',
|
||||
missingContractNo: 'Missing contract number',
|
||||
checkinPendingHint: 'Move-in is being processed, please wait',
|
||||
refreshAction: 'Refresh',
|
||||
cancelOrder: 'Cancel Order',
|
||||
cancelOrderLoading: 'Canceling...',
|
||||
cancelOrderTitle: 'Cancel Order',
|
||||
cancelOrderContent: 'This will close the current unpaid deposit order. Continue?',
|
||||
cancelOrderSuccess: 'Order canceled',
|
||||
cancelOrderFailed: 'Failed to cancel order',
|
||||
viewingTimeKey: 'Viewing Time',
|
||||
leaseDurationKey: 'Expected Stay Duration',
|
||||
budgetKey: 'Budget',
|
||||
commuteKey: 'Work / Commute Location',
|
||||
preferredAreaKey: 'Preferred Area',
|
||||
preferredRoomTypeKey: 'Preferred Room Type',
|
||||
paymentMethodKey: 'Payment Method',
|
||||
dateRangeJoiner: ' to '
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
detailCode: '',
|
||||
@@ -347,24 +241,24 @@ export default {
|
||||
},
|
||||
displayTitle() {
|
||||
if (this.isViewingApplication) {
|
||||
return this.detail.intendedRoomTypeName || this.t('viewingApplicationTitle')
|
||||
return this.detail.intendedRoomTypeName || this.$tr('预约看房申请')
|
||||
}
|
||||
return this.detail.intendedRoomTypeName || this.t('stayApplicationTitle')
|
||||
return this.detail.intendedRoomTypeName || this.$tr('入住申请')
|
||||
},
|
||||
applicationTypeText() {
|
||||
return this.isViewingApplication ? this.t('viewingApplicationType') : this.t('stayApplicationType')
|
||||
return this.isViewingApplication ? this.$tr('预约看房') : this.$tr('入住申请')
|
||||
},
|
||||
statusText() {
|
||||
if (this.language !== 'en' && this.detail && this.detail.statusDesc) {
|
||||
return this.detail.statusDesc
|
||||
}
|
||||
const map = {
|
||||
0: this.t('statusPending'),
|
||||
10: this.t('statusApproved'),
|
||||
20: this.t('statusRejected'),
|
||||
99: this.t('statusFinished')
|
||||
0: this.$tr('待审核'),
|
||||
10: this.$tr('已通过'),
|
||||
20: this.$tr('已拒绝'),
|
||||
99: this.$tr('已结束')
|
||||
}
|
||||
return map[this.detail.status] || this.t('statusProcessing')
|
||||
return map[this.detail.status] || this.$tr('处理中')
|
||||
},
|
||||
statusType() {
|
||||
if (this.detail.status === 10) {
|
||||
@@ -389,14 +283,14 @@ export default {
|
||||
return '--'
|
||||
}
|
||||
if (this.isViewingApplication) {
|
||||
return `${this.formatDateTime(this.detail.start)}${this.t('dateRangeJoiner')}${this.formatDateTime(this.detail.end)}`
|
||||
return `${this.formatDateTime(this.detail.start)}${this.$tr(' 至 ')}${this.formatDateTime(this.detail.end)}`
|
||||
}
|
||||
return `${this.formatDate(this.detail.start)}${this.t('dateRangeJoiner')}${this.formatDate(this.detail.end)}`
|
||||
return `${this.formatDate(this.detail.start)}${this.$tr(' 至 ')}${this.formatDate(this.detail.end)}`
|
||||
},
|
||||
remarkLines() {
|
||||
const text = this.detail && this.detail.remark ? String(this.detail.remark).trim() : ''
|
||||
if (!text) {
|
||||
return [this.t('emptyRemark')]
|
||||
return [this.$tr('暂无补充说明')]
|
||||
}
|
||||
return text.split(/\r?\n/).filter(Boolean)
|
||||
},
|
||||
@@ -429,17 +323,17 @@ export default {
|
||||
return this.getReservationContractStatusText()
|
||||
}
|
||||
if (this.isReservationCheckinProcessing()) {
|
||||
return this.t('checkinPendingHint')
|
||||
return this.$tr('宿管正在办理入住,请耐心等待')
|
||||
}
|
||||
const reservationStepText = getReservationCurrentStepText(this.detail, this.language)
|
||||
if (reservationStepText) {
|
||||
return reservationStepText
|
||||
}
|
||||
if (this.shouldPayDeposit(this.detail)) {
|
||||
return this.t('statusPendingPayment')
|
||||
return this.$tr('请支付定金')
|
||||
}
|
||||
if (this.isWaitingRoomAssignment(this.detail)) {
|
||||
return this.t('statusWaitingRoomAssign')
|
||||
return this.$tr('等待预订中心分配房间')
|
||||
}
|
||||
return ''
|
||||
},
|
||||
@@ -466,9 +360,6 @@ export default {
|
||||
this.loadReservationFlow()
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.application_detail.application_detail', key, params)
|
||||
},
|
||||
isPaidApplication(item = {}) {
|
||||
return !item.isViewingApplication && Number(item.payStatus) === 10
|
||||
},
|
||||
@@ -530,7 +421,7 @@ export default {
|
||||
return Number(detail.status) === 2
|
||||
},
|
||||
getReservationInspectionStatusText() {
|
||||
return this.t('inspectionPendingReviewHint')
|
||||
return this.$tr('inspectionPendingReviewHint')
|
||||
},
|
||||
isReservationContractAwaitingReview() {
|
||||
if (this.getReservationCurrentStepValue() !== RESERVATION_FLOW_STEP.CONTRACT) {
|
||||
@@ -663,13 +554,13 @@ export default {
|
||||
return null
|
||||
}
|
||||
const localizedLabelMap = {
|
||||
'看房时间': this.t('viewingTimeKey'),
|
||||
'预计租住时长': this.t('leaseDurationKey'),
|
||||
'租金预算': this.t('budgetKey'),
|
||||
'工作/通勤地点': this.t('commuteKey'),
|
||||
'意向区域': this.t('preferredAreaKey'),
|
||||
'意向房型': this.t('preferredRoomTypeKey'),
|
||||
'支付方式': this.t('paymentMethodKey')
|
||||
'看房时间': this.$tr('看房时间'),
|
||||
'预计租住时长': this.$tr('预计租住时长'),
|
||||
'租金预算': this.$tr('租金预算'),
|
||||
'工作/通勤地点': this.$tr('工作/通勤地点'),
|
||||
'意向区域': this.$tr('意向区域'),
|
||||
'意向房型': this.$tr('意向房型'),
|
||||
'支付方式': this.$tr('支付方式')
|
||||
}
|
||||
const rawValue = line
|
||||
.replace(`${matched.zh}:`, '')
|
||||
@@ -704,7 +595,7 @@ export default {
|
||||
data: String(this.detail.detailCode),
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: this.t('codeCopied'),
|
||||
title: this.$tr('申请编号已复制'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
@@ -713,8 +604,8 @@ export default {
|
||||
confirmCancelOrder() {
|
||||
return new Promise((resolve) => {
|
||||
uni.showModal({
|
||||
title: this.t('cancelOrderTitle'),
|
||||
content: this.t('cancelOrderContent'),
|
||||
title: this.$tr('取消订单'),
|
||||
content: this.$tr('取消后将关闭当前未支付的定金订单,是否继续?'),
|
||||
confirmColor: '#ef4444',
|
||||
success: (res) => resolve(!!(res && res.confirm)),
|
||||
fail: () => resolve(false)
|
||||
@@ -733,7 +624,7 @@ export default {
|
||||
return {
|
||||
...item,
|
||||
status: 99,
|
||||
statusDesc: this.t('statusFinished')
|
||||
statusDesc: this.$tr('已结束')
|
||||
}
|
||||
})
|
||||
saveMyApplicationList(nextList)
|
||||
@@ -757,18 +648,18 @@ export default {
|
||||
this.detail = {
|
||||
...this.detail,
|
||||
status: 99,
|
||||
statusDesc: this.t('statusFinished')
|
||||
statusDesc: this.$tr('已结束')
|
||||
}
|
||||
this.syncCanceledDetailToCache()
|
||||
uni.showToast({
|
||||
title: this.t('cancelOrderSuccess'),
|
||||
title: this.$tr('订单已取消'),
|
||||
icon: 'success'
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
uni.showToast({
|
||||
title: (error && (error.message || error.msg)) || this.t('cancelOrderFailed'),
|
||||
title: (error && (error.message || error.msg)) || this.$tr('取消订单失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
@@ -782,7 +673,7 @@ export default {
|
||||
goToBillPage() {
|
||||
if (!this.detail.detailCode) {
|
||||
uni.showToast({
|
||||
title: this.t('missingBillCode'),
|
||||
title: this.$tr('申请单编号缺失'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -810,7 +701,7 @@ export default {
|
||||
const contractNo = String(this.detail && this.detail.reservationCurrentNode && this.detail.reservationCurrentNode.refNo || '').trim()
|
||||
if (!contractNo) {
|
||||
uni.showToast({
|
||||
title: this.t('missingContractNo'),
|
||||
title: this.$tr('合同编号缺失'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<view class="bill-panel">
|
||||
<view class="hero-panel tn-margin-bottom-lg">
|
||||
<view class="hero-title tn-margin-top">{{ t('heroTitle') }}</view>
|
||||
<view class="hero-title tn-margin-top">{{ $tr('待支付账单') }}</view>
|
||||
<view class="hero-desc tn-margin-top-sm">{{ heroDesc }}</view>
|
||||
<view v-if="currentReferenceTypeNo" class="source-tag tn-margin-top-sm">{{ t('applicationNoPrefix') }}{{ currentReferenceTypeNo }}</view>
|
||||
<view v-if="currentReferenceTypeNo" class="source-tag tn-margin-top-sm">{{ $tr('申请单号:') }}{{ currentReferenceTypeNo }}</view>
|
||||
<view class="hero-summary tn-margin-top-lg">
|
||||
<view class="summary-card">
|
||||
<view class="summary-label">{{ t('pendingCountLabel') }}</view>
|
||||
<view class="summary-label">{{ $tr('待支付数量') }}</view>
|
||||
<view class="summary-value tn-margin-top-sm">{{ billList.length }}</view>
|
||||
</view>
|
||||
<view class="summary-card">
|
||||
<view class="summary-label">{{ t('pendingAmountLabel') }}</view>
|
||||
<view class="summary-label">{{ $tr('待支付总额') }}</view>
|
||||
<view class="summary-value tn-margin-top-sm">¥{{ formatMoney(totalRemainingAmount) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="loading || resolvingReference" class="empty-panel tn-padding-lg">
|
||||
<view class="empty-title">{{ t('loadingTitle') }}</view>
|
||||
<view class="empty-desc tn-margin-top-sm">{{ t('loadingDesc') }}</view>
|
||||
<view class="empty-title">{{ $tr('账单加载中') }}</view>
|
||||
<view class="empty-desc tn-margin-top-sm">{{ $tr('正在同步您的待支付账单,请稍候。') }}</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="billList.length">
|
||||
@@ -39,64 +39,64 @@
|
||||
|
||||
<view class="card-body tn-margin-top">
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('relatedBusinessNoLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('关联业务编号') }}</text>
|
||||
<text class="info-value">{{ getBillReferenceTypeNo(item) || '--' }}</text>
|
||||
</view>
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('totalChargeLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('应收合计') }}</text>
|
||||
<text class="info-value">¥{{ formatMoney(getBillTotalCharge(item)) }}</text>
|
||||
</view>
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('paidAmountLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('已付金额') }}</text>
|
||||
<text class="info-value">¥{{ formatMoney(getBillPaidAmount(item)) }}</text>
|
||||
</view>
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('remainingAmountLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('待付金额') }}</text>
|
||||
<text class="info-value info-value--highlight">¥{{ formatMoney(getBillRemainingAmount(item)) }}</text>
|
||||
</view>
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('refundStatusLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('退款状态') }}</text>
|
||||
<text class="info-value">{{ getRefundStatusText(getBillRefundStatus(item)) }}</text>
|
||||
</view>
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('createTimeLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('创建时间') }}</text>
|
||||
<text class="info-value">{{ formatDateTime(getBillCreateTime(item)) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="getBillRemark(item) || getBillResult(item)" class="remark-panel tn-margin-top">
|
||||
<view v-if="getBillRemark(item)" class="remark-line">
|
||||
<text class="remark-label">{{ t('remarkLabel') }}</text>
|
||||
<text class="remark-label">{{ $tr('备注') }}</text>
|
||||
<text class="remark-text">{{ getBillRemark(item) }}</text>
|
||||
</view>
|
||||
<view v-if="getBillResult(item)" class="remark-line tn-margin-top-sm">
|
||||
<text class="remark-label">{{ t('resultLabel') }}</text>
|
||||
<text class="remark-label">{{ $tr('处理结果') }}</text>
|
||||
<text class="remark-text">{{ getBillResult(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="getPendingPaymentOrder(item)" class="pending-payment-panel tn-margin-top">
|
||||
<view class="pending-payment-title">{{ t('pendingPaymentTitle') }}</view>
|
||||
<view class="pending-payment-title">{{ $tr('未完成支付订单') }}</view>
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('pendingPaymentOrderNoLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('支付单号') }}</text>
|
||||
<text class="info-value">{{ getPendingPaymentOrderNo(item) }}</text>
|
||||
</view>
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('pendingPaymentAmountLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('订单金额') }}</text>
|
||||
<text class="info-value info-value--highlight">¥{{ formatMoney(getPendingPaymentAmount(item)) }}</text>
|
||||
</view>
|
||||
<view v-if="getPendingPaymentExpireText(item)" class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('pendingPaymentExpireLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('剩余支付时间') }}</text>
|
||||
<text class="info-value" :class="{ 'info-value--expired': isPendingPaymentExpired(item) }">
|
||||
{{ getPendingPaymentExpireText(item) }}
|
||||
</text>
|
||||
</view>
|
||||
<view v-if="getPendingPaymentDescription(item)" class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('pendingPaymentDescLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('支付说明') }}</text>
|
||||
<text class="info-value">{{ getPendingPaymentDescription(item) }}</text>
|
||||
</view>
|
||||
<view v-if="getPendingPaymentChannel(item)" class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('pendingPaymentChannelLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('支付渠道') }}</text>
|
||||
<text class="info-value">{{ getPendingPaymentChannel(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -124,10 +124,10 @@
|
||||
</view>
|
||||
|
||||
<view v-else class="empty-panel tn-padding-lg">
|
||||
<view class="empty-title">{{ currentReferenceTypeNo ? t('emptyPendingTitle') : t('emptyApplicationTitle') }}</view>
|
||||
<view class="empty-desc tn-margin-top-sm">{{ currentReferenceTypeNo ? t('emptyPendingDesc') : t('emptyApplicationDesc') }}</view>
|
||||
<view class="empty-title">{{ currentReferenceTypeNo ? $tr('暂无待支付账单') : $tr('暂无可查询申请单') }}</view>
|
||||
<view class="empty-desc tn-margin-top-sm">{{ currentReferenceTypeNo ? $tr('当前申请单下没有查询到待支付账单,后续有新账单时会在这里展示。') : $tr('当前未找到可关联的申请单,请先前往“我的申请”选择具体申请后查看账单。') }}</view>
|
||||
<view v-if="!currentReferenceTypeNo" class="empty-action tn-margin-top-lg" @tap="goToMyApplication">
|
||||
<text class="tn-text-bold">{{ t('goToMyApplication') }}</text>
|
||||
<text class="tn-text-bold">{{ $tr('前往我的申请') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
|
||||
<view v-if="isPaymentWaitingStage" class="payment-progress-card">
|
||||
<view class="payment-progress-head tn-flex tn-flex-row-between tn-flex-col-center">
|
||||
<text class="payment-progress-label">{{ t('paymentProgressLabel') }}</text>
|
||||
<text class="payment-progress-label">{{ $tr('结果确认进度') }}</text>
|
||||
<text class="payment-progress-value">{{ paymentProgressText }}</text>
|
||||
</view>
|
||||
<view class="payment-progress-track">
|
||||
@@ -208,11 +208,11 @@
|
||||
|
||||
<view class="payment-summary-grid">
|
||||
<view class="payment-summary-item">
|
||||
<view class="payment-summary-label">{{ t('billNoLabel') }}</view>
|
||||
<view class="payment-summary-label">{{ $tr('账单号') }}</view>
|
||||
<view class="payment-summary-value payment-summary-value--mono">{{ paymentWaitingBillNo || '--' }}</view>
|
||||
</view>
|
||||
<view class="payment-summary-item">
|
||||
<view class="payment-summary-label">{{ t('currentPaymentLabel') }}</view>
|
||||
<view class="payment-summary-label">{{ $tr('本次支付') }}</view>
|
||||
<view class="payment-summary-value payment-summary-value--price">¥{{ paymentWaitingAmountText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -380,212 +380,6 @@ export default {
|
||||
lines: [],
|
||||
confirmText: '',
|
||||
cancelText: ''
|
||||
},
|
||||
i18n: {
|
||||
zh: {
|
||||
heroTitle: '待支付账单',
|
||||
applicationNoPrefix: '申请单号:',
|
||||
pendingCountLabel: '待支付数量',
|
||||
pendingAmountLabel: '待支付总额',
|
||||
loadingTitle: '账单加载中',
|
||||
loadingDesc: '正在同步您的待支付账单,请稍候。',
|
||||
relatedBusinessNoLabel: '关联业务编号',
|
||||
totalChargeLabel: '应收合计',
|
||||
paidAmountLabel: '已付金额',
|
||||
remainingAmountLabel: '待付金额',
|
||||
refundStatusLabel: '退款状态',
|
||||
createTimeLabel: '创建时间',
|
||||
remarkLabel: '备注',
|
||||
resultLabel: '处理结果',
|
||||
pendingPaymentTitle: '未完成支付订单',
|
||||
pendingPaymentOrderNoLabel: '支付单号',
|
||||
pendingPaymentAmountLabel: '订单金额',
|
||||
pendingPaymentDescLabel: '支付说明',
|
||||
pendingPaymentChannelLabel: '支付渠道',
|
||||
pendingPaymentExpireLabel: '剩余支付时间',
|
||||
pendingPaymentExpired: '已失效',
|
||||
emptyPendingTitle: '暂无待支付账单',
|
||||
emptyApplicationTitle: '暂无可查询申请单',
|
||||
emptyPendingDesc: '当前申请单下没有查询到待支付账单,后续有新账单时会在这里展示。',
|
||||
emptyApplicationDesc: '当前未找到可关联的申请单,请先前往“我的申请”选择具体申请后查看账单。',
|
||||
goToMyApplication: '前往我的申请',
|
||||
paymentProgressLabel: '结果确认进度',
|
||||
billNoLabel: '账单号',
|
||||
currentPaymentLabel: '本次支付',
|
||||
heroDescResolved: '当前页面已按申请单编号查询其关联的待支付账单记录。',
|
||||
heroDescAutoResolve: '当前将优先读取最近申请单的编号来查询关联账单。',
|
||||
paymentStageLaunching: '正在唤起微信收银台',
|
||||
paymentStagePolling: '正在同步支付结果',
|
||||
paymentStageSuccess: '支付结果已确认',
|
||||
paymentStageFailed: '支付未完成',
|
||||
paymentStageDefault: '支付处理中',
|
||||
paymentTitleLaunching: '请完成微信支付',
|
||||
paymentTitlePolling: '正在确认是否支付成功',
|
||||
paymentTitleSuccess: '支付成功',
|
||||
paymentTitleFailed: '支付结果确认失败',
|
||||
paymentTitleDefault: '支付处理中',
|
||||
paymentDescLaunching: '系统正在调起微信支付,请在微信收银台中完成付款后返回。',
|
||||
paymentDescPolling: '支付完成后,系统会自动向后台查询支付状态,无需手动刷新。',
|
||||
paymentDescSuccess: '本次支付已同步完成,账单状态已更新。',
|
||||
paymentDescFailed: '系统暂时未能确认支付成功,您可以查看提示后稍后重试。',
|
||||
paymentProgressWaiting: '等待支付完成',
|
||||
paymentHintLaunching: '已为您准备好支付信息,等待微信支付完成。',
|
||||
paymentHintPolling: '正在与后台核对支付状态,请稍候。',
|
||||
paymentTipsTitleFailed: '处理建议',
|
||||
paymentTipsTitleSuccess: '完成说明',
|
||||
paymentTipsTitleDefault: '温馨提示',
|
||||
paymentTipsFailed1: '若您已完成付款,请稍后刷新账单,避免重复支付。',
|
||||
paymentTipsFailed2: '若微信侧已扣款但页面未更新,请联系管家或客服协助核实。',
|
||||
paymentTipsFailed3: '若未扣款,可返回账单列表后重新发起支付。',
|
||||
paymentTipsSuccess1: '若当前申请单还有其他待付账单,可继续在当前页完成支付。',
|
||||
paymentTipsSuccess2: '若当前账单已全部支付完成,系统会自动返回首页。',
|
||||
paymentTipsSuccess3: '支付记录同步可能略有延迟,刷新后即可看到最新状态。',
|
||||
paymentTipsDefault1: '支付成功后,系统可能需要几秒钟同步账单状态。',
|
||||
paymentTipsDefault2: '请不要重复点击支付,也不要提前关闭当前页面。',
|
||||
paymentTipsDefault3: '如果超时未完成,系统会自动再校验一次账单状态。',
|
||||
paymentActionAcknowledge: '我知道了',
|
||||
buttonConfirming: '确认结果中...',
|
||||
buttonPolling: '查询结果中({current}/{total})',
|
||||
buttonLaunching: '拉起支付中...',
|
||||
wechatPayButton: '微信支付',
|
||||
continuePayButton: '继续支付',
|
||||
paymentStatusPending: '处理中',
|
||||
billRecordFallback: '账单记录',
|
||||
paymentParamIncomplete: '微信支付参数不完整',
|
||||
wechatCodeFailed: '获取微信登录凭证失败',
|
||||
billPaymentDesc: '账单支付',
|
||||
paymentFailedHint: '暂未查询到支付成功结果,请稍后刷新账单确认。',
|
||||
paymentResultSuccess: '后台确认支付成功',
|
||||
paymentResultFailed: '后台返回支付失败',
|
||||
paymentResultPending: '后台仍在处理中',
|
||||
paymentHintPaidWaiting: '已支付成功,正在等待后台确认账单状态。',
|
||||
paymentFailedError: '支付失败',
|
||||
paymentTimeoutError: '支付结果确认超时,请稍后刷新账单确认',
|
||||
paymentSuccessPendingBills: '支付结果已确认,当前申请单仍有其他待支付账单。',
|
||||
paymentSuccessAllDone: '支付结果已确认,当前申请单账单已全部完成。',
|
||||
billInfoIncomplete: '账单信息不完整',
|
||||
paymentNoticeTitle: '用户须知',
|
||||
paymentNoticeBillLabel: '账单号',
|
||||
paymentNoticeAmountLabel: '支付金额',
|
||||
paymentNoticeItemLabel: '费用项目',
|
||||
paymentNoticeLine1: '请确认本次支付账单和金额无误后再继续付款。',
|
||||
paymentNoticeLine2: '支付完成后,账单状态可能需要几秒同步,请勿重复支付。',
|
||||
paymentNoticeLine3: '若支付中断或页面关闭,可稍后返回账单页查看最新结果。',
|
||||
paymentNoticeConfirm: '继续支付',
|
||||
paymentNoticeCancel: '稍后再付',
|
||||
paymentHintLaunchingToast: '正在唤起微信支付,请在微信内完成付款。',
|
||||
paymentCanceled: '已取消支付',
|
||||
paymentResultFailedRetry: '支付结果确认失败,请稍后刷新账单确认',
|
||||
billLoadFailed: '账单加载失败',
|
||||
cancelOrderButton: '取消订单',
|
||||
cancelOrderLoading: '取消中...',
|
||||
cancelOrderTitle: '取消订单',
|
||||
cancelOrderContent: '取消后将关闭当前未支付订单,是否继续?',
|
||||
cancelOrderSuccess: '订单已取消',
|
||||
cancelOrderFailed: '取消订单失败'
|
||||
},
|
||||
en: {
|
||||
heroTitle: 'Pending Bills',
|
||||
applicationNoPrefix: 'Application No: ',
|
||||
pendingCountLabel: 'Pending Count',
|
||||
pendingAmountLabel: 'Pending Amount',
|
||||
loadingTitle: 'Loading Bills',
|
||||
loadingDesc: 'Syncing your pending bills, please wait.',
|
||||
relatedBusinessNoLabel: 'Related Business No.',
|
||||
totalChargeLabel: 'Total Charge',
|
||||
paidAmountLabel: 'Paid Amount',
|
||||
remainingAmountLabel: 'Remaining Amount',
|
||||
refundStatusLabel: 'Refund Status',
|
||||
createTimeLabel: 'Created At',
|
||||
remarkLabel: 'Remark',
|
||||
resultLabel: 'Result',
|
||||
pendingPaymentTitle: 'Unfinished Payment',
|
||||
pendingPaymentOrderNoLabel: 'Payment Order No.',
|
||||
pendingPaymentAmountLabel: 'Order Amount',
|
||||
pendingPaymentDescLabel: 'Description',
|
||||
pendingPaymentChannelLabel: 'Channel',
|
||||
pendingPaymentExpireLabel: 'Time Left',
|
||||
pendingPaymentExpired: 'Expired',
|
||||
emptyPendingTitle: 'No Pending Bills',
|
||||
emptyApplicationTitle: 'No Application Available',
|
||||
emptyPendingDesc: 'No pending bills are found under the current application. New bills will appear here later.',
|
||||
emptyApplicationDesc: 'No related application is found. Please go to "My Applications" and select an application first.',
|
||||
goToMyApplication: 'Go to My Applications',
|
||||
paymentProgressLabel: 'Confirmation Progress',
|
||||
billNoLabel: 'Bill No.',
|
||||
currentPaymentLabel: 'This Payment',
|
||||
heroDescResolved: 'This page is querying pending bills by the current application number.',
|
||||
heroDescAutoResolve: 'The latest application number will be used first to query related bills.',
|
||||
paymentStageLaunching: 'Launching Wechat Pay',
|
||||
paymentStagePolling: 'Syncing Payment Result',
|
||||
paymentStageSuccess: 'Payment Confirmed',
|
||||
paymentStageFailed: 'Payment Incomplete',
|
||||
paymentStageDefault: 'Processing Payment',
|
||||
paymentTitleLaunching: 'Complete Wechat Pay',
|
||||
paymentTitlePolling: 'Confirming Payment Result',
|
||||
paymentTitleSuccess: 'Payment Successful',
|
||||
paymentTitleFailed: 'Payment Confirmation Failed',
|
||||
paymentTitleDefault: 'Processing Payment',
|
||||
paymentDescLaunching: 'Wechat Pay is being launched. Complete the payment in Wechat and return here.',
|
||||
paymentDescPolling: 'After payment, the system checks the payment status automatically. No manual refresh is needed.',
|
||||
paymentDescSuccess: 'This payment has been synchronized and the bill status is updated.',
|
||||
paymentDescFailed: 'The system cannot confirm the payment for now. Please review the tips and try again later.',
|
||||
paymentProgressWaiting: 'Waiting for Payment',
|
||||
paymentHintLaunching: 'Payment information is ready. Waiting for Wechat payment to complete.',
|
||||
paymentHintPolling: 'Checking payment status with the backend, please wait.',
|
||||
paymentTipsTitleFailed: 'Suggestions',
|
||||
paymentTipsTitleSuccess: 'Completion Notes',
|
||||
paymentTipsTitleDefault: 'Tips',
|
||||
paymentTipsFailed1: 'If you have completed the payment, refresh the bill later to avoid duplicate payment.',
|
||||
paymentTipsFailed2: 'If Wechat has deducted the amount but the page is not updated, contact your manager or support for verification.',
|
||||
paymentTipsFailed3: 'If no deduction occurred, return to the bill list and try again.',
|
||||
paymentTipsSuccess1: 'If there are other pending bills under this application, you can continue paying on this page.',
|
||||
paymentTipsSuccess2: 'If all bills are paid, the system returns to the home page automatically.',
|
||||
paymentTipsSuccess3: 'Payment record synchronization may be slightly delayed. Refresh to see the latest status.',
|
||||
paymentTipsDefault1: 'After successful payment, the system may need a few seconds to sync the bill status.',
|
||||
paymentTipsDefault2: 'Do not tap the pay button repeatedly or close this page too early.',
|
||||
paymentTipsDefault3: 'If the process times out, the system checks the bill status again automatically.',
|
||||
paymentActionAcknowledge: 'Got It',
|
||||
buttonConfirming: 'Confirming...',
|
||||
buttonPolling: 'Checking ({current}/{total})',
|
||||
buttonLaunching: 'Launching...',
|
||||
wechatPayButton: 'Wechat Pay',
|
||||
continuePayButton: 'Continue Pay',
|
||||
paymentStatusPending: 'Processing',
|
||||
billRecordFallback: 'Bill Record',
|
||||
paymentParamIncomplete: 'Incomplete Wechat payment parameters',
|
||||
wechatCodeFailed: 'Failed to get Wechat login code',
|
||||
billPaymentDesc: 'Bill Payment',
|
||||
paymentFailedHint: 'Payment success is not confirmed yet. Please refresh the bill later.',
|
||||
paymentResultSuccess: 'Backend confirmed payment success',
|
||||
paymentResultFailed: 'Backend returned payment failure',
|
||||
paymentResultPending: 'Backend is still processing',
|
||||
paymentHintPaidWaiting: 'Payment succeeded. Waiting for backend confirmation of the bill status.',
|
||||
paymentFailedError: 'Payment failed',
|
||||
paymentTimeoutError: 'Payment confirmation timed out. Please refresh the bill later.',
|
||||
paymentSuccessPendingBills: 'Payment is confirmed. There are still other unpaid bills under this application.',
|
||||
paymentSuccessAllDone: 'Payment is confirmed. All bills under this application are completed.',
|
||||
billInfoIncomplete: 'Incomplete bill information',
|
||||
paymentNoticeTitle: 'Payment Notice',
|
||||
paymentNoticeBillLabel: 'Bill No.',
|
||||
paymentNoticeAmountLabel: 'Amount',
|
||||
paymentNoticeItemLabel: 'Charge Item',
|
||||
paymentNoticeLine1: 'Please confirm the bill and payment amount before continuing.',
|
||||
paymentNoticeLine2: 'After payment, the bill status may take a few seconds to sync. Please do not pay repeatedly.',
|
||||
paymentNoticeLine3: 'If the payment is interrupted or the page is closed, return to the bill page later to check the latest result.',
|
||||
paymentNoticeConfirm: 'Continue',
|
||||
paymentNoticeCancel: 'Later',
|
||||
paymentHintLaunchingToast: 'Launching Wechat Pay. Please complete the payment in Wechat.',
|
||||
paymentCanceled: 'Payment canceled',
|
||||
paymentResultFailedRetry: 'Payment confirmation failed. Please refresh the bill later.',
|
||||
billLoadFailed: 'Failed to load bills',
|
||||
cancelOrderButton: 'Cancel Order',
|
||||
cancelOrderLoading: 'Canceling...',
|
||||
cancelOrderTitle: 'Cancel Order',
|
||||
cancelOrderContent: 'This will close the current unpaid order. Continue?',
|
||||
cancelOrderSuccess: 'Order canceled',
|
||||
cancelOrderFailed: 'Failed to cancel order'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -600,9 +394,9 @@ export default {
|
||||
},
|
||||
heroDesc() {
|
||||
if (this.currentReferenceTypeNo) {
|
||||
return this.t('heroDescResolved')
|
||||
return this.$tr('当前页面已按申请单编号查询其关联的待支付账单记录。')
|
||||
}
|
||||
return this.t('heroDescAutoResolve')
|
||||
return this.$tr('当前将优先读取最近申请单的编号来查询关联账单。')
|
||||
},
|
||||
showPaymentFeedbackPanel() {
|
||||
return Boolean(this.paymentStage)
|
||||
@@ -627,18 +421,18 @@ export default {
|
||||
},
|
||||
paymentStageLabel() {
|
||||
if (this.paymentStage === 'launching') {
|
||||
return this.t('paymentStageLaunching')
|
||||
return this.$tr('正在唤起微信收银台')
|
||||
}
|
||||
if (this.paymentStage === 'polling') {
|
||||
return this.t('paymentStagePolling')
|
||||
return this.$tr('正在同步支付结果')
|
||||
}
|
||||
if (this.paymentStage === 'success') {
|
||||
return this.t('paymentStageSuccess')
|
||||
return this.$tr('支付结果已确认')
|
||||
}
|
||||
if (this.paymentStage === 'failed') {
|
||||
return this.t('paymentStageFailed')
|
||||
return this.$tr('支付未完成')
|
||||
}
|
||||
return this.t('paymentStageDefault')
|
||||
return this.$tr('支付处理中')
|
||||
},
|
||||
paymentBadgeIconClass() {
|
||||
if (this.isPaymentSuccessStage) {
|
||||
@@ -660,31 +454,31 @@ export default {
|
||||
},
|
||||
paymentWaitingTitle() {
|
||||
if (this.paymentStage === 'launching') {
|
||||
return this.t('paymentTitleLaunching')
|
||||
return this.$tr('请完成微信支付')
|
||||
}
|
||||
if (this.paymentStage === 'polling') {
|
||||
return this.t('paymentTitlePolling')
|
||||
return this.$tr('正在确认是否支付成功')
|
||||
}
|
||||
if (this.paymentStage === 'success') {
|
||||
return this.t('paymentTitleSuccess')
|
||||
return this.$tr('支付成功')
|
||||
}
|
||||
if (this.paymentStage === 'failed') {
|
||||
return this.t('paymentTitleFailed')
|
||||
return this.$tr('支付结果确认失败')
|
||||
}
|
||||
return this.t('paymentTitleDefault')
|
||||
return this.$tr('支付处理中')
|
||||
},
|
||||
paymentWaitingDesc() {
|
||||
if (this.paymentStage === 'launching') {
|
||||
return this.t('paymentDescLaunching')
|
||||
return this.$tr('系统正在调起微信支付,请在微信收银台中完成付款后返回。')
|
||||
}
|
||||
if (this.paymentStage === 'polling') {
|
||||
return this.t('paymentDescPolling')
|
||||
return this.$tr('支付完成后,系统会自动向后台查询支付状态,无需手动刷新。')
|
||||
}
|
||||
if (this.paymentStage === 'success') {
|
||||
return this.t('paymentDescSuccess')
|
||||
return this.$tr('本次支付已同步完成,账单状态已更新。')
|
||||
}
|
||||
if (this.paymentStage === 'failed') {
|
||||
return this.t('paymentDescFailed')
|
||||
return this.$tr('系统暂时未能确认支付成功,您可以查看提示后稍后重试。')
|
||||
}
|
||||
return ''
|
||||
},
|
||||
@@ -704,7 +498,7 @@ export default {
|
||||
},
|
||||
paymentProgressText() {
|
||||
if (this.paymentStage !== 'polling') {
|
||||
return this.t('paymentProgressWaiting')
|
||||
return this.$tr('等待支付完成')
|
||||
}
|
||||
const current = this.paymentPollingAttempt > 0 ? this.paymentPollingAttempt : 1
|
||||
return `${current}/${PAYMENT_QUERY_MAX_ATTEMPTS}`
|
||||
@@ -714,45 +508,45 @@ export default {
|
||||
return this.paymentStatusHint
|
||||
}
|
||||
if (this.paymentStage === 'launching') {
|
||||
return this.t('paymentHintLaunching')
|
||||
return this.$tr('已为您准备好支付信息,等待微信支付完成。')
|
||||
}
|
||||
return this.t('paymentHintPolling')
|
||||
return this.$tr('正在与后台核对支付状态,请稍候。')
|
||||
},
|
||||
paymentTipsTitle() {
|
||||
if (this.isPaymentFailedStage) {
|
||||
return this.t('paymentTipsTitleFailed')
|
||||
return this.$tr('处理建议')
|
||||
}
|
||||
if (this.isPaymentSuccessStage) {
|
||||
return this.t('paymentTipsTitleSuccess')
|
||||
return this.$tr('完成说明')
|
||||
}
|
||||
return this.t('paymentTipsTitleDefault')
|
||||
return this.$tr('温馨提示')
|
||||
},
|
||||
paymentTips() {
|
||||
if (this.isPaymentFailedStage) {
|
||||
return [
|
||||
this.t('paymentTipsFailed1'),
|
||||
this.t('paymentTipsFailed2'),
|
||||
this.t('paymentTipsFailed3')
|
||||
this.$tr('若您已完成付款,请稍后刷新账单,避免重复支付。'),
|
||||
this.$tr('若微信侧已扣款但页面未更新,请联系管家或客服协助核实。'),
|
||||
this.$tr('若未扣款,可返回账单列表后重新发起支付。')
|
||||
]
|
||||
}
|
||||
if (this.isPaymentSuccessStage) {
|
||||
return [
|
||||
this.t('paymentTipsSuccess1'),
|
||||
this.t('paymentTipsSuccess2'),
|
||||
this.t('paymentTipsSuccess3')
|
||||
this.$tr('若当前申请单还有其他待付账单,可继续在当前页完成支付。'),
|
||||
this.$tr('若当前账单已全部支付完成,系统会自动返回首页。'),
|
||||
this.$tr('支付记录同步可能略有延迟,刷新后即可看到最新状态。')
|
||||
]
|
||||
}
|
||||
return [
|
||||
this.t('paymentTipsDefault1'),
|
||||
this.t('paymentTipsDefault2'),
|
||||
this.t('paymentTipsDefault3')
|
||||
this.$tr('支付成功后,系统可能需要几秒钟同步账单状态。'),
|
||||
this.$tr('请不要重复点击支付,也不要提前关闭当前页面。'),
|
||||
this.$tr('如果超时未完成,系统会自动再校验一次账单状态。')
|
||||
]
|
||||
},
|
||||
showPaymentActionButton() {
|
||||
return this.isPaymentFailedStage
|
||||
},
|
||||
paymentActionText() {
|
||||
return this.isPaymentFailedStage ? this.t('paymentActionAcknowledge') : ''
|
||||
return this.isPaymentFailedStage ? this.$tr('我知道了') : ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -782,22 +576,6 @@ export default {
|
||||
this.clearCountdownTimer()
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
const translatedText = this.$tm('pkgService.components.CurrentApplicationBillPanel', key, params)
|
||||
if (translatedText && translatedText !== key) {
|
||||
return translatedText
|
||||
}
|
||||
|
||||
const languagePack = this.i18n && this.i18n[this.language] ? this.i18n[this.language] : this.i18n.zh
|
||||
const fallbackText = languagePack && languagePack[key] ? languagePack[key] : key
|
||||
if (!params || typeof fallbackText !== 'string') {
|
||||
return fallbackText
|
||||
}
|
||||
|
||||
return fallbackText.replace(/\{(\w+)\}/g, (match, token) => {
|
||||
return Object.prototype.hasOwnProperty.call(params, token) ? params[token] : match
|
||||
})
|
||||
},
|
||||
getBillNo(item = {}) {
|
||||
return item.no || item.billNo || ''
|
||||
},
|
||||
@@ -812,7 +590,7 @@ export default {
|
||||
},
|
||||
getBillPaymentStatusText(item = {}) {
|
||||
const translatedStatus = this.getPaymentStatusText(this.getBillPaymentStatus(item))
|
||||
return translatedStatus || item.paymentStatusDesc || this.t('paymentStatusPending')
|
||||
return translatedStatus || item.paymentStatusDesc || this.$tr('处理中')
|
||||
},
|
||||
getBillRefundStatus(item = {}) {
|
||||
return item.refundStatus
|
||||
@@ -918,7 +696,7 @@ export default {
|
||||
return ''
|
||||
}
|
||||
if (expireTimestamp <= this.countdownNow) {
|
||||
return this.t('pendingPaymentExpired')
|
||||
return this.$tr('已失效')
|
||||
}
|
||||
return this.formatPendingPaymentCountdown(this.getPendingPaymentRemainingSeconds(item))
|
||||
},
|
||||
@@ -926,20 +704,20 @@ export default {
|
||||
const billNo = this.getBillNo(item)
|
||||
if (this.paymentPollingBillNo && this.paymentPollingBillNo === billNo) {
|
||||
if (!this.paymentPollingAttempt) {
|
||||
return this.t('buttonConfirming')
|
||||
return this.$tr('确认结果中...')
|
||||
}
|
||||
return this.t('buttonPolling', {
|
||||
return this.$tr('查询结果中({current}/{total})', {
|
||||
current: this.paymentPollingAttempt,
|
||||
total: PAYMENT_QUERY_MAX_ATTEMPTS
|
||||
})
|
||||
}
|
||||
if (this.payingBillNo === billNo) {
|
||||
return this.paymentStage === 'launching' ? this.t('buttonLaunching') : this.t('buttonConfirming')
|
||||
return this.paymentStage === 'launching' ? this.$tr('拉起支付中...') : this.$tr('确认结果中...')
|
||||
}
|
||||
if (this.getPendingPaymentOrder(item) && !this.isPendingPaymentExpired(item)) {
|
||||
return this.t('continuePayButton')
|
||||
return this.$tr('继续支付')
|
||||
}
|
||||
return this.t('wechatPayButton')
|
||||
return this.$tr('微信支付')
|
||||
},
|
||||
canCancelOrder(item = {}) {
|
||||
if (!this.currentReferenceTypeNo) {
|
||||
@@ -951,8 +729,8 @@ export default {
|
||||
},
|
||||
getCancelButtonText(item = {}) {
|
||||
return this.cancelingBillNo === this.getBillNo(item)
|
||||
? this.t('cancelOrderLoading')
|
||||
: this.t('cancelOrderButton')
|
||||
? this.$tr('取消中...')
|
||||
: this.$tr('取消订单')
|
||||
},
|
||||
resolveReferenceTypeNo(item = {}) {
|
||||
return item.code || item.detailCode || ''
|
||||
@@ -1024,7 +802,7 @@ export default {
|
||||
return text.length > 16 ? text.slice(0, 16) : text
|
||||
},
|
||||
getPaymentStatusText(status) {
|
||||
return getAccountBillPaymentStatusLabel(status, this.t('paymentStatusPending'))
|
||||
return getAccountBillPaymentStatusLabel(status, this.$tr('处理中'))
|
||||
},
|
||||
resolvePaymentStatusType(status) {
|
||||
if (Number(status) === ACCOUNT_BILL_PAYMENT_STATUS.PAID) {
|
||||
@@ -1040,7 +818,7 @@ export default {
|
||||
},
|
||||
getReferenceTypeText(item = {}) {
|
||||
const translatedType = getAccountReferenceTypeLabel(item.referenceType, '')
|
||||
return translatedType || item.referenceTypeDesc || this.t('billRecordFallback')
|
||||
return translatedType || item.referenceTypeDesc || this.$tr('账单记录')
|
||||
},
|
||||
parsePaymentInfo(paymentInfo) {
|
||||
if (!paymentInfo) {
|
||||
@@ -1073,7 +851,7 @@ export default {
|
||||
requestWechatPayment(paymentInfo) {
|
||||
const payOptions = this.normalizeWechatPayOptions(paymentInfo)
|
||||
if (!payOptions.timeStamp || !payOptions.nonceStr || !payOptions.package || !payOptions.paySign) {
|
||||
return Promise.reject(new Error(this.t('paymentParamIncomplete')))
|
||||
return Promise.reject(new Error(this.$tr('微信支付参数不完整')))
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -1143,13 +921,13 @@ export default {
|
||||
success: (res) => {
|
||||
const code = res && res.code ? res.code : ''
|
||||
if (!code) {
|
||||
reject(new Error(this.t('wechatCodeFailed')))
|
||||
reject(new Error(this.$tr('获取微信登录凭证失败')))
|
||||
return
|
||||
}
|
||||
resolve(code)
|
||||
},
|
||||
fail: (error) => {
|
||||
reject(error || new Error(this.t('wechatCodeFailed')))
|
||||
reject(error || new Error(this.$tr('获取微信登录凭证失败')))
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -1160,7 +938,7 @@ export default {
|
||||
billNo: this.getBillNo(item),
|
||||
payMethod: 'Wechat',
|
||||
amount: Number(this.getBillRemainingAmount(item) || 0),
|
||||
description: this.getReferenceTypeText(item) || this.t('billPaymentDesc')
|
||||
description: this.getReferenceTypeText(item) || this.$tr('账单支付')
|
||||
}
|
||||
if (wechatCode) {
|
||||
payload.ExtraInfo = wechatCode
|
||||
@@ -1168,10 +946,6 @@ export default {
|
||||
return payload
|
||||
},
|
||||
resolveNoticeText(key, zhText, enText) {
|
||||
const translatedText = this.t(key)
|
||||
if (translatedText && translatedText !== key) {
|
||||
return translatedText
|
||||
}
|
||||
return this.language === 'en' ? enText : zhText
|
||||
},
|
||||
resetPaymentNoticeContext() {
|
||||
@@ -1237,8 +1011,8 @@ export default {
|
||||
confirmCancelOrder() {
|
||||
return new Promise((resolve) => {
|
||||
uni.showModal({
|
||||
title: this.t('cancelOrderTitle'),
|
||||
content: this.t('cancelOrderContent'),
|
||||
title: this.$tr('取消订单'),
|
||||
content: this.$tr('取消后将关闭当前未支付订单,是否继续?'),
|
||||
confirmColor: '#ef4444',
|
||||
success: (res) => resolve(!!(res && res.confirm)),
|
||||
fail: () => resolve(false)
|
||||
@@ -1264,7 +1038,7 @@ export default {
|
||||
this.paymentSession = {
|
||||
billNo: this.getBillNo(item),
|
||||
amount: Number(this.getBillRemainingAmount(item) || 0),
|
||||
title: this.getReferenceTypeText(item) || this.t('billPaymentDesc')
|
||||
title: this.getReferenceTypeText(item) || this.$tr('账单支付')
|
||||
}
|
||||
},
|
||||
resetPaymentWaitingState() {
|
||||
@@ -1277,7 +1051,7 @@ export default {
|
||||
},
|
||||
openPaymentFailedState(message = '') {
|
||||
this.paymentStage = 'failed'
|
||||
this.paymentStatusHint = message || this.t('paymentFailedHint')
|
||||
this.paymentStatusHint = message || this.$tr('暂未查询到支付成功结果,请稍后刷新账单确认。')
|
||||
this.payingBillNo = ''
|
||||
this.paymentPollingBillNo = this.paymentWaitingBillNo
|
||||
},
|
||||
@@ -1312,20 +1086,20 @@ export default {
|
||||
if (payStatus === PAYMENT_ORDER_STATUS.SUCCESS) {
|
||||
return {
|
||||
status: PAYMENT_QUERY_STATUS.SUCCESS,
|
||||
message: statusDesc || this.t('paymentResultSuccess'),
|
||||
message: statusDesc || this.$tr('后台确认支付成功'),
|
||||
data: payload
|
||||
}
|
||||
}
|
||||
if (payStatus === PAYMENT_ORDER_STATUS.FAILED) {
|
||||
return {
|
||||
status: PAYMENT_QUERY_STATUS.FAILED,
|
||||
message: statusDesc || this.t('paymentResultFailed'),
|
||||
message: statusDesc || this.$tr('后台返回支付失败'),
|
||||
data: payload
|
||||
}
|
||||
}
|
||||
return {
|
||||
status: PAYMENT_QUERY_STATUS.PENDING,
|
||||
message: statusDesc || this.t('paymentResultPending'),
|
||||
message: statusDesc || this.$tr('后台仍在处理中'),
|
||||
data: payload
|
||||
}
|
||||
})
|
||||
@@ -1337,7 +1111,7 @@ export default {
|
||||
this.paymentStage = 'polling'
|
||||
this.paymentPollingBillNo = queryContext.billNo
|
||||
this.paymentPollingAttempt = 0
|
||||
this.paymentStatusHint = this.t('paymentHintPaidWaiting')
|
||||
this.paymentStatusHint = this.$tr('已支付成功,正在等待后台确认账单状态。')
|
||||
|
||||
const executePolling = async () => {
|
||||
for (let attempt = 1; attempt <= PAYMENT_QUERY_MAX_ATTEMPTS; attempt += 1) {
|
||||
@@ -1346,15 +1120,15 @@ export default {
|
||||
}
|
||||
this.paymentPollingAttempt = attempt
|
||||
lastResult = await this.queryPaymentResult(queryContext)
|
||||
this.paymentStatusHint = lastResult && lastResult.message ? lastResult.message : this.t('paymentHintPolling')
|
||||
this.paymentStatusHint = lastResult && lastResult.message ? lastResult.message : this.$tr('正在与后台核对支付状态,请稍候。')
|
||||
if (lastResult && lastResult.status === PAYMENT_QUERY_STATUS.SUCCESS) {
|
||||
return lastResult
|
||||
}
|
||||
if (lastResult && lastResult.status === PAYMENT_QUERY_STATUS.FAILED) {
|
||||
throw new Error(lastResult.message || this.t('paymentFailedError'))
|
||||
throw new Error(lastResult.message || this.$tr('支付失败'))
|
||||
}
|
||||
}
|
||||
throw new Error((lastResult && lastResult.message) || this.t('paymentTimeoutError'))
|
||||
throw new Error((lastResult && lastResult.message) || this.$tr('支付结果确认超时,请稍后刷新账单确认'))
|
||||
}
|
||||
|
||||
return executePolling()
|
||||
@@ -1363,8 +1137,8 @@ export default {
|
||||
const hasPendingBills = this.billList.length > 0
|
||||
this.paymentStage = 'success'
|
||||
this.paymentStatusHint = hasPendingBills
|
||||
? this.t('paymentSuccessPendingBills')
|
||||
: this.t('paymentSuccessAllDone')
|
||||
? this.$tr('支付结果已确认,当前申请单仍有其他待支付账单。')
|
||||
: this.$tr('支付结果已确认,当前申请单账单已全部完成。')
|
||||
this.payingBillNo = ''
|
||||
this.paymentPollingBillNo = this.paymentWaitingBillNo
|
||||
return this.wait(1200)
|
||||
@@ -1413,7 +1187,7 @@ export default {
|
||||
: null
|
||||
if (!billNo || !this.currentReferenceTypeNo) {
|
||||
uni.showToast({
|
||||
title: this.t('billInfoIncomplete'),
|
||||
title: this.$tr('账单信息不完整'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -1430,7 +1204,7 @@ export default {
|
||||
}
|
||||
this.payingBillNo = billNo
|
||||
this.paymentStage = 'launching'
|
||||
this.paymentStatusHint = this.t('paymentHintLaunchingToast')
|
||||
this.paymentStatusHint = this.$tr('正在唤起微信支付,请在微信内完成付款。')
|
||||
this.createPaymentSession(item)
|
||||
})
|
||||
.then(() => {
|
||||
@@ -1464,7 +1238,7 @@ export default {
|
||||
if (/cancel/i.test(errMsg)) {
|
||||
this.resetPaymentWaitingState()
|
||||
uni.showToast({
|
||||
title: this.t('paymentCanceled'),
|
||||
title: this.$tr('已取消支付'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -1474,7 +1248,7 @@ export default {
|
||||
if (hasConfirmedSuccess) {
|
||||
return
|
||||
}
|
||||
this.openPaymentFailedState(errMsg || this.t('paymentResultFailedRetry'))
|
||||
this.openPaymentFailedState(errMsg || this.$tr('支付结果确认失败,请稍后刷新账单确认'))
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -1500,7 +1274,7 @@ export default {
|
||||
return userDetailCancel(this.buildCancelOrderPayload(item), this.language)
|
||||
.then(() => {
|
||||
uni.showToast({
|
||||
title: this.t('cancelOrderSuccess'),
|
||||
title: this.$tr('订单已取消'),
|
||||
icon: 'success'
|
||||
})
|
||||
return this.refreshBillList()
|
||||
@@ -1508,7 +1282,7 @@ export default {
|
||||
})
|
||||
.catch((error) => {
|
||||
uni.showToast({
|
||||
title: (error && (error.message || error.msg)) || this.t('cancelOrderFailed'),
|
||||
title: (error && (error.message || error.msg)) || this.$tr('取消订单失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
@@ -1554,7 +1328,7 @@ export default {
|
||||
this.billList = []
|
||||
this.pendingPaymentOrderMap = {}
|
||||
uni.showToast({
|
||||
title: (error && (error.message || error.msg)) || this.t('billLoadFailed'),
|
||||
title: (error && (error.message || error.msg)) || this.$tr('账单加载失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
return []
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<view class="contract-detail-page tn-safe-area-inset-bottom">
|
||||
<tn-nav-bar :isBack="true" :bottomShadow="false" backgroundColor="transparent">
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ t('navTitle') }}</view>
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ $tr('合同详情') }}</view>
|
||||
</tn-nav-bar>
|
||||
|
||||
<view class="page-main" :style="{ paddingTop: vuex_custom_bar_height + 'px' }">
|
||||
<view class="overview-panel">
|
||||
<view class="overview-header">
|
||||
<view>
|
||||
<view class="overview-title">{{ t('overviewTitle') }}</view>
|
||||
<view class="overview-subtitle">{{ t('contractNoLabel') }}{{ contractNo || t('notAvailable') }}</view>
|
||||
<view class="overview-title">{{ $tr('合同影像') }}</view>
|
||||
<view class="overview-subtitle">{{ $tr('合同编号:') }}{{ contractNo || $tr('未获取') }}</view>
|
||||
</view>
|
||||
<view class="overview-badge">
|
||||
<text class="tn-icon-read"></text>
|
||||
@@ -19,26 +19,26 @@
|
||||
<view class="overview-tips">
|
||||
<view class="tip-chip">
|
||||
<text class="tn-icon-safe-fill"></text>
|
||||
<text>{{ t('signedChip') }}</text>
|
||||
<text>{{ $tr('已签合同') }}</text>
|
||||
</view>
|
||||
<view class="tip-chip">
|
||||
<text class="tn-icon-charts-ring"></text>
|
||||
<text>{{ t('zoomSupportedChip') }}</text>
|
||||
<text>{{ $tr('支持缩放') }}</text>
|
||||
</view>
|
||||
<view class="tip-chip" v-if="imageUrl">
|
||||
<text class="tn-icon-image-text-fill"></text>
|
||||
<text>{{ t('imageModeChip') }}</text>
|
||||
<text>{{ $tr('A4 影像模式') }}</text>
|
||||
</view>
|
||||
<view class="tip-chip" v-else-if="contractContent">
|
||||
<text class="tn-icon-text-new"></text>
|
||||
<text>{{ t('textModeChip') }}</text>
|
||||
<text>{{ $tr('正文预览模式') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="loading" class="empty-panel">
|
||||
<view class="empty-title">{{ t('loadingTitle') }}</view>
|
||||
<view class="empty-desc">{{ t('loadingDesc') }}</view>
|
||||
<view class="empty-title">{{ $tr('合同加载中') }}</view>
|
||||
<view class="empty-desc">{{ $tr('正在获取合同影像与正文,请稍候。') }}</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="imageUrl || contractContent" class="preview-panel">
|
||||
@@ -72,8 +72,8 @@
|
||||
<view class="empty-icon">
|
||||
<text class="tn-icon-folder"></text>
|
||||
</view>
|
||||
<view class="empty-title">{{ t('emptyTitle') }}</view>
|
||||
<view class="empty-desc">{{ t('emptyDesc') }}</view>
|
||||
<view class="empty-title">{{ $tr('暂无合同内容') }}</view>
|
||||
<view class="empty-desc">{{ $tr('页面未带入影像地址,且通过合同编号也未获取到可预览的合同内容。') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -100,36 +100,6 @@ function normalizeRichTextContent(content = '') {
|
||||
}
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
zh: {
|
||||
navTitle: '合同详情',
|
||||
overviewTitle: '合同影像',
|
||||
contractNoLabel: '合同编号:',
|
||||
notAvailable: '未获取',
|
||||
signedChip: '已签合同',
|
||||
zoomSupportedChip: '支持缩放',
|
||||
imageModeChip: 'A4 影像模式',
|
||||
textModeChip: '正文预览模式',
|
||||
loadingTitle: '合同加载中',
|
||||
loadingDesc: '正在获取合同影像与正文,请稍候。',
|
||||
emptyTitle: '暂无合同内容',
|
||||
emptyDesc: '页面未带入影像地址,且通过合同编号也未获取到可预览的合同内容。'
|
||||
},
|
||||
en: {
|
||||
navTitle: 'Contract Detail',
|
||||
overviewTitle: 'Contract Preview',
|
||||
contractNoLabel: 'Contract No.: ',
|
||||
notAvailable: 'N/A',
|
||||
signedChip: 'Signed Contract',
|
||||
zoomSupportedChip: 'Zoom Supported',
|
||||
imageModeChip: 'A4 Image Mode',
|
||||
textModeChip: 'Text Preview Mode',
|
||||
loadingTitle: 'Loading contract',
|
||||
loadingDesc: 'Fetching contract images and content. Please wait.',
|
||||
emptyTitle: 'No contract content',
|
||||
emptyDesc: 'No previewable contract content was provided by image URL or contract number.'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
contractNo: '',
|
||||
@@ -147,9 +117,6 @@ export default {
|
||||
this.fetchContractDetail()
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.contract_detail.contract_detail', key, params)
|
||||
},
|
||||
fetchContractDetail() {
|
||||
if (!this.contractNo || (this.imageUrl && this.contractContent)) {
|
||||
return Promise.resolve()
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<view class="contract-sign-page tn-safe-area-inset-bottom">
|
||||
<tn-nav-bar :isBack="true" :bottomShadow="false" backgroundColor="transparent">
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ t('navTitle') }}</view>
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ $tr('合同签约') }}</view>
|
||||
</tn-nav-bar>
|
||||
|
||||
<view class="page-main" :style="{ paddingTop: vuex_custom_bar_height + 'px' }">
|
||||
<view class="overview-panel">
|
||||
<view class="overview-header">
|
||||
<view>
|
||||
<view class="overview-title">{{ t('overviewTitle') }}</view>
|
||||
<view class="overview-subtitle">{{ t('contractNoLabel') }}{{ contractNo || t('notAvailable') }}</view>
|
||||
<view class="overview-title">{{ $tr('签约前确认') }}</view>
|
||||
<view class="overview-subtitle">{{ $tr('合同编号:') }}{{ contractNo || $tr('未获取') }}</view>
|
||||
</view>
|
||||
<view class="overview-badge">
|
||||
<text class="tn-icon-edit-write-fill"></text>
|
||||
@@ -18,13 +18,13 @@
|
||||
</view>
|
||||
<view class="overview-meta">
|
||||
<text class="tn-icon-safe-fill"></text>
|
||||
<text>{{ t('overviewMeta') }}</text>
|
||||
<text>{{ $tr('阅读合同正文后完成签名提交,签约结果会同步到我的合同。') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="loading" class="empty-panel">
|
||||
<view class="empty-title">{{ t('loadingTitle') }}</view>
|
||||
<view class="empty-desc">{{ t('loadingDesc') }}</view>
|
||||
<view class="empty-title">{{ $tr('合同加载中') }}</view>
|
||||
<view class="empty-desc">{{ $tr('正在获取合同正文,请稍候。') }}</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="contractContent" class="preview-panel">
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
<view class="preview-tip" @click="openFullscreenPreview">
|
||||
<text class="tn-icon-fullscreen"></text>
|
||||
<text>{{ t('fullscreenPreview') }}</text>
|
||||
<text>{{ $tr('点击全屏查看') }}</text>
|
||||
</view>
|
||||
|
||||
<view class="zoom-controls" @click.stop>
|
||||
@@ -56,17 +56,17 @@
|
||||
<view class="empty-icon">
|
||||
<text class="tn-icon-folder"></text>
|
||||
</view>
|
||||
<view class="empty-title">{{ t('emptyTitle') }}</view>
|
||||
<view class="empty-desc">{{ t('emptyDesc') }}</view>
|
||||
<view class="empty-title">{{ $tr('暂无合同正文') }}</view>
|
||||
<view class="empty-desc">{{ $tr('当前合同暂未返回可签约正文,请稍后再试。') }}</view>
|
||||
</view>
|
||||
|
||||
<view v-if="contractContent" class="footer-bar">
|
||||
<view class="footer-tip">
|
||||
<text class="tn-icon-safe-fill"></text>
|
||||
<text>{{ t('footerTip') }}</text>
|
||||
<text>{{ $tr('签名前请确认您已完整阅读合同内容') }}</text>
|
||||
</view>
|
||||
<view class="action-btn" @click="openSignBoard">
|
||||
{{ isSubmitting ? t('submitting') : t('signAction') }}
|
||||
{{ isSubmitting ? $tr('提交中...') : $tr('我已阅读并同意,去签名') }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -83,9 +83,9 @@
|
||||
<view class="fullscreen-header">
|
||||
<view class="fullscreen-back" @click="closeFullscreenPreview">
|
||||
<text class="tn-icon-left"></text>
|
||||
<text>{{ t('back') }}</text>
|
||||
<text>{{ $tr('返回') }}</text>
|
||||
</view>
|
||||
<view class="fullscreen-title">{{ t('fullscreenTitle') }}</view>
|
||||
<view class="fullscreen-title">{{ $tr('合同全文') }}</view>
|
||||
<view class="fullscreen-placeholder"></view>
|
||||
</view>
|
||||
<scroll-view scroll-y scroll-x class="fullscreen-scroll" :enable-flex="true">
|
||||
@@ -138,54 +138,6 @@ function resolveUploadedFileUrl(uploadResult) {
|
||||
}
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
zh: {
|
||||
navTitle: '合同签约',
|
||||
overviewTitle: '签约前确认',
|
||||
contractNoLabel: '合同编号:',
|
||||
notAvailable: '未获取',
|
||||
overviewMeta: '阅读合同正文后完成签名提交,签约结果会同步到我的合同。',
|
||||
loadingTitle: '合同加载中',
|
||||
loadingDesc: '正在获取合同正文,请稍候。',
|
||||
fullscreenPreview: '点击全屏查看',
|
||||
emptyTitle: '暂无合同正文',
|
||||
emptyDesc: '当前合同暂未返回可签约正文,请稍后再试。',
|
||||
footerTip: '签名前请确认您已完整阅读合同内容',
|
||||
submitting: '提交中...',
|
||||
signAction: '我已阅读并同意,去签名',
|
||||
back: '返回',
|
||||
fullscreenTitle: '合同全文',
|
||||
signerMissing: '未获取到签名人姓名',
|
||||
contractNoMissing: '缺少合同编号',
|
||||
signingLoading: '签约提交中...',
|
||||
uploadFailed: '签名上传失败',
|
||||
signSuccess: '签约成功',
|
||||
signFailed: '签约失败'
|
||||
},
|
||||
en: {
|
||||
navTitle: 'Contract Signing',
|
||||
overviewTitle: 'Before Signing',
|
||||
contractNoLabel: 'Contract No.: ',
|
||||
notAvailable: 'N/A',
|
||||
overviewMeta: 'Read the contract content before submitting your signature. The result will sync to My Contracts.',
|
||||
loadingTitle: 'Loading contract',
|
||||
loadingDesc: 'Fetching contract content. Please wait.',
|
||||
fullscreenPreview: 'Open Fullscreen',
|
||||
emptyTitle: 'No contract content',
|
||||
emptyDesc: 'No signable contract content is available at the moment. Please try again later.',
|
||||
footerTip: 'Please confirm that you have fully read the contract before signing',
|
||||
submitting: 'Submitting...',
|
||||
signAction: 'I have read and agree. Sign now',
|
||||
back: 'Back',
|
||||
fullscreenTitle: 'Full Contract',
|
||||
signerMissing: 'Missing signer name',
|
||||
contractNoMissing: 'Missing contract number',
|
||||
signingLoading: 'Submitting contract...',
|
||||
uploadFailed: 'Failed to upload signature',
|
||||
signSuccess: 'Contract signed successfully',
|
||||
signFailed: 'Failed to sign contract'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ContractSignDialog
|
||||
},
|
||||
@@ -209,9 +161,6 @@ export default {
|
||||
this.fetchContractContent()
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.contract_sign.contract_sign', key, params)
|
||||
},
|
||||
fetchContractContent() {
|
||||
if (!this.contractNo) {
|
||||
return Promise.resolve()
|
||||
@@ -238,14 +187,14 @@ export default {
|
||||
}
|
||||
if (!this.signerName) {
|
||||
uni.showToast({
|
||||
title: this.t('signerMissing'),
|
||||
title: this.$tr('未获取到签名人姓名'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.contractNo) {
|
||||
uni.showToast({
|
||||
title: this.t('contractNoMissing'),
|
||||
title: this.$tr('缺少合同编号'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -307,7 +256,7 @@ export default {
|
||||
|
||||
this.isSubmitting = true
|
||||
uni.showLoading({
|
||||
title: this.t('signingLoading'),
|
||||
title: this.$tr('签约提交中...'),
|
||||
mask: true
|
||||
})
|
||||
|
||||
@@ -322,7 +271,7 @@ export default {
|
||||
.then((uploadResult) => {
|
||||
const signImageUrl = resolveUploadedFileUrl(uploadResult)
|
||||
if (!signImageUrl) {
|
||||
return Promise.reject(new Error((uploadResult && uploadResult.msg) || this.t('uploadFailed')))
|
||||
return Promise.reject(new Error((uploadResult && uploadResult.msg) || this.$tr('签名上传失败')))
|
||||
}
|
||||
|
||||
return contractSign({
|
||||
@@ -349,7 +298,7 @@ export default {
|
||||
.then(() => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: this.t('signSuccess'),
|
||||
title: this.$tr('签约成功'),
|
||||
icon: 'success'
|
||||
})
|
||||
setTimeout(() => {
|
||||
@@ -362,7 +311,7 @@ export default {
|
||||
console.error('contract sign failed', error)
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: (error && (error.message || error.msg)) || this.t('signFailed'),
|
||||
title: (error && (error.message || error.msg)) || this.$tr('签约失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<view class="sheet-handle"></view>
|
||||
|
||||
<view class="sheet-header">
|
||||
<text class="sheet-title">{{ t('controlPanel') }}</text>
|
||||
<text class="sheet-title">{{ $tr('控制面板') }}</text>
|
||||
<text class="sheet-subtitle">{{ functionCountText }}</text>
|
||||
</view>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<text class="tn-icon-set panel-icon"></text>
|
||||
<text>{{ getFunctionLabel(func) }}</text>
|
||||
</view>
|
||||
<view class="status-tag" v-if="!isFunctionSupported(func)">{{ t('pendingTag') }}</view>
|
||||
<view class="status-tag" v-if="!isFunctionSupported(func)">{{ $tr('待完善') }}</view>
|
||||
</view>
|
||||
|
||||
<!-- Switch Theme -->
|
||||
@@ -60,7 +60,7 @@
|
||||
<block v-else-if="isSlideFunction(func)">
|
||||
<view class="slider-container">
|
||||
<view class="slider-header">
|
||||
<text class="slider-label">{{ t('sliderLabel') }}</text>
|
||||
<text class="slider-label">{{ $tr('亮度 / 数值') }}</text>
|
||||
<text class="slider-value">{{ controlValue }}%</text>
|
||||
</view>
|
||||
<slider
|
||||
@@ -76,7 +76,7 @@
|
||||
@change="handleControlValueChange"
|
||||
/>
|
||||
<view class="slider-apply-btn" :class="{ 'is-disabled': isSubmitting }" @click="submitSlideValue(index)">
|
||||
<text>{{ t('applySetting') }}</text>
|
||||
<text>{{ $tr('应用设置') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
@@ -86,22 +86,22 @@
|
||||
<view class="control-row curtain-row">
|
||||
<view class="curtain-btn" :class="{ 'is-active': curtainAction === 'open', 'is-disabled': isSubmitting }" @click="operateCurtain(index, 'open')">
|
||||
<text class="tn-icon-up"></text>
|
||||
<text class="btn-label">{{ t('curtainOpen') }}</text>
|
||||
<text class="btn-label">{{ $tr('打开') }}</text>
|
||||
</view>
|
||||
<view class="curtain-btn stop-btn" :class="{ 'is-active': curtainAction === 'stop', 'is-disabled': isSubmitting }" @click="operateCurtain(index, 'stop')">
|
||||
<text class="tn-icon-minus"></text>
|
||||
<text class="btn-label">{{ t('curtainPause') }}</text>
|
||||
<text class="btn-label">{{ $tr('暂停') }}</text>
|
||||
</view>
|
||||
<view class="curtain-btn" :class="{ 'is-active': curtainAction === 'close', 'is-disabled': isSubmitting }" @click="operateCurtain(index, 'close')">
|
||||
<text class="tn-icon-down"></text>
|
||||
<text class="btn-label">{{ t('curtainClose') }}</text>
|
||||
<text class="btn-label">{{ $tr('关闭') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view v-else class="unsupported-box" @click="notifyUnsupportedFunction(index)">
|
||||
<text class="tn-icon-warning"></text>
|
||||
<text>{{ t('unsupportedBoxText') }}</text>
|
||||
<text>{{ $tr('当前功能暂未开放使用,点击反馈') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -173,68 +173,6 @@ function resolveRefreshIntervalMs(value, fallback = 1000) {
|
||||
}
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
zh: {
|
||||
controlPanel: '控制面板',
|
||||
pendingTag: '待完善',
|
||||
sliderLabel: '亮度 / 数值',
|
||||
applySetting: '应用设置',
|
||||
curtainOpen: '打开',
|
||||
curtainPause: '暂停',
|
||||
curtainClose: '关闭',
|
||||
unsupportedBoxText: '当前功能暂未开放使用,点击反馈',
|
||||
deviceDetail: '设备详情',
|
||||
currentRoom: '当前房间',
|
||||
functionCount: '{count}项功能',
|
||||
commandSending: '指令下发中...',
|
||||
syncHint: '操作完成后会自动刷新设备状态',
|
||||
deviceMissing: '设备信息缺失',
|
||||
unsupportedFunction: '{name}操作功能未完善',
|
||||
unknownSchema: '未识别到参数模板',
|
||||
schemaApplied: '{name}参数已下发',
|
||||
actionSuccess: '操作成功',
|
||||
deviceIdMissing: '设备ID缺失',
|
||||
functionCodeMissing: '功能编码缺失',
|
||||
commandFailed: '指令下发失败',
|
||||
deviceClosed: '已关闭',
|
||||
deviceEnabled: '已开启',
|
||||
deviceOpened: '已打开',
|
||||
curtainOpened: '窗帘已打开',
|
||||
curtainClosed: '窗帘已关闭',
|
||||
curtainPaused: '窗帘已暂停',
|
||||
sliderUpdated: '滑块值已更新'
|
||||
},
|
||||
en: {
|
||||
controlPanel: 'Control Panel',
|
||||
pendingTag: 'Pending',
|
||||
sliderLabel: 'Brightness / Value',
|
||||
applySetting: 'Apply',
|
||||
curtainOpen: 'Open',
|
||||
curtainPause: 'Pause',
|
||||
curtainClose: 'Close',
|
||||
unsupportedBoxText: 'This function is not available yet. Tap to send feedback.',
|
||||
deviceDetail: 'Device Details',
|
||||
currentRoom: 'Current Room',
|
||||
functionCount: '{count} functions',
|
||||
commandSending: 'Sending command...',
|
||||
syncHint: 'Device status refreshes automatically after each action',
|
||||
deviceMissing: 'Missing device information',
|
||||
unsupportedFunction: '{name} is not fully supported yet',
|
||||
unknownSchema: 'No parameter template recognized',
|
||||
schemaApplied: '{name} parameters sent',
|
||||
actionSuccess: 'Action completed',
|
||||
deviceIdMissing: 'Missing device ID',
|
||||
functionCodeMissing: 'Missing function code',
|
||||
commandFailed: 'Failed to send command',
|
||||
deviceClosed: 'Closed',
|
||||
deviceEnabled: 'Enabled',
|
||||
deviceOpened: 'Opened',
|
||||
curtainOpened: 'Curtain opened',
|
||||
curtainClosed: 'Curtain closed',
|
||||
curtainPaused: 'Curtain paused',
|
||||
sliderUpdated: 'Slider value updated'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
brandId: DEFAULT_BRAND_ID,
|
||||
@@ -257,10 +195,10 @@ export default {
|
||||
return this.$getLanguage()
|
||||
},
|
||||
deviceName() {
|
||||
return this.device.deviceName || this.t('deviceDetail')
|
||||
return this.device.deviceName || this.$tr('设备详情')
|
||||
},
|
||||
displayRoomName() {
|
||||
return this.roomName || this.roomCode || this.t('currentRoom')
|
||||
return this.roomName || this.roomCode || this.$tr('当前房间')
|
||||
},
|
||||
controlType() {
|
||||
return inferDeviceControlType(this.device)
|
||||
@@ -273,16 +211,16 @@ export default {
|
||||
},
|
||||
functionCountText() {
|
||||
const count = this.deviceFunctions.length
|
||||
return count ? this.t('functionCount', { count }) : this.controlTypeLabel
|
||||
return count ? this.$tr('{count}项功能', { count }) : this.controlTypeLabel
|
||||
},
|
||||
statusText() {
|
||||
return buildDeviceStateText(this.device)
|
||||
},
|
||||
syncHintText() {
|
||||
if (this.isSubmitting) {
|
||||
return this.t('commandSending')
|
||||
return this.$tr('指令下发中...')
|
||||
}
|
||||
return this.t('syncHint')
|
||||
return this.$tr('操作完成后会自动刷新设备状态')
|
||||
},
|
||||
deviceFunctions() {
|
||||
return getDeviceFunctions(this.device)
|
||||
@@ -306,7 +244,7 @@ export default {
|
||||
const parsedDevice = safeParseDevice(options.device)
|
||||
if (!parsedDevice) {
|
||||
uni.showToast({
|
||||
title: this.t('deviceMissing'),
|
||||
title: this.$tr('设备信息缺失'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -327,9 +265,6 @@ export default {
|
||||
this.stopDevicePolling()
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.device_control.device_control', key, params)
|
||||
},
|
||||
goBack() {
|
||||
uni.navigateBack()
|
||||
},
|
||||
@@ -613,7 +548,7 @@ export default {
|
||||
? this.getDeviceFunctionByIndex(funcOrIndex)
|
||||
: funcOrIndex
|
||||
uni.showToast({
|
||||
title: this.t('unsupportedFunction', { name: this.getFunctionLabel(func) }),
|
||||
title: this.$tr('{name}操作功能未完善', { name: this.getFunctionLabel(func) }),
|
||||
icon: 'none'
|
||||
})
|
||||
},
|
||||
@@ -676,7 +611,7 @@ export default {
|
||||
const fields = this.getFunctionFields(func, index)
|
||||
if (!fields.length) {
|
||||
uni.showToast({
|
||||
title: this.t('unknownSchema'),
|
||||
title: this.$tr('未识别到参数模板'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -688,11 +623,11 @@ export default {
|
||||
return result
|
||||
}, {})
|
||||
|
||||
this.executeCommand(func, payload, this.t('schemaApplied', { name: this.getFunctionLabel(func) }))
|
||||
this.executeCommand(func, payload, this.$tr('{name}参数已下发', { name: this.getFunctionLabel(func) }))
|
||||
},
|
||||
executeCommand(func, command, successText = this.t('actionSuccess')) {
|
||||
executeCommand(func, command, successText = this.$tr('操作成功')) {
|
||||
if (!this.device || !this.device.deviceNo) {
|
||||
uni.showToast({ title: this.t('deviceIdMissing'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('设备ID缺失'), icon: 'none' })
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
@@ -703,7 +638,7 @@ export default {
|
||||
|
||||
const functionCode = String((func && func.functionCode) || '').trim()
|
||||
if (!functionCode) {
|
||||
uni.showToast({ title: this.t('functionCodeMissing'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('功能编码缺失'), icon: 'none' })
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
@@ -720,7 +655,7 @@ export default {
|
||||
.catch((error) => {
|
||||
console.error('execute device command failed', error)
|
||||
uni.showToast({
|
||||
title: (error && (error.message || error.msg)) || this.t('commandFailed'),
|
||||
title: (error && (error.message || error.msg)) || this.$tr('指令下发失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
@@ -734,14 +669,14 @@ export default {
|
||||
if (this.isSubmitting) {
|
||||
return
|
||||
}
|
||||
this.executeCommand(func, this.buildSwitchCommandPayload(index, !this.device.active), this.device.active ? this.t('deviceClosed') : this.t('deviceEnabled'))
|
||||
this.executeCommand(func, this.buildSwitchCommandPayload(index, !this.device.active), this.device.active ? this.$tr('已关闭') : this.$tr('已开启'))
|
||||
},
|
||||
setSwitchState(index = 0, value) {
|
||||
const func = this.getDeviceFunctionByIndex(index)
|
||||
if (this.isSubmitting) {
|
||||
return
|
||||
}
|
||||
this.executeCommand(func, this.buildSwitchCommandPayload(index, !!value), value ? this.t('deviceOpened') : this.t('deviceClosed'))
|
||||
this.executeCommand(func, this.buildSwitchCommandPayload(index, !!value), value ? this.$tr('已打开') : this.$tr('已关闭'))
|
||||
},
|
||||
operateCurtain(index = 0, action) {
|
||||
const func = this.getDeviceFunctionByIndex(index)
|
||||
@@ -751,7 +686,7 @@ export default {
|
||||
this.executeCommand(
|
||||
func,
|
||||
this.buildCurtainCommandPayload(index, action),
|
||||
action === 'open' ? this.t('curtainOpened') : (action === 'close' ? this.t('curtainClosed') : this.t('curtainPaused'))
|
||||
action === 'open' ? this.$tr('窗帘已打开') : (action === 'close' ? this.$tr('窗帘已关闭') : this.$tr('窗帘已暂停'))
|
||||
)
|
||||
},
|
||||
handleControlValueChange(event) {
|
||||
@@ -765,7 +700,7 @@ export default {
|
||||
this.executeCommand(
|
||||
func,
|
||||
this.buildSlideCommandPayload(index, this.controlValue),
|
||||
this.t('sliderUpdated')
|
||||
this.$tr('滑块值已更新')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
:customBackStyle="navBarBackStyle"
|
||||
:fixed="true"
|
||||
>
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black" :style="{ opacity: navTitleOpacity }">{{ t('navTitle') }}</view>
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black" :style="{ opacity: navTitleOpacity }">{{ $tr('失物拾物') }}</view>
|
||||
</tn-nav-bar>
|
||||
|
||||
<scroll-view class="page-scroll" scroll-y :show-scrollbar="false" @scroll="handleScroll">
|
||||
@@ -15,76 +15,76 @@
|
||||
<view class="hero-header tn-margin-bottom-xl">
|
||||
<view class="hero-badge">
|
||||
<text class="badge-dot"></text>
|
||||
<text>{{ t('heroBadge') }}</text>
|
||||
<text>{{ $tr('社区服务') }}</text>
|
||||
</view>
|
||||
<view class="hero-title">{{ t('heroTitle') }}</view>
|
||||
<view class="hero-desc">{{ t('heroDesc') }}</view>
|
||||
<view class="hero-title">{{ $tr('发布失物或招领信息') }}</view>
|
||||
<view class="hero-desc">{{ $tr('将失物或拾获信息同步给社区,方便后续核实与快速匹配。') }}</view>
|
||||
</view>
|
||||
|
||||
<view class="form-card">
|
||||
<view class="block-title">{{ t('formTitle') }}</view>
|
||||
<view class="block-subtitle">{{ t('formDesc') }}</view>
|
||||
<view class="block-title">{{ $tr('物品信息') }}</view>
|
||||
<view class="block-subtitle">{{ $tr('请补充关键字段,必填项越完整,越方便他人联系与认领。') }}</view>
|
||||
|
||||
<view class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('typeLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('发布类型') }}</view>
|
||||
<picker mode="selector" :range="typeLabels" @change="handleTypeChange">
|
||||
<view class="form-picker">
|
||||
{{ selectedTypeLabel || t('typePlaceholder') }}
|
||||
{{ selectedTypeLabel || $tr('请选择失物或招领') }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('itemTypeLabel') }}</view>
|
||||
<input v-model="form.itemType" class="form-input" :placeholder="t('itemTypePlaceholder')" maxlength="40" />
|
||||
<view class="form-label">{{ $tr('物品类型') }}</view>
|
||||
<input v-model="form.itemType" class="form-input" :placeholder="$tr('例如证件、钥匙、电子设备')" maxlength="40" />
|
||||
</view>
|
||||
|
||||
<view class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('itemNameLabel') }}</view>
|
||||
<input v-model="form.itemName" class="form-input" :placeholder="t('itemNamePlaceholder')" maxlength="60" />
|
||||
<view class="form-label">{{ $tr('物品名称') }}</view>
|
||||
<input v-model="form.itemName" class="form-input" :placeholder="$tr('请输入物品名称')" maxlength="60" />
|
||||
</view>
|
||||
|
||||
<view class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('placeLabel') }}</view>
|
||||
<input v-model="form.place" class="form-input" :placeholder="t('placePlaceholder')" maxlength="100" />
|
||||
<view class="form-label">{{ $tr('地点') }}</view>
|
||||
<input v-model="form.place" class="form-input" :placeholder="$tr('请输入丢失或拾取地点')" maxlength="100" />
|
||||
</view>
|
||||
|
||||
<view class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('whenLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('时间') }}</view>
|
||||
<view class="picker-row">
|
||||
<picker mode="date" :value="form.whenDate" @change="handleDateChange">
|
||||
<view class="form-picker">{{ form.whenDate || t('selectDate') }}</view>
|
||||
<view class="form-picker">{{ form.whenDate || $tr('选择日期') }}</view>
|
||||
</picker>
|
||||
<picker mode="time" :value="form.whenTime" @change="handleTimeChange">
|
||||
<view class="form-picker form-picker--time">{{ form.whenTime || t('selectTime') }}</view>
|
||||
<view class="form-picker form-picker--time">{{ form.whenTime || $tr('选择时间') }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="field-tip">{{ t('whenTip') }}</view>
|
||||
<view class="field-tip">{{ $tr('可选,若已知大致时间可一并填写。') }}</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('contractLabel') }}</view>
|
||||
<input v-model="form.contract" class="form-input" :placeholder="t('contractPlaceholder')" maxlength="40" />
|
||||
<view class="form-label">{{ $tr('联系人') }}</view>
|
||||
<input v-model="form.contract" class="form-input" :placeholder="$tr('请输入联系人')" maxlength="40" />
|
||||
</view>
|
||||
|
||||
<view class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('contractPhoneLabel') }}</view>
|
||||
<input v-model="form.contractPhone" class="form-input" :placeholder="t('contractPhonePlaceholder')" maxlength="30" />
|
||||
<view class="form-label">{{ $tr('联系电话') }}</view>
|
||||
<input v-model="form.contractPhone" class="form-input" :placeholder="$tr('请输入联系电话')" maxlength="30" />
|
||||
</view>
|
||||
|
||||
<view class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('remarkLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('备注') }}</view>
|
||||
<textarea
|
||||
v-model="form.remark"
|
||||
class="form-textarea"
|
||||
:placeholder="t('remarkPlaceholder')"
|
||||
:placeholder="$tr('可补充外观特征、认领说明或其他辅助信息')"
|
||||
maxlength="300"
|
||||
></textarea>
|
||||
<view class="field-counter">{{ (form.remark || '').length }}/300</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('imagesLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('现场图片') }}</view>
|
||||
<tn-image-upload
|
||||
:key="uploadInstanceKey"
|
||||
:fileList="form.photos"
|
||||
@@ -104,11 +104,11 @@
|
||||
<template #addBtn>
|
||||
<view class="upload-trigger">
|
||||
<text class="tn-icon-camera-fill upload-trigger__icon"></text>
|
||||
<view class="upload-trigger__text">{{ t('uploadImage') }}</view>
|
||||
<view class="upload-trigger__text">{{ $tr('上传图片') }}</view>
|
||||
</view>
|
||||
</template>
|
||||
</tn-image-upload>
|
||||
<view class="field-tip">{{ t('imagesTip') }}</view>
|
||||
<view class="field-tip">{{ $tr('可选,上传现场图或物品图可提升识别效率。') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -116,9 +116,9 @@
|
||||
|
||||
<view class="floating-submit-bar">
|
||||
<view class="floating-submit-bar__inner">
|
||||
<view class="floating-submit-tip">{{ t('submitTip') }}</view>
|
||||
<view class="floating-submit-tip">{{ $tr('发布前请确认信息准确,系统会按当前语言提交接口。') }}</view>
|
||||
<view class="submit-btn btn-primary" :class="{ 'submit-btn--disabled': isSubmitting }" @click="submitForm">
|
||||
<text class="tn-text-bold">{{ isSubmitting ? t('submitting') : t('submitButton') }}</text>
|
||||
<text class="tn-text-bold">{{ isSubmitting ? $tr('发布中...') : $tr('立即发布') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -180,8 +180,8 @@ export default {
|
||||
},
|
||||
typeOptions() {
|
||||
return [
|
||||
{ value: 1, label: this.t('typeLost'), labelEn: this.t('typeLost') },
|
||||
{ value: 2, label: this.t('typeFound'), labelEn: this.t('typeFound') }
|
||||
{ value: 1, label: this.$tr('失物'), labelEn: this.$tr('失物') },
|
||||
{ value: 2, label: this.$tr('招领'), labelEn: this.$tr('招领') }
|
||||
]
|
||||
},
|
||||
typeLabels() {
|
||||
@@ -211,9 +211,6 @@ export default {
|
||||
this.prefillContact()
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.lost_found_publish.lost_found_publish', key, params)
|
||||
},
|
||||
createDefaultForm() {
|
||||
return {
|
||||
type: 1,
|
||||
@@ -288,20 +285,20 @@ export default {
|
||||
this.form.imageUrls.splice(index, 1)
|
||||
},
|
||||
onUploadError() {
|
||||
uni.showToast({ title: this.t('uploadFailed'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('图片上传失败'), icon: 'none' })
|
||||
},
|
||||
onUploadOversize() {
|
||||
uni.showToast({ title: this.t('uploadOversize'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('单张图片不能超过 5 MB'), icon: 'none' })
|
||||
},
|
||||
onUploadExceed() {
|
||||
uni.showToast({ title: this.t('uploadExceed'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('最多上传 6 张图片'), icon: 'none' })
|
||||
},
|
||||
getValidationMessage() {
|
||||
if (!String(this.form.itemType || '').trim()) return this.t('validateItemType')
|
||||
if (!String(this.form.itemName || '').trim()) return this.t('validateItemName')
|
||||
if (!String(this.form.place || '').trim()) return this.t('validatePlace')
|
||||
if (!String(this.form.contract || '').trim()) return this.t('validateContract')
|
||||
if (!String(this.form.contractPhone || '').trim()) return this.t('validateContractPhone')
|
||||
if (!String(this.form.itemType || '').trim()) return this.$tr('请输入物品类型')
|
||||
if (!String(this.form.itemName || '').trim()) return this.$tr('请输入物品名称')
|
||||
if (!String(this.form.place || '').trim()) return this.$tr('请输入地点')
|
||||
if (!String(this.form.contract || '').trim()) return this.$tr('请输入联系人')
|
||||
if (!String(this.form.contractPhone || '').trim()) return this.$tr('请输入联系电话')
|
||||
return ''
|
||||
},
|
||||
buildSubmitPayload() {
|
||||
@@ -335,7 +332,7 @@ export default {
|
||||
lostAndFoundPublish(this.buildSubmitPayload(), this.language)
|
||||
.then(() => {
|
||||
uni.showToast({
|
||||
title: this.t('submitSuccess'),
|
||||
title: this.$tr('发布成功'),
|
||||
icon: 'success'
|
||||
})
|
||||
this.resetForm()
|
||||
@@ -347,7 +344,7 @@ export default {
|
||||
})
|
||||
.catch((error) => {
|
||||
uni.showToast({
|
||||
title: (error && (error.message || error.msg)) || this.t('submitFailed'),
|
||||
title: (error && (error.message || error.msg)) || this.$tr('发布失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<view class="message-detail-page tn-safe-area-inset-bottom">
|
||||
<tn-nav-bar :isBack="true" :bottomShadow="false" backgroundColor="transparent">
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ t('navTitle') }}</view>
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ $tr('消息详情') }}</view>
|
||||
</tn-nav-bar>
|
||||
|
||||
<view class="page-main tn-padding" :style="{ paddingTop: vuex_custom_bar_height + 'px', paddingBottom: '48rpx' }">
|
||||
@@ -12,7 +12,7 @@
|
||||
<text :class="categoryIcon"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hero-title tn-margin-top">{{ localizedTitle || t('messageFallbackTitle') }}</view>
|
||||
<view class="hero-title tn-margin-top">{{ localizedTitle || $tr('消息通知') }}</view>
|
||||
<view class="hero-meta-row tn-margin-top">
|
||||
<view class="hero-meta-chip">
|
||||
<text class="tn-icon-time tn-margin-right-xs"></text>
|
||||
@@ -26,7 +26,7 @@
|
||||
</view>
|
||||
|
||||
<view class="article-header tn-margin-bottom-lg">
|
||||
<view class="article-title">{{ localizedTitle || t('messageFallbackTitle') }}</view>
|
||||
<view class="article-title">{{ localizedTitle || $tr('消息通知') }}</view>
|
||||
<view class="article-meta tn-margin-top">
|
||||
<view class="article-tag">{{ categoryText }}</view>
|
||||
<view class="article-time">{{ detail.time || '--' }}</view>
|
||||
@@ -34,42 +34,42 @@
|
||||
</view>
|
||||
|
||||
<view class="content-panel tn-margin-bottom-lg">
|
||||
<view class="panel-title">{{ t('contentTitle') }}</view>
|
||||
<view class="panel-title">{{ $tr('通知内容') }}</view>
|
||||
<rich-text class="article-content tn-margin-top" :nodes="contentNodes"></rich-text>
|
||||
</view>
|
||||
|
||||
<view v-if="localizedDesc && localizedDesc !== localizedContent" class="content-panel tn-margin-bottom-lg">
|
||||
<view class="panel-title">{{ t('summaryTitle') }}</view>
|
||||
<view class="panel-title">{{ $tr('摘要') }}</view>
|
||||
<view class="panel-desc tn-margin-top">{{ localizedDesc }}</view>
|
||||
</view>
|
||||
|
||||
<view class="meta-panel tn-margin-bottom-lg">
|
||||
<view class="meta-row">
|
||||
<text class="meta-label">{{ t('sourceLabel') }}</text>
|
||||
<text class="meta-label">{{ $tr('消息来源') }}</text>
|
||||
<text class="meta-value">{{ sourceText }}</text>
|
||||
</view>
|
||||
<view class="meta-row">
|
||||
<text class="meta-label">{{ t('categoryLabel') }}</text>
|
||||
<text class="meta-label">{{ $tr('消息分类') }}</text>
|
||||
<text class="meta-value">{{ categoryText }}</text>
|
||||
</view>
|
||||
<view v-if="detail.code" class="meta-row">
|
||||
<text class="meta-label">{{ t('codeLabel') }}</text>
|
||||
<text class="meta-label">{{ $tr('通知编码') }}</text>
|
||||
<view class="meta-action-wrap">
|
||||
<text class="meta-value">{{ detail.code }}</text>
|
||||
<view class="copy-btn" @click="copyCode">
|
||||
<text class="tn-text-xs tn-text-bold">{{ t('copy') }}</text>
|
||||
<text class="tn-text-xs tn-text-bold">{{ $tr('复制') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="detail.statusHint" class="meta-row">
|
||||
<text class="meta-label">{{ t('statusLabel') }}</text>
|
||||
<text class="meta-label">{{ $tr('当前状态') }}</text>
|
||||
<text class="meta-value">{{ detail.statusHint }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="action-row">
|
||||
<view class="ghost-btn" @click="goBackList">
|
||||
<text class="tn-text-bold">{{ t('backList') }}</text>
|
||||
<text class="tn-text-bold">{{ $tr('返回消息页') }}</text>
|
||||
</view>
|
||||
<view v-if="detail.path" class="action-btn" @click="handleGoBusiness">
|
||||
<text class="tn-text-bold">{{ actionButtonText }}</text>
|
||||
@@ -111,58 +111,6 @@ function normalizeContentToRichText(value = '', emptyText = '') {
|
||||
}
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
zh: {
|
||||
navTitle: '消息详情',
|
||||
messageFallbackTitle: '消息通知',
|
||||
contentTitle: '通知内容',
|
||||
summaryTitle: '摘要',
|
||||
sourceLabel: '消息来源',
|
||||
categoryLabel: '消息分类',
|
||||
codeLabel: '通知编码',
|
||||
copy: '复制',
|
||||
statusLabel: '当前状态',
|
||||
backList: '返回消息页',
|
||||
categorySystem: '系统通知',
|
||||
categoryPayment: '缴费账单',
|
||||
categoryButler: '管家消息',
|
||||
actionSystem: '前往相关页面',
|
||||
actionPayment: '去处理账单',
|
||||
actionButler: '去查看服务',
|
||||
actionDefault: '继续前往业务页',
|
||||
remoteSource: '系统通知接口',
|
||||
localSource: '本地业务消息',
|
||||
expiredDesc: '当前消息详情已失效,请返回消息中心重新打开。',
|
||||
expiredHint: '消息缓存已失效',
|
||||
codeCopied: '通知编号已复制',
|
||||
emptyContent: '暂无详细内容'
|
||||
},
|
||||
en: {
|
||||
navTitle: 'Message Detail',
|
||||
messageFallbackTitle: 'Notification',
|
||||
contentTitle: 'Content',
|
||||
summaryTitle: 'Summary',
|
||||
sourceLabel: 'Source',
|
||||
categoryLabel: 'Category',
|
||||
codeLabel: 'Notice Code',
|
||||
copy: 'Copy',
|
||||
statusLabel: 'Status',
|
||||
backList: 'Back to Messages',
|
||||
categorySystem: 'System Notice',
|
||||
categoryPayment: 'Payment Bill',
|
||||
categoryButler: 'Butler Message',
|
||||
actionSystem: 'Open Related Page',
|
||||
actionPayment: 'Handle Bill',
|
||||
actionButler: 'View Service',
|
||||
actionDefault: 'Continue to Page',
|
||||
remoteSource: 'Remote Notification API',
|
||||
localSource: 'Local Business Message',
|
||||
expiredDesc: 'This message detail has expired. Please return to the message center and open it again.',
|
||||
expiredHint: 'Message cache expired',
|
||||
codeCopied: 'Notice code copied',
|
||||
emptyContent: 'No detailed content available'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
lookupId: '',
|
||||
@@ -205,14 +153,14 @@ export default {
|
||||
},
|
||||
categoryText() {
|
||||
const map = {
|
||||
system: this.t('categorySystem'),
|
||||
payment: this.t('categoryPayment'),
|
||||
butler: this.t('categoryButler')
|
||||
system: this.$tr('系统通知'),
|
||||
payment: this.$tr('缴费账单'),
|
||||
butler: this.$tr('管家消息')
|
||||
}
|
||||
return map[this.detail.category] || this.t('messageFallbackTitle')
|
||||
return map[this.detail.category] || this.$tr('消息通知')
|
||||
},
|
||||
contentNodes() {
|
||||
return normalizeContentToRichText(this.localizedContent || this.localizedDesc || '', this.t('emptyContent'))
|
||||
return normalizeContentToRichText(this.localizedContent || this.localizedDesc || '', this.$tr('暂无详细内容'))
|
||||
},
|
||||
categoryIcon() {
|
||||
const map = {
|
||||
@@ -240,14 +188,14 @@ export default {
|
||||
},
|
||||
actionButtonText() {
|
||||
const map = {
|
||||
system: this.t('actionSystem'),
|
||||
payment: this.t('actionPayment'),
|
||||
butler: this.t('actionButler')
|
||||
system: this.$tr('前往相关页面'),
|
||||
payment: this.$tr('去处理账单'),
|
||||
butler: this.$tr('去查看服务')
|
||||
}
|
||||
return map[this.detail.category] || this.t('actionDefault')
|
||||
return map[this.detail.category] || this.$tr('继续前往业务页')
|
||||
},
|
||||
sourceText() {
|
||||
return this.detail.source === 'remote' ? this.t('remoteSource') : this.t('localSource')
|
||||
return this.detail.source === 'remote' ? this.$tr('系统通知接口') : this.$tr('本地业务消息')
|
||||
}
|
||||
},
|
||||
onLoad(options = {}) {
|
||||
@@ -264,9 +212,6 @@ export default {
|
||||
clearMessageDetailPayload(this.language)
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.message_detail.message_detail', key, params)
|
||||
},
|
||||
restoreDetail() {
|
||||
const payload = getMessageDetailPayload(this.language)
|
||||
const fallbackPayload = findMessageDetailPayload(this.lookupId, this.lookupCode, this.language)
|
||||
@@ -284,17 +229,17 @@ export default {
|
||||
...this.detail,
|
||||
id: this.lookupId || this.lookupCode || '',
|
||||
code: this.lookupCode || '',
|
||||
titleZh: this.t('messageFallbackTitle'),
|
||||
titleEn: this.t('messageFallbackTitle'),
|
||||
descZh: this.t('expiredDesc'),
|
||||
descEn: this.t('expiredDesc'),
|
||||
contentZh: this.t('expiredDesc'),
|
||||
contentEn: this.t('expiredDesc'),
|
||||
title: this.t('messageFallbackTitle'),
|
||||
desc: this.t('expiredDesc'),
|
||||
content: this.t('expiredDesc'),
|
||||
titleZh: this.$tr('消息通知'),
|
||||
titleEn: this.$tr('消息通知'),
|
||||
descZh: this.$tr('当前消息详情已失效,请返回消息中心重新打开。'),
|
||||
descEn: this.$tr('当前消息详情已失效,请返回消息中心重新打开。'),
|
||||
contentZh: this.$tr('当前消息详情已失效,请返回消息中心重新打开。'),
|
||||
contentEn: this.$tr('当前消息详情已失效,请返回消息中心重新打开。'),
|
||||
title: this.$tr('消息通知'),
|
||||
desc: this.$tr('当前消息详情已失效,请返回消息中心重新打开。'),
|
||||
content: this.$tr('当前消息详情已失效,请返回消息中心重新打开。'),
|
||||
source: 'remote',
|
||||
statusHint: this.t('expiredHint')
|
||||
statusHint: this.$tr('消息缓存已失效')
|
||||
}
|
||||
},
|
||||
goBackList() {
|
||||
@@ -308,7 +253,7 @@ export default {
|
||||
data: String(this.detail.code),
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: this.t('codeCopied'),
|
||||
title: this.$tr('通知编号已复制'),
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<view class="my-application-page tn-safe-area-inset-bottom">
|
||||
<tn-nav-bar :isBack="true" :bottomShadow="false" backgroundColor="transparent">
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ t('navTitle') }}</view>
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ $tr('我的申请') }}</view>
|
||||
</tn-nav-bar>
|
||||
|
||||
<view class="page-main tn-padding" :style="{ paddingTop: vuex_custom_bar_height + 'px', paddingBottom: '48rpx' }">
|
||||
@@ -20,7 +20,7 @@
|
||||
</scroll-view>
|
||||
|
||||
<view class="toolbar-row tn-margin-bottom-lg">
|
||||
<view class="toolbar-summary">{{ t('toolbarSummary', { total }) }}</view>
|
||||
<view class="toolbar-summary">{{ $tr('共 {total} 条申请', { total }) }}</view>
|
||||
<view
|
||||
class="refresh-btn"
|
||||
:class="{ 'refresh-btn--loading': loading }"
|
||||
@@ -30,7 +30,7 @@
|
||||
class="tn-text-bold tn-flex tn-flex-row-center tn-flex-col-center"
|
||||
>
|
||||
<text v-if="loading" class="tn-icon-loading tn-margin-right-xs spin"></text>
|
||||
{{ loading ? t('refreshing') : t('refresh') }}
|
||||
{{ loading ? $tr('刷新中...') : $tr('刷新状态') }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -54,23 +54,23 @@
|
||||
|
||||
<view class="card-body tn-margin-top">
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('apartmentLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('所属公寓') }}</text>
|
||||
<text class="info-value">{{ item.intendedAreaName || '--' }}</text>
|
||||
</view>
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('occupantLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('入住人') }}</text>
|
||||
<text class="info-value">{{ item.userName || item.phone || '--' }}</text>
|
||||
</view>
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ item.isViewingApplication ? t('viewingTimeLabel') : t('leaseTermLabel') }}</text>
|
||||
<text class="info-label">{{ item.isViewingApplication ? $tr('预约时间') : $tr('预计租期') }}</text>
|
||||
<text class="info-value">{{ formatDateRange(item.start, item.end) }}</text>
|
||||
</view>
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('submittedAtLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('提交时间') }}</text>
|
||||
<text class="info-value">{{ formatDateTime(item.createTime) }}</text>
|
||||
</view>
|
||||
<view v-if="item.remark" class="remark-panel tn-margin-top">
|
||||
<view class="remark-label">{{ t('remarkLabel') }}</view>
|
||||
<view class="remark-label">{{ $tr('补充说明') }}</view>
|
||||
<view class="remark-text tn-margin-top-xs">{{ item.remark }}</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -80,29 +80,29 @@
|
||||
:data-reference-type-no="resolveReferenceTypeNo(item)"
|
||||
@click="goToBillPage"
|
||||
>
|
||||
<text class="tn-text-bold">{{ t('viewBill') }}</text>
|
||||
<text class="tn-text-bold">{{ $tr('查看关联账单') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="load-state">
|
||||
<text v-if="loadingMore">{{ t('loadingMore') }}</text>
|
||||
<text v-else-if="!hasMore">{{ t('noMore') }}</text>
|
||||
<text v-else>{{ t('pullUpMore') }}</text>
|
||||
<text v-if="loadingMore">{{ $tr('加载中...') }}</text>
|
||||
<text v-else-if="!hasMore">{{ $tr('没有更多申请了') }}</text>
|
||||
<text v-else>{{ $tr('上拉加载更多') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="!loading" class="empty-panel tn-padding-lg">
|
||||
<view class="empty-title">{{ t('emptyTitle') }}</view>
|
||||
<view class="empty-desc tn-margin-top-sm">{{ t('emptyDesc') }}</view>
|
||||
<view class="empty-title">{{ $tr('暂无申请记录') }}</view>
|
||||
<view class="empty-desc tn-margin-top-sm">{{ $tr('您还没有提交任何申请,去选房后可发起入住申请或预约看房。') }}</view>
|
||||
<view class="action-btn tn-margin-top-lg" @click="goSelectRoom">
|
||||
<text class="tn-text-bold">{{ t('goSelectRoom') }}</text>
|
||||
<text class="tn-text-bold">{{ $tr('去选房') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="loading && !list.length" class="empty-panel tn-padding-lg">
|
||||
<view class="empty-title">{{ t('loadingTitle') }}</view>
|
||||
<view class="empty-desc tn-margin-top-sm">{{ t('loadingDesc') }}</view>
|
||||
<view class="empty-title">{{ $tr('申请列表加载中') }}</view>
|
||||
<view class="empty-desc tn-margin-top-sm">{{ $tr('正在同步您的入住申请记录,请稍候。') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -169,76 +169,6 @@ function normalizeApplicationList(list = []) {
|
||||
}
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
zh: {
|
||||
navTitle: '我的申请',
|
||||
toolbarSummary: '共 {total} 条申请',
|
||||
refreshing: '刷新中...',
|
||||
refresh: '刷新状态',
|
||||
apartmentLabel: '所属公寓',
|
||||
occupantLabel: '入住人',
|
||||
viewingTimeLabel: '预约时间',
|
||||
leaseTermLabel: '预计租期',
|
||||
submittedAtLabel: '提交时间',
|
||||
remarkLabel: '补充说明',
|
||||
viewBill: '查看关联账单',
|
||||
loadingMore: '加载中...',
|
||||
noMore: '没有更多申请了',
|
||||
pullUpMore: '上拉加载更多',
|
||||
emptyTitle: '暂无申请记录',
|
||||
emptyDesc: '您还没有提交任何申请,去选房后可发起入住申请或预约看房。',
|
||||
goSelectRoom: '去选房',
|
||||
loadingTitle: '申请列表加载中',
|
||||
loadingDesc: '正在同步您的入住申请记录,请稍候。',
|
||||
statusAll: '全部',
|
||||
statusPending: '待审核',
|
||||
statusApproved: '已通过',
|
||||
statusRejected: '已拒绝',
|
||||
statusFinished: '已结束',
|
||||
statusProcessing: '处理中',
|
||||
refreshSuccess: '申请状态已刷新',
|
||||
loadError: '申请记录加载失败',
|
||||
viewingApplicationTitle: '预约看房申请',
|
||||
stayApplicationTitle: '入住申请',
|
||||
missingBillCode: '申请单编号缺失',
|
||||
missingApplicationCode: '申请编号缺失',
|
||||
dateRangeJoiner: ' 至 '
|
||||
},
|
||||
en: {
|
||||
navTitle: 'My Applications',
|
||||
toolbarSummary: '{total} applications',
|
||||
refreshing: 'Refreshing...',
|
||||
refresh: 'Refresh Status',
|
||||
apartmentLabel: 'Apartment',
|
||||
occupantLabel: 'Resident',
|
||||
viewingTimeLabel: 'Viewing Time',
|
||||
leaseTermLabel: 'Lease Term',
|
||||
submittedAtLabel: 'Submitted At',
|
||||
remarkLabel: 'Remarks',
|
||||
viewBill: 'View Related Bill',
|
||||
loadingMore: 'Loading...',
|
||||
noMore: 'No more applications',
|
||||
pullUpMore: 'Pull up to load more',
|
||||
emptyTitle: 'No applications yet',
|
||||
emptyDesc: 'You have not submitted any application yet. Go select a room to start a stay or viewing application.',
|
||||
goSelectRoom: 'Select Room',
|
||||
loadingTitle: 'Loading applications',
|
||||
loadingDesc: 'Syncing your application records. Please wait.',
|
||||
statusAll: 'All',
|
||||
statusPending: 'Pending',
|
||||
statusApproved: 'Approved',
|
||||
statusRejected: 'Rejected',
|
||||
statusFinished: 'Closed',
|
||||
statusProcessing: 'Processing',
|
||||
refreshSuccess: 'Application status refreshed',
|
||||
loadError: 'Failed to load applications',
|
||||
viewingApplicationTitle: 'Viewing Request',
|
||||
stayApplicationTitle: 'Stay Application',
|
||||
missingBillCode: 'Missing application bill number',
|
||||
missingApplicationCode: 'Missing application number',
|
||||
dateRangeJoiner: ' to '
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
status: '',
|
||||
@@ -278,26 +208,23 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.my_application.my_application', key, params)
|
||||
},
|
||||
syncStatusOptions() {
|
||||
this.statusOptions = [
|
||||
{ label: this.t('statusAll'), value: '' },
|
||||
{ label: this.t('statusPending'), value: 0 },
|
||||
{ label: this.t('statusApproved'), value: 10 },
|
||||
{ label: this.t('statusRejected'), value: 20 },
|
||||
{ label: this.t('statusFinished'), value: 99 }
|
||||
{ label: this.$tr('全部'), value: '' },
|
||||
{ label: this.$tr('待审核'), value: 0 },
|
||||
{ label: this.$tr('已通过'), value: 10 },
|
||||
{ label: this.$tr('已拒绝'), value: 20 },
|
||||
{ label: this.$tr('已结束'), value: 99 }
|
||||
]
|
||||
},
|
||||
getStatusText(status) {
|
||||
const map = {
|
||||
0: this.t('statusPending'),
|
||||
10: this.t('statusApproved'),
|
||||
20: this.t('statusRejected'),
|
||||
99: this.t('statusFinished')
|
||||
0: this.$tr('待审核'),
|
||||
10: this.$tr('已通过'),
|
||||
20: this.$tr('已拒绝'),
|
||||
99: this.$tr('已结束')
|
||||
}
|
||||
return map[status] || this.t('statusProcessing')
|
||||
return map[status] || this.$tr('处理中')
|
||||
},
|
||||
getDisplayStatusText(item = {}) {
|
||||
if (this.language !== 'en' && item.statusDesc) {
|
||||
@@ -338,10 +265,10 @@ export default {
|
||||
const startText = this.formatDateTime(start)
|
||||
const endText = this.formatDateTime(end)
|
||||
if (String(start).includes('T') || String(end).includes('T')) {
|
||||
return `${startText}${this.t('dateRangeJoiner')}${endText}`
|
||||
return `${startText}${this.$tr(' 至 ')}${endText}`
|
||||
}
|
||||
}
|
||||
return `${this.formatDate(start)}${this.t('dateRangeJoiner')}${this.formatDate(end)}`
|
||||
return `${this.formatDate(start)}${this.$tr(' 至 ')}${this.formatDate(end)}`
|
||||
},
|
||||
async refreshStatus() {
|
||||
if (this.loading || this.loadingMore) {
|
||||
@@ -350,7 +277,7 @@ export default {
|
||||
await this.reloadList()
|
||||
if (this.list.length || this.total === 0) {
|
||||
uni.showToast({
|
||||
title: this.t('refreshSuccess'),
|
||||
title: this.$tr('申请状态已刷新'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
@@ -407,7 +334,7 @@ export default {
|
||||
this.pageIndex = Math.max(1, this.pageIndex - 1)
|
||||
}
|
||||
uni.showToast({
|
||||
title: (error && (error.message || error.msg)) || this.t('loadError'),
|
||||
title: (error && (error.message || error.msg)) || this.$tr('申请记录加载失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
@@ -431,9 +358,9 @@ export default {
|
||||
},
|
||||
getApplicationTitle(item = {}) {
|
||||
if (item.isViewingApplication) {
|
||||
return this.t('viewingApplicationTitle')
|
||||
return this.$tr('预约看房申请')
|
||||
}
|
||||
return item.intendedRoomTypeName || this.t('stayApplicationTitle')
|
||||
return item.intendedRoomTypeName || this.$tr('入住申请')
|
||||
},
|
||||
resolveReferenceTypeNo(item = {}) {
|
||||
return item.detailCode || ''
|
||||
@@ -495,7 +422,7 @@ export default {
|
||||
: ''
|
||||
if (!referenceTypeNo) {
|
||||
uni.showToast({
|
||||
title: this.t('missingBillCode'),
|
||||
title: this.$tr('申请单编号缺失'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<view class="my-contract-page tn-safe-area-inset-bottom">
|
||||
<tn-nav-bar :isBack="true" :bottomShadow="false" backgroundColor="transparent">
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ t('navTitle') }}</view>
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ $tr('我的合同') }}</view>
|
||||
</tn-nav-bar>
|
||||
|
||||
<view class="page-main" :style="{ paddingTop: vuex_custom_bar_height + 'px' }">
|
||||
<view class="overview-panel">
|
||||
<view class="overview-header">
|
||||
<view>
|
||||
<view class="overview-title">{{ t('overviewTitle') }}</view>
|
||||
<view class="overview-subtitle">{{ t('overviewSubtitle') }}</view>
|
||||
<view class="overview-title">{{ $tr('合同概览') }}</view>
|
||||
<view class="overview-subtitle">{{ $tr('查看住宿合同、签约状态与有效期限') }}</view>
|
||||
</view>
|
||||
<view class="overview-badge">
|
||||
<text class="tn-icon-edit-form"></text>
|
||||
@@ -18,11 +18,11 @@
|
||||
</view>
|
||||
<view class="overview-metrics">
|
||||
<view class="metric-item">
|
||||
<view class="metric-label">{{ t('pendingMetricLabel') }}</view>
|
||||
<view class="metric-label">{{ $tr('待签约/审批') }}</view>
|
||||
<view class="metric-value">{{ summaryStats.pending }}</view>
|
||||
</view>
|
||||
<view class="metric-item is-primary">
|
||||
<view class="metric-label">{{ t('displayMetricLabel') }}</view>
|
||||
<view class="metric-label">{{ $tr('当前展示') }}</view>
|
||||
<view class="metric-value">{{ displayList.length }}</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -41,8 +41,8 @@
|
||||
</view>
|
||||
|
||||
<view v-if="loading" class="empty-panel">
|
||||
<view class="empty-title">{{ t('loadingTitle') }}</view>
|
||||
<view class="empty-desc">{{ t('loadingDesc') }}</view>
|
||||
<view class="empty-title">{{ $tr('合同记录加载中') }}</view>
|
||||
<view class="empty-desc">{{ $tr('正在同步您的合同数据,请稍候。') }}</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="displayList.length" class="list-wrapper">
|
||||
@@ -58,7 +58,7 @@
|
||||
<text class="tn-icon-edit-write-fill"></text>
|
||||
</view>
|
||||
<view class="card-title-group">
|
||||
<view class="card-title">{{ t('contractTitle') }}</view>
|
||||
<view class="card-title">{{ $tr('住宿合同') }}</view>
|
||||
<view class="card-code">{{ item.no || item.contractNo || '--' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -70,26 +70,26 @@
|
||||
|
||||
<view class="meta-strip">
|
||||
<view class="meta-chip">
|
||||
<view class="meta-chip-label">{{ t('relatedOrderLabel') }}</view>
|
||||
<view class="meta-chip-label">{{ $tr('关联订单') }}</view>
|
||||
<view class="meta-chip-value">{{ item.orderNo || '--' }}</view>
|
||||
</view>
|
||||
<view class="meta-chip">
|
||||
<view class="meta-chip-label">{{ t('signStatusLabel') }}</view>
|
||||
<view class="meta-chip-value">{{ item.signImageUrl ? t('signed') : t('unsigned') }}</view>
|
||||
<view class="meta-chip-label">{{ $tr('签署状态') }}</view>
|
||||
<view class="meta-chip-value">{{ item.signImageUrl ? $tr('已签名') : $tr('待签名') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="detail-panel">
|
||||
<view class="info-row">
|
||||
<text class="info-label">{{ t('contractPeriodLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('合同期限') }}</text>
|
||||
<text class="info-value">{{ formatDateRange(item.start, item.end) }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">{{ t('recordTipLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('记录说明') }}</text>
|
||||
<text class="info-value">{{ getStatusTip(item) }}</text>
|
||||
</view>
|
||||
<view v-if="item.signImageUrl" class="sign-row">
|
||||
<text class="info-label">{{ t('mySignatureLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('我的签名') }}</text>
|
||||
<view class="sign-preview">
|
||||
<image :src="item.signImageUrl" mode="aspectFit"></image>
|
||||
</view>
|
||||
@@ -112,8 +112,8 @@
|
||||
<view class="empty-icon">
|
||||
<text class="tn-icon-folder"></text>
|
||||
</view>
|
||||
<view class="empty-title">{{ t('emptyTitle') }}</view>
|
||||
<view class="empty-desc">{{ t('emptyDesc') }}</view>
|
||||
<view class="empty-title">{{ $tr('暂无对应的合同记录') }}</view>
|
||||
<view class="empty-desc">{{ $tr('切换筛选条件,或等待系统生成新的合同数据。') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -133,74 +133,6 @@ function normalizeContract(item = {}) {
|
||||
}
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
zh: {
|
||||
navTitle: '我的合同',
|
||||
overviewTitle: '合同概览',
|
||||
overviewSubtitle: '查看住宿合同、签约状态与有效期限',
|
||||
pendingMetricLabel: '待签约/审批',
|
||||
displayMetricLabel: '当前展示',
|
||||
loadingTitle: '合同记录加载中',
|
||||
loadingDesc: '正在同步您的合同数据,请稍候。',
|
||||
contractTitle: '住宿合同',
|
||||
relatedOrderLabel: '关联订单',
|
||||
signStatusLabel: '签署状态',
|
||||
signed: '已签名',
|
||||
unsigned: '待签名',
|
||||
contractPeriodLabel: '合同期限',
|
||||
recordTipLabel: '记录说明',
|
||||
mySignatureLabel: '我的签名',
|
||||
emptyTitle: '暂无对应的合同记录',
|
||||
emptyDesc: '切换筛选条件,或等待系统生成新的合同数据。',
|
||||
tabAll: '全部',
|
||||
tabPending: '待签约',
|
||||
statusRejected: '已拒绝',
|
||||
statusPending: '待审批',
|
||||
statusApproved: '已通过',
|
||||
statusProcessing: '处理中',
|
||||
dateRangeJoiner: ' 至 ',
|
||||
tipApproved: '合同已生效,可查看签约结果。',
|
||||
tipNeedSign: '待您完成签名后进入审批流程。',
|
||||
tipPending: '已提交签约信息,等待审批结果。',
|
||||
tipRejected: '合同未通过审批,请联系管理员处理。',
|
||||
tipDefault: '请关注合同最新状态。',
|
||||
actionSign: '去签约',
|
||||
actionViewDetail: '查看详情'
|
||||
},
|
||||
en: {
|
||||
navTitle: 'My Contracts',
|
||||
overviewTitle: 'Contract Overview',
|
||||
overviewSubtitle: 'Check stay contracts, signing status, and effective period',
|
||||
pendingMetricLabel: 'Pending Sign / Review',
|
||||
displayMetricLabel: 'Displayed',
|
||||
loadingTitle: 'Loading contracts',
|
||||
loadingDesc: 'Syncing your contract data. Please wait.',
|
||||
contractTitle: 'Stay Contract',
|
||||
relatedOrderLabel: 'Related Order',
|
||||
signStatusLabel: 'Signing Status',
|
||||
signed: 'Signed',
|
||||
unsigned: 'Unsigned',
|
||||
contractPeriodLabel: 'Contract Period',
|
||||
recordTipLabel: 'Notes',
|
||||
mySignatureLabel: 'My Signature',
|
||||
emptyTitle: 'No contract record found',
|
||||
emptyDesc: 'Switch filters or wait for new contract data to be generated.',
|
||||
tabAll: 'All',
|
||||
tabPending: 'Pending Sign',
|
||||
statusRejected: 'Rejected',
|
||||
statusPending: 'Pending Review',
|
||||
statusApproved: 'Approved',
|
||||
statusProcessing: 'Processing',
|
||||
dateRangeJoiner: ' to ',
|
||||
tipApproved: 'The contract is effective now. You can view the signing result.',
|
||||
tipNeedSign: 'Please complete your signature to enter the review process.',
|
||||
tipPending: 'Signing information has been submitted and is waiting for review.',
|
||||
tipRejected: 'The contract did not pass review. Please contact the administrator.',
|
||||
tipDefault: 'Please pay attention to the latest contract status.',
|
||||
actionSign: 'Sign Now',
|
||||
actionViewDetail: 'View Detail'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentTab: 'all',
|
||||
@@ -241,13 +173,10 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.my_contract.my_contract', key, params)
|
||||
},
|
||||
syncTabs() {
|
||||
this.tabs = [
|
||||
{ label: this.t('tabAll'), value: 'all' },
|
||||
{ label: this.t('tabPending'), value: 'pending' }
|
||||
{ label: this.$tr('全部'), value: 'all' },
|
||||
{ label: this.$tr('待签约'), value: 'pending' }
|
||||
]
|
||||
},
|
||||
getStoreUser() {
|
||||
@@ -316,11 +245,11 @@ export default {
|
||||
},
|
||||
getStatusText(status) {
|
||||
const map = {
|
||||
'-1': this.t('statusRejected'),
|
||||
'0': this.t('statusPending'),
|
||||
'1': this.t('statusApproved')
|
||||
'-1': this.$tr('已拒绝'),
|
||||
'0': this.$tr('待审批'),
|
||||
'1': this.$tr('已通过')
|
||||
}
|
||||
return map[String(status)] || this.t('statusProcessing')
|
||||
return map[String(status)] || this.$tr('处理中')
|
||||
},
|
||||
getDisplayStatusText(item = {}) {
|
||||
if (this.language !== 'en' && item.approvalStatusDesc) {
|
||||
@@ -340,28 +269,28 @@ export default {
|
||||
if (!start && !end) {
|
||||
return '--'
|
||||
}
|
||||
return `${this.formatDate(start)}${this.t('dateRangeJoiner')}${this.formatDate(end)}`
|
||||
return `${this.formatDate(start)}${this.$tr(' 至 ')}${this.formatDate(end)}`
|
||||
},
|
||||
getStatusTip(item = {}) {
|
||||
if (Number(item.approvalStatus) === 1) {
|
||||
return this.t('tipApproved')
|
||||
return this.$tr('合同已生效,可查看签约结果。')
|
||||
}
|
||||
if (Number(item.approvalStatus) === 0 && !item.signImageUrl) {
|
||||
return this.t('tipNeedSign')
|
||||
return this.$tr('待您完成签名后进入审批流程。')
|
||||
}
|
||||
if (Number(item.approvalStatus) === 0) {
|
||||
return this.t('tipPending')
|
||||
return this.$tr('已提交签约信息,等待审批结果。')
|
||||
}
|
||||
if (Number(item.approvalStatus) === -1) {
|
||||
return this.t('tipRejected')
|
||||
return this.$tr('合同未通过审批,请联系管理员处理。')
|
||||
}
|
||||
return this.t('tipDefault')
|
||||
return this.$tr('请关注合同最新状态。')
|
||||
},
|
||||
resolveActionText(item = {}) {
|
||||
if (this.shouldShowSignAction(item)) {
|
||||
return this.t('actionSign')
|
||||
return this.$tr('去签约')
|
||||
}
|
||||
return this.t('actionViewDetail')
|
||||
return this.$tr('查看详情')
|
||||
},
|
||||
shouldShowSignAction(item = {}) {
|
||||
return Number(item.approvalStatus) === 0 && !item.signImageUrl
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<!-- Header -->
|
||||
<view class="page-header" :style="{ paddingTop: vuex_custom_bar_height ? 'calc(' + vuex_custom_bar_height + 'px + 32rpx)' : '32rpx' }">
|
||||
<view class="title-wrap">
|
||||
<text class="title-zh">{{ t('pageTitle') }}</text>
|
||||
<text class="title-zh">{{ $tr('验房') }}</text>
|
||||
<text class="title-en">Inspection</text>
|
||||
</view>
|
||||
<view v-if="activeInspection" class="status-tag">
|
||||
@@ -37,15 +37,15 @@
|
||||
<!-- High Density Info Grid -->
|
||||
<view class="info-grid">
|
||||
<view class="info-cell">
|
||||
<text class="info-label">{{ t('roomNoLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('房间号') }}</text>
|
||||
<text class="info-value font-mono">{{ activeInspectionDetail.roomNo || '--' }}</text>
|
||||
</view>
|
||||
<view class="info-cell">
|
||||
<text class="info-label">{{ t('inspectionTypeLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('验房类型') }}</text>
|
||||
<text class="info-value">{{ activeInspectionDetail.typeText }}</text>
|
||||
</view>
|
||||
<view class="info-cell full-width">
|
||||
<text class="info-label">{{ t('inspectionTimeLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('发起时间') }}</text>
|
||||
<text class="info-value font-mono">{{ activeInspectionDetail.createTimeText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -55,7 +55,7 @@
|
||||
<textarea
|
||||
class="remarks-input"
|
||||
:value="remarksDraft"
|
||||
:placeholder="t('inspectionRemarksPlaceholder')"
|
||||
:placeholder="$tr('可填写本次验房的补充说明')"
|
||||
maxlength="300"
|
||||
auto-height
|
||||
@input="handleRemarksInput"
|
||||
@@ -65,7 +65,7 @@
|
||||
<!-- Items -->
|
||||
<view v-if="activeInspectionDetail.items.length" class="items-wrap">
|
||||
<view class="section-title">
|
||||
<text class="section-title-zh">{{ t('inspectionItemsTitle') }}</text>
|
||||
<text class="section-title-zh">{{ $tr('检查项') }}</text>
|
||||
<text class="section-title-en">Items</text>
|
||||
</view>
|
||||
|
||||
@@ -77,34 +77,34 @@
|
||||
>
|
||||
<view class="item-header">
|
||||
<view class="item-title-col">
|
||||
<text class="item-name">{{ item.deviceName || t('deviceFallback') }}</text>
|
||||
<text class="item-name">{{ item.deviceName || $tr('未命名设备') }}</text>
|
||||
<text class="item-meta" v-if="item.assetSourceText || item.brandSnapshot">
|
||||
{{ [item.assetSourceText, item.brandSnapshot].filter(Boolean).join(' / ') }}
|
||||
</text>
|
||||
</view>
|
||||
<text v-if="item.isRequiredSnapshot" class="item-required">{{ t('requiredTag') }}</text>
|
||||
<text v-if="item.isRequiredSnapshot" class="item-required">{{ $tr('必查') }}</text>
|
||||
</view>
|
||||
|
||||
<view class="item-body">
|
||||
<view class="row-flex">
|
||||
<view class="col-half">
|
||||
<text class="field-label">{{ t('expectedQuantityLabel') }}</text>
|
||||
<text class="field-label">{{ $tr('应有数量') }}</text>
|
||||
<text class="field-value font-mono">{{ item.expectedQuantityText }}</text>
|
||||
</view>
|
||||
<view class="col-half">
|
||||
<text class="field-label">{{ t('checkedQuantityLabel') }}</text>
|
||||
<text class="field-label">{{ $tr('实测数量') }}</text>
|
||||
<input
|
||||
class="field-input font-mono"
|
||||
type="number"
|
||||
:value="item.checkedQuantityDraft"
|
||||
:placeholder="t('checkedQuantityPlaceholder')"
|
||||
:placeholder="$tr('请输入数量')"
|
||||
@input="updateItemField(index, 'checkedQuantityDraft', $event.detail.value)"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="field-row mt-20">
|
||||
<text class="field-label">{{ t('inspectionResultLabel') }}</text>
|
||||
<text class="field-label">{{ $tr('检查结果') }}</text>
|
||||
<view class="radio-group">
|
||||
<view
|
||||
v-for="option in inspectionResultOptions"
|
||||
@@ -122,7 +122,7 @@
|
||||
<textarea
|
||||
class="field-textarea"
|
||||
:value="item.problemDetailDraft"
|
||||
:placeholder="t('problemDetailPlaceholder')"
|
||||
:placeholder="$tr('请描述异常、缺失或损坏情况')"
|
||||
maxlength="300"
|
||||
auto-height
|
||||
@input="updateItemField(index, 'problemDetailDraft', $event.detail.value)"
|
||||
@@ -155,25 +155,25 @@
|
||||
</view>
|
||||
|
||||
<view v-else-if="!loading" class="empty-state">
|
||||
<text class="empty-title">{{ t('emptyItemsTitle') }}</text>
|
||||
<text class="empty-desc">{{ t('emptyItemsDesc') }}</text>
|
||||
<text class="empty-title">{{ $tr('暂无检查项') }}</text>
|
||||
<text class="empty-desc">{{ $tr('当前验房单还没有检查项明细。') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="!loading && !inspectionList.length" class="empty-state">
|
||||
<text class="empty-title">{{ t('emptyTitle') }}</text>
|
||||
<text class="empty-desc">{{ t('emptyDesc') }}</text>
|
||||
<text class="empty-title">{{ $tr('暂无验房单') }}</text>
|
||||
<text class="empty-desc">{{ $tr('当前订单还没有可查看的验房记录。') }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="activeInspectionDetail" class="bottom-action">
|
||||
<view class="btn-submit" @click="submitInspection">
|
||||
{{ submitting ? t('submitting') : t('submitAction') }}
|
||||
{{ submitting ? $tr('提交中...') : $tr('提交验房') }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="loading" class="global-loading">
|
||||
<tn-loading mode="circle" color="#0F172A" size="48"></tn-loading>
|
||||
<text class="loading-text">{{ t('loadingDesc') }}</text>
|
||||
<text class="loading-text">{{ $tr('正在同步验房数据...') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -295,84 +295,6 @@ export default {
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
t(key) {
|
||||
const map = {
|
||||
zh: {
|
||||
pageTitle: '验房',
|
||||
pageDesc: '按当前订单查看并提交验房结果',
|
||||
inspectionListTitle: '验房记录',
|
||||
roomNoLabel: '房间号',
|
||||
inspectionTypeLabel: '验房类型',
|
||||
inspectionStatusLabel: '当前状态',
|
||||
inspectionTimeLabel: '发起时间',
|
||||
inspectionRemarksLabel: '备注',
|
||||
inspectionRemarksPlaceholder: '可填写本次验房的补充说明',
|
||||
inspectionItemsTitle: '检查项',
|
||||
inspectionItemsDesc: '请根据现场情况逐项核对',
|
||||
deviceFallback: '未命名设备',
|
||||
requiredTag: '必查',
|
||||
expectedQuantityLabel: '应有数量',
|
||||
inspectionResultLabel: '检查结果',
|
||||
checkedQuantityLabel: '实测数量',
|
||||
checkedQuantityPlaceholder: '请输入数量',
|
||||
problemDetailLabel: '问题说明',
|
||||
problemDetailPlaceholder: '请描述异常、缺失或损坏情况',
|
||||
photosLabel: '现场照片',
|
||||
addPhoto: '添加',
|
||||
submitAction: '提交验房',
|
||||
loadingDesc: '正在同步验房数据...',
|
||||
emptyTitle: '暂无验房单',
|
||||
emptyDesc: '当前订单还没有可查看的验房记录。',
|
||||
emptyItemsTitle: '暂无检查项',
|
||||
emptyItemsDesc: '当前验房单还没有检查项明细。',
|
||||
submitSuccess: '验房单已提交',
|
||||
submitFailed: '提交失败',
|
||||
submitting: '提交中...',
|
||||
missingInspectionNo: '未获取到验房单',
|
||||
uploadFailed: '图片上传失败',
|
||||
chooseImageFailed: '选择图片失败',
|
||||
resultRequired: '请先完成所有检查项结果选择'
|
||||
},
|
||||
en: {
|
||||
pageTitle: 'Inspection',
|
||||
pageDesc: 'Review and submit inspection results for the current order',
|
||||
inspectionListTitle: 'Inspection Records',
|
||||
roomNoLabel: 'Room No.',
|
||||
inspectionTypeLabel: 'Inspection Type',
|
||||
inspectionStatusLabel: 'Status',
|
||||
inspectionTimeLabel: 'Created At',
|
||||
inspectionRemarksLabel: 'Remarks',
|
||||
inspectionRemarksPlaceholder: 'Add notes for this inspection',
|
||||
inspectionItemsTitle: 'Inspection Items',
|
||||
inspectionItemsDesc: 'Check each item according to the on-site condition',
|
||||
deviceFallback: 'Unnamed Device',
|
||||
requiredTag: 'Required',
|
||||
expectedQuantityLabel: 'Expected Qty',
|
||||
inspectionResultLabel: 'Result',
|
||||
checkedQuantityLabel: 'Checked Qty',
|
||||
checkedQuantityPlaceholder: 'Enter quantity',
|
||||
problemDetailLabel: 'Problem Detail',
|
||||
problemDetailPlaceholder: 'Describe any abnormal, missing, or damaged condition',
|
||||
photosLabel: 'Photos',
|
||||
addPhoto: 'Add',
|
||||
submitAction: 'Submit',
|
||||
loadingDesc: 'Syncing inspection data...',
|
||||
emptyTitle: 'No inspections',
|
||||
emptyDesc: 'No inspection record is available for the current order.',
|
||||
emptyItemsTitle: 'No items',
|
||||
emptyItemsDesc: 'No inspection item is available for this inspection.',
|
||||
submitSuccess: 'Inspection submitted',
|
||||
submitFailed: 'Failed to submit',
|
||||
submitting: 'Submitting...',
|
||||
missingInspectionNo: 'Missing inspection record',
|
||||
uploadFailed: 'Failed to upload image',
|
||||
chooseImageFailed: 'Failed to choose image',
|
||||
resultRequired: 'Please complete the result selection for all items first'
|
||||
}
|
||||
}
|
||||
const lang = this.language === 'en' ? 'en' : 'zh'
|
||||
return (map[lang] && map[lang][key]) || key
|
||||
},
|
||||
syncInspectionResultOptions() {
|
||||
this.inspectionResultOptions = this.getEnumOptionsWithAliases([
|
||||
'InspectionItemResultEnum',
|
||||
@@ -561,7 +483,7 @@ export default {
|
||||
const hasMissingResult = items.some(item => item.result === null || Number.isNaN(item.result))
|
||||
if (hasMissingResult) {
|
||||
uni.showToast({
|
||||
title: this.t('resultRequired'),
|
||||
title: this.$tr('请先完成所有检查项结果选择'),
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
@@ -584,7 +506,7 @@ export default {
|
||||
items: this.buildSubmitItems()
|
||||
}, this.language)
|
||||
uni.showToast({
|
||||
title: this.t('submitSuccess'),
|
||||
title: this.$tr('验房单已提交'),
|
||||
icon: 'success'
|
||||
})
|
||||
setTimeout(() => {
|
||||
@@ -597,7 +519,7 @@ export default {
|
||||
}, 500)
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: (error && (error.message || error.msg)) || this.t('submitFailed'),
|
||||
title: (error && (error.message || error.msg)) || this.$tr('提交失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
@@ -615,7 +537,7 @@ export default {
|
||||
return
|
||||
}
|
||||
uni.showLoading({
|
||||
title: this.t('loadingDesc'),
|
||||
title: this.$tr('正在同步验房数据...'),
|
||||
mask: true
|
||||
})
|
||||
try {
|
||||
@@ -631,7 +553,7 @@ export default {
|
||||
)
|
||||
const remoteUrl = resolveUploadedFileUrl(uploadResult)
|
||||
if (!remoteUrl) {
|
||||
throw new Error(this.t('uploadFailed'))
|
||||
throw new Error(this.$tr('图片上传失败'))
|
||||
}
|
||||
uploadedUrls.push(addFilePrefix(remoteUrl))
|
||||
}
|
||||
@@ -643,7 +565,7 @@ export default {
|
||||
this.$set(detail.items[index], 'imageUrlsDraft', nextUrls)
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: (error && (error.message || error.msg)) || this.t('uploadFailed'),
|
||||
title: (error && (error.message || error.msg)) || this.$tr('图片上传失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
@@ -652,7 +574,7 @@ export default {
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: this.t('chooseImageFailed'),
|
||||
title: this.$tr('选择图片失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,22 +12,22 @@
|
||||
<view class="tn-bg-gray--light tn-padding-xl tn-border-radius-circle tn-margin-bottom">
|
||||
<text class="tn-icon-lock tn-color-gray" style="font-size: 80rpx;"></text>
|
||||
</view>
|
||||
<view class="hero-title tn-text-bold">{{ t('lockNoAccessTitle') }}</view>
|
||||
<view class="hero-desc tn-margin-top-sm tn-text-center">{{ t('lockNoAccessDesc') }}</view>
|
||||
<view class="hero-title tn-text-bold">{{ $tr('暂无门锁权限') }}</view>
|
||||
<view class="hero-desc tn-margin-top-sm tn-text-center">{{ $tr('您当前暂未分配智能门锁,或门锁暂未联网。\n入住后即可使用一键开门与临时密码下发功能。') }}</view>
|
||||
<view class="tn-flex tn-margin-top-xl tn-width-full tn-flex-row-between">
|
||||
<view class="btn-light tn-flex-1 tn-margin-right-sm tn-flex tn-flex-col-center tn-flex-row-center tn-padding-sm" style="border-radius: 12rpx; opacity: 0.6;">
|
||||
<text class="tn-icon-key tn-margin-right-xs"></text> {{ t('tempPassword') }}
|
||||
<text class="tn-icon-key tn-margin-right-xs"></text> {{ $tr('临时密码') }}
|
||||
</view>
|
||||
<view class="btn-primary tn-flex-1 tn-margin-left-sm tn-flex tn-flex-col-center tn-flex-row-center tn-padding-sm" style="border-radius: 12rpx; opacity: 0.6;">
|
||||
<text class="tn-icon-unlock tn-margin-right-xs"></text> {{ t('oneTapUnlock') }}
|
||||
<text class="tn-icon-unlock tn-margin-right-xs"></text> {{ $tr('一键开锁') }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="record-card tn-margin-top-lg">
|
||||
<view class="block-title">{{ t('authRecordTitle') }}</view>
|
||||
<view class="block-title">{{ $tr('授权记录') }}</view>
|
||||
<view class="tn-margin-top tn-flex tn-flex-row-center tn-padding-xl">
|
||||
<tn-empty icon="tn-icon-empty-data" :text="t('lockEmptyRecord')"></tn-empty>
|
||||
<tn-empty icon="tn-icon-empty-data" :text="$tr('暂无门锁操作记录')"></tn-empty>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -36,16 +36,16 @@
|
||||
<view v-else-if="pageKey === 'points'">
|
||||
<view class="hero-card" style="background: linear-gradient(135deg, #FFB703 0%, #FF8A00 100%); color: #fff; border: none;">
|
||||
<view class="tn-flex tn-flex-row-between tn-flex-col-center">
|
||||
<view class="tn-text-md">{{ t('pointsAvailable') }}</view>
|
||||
<view class="tn-text-sm" style="background: rgba(255,255,255,0.2); padding: 4rpx 16rpx; border-radius: 100rpx;">{{ t('redeemRules') }}</view>
|
||||
<view class="tn-text-md">{{ $tr('当前可用积分') }}</view>
|
||||
<view class="tn-text-sm" style="background: rgba(255,255,255,0.2); padding: 4rpx 16rpx; border-radius: 100rpx;">{{ $tr('兑换规则') }}</view>
|
||||
</view>
|
||||
<view class="tn-margin-top-lg tn-text-bold" style="font-size: 80rpx;">--</view>
|
||||
<view class="tn-margin-top tn-flex tn-flex-row-between">
|
||||
<view class="tn-flex tn-flex-col-center">
|
||||
<text class="tn-icon-calendar tn-margin-right-xs"></text> {{ t('dailyPoints') }}
|
||||
<text class="tn-icon-calendar tn-margin-right-xs"></text> {{ $tr('每日签到领积分') }}
|
||||
</view>
|
||||
<view class="tn-flex tn-flex-col-center" style="opacity: 0.8;">
|
||||
{{ t('goCheckIn') }} <text class="tn-icon-right tn-margin-left-xs"></text>
|
||||
{{ $tr('去签到') }} <text class="tn-icon-right tn-margin-left-xs"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -53,20 +53,20 @@
|
||||
<view class="tn-flex tn-flex-row-between tn-margin-top-lg">
|
||||
<view class="btn-light tn-flex-1 tn-margin-right-sm tn-flex tn-flex-direction-column tn-flex-col-center tn-padding-lg" style="border-radius: 20rpx;">
|
||||
<text class="tn-icon-shop tn-color-orange tn-margin-bottom-sm" style="font-size: 60rpx;"></text>
|
||||
<text class="tn-text-bold tn-color-black">{{ t('pointsMall') }}</text>
|
||||
<text class="tn-text-xs tn-color-gray tn-margin-top-xs">{{ t('pointsMallDesc') }}</text>
|
||||
<text class="tn-text-bold tn-color-black">{{ $tr('积分商城') }}</text>
|
||||
<text class="tn-text-xs tn-color-gray tn-margin-top-xs">{{ $tr('超值好物兑换') }}</text>
|
||||
</view>
|
||||
<view class="btn-light tn-flex-1 tn-margin-left-sm tn-flex tn-flex-direction-column tn-flex-col-center tn-padding-lg" style="border-radius: 20rpx;">
|
||||
<text class="tn-icon-coupon tn-color-purplered tn-margin-bottom-sm" style="font-size: 60rpx;"></text>
|
||||
<text class="tn-text-bold tn-color-black">{{ t('coupon') }}</text>
|
||||
<text class="tn-text-xs tn-color-gray tn-margin-top-xs">{{ t('couponDesc') }}</text>
|
||||
<text class="tn-text-bold tn-color-black">{{ $tr('优惠券') }}</text>
|
||||
<text class="tn-text-xs tn-color-gray tn-margin-top-xs">{{ $tr('租金水电抵扣') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="record-card tn-margin-top-lg">
|
||||
<view class="block-title">{{ t('pointsRecordTitle') }}</view>
|
||||
<view class="block-title">{{ $tr('积分明细') }}</view>
|
||||
<view class="tn-margin-top tn-flex tn-flex-row-center tn-padding-xl">
|
||||
<tn-empty icon="tn-icon-empty-data" :text="t('pointsEmpty')"></tn-empty>
|
||||
<tn-empty icon="tn-icon-empty-data" :text="$tr('暂无积分明细')"></tn-empty>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -74,28 +74,28 @@
|
||||
<!-- 一码通管理 Mockup -->
|
||||
<view v-else-if="pageKey === 'code'">
|
||||
<view class="hero-card tn-flex tn-flex-direction-column tn-flex-col-center">
|
||||
<view class="tn-text-md tn-color-black tn-text-bold">{{ t('accessCodeTitle') }}</view>
|
||||
<view class="tn-text-xs tn-color-gray tn-margin-top-xs">{{ t('accessCodeDesc') }}</view>
|
||||
<view class="tn-text-md tn-color-black tn-text-bold">{{ $tr('我的通行二维码') }}</view>
|
||||
<view class="tn-text-xs tn-color-gray tn-margin-top-xs">{{ $tr('可用于社区大门、单元门及电梯通行') }}</view>
|
||||
|
||||
<view class="qr-code-box tn-margin-top-xl tn-margin-bottom-lg tn-flex tn-flex-col-center tn-flex-row-center">
|
||||
<view class="qr-placeholder tn-flex tn-flex-col-center tn-flex-row-center">
|
||||
<text class="tn-icon-qr-code tn-color-gray" style="font-size: 200rpx; opacity: 0.2;"></text>
|
||||
</view>
|
||||
<view class="qr-mask tn-flex tn-flex-col-center tn-flex-row-center">
|
||||
<text class="tn-color-white tn-text-bold tn-text-lg">{{ t('noAccessPermission') }}</text>
|
||||
<text class="tn-color-white tn-text-bold tn-text-lg">{{ $tr('未获取通行权限') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="tn-text-xs tn-color-gray tn-text-center tn-margin-bottom">{{ t('accessAssignDesc') }}</view>
|
||||
<view class="tn-text-xs tn-color-gray tn-text-center tn-margin-bottom">{{ $tr('请在完成入住签约并录入人脸/实名信息后\n系统将自动为您分配通行权限') }}</view>
|
||||
</view>
|
||||
|
||||
<view class="record-card tn-margin-top-lg">
|
||||
<view class="tn-flex tn-flex-row-between tn-flex-col-center">
|
||||
<view class="block-title">{{ t('visitorAccessTitle') }}</view>
|
||||
<view class="tn-color-gray tn-text-sm">{{ t('visitorAccessAction') }} <text class="tn-icon-right"></text></view>
|
||||
<view class="block-title">{{ $tr('访客通行') }}</view>
|
||||
<view class="tn-color-gray tn-text-sm">{{ $tr('临时访客授权') }} <text class="tn-icon-right"></text></view>
|
||||
</view>
|
||||
<view class="tn-margin-top tn-flex tn-flex-row-center tn-padding-xl">
|
||||
<tn-empty icon="tn-icon-empty-data" :text="t('visitorEmpty')"></tn-empty>
|
||||
<tn-empty icon="tn-icon-empty-data" :text="$tr('暂无访客通行记录')"></tn-empty>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -103,25 +103,25 @@
|
||||
<!-- 默认通用占位 -->
|
||||
<view v-else>
|
||||
<view class="hero-card">
|
||||
<view class="hero-badge">{{ t('heroBadge') }}</view>
|
||||
<view class="hero-title tn-margin-top">{{ resolvedPageTitle || t('comingSoonTitle') }}</view>
|
||||
<view class="hero-badge">{{ $tr('即将开放') }}</view>
|
||||
<view class="hero-title tn-margin-top">{{ resolvedPageTitle || $tr('功能建设中') }}</view>
|
||||
<view class="hero-desc tn-margin-top-sm">{{ resolvedPageDesc || resolvedDefaultDesc }}</view>
|
||||
</view>
|
||||
|
||||
<view class="record-card tn-margin-top-xl">
|
||||
<view class="block-title">{{ t('currentStatusTitle') }}</view>
|
||||
<view class="block-title">{{ $tr('当前状态') }}</view>
|
||||
<view class="empty-text tn-margin-top">
|
||||
{{ t('currentStatusDesc') }}
|
||||
{{ $tr('该功能当前仍在建设中,暂未开放正式办理入口。你可以先返回上一页,或回到首页继续查看已开放功能。') }}
|
||||
</view>
|
||||
<view class="tip-card tn-margin-top-lg">
|
||||
<view class="tip-title">{{ t('noteTitle') }}</view>
|
||||
<view class="tip-desc tn-margin-top-xs">{{ t('noteDesc') }}</view>
|
||||
<view class="tip-title">{{ $tr('说明') }}</view>
|
||||
<view class="tip-desc tn-margin-top-xs">{{ $tr('后续接入真实能力后,这里会展示正式的业务入口、状态数据和办理记录。') }}</view>
|
||||
</view>
|
||||
<view class="submit-btn btn-primary tn-margin-top-xl" @click="goBack">
|
||||
<text class="tn-text-bold">{{ t('backPrev') }}</text>
|
||||
<text class="tn-text-bold">{{ $tr('返回上一页') }}</text>
|
||||
</view>
|
||||
<view class="submit-btn btn-light tn-margin-top" @click="goHome">
|
||||
<text class="tn-text-bold">{{ t('backHome') }}</text>
|
||||
<text class="tn-text-bold">{{ $tr('返回首页') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -143,78 +143,6 @@ function safeDecodeText(value, fallback = '') {
|
||||
}
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
zh: {
|
||||
defaultPageTitle: '业务办理',
|
||||
defaultPageDesc: '该能力正在完善中,开放后会同步到个人中心的对应入口。',
|
||||
lockNoAccessTitle: '暂无门锁权限',
|
||||
lockNoAccessDesc: '您当前暂未分配智能门锁,或门锁暂未联网。\n入住后即可使用一键开门与临时密码下发功能。',
|
||||
tempPassword: '临时密码',
|
||||
oneTapUnlock: '一键开锁',
|
||||
authRecordTitle: '授权记录',
|
||||
lockEmptyRecord: '暂无门锁操作记录',
|
||||
pointsAvailable: '当前可用积分',
|
||||
redeemRules: '兑换规则',
|
||||
dailyPoints: '每日签到领积分',
|
||||
goCheckIn: '去签到',
|
||||
pointsMall: '积分商城',
|
||||
pointsMallDesc: '超值好物兑换',
|
||||
coupon: '优惠券',
|
||||
couponDesc: '租金水电抵扣',
|
||||
pointsRecordTitle: '积分明细',
|
||||
pointsEmpty: '暂无积分明细',
|
||||
accessCodeTitle: '我的通行二维码',
|
||||
accessCodeDesc: '可用于社区大门、单元门及电梯通行',
|
||||
noAccessPermission: '未获取通行权限',
|
||||
accessAssignDesc: '请在完成入住签约并录入人脸/实名信息后\n系统将自动为您分配通行权限',
|
||||
visitorAccessTitle: '访客通行',
|
||||
visitorAccessAction: '临时访客授权',
|
||||
visitorEmpty: '暂无访客通行记录',
|
||||
heroBadge: '即将开放',
|
||||
comingSoonTitle: '功能建设中',
|
||||
currentStatusTitle: '当前状态',
|
||||
currentStatusDesc: '该功能当前仍在建设中,暂未开放正式办理入口。你可以先返回上一页,或回到首页继续查看已开放功能。',
|
||||
noteTitle: '说明',
|
||||
noteDesc: '后续接入真实能力后,这里会展示正式的业务入口、状态数据和办理记录。',
|
||||
backPrev: '返回上一页',
|
||||
backHome: '返回首页'
|
||||
},
|
||||
en: {
|
||||
defaultPageTitle: 'Service Center',
|
||||
defaultPageDesc: 'This capability is being improved and will appear in the related personal center entry when available.',
|
||||
lockNoAccessTitle: 'No door lock access',
|
||||
lockNoAccessDesc: 'No smart lock is assigned yet, or the lock is currently offline.\nAfter check-in, one-tap unlock and temporary password features will be available.',
|
||||
tempPassword: 'Temporary Code',
|
||||
oneTapUnlock: 'Unlock Now',
|
||||
authRecordTitle: 'Access Records',
|
||||
lockEmptyRecord: 'No door lock records',
|
||||
pointsAvailable: 'Available Points',
|
||||
redeemRules: 'Redeem Rules',
|
||||
dailyPoints: 'Daily check-in rewards',
|
||||
goCheckIn: 'Check In',
|
||||
pointsMall: 'Points Mall',
|
||||
pointsMallDesc: 'Redeem for selected items',
|
||||
coupon: 'Coupons',
|
||||
couponDesc: 'Offset rent and utilities',
|
||||
pointsRecordTitle: 'Points History',
|
||||
pointsEmpty: 'No points record',
|
||||
accessCodeTitle: 'My Access QR Code',
|
||||
accessCodeDesc: 'Use it for community gates, unit doors, and elevators',
|
||||
noAccessPermission: 'No access permission',
|
||||
accessAssignDesc: 'After completing check-in signing and face / identity enrollment,\nthe system will automatically assign your access permission.',
|
||||
visitorAccessTitle: 'Visitor Access',
|
||||
visitorAccessAction: 'Temporary visitor authorization',
|
||||
visitorEmpty: 'No visitor access records',
|
||||
heroBadge: 'Coming Soon',
|
||||
comingSoonTitle: 'Coming Soon',
|
||||
currentStatusTitle: 'Current Status',
|
||||
currentStatusDesc: 'This capability is still under development and is not yet officially available. You can go back or return to the home page to browse available features.',
|
||||
noteTitle: 'Notes',
|
||||
noteDesc: 'After the real capability is connected, this page will display the formal service entry, status data, and processing records.',
|
||||
backPrev: 'Go Back',
|
||||
backHome: 'Back Home'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageTitleZh: '',
|
||||
@@ -229,9 +157,9 @@ export default {
|
||||
computed: {
|
||||
resolvedPageTitle() {
|
||||
if (this.$getLanguage() === 'en') {
|
||||
return this.pageTitleEn || this.pageTitleZh || this.rawPageTitle || this.t('defaultPageTitle')
|
||||
return this.pageTitleEn || this.pageTitleZh || this.rawPageTitle || this.$tr('业务办理')
|
||||
}
|
||||
return this.pageTitleZh || this.pageTitleEn || this.rawPageTitle || this.t('defaultPageTitle')
|
||||
return this.pageTitleZh || this.pageTitleEn || this.rawPageTitle || this.$tr('业务办理')
|
||||
},
|
||||
resolvedPageDesc() {
|
||||
if (this.$getLanguage() === 'en') {
|
||||
@@ -240,7 +168,7 @@ export default {
|
||||
return this.pageDescZh || this.pageDescEn || this.rawPageDesc || ''
|
||||
},
|
||||
resolvedDefaultDesc() {
|
||||
return this.t('defaultPageDesc')
|
||||
return this.$tr('该能力正在完善中,开放后会同步到个人中心的对应入口。')
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
@@ -253,9 +181,6 @@ export default {
|
||||
this.pageKey = safeDecodeText(options && options.key, '')
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.service_stub.service_stub', key, params)
|
||||
},
|
||||
goBack() {
|
||||
uni.navigateBack()
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<view class="smart-page">
|
||||
<tn-nav-bar :isBack="true" :bottomShadow="false" backgroundColor="transparent" fontColor="#ffffff">
|
||||
<view class="tn-text-bold tn-text-xl">{{ t('navTitle') }}</view>
|
||||
<view class="tn-text-bold tn-text-xl">{{ $tr('全屋智能') }}</view>
|
||||
</tn-nav-bar>
|
||||
|
||||
<view class="header-section" :style="{ paddingTop: (vuex_custom_bar_height + 20) + 'px' }">
|
||||
@@ -13,31 +13,31 @@
|
||||
</view>
|
||||
|
||||
<view class="toolbar">
|
||||
<view class="toolbar-tip">{{ t('toolbarTip') }}</view>
|
||||
<view class="toolbar-tip">{{ $tr('点击设备进入详情并下发控制指令') }}</view>
|
||||
<view class="toolbar-action" @click="reloadDevices">
|
||||
<text class="tn-icon-refresh" :class="{'spin-anim': isLoading}" style="margin-right: 8rpx;"></text>
|
||||
<text>{{ isLoading ? t('loadingShort') : t('refreshStatus') }}</text>
|
||||
<text>{{ isLoading ? $tr('加载中') : $tr('刷新状态') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Feedback States -->
|
||||
<view v-if="isLoading && !devices.length" class="empty-state">
|
||||
<view class="loading-ring"></view>
|
||||
<view class="empty-title">{{ t('loadingTitle') }}</view>
|
||||
<view class="empty-desc">{{ t('loadingDesc') }}</view>
|
||||
<view class="empty-title">{{ $tr('正在连接设备') }}</view>
|
||||
<view class="empty-desc">{{ $tr('正在查询当前房间的可控设备...') }}</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="loadError && !devices.length" class="empty-state error-state">
|
||||
<text class="tn-icon-warning empty-icon"></text>
|
||||
<view class="empty-title">{{ t('loadFailedTitle') }}</view>
|
||||
<view class="empty-title">{{ $tr('设备加载失败') }}</view>
|
||||
<view class="empty-desc">{{ loadError }}</view>
|
||||
<view class="retry-btn" @click="reloadDevices">{{ t('retry') }}</view>
|
||||
<view class="retry-btn" @click="reloadDevices">{{ $tr('重新加载') }}</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="!devices.length" class="empty-state">
|
||||
<text class="tn-icon-empty empty-icon"></text>
|
||||
<view class="empty-title">{{ t('emptyTitle') }}</view>
|
||||
<view class="empty-desc">{{ t('emptyDesc') }}</view>
|
||||
<view class="empty-title">{{ $tr('暂无可控设备') }}</view>
|
||||
<view class="empty-desc">{{ $tr('当前房间未绑定智能设备') }}</view>
|
||||
</view>
|
||||
|
||||
<scroll-view v-else scroll-y class="device-scroll">
|
||||
@@ -58,7 +58,7 @@
|
||||
</view>
|
||||
<view class="card-bottom">
|
||||
<view class="device-name">{{ item.deviceName }}</view>
|
||||
<view class="device-state" :class="{'is-active': item.active}">{{ item.stateText || (item.active ? t('deviceRunning') : t('deviceOff')) }}</view>
|
||||
<view class="device-state" :class="{'is-active': item.active}">{{ item.stateText || (item.active ? $tr('运行中') : $tr('已关闭')) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -126,60 +126,6 @@ function resolveDeviceListPollingInterval(deviceList = [], fallback = 1000) {
|
||||
}
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
zh: {
|
||||
navTitle: '全屋智能',
|
||||
toolbarTip: '点击设备进入详情并下发控制指令',
|
||||
loadingShort: '加载中',
|
||||
refreshStatus: '刷新状态',
|
||||
loadingTitle: '正在连接设备',
|
||||
loadingDesc: '正在查询当前房间的可控设备...',
|
||||
loadFailedTitle: '设备加载失败',
|
||||
retry: '重新加载',
|
||||
emptyTitle: '暂无可控设备',
|
||||
emptyDesc: '当前房间未绑定智能设备',
|
||||
deviceSummary: '共 {count} 台设备,可进入详情页控制',
|
||||
deviceRunning: '运行中',
|
||||
deviceOff: '已关闭',
|
||||
currentRoom: '当前房间',
|
||||
missingRoomCode: '缺少房间编码',
|
||||
syncingStatus: '正在同步设备状态',
|
||||
unsupportedQuickControl: '设备暂不支持快捷控制',
|
||||
unsupportedSwitch: '该设备不支持快捷开关',
|
||||
missingFunctionCode: '功能编码缺失',
|
||||
sending: '发送中...',
|
||||
enabled: '已开启',
|
||||
disabled: '已关闭',
|
||||
commandFailed: '指令下发失败',
|
||||
requestFailed: '设备列表请求失败'
|
||||
},
|
||||
en: {
|
||||
navTitle: 'Smart Home',
|
||||
toolbarTip: 'Tap a device to open details and send control commands',
|
||||
loadingShort: 'Loading',
|
||||
refreshStatus: 'Refresh Status',
|
||||
loadingTitle: 'Connecting devices',
|
||||
loadingDesc: 'Checking controllable devices in the current room...',
|
||||
loadFailedTitle: 'Failed to load devices',
|
||||
retry: 'Retry',
|
||||
emptyTitle: 'No controllable devices',
|
||||
emptyDesc: 'No smart devices are bound to this room',
|
||||
deviceSummary: '{count} devices available. Tap to control in detail view',
|
||||
deviceRunning: 'Running',
|
||||
deviceOff: 'Off',
|
||||
currentRoom: 'Current Room',
|
||||
missingRoomCode: 'Missing room code',
|
||||
syncingStatus: 'Syncing device status',
|
||||
unsupportedQuickControl: 'Quick control is not supported for this device',
|
||||
unsupportedSwitch: 'This device does not support quick switching',
|
||||
missingFunctionCode: 'Missing function code',
|
||||
sending: 'Sending...',
|
||||
enabled: 'Enabled',
|
||||
disabled: 'Disabled',
|
||||
commandFailed: 'Failed to send command',
|
||||
requestFailed: 'Failed to request device list'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
brandId: DEFAULT_BRAND_ID,
|
||||
@@ -202,19 +148,19 @@ export default {
|
||||
return this.$getLanguage()
|
||||
},
|
||||
displayRoomName() {
|
||||
return this.roomName || this.roomCode || this.t('currentRoom')
|
||||
return this.roomName || this.roomCode || this.$tr('当前房间')
|
||||
},
|
||||
summaryText() {
|
||||
if (!this.roomCode) {
|
||||
return this.t('missingRoomCode')
|
||||
return this.$tr('缺少房间编码')
|
||||
}
|
||||
if (this.isLoading) {
|
||||
return this.t('syncingStatus')
|
||||
return this.$tr('正在同步设备状态')
|
||||
}
|
||||
if (this.devices.length) {
|
||||
return this.t('deviceSummary', { count: this.devices.length })
|
||||
return this.$tr('共 {count} 台设备,可进入详情页控制', { count: this.devices.length })
|
||||
}
|
||||
return this.t('emptyTitle')
|
||||
return this.$tr('暂无可控设备')
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
@@ -236,9 +182,6 @@ export default {
|
||||
this.stopPolling()
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.smart_control.smart_control', key, params)
|
||||
},
|
||||
resolvePageContext(options = {}) {
|
||||
const session = getSessionSnapshot()
|
||||
const roomData = (session && session.myRoomData) || {}
|
||||
@@ -321,7 +264,7 @@ export default {
|
||||
|
||||
if (!this.roomCode) {
|
||||
this.devices = []
|
||||
this.loadError = this.t('missingRoomCode')
|
||||
this.loadError = this.$tr('缺少房间编码')
|
||||
if (stopRefresh) {
|
||||
uni.stopPullDownRefresh()
|
||||
}
|
||||
@@ -361,7 +304,7 @@ export default {
|
||||
this.devices = []
|
||||
}
|
||||
if (!silent) {
|
||||
this.loadError = (error && (error.message || error.msg)) || this.t('requestFailed')
|
||||
this.loadError = (error && (error.message || error.msg)) || this.$tr('设备列表请求失败')
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -397,7 +340,7 @@ export default {
|
||||
|
||||
const functions = getDeviceFunctions(item)
|
||||
if (!functions || !functions.length) {
|
||||
uni.showToast({ title: this.t('unsupportedQuickControl'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('设备暂不支持快捷控制'), icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -409,13 +352,13 @@ export default {
|
||||
|
||||
const category = getControlTypeCategory(targetFunc.controlType)
|
||||
if (category !== 'switch') {
|
||||
uni.showToast({ title: this.t('unsupportedSwitch'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('该设备不支持快捷开关'), icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
const functionCode = String((targetFunc && targetFunc.functionCode) || '').trim()
|
||||
if (!functionCode) {
|
||||
uni.showToast({ title: this.t('missingFunctionCode'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('功能编码缺失'), icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -433,7 +376,7 @@ export default {
|
||||
}
|
||||
|
||||
this.isSubmitting = true
|
||||
uni.showLoading({ title: this.t('sending') })
|
||||
uni.showLoading({ title: this.$tr('发送中...') })
|
||||
|
||||
gatewayExecuteDeviceCommand(this.brandId, item.deviceNo, functionCode, commandPayload)
|
||||
.then(() => {
|
||||
@@ -447,11 +390,11 @@ export default {
|
||||
renderKey: this.devices[index].renderKey
|
||||
})
|
||||
}
|
||||
uni.showToast({ title: enabled ? this.t('enabled') : this.t('disabled'), icon: 'success' })
|
||||
uni.showToast({ title: enabled ? this.$tr('已开启') : this.$tr('已关闭'), icon: 'success' })
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('execute device command failed', error)
|
||||
uni.showToast({ title: (error && (error.message || error.msg)) || this.t('commandFailed'), icon: 'none' })
|
||||
uni.showToast({ title: (error && (error.message || error.msg)) || this.$tr('指令下发失败'), icon: 'none' })
|
||||
})
|
||||
.finally(() => {
|
||||
this.isSubmitting = false
|
||||
|
||||
@@ -16,17 +16,17 @@
|
||||
<tn-popup v-model="showPopup" mode="bottom" length="72%" :borderRadius="32" :closeBtn="true">
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">{{ t('popupTitle') }}</text>
|
||||
<text class="popup-title">{{ $tr('选择意向楼栋') }}</text>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="building-list-scroll">
|
||||
<view v-if="isLoading" class="loading-state tn-padding-xl tn-text-center">
|
||||
<tn-loading mode="circle"></tn-loading>
|
||||
<view class="tn-margin-top-sm tn-color-gray">{{ t('loadingText') }}</view>
|
||||
<view class="tn-margin-top-sm tn-color-gray">{{ $tr('楼栋加载中...') }}</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="!buildingList.length" class="empty-state tn-padding-xl tn-text-center">
|
||||
<text class="tn-color-gray">{{ t('emptyText') }}</text>
|
||||
<text class="tn-color-gray">{{ $tr('暂无可选楼栋') }}</text>
|
||||
</view>
|
||||
|
||||
<view v-else class="building-list">
|
||||
@@ -97,7 +97,7 @@ export default {
|
||||
return this.$getLanguage ? this.$getLanguage() : 'zh'
|
||||
},
|
||||
placeholderText() {
|
||||
return this.areaCode ? this.t('selectBuilding') : this.t('selectAreaFirst')
|
||||
return this.areaCode ? this.$tr('请选择楼栋') : this.$tr('请先选择区域')
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -120,13 +120,10 @@ export default {
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.submit_request.components.BuildingSelector', key, params)
|
||||
},
|
||||
handleOpen() {
|
||||
if (!this.areaCode) {
|
||||
uni.showToast({
|
||||
title: this.t('selectAreaFirst'),
|
||||
title: this.$tr('请先选择区域'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -189,7 +186,7 @@ export default {
|
||||
this.buildingList = []
|
||||
this.selectedBuilding = null
|
||||
uni.showToast({
|
||||
title: this.t('loadFailed'),
|
||||
title: this.$tr('楼栋列表加载失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="date-divider">{{ t('dateDivider') }}</view>
|
||||
<view class="date-divider">{{ $tr('至') }}</view>
|
||||
<view class="date-item">
|
||||
<view class="date-label">{{ resolvedEndLabel }}</view>
|
||||
<picker mode="date" @change="onEndChange">
|
||||
@@ -23,22 +23,6 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'DateRangeSelector',
|
||||
i18n: {
|
||||
zh: {
|
||||
startLabel: '预计入住',
|
||||
endLabel: '预计离开',
|
||||
startPlaceholder: '请选择入住日期',
|
||||
endPlaceholder: '请选择离开日期',
|
||||
dateDivider: '至'
|
||||
},
|
||||
en: {
|
||||
startLabel: 'Expected Check-in',
|
||||
endLabel: 'Expected Check-out',
|
||||
startPlaceholder: 'Select check-in date',
|
||||
endPlaceholder: 'Select check-out date',
|
||||
dateDivider: 'to'
|
||||
}
|
||||
},
|
||||
props: {
|
||||
start: {
|
||||
type: String,
|
||||
@@ -67,22 +51,19 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
resolvedStartLabel() {
|
||||
return this.startLabel || this.t('startLabel')
|
||||
return this.startLabel || this.$tr('预计入住')
|
||||
},
|
||||
resolvedEndLabel() {
|
||||
return this.endLabel || this.t('endLabel')
|
||||
return this.endLabel || this.$tr('预计离开')
|
||||
},
|
||||
resolvedStartPlaceholder() {
|
||||
return this.startPlaceholder || this.t('startPlaceholder')
|
||||
return this.startPlaceholder || this.$tr('请选择入住日期')
|
||||
},
|
||||
resolvedEndPlaceholder() {
|
||||
return this.endPlaceholder || this.t('endPlaceholder')
|
||||
return this.endPlaceholder || this.$tr('请选择离开日期')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
t(key) {
|
||||
return this.$tm('pkgService.submit_request.components.DateRangeSelector', key)
|
||||
},
|
||||
onStartChange(e) {
|
||||
this.$emit('update:start', e.detail.value)
|
||||
},
|
||||
@@ -128,7 +109,7 @@ export default {
|
||||
font-size: 28rpx;
|
||||
color: #1A2B4C;
|
||||
font-weight: 600;
|
||||
|
||||
|
||||
&.is-empty {
|
||||
color: #CBD5E1;
|
||||
font-weight: normal;
|
||||
|
||||
@@ -15,17 +15,17 @@
|
||||
<tn-popup v-model="showPopup" mode="bottom" length="72%" :borderRadius="32" :closeBtn="true">
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">{{ t('popupTitle') }}</text>
|
||||
<text class="popup-title">{{ $tr('选择意向楼层') }}</text>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="floor-list-scroll">
|
||||
<view v-if="isLoading" class="loading-state tn-padding-xl tn-text-center">
|
||||
<tn-loading mode="circle"></tn-loading>
|
||||
<view class="tn-margin-top-sm tn-color-gray">{{ t('loadingText') }}</view>
|
||||
<view class="tn-margin-top-sm tn-color-gray">{{ $tr('楼层加载中...') }}</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="!floorList.length" class="empty-state tn-padding-xl tn-text-center">
|
||||
<text class="tn-color-gray">{{ t('emptyText') }}</text>
|
||||
<text class="tn-color-gray">{{ $tr('暂无可选楼层') }}</text>
|
||||
</view>
|
||||
|
||||
<view v-else class="floor-list">
|
||||
@@ -34,7 +34,7 @@
|
||||
:class="{ 'is-active': !selectedFloor }"
|
||||
@click="handleClear"
|
||||
>
|
||||
<text class="floor-name">{{ t('clearSelection') }}</text>
|
||||
<text class="floor-name">{{ $tr('不选择') }}</text>
|
||||
<text v-if="!selectedFloor" class="tn-icon-success-circle-fill floor-check"></text>
|
||||
</view>
|
||||
<view
|
||||
@@ -133,7 +133,7 @@ export default {
|
||||
return this.$getLanguage ? this.$getLanguage() : 'zh'
|
||||
},
|
||||
placeholderText() {
|
||||
return this.t('selectFloor')
|
||||
return this.$tr('请选择楼层')
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -148,9 +148,6 @@ export default {
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.submit_request.components.FloorSelector', key, params)
|
||||
},
|
||||
handleOpen() {
|
||||
this.showPopup = true
|
||||
this.loadData()
|
||||
@@ -176,7 +173,7 @@ export default {
|
||||
this.floorList = []
|
||||
this.selectedFloor = null
|
||||
uni.showToast({
|
||||
title: this.t('loadFailed'),
|
||||
title: this.$tr('楼层列表加载失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<view class="selector-header tn-flex tn-flex-row-between tn-flex-col-center" @click="openSelector">
|
||||
<view class="selected-info">
|
||||
<view class="selected-name tn-text-ellipsis" :class="{ 'is-empty': !selectedRoomType }">
|
||||
{{ selectedRoomType ? getRoomTypeDisplayName(selectedRoomType) : t('selectRoomType') }}
|
||||
{{ selectedRoomType ? getRoomTypeDisplayName(selectedRoomType) : $tr('请选择意向房型') }}
|
||||
</view>
|
||||
<view class="selected-area tn-text-ellipsis" v-if="selectedArea">
|
||||
{{ getAreaDisplayName(selectedArea) }}
|
||||
@@ -15,17 +15,17 @@
|
||||
<tn-popup v-model="showPopup" mode="bottom" length="80%" :borderRadius="32" :closeBtn="true">
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">{{ t('popupTitle') }}</text>
|
||||
<text class="popup-title">{{ $tr('选择意向房型') }}</text>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="area-list-scroll">
|
||||
<view v-if="isLoading" class="loading-state tn-padding-xl tn-text-center">
|
||||
<tn-loading mode="circle"></tn-loading>
|
||||
<view class="tn-margin-top-sm tn-color-gray">{{ t('loadingRoomTypes') }}</view>
|
||||
<view class="tn-margin-top-sm tn-color-gray">{{ $tr('房型加载中...') }}</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="!displayAreaList.length" class="empty-state tn-padding-xl tn-text-center">
|
||||
<text class="tn-color-gray">{{ t('emptyRoomTypes') }}</text>
|
||||
<text class="tn-color-gray">{{ $tr('暂无可选房型') }}</text>
|
||||
</view>
|
||||
|
||||
<view v-else class="area-group" v-for="(area, index) in displayAreaList" :key="area.code">
|
||||
@@ -45,7 +45,7 @@
|
||||
@click="handleSelect(area, room)"
|
||||
>
|
||||
<view class="room-name tn-text-ellipsis">{{ getRoomTypeDisplayName(room) }}</view>
|
||||
<view class="room-price" v-if="room.price">¥{{ getPriceValue(room.price) }}{{ t('priceUnit') }}</view>
|
||||
<view class="room-price" v-if="room.price">¥{{ getPriceValue(room.price) }}{{ $tr('/月') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -118,9 +118,6 @@ export default {
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
t(key) {
|
||||
return this.$translate(this.i18n, key)
|
||||
},
|
||||
openSelector() {
|
||||
this.showPopup = true
|
||||
this.loadData()
|
||||
@@ -148,7 +145,7 @@ export default {
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('load room types error', e)
|
||||
uni.showToast({ title: this.t('loadFailed'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('房型列表加载失败'), icon: 'none' })
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
|
||||
@@ -11,23 +11,13 @@
|
||||
{{ item.value }}
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="empty-tips">{{ loading ? t('loadingText') : resolvedEmptyText }}</view>
|
||||
<view v-else class="empty-tips">{{ loading ? $tr('标签加载中...') : resolvedEmptyText }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TagSelector',
|
||||
i18n: {
|
||||
zh: {
|
||||
loadingText: '标签加载中...',
|
||||
emptyText: '暂无标签'
|
||||
},
|
||||
en: {
|
||||
loadingText: 'Loading tags...',
|
||||
emptyText: 'No tags available'
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
@@ -48,13 +38,10 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
resolvedEmptyText() {
|
||||
return this.emptyText || this.t('emptyText')
|
||||
return this.emptyText || this.$tr('暂无标签')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.submit_request.components.TagSelector', key, params)
|
||||
},
|
||||
toggleTag(key) {
|
||||
const currentList = [...this.value]
|
||||
const index = currentList.indexOf(key)
|
||||
|
||||
@@ -44,22 +44,22 @@
|
||||
</view>
|
||||
|
||||
<view v-if="showPreferenceSelectors" class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('hobbyLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('兴趣爱好') }}</view>
|
||||
<tag-selector
|
||||
v-model="form.hobbiesAndInterestsTagKeys"
|
||||
:options="hobbyOptions"
|
||||
:loading="dictLoading"
|
||||
:emptyText="t('emptyHobbyTags')"
|
||||
:emptyText="$tr('暂无兴趣爱好标签')"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view v-if="showPreferenceSelectors" class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('lifestyleLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('生活习惯') }}</view>
|
||||
<tag-selector
|
||||
v-model="form.lifestyleHabitsTagKeys"
|
||||
:options="lifestyleOptions"
|
||||
:loading="dictLoading"
|
||||
:emptyText="t('emptyLifestyleTags')"
|
||||
:emptyText="$tr('暂无生活习惯标签')"
|
||||
/>
|
||||
</view>
|
||||
|
||||
@@ -76,12 +76,12 @@
|
||||
</view>
|
||||
|
||||
<view class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('remarkLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('补充说明') }}</view>
|
||||
<textarea class="form-textarea" :placeholder="remarkPlaceholder" v-model="form.remark"></textarea>
|
||||
</view>
|
||||
|
||||
<view v-if="!showFloatingSubmitBtn" class="submit-btn btn-primary tn-margin-top-xl" :class="{ 'submit-btn--disabled': isSubmitting }" @click="submitRequest">
|
||||
<text class="tn-text-bold">{{ isSubmitting ? t('submitting') : primaryActionText }}</text>
|
||||
<text class="tn-text-bold">{{ isSubmitting ? $tr('提交中...') : primaryActionText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -91,7 +91,7 @@
|
||||
<view v-if="showFloatingSubmitBtn" class="floating-submit-bar">
|
||||
<view class="floating-submit-bar__inner">
|
||||
<view class="submit-btn btn-primary" :class="{ 'submit-btn--disabled': isSubmitting }" @click="submitRequest">
|
||||
<text class="tn-text-bold">{{ isSubmitting ? t('submitting') : primaryActionText }}</text>
|
||||
<text class="tn-text-bold">{{ isSubmitting ? $tr('提交中...') : primaryActionText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -594,81 +594,7 @@ export default {
|
||||
lifestyleOptions: [],
|
||||
form: createDefaultForm(),
|
||||
scrollTop: 0,
|
||||
lastAutoRemark: '',
|
||||
i18n: {
|
||||
zh: {
|
||||
hobbyLabel: '兴趣爱好',
|
||||
emptyHobbyTags: '暂无兴趣爱好标签',
|
||||
lifestyleLabel: '生活习惯',
|
||||
emptyLifestyleTags: '暂无生活习惯标签',
|
||||
remarkLabel: '补充说明',
|
||||
submitting: '提交中...',
|
||||
roomTypeApplyTitle: '房型申请',
|
||||
roomTypeApplyDesc: '请确认房型、区域、偏好标签和租期信息后提交申请。',
|
||||
roomTypeApplyBlockTitle: '房型申请信息',
|
||||
roomTypeApplyBlockDesc: '已接入真实申请单接口,支持带出房型与区域编码后直接提交。',
|
||||
applyRemarkPlaceholder: '请输入您的申请补充说明',
|
||||
submitRoomTypeApply: '提交房型申请',
|
||||
applyRoomType: '申请房型',
|
||||
leaseRange: '租期时间',
|
||||
expectedCheckin: '预计入住',
|
||||
expectedCheckout: '预计离开',
|
||||
selectCheckinDate: '请选择入住日期',
|
||||
selectCheckoutDate: '请选择离开日期',
|
||||
currentRoom: '当前房间',
|
||||
areaLabel: '所属区域',
|
||||
referencePrice: '参考价格',
|
||||
paymentMethod: '支付方式',
|
||||
applicationType: '申请类型',
|
||||
stayApplyDefaultTitle: '入住申请',
|
||||
stayApplyDefaultDesc: '请填写您的入住意向、生活偏好与预计租期后提交申请单。',
|
||||
sourceDefaultDesc: '请填写您的入住意向、租期和补充说明。',
|
||||
tagLoadFailed: '偏好标签加载失败',
|
||||
remarkRequired: '请输入补充说明',
|
||||
applicationInfo: '申请信息',
|
||||
selectDateStart: '请选择{label}',
|
||||
selectDateEnd: '请选择{label}',
|
||||
dateCannotBefore: '{endLabel}不能早于{startLabel}',
|
||||
submitSuccess: '申请单提交成功',
|
||||
submitFailed: '申请单提交失败'
|
||||
},
|
||||
en: {
|
||||
hobbyLabel: 'Hobbies',
|
||||
emptyHobbyTags: 'No hobby tags',
|
||||
lifestyleLabel: 'Lifestyle Habits',
|
||||
emptyLifestyleTags: 'No lifestyle tags',
|
||||
remarkLabel: 'Additional Notes',
|
||||
submitting: 'Submitting...',
|
||||
roomTypeApplyTitle: 'Room Type Application',
|
||||
roomTypeApplyDesc: 'Confirm the room type, area, preference tags, and lease period before submitting.',
|
||||
roomTypeApplyBlockTitle: 'Application Details',
|
||||
roomTypeApplyBlockDesc: 'The live application API is connected and can submit with room and area codes.',
|
||||
applyRemarkPlaceholder: 'Enter your additional notes',
|
||||
submitRoomTypeApply: 'Submit Application',
|
||||
applyRoomType: 'Requested Room Type',
|
||||
leaseRange: 'Lease Period',
|
||||
expectedCheckin: 'Expected Check-in',
|
||||
expectedCheckout: 'Expected Checkout',
|
||||
selectCheckinDate: 'Select check-in date',
|
||||
selectCheckoutDate: 'Select checkout date',
|
||||
currentRoom: 'Current Room',
|
||||
areaLabel: 'Area',
|
||||
referencePrice: 'Reference Price',
|
||||
paymentMethod: 'Payment Method',
|
||||
applicationType: 'Application Type',
|
||||
stayApplyDefaultTitle: 'Stay Application',
|
||||
stayApplyDefaultDesc: 'Fill in your stay intention, preferences, and lease period before submission.',
|
||||
sourceDefaultDesc: 'Fill in your stay intention, lease period, and notes.',
|
||||
tagLoadFailed: 'Failed to load preference tags',
|
||||
remarkRequired: 'Please enter additional notes',
|
||||
applicationInfo: 'Application Details',
|
||||
selectDateStart: 'Please select {label}',
|
||||
selectDateEnd: 'Please select {label}',
|
||||
dateCannotBefore: '{endLabel} cannot be earlier than {startLabel}',
|
||||
submitSuccess: 'Application submitted',
|
||||
submitFailed: 'Failed to submit application'
|
||||
}
|
||||
}
|
||||
lastAutoRemark: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -709,52 +635,52 @@ export default {
|
||||
pageTitle() {
|
||||
if (this.isRoomTypeApply) {
|
||||
return this.language === 'en'
|
||||
? compactEnglishText(this.t('roomTypeApplyTitle'), 22)
|
||||
: this.t('roomTypeApplyTitle')
|
||||
? compactEnglishText(this.$tr('房型申请'), 22)
|
||||
: this.$tr('房型申请')
|
||||
}
|
||||
return this.getBusinessText('titleShort')
|
||||
|| this.getBusinessText('title')
|
||||
|| this.getLocalizedSourceText('title')
|
||||
|| this.t('stayApplyDefaultTitle')
|
||||
|| this.$tr('入住申请')
|
||||
},
|
||||
pageDesc() {
|
||||
if (this.isRoomTypeApply) {
|
||||
return this.language === 'en'
|
||||
? compactEnglishText(this.t('roomTypeApplyDesc'), 96)
|
||||
: this.t('roomTypeApplyDesc')
|
||||
? compactEnglishText(this.$tr('请确认房型、区域、偏好标签和租期信息后提交申请。'), 96)
|
||||
: this.$tr('请确认房型、区域、偏好标签和租期信息后提交申请。')
|
||||
}
|
||||
const text = this.getBusinessText('desc') || this.getLocalizedSourceText('desc') || this.t('stayApplyDefaultDesc')
|
||||
const text = this.getBusinessText('desc') || this.getLocalizedSourceText('desc') || this.$tr('请填写您的入住意向、生活偏好与预计租期后提交申请单。')
|
||||
return this.language === 'en' ? compactEnglishText(text, 96) : text
|
||||
},
|
||||
formBlockTitle() {
|
||||
if (this.isRoomTypeApply) {
|
||||
return this.t('roomTypeApplyBlockTitle')
|
||||
return this.$tr('房型申请信息')
|
||||
}
|
||||
return this.getBusinessText('formBlockTitle') || this.t('applicationInfo')
|
||||
return this.getBusinessText('formBlockTitle') || this.$tr('申请信息')
|
||||
},
|
||||
formBlockDesc() {
|
||||
if (this.isRoomTypeApply) {
|
||||
return this.t('roomTypeApplyBlockDesc')
|
||||
return this.$tr('已接入真实申请单接口,支持带出房型与区域编码后直接提交。')
|
||||
}
|
||||
return this.getBusinessText('formBlockDesc') || this.t('stayApplyDefaultDesc')
|
||||
return this.getBusinessText('formBlockDesc') || this.$tr('请填写您的入住意向、生活偏好与预计租期后提交申请单。')
|
||||
},
|
||||
remarkPlaceholder() {
|
||||
if (this.isRoomTypeApply) {
|
||||
return this.t('applyRemarkPlaceholder')
|
||||
return this.$tr('请输入您的申请补充说明')
|
||||
}
|
||||
return this.getBusinessText('remarkPlaceholder') || this.t('remarkRequired')
|
||||
return this.getBusinessText('remarkPlaceholder') || this.$tr('请输入补充说明')
|
||||
},
|
||||
primaryActionText() {
|
||||
if (this.isRoomTypeApply) {
|
||||
return this.language === 'en'
|
||||
? compactEnglishText(this.t('submitRoomTypeApply'), 24)
|
||||
: this.t('submitRoomTypeApply')
|
||||
? compactEnglishText(this.$tr('提交房型申请'), 24)
|
||||
: this.$tr('提交房型申请')
|
||||
}
|
||||
const text = this.getBusinessText('primaryActionText') || this.t('submitApplicationFallback')
|
||||
const text = this.getBusinessText('primaryActionText') || this.$tr('提交申请')
|
||||
return this.language === 'en' ? compactEnglishText(text, 24) : text
|
||||
},
|
||||
roomTypeLabel() {
|
||||
return this.getBusinessText('roomTypeLabel') || this.t('applyRoomType')
|
||||
return this.getBusinessText('roomTypeLabel') || this.$tr('申请房型')
|
||||
},
|
||||
pageBottomPadding() {
|
||||
return this.showFloatingSubmitBtn ? '220rpx' : '60rpx'
|
||||
@@ -763,7 +689,7 @@ export default {
|
||||
return this.isRoomTypeApply
|
||||
},
|
||||
floorLabel() {
|
||||
return this.getBusinessText('floorLabel') || this.t('floorLabel')
|
||||
return this.getBusinessText('floorLabel') || this.$tr('楼层')
|
||||
},
|
||||
showRoomTypeSelector() {
|
||||
if (this.isRoomTypeApply) {
|
||||
@@ -790,19 +716,19 @@ export default {
|
||||
return this.businessConfig ? this.businessConfig.showDateRange !== false : true
|
||||
},
|
||||
dateRangeLabel() {
|
||||
return this.getBusinessText('dateRangeLabel') || this.t('leaseRange')
|
||||
return this.getBusinessText('dateRangeLabel') || this.$tr('租期时间')
|
||||
},
|
||||
dateRangeStartLabel() {
|
||||
return this.getBusinessText('dateRangeStartLabel') || this.t('expectedCheckin')
|
||||
return this.getBusinessText('dateRangeStartLabel') || this.$tr('预计入住')
|
||||
},
|
||||
dateRangeEndLabel() {
|
||||
return this.getBusinessText('dateRangeEndLabel') || this.t('expectedCheckout')
|
||||
return this.getBusinessText('dateRangeEndLabel') || this.$tr('预计离开')
|
||||
},
|
||||
dateRangeStartPlaceholder() {
|
||||
return this.getBusinessText('dateRangeStartPlaceholder') || this.t('selectCheckinDate')
|
||||
return this.getBusinessText('dateRangeStartPlaceholder') || this.$tr('请选择入住日期')
|
||||
},
|
||||
dateRangeEndPlaceholder() {
|
||||
return this.getBusinessText('dateRangeEndPlaceholder') || this.t('selectCheckoutDate')
|
||||
return this.getBusinessText('dateRangeEndPlaceholder') || this.$tr('请选择离开日期')
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -839,9 +765,6 @@ export default {
|
||||
this.loadDictOptions()
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.submit_request.submit_request', key, params)
|
||||
},
|
||||
decodeRouteText(value, fallback = '') {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
return fallback
|
||||
@@ -1000,7 +923,7 @@ export default {
|
||||
.catch((error) => {
|
||||
console.error('load application dict options failed', error)
|
||||
uni.showToast({
|
||||
title: this.t('tagLoadFailed'),
|
||||
title: this.$tr('偏好标签加载失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
@@ -1038,20 +961,20 @@ export default {
|
||||
validateForm() {
|
||||
if (this.showDateRange) {
|
||||
if (!this.form.start) {
|
||||
return this.t('selectDateStart', { label: this.dateRangeStartLabel })
|
||||
return this.$tr('请选择{label}', { label: this.dateRangeStartLabel })
|
||||
}
|
||||
if (!this.form.end) {
|
||||
return this.t('selectDateEnd', { label: this.dateRangeEndLabel })
|
||||
return this.$tr('请选择{label}', { label: this.dateRangeEndLabel })
|
||||
}
|
||||
if (new Date(this.form.end).getTime() < new Date(this.form.start).getTime()) {
|
||||
return this.t('dateCannotBefore', {
|
||||
return this.$tr('{endLabel}不能早于{startLabel}', {
|
||||
endLabel: this.dateRangeEndLabel,
|
||||
startLabel: this.dateRangeStartLabel
|
||||
})
|
||||
}
|
||||
}
|
||||
if (!this.form.remark.trim()) {
|
||||
return this.t('remarkRequired')
|
||||
return this.$tr('请输入补充说明')
|
||||
}
|
||||
return ''
|
||||
},
|
||||
@@ -1084,7 +1007,7 @@ export default {
|
||||
|
||||
this.isSubmitting = true
|
||||
uni.showLoading({
|
||||
title: this.t('submitting')
|
||||
title: this.$tr('提交中...')
|
||||
})
|
||||
|
||||
const payload = this.buildSubmitPayload()
|
||||
@@ -1096,7 +1019,7 @@ export default {
|
||||
}
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: this.t('submitSuccess'),
|
||||
title: this.$tr('申请单提交成功'),
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
@@ -1111,7 +1034,7 @@ export default {
|
||||
console.error('submit application form failed', error)
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: (error && (error.message || error.msg)) || this.t('submitFailed'),
|
||||
title: (error && (error.message || error.msg)) || this.$tr('申请单提交失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<view class="ticket-center-page tn-safe-area-inset-bottom">
|
||||
<tn-nav-bar :isBack="true" :bottomShadow="false" backgroundColor="transparent">
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ t('navTitle') }}</view>
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ $tr('工单中心') }}</view>
|
||||
</tn-nav-bar>
|
||||
|
||||
<view class="page-content tn-padding" :style="{ paddingTop: vuex_custom_bar_height + 'px' }">
|
||||
<view class="hero-card tn-margin-bottom-lg">
|
||||
<view class="hero-badge">
|
||||
<text class="badge-dot"></text>
|
||||
<text>{{ t('heroBadge') }}</text>
|
||||
<text>{{ $tr('SERVICE') }}</text>
|
||||
</view>
|
||||
<view class="hero-title tn-margin-top">{{ t('heroTitle') }}</view>
|
||||
<view class="hero-desc tn-margin-top-sm">{{ t('heroDesc') }}</view>
|
||||
<view class="hero-title tn-margin-top">{{ $tr('住中工单服务') }}</view>
|
||||
<view class="hero-desc tn-margin-top-sm">{{ $tr('报修、续住、退宿、调宿、送水、清洁和意见建议都统一从这里进入,提交后可继续查看流转记录。') }}</view>
|
||||
</view>
|
||||
|
||||
<view class="service-grid">
|
||||
@@ -33,20 +33,6 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'TicketCenterPage',
|
||||
i18n: {
|
||||
zh: {
|
||||
navTitle: '工单中心',
|
||||
heroBadge: 'SERVICE',
|
||||
heroTitle: '住中工单服务',
|
||||
heroDesc: '报修、续住、退宿、调宿、送水、清洁和意见建议都统一从这里进入,提交后可继续查看流转记录。'
|
||||
},
|
||||
en: {
|
||||
navTitle: 'Work Orders',
|
||||
heroBadge: 'SERVICE',
|
||||
heroTitle: 'In-stay Ticket Services',
|
||||
heroDesc: 'Repair, renewal, checkout, room change, water delivery, cleaning, and suggestions are all handled here.'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ticketServices: [
|
||||
@@ -110,9 +96,6 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$translate(this.i18n, key, params)
|
||||
},
|
||||
getItemText(item, fieldZh, fieldEn) {
|
||||
return this.$getLanguage && this.$getLanguage() === 'en'
|
||||
? (item[fieldEn] || item[fieldZh] || '')
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<view class="hero-header tn-margin-bottom-xl">
|
||||
<view class="hero-badge">
|
||||
<text class="badge-dot"></text>
|
||||
<text>{{ t('ticketKicker') }}</text>
|
||||
<text>{{ $tr('WORK ORDER') }}</text>
|
||||
</view>
|
||||
<view class="hero-title">{{ pageTitle }}</view>
|
||||
<view class="hero-desc">{{ pageDesc }}</view>
|
||||
@@ -27,35 +27,35 @@
|
||||
:class="{ 'segment-item--active': activeTab === 'submit' }"
|
||||
@click="switchTab('submit')"
|
||||
>
|
||||
{{ t('submitTab') }}
|
||||
{{ $tr('提交申请') }}
|
||||
</view>
|
||||
<view
|
||||
class="segment-item"
|
||||
:class="{ 'segment-item--active': activeTab === 'history' }"
|
||||
@click="switchTab('history')"
|
||||
>
|
||||
{{ t('historyTab') }}
|
||||
{{ $tr('记录查询') }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="activeTab === 'submit'" class="context-card tn-margin-bottom-lg">
|
||||
<view class="block-title">{{ t('currentStayInfo') }}</view>
|
||||
<view class="block-title">{{ $tr('当前入住信息') }}</view>
|
||||
<view class="block-subtitle">{{ currentOrderStatusText }}</view>
|
||||
<view class="context-grid tn-margin-top">
|
||||
<view class="context-item">
|
||||
<view class="context-label">{{ t('roomLabel') }}</view>
|
||||
<view class="context-label">{{ $tr('当前房间') }}</view>
|
||||
<view class="context-value">{{ currentRoomText }}</view>
|
||||
</view>
|
||||
<view v-if="currentAreaText" class="context-item">
|
||||
<view class="context-label">{{ t('areaLabel') }}</view>
|
||||
<view class="context-label">{{ $tr('所属区域') }}</view>
|
||||
<view class="context-value">{{ currentAreaText }}</view>
|
||||
</view>
|
||||
<view v-if="currentLeaseText" class="context-item">
|
||||
<view class="context-label">{{ t('leaseLabel') }}</view>
|
||||
<view class="context-label">{{ $tr('租期') }}</view>
|
||||
<view class="context-value">{{ currentLeaseText }}</view>
|
||||
</view>
|
||||
<view v-if="currentRoomTypeText" class="context-item">
|
||||
<view class="context-label">{{ t('roomTypeLabel') }}</view>
|
||||
<view class="context-label">{{ $tr('当前房型') }}</view>
|
||||
<view class="context-value">{{ currentRoomTypeText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -64,8 +64,8 @@
|
||||
<view v-if="modeBannerText && activeTab === 'submit'" class="status-card tn-margin-bottom-lg" :class="statusCardClass">
|
||||
<view class="status-card__title">{{ modeBannerTitle }}</view>
|
||||
<view class="status-card__desc">{{ modeBannerText }}</view>
|
||||
<view v-if="fixOnholdMode" class="status-card__action" @click="cancelFixOnhold">{{ t('cancelSupplement') }}</view>
|
||||
<view v-else-if="transitActionMode" class="status-card__action" @click="cancelTransitAction">{{ t('cancelProcess') }}</view>
|
||||
<view v-if="fixOnholdMode" class="status-card__action" @click="cancelFixOnhold">{{ $tr('取消补充') }}</view>
|
||||
<view v-else-if="transitActionMode" class="status-card__action" @click="cancelTransitAction">{{ $tr('退出处理') }}</view>
|
||||
</view>
|
||||
|
||||
<view v-if="activeTab === 'submit'" class="form-card">
|
||||
@@ -73,7 +73,7 @@
|
||||
<view class="block-subtitle">{{ submitSectionDesc }}</view>
|
||||
|
||||
<view v-if="isChangeService" class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('changeRoomTypeLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('意向房型') }}</view>
|
||||
<room-type-selector
|
||||
v-model="switchForm.roomTypeCode"
|
||||
:initial-area-code="switchForm.areaCode"
|
||||
@@ -82,37 +82,37 @@
|
||||
</view>
|
||||
|
||||
<view v-if="isCheckOutService" class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('checkoutTimeLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('预计退宿时间') }}</view>
|
||||
<view class="picker-row">
|
||||
<picker mode="date" :value="form.checkOutDate" @change="onDateChange('checkOutDate', $event)">
|
||||
<view class="form-picker">{{ form.checkOutDate || t('selectDate') }}</view>
|
||||
<view class="form-picker">{{ form.checkOutDate || $tr('请选择日期') }}</view>
|
||||
</picker>
|
||||
<picker mode="time" :value="form.checkOutTimePart" @change="onTimeChange('checkOutTimePart', $event)">
|
||||
<view class="form-picker form-picker--time">{{ form.checkOutTimePart || t('selectTime') }}</view>
|
||||
<view class="form-picker form-picker--time">{{ form.checkOutTimePart || $tr('请选择时间') }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="isRenewalService" class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('renewalTimeLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('续住至') }}</view>
|
||||
<view class="picker-row">
|
||||
<picker mode="date" :value="form.renewalDate" @change="onDateChange('renewalDate', $event)">
|
||||
<view class="form-picker">{{ form.renewalDate || t('selectDate') }}</view>
|
||||
<view class="form-picker">{{ form.renewalDate || $tr('请选择日期') }}</view>
|
||||
</picker>
|
||||
<picker mode="time" :value="form.renewalTimePart" @change="onTimeChange('renewalTimePart', $event)">
|
||||
<view class="form-picker form-picker--time">{{ form.renewalTimePart || t('selectTime') }}</view>
|
||||
<view class="form-picker form-picker--time">{{ form.renewalTimePart || $tr('请选择时间') }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="isCleaningService" class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('cleaningTimeLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('预约清洁时间') }}</view>
|
||||
<view class="picker-row">
|
||||
<picker mode="date" :value="form.cleaningDate" @change="onDateChange('cleaningDate', $event)">
|
||||
<view class="form-picker">{{ form.cleaningDate || t('selectDate') }}</view>
|
||||
<view class="form-picker">{{ form.cleaningDate || $tr('请选择日期') }}</view>
|
||||
</picker>
|
||||
<picker mode="time" :value="form.cleaningTimePart" @change="onTimeChange('cleaningTimePart', $event)">
|
||||
<view class="form-picker form-picker--time">{{ form.cleaningTimePart || t('selectTime') }}</view>
|
||||
<view class="form-picker form-picker--time">{{ form.cleaningTimePart || $tr('请选择时间') }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
@@ -129,26 +129,26 @@
|
||||
</view>
|
||||
|
||||
<view class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('remarkLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('补充说明') }}</view>
|
||||
<textarea
|
||||
class="form-textarea form-textarea--remark"
|
||||
:placeholder="t('remarkPlaceholder')"
|
||||
:placeholder="$tr('请输入补充说明,帮助工作人员更快处理')"
|
||||
:maxlength="300"
|
||||
v-model="form.remark"
|
||||
></textarea>
|
||||
</view>
|
||||
|
||||
<view v-if="showTransitAssigneeSelector" class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('assigneeLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('处理目标') }}</view>
|
||||
<picker mode="selector" :range="transitAssigneePickerLabels" @change="onTransitAssigneeChange">
|
||||
<view class="form-picker">
|
||||
{{ transitSelectedAssigneeName || t('selectAssignee') }}
|
||||
{{ transitSelectedAssigneeName || $tr('请选择处理目标') }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view v-if="fixOnholdMode && fixOnholdFields.length" class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('supplementLabel') }}</view>
|
||||
<view class="form-label">{{ $tr('补充业务信息') }}</view>
|
||||
<view
|
||||
v-for="(item, index) in fixOnholdFields"
|
||||
:key="`${item.key}-${index}`"
|
||||
@@ -159,20 +159,20 @@
|
||||
v-if="shouldUseTextarea(item.value)"
|
||||
class="form-textarea form-textarea--small"
|
||||
v-model="item.value"
|
||||
:placeholder="t('supplementPlaceholder', { label: item.title })"
|
||||
:placeholder="$tr('请输入{label}', { label: item.title })"
|
||||
></textarea>
|
||||
<input
|
||||
v-else
|
||||
class="form-input"
|
||||
type="text"
|
||||
v-model="item.value"
|
||||
:placeholder="t('supplementPlaceholder', { label: item.title })"
|
||||
:placeholder="$tr('请输入{label}', { label: item.title })"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item tn-margin-top">
|
||||
<view class="form-label">{{ t('attachmentsLabel') }}<text v-if="isRepairService" class="required-mark"> *</text></view>
|
||||
<view class="form-label">{{ $tr('附件图片') }}<text v-if="isRepairService" class="required-mark"> *</text></view>
|
||||
<tn-image-upload
|
||||
:key="uploadInstanceKey"
|
||||
:fileList="form.photos"
|
||||
@@ -192,7 +192,7 @@
|
||||
<template #addBtn>
|
||||
<view class="upload-trigger">
|
||||
<text class="tn-icon-camera-fill upload-trigger__icon"></text>
|
||||
<view class="upload-trigger__text">{{ t('uploadImage') }}</view>
|
||||
<view class="upload-trigger__text">{{ $tr('上传图片') }}</view>
|
||||
</view>
|
||||
</template>
|
||||
</tn-image-upload>
|
||||
@@ -207,13 +207,13 @@
|
||||
<input
|
||||
v-model="searchKeyword"
|
||||
class="search-box__input"
|
||||
:placeholder="t('searchPlaceholder')"
|
||||
:placeholder="$tr('搜索工单标题或内容')"
|
||||
confirm-type="search"
|
||||
@confirm="refreshHistory"
|
||||
/>
|
||||
</view>
|
||||
<view class="refresh-mini-btn" @click="refreshHistory">
|
||||
{{ historyLoading ? t('refreshing') : t('refresh') }}
|
||||
{{ historyLoading ? $tr('刷新中...') : $tr('刷新') }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -249,26 +249,26 @@
|
||||
</view>
|
||||
<view class="history-card__body tn-margin-top">
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('submittedAtLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('提交时间') }}</text>
|
||||
<text class="info-value">{{ formatDateTime(item.createTime) }}</text>
|
||||
</view>
|
||||
<view class="info-row tn-flex tn-flex-row-between">
|
||||
<text class="info-label">{{ t('contentLabel') }}</text>
|
||||
<text class="info-label">{{ $tr('申请内容') }}</text>
|
||||
<text class="info-value info-value--multiline">{{ item.content || item.remark || '--' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="load-state">
|
||||
<text v-if="historyLoading">{{ t('loadingMore') }}</text>
|
||||
<text v-else-if="!hasNext">{{ t('noMore') }}</text>
|
||||
<text v-else @click="loadMoreHistory">{{ t('loadMore') }}</text>
|
||||
<text v-if="historyLoading">{{ $tr('加载中...') }}</text>
|
||||
<text v-else-if="!hasNext">{{ $tr('没有更多了') }}</text>
|
||||
<text v-else @click="loadMoreHistory">{{ $tr('加载更多') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="!historyLoading" class="empty-panel tn-padding-lg">
|
||||
<view class="empty-title">{{ t('emptyHistoryTitle') }}</view>
|
||||
<view class="empty-desc tn-margin-top-sm">{{ t('emptyHistoryDesc') }}</view>
|
||||
<view class="empty-title">{{ $tr('暂无工单记录') }}</view>
|
||||
<view class="empty-desc tn-margin-top-sm">{{ $tr('当前类型还没有工单记录。') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -278,7 +278,7 @@
|
||||
<view class="floating-submit-bar__inner">
|
||||
<view class="floating-submit-tip">{{ submitFooterTip }}</view>
|
||||
<view class="submit-btn btn-primary" :class="{ 'submit-btn--disabled': submitting }" @click="submitForm">
|
||||
<text class="tn-text-bold">{{ submitting ? t('submitting') : submitButtonText }}</text>
|
||||
<text class="tn-text-bold">{{ submitting ? $tr('提交中...') : submitButtonText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -298,10 +298,10 @@
|
||||
<view class="flow-card__status">{{ getFlowStatusText(item) }}</view>
|
||||
<view class="flow-card__time tn-margin-top-xs">{{ formatDateTime(item.createTime) }}</view>
|
||||
</view>
|
||||
<view v-if="isCurrentFlowItem(index)" class="flow-card__tag">{{ t('currentFlowTag') }}</view>
|
||||
<view v-if="isCurrentFlowItem(index)" class="flow-card__tag">{{ $tr('当前节点') }}</view>
|
||||
</view>
|
||||
|
||||
<view class="flow-card__content tn-margin-top">{{ item.content || item.remark || t('noFlowContent') }}</view>
|
||||
<view class="flow-card__content tn-margin-top">{{ item.content || item.remark || $tr('暂无处理内容') }}</view>
|
||||
|
||||
<view v-if="item.attachments && item.attachments.length" class="flow-attachments tn-margin-top">
|
||||
<image
|
||||
@@ -316,7 +316,7 @@
|
||||
</view>
|
||||
|
||||
<view v-if="transitionOptions.length" class="flow-actions">
|
||||
<view class="block-title">{{ t('flowActionTitle') }}</view>
|
||||
<view class="block-title">{{ $tr('可执行操作') }}</view>
|
||||
<view class="flow-action-list tn-margin-top">
|
||||
<view
|
||||
v-for="(item, index) in transitionOptions"
|
||||
@@ -324,14 +324,14 @@
|
||||
class="flow-action-btn"
|
||||
@click="startTransitAction(item, getCurrentFlowItem())"
|
||||
>
|
||||
{{ item.nextStatusDesc || t('continueProcess') }}
|
||||
{{ item.nextStatusDesc || $tr('继续处理') }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="canFixOnhold(currentFlowOrder)" class="flow-actions tn-margin-top">
|
||||
<view class="flow-action-btn flow-action-btn--ghost" @click="startFixOnhold(currentFlowOrder)">
|
||||
{{ t('supplementAction') }}
|
||||
{{ $tr('补充信息') }}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
@@ -455,158 +455,6 @@ export default {
|
||||
components: {
|
||||
RoomTypeSelector
|
||||
},
|
||||
i18n: {
|
||||
zh: {
|
||||
areaLabel: '所属区域',
|
||||
assigneeLabel: '处理目标',
|
||||
attachmentsLabel: '附件图片',
|
||||
cancelProcess: '退出处理',
|
||||
cancelSupplement: '取消补充',
|
||||
changeRoomTypeLabel: '意向房型',
|
||||
cleaningTimeLabel: '预约清洁时间',
|
||||
contentLabel: '申请内容',
|
||||
currentFlowTag: '当前节点',
|
||||
currentStayInfo: '当前入住信息',
|
||||
currentStayOrder: '当前入住订单',
|
||||
emptyHistoryDesc: '当前类型还没有工单记录。',
|
||||
emptyHistoryTitle: '暂无工单记录',
|
||||
flowActionTitle: '可执行操作',
|
||||
historyTab: '记录查询',
|
||||
leaseLabel: '租期',
|
||||
loadMore: '加载更多',
|
||||
loadingMore: '加载中...',
|
||||
loadOrderFailed: '入住信息加载失败',
|
||||
noFlowContent: '暂无处理内容',
|
||||
noMore: '没有更多了',
|
||||
refresh: '刷新',
|
||||
refreshing: '刷新中...',
|
||||
remarkLabel: '补充说明',
|
||||
remarkPlaceholder: '请输入补充说明,帮助工作人员更快处理',
|
||||
roomLabel: '当前房间',
|
||||
roomTypeLabel: '当前房型',
|
||||
searchPlaceholder: '搜索工单标题或内容',
|
||||
selectAssignee: '请选择处理目标',
|
||||
selectDate: '请选择日期',
|
||||
selectTime: '请选择时间',
|
||||
submitSectionDefaultDesc: '以下内容将通过工单接口提交并进入后续流转。',
|
||||
submitTab: '提交申请',
|
||||
submitTicket: '提交工单',
|
||||
submitting: '提交中...',
|
||||
supplementAction: '补充信息',
|
||||
supplementLabel: '补充业务信息',
|
||||
supplementPlaceholder: '请输入{label}',
|
||||
ticketKicker: 'WORK ORDER',
|
||||
uploadImage: '上传图片',
|
||||
uploadImageCountExceeded: '最多上传 6 张图片',
|
||||
uploadImageFailed: '图片上传失败,请重试',
|
||||
uploadImageOversize: '图片不能超过 5MB',
|
||||
uploadTip: '支持上传 JPG、PNG 等图片,单张不超过 5MB,最多 6 张。',
|
||||
uploadTipRepair: '支持上传 JPG、PNG 等图片,单张不超过 5MB,最多 6 张。报修至少上传 1 张图片。',
|
||||
checkoutTimeLabel: '预计退宿时间',
|
||||
renewalTimeLabel: '续住至',
|
||||
submittedAtLabel: '提交时间',
|
||||
submitSuccess: '工单提交成功',
|
||||
submitFailed: '工单提交失败',
|
||||
confirmSubmitTitle: '确认提交',
|
||||
confirmSubmitContent: '确认提交当前工单吗?',
|
||||
missingStayContext: '当前缺少入住订单或房间信息,暂无法提交工单',
|
||||
repairAttachmentRequired: '请上传报修附件图片',
|
||||
changeAreaRequired: '请选择意向房型',
|
||||
checkoutTimeRequired: '请选择退宿时间',
|
||||
checkoutReasonRequired: '请填写退宿原因',
|
||||
loadHistoryFailed: '工单记录加载失败',
|
||||
loadFlowsFailed: '工单流转加载失败',
|
||||
loadActionsFailed: '工单操作项加载失败',
|
||||
continueProcess: '继续处理',
|
||||
loadAssigneeFailed: '处理目标加载失败',
|
||||
submitSectionActionDesc: '当前工单正在处理中,提交后会继续流转。',
|
||||
submitSectionSupplementDesc: '当前工单处于挂起状态,补充信息后会继续流转。',
|
||||
currentStatusPending: '待处理',
|
||||
currentStatusProcessing: '处理中',
|
||||
currentStatusResolved: '已解决',
|
||||
currentStatusClosed: '已结束',
|
||||
allStatus: '全部',
|
||||
pendingStatus: '待处理',
|
||||
processingStatus: '处理中',
|
||||
resolvedStatus: '已解决',
|
||||
closedStatus: '已结束'
|
||||
},
|
||||
en: {
|
||||
areaLabel: 'Area',
|
||||
assigneeLabel: 'Assignee',
|
||||
attachmentsLabel: 'Attachments',
|
||||
cancelProcess: 'Cancel Action',
|
||||
cancelSupplement: 'Cancel Supplement',
|
||||
changeRoomTypeLabel: 'Preferred Room Type',
|
||||
cleaningTimeLabel: 'Cleaning Time',
|
||||
contentLabel: 'Content',
|
||||
currentFlowTag: 'Current',
|
||||
currentStayInfo: 'Current Stay',
|
||||
currentStayOrder: 'Current Stay Order',
|
||||
emptyHistoryDesc: 'No tickets of this type yet.',
|
||||
emptyHistoryTitle: 'No Ticket Records',
|
||||
flowActionTitle: 'Available Actions',
|
||||
historyTab: 'History',
|
||||
leaseLabel: 'Lease',
|
||||
loadMore: 'Load More',
|
||||
loadingMore: 'Loading...',
|
||||
loadOrderFailed: 'Failed to load stay context',
|
||||
noFlowContent: 'No handling content',
|
||||
noMore: 'No more records',
|
||||
refresh: 'Refresh',
|
||||
refreshing: 'Refreshing...',
|
||||
remarkLabel: 'Notes',
|
||||
remarkPlaceholder: 'Enter notes to help the staff handle this ticket',
|
||||
roomLabel: 'Room',
|
||||
roomTypeLabel: 'Room Type',
|
||||
searchPlaceholder: 'Search title or content',
|
||||
selectAssignee: 'Select assignee',
|
||||
selectDate: 'Select date',
|
||||
selectTime: 'Select time',
|
||||
submitSectionDefaultDesc: 'The form below will be submitted through the ticket APIs.',
|
||||
submitTab: 'Submit',
|
||||
submitTicket: 'Submit Ticket',
|
||||
submitting: 'Submitting...',
|
||||
supplementAction: 'Supplement',
|
||||
supplementLabel: 'Supplementary Fields',
|
||||
supplementPlaceholder: 'Please enter {label}',
|
||||
ticketKicker: 'WORK ORDER',
|
||||
uploadImage: 'Upload Image',
|
||||
uploadImageCountExceeded: 'Up to 6 images',
|
||||
uploadImageFailed: 'Failed to upload image',
|
||||
uploadImageOversize: 'Image must be less than 5MB',
|
||||
uploadTip: 'Upload JPG or PNG images, up to 6 images and 5MB each.',
|
||||
uploadTipRepair: 'Upload JPG or PNG images, up to 6 images and 5MB each. Repair requires at least 1 image.',
|
||||
checkoutTimeLabel: 'Checkout Time',
|
||||
renewalTimeLabel: 'Renew Until',
|
||||
submittedAtLabel: 'Submitted At',
|
||||
submitSuccess: 'Ticket submitted',
|
||||
submitFailed: 'Failed to submit ticket',
|
||||
confirmSubmitTitle: 'Confirm',
|
||||
confirmSubmitContent: 'Confirm submitting this ticket?',
|
||||
missingStayContext: 'Missing current stay order or room information',
|
||||
repairAttachmentRequired: 'Please upload repair images',
|
||||
changeAreaRequired: 'Please select a room type',
|
||||
checkoutTimeRequired: 'Please select checkout time',
|
||||
checkoutReasonRequired: 'Please fill in the checkout reason',
|
||||
loadHistoryFailed: 'Failed to load ticket history',
|
||||
loadFlowsFailed: 'Failed to load ticket flows',
|
||||
loadActionsFailed: 'Failed to load ticket actions',
|
||||
continueProcess: 'Continue',
|
||||
loadAssigneeFailed: 'Failed to load assignees',
|
||||
submitSectionActionDesc: 'The ticket is in progress and will continue after submission.',
|
||||
submitSectionSupplementDesc: 'The ticket is on hold and will continue after supplementing the information.',
|
||||
currentStatusPending: 'Pending',
|
||||
currentStatusProcessing: 'Processing',
|
||||
currentStatusResolved: 'Resolved',
|
||||
currentStatusClosed: 'Closed',
|
||||
allStatus: 'All',
|
||||
pendingStatus: 'Pending',
|
||||
processingStatus: 'Processing',
|
||||
resolvedStatus: 'Resolved',
|
||||
closedStatus: 'Closed'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
serviceType: 'TicketRepairApply',
|
||||
@@ -737,11 +585,11 @@ export default {
|
||||
},
|
||||
currentOrderStatusText() {
|
||||
const status = Number(this.currentOrderDetail.orderStatus)
|
||||
if (Number.isNaN(status)) return this.t('currentStayOrder')
|
||||
if ([0, 1, 2].includes(status)) return this.t('currentStatusPending')
|
||||
if ([3, 4, 7].includes(status)) return this.t('currentStatusProcessing')
|
||||
if ([5, 6].includes(status)) return this.t('currentStatusResolved')
|
||||
return this.t('currentStatusClosed')
|
||||
if (Number.isNaN(status)) return this.$tr('当前入住订单')
|
||||
if ([0, 1, 2].includes(status)) return this.$tr('待处理')
|
||||
if ([3, 4, 7].includes(status)) return this.$tr('处理中')
|
||||
if ([5, 6].includes(status)) return this.$tr('已解决')
|
||||
return this.$tr('已结束')
|
||||
},
|
||||
contentFieldLabel() {
|
||||
if (this.isChangeService) return this.language === 'en' ? 'Change Reason' : '调宿说明'
|
||||
@@ -776,7 +624,7 @@ export default {
|
||||
}
|
||||
},
|
||||
uploadTipText() {
|
||||
return this.isRepairService ? this.t('uploadTipRepair') : this.t('uploadTip')
|
||||
return this.isRepairService ? this.$tr('支持上传 JPG、PNG 等图片,单张不超过 5MB,最多 6 张。报修至少上传 1 张图片。') : this.$tr('支持上传 JPG、PNG 等图片,单张不超过 5MB,最多 6 张。')
|
||||
},
|
||||
submitButtonText() {
|
||||
if (this.fixOnholdMode) {
|
||||
@@ -785,9 +633,9 @@ export default {
|
||||
if (this.transitActionMode) {
|
||||
return this.transitActionOption && this.transitActionOption.nextStatusDesc
|
||||
? this.transitActionOption.nextStatusDesc
|
||||
: this.t('continueProcess')
|
||||
: this.$tr('继续处理')
|
||||
}
|
||||
return this.t('submitTicket')
|
||||
return this.$tr('提交工单')
|
||||
},
|
||||
submitSectionTitle() {
|
||||
if (this.fixOnholdMode) return this.language === 'en' ? 'Supplement Information' : '补充工单信息'
|
||||
@@ -795,9 +643,9 @@ export default {
|
||||
return this.pageTitle
|
||||
},
|
||||
submitSectionDesc() {
|
||||
if (this.fixOnholdMode) return this.t('submitSectionSupplementDesc')
|
||||
if (this.transitActionMode) return this.t('submitSectionActionDesc')
|
||||
return this.t('submitSectionDefaultDesc')
|
||||
if (this.fixOnholdMode) return this.$tr('当前工单处于挂起状态,补充信息后会继续流转。')
|
||||
if (this.transitActionMode) return this.$tr('当前工单正在处理中,提交后会继续流转。')
|
||||
return this.$tr('以下内容将通过工单接口提交并进入后续流转。')
|
||||
},
|
||||
modeBannerTitle() {
|
||||
if (this.fixOnholdMode) return this.language === 'en' ? 'Supplement Required' : '当前工单需要补充信息'
|
||||
@@ -808,12 +656,12 @@ export default {
|
||||
if (this.fixOnholdMode) {
|
||||
return this.fixOnholdTicket && this.fixOnholdTicket.no
|
||||
? `${this.fixOnholdTicket.no} ${this.language === 'en' ? 'needs more information before continuing.' : '需要补充信息后继续流转。'}`
|
||||
: this.t('submitSectionSupplementDesc')
|
||||
: this.$tr('当前工单处于挂起状态,补充信息后会继续流转。')
|
||||
}
|
||||
if (this.transitActionMode) {
|
||||
return this.transitActionOption && this.transitActionOption.nextStatusDesc
|
||||
? `${this.language === 'en' ? 'Current action:' : '当前操作:'}${this.transitActionOption.nextStatusDesc}`
|
||||
: this.t('submitSectionActionDesc')
|
||||
: this.$tr('当前工单正在处理中,提交后会继续流转。')
|
||||
}
|
||||
return ''
|
||||
},
|
||||
@@ -827,11 +675,11 @@ export default {
|
||||
},
|
||||
historyStatusOptions() {
|
||||
return [
|
||||
{ value: '', label: this.t('allStatus') },
|
||||
{ value: '0', label: this.t('pendingStatus') },
|
||||
{ value: '3', label: this.t('processingStatus') },
|
||||
{ value: '5', label: this.t('resolvedStatus') },
|
||||
{ value: '9', label: this.t('closedStatus') }
|
||||
{ value: '', label: this.$tr('全部') },
|
||||
{ value: '0', label: this.$tr('待处理') },
|
||||
{ value: '3', label: this.$tr('处理中') },
|
||||
{ value: '5', label: this.$tr('已解决') },
|
||||
{ value: '9', label: this.$tr('已结束') }
|
||||
]
|
||||
},
|
||||
transitAssigneePickerRange() {
|
||||
@@ -868,9 +716,6 @@ export default {
|
||||
this.refreshContext()
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$translate(this.i18n, key, params)
|
||||
},
|
||||
handleScroll(e) {
|
||||
this.scrollTop = e.detail.scrollTop
|
||||
},
|
||||
@@ -905,7 +750,7 @@ export default {
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
uni.showToast({ title: this.t('loadOrderFailed'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('入住信息加载失败'), icon: 'none' })
|
||||
})
|
||||
},
|
||||
resetForm() {
|
||||
@@ -1005,28 +850,28 @@ export default {
|
||||
},
|
||||
getSubmitValidationMessage() {
|
||||
if (this.fixOnholdMode && !this.fixOnholdFlowNo) {
|
||||
return this.t('submitFailed')
|
||||
return this.$tr('工单提交失败')
|
||||
}
|
||||
if (this.transitActionMode && !this.transitActionFlowNo) {
|
||||
return this.t('submitFailed')
|
||||
return this.$tr('工单提交失败')
|
||||
}
|
||||
if (!this.fixOnholdMode && !this.transitActionMode && !this.getSubmitOrderNo() && !this.getSubmitRoomCode()) {
|
||||
return this.t('missingStayContext')
|
||||
return this.$tr('当前缺少入住订单或房间信息,暂无法提交工单')
|
||||
}
|
||||
if (this.isRepairService && !(Array.isArray(this.form.attachments) && this.form.attachments.length)) {
|
||||
return this.t('repairAttachmentRequired')
|
||||
return this.$tr('请上传报修附件图片')
|
||||
}
|
||||
if (this.isChangeService && !this.switchForm.roomTypeCode) {
|
||||
return this.t('changeAreaRequired')
|
||||
return this.$tr('请选择意向房型')
|
||||
}
|
||||
if (this.isCheckOutService && !this.resolveCheckOutTime()) {
|
||||
return this.t('checkoutTimeRequired')
|
||||
return this.$tr('请选择退宿时间')
|
||||
}
|
||||
if (this.isCheckOutService && !String(this.form.content || '').trim()) {
|
||||
return this.t('checkoutReasonRequired')
|
||||
return this.$tr('请填写退宿原因')
|
||||
}
|
||||
if (this.showTransitAssigneeSelector && !this.transitSelectedAssigneeValue) {
|
||||
return this.t('selectAssignee')
|
||||
return this.$tr('请选择处理目标')
|
||||
}
|
||||
return ''
|
||||
},
|
||||
@@ -1278,8 +1123,8 @@ export default {
|
||||
|
||||
new Promise((resolve) => {
|
||||
uni.showModal({
|
||||
title: this.t('confirmSubmitTitle'),
|
||||
content: this.t('confirmSubmitContent'),
|
||||
title: this.$tr('确认提交'),
|
||||
content: this.$tr('确认提交当前工单吗?'),
|
||||
success: (res) => resolve(!!res.confirm),
|
||||
fail: () => resolve(false)
|
||||
})
|
||||
@@ -1299,7 +1144,7 @@ export default {
|
||||
return this.submitWithCompatibilityFallback(api, this.buildSubmitPayload())
|
||||
})
|
||||
.then(() => {
|
||||
uni.showToast({ title: this.t('submitSuccess'), icon: 'success' })
|
||||
uni.showToast({ title: this.$tr('工单提交成功'), icon: 'success' })
|
||||
this.cancelFixOnhold()
|
||||
this.cancelTransitAction()
|
||||
this.resetForm()
|
||||
@@ -1311,7 +1156,7 @@ export default {
|
||||
return
|
||||
}
|
||||
uni.showToast({
|
||||
title: this.getSubmitErrorText(error) || this.t('submitFailed'),
|
||||
title: this.getSubmitErrorText(error) || this.$tr('工单提交失败'),
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
@@ -1360,7 +1205,7 @@ export default {
|
||||
this.historyList = []
|
||||
}
|
||||
this.hasNext = false
|
||||
uni.showToast({ title: this.t('loadHistoryFailed'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('工单记录加载失败'), icon: 'none' })
|
||||
})
|
||||
.finally(() => {
|
||||
this.historyLoading = false
|
||||
@@ -1380,10 +1225,10 @@ export default {
|
||||
return 'closed'
|
||||
},
|
||||
statusText(status) {
|
||||
if ([0, 1, 2].includes(status)) return this.t('pendingStatus')
|
||||
if ([3, 4, 7].includes(status)) return this.t('processingStatus')
|
||||
if ([5, 6].includes(status)) return this.t('resolvedStatus')
|
||||
return this.t('closedStatus')
|
||||
if ([0, 1, 2].includes(status)) return this.$tr('待处理')
|
||||
if ([3, 4, 7].includes(status)) return this.$tr('处理中')
|
||||
if ([5, 6].includes(status)) return this.$tr('已解决')
|
||||
return this.$tr('已结束')
|
||||
},
|
||||
openFlows(item) {
|
||||
this.currentFlowOrder = item
|
||||
@@ -1398,7 +1243,7 @@ export default {
|
||||
return this.loadTransitionOptions(this.getCurrentFlowItem())
|
||||
})
|
||||
.catch(() => {
|
||||
uni.showToast({ title: this.t('loadFlowsFailed'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('工单流转加载失败'), icon: 'none' })
|
||||
})
|
||||
.finally(() => {
|
||||
this.flowLoading = false
|
||||
@@ -1419,7 +1264,7 @@ export default {
|
||||
})
|
||||
.catch(() => {
|
||||
this.transitionOptions = []
|
||||
uni.showToast({ title: this.t('loadActionsFailed'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('工单操作项加载失败'), icon: 'none' })
|
||||
return []
|
||||
})
|
||||
},
|
||||
@@ -1624,7 +1469,7 @@ export default {
|
||||
this.transitAssigneeGroups = this.normalizeTransitAssigneeGroups(response)
|
||||
})
|
||||
.catch(() => {
|
||||
uni.showToast({ title: this.t('loadAssigneeFailed'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('处理目标加载失败'), icon: 'none' })
|
||||
})
|
||||
},
|
||||
onTransitAssigneeChange(event) {
|
||||
@@ -1671,13 +1516,13 @@ export default {
|
||||
this.form.attachments.splice(index, 1)
|
||||
},
|
||||
onUploadError() {
|
||||
uni.showToast({ title: this.t('uploadImageFailed'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('图片上传失败,请重试'), icon: 'none' })
|
||||
},
|
||||
onUploadOversize() {
|
||||
uni.showToast({ title: this.t('uploadImageOversize'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('图片不能超过 5MB'), icon: 'none' })
|
||||
},
|
||||
onUploadExceed() {
|
||||
uni.showToast({ title: this.t('uploadImageCountExceeded'), icon: 'none' })
|
||||
uni.showToast({ title: this.$tr('最多上传 6 张图片'), icon: 'none' })
|
||||
},
|
||||
getAttachmentPreview(attachment) {
|
||||
return addFilePrefix(pickReadableValue(attachment && attachment.resourceUrl, attachment && attachment.url, attachment && attachment.path))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<view class="bill-page tn-safe-area-inset-bottom">
|
||||
<tn-nav-bar :isBack="true" :bottomShadow="false" backgroundColor="transparent">
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ t('navTitle') }}</view>
|
||||
<view class="tn-text-bold tn-text-xl tn-color-black">{{ $tr('账单管理') }}</view>
|
||||
</tn-nav-bar>
|
||||
|
||||
<view class="bill-body tn-padding" :style="{ paddingTop: vuex_custom_bar_height + 'px', paddingBottom: '48rpx' }">
|
||||
@@ -21,14 +21,6 @@ import { saveActiveApplicationCode, saveHomePageTabId } from '@/utils/app-state'
|
||||
import CurrentApplicationBillPanel from '../components/CurrentApplicationBillPanel.vue'
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
zh: {
|
||||
navTitle: '账单管理'
|
||||
},
|
||||
en: {
|
||||
navTitle: 'Bill Management'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
CurrentApplicationBillPanel
|
||||
},
|
||||
@@ -45,9 +37,6 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
t(key, params) {
|
||||
return this.$tm('pkgService.utility_recharge.utility_recharge', key, params)
|
||||
},
|
||||
handleReferenceResolved(referenceTypeNo) {
|
||||
this.referenceTypeNo = referenceTypeNo || ''
|
||||
if (this.referenceTypeNo) {
|
||||
|
||||
Reference in New Issue
Block a user