diff --git a/apps/frontend/src/views/admin/manual-redeem/AdminManualRedeemView.vue b/apps/frontend/src/views/admin/manual-redeem/AdminManualRedeemView.vue index 6201c722..389d115e 100644 --- a/apps/frontend/src/views/admin/manual-redeem/AdminManualRedeemView.vue +++ b/apps/frontend/src/views/admin/manual-redeem/AdminManualRedeemView.vue @@ -5,6 +5,9 @@ import TencentAuthCard from '@/components/tencent/TencentAuthCard.vue' import TencentRedeemPanel from '@/components/tencent/TencentRedeemPanel.vue' import TencentResultPanel from '@/components/tencent/TencentResultPanel.vue' import { useAdminManualRedeemPage } from '@/composables/useAdminManualRedeemPage' +import AdminManualRedeemCreateCard from './components/AdminManualRedeemCreateCard.vue' +import AdminManualRedeemSummaryCard from './components/AdminManualRedeemSummaryCard.vue' +import AdminManualRedeemReviewCard from './components/AdminManualRedeemReviewCard.vue' const { form, @@ -104,82 +107,21 @@ const taskDetailLink = computed(() => -
-
-
-

1. 创建人工兑换任务

-

先录入唯一凭据并锁定库存,后续二维码、角色确认和兑换都基于这条任务继续。

-
-
+ -
-
- 唯一凭据 - -
- -
- 内部履约 SKU - - - -
- -
- 备注 - -
-
- -
- - 创建任务并预占库存 - -
-
- -
-
- 唯一凭据 - {{ manualRequest?.proofValue || order?.platformOrderId || '-' }} -
-
- 任务号 - {{ task?.taskNo || '-' }} -
-
- 商品 - {{ orderItem?.skuName || '-' }} -
-
- 当前状态 - {{ statusLabel }} -
-
+
人工兑换详情加载中
@@ -237,43 +179,18 @@ const taskDetailLink = computed(() => -
-
-
-

2. {{ reviewCardTitle }}

-

- 客户登录后,系统会把当前角色截图回传到这里。客服复制后可直接发给客户做二次确认。 -

-

最终兑换完成后,客服可以把结果截图直接发给客户确认。

-

- {{ screenshotEmptyMessage }} -

-
-
- - 复制图片 - - - 下载图片 - -
-
- -
- -
- -
- {{ screenshotEmptyTitle }} -

{{ screenshotEmptyMessage }}

-
-
+ gap: 18px; } -.header-actions, -.card-head { - display: flex; - align-items: center; - justify-content: space-between; - gap: var(--space-4); -} - -.header-actions { - flex-wrap: wrap; -} - .task-link { color: var(--color-primary); text-decoration: none; font-weight: 600; } -.create-card, -.summary-card, -.review-card { - padding: 22px var(--space-6); - border-radius: var(--radius-xl); - background: var(--bg-surface); - border: 1px solid var(--border-default); - box-shadow: var(--shadow-lg); -} - -.card-head h2 { - margin: 0; - font-size: var(--text-lg); - color: var(--text-primary); -} - -.card-head p { - margin: 6px 0 0; - color: var(--text-secondary); - line-height: 1.7; -} - -.form-grid { - margin-top: 18px; - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: var(--space-4); -} - -.field { - display: grid; - gap: var(--space-2); -} - -.field span { - color: var(--text-secondary); - font-size: var(--text-sm); - font-weight: 600; -} - -.field-remark { - grid-column: 1 / -1; -} - -.action-row { - margin-top: 18px; - display: flex; - gap: var(--space-3); -} - -.summary-card { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: var(--space-3); -} - -.summary-card article { - padding: 14px; - border-radius: var(--radius-md); - background: var(--bg-page); -} - -.summary-card span { - display: block; - font-size: var(--text-xs); - color: var(--text-muted); -} - -.summary-card strong { - display: block; - margin-top: var(--space-2); - color: var(--text-primary); - word-break: break-word; -} - .layout-grid { display: grid; grid-template-columns: minmax(340px, 392px) minmax(0, 1fr); @@ -426,30 +256,6 @@ const taskDetailLink = computed(() => display: grid; } -.review-stage { - margin-top: 18px; - border-radius: var(--radius-lg); - overflow: hidden; - border: 1px solid var(--border-default); - background: var(--bg-page); -} - -.screenshot-button { - display: block; - width: 100%; - padding: 0; - border: 0; - background: transparent; - cursor: zoom-in; -} - -.screenshot-button img, -.preview-image { - display: block; - width: 100%; - height: auto; -} - .empty-block { min-height: 180px; padding: var(--space-6); @@ -472,10 +278,15 @@ const taskDetailLink = computed(() => line-height: 1.7; } +.preview-image { + display: block; + width: 100%; + height: auto; +} + @media (max-width: 900px) { .summary-card, - .layout-grid, - .form-grid { + .layout-grid { grid-template-columns: 1fr; } } diff --git a/apps/frontend/src/views/admin/manual-redeem/components/AdminManualRedeemCreateCard.vue b/apps/frontend/src/views/admin/manual-redeem/components/AdminManualRedeemCreateCard.vue new file mode 100644 index 00000000..ac3e9a2f --- /dev/null +++ b/apps/frontend/src/views/admin/manual-redeem/components/AdminManualRedeemCreateCard.vue @@ -0,0 +1,138 @@ + + + + + diff --git a/apps/frontend/src/views/admin/manual-redeem/components/AdminManualRedeemReviewCard.vue b/apps/frontend/src/views/admin/manual-redeem/components/AdminManualRedeemReviewCard.vue new file mode 100644 index 00000000..20ba2dfe --- /dev/null +++ b/apps/frontend/src/views/admin/manual-redeem/components/AdminManualRedeemReviewCard.vue @@ -0,0 +1,133 @@ + + + + + diff --git a/apps/frontend/src/views/admin/manual-redeem/components/AdminManualRedeemSummaryCard.vue b/apps/frontend/src/views/admin/manual-redeem/components/AdminManualRedeemSummaryCard.vue new file mode 100644 index 00000000..5f2e11ca --- /dev/null +++ b/apps/frontend/src/views/admin/manual-redeem/components/AdminManualRedeemSummaryCard.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/AdminPlatformShopsView.vue b/apps/frontend/src/views/admin/platform-shops/AdminPlatformShopsView.vue index e919b58e..7024fed9 100644 --- a/apps/frontend/src/views/admin/platform-shops/AdminPlatformShopsView.vue +++ b/apps/frontend/src/views/admin/platform-shops/AdminPlatformShopsView.vue @@ -12,10 +12,10 @@ import { } from '@/services/admin' import { hasAdminRole } from '@/utils/admin-auth' import AdminPlatformAgisoSection from './components/AdminPlatformAgisoSection.vue' -import AdminPlatformCloudtentaclesSection from './components/AdminPlatformCloudtentaclesSection.vue' +import AdminPlatformCloudtentaclesSection from './components/cloudtentacles/AdminPlatformCloudtentaclesSection.vue' import AdminPlatformNinetyoneSection from './components/AdminPlatformNinetyoneSection.vue' -import AdminPlatformNotificationSection from './components/AdminPlatformNotificationSection.vue' -import AdminPlatformKuaishouEticketSection from './components/AdminPlatformKuaishouEticketSection.vue' +import AdminPlatformNotificationSection from './components/notification/AdminPlatformNotificationSection.vue' +import AdminPlatformKuaishouEticketSection from './components/kuaishou-eticket/AdminPlatformKuaishouEticketSection.vue' import { useAdminAgisoPlatform } from './composables/useAdminAgisoPlatform' import { useAdminCloudtentaclesPlatform } from './composables/useAdminCloudtentaclesPlatform' import { useAdminNinetyonePlatform } from './composables/useAdminNinetyonePlatform' @@ -273,7 +273,9 @@ onMounted(loadConfigs) tag: 'Cookie / 券核销', value: kuaishouEticketStats.configuredShopCount, unit: '已配置店铺', - meta: `Cookie 就绪 ${kuaishouEticketStats.cookieReadyCount} 家 · 当前店铺 ${kuaishouEticketStats.selectedShopReady ? '可调试' : '待补全'}`, + meta: `Cookie 就绪 ${kuaishouEticketStats.cookieReadyCount} 家 · 当前店铺 ${ + kuaishouEticketStats.selectedShopReady ? '可调试' : '待补全' + }`, }, ...(isDevMode ? [ @@ -283,7 +285,9 @@ onMounted(loadConfigs) tag: '履约 / 登录', value: cloudtentaclesStats.hasCredential ? '已配置' : '未配置', unit: '履约凭据', - meta: `短信 ${cloudtentaclesStats.smsSent ? '已发送' : '未发送'} · 会话 ${cloudtentaclesStats.validated ? '已验证' : '未验证'}`, + meta: `短信 ${cloudtentaclesStats.smsSent ? '已发送' : '未发送'} · 会话 ${ + cloudtentaclesStats.validated ? '已验证' : '未验证' + }`, }, ] : []), @@ -455,9 +459,7 @@ onMounted(loadConfigs) } .overview-card { - transition: - border-color 0.2s ease, - box-shadow 0.2s ease; + transition: border-color 0.2s ease, box-shadow 0.2s ease; } .overview-card.is-active { diff --git a/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformCloudtentaclesSection.vue b/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformCloudtentaclesSection.vue deleted file mode 100644 index ff64296c..00000000 --- a/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformCloudtentaclesSection.vue +++ /dev/null @@ -1,455 +0,0 @@ - - - - - diff --git a/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformKuaishouEticketSection.vue b/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformKuaishouEticketSection.vue deleted file mode 100644 index 4c02f218..00000000 --- a/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformKuaishouEticketSection.vue +++ /dev/null @@ -1,654 +0,0 @@ - - - - - diff --git a/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformNotificationSection.vue b/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformNotificationSection.vue deleted file mode 100644 index 244235c9..00000000 --- a/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformNotificationSection.vue +++ /dev/null @@ -1,548 +0,0 @@ - - - - - diff --git a/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminCloudtentaclesConfigCard.vue b/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminCloudtentaclesConfigCard.vue new file mode 100644 index 00000000..30377dd0 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminCloudtentaclesConfigCard.vue @@ -0,0 +1,250 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminCloudtentaclesDebugCard.vue b/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminCloudtentaclesDebugCard.vue new file mode 100644 index 00000000..187f1299 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminCloudtentaclesDebugCard.vue @@ -0,0 +1,140 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminCloudtentaclesInfoCard.vue b/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminCloudtentaclesInfoCard.vue new file mode 100644 index 00000000..6d688929 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminCloudtentaclesInfoCard.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminCloudtentaclesResultCard.vue b/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminCloudtentaclesResultCard.vue new file mode 100644 index 00000000..d9c4ac57 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminCloudtentaclesResultCard.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminPlatformCloudtentaclesSection.vue b/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminPlatformCloudtentaclesSection.vue new file mode 100644 index 00000000..84206a2b --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/cloudtentacles/AdminPlatformCloudtentaclesSection.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminKuaishouEticketDebug.vue b/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminKuaishouEticketDebug.vue new file mode 100644 index 00000000..95788c72 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminKuaishouEticketDebug.vue @@ -0,0 +1,244 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminKuaishouEticketInfoCard.vue b/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminKuaishouEticketInfoCard.vue new file mode 100644 index 00000000..91a2f9d9 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminKuaishouEticketInfoCard.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminKuaishouEticketResults.vue b/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminKuaishouEticketResults.vue new file mode 100644 index 00000000..66e64a73 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminKuaishouEticketResults.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminKuaishouEticketShopConfig.vue b/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminKuaishouEticketShopConfig.vue new file mode 100644 index 00000000..e401e822 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminKuaishouEticketShopConfig.vue @@ -0,0 +1,405 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminPlatformKuaishouEticketSection.vue b/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminPlatformKuaishouEticketSection.vue new file mode 100644 index 00000000..061c2ce3 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/kuaishou-eticket/AdminPlatformKuaishouEticketSection.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/notification/AdminNotificationBarkCard.vue b/apps/frontend/src/views/admin/platform-shops/components/notification/AdminNotificationBarkCard.vue new file mode 100644 index 00000000..d1d7492e --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/notification/AdminNotificationBarkCard.vue @@ -0,0 +1,141 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/notification/AdminNotificationInfoCard.vue b/apps/frontend/src/views/admin/platform-shops/components/notification/AdminNotificationInfoCard.vue new file mode 100644 index 00000000..efe2ae22 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/notification/AdminNotificationInfoCard.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/notification/AdminNotificationScheduledJobsCard.vue b/apps/frontend/src/views/admin/platform-shops/components/notification/AdminNotificationScheduledJobsCard.vue new file mode 100644 index 00000000..37858cc1 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/notification/AdminNotificationScheduledJobsCard.vue @@ -0,0 +1,317 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/notification/AdminNotificationTestCard.vue b/apps/frontend/src/views/admin/platform-shops/components/notification/AdminNotificationTestCard.vue new file mode 100644 index 00000000..b049c2b0 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/notification/AdminNotificationTestCard.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/components/notification/AdminPlatformNotificationSection.vue b/apps/frontend/src/views/admin/platform-shops/components/notification/AdminPlatformNotificationSection.vue new file mode 100644 index 00000000..92bfec76 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/components/notification/AdminPlatformNotificationSection.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/apps/frontend/src/views/admin/platform-shops/composables/useAdminCloudtentaclesPlatform.ts b/apps/frontend/src/views/admin/platform-shops/composables/useAdminCloudtentaclesPlatform.ts index c31c23eb..f90ff6d5 100644 --- a/apps/frontend/src/views/admin/platform-shops/composables/useAdminCloudtentaclesPlatform.ts +++ b/apps/frontend/src/views/admin/platform-shops/composables/useAdminCloudtentaclesPlatform.ts @@ -2,24 +2,10 @@ import { computed, ref } from 'vue' import { showError, showSuccess } from '@/lib/feedback' import { - appointAdminCloudtentaclesVn, - backAdminCloudtentaclesVn, - buyAdminCloudtentaclesSku, - fetchAdminCloudtentaclesAsset, - fetchAdminCloudtentaclesBindUrl, - fetchAdminCloudtentaclesCategories, - fetchAdminCloudtentaclesKnapsack, - fetchAdminCloudtentaclesSkuList, - fetchAdminCloudtentaclesVnCode, - fetchAdminCloudtentaclesVnList, - generateAdminCloudtentaclesVnLoginCode, - runAdminCloudtentaclesFullFlow, saveAdminCloudtentaclesSourceConfig, sendAdminCloudtentaclesSmsCode, testAdminCloudtentaclesLogin, - useAdminCloudtentaclesSku, validateAdminCloudtentaclesSession, - verifyAdminCloudtentaclesVnCode, } from '@/services/admin' import type { AdminCloudtentaclesLoginTestResult, @@ -29,10 +15,13 @@ import type { AdminCloudtentaclesValidateSessionResult, } from '@/types/admin' +import type { CloudtentaclesForm } from './useCloudtentaclesDebugActions' +import { useCloudtentaclesDebugActions } from './useCloudtentaclesDebugActions' + export function useAdminCloudtentaclesPlatform() { const cloudtentaclesFilePath = ref('') const cloudtentaclesSessionFilePath = ref('') - const cloudtentaclesForm = ref({ + const cloudtentaclesForm = ref({ baseUrl: 'https://123.207.217.176', username: '', password: '', @@ -54,10 +43,10 @@ export function useAdminCloudtentaclesPlatform() { const cloudtentaclesSmsResult = ref(null) const cloudtentaclesLoginResult = ref(null) const cloudtentaclesValidateResult = ref(null) - const cloudtentaclesDebugLoading = ref(false) - const cloudtentaclesDebugResult = ref('') const cloudtentaclesPersistedSession = ref(null) + const debugActions = useCloudtentaclesDebugActions(cloudtentaclesForm, cloudtentaclesResultError) + const cloudtentaclesStats = computed(() => ({ hasCredential: Boolean( cloudtentaclesForm.value.username.trim() && @@ -260,198 +249,6 @@ export function useAdminCloudtentaclesPlatform() { } } - function buildCloudtentaclesTokenPayload() { - return { - baseUrl: cloudtentaclesForm.value.baseUrl.trim() || 'https://123.207.217.176', - token: cloudtentaclesForm.value.token.trim(), - deviceId: cloudtentaclesForm.value.deviceId.trim() || '-', - deviceType: Number(cloudtentaclesForm.value.deviceType || 0), - } - } - - function ensureCloudtentaclesToken() { - if (!cloudtentaclesForm.value.token.trim()) { - cloudtentaclesResultError.value = '请先登录或手动填写 token' - return false - } - return true - } - - function renderCloudtentaclesDebugResult(label: string, data: unknown) { - cloudtentaclesDebugResult.value = `${label}\n${JSON.stringify(data, null, 2)}` - } - - async function runCloudtentaclesDebugAction( - label: string, - runner: () => Promise<{ data: unknown }>, - ) { - cloudtentaclesDebugLoading.value = true - cloudtentaclesResultError.value = '' - - try { - const response = await runner() - renderCloudtentaclesDebugResult(label, response.data) - showSuccess(`${label}成功`) - } catch (error) { - cloudtentaclesResultError.value = error instanceof Error ? error.message : `${label}失败` - showError(cloudtentaclesResultError.value) - } finally { - cloudtentaclesDebugLoading.value = false - } - } - - async function handleCloudtentaclesFetchAsset() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('查询余额', () => - fetchAdminCloudtentaclesAsset(buildCloudtentaclesTokenPayload()), - ) - } - - async function handleCloudtentaclesFetchCategories() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('查询分类', () => - fetchAdminCloudtentaclesCategories(buildCloudtentaclesTokenPayload()), - ) - } - - async function handleCloudtentaclesFetchSkuList() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('查询SKU列表', () => - fetchAdminCloudtentaclesSkuList(buildCloudtentaclesTokenPayload()), - ) - } - - async function handleCloudtentaclesBuySku() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('购买SKU', () => - buyAdminCloudtentaclesSku({ - ...buildCloudtentaclesTokenPayload(), - id: Number(cloudtentaclesForm.value.skuId || 0), - count: Number(cloudtentaclesForm.value.skuCount || 1), - }), - ) - } - - async function handleCloudtentaclesUseSku() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('执行发货', () => - useAdminCloudtentaclesSku({ - ...buildCloudtentaclesTokenPayload(), - id: Number(cloudtentaclesForm.value.skuId || 0), - virtualNumberId: Number(cloudtentaclesForm.value.vnId || 0), - phone: cloudtentaclesForm.value.phone.trim(), - }), - ) - } - - async function handleCloudtentaclesFetchKnapsack() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('查询背包', () => - fetchAdminCloudtentaclesKnapsack(buildCloudtentaclesTokenPayload()), - ) - } - - async function handleCloudtentaclesFetchVnList() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('查询虚拟号列表', () => - fetchAdminCloudtentaclesVnList({ - ...buildCloudtentaclesTokenPayload(), - key: cloudtentaclesForm.value.vnKey.trim(), - }), - ) - } - - async function handleCloudtentaclesAppointVn() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('申请虚拟号', async () => { - const response = await appointAdminCloudtentaclesVn({ - ...buildCloudtentaclesTokenPayload(), - key: cloudtentaclesForm.value.vnKey.trim(), - }) - const item = (response.data as { item?: { id?: number; phone?: string } }).item - if (item?.id) { - cloudtentaclesForm.value.vnId = Number(item.id) - } - if (item?.phone) { - cloudtentaclesForm.value.phone = String(item.phone) - } - return response - }) - } - - async function handleCloudtentaclesGenerateVnLoginCode() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('生成登录码', () => - generateAdminCloudtentaclesVnLoginCode({ - ...buildCloudtentaclesTokenPayload(), - key: cloudtentaclesForm.value.vnKey.trim(), - id: Number(cloudtentaclesForm.value.vnId || 0), - }), - ) - } - - async function handleCloudtentaclesFetchVnCode() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('获取验证码', async () => { - const response = await fetchAdminCloudtentaclesVnCode({ - ...buildCloudtentaclesTokenPayload(), - key: cloudtentaclesForm.value.vnKey.trim(), - phone: cloudtentaclesForm.value.phone.trim(), - }) - const code = (response.data as { code?: string }).code - if (code) { - cloudtentaclesForm.value.code = String(code) - } - return response - }) - } - - async function handleCloudtentaclesVerifyVnCode() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('校验验证码', () => - verifyAdminCloudtentaclesVnCode({ - ...buildCloudtentaclesTokenPayload(), - key: cloudtentaclesForm.value.vnKey.trim(), - id: Number(cloudtentaclesForm.value.vnId || 0), - code: cloudtentaclesForm.value.code.trim(), - }), - ) - } - - async function handleCloudtentaclesFetchBindUrl() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('获取兑换链接', () => - fetchAdminCloudtentaclesBindUrl({ - ...buildCloudtentaclesTokenPayload(), - key: cloudtentaclesForm.value.vnKey.trim(), - id: Number(cloudtentaclesForm.value.vnId || 0), - }), - ) - } - - async function handleCloudtentaclesBackVn() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('退还号码', () => - backAdminCloudtentaclesVn({ - ...buildCloudtentaclesTokenPayload(), - key: cloudtentaclesForm.value.vnKey.trim(), - id: Number(cloudtentaclesForm.value.vnId || 0), - }), - ) - } - - async function handleCloudtentaclesRunFullFlow() { - if (!ensureCloudtentaclesToken()) return - await runCloudtentaclesDebugAction('完整测试流程', () => - runAdminCloudtentaclesFullFlow({ - ...buildCloudtentaclesTokenPayload(), - skuId: Number(cloudtentaclesForm.value.skuId || 0), - skuCount: Number(cloudtentaclesForm.value.skuCount || 1), - vnKey: cloudtentaclesForm.value.vnKey.trim(), - }), - ) - } - return { cloudtentaclesFilePath, cloudtentaclesSessionFilePath, @@ -464,8 +261,8 @@ export function useAdminCloudtentaclesPlatform() { cloudtentaclesSmsResult, cloudtentaclesLoginResult, cloudtentaclesValidateResult, - cloudtentaclesDebugLoading, - cloudtentaclesDebugResult, + cloudtentaclesDebugLoading: debugActions.cloudtentaclesDebugLoading, + cloudtentaclesDebugResult: debugActions.cloudtentaclesDebugResult, cloudtentaclesPersistedSession, cloudtentaclesStats, hydrateCloudtentaclesConfig, @@ -473,19 +270,19 @@ export function useAdminCloudtentaclesPlatform() { handleCloudtentaclesSendSmsCode, handleCloudtentaclesTestLogin, handleCloudtentaclesValidateSession, - handleCloudtentaclesFetchAsset, - handleCloudtentaclesFetchCategories, - handleCloudtentaclesFetchSkuList, - handleCloudtentaclesBuySku, - handleCloudtentaclesUseSku, - handleCloudtentaclesFetchKnapsack, - handleCloudtentaclesFetchVnList, - handleCloudtentaclesAppointVn, - handleCloudtentaclesGenerateVnLoginCode, - handleCloudtentaclesFetchVnCode, - handleCloudtentaclesVerifyVnCode, - handleCloudtentaclesFetchBindUrl, - handleCloudtentaclesBackVn, - handleCloudtentaclesRunFullFlow, + handleCloudtentaclesFetchAsset: debugActions.handleCloudtentaclesFetchAsset, + handleCloudtentaclesFetchCategories: debugActions.handleCloudtentaclesFetchCategories, + handleCloudtentaclesFetchSkuList: debugActions.handleCloudtentaclesFetchSkuList, + handleCloudtentaclesBuySku: debugActions.handleCloudtentaclesBuySku, + handleCloudtentaclesUseSku: debugActions.handleCloudtentaclesUseSku, + handleCloudtentaclesFetchKnapsack: debugActions.handleCloudtentaclesFetchKnapsack, + handleCloudtentaclesFetchVnList: debugActions.handleCloudtentaclesFetchVnList, + handleCloudtentaclesAppointVn: debugActions.handleCloudtentaclesAppointVn, + handleCloudtentaclesGenerateVnLoginCode: debugActions.handleCloudtentaclesGenerateVnLoginCode, + handleCloudtentaclesFetchVnCode: debugActions.handleCloudtentaclesFetchVnCode, + handleCloudtentaclesVerifyVnCode: debugActions.handleCloudtentaclesVerifyVnCode, + handleCloudtentaclesFetchBindUrl: debugActions.handleCloudtentaclesFetchBindUrl, + handleCloudtentaclesBackVn: debugActions.handleCloudtentaclesBackVn, + handleCloudtentaclesRunFullFlow: debugActions.handleCloudtentaclesRunFullFlow, } } diff --git a/apps/frontend/src/views/admin/platform-shops/composables/useAdminKuaishouEticketPlatform.ts b/apps/frontend/src/views/admin/platform-shops/composables/useAdminKuaishouEticketPlatform.ts index a4d481aa..217420ce 100644 --- a/apps/frontend/src/views/admin/platform-shops/composables/useAdminKuaishouEticketPlatform.ts +++ b/apps/frontend/src/views/admin/platform-shops/composables/useAdminKuaishouEticketPlatform.ts @@ -1,5 +1,4 @@ -import { computed, ref } from 'vue' - +import { ref, computed, type Ref } from 'vue' import { showError, showSuccess } from '@/lib/feedback' import { consumeAdminKuaishouEticket, @@ -10,18 +9,28 @@ import { import type { AdminKuaishouEticketConsumeResult, AdminKuaishouEticketDetailResult, - AdminKuaishouEticketShopConfigItem, AdminKuaishouEticketShopInfoResult, AdminKuaishouEticketSourceConfig, } from '@/types/admin' - import type { EditableKuaishouEticketShop } from './types' +import { useKuaishouEticketShopManager } from './useKuaishouEticketShopManager' + +type KuaishouEticketForm = { + baseUrl: string + selectedShopId: string + queryTicketCode: string + eTicketId: string + oid: string + formToken: string + num: number + storeId: string +} export function useAdminKuaishouEticketPlatform() { + const shopManager = useKuaishouEticketShopManager() + const kuaishouEticketFilePath = ref('') - const kuaishouEticketShops = ref([]) - const expandedKuaishouEticketShopIds = ref([]) - const kuaishouEticketForm = ref({ + const kuaishouEticketForm = ref({ baseUrl: 'https://s.kwaixiaodian.com', selectedShopId: '', queryTicketCode: '', @@ -42,14 +51,14 @@ export function useAdminKuaishouEticketPlatform() { const activeKuaishouEticketShop = computed( () => - kuaishouEticketShops.value.find( + shopManager.kuaishouEticketShops.value.find( (item) => item.id === kuaishouEticketForm.value.selectedShopId, ) || null, ) const kuaishouEticketStats = computed(() => ({ - configuredShopCount: kuaishouEticketShops.value.length, - cookieReadyCount: kuaishouEticketShops.value.filter((item) => item.cookie.trim()).length, + configuredShopCount: shopManager.kuaishouEticketShops.value.length, + cookieReadyCount: shopManager.kuaishouEticketShops.value.filter((item) => item.cookie.trim()).length, selectedShopReady: Boolean(activeKuaishouEticketShop.value?.cookie.trim()), detailReady: Boolean(kuaishouEticketDetailResult.value?.detail), consumed: Boolean(kuaishouEticketConsumeResult.value?.consumed), @@ -59,11 +68,11 @@ export function useAdminKuaishouEticketPlatform() { filePath: string source: { baseUrl?: string - shops: AdminKuaishouEticketShopConfigItem[] + shops: AdminKuaishouEticketShopInfoResult['shop'][] } }) { kuaishouEticketFilePath.value = data.filePath - kuaishouEticketShops.value = data.source.shops.map(mapEditableKuaishouEticketShop) + shopManager.setShopsFromConfig(data.source.shops as any) kuaishouEticketForm.value = { baseUrl: data.source.baseUrl || 'https://s.kwaixiaodian.com', selectedShopId: '', @@ -74,9 +83,9 @@ export function useAdminKuaishouEticketPlatform() { num: 1, storeId: '0', } - kuaishouEticketForm.value.selectedShopId = kuaishouEticketShops.value[0]?.id || '' - expandedKuaishouEticketShopIds.value = kuaishouEticketShops.value[0]?.id - ? [kuaishouEticketShops.value[0].id] + kuaishouEticketForm.value.selectedShopId = shopManager.kuaishouEticketShops.value[0]?.id || '' + shopManager.expandedKuaishouEticketShopIds.value = shopManager.kuaishouEticketShops.value[0]?.id + ? [shopManager.kuaishouEticketShops.value[0].id] : [] } @@ -84,7 +93,7 @@ export function useAdminKuaishouEticketPlatform() { return { enabled: true, baseUrl: kuaishouEticketForm.value.baseUrl.trim() || 'https://s.kwaixiaodian.com', - shops: kuaishouEticketShops.value.map((item) => ({ + shops: shopManager.kuaishouEticketShops.value.map((item) => ({ shopId: item.shopId.trim(), kshopName: item.kshopName.trim(), cookie: item.cookie.trim(), @@ -97,66 +106,20 @@ export function useAdminKuaishouEticketPlatform() { } function addKuaishouEticketShop() { - const shop = createEmptyKuaishouEticketShop() - kuaishouEticketShops.value.unshift(shop) - setKuaishouEticketDebugShop(shop.id) + const { newSelectedId } = shopManager.addKuaishouEticketShop(kuaishouEticketForm.value.selectedShopId) + setKuaishouEticketDebugShop(newSelectedId) } function removeKuaishouEticketShop(id: string) { - kuaishouEticketShops.value = kuaishouEticketShops.value.filter((item) => item.id !== id) - collapseKuaishouEticketShop(id) - if (kuaishouEticketForm.value.selectedShopId === id) { - kuaishouEticketForm.value.selectedShopId = kuaishouEticketShops.value[0]?.id || '' - } - } - - function isKuaishouEticketShopExpanded(id: string) { - return expandedKuaishouEticketShopIds.value.includes(id) - } - - function expandKuaishouEticketShop(id: string) { - if (expandedKuaishouEticketShopIds.value.includes(id)) { - return - } - expandedKuaishouEticketShopIds.value = [id, ...expandedKuaishouEticketShopIds.value] - } - - function collapseKuaishouEticketShop(id: string) { - expandedKuaishouEticketShopIds.value = expandedKuaishouEticketShopIds.value.filter( - (item) => item !== id, + kuaishouEticketForm.value.selectedShopId = shopManager.removeKuaishouEticketShop( + id, + kuaishouEticketForm.value.selectedShopId, ) } - function toggleKuaishouEticketShop(id: string) { - if (isKuaishouEticketShopExpanded(id)) { - collapseKuaishouEticketShop(id) - return - } - expandKuaishouEticketShop(id) - } - - function expandAllKuaishouEticketShops() { - expandedKuaishouEticketShopIds.value = kuaishouEticketShops.value.map((item) => item.id) - } - - function collapseAllKuaishouEticketShops() { - expandedKuaishouEticketShopIds.value = [] - } - function setKuaishouEticketDebugShop(id: string) { kuaishouEticketForm.value.selectedShopId = id - expandKuaishouEticketShop(id) - } - - function describeKuaishouEticketShop(shop: EditableKuaishouEticketShop) { - const status = shop.cookie.trim() ? 'Cookie 已就绪' : '待补 Cookie' - const identity = shop.shopId.trim() ? '已识别店铺' : '待读取信息' - return `${status} · ${identity}` - } - - function getKuaishouEticketShopInitial(shop: EditableKuaishouEticketShop) { - const label = shop.kshopName.trim() || shop.shopId.trim() || '店' - return label.slice(0, 1).toUpperCase() + shopManager.expandKuaishouEticketShop(id) } function ensureSelectedKuaishouEticketShop() { @@ -264,14 +227,12 @@ export function useAdminKuaishouEticketPlatform() { kuaishouEticketForm.value.baseUrl = response.data.source.baseUrl || 'https://s.kwaixiaodian.com' const previousSelectedShopId = activeKuaishouEticketShop.value?.shopId || '' - kuaishouEticketShops.value = response.data.source.shops.map(mapEditableKuaishouEticketShop) + shopManager.setShopsFromConfig(response.data.source.shops) kuaishouEticketForm.value.selectedShopId = - kuaishouEticketShops.value.find( - (item) => item.shopId && item.shopId === previousSelectedShopId, - )?.id || - kuaishouEticketShops.value[0]?.id || + shopManager.findShopByShopId(previousSelectedShopId)?.id || + shopManager.kuaishouEticketShops.value[0]?.id || '' - expandedKuaishouEticketShopIds.value = kuaishouEticketForm.value.selectedShopId + shopManager.expandedKuaishouEticketShopIds.value = kuaishouEticketForm.value.selectedShopId ? [kuaishouEticketForm.value.selectedShopId] : [] showSuccess('快手小店核销配置已保存') @@ -351,8 +312,8 @@ export function useAdminKuaishouEticketPlatform() { return { kuaishouEticketFilePath, - kuaishouEticketShops, - expandedKuaishouEticketShopIds, + kuaishouEticketShops: shopManager.kuaishouEticketShops, + expandedKuaishouEticketShopIds: shopManager.expandedKuaishouEticketShopIds, kuaishouEticketForm, kuaishouEticketSaving, kuaishouEticketResolvingShopId, @@ -367,42 +328,18 @@ export function useAdminKuaishouEticketPlatform() { hydrateKuaishouEticketConfig, addKuaishouEticketShop, removeKuaishouEticketShop, - isKuaishouEticketShopExpanded, - expandKuaishouEticketShop, - collapseKuaishouEticketShop, - toggleKuaishouEticketShop, - expandAllKuaishouEticketShops, - collapseAllKuaishouEticketShops, + isKuaishouEticketShopExpanded: shopManager.isKuaishouEticketShopExpanded, + expandKuaishouEticketShop: shopManager.expandKuaishouEticketShop, + collapseKuaishouEticketShop: shopManager.collapseKuaishouEticketShop, + toggleKuaishouEticketShop: shopManager.toggleKuaishouEticketShop, + expandAllKuaishouEticketShops: shopManager.expandAllKuaishouEticketShops, + collapseAllKuaishouEticketShops: shopManager.collapseAllKuaishouEticketShops, setKuaishouEticketDebugShop, - describeKuaishouEticketShop, - getKuaishouEticketShopInitial, + describeKuaishouEticketShop: shopManager.describeKuaishouEticketShop, + getKuaishouEticketShopInitial: shopManager.getKuaishouEticketShopInitial, handleKuaishouEticketResolveShopInfo, handleKuaishouEticketSaveSource, handleKuaishouEticketQueryDetail, handleKuaishouEticketConsume, } } - -function createEmptyKuaishouEticketShop(): EditableKuaishouEticketShop { - return { - id: crypto.randomUUID(), - shopId: '', - kshopName: '', - cookie: '', - userAvatar: '', - enabled: true, - } -} - -function mapEditableKuaishouEticketShop( - item: AdminKuaishouEticketShopConfigItem, -): EditableKuaishouEticketShop { - return { - id: crypto.randomUUID(), - shopId: item.shopId, - kshopName: item.kshopName, - cookie: item.cookie, - userAvatar: item.userAvatar, - enabled: item.enabled !== false, - } -} diff --git a/apps/frontend/src/views/admin/platform-shops/composables/useCloudtentaclesDebugActions.ts b/apps/frontend/src/views/admin/platform-shops/composables/useCloudtentaclesDebugActions.ts new file mode 100644 index 00000000..d616e63a --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/composables/useCloudtentaclesDebugActions.ts @@ -0,0 +1,254 @@ +import { ref } from 'vue' +import { showError, showSuccess } from '@/lib/feedback' +import { + appointAdminCloudtentaclesVn, + backAdminCloudtentaclesVn, + buyAdminCloudtentaclesSku, + fetchAdminCloudtentaclesAsset, + fetchAdminCloudtentaclesBindUrl, + fetchAdminCloudtentaclesCategories, + fetchAdminCloudtentaclesKnapsack, + fetchAdminCloudtentaclesSkuList, + fetchAdminCloudtentaclesVnCode, + fetchAdminCloudtentaclesVnList, + generateAdminCloudtentaclesVnLoginCode, + runAdminCloudtentaclesFullFlow, + useAdminCloudtentaclesSku, + verifyAdminCloudtentaclesVnCode, +} from '@/services/admin' + +export type CloudtentaclesForm = { + baseUrl: string + username: string + password: string + phone: string + code: string + token: string + vnKey: string + vnId: number + skuId: number + skuCount: number + deviceId: string + deviceType: number +} + +export function useCloudtentaclesDebugActions( + cloudtentaclesForm: { value: CloudtentaclesForm }, + cloudtentaclesResultError: { value: string }, +) { + const cloudtentaclesDebugLoading = ref(false) + const cloudtentaclesDebugResult = ref('') + + function buildCloudtentaclesTokenPayload() { + return { + baseUrl: cloudtentaclesForm.value.baseUrl.trim() || 'https://123.207.217.176', + token: cloudtentaclesForm.value.token.trim(), + deviceId: cloudtentaclesForm.value.deviceId.trim() || '-', + deviceType: Number(cloudtentaclesForm.value.deviceType || 0), + } + } + + function ensureCloudtentaclesToken() { + if (!cloudtentaclesForm.value.token.trim()) { + cloudtentaclesResultError.value = '请先登录或手动填写 token' + return false + } + return true + } + + function renderCloudtentaclesDebugResult(label: string, data: unknown) { + cloudtentaclesDebugResult.value = `${label}\n${JSON.stringify(data, null, 2)}` + } + + async function runCloudtentaclesDebugAction( + label: string, + runner: () => Promise<{ data: unknown }>, + ) { + cloudtentaclesDebugLoading.value = true + cloudtentaclesResultError.value = '' + + try { + const response = await runner() + renderCloudtentaclesDebugResult(label, response.data) + showSuccess(`${label}成功`) + } catch (error) { + cloudtentaclesResultError.value = error instanceof Error ? error.message : `${label}失败` + showError(cloudtentaclesResultError.value) + } finally { + cloudtentaclesDebugLoading.value = false + } + } + + async function handleCloudtentaclesFetchAsset() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('查询余额', () => + fetchAdminCloudtentaclesAsset(buildCloudtentaclesTokenPayload()), + ) + } + + async function handleCloudtentaclesFetchCategories() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('查询分类', () => + fetchAdminCloudtentaclesCategories(buildCloudtentaclesTokenPayload()), + ) + } + + async function handleCloudtentaclesFetchSkuList() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('查询SKU列表', () => + fetchAdminCloudtentaclesSkuList(buildCloudtentaclesTokenPayload()), + ) + } + + async function handleCloudtentaclesBuySku() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('购买SKU', () => + buyAdminCloudtentaclesSku({ + ...buildCloudtentaclesTokenPayload(), + id: Number(cloudtentaclesForm.value.skuId || 0), + count: Number(cloudtentaclesForm.value.skuCount || 1), + }), + ) + } + + async function handleCloudtentaclesUseSku() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('执行发货', () => + useAdminCloudtentaclesSku({ + ...buildCloudtentaclesTokenPayload(), + id: Number(cloudtentaclesForm.value.skuId || 0), + virtualNumberId: Number(cloudtentaclesForm.value.vnId || 0), + phone: cloudtentaclesForm.value.phone.trim(), + }), + ) + } + + async function handleCloudtentaclesFetchKnapsack() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('查询背包', () => + fetchAdminCloudtentaclesKnapsack(buildCloudtentaclesTokenPayload()), + ) + } + + async function handleCloudtentaclesFetchVnList() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('查询虚拟号列表', () => + fetchAdminCloudtentaclesVnList({ + ...buildCloudtentaclesTokenPayload(), + key: cloudtentaclesForm.value.vnKey.trim(), + }), + ) + } + + async function handleCloudtentaclesAppointVn() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('申请虚拟号', async () => { + const response = await appointAdminCloudtentaclesVn({ + ...buildCloudtentaclesTokenPayload(), + key: cloudtentaclesForm.value.vnKey.trim(), + }) + const item = (response.data as { item?: { id?: number; phone?: string } }).item + if (item?.id) { + cloudtentaclesForm.value.vnId = Number(item.id) + } + if (item?.phone) { + cloudtentaclesForm.value.phone = String(item.phone) + } + return response + }) + } + + async function handleCloudtentaclesGenerateVnLoginCode() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('生成登录码', () => + generateAdminCloudtentaclesVnLoginCode({ + ...buildCloudtentaclesTokenPayload(), + key: cloudtentaclesForm.value.vnKey.trim(), + id: Number(cloudtentaclesForm.value.vnId || 0), + }), + ) + } + + async function handleCloudtentaclesFetchVnCode() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('获取验证码', async () => { + const response = await fetchAdminCloudtentaclesVnCode({ + ...buildCloudtentaclesTokenPayload(), + key: cloudtentaclesForm.value.vnKey.trim(), + phone: cloudtentaclesForm.value.phone.trim(), + }) + const code = (response.data as { code?: string }).code + if (code) { + cloudtentaclesForm.value.code = String(code) + } + return response + }) + } + + async function handleCloudtentaclesVerifyVnCode() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('校验验证码', () => + verifyAdminCloudtentaclesVnCode({ + ...buildCloudtentaclesTokenPayload(), + key: cloudtentaclesForm.value.vnKey.trim(), + id: Number(cloudtentaclesForm.value.vnId || 0), + code: cloudtentaclesForm.value.code.trim(), + }), + ) + } + + async function handleCloudtentaclesFetchBindUrl() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('获取兑换链接', () => + fetchAdminCloudtentaclesBindUrl({ + ...buildCloudtentaclesTokenPayload(), + key: cloudtentaclesForm.value.vnKey.trim(), + id: Number(cloudtentaclesForm.value.vnId || 0), + }), + ) + } + + async function handleCloudtentaclesBackVn() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('退还号码', () => + backAdminCloudtentaclesVn({ + ...buildCloudtentaclesTokenPayload(), + key: cloudtentaclesForm.value.vnKey.trim(), + id: Number(cloudtentaclesForm.value.vnId || 0), + }), + ) + } + + async function handleCloudtentaclesRunFullFlow() { + if (!ensureCloudtentaclesToken()) return + await runCloudtentaclesDebugAction('完整测试流程', () => + runAdminCloudtentaclesFullFlow({ + ...buildCloudtentaclesTokenPayload(), + skuId: Number(cloudtentaclesForm.value.skuId || 0), + skuCount: Number(cloudtentaclesForm.value.skuCount || 1), + vnKey: cloudtentaclesForm.value.vnKey.trim(), + }), + ) + } + + return { + cloudtentaclesDebugLoading, + cloudtentaclesDebugResult, + buildCloudtentaclesTokenPayload, + ensureCloudtentaclesToken, + handleCloudtentaclesFetchAsset, + handleCloudtentaclesFetchCategories, + handleCloudtentaclesFetchSkuList, + handleCloudtentaclesBuySku, + handleCloudtentaclesUseSku, + handleCloudtentaclesFetchKnapsack, + handleCloudtentaclesFetchVnList, + handleCloudtentaclesAppointVn, + handleCloudtentaclesGenerateVnLoginCode, + handleCloudtentaclesFetchVnCode, + handleCloudtentaclesVerifyVnCode, + handleCloudtentaclesFetchBindUrl, + handleCloudtentaclesBackVn, + handleCloudtentaclesRunFullFlow, + } +} diff --git a/apps/frontend/src/views/admin/platform-shops/composables/useKuaishouEticketShopManager.ts b/apps/frontend/src/views/admin/platform-shops/composables/useKuaishouEticketShopManager.ts new file mode 100644 index 00000000..1dfb8617 --- /dev/null +++ b/apps/frontend/src/views/admin/platform-shops/composables/useKuaishouEticketShopManager.ts @@ -0,0 +1,117 @@ +import { ref } from 'vue' +import type { EditableKuaishouEticketShop } from '../types' +import type { AdminKuaishouEticketShopConfigItem } from '@/types/admin' + +export function useKuaishouEticketShopManager() { + const kuaishouEticketShops = ref([]) + const expandedKuaishouEticketShopIds = ref([]) + + function addKuaishouEticketShop(selectedShopId: string) { + const shop = createEmptyKuaishouEticketShop() + kuaishouEticketShops.value.unshift(shop) + return { shop, newSelectedId: shop.id } + } + + function removeKuaishouEticketShop(id: string, currentSelectedId: string) { + kuaishouEticketShops.value = kuaishouEticketShops.value.filter((item) => item.id !== id) + collapseKuaishouEticketShop(id) + if (currentSelectedId === id) { + return kuaishouEticketShops.value[0]?.id || '' + } + return currentSelectedId + } + + function isKuaishouEticketShopExpanded(id: string) { + return expandedKuaishouEticketShopIds.value.includes(id) + } + + function expandKuaishouEticketShop(id: string) { + if (expandedKuaishouEticketShopIds.value.includes(id)) { + return + } + expandedKuaishouEticketShopIds.value = [id, ...expandedKuaishouEticketShopIds.value] + } + + function collapseKuaishouEticketShop(id: string) { + expandedKuaishouEticketShopIds.value = expandedKuaishouEticketShopIds.value.filter( + (item) => item !== id, + ) + } + + function toggleKuaishouEticketShop(id: string) { + if (isKuaishouEticketShopExpanded(id)) { + collapseKuaishouEticketShop(id) + return + } + expandKuaishouEticketShop(id) + } + + function expandAllKuaishouEticketShops() { + expandedKuaishouEticketShopIds.value = kuaishouEticketShops.value.map((item) => item.id) + } + + function collapseAllKuaishouEticketShops() { + expandedKuaishouEticketShopIds.value = [] + } + + function describeKuaishouEticketShop(shop: EditableKuaishouEticketShop) { + const status = shop.cookie.trim() ? 'Cookie 已就绪' : '待补 Cookie' + const identity = shop.shopId.trim() ? '已识别店铺' : '待读取信息' + return `${status} · ${identity}` + } + + function getKuaishouEticketShopInitial(shop: EditableKuaishouEticketShop) { + const label = shop.kshopName.trim() || shop.shopId.trim() || '店' + return label.slice(0, 1).toUpperCase() + } + + function setShopsFromConfig(shops: AdminKuaishouEticketShopConfigItem[]) { + kuaishouEticketShops.value = shops.map(mapEditableKuaishouEticketShop) + return kuaishouEticketShops.value + } + + function findShopByShopId(shopId: string) { + return kuaishouEticketShops.value.find((item) => item.shopId && item.shopId === shopId) + } + + return { + kuaishouEticketShops, + expandedKuaishouEticketShopIds, + addKuaishouEticketShop, + removeKuaishouEticketShop, + isKuaishouEticketShopExpanded, + expandKuaishouEticketShop, + collapseKuaishouEticketShop, + toggleKuaishouEticketShop, + expandAllKuaishouEticketShops, + collapseAllKuaishouEticketShops, + describeKuaishouEticketShop, + getKuaishouEticketShopInitial, + setShopsFromConfig, + findShopByShopId, + } +} + +function createEmptyKuaishouEticketShop(): EditableKuaishouEticketShop { + return { + id: crypto.randomUUID(), + shopId: '', + kshopName: '', + cookie: '', + userAvatar: '', + enabled: true, + } +} + +function mapEditableKuaishouEticketShop( + item: AdminKuaishouEticketShopConfigItem, +): EditableKuaishouEticketShop { + return { + id: crypto.randomUUID(), + shopId: item.shopId, + kshopName: item.kshopName, + cookie: item.cookie, + userAvatar: item.userAvatar, + enabled: item.enabled !== false, + } +}