refactor: 授权弹窗逻辑梳理/增加重新生成按钮

This commit is contained in:
rd
2025-07-11 11:15:04 +08:00
parent 27c8d2e200
commit ef69b914b4
2 changed files with 325 additions and 250 deletions

View File

@ -9,11 +9,12 @@
title="授权账号" title="授权账号"
modal-class="authorized-account-modal" modal-class="authorized-account-modal"
:mask-closable="false" :mask-closable="false"
:footer="!isLoading" :footer="modalState !== MODAL_STATE.LOADING"
@close="close" @close="close"
> >
<div class="flex flex-col items-center"> <div class="flex flex-col items-center">
<template v-if="isLoading"> <!-- 加载中状态 -->
<template v-if="modalState === MODAL_STATE.LOADING">
<a-progress <a-progress
:percent="progress" :percent="progress"
color="#6D4CFE" color="#6D4CFE"
@ -24,32 +25,48 @@
/> />
<p class="s2 mt-16px">数据同步和初始化中请勿关闭窗口</p> <p class="s2 mt-16px">数据同步和初始化中请勿关闭窗口</p>
</template> </template>
<template v-else> <template v-else>
<template v-if="isCompleted"> <!-- 完成状态 -->
<img :src="isSuccess ? icon2 : icon3" width="80" height="80" class="mb-16px" /> <template v-if="modalState === MODAL_STATE.SUCCESS || modalState === MODAL_STATE.FAILED">
<p class="s2">{{ `数据初始化${isSuccess ? '成功' : '失败'}` }}</p> <img :src="modalState === MODAL_STATE.SUCCESS ? icon2 : icon3" width="80" height="80" class="mb-16px" />
<p v-if="!isSuccess" class="red-text">失败原因{{ failReason || '-' }}</p> <p class="s2">{{ `数据初始化${modalState === MODAL_STATE.SUCCESS ? '成功' : '失败'}` }}</p>
<p v-if="modalState === MODAL_STATE.FAILED" class="red-text">失败原因{{ failReason || '-' }}</p>
</template> </template>
<!-- 二维码状态 -->
<template v-else> <template v-else>
<div class="img-box"> <div class="img-box">
<template v-if="qrCodeLoading || isFailLoadQrCode"> <!-- 二维码加载中或失败 -->
<template v-if="modalState === MODAL_STATE.QR_LOADING || modalState === MODAL_STATE.QR_FAILED">
<div class="relative w-160px h-160px"> <div class="relative w-160px h-160px">
<a-image :src="icon1" width="160" height="160" /> <a-image :src="icon1" width="160" height="160" />
<div class="absolute top-0 left-0 z-2 w-full h-full flex flex-col items-center justify-center"> <div class="absolute top-0 left-0 z-2 w-full h-full flex flex-col items-center justify-center">
<img v-if="isFailLoadQrCode" :src="icon4" width="24" height="24" class="mb-13px" /> <img
v-if="modalState === MODAL_STATE.QR_FAILED"
:src="icon4"
width="24"
height="24"
class="mb-13px"
/>
<icon-loading v-else size="24" class="color-#6D4CFE mb-13px" /> <icon-loading v-else size="24" class="color-#6D4CFE mb-13px" />
<span :class="isFailLoadQrCode ? '!color-#F64B31' : '!color-#6D4CFE'" class="s2">{{ <span
isFailLoadQrCode ? '二维码生成失败' : '二维码生成中...' :class="modalState === MODAL_STATE.QR_FAILED ? '!color-#F64B31' : '!color-#6D4CFE'"
}}</span> class="s2"
>{{ modalState === MODAL_STATE.QR_FAILED ? '二维码生成失败' : '二维码生成中...' }}</span
>
</div> </div>
<div <div
class="absolute top-0 left-0 w-full h-full flex items-center justify-center opacity-80 bg-#fff" class="absolute top-0 left-0 w-full h-full flex items-center justify-center opacity-80 bg-#fff"
></div> ></div>
</div> </div>
</template> </template>
<!-- 正常二维码 -->
<a-image v-else :src="qrCodeUrl" width="160" height="160" /> <a-image v-else :src="qrCodeUrl" width="160" height="160" />
<div v-if="isOverdue" class="mask cursor-pointer" @click="handleRefreshQrCode"> <!-- 二维码失效遮罩 -->
<div v-if="modalState === MODAL_STATE.QR_EXPIRED" class="mask cursor-pointer" @click="handleRefreshQrCode">
<icon-refresh size="24" class="mb-13px" /> <icon-refresh size="24" class="mb-13px" />
<p class="s1">二维码失效</p> <p class="s1">二维码失效</p>
<p class="s1">请点击刷新</p> <p class="s1">请点击刷新</p>
@ -59,15 +76,29 @@
</template> </template>
</template> </template>
</div> </div>
<template #footer> <template #footer>
<a-button v-if="isCompleted" size="large" class="cancel-btn" @click="close">取消</a-button> <a-button v-if="modalState === MODAL_STATE.QR_READY" size="large" class="cancel-btn" @click="handleRefreshQrCode">
<a-button type="primary" size="large" @click="handleOk">{{ confirmBtnText }} </a-button> 重新生成
</a-button>
<a-button
v-if="modalState === MODAL_STATE.SUCCESS || modalState === MODAL_STATE.FAILED"
size="large"
class="cancel-btn"
@click="close"
>
取消
</a-button>
<a-button type="primary" size="large" @click="handleOk">
{{ confirmBtnText }}
</a-button>
</template> </template>
</a-modal> </a-modal>
</template> </template>
<script setup> <script setup>
import { defineExpose, ref } from 'vue'; import { defineExpose, ref, computed } from 'vue';
import { Message as AMessage } from '@arco-design/web-vue';
import { getAuthorizedImage, getMediaAccountsAuthorizedStatus } from '@/api/all/propertyMarketing'; import { getAuthorizedImage, getMediaAccountsAuthorizedStatus } from '@/api/all/propertyMarketing';
import icon1 from '@/assets/img/media-account/icon-default-qrcode.png'; import icon1 from '@/assets/img/media-account/icon-default-qrcode.png';
@ -75,52 +106,67 @@ import icon2 from '@/assets/img/media-account/icon-feedback-success.png';
import icon3 from '@/assets/img/media-account/icon-feedback-fail.png'; import icon3 from '@/assets/img/media-account/icon-feedback-fail.png';
import icon4 from '@/assets/img/media-account/icon-warn.png'; import icon4 from '@/assets/img/media-account/icon-warn.png';
// 失效时间
const emits = defineEmits(['update']); const emits = defineEmits(['update']);
const OVERDUE_TIME = 30000; // 状态枚举
const MODAL_STATE = {
QR_LOADING: 0, // 二维码加载中
QR_FAILED: 1, // 二维码生成失败
QR_READY: 2, // 二维码就绪,等待扫码
QR_EXPIRED: 3, // 二维码已过期
LOADING: 4, // 数据同步中
SUCCESS: 5, // 授权成功
FAILED: 6, // 授权失败
};
const OVERDUE_TIME = 30000; // 失效时间
const visible = ref(false); const visible = ref(false);
const isOverdue = ref(false); // 二维码失效 const modalState = ref(MODAL_STATE.QR_LOADING);
const isLoading = ref(false);
const isCompleted = ref(false);
const isSuccess = ref(false);
const failReason = ref(''); const failReason = ref('');
const progress = ref(0); const progress = ref(0);
const id = ref(''); const id = ref('');
const platform = ref(''); const platform = ref('');
const isFailLoadQrCode = ref(false);
const qrCodeUrl = ref(''); const qrCodeUrl = ref('');
const qrCodeLoading = ref(false);
let progressTimer = null; let progressTimer = null;
let overdueTimer = null; let overdueTimer = null;
let statusPollingTimer = null; let statusPollingTimer = null;
// 按钮文案映射
const confirmBtnText = computed(() => { const confirmBtnText = computed(() => {
if (isFailLoadQrCode.value) return '重新生成'; const btnTextMap = {
if (!isCompleted.value) return '完成扫码'; [MODAL_STATE.QR_LOADING]: '完成扫码',
return isSuccess.value ? '继续添加' : '重新扫码'; [MODAL_STATE.QR_FAILED]: '重新生成',
[MODAL_STATE.QR_READY]: '完成扫码',
[MODAL_STATE.QR_EXPIRED]: '重新生成',
[MODAL_STATE.LOADING]: '处理中...',
[MODAL_STATE.SUCCESS]: '继续添加',
[MODAL_STATE.FAILED]: '重新扫码',
};
return btnTextMap[modalState.value] || '确定';
});
// 按钮是否禁用
const isBtnDisabled = computed(() => {
return false; // 所有状态下按钮都是可点击的
}); });
const open = (accountId, platformCode) => { const open = (accountId, platformCode) => {
id.value = accountId; id.value = accountId;
platform.value = platformCode === 0 ? '抖音' : '小红书'; platform.value = platformCode === 0 ? '抖音' : '小红书';
modalState.value = MODAL_STATE.QR_LOADING;
getAuthorizedQrCode(); getAuthorizedQrCode();
visible.value = true; visible.value = true;
}; };
const resetTaskFields = () => { const resetTaskFields = () => {
isOverdue.value = false; modalState.value = MODAL_STATE.QR_LOADING;
isLoading.value = false;
isCompleted.value = false;
isSuccess.value = false;
failReason.value = ''; failReason.value = '';
platform.value = ''; platform.value = '';
progress.value = 0; progress.value = 0;
qrCodeUrl.value = ''; qrCodeUrl.value = '';
qrCodeLoading.value = false;
isFailLoadQrCode.value = false;
}; };
const close = () => { const close = () => {
resetTaskFields(); resetTaskFields();
id.value = ''; id.value = '';
@ -132,24 +178,22 @@ const close = () => {
const getAuthorizedQrCode = async () => { const getAuthorizedQrCode = async () => {
try { try {
qrCodeLoading.value = true; modalState.value = MODAL_STATE.QR_LOADING;
const { code, data } = await getAuthorizedImage(id.value); const { code, data } = await getAuthorizedImage(id.value);
if (code === 200) { if (code === 200) {
qrCodeUrl.value = data.image; qrCodeUrl.value = data.image;
overdueTimer = null; overdueTimer = null;
isOverdue.value = false; modalState.value = MODAL_STATE.QR_READY;
// 约定后端限制40s内必须扫码前端定30s后失效 // 约定后端限制40s内必须扫码前端定30s后失效
overdueTimer = setTimeout(() => { overdueTimer = setTimeout(() => {
isOverdue.value = true; modalState.value = MODAL_STATE.QR_EXPIRED;
}, OVERDUE_TIME); }, OVERDUE_TIME);
} else { } else {
isFailLoadQrCode.value = true; modalState.value = MODAL_STATE.QR_FAILED;
} }
} catch (error) { } catch (error) {
isFailLoadQrCode.value = true; modalState.value = MODAL_STATE.QR_FAILED;
} finally {
qrCodeLoading.value = false;
} }
}; };
@ -163,22 +207,14 @@ const clearStatusPollingTimer = () => {
const startStatusPolling = () => { const startStatusPolling = () => {
clearStatusPollingTimer(); clearStatusPollingTimer();
statusPollingTimer = setInterval(async () => { statusPollingTimer = setInterval(async () => {
if (!isCompleted.value) { if (modalState.value === MODAL_STATE.LOADING) {
await getAuthorizedStatus(); await getAuthorizedStatus();
if (isCompleted.value) {
progress.value = 1;
clearFakeProgressTimer();
clearStatusPollingTimer();
isLoading.value = false;
emits('update');
}
} }
}, 2000); }, 2000);
}; };
const startLoading = async () => { const startLoading = async () => {
isLoading.value = true; modalState.value = MODAL_STATE.LOADING;
isCompleted.value = false;
progress.value = 0; progress.value = 0;
startFakeProgressPolling(); startFakeProgressPolling();
startStatusPolling(); startStatusPolling();
@ -189,10 +225,18 @@ const getAuthorizedStatus = async () => {
if (code === 200) { if (code === 200) {
const { status, message } = data; const { status, message } = data;
if (status !== 0) { if (status !== 0) {
isCompleted.value = true; progress.value = 1;
isSuccess.value = status === 1; clearFakeProgressTimer();
failReason.value = status === 2 ? message : ''; clearStatusPollingTimer();
isOverdue.value = false;
if (status === 1) {
modalState.value = MODAL_STATE.SUCCESS;
} else {
modalState.value = MODAL_STATE.FAILED;
failReason.value = message || '';
}
emits('update');
} }
} }
}; };
@ -200,11 +244,11 @@ const getAuthorizedStatus = async () => {
const startFakeProgressPolling = () => { const startFakeProgressPolling = () => {
clearFakeProgressTimer(); clearFakeProgressTimer();
progressTimer = setInterval(() => { progressTimer = setInterval(() => {
if (!isCompleted.value && progress.value < 0.99) { if (modalState.value === MODAL_STATE.LOADING && progress.value < 0.99) {
const step = Math.random() * 0.04 + 0.01; const step = Math.random() * 0.04 + 0.01;
progress.value = Math.min(progress.value + step, 0.99); progress.value = Math.min(progress.value + step, 0.99);
progress.value = Number(progress.value.toFixed(2)); progress.value = Number(progress.value.toFixed(2));
} else if (!isCompleted.value && progress.value >= 0.99) { } else if (modalState.value === MODAL_STATE.LOADING && progress.value >= 0.99) {
progress.value = 0.99; // 卡在99% progress.value = 0.99; // 卡在99%
} else { } else {
clearFakeProgressTimer(); clearFakeProgressTimer();
@ -219,44 +263,57 @@ const clearFakeProgressTimer = () => {
progressTimer = null; progressTimer = null;
} }
}; };
const clearOverdueTimer = () => { const clearOverdueTimer = () => {
if (overdueTimer) { if (overdueTimer) {
clearTimeout(overdueTimer); clearTimeout(overdueTimer);
overdueTimer = null; overdueTimer = null;
} }
}; };
// 重新扫码 // 重新扫码
const handleRefreshQrCode = () => { const handleRefreshQrCode = () => {
clearOverdueTimer();
resetTaskFields(); resetTaskFields();
getAuthorizedQrCode(); getAuthorizedQrCode();
}; };
const handleOk = () => { const handleOk = () => {
if (isFailLoadQrCode.value) { // 二维码已过期
if (modalState.value === MODAL_STATE.QR_EXPIRED) {
handleRefreshQrCode(); handleRefreshQrCode();
return; return;
} }
if (!qrCodeUrl.value) { // 二维码还在加载中
if (modalState.value === MODAL_STATE.QR_LOADING) {
AMessage.warning('二维码生成中,请稍等'); AMessage.warning('二维码生成中,请稍等');
return; return;
} }
if (isOverdue.value) { // 二维码生成失败
AMessage.error('二维码已失效,请重新扫码'); if (modalState.value === MODAL_STATE.QR_FAILED) {
handleRefreshQrCode();
return; return;
} }
if (isCompleted.value) { // 授权成功,关闭弹窗
clearOverdueTimer(); if (modalState.value === MODAL_STATE.SUCCESS) {
if (isSuccess.value) {
close(); close();
} else { return;
handleRefreshQrCode();
} }
} else {
// 授权失败,重新扫码
if (modalState.value === MODAL_STATE.FAILED) {
handleRefreshQrCode();
return;
}
// 二维码就绪,开始授权流程
if (modalState.value === MODAL_STATE.QR_READY) {
clearOverdueTimer();
startLoading(); startLoading();
return;
} }
}; };

View File

@ -9,56 +9,12 @@
title="重新授权" title="重新授权"
modal-class="reauthorize-account-modal" modal-class="reauthorize-account-modal"
:mask-closable="false" :mask-closable="false"
:footer="taskStep !== TASK_STEP.loading" :footer="modalState !== MODAL_STATE.LOADING"
@close="close" @close="close"
> >
<div class="flex flex-col items-center"> <div class="flex flex-col items-center">
<template v-if="taskStep === TASK_STEP.default"> <!-- 加载中状态 -->
<!-- <template v-if="hasUnsyncData"> <template v-if="modalState === MODAL_STATE.LOADING">
<div class="flex items-center mb-20px">
<img :src="icon4" width="16" height="16" class="mr-16px" />
<span class="s2 color-#3C4043">检测到该账号最后更新日期为x月x日已有x天未同步最新数据</span>
</div>
<a-radio-group v-model="actionType" class="ml-32px">
<a-radio :value="1" class="mb-16px"
><span class="s2"
>立即同步遗漏数据 - 获取完整的最新数据 <span class="color-#6D4CFE">推荐</span></span
></a-radio
>
<a-radio :value="2" class="mb-16px"
><span class="s2">仅授权不更新 - 继续使用当前不完全的数据</span></a-radio
>
</a-radio-group>
</template> -->
<!-- <template v-else> -->
<div class="img-box">
<template v-if="qrCodeLoading || isFailLoadQrCode">
<div class="relative w-160px h-160px">
<a-image :src="icon1" width="160" height="160" />
<div class="absolute top-0 left-0 z-2 w-full h-full flex flex-col items-center justify-center">
<img v-if="isFailLoadQrCode" :src="icon4" width="24" height="24" class="mb-13px" />
<icon-loading v-else size="24" class="color-#6D4CFE mb-13px" />
<span :class="isFailLoadQrCode ? '!color-#F64B31' : '!color-#6D4CFE'" class="s2">{{
isFailLoadQrCode ? '二维码生成失败' : '二维码生成中...'
}}</span>
</div>
<div
class="absolute top-0 left-0 w-full h-full flex items-center justify-center opacity-80 bg-#fff"
></div>
</div>
</template>
<a-image v-else :src="qrCodeUrl" width="160" height="160" />
<div v-if="isOverdue" class="mask cursor-pointer" @click="handleRefreshQrCode">
<icon-refresh size="24" class="mb-13px" />
<p class="s1">二维码失效</p>
<p class="s1">请点击刷新</p>
</div>
</div>
<span class="mt-16px"> 请使用{{ platform }}扫码将公司账号绑定至灵机平台 </span>
</template>
<!-- </template> -->
<template v-else-if="taskStep === TASK_STEP.loading">
<a-progress <a-progress
:percent="progress" :percent="progress"
color="#6D4CFE" color="#6D4CFE"
@ -69,7 +25,10 @@
/> />
<p class="s2 mt-16px">数据同步和初始化中请勿关闭窗口</p> <p class="s2 mt-16px">数据同步和初始化中请勿关闭窗口</p>
</template> </template>
<!-- 完成状态 -->
<template v-else> <template v-else>
<template v-if="modalState === MODAL_STATE.SUCCESS || modalState === MODAL_STATE.FAILED">
<template v-if="isNicknameChanged"> <template v-if="isNicknameChanged">
<div class="flex items-center mb-20px"> <div class="flex items-center mb-20px">
<img :src="icon4" width="16" height="16" class="mr-16px" /> <img :src="icon4" width="16" height="16" class="mr-16px" />
@ -83,27 +42,77 @@
</div> </div>
</template> </template>
<template v-else> <template v-else>
<img :src="isSuccess ? icon2 : icon3" width="80" height="80" class="mb-16px" /> <img :src="modalState === MODAL_STATE.SUCCESS ? icon2 : icon3" width="80" height="80" class="mb-16px" />
<p class="s2">{{ `数据初始化${isSuccess ? '成功' : '失败'}` }}</p> <p class="s2">{{ `数据初始化${modalState === MODAL_STATE.SUCCESS ? '成功' : '失败'}` }}</p>
<p v-if="!isSuccess" class="red-text">失败原因{{ failReason || '-' }}</p> <p v-if="modalState === MODAL_STATE.FAILED" class="red-text">失败原因{{ failReason || '-' }}</p>
</template>
</template>
<!-- 二维码状态 -->
<template v-else>
<div class="img-box">
<!-- 二维码加载中或失败 -->
<template v-if="modalState === MODAL_STATE.QR_LOADING || modalState === MODAL_STATE.QR_FAILED">
<div class="relative w-160px h-160px">
<a-image :src="icon1" width="160" height="160" />
<div class="absolute top-0 left-0 z-2 w-full h-full flex flex-col items-center justify-center">
<img
v-if="modalState === MODAL_STATE.QR_FAILED"
:src="icon4"
width="24"
height="24"
class="mb-13px"
/>
<icon-loading v-else size="24" class="color-#6D4CFE mb-13px" />
<span
:class="modalState === MODAL_STATE.QR_FAILED ? '!color-#F64B31' : '!color-#6D4CFE'"
class="s2"
>{{ modalState === MODAL_STATE.QR_FAILED ? '二维码生成失败' : '二维码生成中...' }}</span
>
</div>
<div
class="absolute top-0 left-0 w-full h-full flex items-center justify-center opacity-80 bg-#fff"
></div>
</div>
</template>
<!-- 正常二维码 -->
<a-image v-else :src="qrCodeUrl" width="160" height="160" />
<!-- 二维码失效遮罩 -->
<div v-if="modalState === MODAL_STATE.QR_EXPIRED" class="mask cursor-pointer" @click="handleRefreshQrCode">
<icon-refresh size="24" class="mb-13px" />
<p class="s1">二维码失效</p>
<p class="s1">请点击刷新</p>
</div>
</div>
<span class="mt-16px"> 请使用{{ platform }}扫码将公司账号绑定至灵机平台 </span>
</template> </template>
</template> </template>
</div> </div>
<template #footer> <template #footer>
<a-button v-if="modalState === MODAL_STATE.QR_READY" size="large" class="cancel-btn" @click="handleRefreshQrCode">
重新生成
</a-button>
<a-button <a-button
v-if="taskStep === TASK_STEP.default || taskStep === TASK_STEP.end" v-if="modalState === MODAL_STATE.SUCCESS || modalState === MODAL_STATE.FAILED"
size="large" size="large"
class="cancel-btn" class="cancel-btn"
@click="close" @click="close"
>取消</a-button
> >
<a-button type="primary" size="large" @click="handleOk">{{ confirmBtnText }} </a-button> 取消
</a-button>
<a-button type="primary" size="large" @click="handleOk">
{{ confirmBtnText }}
</a-button>
</template> </template>
</a-modal> </a-modal>
</template> </template>
<script setup> <script setup>
import { defineExpose, ref, onUnmounted } from 'vue'; import { defineExpose, ref, computed } from 'vue';
import { Message as AMessage } from '@arco-design/web-vue';
import { getMediaAccountsAuthorizedStatus, getAuthorizedImage } from '@/api/all/propertyMarketing'; import { getMediaAccountsAuthorizedStatus, getAuthorizedImage } from '@/api/all/propertyMarketing';
import icon1 from '@/assets/img/media-account/icon-default-qrcode.png'; import icon1 from '@/assets/img/media-account/icon-default-qrcode.png';
@ -112,144 +121,148 @@ import icon3 from '@/assets/img/media-account/icon-feedback-fail.png';
import icon4 from '@/assets/img/media-account/icon-warn-1.png'; import icon4 from '@/assets/img/media-account/icon-warn-1.png';
const emits = defineEmits(['update']); const emits = defineEmits(['update']);
const OVERDUE_TIME = 30000; // 失效时间
const TASK_STEP = { // 状态枚举
default: 1, const MODAL_STATE = {
loading: 2, QR_LOADING: 0, // 二维码加载中
end: 3, QR_FAILED: 1, // 二维码生成失败
QR_READY: 2, // 二维码就绪,等待扫码
QR_EXPIRED: 3, // 二维码已过期
LOADING: 4, // 数据同步中
SUCCESS: 5, // 授权成功
FAILED: 6, // 授权失败
}; };
const OVERDUE_TIME = 30000; // 失效时间
const visible = ref(false); const visible = ref(false);
const isOverdue = ref(false); // 二维码失效 const modalState = ref(MODAL_STATE.QR_LOADING);
const isSuccess = ref(false);
const failReason = ref(''); const failReason = ref('');
const progress = ref(0); const progress = ref(0);
const id = ref(''); const id = ref('');
const platform = ref(''); const platform = ref('');
const isFailLoadQrCode = ref(false);
const qrCodeUrl = ref(''); const qrCodeUrl = ref('');
const qrCodeLoading = ref(false);
const taskStep = ref(TASK_STEP.default);
// const hasUnsyncData = ref(false); // 含有未同步数据
const isNicknameChanged = ref(false); // 昵称发生变化 const isNicknameChanged = ref(false); // 昵称发生变化
const actionType = ref(1);
let progressTimer = null; let progressTimer = null;
let overdueTimer = null; let overdueTimer = null;
let statusPollingTimer = null; let statusPollingTimer = null;
// 按钮文案映射
const confirmBtnText = computed(() => { const confirmBtnText = computed(() => {
if (isFailLoadQrCode.value) return '重新生成'; const btnTextMap = {
if (taskStep.value === TASK_STEP.default) { [MODAL_STATE.QR_LOADING]: '完成扫码',
// return hasUnsyncData.value ? '确定' : '完成扫码'; [MODAL_STATE.QR_FAILED]: '重新生成',
return '完成扫码'; [MODAL_STATE.QR_READY]: '完成扫码',
} [MODAL_STATE.QR_EXPIRED]: '重新生成',
[MODAL_STATE.LOADING]: '处理中...',
if (taskStep.value === TASK_STEP.end) { [MODAL_STATE.SUCCESS]: isNicknameChanged.value ? '确定覆盖' : '继续添加',
if (isNicknameChanged.value) return '确定覆盖'; [MODAL_STATE.FAILED]: '重新扫码',
return isSuccess.value ? '继续添加' : '重新扫码'; };
} return btnTextMap[modalState.value] || '确定';
return '';
}); });
const open = (accountId, platformCode) => { const open = (accountId, platformCode) => {
id.value = accountId; id.value = accountId;
platform.value = platformCode === 0 ? '抖音' : '小红书'; platform.value = platformCode === 0 ? '抖音' : '小红书';
modalState.value = MODAL_STATE.QR_LOADING;
getAuthorizedQrCode(); getAuthorizedQrCode();
visible.value = true; visible.value = true;
}; };
const resetTaskFields = () => { const resetTaskFields = () => {
isOverdue.value = false; modalState.value = MODAL_STATE.QR_LOADING;
isSuccess.value = false;
failReason.value = ''; failReason.value = '';
platform.value = ''; platform.value = '';
progress.value = 0; progress.value = 0;
qrCodeUrl.value = ''; qrCodeUrl.value = '';
qrCodeLoading.value = false;
isNicknameChanged.value = false; isNicknameChanged.value = false;
isFailLoadQrCode.value = false;
actionType.value = 1;
taskStep.value = TASK_STEP.default;
}; };
const close = () => { const close = () => {
resetTaskFields(); resetTaskFields();
id.value = ''; id.value = '';
clearFakeProgressTimer(); clearFakeProgressTimer();
clearStatusPollingTimer();
clearOverdueTimer(); clearOverdueTimer();
visible.value = false; visible.value = false;
}; };
const getAuthorizedQrCode = async () => {
try {
modalState.value = MODAL_STATE.QR_LOADING;
const { code, data } = await getAuthorizedImage(id.value);
if (code === 200) {
qrCodeUrl.value = data.image;
overdueTimer = null;
modalState.value = MODAL_STATE.QR_READY;
// 约定后端限制40s内必须扫码前端定30s后失效
overdueTimer = setTimeout(() => {
modalState.value = MODAL_STATE.QR_EXPIRED;
}, OVERDUE_TIME);
} else {
modalState.value = MODAL_STATE.QR_FAILED;
}
} catch (error) {
modalState.value = MODAL_STATE.QR_FAILED;
}
};
const clearStatusPollingTimer = () => {
if (statusPollingTimer) {
clearInterval(statusPollingTimer);
statusPollingTimer = null;
}
};
const startStatusPolling = () => {
clearStatusPollingTimer();
statusPollingTimer = setInterval(async () => {
if (modalState.value === MODAL_STATE.LOADING) {
await getAuthorizedStatus();
}
}, 2000);
};
const startLoading = async () => {
modalState.value = MODAL_STATE.LOADING;
progress.value = 0;
startFakeProgressPolling();
startStatusPolling();
};
const getAuthorizedStatus = async () => { const getAuthorizedStatus = async () => {
const { code, data } = await getMediaAccountsAuthorizedStatus(id.value); const { code, data } = await getMediaAccountsAuthorizedStatus(id.value);
if (code === 200) { if (code === 200) {
const { status, message } = data; const { status, message } = data;
if (status !== 0) { if (status !== 0) {
taskStep.value = TASK_STEP.end;
isSuccess.value = status === 1;
failReason.value = status === 2 ? message : '';
isOverdue.value = false;
}
}
};
const startStatusPolling = () => {
clearStatusPollingTimer();
statusPollingTimer = setInterval(async () => {
if (taskStep.value === TASK_STEP.loading) {
await getAuthorizedStatus();
if (taskStep.value === TASK_STEP.end) {
progress.value = 1; progress.value = 1;
clearFakeProgressTimer(); clearFakeProgressTimer();
clearStatusPollingTimer(); clearStatusPollingTimer();
if (status === 1) {
modalState.value = MODAL_STATE.SUCCESS;
// 这里可以根据实际业务逻辑判断是否需要显示昵称变更提示
// isNicknameChanged.value = true; // 示例:如果需要显示昵称变更
} else {
modalState.value = MODAL_STATE.FAILED;
failReason.value = message || '';
}
emits('update'); emits('update');
} }
} }
}, 2000);
};
const getAuthorizedQrCode = async () => {
try {
qrCodeLoading.value = true;
const { code, data } = await getAuthorizedImage(id.value);
if (code === 200) {
qrCodeUrl.value = data.image;
overdueTimer = null;
isOverdue.value = false;
// 约定后端限制40s内必须扫码前端定30s后失效
overdueTimer = setTimeout(() => {
isOverdue.value = true;
}, OVERDUE_TIME);
} else {
isFailLoadQrCode.value = true;
}
} catch (error) {
isFailLoadQrCode.value = true;
} finally {
qrCodeLoading.value = false;
}
};
const startLoading = async () => {
taskStep.value = TASK_STEP.loading;
progress.value = 0;
startFakeProgressPolling();
startStatusPolling();
}; };
const startFakeProgressPolling = () => { const startFakeProgressPolling = () => {
clearFakeProgressTimer(); clearFakeProgressTimer();
progressTimer = setInterval(() => { progressTimer = setInterval(() => {
if (taskStep.value === TASK_STEP.loading) { if (modalState.value === MODAL_STATE.LOADING && progress.value < 0.99) {
if (progress.value < 0.99) {
const step = Math.random() * 0.04 + 0.01; const step = Math.random() * 0.04 + 0.01;
progress.value = Math.min(progress.value + step, 0.99); progress.value = Math.min(progress.value + step, 0.99);
progress.value = Number(progress.value.toFixed(2)); progress.value = Number(progress.value.toFixed(2));
} else if (progress.value >= 0.99) { } else if (modalState.value === MODAL_STATE.LOADING && progress.value >= 0.99) {
progress.value = 0.99; // 卡在99% progress.value = 0.99; // 卡在99%
}
} else { } else {
clearFakeProgressTimer(); clearFakeProgressTimer();
clearStatusPollingTimer(); clearStatusPollingTimer();
@ -263,6 +276,7 @@ const clearFakeProgressTimer = () => {
progressTimer = null; progressTimer = null;
} }
}; };
const clearOverdueTimer = () => { const clearOverdueTimer = () => {
if (overdueTimer) { if (overdueTimer) {
clearTimeout(overdueTimer); clearTimeout(overdueTimer);
@ -270,52 +284,56 @@ const clearOverdueTimer = () => {
} }
}; };
const clearStatusPollingTimer = () => {
if (statusPollingTimer) {
clearInterval(statusPollingTimer);
statusPollingTimer = null;
}
};
// 重新扫码 // 重新扫码
const handleRefreshQrCode = () => { const handleRefreshQrCode = () => {
clearOverdueTimer();
resetTaskFields(); resetTaskFields();
getAuthorizedQrCode(); getAuthorizedQrCode();
}; };
const handleOk = () => { const handleOk = () => {
if (taskStep.value === TASK_STEP.default) { // 二维码已过期
if (isFailLoadQrCode.value) { if (modalState.value === MODAL_STATE.QR_EXPIRED) {
AMessage.error('二维码已失效,请重新扫码');
handleRefreshQrCode(); handleRefreshQrCode();
return; return;
} }
clearOverdueTimer(); // 二维码还在加载中
if (modalState.value === MODAL_STATE.QR_LOADING) {
if (!qrCodeUrl.value) {
AMessage.warning('二维码生成中,请稍等'); AMessage.warning('二维码生成中,请稍等');
return; return;
} }
if (isOverdue.value) {
AMessage.error('二维码已失效,请重新扫码'); // 二维码生成失败
if (modalState.value === MODAL_STATE.QR_FAILED) {
handleRefreshQrCode();
return; return;
} }
startLoading(); // 授权成功
return; if (modalState.value === MODAL_STATE.SUCCESS) {
}
if (taskStep.value === TASK_STEP.end) {
if (isNicknameChanged.value) { if (isNicknameChanged.value) {
isNicknameChanged.value = false; isNicknameChanged.value = false;
console.log('确定覆盖'); console.log('确定覆盖');
// 这里可以添加覆盖逻辑
} else { } else {
if (isSuccess.value) {
close(); close();
} else { }
return;
}
// 授权失败,重新扫码
if (modalState.value === MODAL_STATE.FAILED) {
handleRefreshQrCode(); handleRefreshQrCode();
return;
} }
}
// 二维码就绪,开始授权流程
if (modalState.value === MODAL_STATE.QR_READY) {
clearOverdueTimer();
startLoading();
return;
} }
}; };