重构:提取useAdminAction/useAdminListQuerySync + 迁移列表视图到useAdminListPage + 修复formatAutoDeliveryReason缺失case + 消除重复格式化函数 + 修复CSS类冲突
This commit is contained in:
@@ -147,12 +147,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- 数据表 (用于 el-table,具体单元格样式见各页面 :deep() 规则) ---------- */
|
/* ---------- 数据表 (用于 el-table,具体单元格样式见各页面 :deep() 规则) ---------- */
|
||||||
.data-table {
|
.data-table--config {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell-stack {
|
.cell-stack--config {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
@@ -233,4 +233,6 @@
|
|||||||
margin: 10px 0 0;
|
margin: 10px 0 0;
|
||||||
font-size: var(--text-xs);
|
font-size: var(--text-xs);
|
||||||
}
|
}
|
||||||
.mt-4 { margin-top: 16px; }
|
.mt-4 {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -309,10 +309,18 @@ function resetFilters() {
|
|||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="cell-subline"
|
class="cell-subline"
|
||||||
:title="formatBindingRoleSummary(row.bindingSummary.roleKeys)"
|
:title="
|
||||||
|
formatBindingRoleSummary(
|
||||||
|
row.bindingSummary.roleKeys,
|
||||||
|
'无绑定角色'
|
||||||
|
)
|
||||||
|
"
|
||||||
>绑定
|
>绑定
|
||||||
{{
|
{{
|
||||||
formatBindingRoleSummary(row.bindingSummary.roleKeys)
|
formatBindingRoleSummary(
|
||||||
|
row.bindingSummary.roleKeys,
|
||||||
|
"无绑定角色"
|
||||||
|
)
|
||||||
}}</span
|
}}</span
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -320,7 +328,6 @@ function resetFilters() {
|
|||||||
:title="formatBindingCountSummary(row.bindingSummary)"
|
:title="formatBindingCountSummary(row.bindingSummary)"
|
||||||
>{{ formatBindingCountSummary(row.bindingSummary) }}</span
|
>{{ formatBindingCountSummary(row.bindingSummary) }}</span
|
||||||
>
|
>
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|||||||
+168
-162
@@ -1,325 +1,331 @@
|
|||||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
|
import { computed, onBeforeUnmount, onMounted, ref } from "vue";
|
||||||
import QRCode from 'qrcode'
|
import QRCode from "qrcode";
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from "element-plus";
|
||||||
|
|
||||||
import { showError, showSuccess } from '@/lib/feedback'
|
import { showError, showSuccess } from "@/lib/feedback";
|
||||||
|
import { formatAdminDateTime } from "@/utils/admin-time";
|
||||||
import {
|
import {
|
||||||
confirmKuaishouCloudClaimRole,
|
confirmKuaishouCloudClaimRole,
|
||||||
fetchClaimDetail,
|
fetchClaimDetail,
|
||||||
redeemKuaishouCloudClaim,
|
redeemKuaishouCloudClaim,
|
||||||
verifyKuaishouCloudClaimTicket,
|
verifyKuaishouCloudClaimTicket,
|
||||||
} from '@/services/claim'
|
} from "@/services/claim";
|
||||||
import type { ClaimDetailData } from '@/types/claim'
|
import type { ClaimDetailData } from "@/types/claim";
|
||||||
|
|
||||||
export function useKuaishouCloudClaim(token: () => string) {
|
export function useKuaishouCloudClaim(token: () => string) {
|
||||||
const loading = ref(true)
|
const loading = ref(true);
|
||||||
const submitting = ref(false)
|
const submitting = ref(false);
|
||||||
const refreshingRole = ref(false)
|
const refreshingRole = ref(false);
|
||||||
const confirmingRole = ref(false)
|
const confirmingRole = ref(false);
|
||||||
const redeeming = ref(false)
|
const redeeming = ref(false);
|
||||||
const errorMessage = ref('')
|
const errorMessage = ref("");
|
||||||
const detail = ref<ClaimDetailData | null>(null)
|
const detail = ref<ClaimDetailData | null>(null);
|
||||||
const ticketCode = ref('')
|
const ticketCode = ref("");
|
||||||
const qrCodeDataUrl = ref('')
|
const qrCodeDataUrl = ref("");
|
||||||
let pollTimer = 0
|
let pollTimer = 0;
|
||||||
|
|
||||||
// ── derived data ────────────────────────────────────────
|
// ── derived data ────────────────────────────────────────
|
||||||
|
|
||||||
const flow = computed(() => detail.value?.kuaishouCloudFulfillment || null)
|
const flow = computed(() => detail.value?.kuaishouCloudFulfillment || null);
|
||||||
const order = computed(() => detail.value?.order || null)
|
const order = computed(() => detail.value?.order || null);
|
||||||
const orderItem = computed(() => detail.value?.orderItem || null)
|
const orderItem = computed(() => detail.value?.orderItem || null);
|
||||||
const task = computed(() => detail.value?.task || null)
|
const task = computed(() => detail.value?.task || null);
|
||||||
|
|
||||||
// ── computed status flags ───────────────────────────────
|
// ── computed status flags ───────────────────────────────
|
||||||
|
|
||||||
const roleName = computed(() => flow.value?.role.name || flow.value?.binding.roleName || '')
|
const roleName = computed(
|
||||||
const roleId = computed(() => flow.value?.role.rid || flow.value?.binding.roleId || '')
|
() => flow.value?.role.name || flow.value?.binding.roleName || ""
|
||||||
const isTicketVerified = computed(() => flow.value?.ticket.status === 'verified')
|
);
|
||||||
|
const roleId = computed(
|
||||||
|
() => flow.value?.role.rid || flow.value?.binding.roleId || ""
|
||||||
|
);
|
||||||
|
const isTicketVerified = computed(
|
||||||
|
() => flow.value?.ticket.status === "verified"
|
||||||
|
);
|
||||||
|
|
||||||
const isBindUrlExpired = computed(() => {
|
const isBindUrlExpired = computed(() => {
|
||||||
const expiresAt = String(flow.value?.binding.bindExpiresAt || '').trim()
|
const expiresAt = String(flow.value?.binding.bindExpiresAt || "").trim();
|
||||||
if (!expiresAt) {
|
if (!expiresAt) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
const expiresTime = Date.parse(expiresAt)
|
const expiresTime = Date.parse(expiresAt);
|
||||||
return Number.isFinite(expiresTime) && expiresTime <= Date.now()
|
return Number.isFinite(expiresTime) && expiresTime <= Date.now();
|
||||||
})
|
});
|
||||||
|
|
||||||
const isBindingPrepared = computed(
|
const isBindingPrepared = computed(
|
||||||
() =>
|
() =>
|
||||||
flow.value?.binding.prepareStatus === 'ready' &&
|
flow.value?.binding.prepareStatus === "ready" &&
|
||||||
Boolean(String(flow.value?.binding.bindUrl || '').trim()) &&
|
Boolean(String(flow.value?.binding.bindUrl || "").trim()) &&
|
||||||
!isBindUrlExpired.value,
|
!isBindUrlExpired.value
|
||||||
)
|
);
|
||||||
|
|
||||||
const isBindingPreparing = computed(() => flow.value?.binding.prepareStatus === 'pending')
|
const isBindingPreparing = computed(
|
||||||
const canEnterBindingStep = computed(() => isTicketVerified.value)
|
() => flow.value?.binding.prepareStatus === "pending"
|
||||||
const isRoleReady = computed(() => Boolean(roleName.value || roleId.value))
|
);
|
||||||
const isRoleConfirmed = computed(() => String(task.value?.status || '').trim() === 'role_confirmed')
|
const canEnterBindingStep = computed(() => isTicketVerified.value);
|
||||||
const isDispatched = computed(() => String(flow.value?.dispatch.status || '').trim() === 'success')
|
const isRoleReady = computed(() => Boolean(roleName.value || roleId.value));
|
||||||
|
const isRoleConfirmed = computed(
|
||||||
|
() => String(task.value?.status || "").trim() === "role_confirmed"
|
||||||
|
);
|
||||||
|
const isDispatched = computed(
|
||||||
|
() => String(flow.value?.dispatch.status || "").trim() === "success"
|
||||||
|
);
|
||||||
|
|
||||||
const isCompleted = computed(
|
const isCompleted = computed(
|
||||||
() =>
|
() =>
|
||||||
String(task.value?.status || '').trim() === 'completed' ||
|
String(task.value?.status || "").trim() === "completed" ||
|
||||||
String(flow.value?.consume.status || '').trim() === 'success',
|
String(flow.value?.consume.status || "").trim() === "success"
|
||||||
)
|
);
|
||||||
|
|
||||||
const hasRedeemResult = computed(() => {
|
const hasRedeemResult = computed(() => {
|
||||||
const status = String(task.value?.status || '').trim()
|
const status = String(task.value?.status || "").trim();
|
||||||
return (
|
return (
|
||||||
isDispatched.value ||
|
isDispatched.value ||
|
||||||
['dispatched_pending_return', 'completed', 'manual_review', 'failed'].includes(status)
|
[
|
||||||
)
|
"dispatched_pending_return",
|
||||||
})
|
"completed",
|
||||||
|
"manual_review",
|
||||||
|
"failed",
|
||||||
|
].includes(status)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const canSubmitTicket = computed(
|
const canSubmitTicket = computed(
|
||||||
() =>
|
() =>
|
||||||
!['completed', 'manual_review', 'closed', 'expired'].includes(
|
!["completed", "manual_review", "closed", "expired"].includes(
|
||||||
String(task.value?.status || '').trim(),
|
String(task.value?.status || "").trim()
|
||||||
) && !submitting.value,
|
) && !submitting.value
|
||||||
)
|
);
|
||||||
|
|
||||||
const currentStep = computed(() => {
|
const currentStep = computed(() => {
|
||||||
if (hasRedeemResult.value) {
|
if (hasRedeemResult.value) {
|
||||||
return 4
|
return 4;
|
||||||
}
|
}
|
||||||
if (isRoleConfirmed.value) {
|
if (isRoleConfirmed.value) {
|
||||||
return 3
|
return 3;
|
||||||
}
|
}
|
||||||
if (canEnterBindingStep.value) {
|
if (canEnterBindingStep.value) {
|
||||||
return 2
|
return 2;
|
||||||
}
|
}
|
||||||
return 1
|
return 1;
|
||||||
})
|
});
|
||||||
|
|
||||||
const progressText = computed(() => {
|
const progressText = computed(() => {
|
||||||
if (hasRedeemResult.value) {
|
if (hasRedeemResult.value) {
|
||||||
return '兑换结果已生成'
|
return "兑换结果已生成";
|
||||||
}
|
}
|
||||||
if (isRoleConfirmed.value) {
|
if (isRoleConfirmed.value) {
|
||||||
return '角色已确认,等待兑换'
|
return "角色已确认,等待兑换";
|
||||||
}
|
}
|
||||||
if (isTicketVerified.value) {
|
if (isTicketVerified.value) {
|
||||||
return isBindingPrepared.value ? '请完成扫码绑定' : '绑定链接刷新中,请稍候'
|
return isBindingPrepared.value
|
||||||
|
? "请完成扫码绑定"
|
||||||
|
: "绑定链接刷新中,请稍候";
|
||||||
}
|
}
|
||||||
return '等待提交核销码'
|
return "等待提交核销码";
|
||||||
})
|
});
|
||||||
|
|
||||||
const resultTitle = computed(() => {
|
const resultTitle = computed(() => {
|
||||||
if (isCompleted.value) {
|
if (isCompleted.value) {
|
||||||
return '兑换成功'
|
return "兑换成功";
|
||||||
}
|
}
|
||||||
if (isDispatched.value) {
|
if (isDispatched.value) {
|
||||||
return '兑换请求已提交'
|
return "兑换请求已提交";
|
||||||
}
|
}
|
||||||
return '结果已记录'
|
return "结果已记录";
|
||||||
})
|
});
|
||||||
|
|
||||||
const resultDescription = computed(() => {
|
const resultDescription = computed(() => {
|
||||||
if (isCompleted.value) {
|
if (isCompleted.value) {
|
||||||
return '当前兑换流程已经完成。发货、退号和核销结果会保存在后台任务界面。'
|
return "当前兑换流程已经完成。发货、退号和核销结果会保存在后台任务界面。";
|
||||||
}
|
}
|
||||||
return '你的兑换请求已经提交。发货、退号和核销结果会由系统保存在后台任务界面,无需在此页面等待。'
|
return "你的兑换请求已经提交。发货、退号和核销结果会由系统保存在后台任务界面,无需在此页面等待。";
|
||||||
})
|
});
|
||||||
|
|
||||||
// ── actions ─────────────────────────────────────────────
|
// ── actions ─────────────────────────────────────────────
|
||||||
|
|
||||||
async function generateQRCode(url: string) {
|
async function generateQRCode(url: string) {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
qrCodeDataUrl.value = ''
|
qrCodeDataUrl.value = "";
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
qrCodeDataUrl.value = await QRCode.toDataURL(url, {
|
qrCodeDataUrl.value = await QRCode.toDataURL(url, {
|
||||||
width: 280,
|
width: 280,
|
||||||
margin: 2,
|
margin: 2,
|
||||||
color: {
|
color: {
|
||||||
dark: '#0f172a',
|
dark: "#0f172a",
|
||||||
light: '#ffffff',
|
light: "#ffffff",
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
qrCodeDataUrl.value = ''
|
qrCodeDataUrl.value = "";
|
||||||
console.error('生成二维码失败:', error)
|
console.error("生成二维码失败:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function applyDetail(nextDetail: ClaimDetailData) {
|
async function applyDetail(nextDetail: ClaimDetailData) {
|
||||||
detail.value = nextDetail
|
detail.value = nextDetail;
|
||||||
if (!ticketCode.value && nextDetail.kuaishouCloudFulfillment?.ticket.code) {
|
if (!ticketCode.value && nextDetail.kuaishouCloudFulfillment?.ticket.code) {
|
||||||
ticketCode.value = nextDetail.kuaishouCloudFulfillment.ticket.code
|
ticketCode.value = nextDetail.kuaishouCloudFulfillment.ticket.code;
|
||||||
}
|
}
|
||||||
await generateQRCode(String(nextDetail.kuaishouCloudFulfillment?.binding.bindUrl || '').trim())
|
await generateQRCode(
|
||||||
|
String(nextDetail.kuaishouCloudFulfillment?.binding.bindUrl || "").trim()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadDetail(options: { silent?: boolean } = {}) {
|
async function loadDetail(options: { silent?: boolean } = {}) {
|
||||||
if (!options.silent) {
|
if (!options.silent) {
|
||||||
loading.value = true
|
loading.value = true;
|
||||||
}
|
}
|
||||||
errorMessage.value = ''
|
errorMessage.value = "";
|
||||||
try {
|
try {
|
||||||
const response = await fetchClaimDetail(token())
|
const response = await fetchClaimDetail(token());
|
||||||
await applyDetail(response.data)
|
await applyDetail(response.data);
|
||||||
syncPolling()
|
syncPolling();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
errorMessage.value = error instanceof Error ? error.message : '读取领取信息失败'
|
errorMessage.value =
|
||||||
stopPolling()
|
error instanceof Error ? error.message : "读取领取信息失败";
|
||||||
|
stopPolling();
|
||||||
} finally {
|
} finally {
|
||||||
if (!options.silent) {
|
if (!options.silent) {
|
||||||
loading.value = false
|
loading.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitTicket() {
|
async function submitTicket() {
|
||||||
const normalizedTicketCode = ticketCode.value.trim()
|
const normalizedTicketCode = ticketCode.value.trim();
|
||||||
if (!normalizedTicketCode) {
|
if (!normalizedTicketCode) {
|
||||||
showError('请输入核销码')
|
showError("请输入核销码");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
submitting.value = true
|
submitting.value = true;
|
||||||
try {
|
try {
|
||||||
const response = await verifyKuaishouCloudClaimTicket(token(), {
|
const response = await verifyKuaishouCloudClaimTicket(token(), {
|
||||||
ticketCode: normalizedTicketCode,
|
ticketCode: normalizedTicketCode,
|
||||||
})
|
});
|
||||||
await applyDetail(response.data)
|
await applyDetail(response.data);
|
||||||
showSuccess('核销码验证通过,系统已开始准备绑定资源')
|
showSuccess("核销码验证通过,系统已开始准备绑定资源");
|
||||||
syncPolling()
|
syncPolling();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError(error instanceof Error ? error.message : '核销码验证失败')
|
showError(error instanceof Error ? error.message : "核销码验证失败");
|
||||||
} finally {
|
} finally {
|
||||||
submitting.value = false
|
submitting.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refreshRole() {
|
async function refreshRole() {
|
||||||
refreshingRole.value = true
|
refreshingRole.value = true;
|
||||||
try {
|
try {
|
||||||
await loadDetail({ silent: true })
|
await loadDetail({ silent: true });
|
||||||
if (isRoleReady.value) {
|
if (isRoleReady.value) {
|
||||||
showSuccess('角色信息已刷新')
|
showSuccess("角色信息已刷新");
|
||||||
} else {
|
} else {
|
||||||
showError(
|
showError(
|
||||||
flow.value?.role.errorMessage || '暂时还没有识别到角色信息,请完成绑定后稍等片刻再试',
|
flow.value?.role.errorMessage ||
|
||||||
)
|
"暂时还没有识别到角色信息,请完成绑定后稍等片刻再试"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
refreshingRole.value = false
|
refreshingRole.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function confirmRole() {
|
async function confirmRole() {
|
||||||
confirmingRole.value = true
|
confirmingRole.value = true;
|
||||||
try {
|
try {
|
||||||
const response = await confirmKuaishouCloudClaimRole(token())
|
const response = await confirmKuaishouCloudClaimRole(token());
|
||||||
await applyDetail(response.data)
|
await applyDetail(response.data);
|
||||||
showSuccess('角色已确认,进入下一步')
|
showSuccess("角色已确认,进入下一步");
|
||||||
syncPolling()
|
syncPolling();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError(error instanceof Error ? error.message : '确认角色失败')
|
showError(error instanceof Error ? error.message : "确认角色失败");
|
||||||
} finally {
|
} finally {
|
||||||
confirmingRole.value = false
|
confirmingRole.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function confirmRedeem() {
|
async function confirmRedeem() {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm(
|
await ElMessageBox.confirm(
|
||||||
'兑换后不可取消,也不可退货。请确认角色和商品信息完全正确。',
|
"兑换后不可取消,也不可退货。请确认角色和商品信息完全正确。",
|
||||||
'确认兑换',
|
"确认兑换",
|
||||||
{
|
{
|
||||||
confirmButtonText: '确认兑换',
|
confirmButtonText: "确认兑换",
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: "取消",
|
||||||
type: 'warning',
|
type: "warning",
|
||||||
center: true,
|
center: true,
|
||||||
},
|
}
|
||||||
)
|
);
|
||||||
} catch {
|
} catch {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
redeeming.value = true
|
redeeming.value = true;
|
||||||
try {
|
try {
|
||||||
const response = await redeemKuaishouCloudClaim(token())
|
const response = await redeemKuaishouCloudClaim(token());
|
||||||
await applyDetail(response.data)
|
await applyDetail(response.data);
|
||||||
showSuccess('兑换请求已提交')
|
showSuccess("兑换请求已提交");
|
||||||
syncPolling()
|
syncPolling();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError(error instanceof Error ? error.message : '兑换失败')
|
showError(error instanceof Error ? error.message : "兑换失败");
|
||||||
} finally {
|
} finally {
|
||||||
redeeming.value = false
|
redeeming.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openBindUrl(useCurrentPage = false) {
|
function openBindUrl(useCurrentPage = false) {
|
||||||
const bindUrl = String(flow.value?.binding.bindUrl || '').trim()
|
const bindUrl = String(flow.value?.binding.bindUrl || "").trim();
|
||||||
if (!bindUrl) {
|
if (!bindUrl) {
|
||||||
showError('绑定链接还没准备好,请稍后刷新')
|
showError("绑定链接还没准备好,请稍后刷新");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (useCurrentPage) {
|
if (useCurrentPage) {
|
||||||
window.location.assign(bindUrl)
|
window.location.assign(bindUrl);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
window.open(bindUrl, '_blank', 'noopener,noreferrer')
|
window.open(bindUrl, "_blank", "noopener,noreferrer");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── polling ─────────────────────────────────────────────
|
// ── polling ─────────────────────────────────────────────
|
||||||
|
|
||||||
function stopPolling() {
|
function stopPolling() {
|
||||||
if (pollTimer) {
|
if (pollTimer) {
|
||||||
window.clearInterval(pollTimer)
|
window.clearInterval(pollTimer);
|
||||||
pollTimer = 0
|
pollTimer = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncPolling() {
|
function syncPolling() {
|
||||||
const taskStatus = String(task.value?.status || '').trim()
|
const taskStatus = String(task.value?.status || "").trim();
|
||||||
const shouldPoll =
|
const shouldPoll =
|
||||||
Boolean(flow.value) && !hasRedeemResult.value && !['closed', 'expired'].includes(taskStatus)
|
Boolean(flow.value) &&
|
||||||
|
!hasRedeemResult.value &&
|
||||||
|
!["closed", "expired"].includes(taskStatus);
|
||||||
|
|
||||||
if (!shouldPoll) {
|
if (!shouldPoll) {
|
||||||
stopPolling()
|
stopPolling();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (pollTimer) {
|
if (pollTimer) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
pollTimer = window.setInterval(() => {
|
pollTimer = window.setInterval(() => {
|
||||||
void loadDetail({ silent: true })
|
void loadDetail({ silent: true });
|
||||||
}, 4000)
|
}, 4000);
|
||||||
}
|
|
||||||
|
|
||||||
// ── utility ─────────────────────────────────────────────
|
|
||||||
|
|
||||||
function formatDateTime(value: string | null) {
|
|
||||||
if (!value) {
|
|
||||||
return '-'
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return new Date(value).toLocaleString('zh-CN', {
|
|
||||||
year: 'numeric',
|
|
||||||
month: '2-digit',
|
|
||||||
day: '2-digit',
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit',
|
|
||||||
second: '2-digit',
|
|
||||||
})
|
|
||||||
} catch {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── lifecycle ───────────────────────────────────────────
|
// ── lifecycle ───────────────────────────────────────────
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
void loadDetail()
|
void loadDetail();
|
||||||
})
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
stopPolling()
|
stopPolling();
|
||||||
})
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// state
|
// state
|
||||||
@@ -363,6 +369,6 @@ export function useKuaishouCloudClaim(token: () => string) {
|
|||||||
confirmRedeem,
|
confirmRedeem,
|
||||||
openBindUrl,
|
openBindUrl,
|
||||||
// utility
|
// utility
|
||||||
formatDateTime,
|
formatAdminDateTime,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user