feat: 授权/重新授权逻辑

This commit is contained in:
rd
2025-06-28 16:57:30 +08:00
parent 78b9083ce8
commit 126c0eab38
2 changed files with 152 additions and 85 deletions

View File

@ -31,19 +31,19 @@
<p v-if="!isSuccess" class="red-text">失败原因{{ failReason || '-' }}</p> <p v-if="!isSuccess" class="red-text">失败原因{{ failReason || '-' }}</p>
</template> </template>
<template v-else> <template v-else>
<div class="flex items-center mb-16px"> <!-- <div class="flex items-center mb-16px">
<img :src="icon1" width="16" height="16" /> <img :src="icon1" width="16" height="16" />
<span class="ml-8px red-text">未识别到有效二维码</span> <span class="ml-8px red-text">未识别到有效二维码</span>
</div> </div> -->
<div class="img-box"> <div class="img-box">
<img :src="imgUrl" width="160" height="160" class="mb-16px" /> <img :src="imgUrl" width="160" height="160" class="mb-16px" />
<div v-if="isOverdue" class="mask"> <div v-if="isOverdue" class="mask" @click="getAuthorizedQrCode">
<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>
</div> </div>
</div> </div>
<span class="mt-16px"> 请使用抖音扫码将公司账号绑定至灵机平台 </span> <span> 请使用抖音扫码将公司账号绑定至灵机平台 </span>
</template> </template>
</template> </template>
</div> </div>
@ -62,8 +62,10 @@ import icon1 from '@/assets/img/media-account/icon-warn.png';
import icon2 from '@/assets/img/media-account/icon-feedback-success.png'; 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';
const OVERDUE_TIME = 30000; // 失效时间
const visible = ref(false); const visible = ref(false);
const isOverdue = ref(false); const isOverdue = ref(false); // 二维码失效
const isLoading = ref(false); const isLoading = ref(false);
const isCompleted = ref(false); const isCompleted = ref(false);
const isSuccess = ref(false); const isSuccess = ref(false);
@ -73,6 +75,7 @@ const id = ref('');
const imgUrl = ref(''); const imgUrl = ref('');
let progressTimer = null; let progressTimer = null;
let overdueTimer = null;
const notCompleted = computed(() => { const notCompleted = computed(() => {
return !isCompleted.value; return !isCompleted.value;
@ -84,7 +87,7 @@ const confirmBtnText = computed(() => {
const open = (accountId) => { const open = (accountId) => {
id.value = accountId; id.value = accountId;
handleAuthorizedImage(); getAuthorizedQrCode();
visible.value = true; visible.value = true;
}; };
const close = () => { const close = () => {
@ -95,14 +98,21 @@ const close = () => {
failReason.value = ''; failReason.value = '';
progress.value = 0; progress.value = 0;
id.value = ''; id.value = '';
clearFakeProgressTimer();
clearOverdueTimer();
visible.value = false; visible.value = false;
}; };
const handleAuthorizedImage = async () => { const getAuthorizedQrCode = async () => {
const { code, data } = await getAuthorizedImage(id.value); const { code, data } = await getAuthorizedImage(id.value);
if (code === 200) { if (code === 200) {
imgUrl.value = data.url; imgUrl.value = data.url;
overdueTimer = null;
// 约定后端限制40s内必须扫码前端定30s后失效
overdueTimer = setTimeout(() => {
isOverdue.value = true;
}, OVERDUE_TIME);
} }
}; };
const startLoading = async () => { const startLoading = async () => {
@ -136,18 +146,27 @@ const clearFakeProgressTimer = () => {
progressTimer = null; progressTimer = null;
} }
}; };
const clearOverdueTimer = () => {
if (overdueTimer) {
clearTimeout(overdueTimer);
overdueTimer = null;
}
};
const handleOk = () => { const handleOk = () => {
if (notCompleted.value) { if (notCompleted.value) {
clearOverdueTimer();
if (isOverdue.value) {
AMessage.error('二维码已失效,请重新扫码');
return;
}
startLoading(); startLoading();
return; return;
} }
}; };
onUnmounted(() => {
clearFakeProgressTimer();
});
defineExpose({ defineExpose({
open, open,
}); });

View File

@ -9,11 +9,40 @@
title="重新授权" title="重新授权"
modal-class="reauthorize-account-modal" modal-class="reauthorize-account-modal"
:mask-closable="false" :mask-closable="false"
:footer="!isLoading" :footer="taskStep !== TASK_STEP.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="taskStep === TASK_STEP.default">
<template v-if="hasUnsyncData">
<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">
<img :src="imgUrl" width="160" height="160" class="mb-16px" />
<div v-if="isOverdue" class="mask" @click="getAuthorizedQrCode">
<icon-refresh size="24" class="mb-13px" />
<p class="s1">二维码失效</p>
<p class="s1">请点击刷新</p>
</div>
</div>
<span> 请使用抖音扫码将公司账号绑定至灵机平台 </span>
</template>
</template>
<template v-else-if="taskStep === TASK_STEP.loading">
<a-progress <a-progress
:percent="progress" :percent="progress"
color="#6D4CFE" color="#6D4CFE"
@ -24,57 +53,32 @@
/> />
<p class="s2 mt-16px">数据同步和初始化中请勿关闭窗口</p> <p class="s2 mt-16px">数据同步和初始化中请勿关闭窗口</p>
</template> </template>
<template v-else-if="loadingStep === 1">
<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-if="loadingStep === 2">
<div class="flex items-center mb-20px">
<img :src="icon4" width="16" height="16" class="mr-16px" />
<span class="s2 color-#3C4043">当前绑定的账号与之前的昵称不一致请确认是否覆盖原账号信息</span>
</div>
<div class="w-100% pl-32px">
<div class="account-tip-box">
<p class="mb-4px s2"><span class="color-#3C4043">原账号</span>全球旅行小助手</p>
<p class="s2"><span class="color-#3C4043">当前账号</span>环球旅行官</p>
</div>
</div>
</template>
<template v-else> <template v-else>
<template v-if="isCompleted"> <template v-if="isNicknameChanged">
<div class="flex items-center mb-20px">
<img :src="icon4" width="16" height="16" class="mr-16px" />
<span class="s2 color-#3C4043">当前绑定的账号与之前的昵称不一致请确认是否覆盖原账号信息</span>
</div>
<div class="w-100% pl-32px">
<div class="account-tip-box">
<p class="mb-4px s2"><span class="color-#3C4043">原账号</span>全球旅行小助手</p>
<p class="s2"><span class="color-#3C4043">当前账号</span>环球旅行官</p>
</div>
</div>
</template>
<template v-else>
<img :src="isSuccess ? icon2 : icon3" width="80" height="80" class="mb-16px" /> <img :src="isSuccess ? icon2 : icon3" width="80" height="80" class="mb-16px" />
<p class="s2">{{ `数据初始化${isSuccess ? '成功' : '失败'}` }}</p> <p class="s2">{{ `数据初始化${isSuccess ? '成功' : '失败'}` }}</p>
<p v-if="!isSuccess" class="red-text">失败原因{{ failReason || '-' }}</p> <p v-if="!isSuccess" class="red-text">失败原因{{ failReason || '-' }}</p>
</template> </template>
<template v-else>
<div class="flex items-center mb-16px">
<img :src="icon1" width="16" height="16" />
<span class="ml-8px red-text">未识别到有效二维码</span>
</div>
<div class="img-box">
<img :src="imgUrl" width="160" height="160" class="mb-16px" />
<div v-if="isOverdue" class="mask">
<icon-refresh size="24" class="mb-13px" />
<p class="s1">二维码失效</p>
<p class="s1">请点击刷新</p>
</div>
</div>
<span class="mt-16px"> 请使用抖音扫码将公司账号绑定至灵机平台 </span>
</template>
</template> </template>
</div> </div>
<template #footer> <template #footer>
<a-button v-if="isCompleted || [1, 3].includes(actionType)" size="large" class="cancel-btn" @click="close" <a-button
v-if="(taskStep === TASK_STEP.default && hasUnsyncData) || taskStep === TASK_STEP.end"
size="large"
class="cancel-btn"
@click="close"
>取消</a-button >取消</a-button
> >
<a-button type="primary" size="large" @click="handleOk">{{ confirmBtnText }} </a-button> <a-button type="primary" size="large" @click="handleOk">{{ confirmBtnText }} </a-button>
@ -91,64 +95,81 @@ 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-1.png'; import icon4 from '@/assets/img/media-account/icon-warn-1.png';
const OVERDUE_TIME = 30000; // 失效时间
const TASK_STEP = {
default: 1,
loading: 2,
end: 3,
};
const visible = ref(false); const visible = ref(false);
const isOverdue = ref(false); const isOverdue = ref(false); // 二维码失效
const isLoading = ref(false);
const isCompleted = ref(false);
const isSuccess = 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 imgUrl = ref(''); const imgUrl = ref('');
const loadingStep = ref(0); // 1 | 2
const taskStep = ref(TASK_STEP.default);
const hasUnsyncData = ref(false); // 含有未同步数据
const isNicknameChanged = ref(false); // 昵称发生变化
const actionType = ref(1); const actionType = ref(1);
let progressTimer = null; let progressTimer = null;
let overdueTimer = null;
const notCompleted = computed(() => {
return !isCompleted.value;
});
const confirmBtnText = computed(() => { const confirmBtnText = computed(() => {
if (loadingStep.value === 1) return '确定'; if (taskStep.value === TASK_STEP.default) {
if (loadingStep.value === 2) return '确定覆盖'; return hasUnsyncData.value ? '确定' : '完成扫码';
}
if (notCompleted.value) return '完成扫码'; if (taskStep.value === TASK_STEP.end) {
if (isNicknameChanged.value) return '确定覆盖';
return isSuccess.value ? '继续添加' : '重新扫码';
}
return isSuccess.value ? '继续添加' : '重新扫码'; return '';
}); });
const open = (accountId) => { const open = (accountId) => {
id.value = accountId; id.value = accountId;
handleAuthorizedImage(); getAuthorizedQrCode();
visible.value = true; visible.value = true;
}; };
const close = () => { const close = () => {
isOverdue.value = false; isOverdue.value = false;
isLoading.value = false;
isCompleted.value = false;
isSuccess.value = false; isSuccess.value = false;
failReason.value = ''; failReason.value = '';
progress.value = 0; progress.value = 0;
loadingStep.value = 0; taskStep.value = TASK_STEP.default;
actionType.value = 1; actionType.value = 1;
hasUnsyncData.value = false;
isNicknameChanged.value = false;
id.value = ''; id.value = '';
clearFakeProgressTimer();
clearOverdueTimer();
visible.value = false; visible.value = false;
}; };
const handleAuthorizedImage = async () => { const getAuthorizedQrCode = async () => {
const { code, data } = await getAuthorizedImage(id.value); const { code, data } = await getAuthorizedImage(id.value);
if (code === 200) { if (code === 200) {
imgUrl.value = data.url; imgUrl.value = data.url;
overdueTimer = null;
// 约定后端限制40s内必须扫码前端定30s后失效
overdueTimer = setTimeout(() => {
isOverdue.value = true;
}, OVERDUE_TIME);
} }
}; };
const startLoading = async () => { const startLoading = async () => {
isLoading.value = true; taskStep.value = TASK_STEP.loading;
progress.value = 0; progress.value = 0;
startFakeProgressPolling(); startFakeProgressPolling();
// const { code } = await startPatchAccount(id.value); // const { code } = await startPatchAccount(id.value);
// if (code === 200) { // if (code === 200) {
// isLoading.value = true; // taskStep.value = TASK_STEP.loading;
// progress.value = 0; // progress.value = 0;
// startFakeProgressPolling(); // startFakeProgressPolling();
// } // }
@ -162,7 +183,7 @@ const startFakeProgressPolling = () => {
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 { } else {
loadingStep.value = 2; taskStep.value = TASK_STEP.end;
clearFakeProgressTimer(); clearFakeProgressTimer();
} }
}, 1000); }, 1000);
@ -174,23 +195,50 @@ const clearFakeProgressTimer = () => {
progressTimer = null; progressTimer = null;
} }
}; };
const clearOverdueTimer = () => {
if (overdueTimer) {
clearTimeout(overdueTimer);
overdueTimer = null;
}
};
const getSyncDataStatus = () => {
return hasUnsyncData.value;
};
const handleOk = () => { const handleOk = () => {
if (loadingStep.value === 1) { if (taskStep.value === TASK_STEP.default) {
clearOverdueTimer();
if (isOverdue.value) {
AMessage.error('二维码已失效,请重新扫码');
return;
}
const _hasUnsyncData = getSyncDataStatus();
if (!_hasUnsyncData) {
hasUnsyncData.value = true;
return;
}
startLoading(); startLoading();
return; return;
} }
if (notCompleted.value) { if (taskStep.value === TASK_STEP.end) {
loadingStep.value = 1; if (isNicknameChanged.value) {
return; isNicknameChanged.value = false;
console.log('确定覆盖');
} else {
if (isSuccess.value) {
console.log('继续添加');
} else {
console.log('重新扫码');
}
}
} }
}; };
onUnmounted(() => {
clearFakeProgressTimer();
});
defineExpose({ defineExpose({
open, open,
}); });