将组件级 i18n 对象重构为统一由全局 locales/messages.js 管理,确保中英文语言切换时正确显示对应文本。 - 新增 utils/i18n.js 国际化工具函数 - 更新 store/$t.mixin.js 翻译混入逻辑 - 迁移 pkgService、pkgBooking、pkgAccount、pkgExplore、pages 等共 58 个组件的中英文文本至全局消息表
478 lines
13 KiB
Vue
478 lines
13 KiB
Vue
<template>
|
|
<view class="registration-records-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">{{ $tr('注册记录') }}</view>
|
|
</tn-nav-bar>
|
|
|
|
<view class="page-main tn-padding" :style="{ paddingTop: vuex_custom_bar_height + 'px', paddingBottom: '48rpx' }">
|
|
<scroll-view class="filter-scroll" scroll-x :show-scrollbar="false">
|
|
<view class="filter-row tn-margin-bottom-lg">
|
|
<view
|
|
v-for="item in statusOptions"
|
|
:key="item.value"
|
|
class="filter-chip"
|
|
:class="{ 'filter-chip--active': approvalStatus === item.value }"
|
|
@click="changeStatus(item.value)"
|
|
>
|
|
{{ item.label }}
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
|
|
<view v-if="providerUnavailable" class="empty-panel tn-padding-lg">
|
|
<view class="empty-title">{{ $tr('当前无法获取微信身份') }}</view>
|
|
<view class="empty-desc tn-margin-top-sm">{{ $tr('请在微信小程序中打开后,再查看当前微信账号提交的注册记录。') }}</view>
|
|
</view>
|
|
|
|
<view v-else-if="list.length">
|
|
<view
|
|
v-for="item in list"
|
|
:key="getRecordKey(item)"
|
|
class="record-card tn-margin-bottom-lg"
|
|
@click="goToRecordDetail(item)"
|
|
>
|
|
<view class="card-head tn-flex tn-flex-row-between tn-flex-col-center">
|
|
<view class="card-title-wrap">
|
|
<view class="card-title">{{ item.name || item.account || $tr('人员注册申请') }}</view>
|
|
<view class="card-code tn-margin-top-xs">{{ item.code || '--' }}</view>
|
|
</view>
|
|
<view :class="['status-badge', 'status-' + resolveStatusType(item.approvalStatus)]">
|
|
{{ getDisplayStatusText(item) }}
|
|
</view>
|
|
</view>
|
|
|
|
<view class="card-body tn-margin-top">
|
|
<view class="info-row tn-flex tn-flex-row-between">
|
|
<text class="info-label">{{ $tr('注册账号') }}</text>
|
|
<text class="info-value">{{ item.account || '--' }}</text>
|
|
</view>
|
|
<view class="info-row tn-flex tn-flex-row-between">
|
|
<text class="info-label">{{ $tr('手机号') }}</text>
|
|
<text class="info-value">{{ item.phone || '--' }}</text>
|
|
</view>
|
|
<view class="info-row tn-flex tn-flex-row-between">
|
|
<text class="info-label">{{ $tr('证件号') }}</text>
|
|
<text class="info-value">{{ item.idCard || item.passportNumber || '--' }}</text>
|
|
</view>
|
|
<view class="info-row tn-flex tn-flex-row-between">
|
|
<text class="info-label">{{ $tr('提交时间') }}</text>
|
|
<text class="info-value">{{ formatDateTime(item.createTime) }}</text>
|
|
</view>
|
|
<view v-if="item.approveTime" class="info-row tn-flex tn-flex-row-between">
|
|
<text class="info-label">{{ $tr('审批时间') }}</text>
|
|
<text class="info-value">{{ formatDateTime(item.approveTime) }}</text>
|
|
</view>
|
|
<view v-if="item.approveReason" class="remark-panel tn-margin-top">
|
|
<view class="remark-label">{{ item.approvalStatus === -1 ? $tr('驳回原因') : $tr('审批意见') }}</view>
|
|
<view class="remark-text tn-margin-top-xs">{{ item.approveReason }}</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="load-state">
|
|
<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">{{ $tr('暂无注册记录') }}</view>
|
|
<view class="empty-desc tn-margin-top-sm">{{ $tr('当前微信账号还没有提交过人员注册申请。') }}</view>
|
|
<view class="action-btn tn-margin-top-lg" @click="goToRegister">
|
|
<text class="tn-text-bold">{{ $tr('去提交注册申请') }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view v-if="loading && !list.length && !providerUnavailable" class="empty-panel tn-padding-lg">
|
|
<view class="empty-title">{{ $tr('注册记录加载中') }}</view>
|
|
<view class="empty-desc tn-margin-top-sm">{{ $tr('正在同步当前微信账号提交的注册申请记录,请稍候。') }}</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { registrationApplicationMePage } from '@/api/index.js'
|
|
|
|
function formatPageResponse(response) {
|
|
const payload = response && response.data ? response.data : response
|
|
return payload && typeof payload === 'object' ? payload : {}
|
|
}
|
|
|
|
function normalizeRecordList(list = []) {
|
|
if (!Array.isArray(list)) {
|
|
return []
|
|
}
|
|
return list.filter(item => item && typeof item === 'object')
|
|
}
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
providerValue: '',
|
|
providerUnavailable: false,
|
|
approvalStatus: '',
|
|
pageIndex: 1,
|
|
pageSize: 10,
|
|
total: 0,
|
|
list: [],
|
|
loading: false,
|
|
loadingMore: false,
|
|
hasMore: true,
|
|
statusOptions: []
|
|
}
|
|
},
|
|
created() {
|
|
this.syncStatusOptions()
|
|
this.syncNavigationTitle()
|
|
},
|
|
onShow() {
|
|
this.syncNavigationTitle()
|
|
this.reloadList()
|
|
},
|
|
onPullDownRefresh() {
|
|
this.reloadList().finally(() => {
|
|
uni.stopPullDownRefresh()
|
|
})
|
|
},
|
|
onReachBottom() {
|
|
this.loadMore()
|
|
},
|
|
computed: {
|
|
language() {
|
|
return this.$getLanguage()
|
|
}
|
|
},
|
|
watch: {
|
|
language() {
|
|
this.syncNavigationTitle()
|
|
this.syncStatusOptions()
|
|
this.reloadList()
|
|
}
|
|
},
|
|
methods: {
|
|
syncStatusOptions() {
|
|
this.statusOptions = [
|
|
{ label: this.$tr('全部'), value: '' },
|
|
{ label: this.$tr('审核中'), value: 0 },
|
|
{ label: this.$tr('已通过'), value: 1 },
|
|
{ label: this.$tr('已驳回'), value: -1 }
|
|
]
|
|
},
|
|
syncNavigationTitle() {
|
|
this.$syncNavigationTitle()
|
|
},
|
|
getWechatCode() {
|
|
return new Promise((resolve) => {
|
|
// #ifdef MP-WEIXIN
|
|
uni.login({
|
|
provider: 'weixin',
|
|
success: (res) => {
|
|
resolve(res.code || '')
|
|
},
|
|
fail: (err) => {
|
|
console.error('getWechatCode failed', err)
|
|
resolve('')
|
|
}
|
|
})
|
|
// #endif
|
|
// #ifndef MP-WEIXIN
|
|
resolve('')
|
|
// #endif
|
|
})
|
|
},
|
|
getStatusText(status) {
|
|
const map = {
|
|
0: this.$tr('审核中'),
|
|
1: this.$tr('已通过'),
|
|
'-1': this.$tr('已驳回')
|
|
}
|
|
return map[status] || this.$tr('处理中')
|
|
},
|
|
getDisplayStatusText(item = {}) {
|
|
if (this.language !== 'en' && item.approvalStatusDesc) {
|
|
return item.approvalStatusDesc
|
|
}
|
|
return this.getStatusText(item.approvalStatus)
|
|
},
|
|
resolveStatusType(status) {
|
|
if (Number(status) === 1) {
|
|
return 'approved'
|
|
}
|
|
if (Number(status) === -1) {
|
|
return 'rejected'
|
|
}
|
|
return 'pending'
|
|
},
|
|
formatDateTime(value) {
|
|
if (!value) {
|
|
return '--'
|
|
}
|
|
const text = String(value).replace('T', ' ')
|
|
return text.length > 16 ? text.slice(0, 16) : text
|
|
},
|
|
getRecordKey(item = {}) {
|
|
return item.code || `${item.account || 'registration'}-${item.createTime || ''}`
|
|
},
|
|
buildRecordRoutePayload(item = {}) {
|
|
return {
|
|
code: item.code || '',
|
|
account: item.account || '',
|
|
name: item.name || '',
|
|
gender: typeof item.gender === 'number' ? item.gender : null,
|
|
genderDesc: item.genderDesc || '',
|
|
email: item.email || '',
|
|
phone: item.phone || '',
|
|
country: item.country || '',
|
|
idCard: item.idCard || '',
|
|
workUnit: item.workUnit || '',
|
|
passportNumber: item.passportNumber || '',
|
|
school: item.school || '',
|
|
hobbyTags: item.hobbyTags || [],
|
|
approvalStatus: typeof item.approvalStatus === 'number' ? item.approvalStatus : undefined,
|
|
approvalStatusDesc: item.approvalStatusDesc || '',
|
|
approveReason: item.approveReason || '',
|
|
approveTime: item.approveTime || '',
|
|
createTime: item.createTime || ''
|
|
}
|
|
},
|
|
async ensureProviderValue() {
|
|
const providerValue = await this.getWechatCode()
|
|
this.providerValue = providerValue || ''
|
|
this.providerUnavailable = !this.providerValue
|
|
return this.providerValue
|
|
},
|
|
async reloadList() {
|
|
this.pageIndex = 1
|
|
this.hasMore = true
|
|
this.list = []
|
|
|
|
const providerValue = await this.ensureProviderValue()
|
|
if (!providerValue) {
|
|
this.total = 0
|
|
return
|
|
}
|
|
|
|
await this.fetchList(true)
|
|
},
|
|
async loadMore() {
|
|
if (!this.hasMore || this.loading || this.loadingMore || this.providerUnavailable) {
|
|
return
|
|
}
|
|
this.pageIndex += 1
|
|
await this.fetchList(false)
|
|
},
|
|
async fetchList(isReload = false) {
|
|
if (!this.providerValue) {
|
|
return
|
|
}
|
|
|
|
if (isReload) {
|
|
this.loading = true
|
|
} else {
|
|
this.loadingMore = true
|
|
}
|
|
|
|
const params = {
|
|
ProviderValue: this.providerValue,
|
|
PageIndex: this.pageIndex,
|
|
PageSize: this.pageSize
|
|
}
|
|
if (this.approvalStatus !== '' && this.approvalStatus !== null && typeof this.approvalStatus !== 'undefined') {
|
|
params.ApprovalStatus = this.approvalStatus
|
|
}
|
|
|
|
await registrationApplicationMePage(params, this.language)
|
|
.then((response) => {
|
|
const pageData = formatPageResponse(response)
|
|
const nextList = normalizeRecordList(pageData.data || [])
|
|
const total = Number(pageData.total || 0)
|
|
|
|
this.total = total
|
|
this.list = isReload ? nextList : this.list.concat(nextList)
|
|
this.hasMore = this.list.length < total && nextList.length > 0
|
|
})
|
|
.catch((error) => {
|
|
if (!isReload) {
|
|
this.pageIndex = Math.max(1, this.pageIndex - 1)
|
|
}
|
|
uni.showToast({
|
|
title: (error && (error.message || error.msg)) || this.$tr('注册记录加载失败'),
|
|
icon: 'none'
|
|
})
|
|
})
|
|
.finally(() => {
|
|
this.loading = false
|
|
this.loadingMore = false
|
|
})
|
|
},
|
|
changeStatus(value) {
|
|
if (this.approvalStatus === value) {
|
|
return
|
|
}
|
|
this.approvalStatus = value
|
|
this.reloadList()
|
|
},
|
|
goToRecordDetail(item = {}) {
|
|
const code = item.code || ''
|
|
const payload = this.buildRecordRoutePayload(item)
|
|
uni.navigateTo({
|
|
url: `/pkgAccount/auth_result/auth_result?from=registration-records&code=${encodeURIComponent(code)}&payload=${encodeURIComponent(JSON.stringify(payload))}`
|
|
})
|
|
},
|
|
goToRegister() {
|
|
uni.navigateTo({
|
|
url: '/pkgAccount/register/register'
|
|
})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.registration-records-page {
|
|
min-height: 100vh;
|
|
background: linear-gradient(180deg, #F0F6FF 0%, #F8FAFF 100%);
|
|
}
|
|
|
|
.record-card,
|
|
.empty-panel {
|
|
background: #FFFFFF;
|
|
border-radius: 24rpx;
|
|
padding: 32rpx;
|
|
box-shadow: 0 8rpx 20rpx rgba(15, 23, 42, 0.04);
|
|
border: 1px solid rgba($brand-primary, 0.05);
|
|
}
|
|
.record-card:active {
|
|
transform: scale(0.99);
|
|
}
|
|
|
|
.empty-title,
|
|
.card-title {
|
|
font-size: 32rpx;
|
|
font-weight: 700;
|
|
color: #1A2233;
|
|
}
|
|
|
|
.empty-desc,
|
|
.card-code,
|
|
.info-label,
|
|
.remark-label,
|
|
.load-state {
|
|
color: #6A7A99;
|
|
}
|
|
|
|
.filter-scroll {
|
|
width: 100%;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.filter-row {
|
|
display: inline-flex;
|
|
flex-wrap: nowrap;
|
|
gap: 16rpx;
|
|
padding: 4rpx;
|
|
}
|
|
|
|
.filter-chip {
|
|
flex-shrink: 0;
|
|
padding: 14rpx 28rpx;
|
|
border-radius: 999rpx;
|
|
background: #FFFFFF;
|
|
border: 1rpx solid rgba($brand-primary, 0.15);
|
|
color: #6A7A99;
|
|
font-size: 24rpx;
|
|
box-shadow: 0 4rpx 12rpx rgba($brand-primary, 0.05);
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.filter-chip--active {
|
|
background: #FFFFFF;
|
|
border-color: $brand-primary;
|
|
color: $brand-primary;
|
|
font-weight: bold;
|
|
box-shadow: 0 4rpx 16rpx rgba($brand-primary, 0.1);
|
|
}
|
|
|
|
.card-code {
|
|
font-size: 22rpx;
|
|
}
|
|
|
|
.status-badge {
|
|
padding: 8rpx 20rpx;
|
|
border-radius: 999rpx;
|
|
font-size: 22rpx;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.status-pending {
|
|
background: rgba(245, 158, 11, 0.12);
|
|
color: #B45309;
|
|
}
|
|
|
|
.status-approved {
|
|
background: rgba($brand-primary, 0.12);
|
|
color: $brand-primary;
|
|
}
|
|
|
|
.status-rejected {
|
|
background: rgba(239, 68, 68, 0.12);
|
|
color: #B91C1C;
|
|
}
|
|
|
|
.info-row {
|
|
padding: 16rpx 0;
|
|
border-bottom: 1px dashed rgba($brand-primary, 0.15);
|
|
}
|
|
|
|
.info-row:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.info-value {
|
|
max-width: 62%;
|
|
text-align: right;
|
|
color: #1A2233;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.remark-panel {
|
|
padding: 24rpx;
|
|
border-radius: 20rpx;
|
|
background: rgba($brand-primary, 0.02);
|
|
border: 1rpx solid rgba($brand-primary, 0.1);
|
|
}
|
|
|
|
.remark-text {
|
|
color: #1A2233;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.action-btn {
|
|
width: 100%;
|
|
height: 96rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 999rpx;
|
|
background: linear-gradient(135deg, rgba($brand-primary, 0.9) 0%, $brand-primary 100%);
|
|
color: #FFFFFF;
|
|
box-shadow: 0 12rpx 32rpx rgba($brand-primary, 0.25);
|
|
}
|
|
|
|
.load-state {
|
|
text-align: center;
|
|
font-size: 24rpx;
|
|
padding: 12rpx 0 24rpx;
|
|
}
|
|
|
|
::-webkit-scrollbar {
|
|
display: none;
|
|
width: 0 !important;
|
|
height: 0 !important;
|
|
-webkit-appearance: none;
|
|
background: transparent;
|
|
}
|
|
</style>
|