feat: new

This commit is contained in:
luo
2026-09-16 16:32:08 +08:00
parent 6a1543f9f6
commit 8bd9de15cd
22 changed files with 2502 additions and 33 deletions

View File

@@ -40,7 +40,7 @@
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { authApi } from '@/api/index.js';
import { authApi, assetApi } from '@/api/index.js';
import { useUserStore } from '@/store/index.js';
const POST_BIND_RELOGIN_NOTICE_KEY = 'postBindReloginNotice';
@@ -57,12 +57,29 @@
let timer = null;
let fromLogin = ref(false);
onMounted(() => {
onMounted(async () => {
// 获取页面参数,判断是否从登录页面跳转过来
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const options = currentPage.options;
fromLogin.value = options.fromLogin === 'true';
// 契约变化:账号已有主手机号时,主号 + 验证码有效 → 幂等建联。
// 预填账号已有主手机号,避免存量用户「提示要验证却提交任何号码都被拒」的死锁。
const token = uni.getStorageSync('token');
const identifier = userStore.state.identifier || uni.getStorageSync('identifier') || '';
if (!token || !identifier) return;
try {
const data = await assetApi.getInfo(identifier);
const mainPhone = (data && data.bound_phone) || '';
if (mainPhone) {
bind.phone = mainPhone;
}
} catch (e) {
// 预填失败不阻塞绑定流程,用户仍可手动输入手机号
console.error('预填主手机号失败', e);
}
});
const prepareManualRelogin = () => {

View File

@@ -104,6 +104,9 @@
<RenewalPaymentPopup ref="renewalPopupRef" :identifier="userStore.state.identifier"
paymentRefreshTarget="home" @completed="loadAssetInfo" />
<PopupCandidate v-if='popupCandidateShow' page='home' :identifier='userStore.state.identifier'
@close='onPopupCandidateClose' />
<!-- 日期选择器弹窗 -->
<up-datetime-picker v-if="!userInfo.isDevice" :show="showStartDatePicker" v-model="startDateTimestamp"
mode="date" @confirm="onStartDateConfirm" @cancel="showStartDatePicker=false"
@@ -134,6 +137,7 @@
import FloatingButton from '@/components/FloatingButton.vue';
import NotificationPopup from '@/components/NotificationPopup.vue';
import RenewalPaymentPopup from '@/components/RenewalPaymentPopup.vue';
import PopupCandidate from '@/components/PopupCandidate.vue';
import {
assetApi,
deviceApi,
@@ -238,6 +242,7 @@
let notificationPopupCurrent = ref(0);
let renewalPopupRef = ref(null);
const notificationReadPending = new Set();
let popupCandidateShow = ref(false);
const formatDate = (dateStr) => {
if (!dateStr) return '-';
@@ -862,11 +867,10 @@
const loadUnreadNotifications = async () => {
try {
const data = await notificationApi.getList(1, 50, false);
const items = (data?.items || [])
.filter(item => !item.is_read)
.sort((a, b) => getNotificationPriority(b) - getNotificationPriority(a));
if (!items.length) return;
const data = await notificationApi.getList(1, 50, false);
const items = (data?.items || [])
.filter(item => !item.is_read);
if (!items.length) return;
notificationItems.value = items;
notificationPopupCurrent.value = 0;
@@ -885,17 +889,6 @@
});
};
const getNotificationPriority = (item) => {
const severityRank = { info: 10, warning: 20, error: 30, critical: 40 };
const remainingDays = Number(item?.days_until_expiry ?? item?.days_remaining ?? item?.remaining_days);
const expiryLevel = String(item?.expiry_level || '').toLowerCase();
if (item?.category === 'expiry' && ((Number.isFinite(remainingDays) && remainingDays >= 0 && remainingDays <= 3) ||
['0_3', '0-3', '0~3', 'critical'].includes(expiryLevel))) {
return 100;
}
return severityRank[item?.severity] || 0;
};
const onNotificationChange = (event) => {
const index = Number(event?.detail?.current ?? event?.current ?? 0);
notificationPopupCurrent.value = index;
@@ -906,6 +899,18 @@
notificationPopupShow.value = false;
};
const runPopupCandidate = () => {
popupCandidateShow.value = true;
};
const onPopupCandidateClose = (reason) => {
popupCandidateShow.value = false;
if (reason === 'empty' || reason === 'invisible') {
loadUnreadNotifications();
}
loadNotificationUnreadCount();
};
onMounted(() => {
initCurrentMonth();
});
@@ -916,7 +921,7 @@
}
handleIndexEntry();
loadNotificationUnreadCount();
loadUnreadNotifications();
runPopupCandidate();
});
</script>

View File

@@ -221,6 +221,10 @@
</view>
</view>
</view>
<PopupCandidate v-if='popupCandidateShow' page='asset_wallet_recharge'
:identifier='userStore.state.identifier' @close='onPopupCandidateClose' />
</template>
<script setup>
@@ -228,6 +232,7 @@
import { onShow } from '@dcloudio/uni-app';
import { walletApi } from '@/api/index.js';
import { useUserStore } from '@/store/index.js';
import PopupCandidate from '@/components/PopupCandidate.vue';
import {
consumePendingPaymentRefresh,
handlePaymentError,
@@ -242,6 +247,11 @@
import { getDefaultPaymentMethod, getPaymentMethodOptions, normalizePaymentMethods } from '@/utils/payment-methods.js';
const userStore = useUserStore();
const popupCandidateShow = ref(false);
const onPopupCandidateClose = () => {
popupCandidateShow.value = false;
};
const currentTab = ref(0);
const walletDetail = reactive({
@@ -765,6 +775,7 @@
onMounted(() => {
syncWalletStatus();
popupCandidateShow.value = true;
});
</script>

View File

@@ -61,7 +61,6 @@
const getCategoryText = (category) => ({
approval: '审批',
expiry: '临期',
exchange: '换货',
sync: '同步',
system: '系统'
}[category] || '通知');
@@ -73,17 +72,6 @@
critical: '严重'
}[severity] || '提示');
const getNotificationPriority = (item) => {
const severityRank = { info: 10, warning: 20, error: 30, critical: 40 };
const remainingDays = Number(item?.days_until_expiry ?? item?.days_remaining ?? item?.remaining_days);
const expiryLevel = String(item?.expiry_level || '').toLowerCase();
if (item?.category === 'expiry' && ((Number.isFinite(remainingDays) && remainingDays >= 0 && remainingDays <= 3) ||
['0_3', '0-3', '0~3', 'critical'].includes(expiryLevel))) {
return 100;
}
return severityRank[item?.severity] || 0;
};
const loadUnreadCount = async () => {
try {
const data = await notificationApi.getUnreadCount();
@@ -98,7 +86,7 @@
loading.value = true;
try {
const data = await notificationApi.getList(page.value, pageSize);
const items = (data?.items || []).sort((a, b) => getNotificationPriority(b) - getNotificationPriority(a));
const items = (data?.items || []);
if (append) {
notifications.push(...items);
} else {

View File

@@ -95,6 +95,10 @@
</view>
</up-popup>
</view>
<PopupCandidate v-if='popupCandidateShow' page='package_purchase'
:identifier='userStore.state.identifier' @close='onPopupCandidateClose' />
</template>
<script setup>
@@ -102,6 +106,7 @@
import { onLoad, onShow } from '@dcloudio/uni-app';
import { assetApi, isAssetRealNameCompleted, orderApi, walletApi } from '@/api/index.js';
import { useUserStore } from '@/store/index.js';
import PopupCandidate from '@/components/PopupCandidate.vue';
import {
consumePendingPaymentRefresh,
handlePaymentError,
@@ -116,6 +121,11 @@
import { getDefaultPaymentMethod, getPaymentMethodOptions, normalizePaymentMethods } from '@/utils/payment-methods.js';
const userStore = useUserStore();
const popupCandidateShow = ref(false);
const onPopupCandidateClose = () => {
popupCandidateShow.value = false;
};
const showModal = ref(false);
const currentPackage = ref(null);
@@ -515,6 +525,7 @@
} catch (error) {
renewalPackageNames.value = [];
}
popupCandidateShow.value = true;
});
onMounted(() => {