feat(cloudtentacles): 合并前端多账号支持改动

This commit is contained in:
yml
2026-05-20 00:38:20 +08:00
10 changed files with 385 additions and 72 deletions
@@ -1,29 +1,37 @@
import { apiGet, apiPost } from '@/lib/http' import { apiDelete, apiGet, apiPost } from '@/lib/http'
import type { import type {
AdminCloudtentaclesLoginTestResult, AdminCloudtentaclesLoginTestResult,
AdminCloudtentaclesPersistedSession, AdminCloudtentaclesPersistedSession,
AdminCloudtentaclesSessionsMap,
AdminCloudtentaclesSkuListResult, AdminCloudtentaclesSkuListResult,
AdminCloudtentaclesSendSmsResult, AdminCloudtentaclesSendSmsResult,
AdminCloudtentaclesSourceConfig, AdminCloudtentaclesSourceConfigResponse,
AdminCloudtentaclesSourceItem,
AdminCloudtentaclesSourcesConfig,
AdminCloudtentaclesValidateSessionResult, AdminCloudtentaclesValidateSessionResult,
} from '@/types/admin' } from '@/types/admin'
export function fetchAdminCloudtentaclesSourceConfig() { export function fetchAdminCloudtentaclesSourceConfig() {
return apiGet<{ return apiGet<AdminCloudtentaclesSourceConfigResponse>(
filePath: string '/api/v1/admin/platform-config/cloudtentacles-source',
sessionFilePath: string )
source: AdminCloudtentaclesSourceConfig
session: AdminCloudtentaclesPersistedSession
}>('/api/v1/admin/platform-config/cloudtentacles-source')
} }
export function saveAdminCloudtentaclesSourceConfig(payload: AdminCloudtentaclesSourceConfig) { export function saveAdminCloudtentaclesSourceConfig(
return apiPost<{ payload:
filePath: string | AdminCloudtentaclesSourcesConfig
sessionFilePath: string | ({ sourceKey: string } & Partial<AdminCloudtentaclesSourceItem>),
source: AdminCloudtentaclesSourceConfig ) {
session: AdminCloudtentaclesPersistedSession return apiPost<AdminCloudtentaclesSourceConfigResponse>(
}>('/api/v1/admin/platform-config/cloudtentacles-source', payload) '/api/v1/admin/platform-config/cloudtentacles-source',
payload,
)
}
export function deleteAdminCloudtentaclesSource(sourceKey: string) {
return apiDelete<{ success: boolean }>(
`/api/v1/admin/platform-config/cloudtentacles-source/${sourceKey}`,
)
} }
export function sendAdminCloudtentaclesSmsCode(payload: { export function sendAdminCloudtentaclesSmsCode(payload: {
@@ -32,6 +40,7 @@ export function sendAdminCloudtentaclesSmsCode(payload: {
phone?: string phone?: string
deviceId?: string deviceId?: string
deviceType?: number deviceType?: number
sourceKey?: string
}) { }) {
return apiPost<AdminCloudtentaclesSendSmsResult>( return apiPost<AdminCloudtentaclesSendSmsResult>(
'/api/v1/admin/platform-config/cloudtentacles/send-sms-code', '/api/v1/admin/platform-config/cloudtentacles/send-sms-code',
@@ -47,6 +56,7 @@ export function testAdminCloudtentaclesLogin(payload: {
code?: string code?: string
deviceId?: string deviceId?: string
deviceType?: number deviceType?: number
sourceKey?: string
}) { }) {
return apiPost<AdminCloudtentaclesLoginTestResult>( return apiPost<AdminCloudtentaclesLoginTestResult>(
'/api/v1/admin/platform-config/cloudtentacles/test-login', '/api/v1/admin/platform-config/cloudtentacles/test-login',
@@ -59,6 +69,7 @@ export function validateAdminCloudtentaclesSession(payload: {
token?: string token?: string
deviceId?: string deviceId?: string
deviceType?: number deviceType?: number
sourceKey?: string
}) { }) {
return apiPost<AdminCloudtentaclesValidateSessionResult>( return apiPost<AdminCloudtentaclesValidateSessionResult>(
'/api/v1/admin/platform-config/cloudtentacles/validate-session', '/api/v1/admin/platform-config/cloudtentacles/validate-session',
@@ -71,6 +82,7 @@ export function fetchAdminCloudtentaclesAsset(payload: {
token?: string token?: string
deviceId?: string deviceId?: string
deviceType?: number deviceType?: number
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/asset', '/api/v1/admin/platform-config/cloudtentacles/asset',
@@ -83,6 +95,7 @@ export function fetchAdminCloudtentaclesCategories(payload: {
token?: string token?: string
deviceId?: string deviceId?: string
deviceType?: number deviceType?: number
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/categories', '/api/v1/admin/platform-config/cloudtentacles/categories',
@@ -95,6 +108,7 @@ export function fetchAdminCloudtentaclesSkuList(payload: {
token?: string token?: string
deviceId?: string deviceId?: string
deviceType?: number deviceType?: number
sourceKey?: string
}) { }) {
return apiPost<AdminCloudtentaclesSkuListResult>( return apiPost<AdminCloudtentaclesSkuListResult>(
'/api/v1/admin/platform-config/cloudtentacles/sku/list', '/api/v1/admin/platform-config/cloudtentacles/sku/list',
@@ -109,6 +123,7 @@ export function buyAdminCloudtentaclesSku(payload: {
deviceType?: number deviceType?: number
id?: number id?: number
count?: number count?: number
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/sku/buy', '/api/v1/admin/platform-config/cloudtentacles/sku/buy',
@@ -124,6 +139,7 @@ export function useAdminCloudtentaclesSku(payload: {
id?: number id?: number
virtualNumberId?: number virtualNumberId?: number
phone?: string phone?: string
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/sku/use', '/api/v1/admin/platform-config/cloudtentacles/sku/use',
@@ -136,6 +152,7 @@ export function fetchAdminCloudtentaclesKnapsack(payload: {
token?: string token?: string
deviceId?: string deviceId?: string
deviceType?: number deviceType?: number
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/knapsack', '/api/v1/admin/platform-config/cloudtentacles/knapsack',
@@ -149,6 +166,7 @@ export function fetchAdminCloudtentaclesVnList(payload: {
deviceId?: string deviceId?: string
deviceType?: number deviceType?: number
key?: string key?: string
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/vn/list', '/api/v1/admin/platform-config/cloudtentacles/vn/list',
@@ -162,6 +180,7 @@ export function appointAdminCloudtentaclesVn(payload: {
deviceId?: string deviceId?: string
deviceType?: number deviceType?: number
key?: string key?: string
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/vn/appoint', '/api/v1/admin/platform-config/cloudtentacles/vn/appoint',
@@ -176,6 +195,7 @@ export function generateAdminCloudtentaclesVnLoginCode(payload: {
deviceType?: number deviceType?: number
key?: string key?: string
id?: number id?: number
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/vn/generate-login-code', '/api/v1/admin/platform-config/cloudtentacles/vn/generate-login-code',
@@ -190,6 +210,7 @@ export function fetchAdminCloudtentaclesVnCode(payload: {
deviceType?: number deviceType?: number
key?: string key?: string
phone?: string phone?: string
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/vn/fetch-code', '/api/v1/admin/platform-config/cloudtentacles/vn/fetch-code',
@@ -205,6 +226,7 @@ export function verifyAdminCloudtentaclesVnCode(payload: {
key?: string key?: string
id?: number id?: number
code?: string code?: string
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/vn/verify-code', '/api/v1/admin/platform-config/cloudtentacles/vn/verify-code',
@@ -219,6 +241,7 @@ export function fetchAdminCloudtentaclesBindUrl(payload: {
deviceType?: number deviceType?: number
key?: string key?: string
id?: number id?: number
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/vn/bind-url', '/api/v1/admin/platform-config/cloudtentacles/vn/bind-url',
@@ -233,6 +256,7 @@ export function backAdminCloudtentaclesVn(payload: {
deviceType?: number deviceType?: number
key?: string key?: string
id?: number id?: number
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/vn/back', '/api/v1/admin/platform-config/cloudtentacles/vn/back',
@@ -248,6 +272,7 @@ export function runAdminCloudtentaclesFullFlow(payload: {
skuId?: number skuId?: number
skuCount?: number skuCount?: number
vnKey?: string vnKey?: string
sourceKey?: string
}) { }) {
return apiPost<Record<string, unknown>>( return apiPost<Record<string, unknown>>(
'/api/v1/admin/platform-config/cloudtentacles/debug/full-flow', '/api/v1/admin/platform-config/cloudtentacles/debug/full-flow',
+6 -10
View File
@@ -2,12 +2,7 @@
export type { AdminPagination } from './common' export type { AdminPagination } from './common'
// Auth types // Auth types
export type { export type { AdminRole, AdminUserStatus, AdminLoginResponse, AdminSessionSummary } from './auth'
AdminRole,
AdminUserStatus,
AdminLoginResponse,
AdminSessionSummary,
} from './auth'
// Users types // Users types
export type { AdminUserListItem } from './users' export type { AdminUserListItem } from './users'
@@ -37,10 +32,7 @@ export type {
} from './tasks' } from './tasks'
// Inventory types // Inventory types
export type { export type { AdminInventorySkuSuggestion, AdminInventoryItemListItem } from './inventory'
AdminInventorySkuSuggestion,
AdminInventoryItemListItem,
} from './inventory'
// Manual redeem types // Manual redeem types
export type { AdminManualRedeemDetail } from './manual-redeem' export type { AdminManualRedeemDetail } from './manual-redeem'
@@ -83,6 +75,10 @@ export type {
AdminKuaishouEticketShopInfoResult, AdminKuaishouEticketShopInfoResult,
AdminKuaishouEticketDetailResult, AdminKuaishouEticketDetailResult,
AdminKuaishouEticketConsumeResult, AdminKuaishouEticketConsumeResult,
AdminCloudtentaclesSourceItem,
AdminCloudtentaclesSourcesConfig,
AdminCloudtentaclesSourceConfigResponse,
AdminCloudtentaclesSessionsMap,
AdminCloudtentaclesSourceConfig, AdminCloudtentaclesSourceConfig,
AdminCloudtentaclesPersistedSession, AdminCloudtentaclesPersistedSession,
AdminCloudtentaclesSendSmsResult, AdminCloudtentaclesSendSmsResult,
@@ -1,5 +1,6 @@
export interface AdminCloudtentaclesSourceConfig { export interface AdminCloudtentaclesSourceItem {
enabled: boolean key: string
label: string
baseUrl: string baseUrl: string
username: string username: string
password: string password: string
@@ -8,6 +9,11 @@ export interface AdminCloudtentaclesSourceConfig {
deviceType: number deviceType: number
} }
export interface AdminCloudtentaclesSourcesConfig {
enabled: boolean
sources: AdminCloudtentaclesSourceItem[]
}
export interface AdminCloudtentaclesPersistedSession { export interface AdminCloudtentaclesPersistedSession {
token: string token: string
tokenMasked: string tokenMasked: string
@@ -20,6 +26,18 @@ export interface AdminCloudtentaclesPersistedSession {
hasToken: boolean hasToken: boolean
} }
export interface AdminCloudtentaclesSessionsMap {
[sourceKey: string]: AdminCloudtentaclesPersistedSession
}
export interface AdminCloudtentaclesSourceConfigResponse {
filePath: string
sessionFilePath: string
enabled: boolean
sources: AdminCloudtentaclesSourceItem[]
sessions: AdminCloudtentaclesSessionsMap
}
export interface AdminCloudtentaclesSendSmsResult { export interface AdminCloudtentaclesSendSmsResult {
baseUrl: string baseUrl: string
username: string username: string
@@ -77,3 +95,14 @@ export interface AdminCloudtentaclesSkuListResult {
items: AdminCloudtentaclesSkuItem[] items: AdminCloudtentaclesSkuItem[]
rawItems: Record<string, unknown>[] rawItems: Record<string, unknown>[]
} }
/** @deprecated Use AdminCloudtentaclesSourceItem + AdminCloudtentaclesSourcesConfig instead */
export interface AdminCloudtentaclesSourceConfig {
enabled: boolean
baseUrl: string
username: string
password: string
phone: string
deviceId: string
deviceType: number
}
@@ -33,6 +33,10 @@ export type {
} from './kuaishou-eticket' } from './kuaishou-eticket'
export type { export type {
AdminCloudtentaclesSourceItem,
AdminCloudtentaclesSourcesConfig,
AdminCloudtentaclesSourceConfigResponse,
AdminCloudtentaclesSessionsMap,
AdminCloudtentaclesSourceConfig, AdminCloudtentaclesSourceConfig,
AdminCloudtentaclesPersistedSession, AdminCloudtentaclesPersistedSession,
AdminCloudtentaclesSendSmsResult, AdminCloudtentaclesSendSmsResult,
@@ -132,7 +132,14 @@ const {
cloudtentaclesDebugResult, cloudtentaclesDebugResult,
cloudtentaclesPersistedSession, cloudtentaclesPersistedSession,
cloudtentaclesStats, cloudtentaclesStats,
sources: cloudtentaclesSources,
sessions: cloudtentaclesSessions,
selectedSourceKey: selectedCloudtentaclesSourceKey,
sourceOptions: cloudtentaclesSourceOptions,
hydrateCloudtentaclesConfig, hydrateCloudtentaclesConfig,
switchSource: switchCloudtentaclesSource,
addSource: addCloudtentaclesSource,
removeSource: removeCloudtentaclesSource,
handleCloudtentaclesSaveSource, handleCloudtentaclesSaveSource,
handleCloudtentaclesSendSmsCode, handleCloudtentaclesSendSmsCode,
handleCloudtentaclesTestLogin, handleCloudtentaclesTestLogin,
@@ -417,6 +424,13 @@ onMounted(loadConfigs)
:cloudtentacles-debug-result="cloudtentaclesDebugResult" :cloudtentacles-debug-result="cloudtentaclesDebugResult"
:cloudtentacles-persisted-session="cloudtentaclesPersistedSession" :cloudtentacles-persisted-session="cloudtentaclesPersistedSession"
:cloudtentacles-stats="cloudtentaclesStats" :cloudtentacles-stats="cloudtentaclesStats"
:sources="cloudtentaclesSources"
:sessions="cloudtentaclesSessions"
:selected-source-key="selectedCloudtentaclesSourceKey"
:source-options="cloudtentaclesSourceOptions"
:switch-source="switchCloudtentaclesSource"
:add-source="addCloudtentaclesSource"
:remove-source="removeCloudtentaclesSource"
:handle-cloudtentacles-save-source="handleCloudtentaclesSaveSource" :handle-cloudtentacles-save-source="handleCloudtentaclesSaveSource"
:handle-cloudtentacles-send-sms-code="handleCloudtentaclesSendSmsCode" :handle-cloudtentacles-send-sms-code="handleCloudtentaclesSendSmsCode"
:handle-cloudtentacles-test-login="handleCloudtentaclesTestLogin" :handle-cloudtentacles-test-login="handleCloudtentaclesTestLogin"
@@ -2,6 +2,7 @@
import type { import type {
AdminCloudtentaclesLoginTestResult, AdminCloudtentaclesLoginTestResult,
AdminCloudtentaclesSendSmsResult, AdminCloudtentaclesSendSmsResult,
AdminCloudtentaclesSourceItem,
AdminCloudtentaclesValidateSessionResult, AdminCloudtentaclesValidateSessionResult,
} from '@/types/admin' } from '@/types/admin'
import AdminResultCard from '@/components/admin/AdminResultCard.vue' import AdminResultCard from '@/components/admin/AdminResultCard.vue'
@@ -22,6 +23,11 @@ type CloudtentaclesForm = {
deviceType: number deviceType: number
} }
type SourceOption = {
key: string
label: string
}
type Props = { type Props = {
cloudtentaclesForm: CloudtentaclesForm cloudtentaclesForm: CloudtentaclesForm
cloudtentaclesSaving: boolean cloudtentaclesSaving: boolean
@@ -32,13 +38,19 @@ type Props = {
cloudtentaclesSmsResult: AdminCloudtentaclesSendSmsResult | null cloudtentaclesSmsResult: AdminCloudtentaclesSendSmsResult | null
cloudtentaclesLoginResult: AdminCloudtentaclesLoginTestResult | null cloudtentaclesLoginResult: AdminCloudtentaclesLoginTestResult | null
cloudtentaclesValidateResult: AdminCloudtentaclesValidateSessionResult | null cloudtentaclesValidateResult: AdminCloudtentaclesValidateSessionResult | null
selectedSourceKey: string
sourceOptions: SourceOption[]
sources: AdminCloudtentaclesSourceItem[]
handleCloudtentaclesSaveSource: () => void | Promise<void> handleCloudtentaclesSaveSource: () => void | Promise<void>
handleCloudtentaclesSendSmsCode: () => void | Promise<void> handleCloudtentaclesSendSmsCode: () => void | Promise<void>
handleCloudtentaclesTestLogin: () => void | Promise<void> handleCloudtentaclesTestLogin: () => void | Promise<void>
handleCloudtentaclesValidateSession: () => void | Promise<void> handleCloudtentaclesValidateSession: () => void | Promise<void>
switchSource: (sourceKey: string) => void
addSource: () => void
removeSource: (sourceKey: string) => void
} }
defineProps<Props>() const props = defineProps<Props>()
</script> </script>
<template> <template>
@@ -73,6 +85,32 @@ defineProps<Props>()
</div> </div>
</template> </template>
<!-- 账号选择器 -->
<div class="source-selector">
<el-select
:model-value="selectedSourceKey"
placeholder="选择账号"
@change="switchSource"
class="source-select"
>
<el-option
v-for="opt in sourceOptions"
:key="opt.key"
:label="opt.label"
:value="opt.key"
/>
</el-select>
<el-button type="primary" plain size="small" @click="addSource">新增账号</el-button>
<el-button
v-if="selectedSourceKey !== 'default'"
type="danger"
plain
size="small"
@click="removeSource(selectedSourceKey)"
>删除账号</el-button
>
</div>
<el-form label-width="auto" label-position="top"> <el-form label-width="auto" label-position="top">
<el-form-item label="Base URL"> <el-form-item label="Base URL">
<el-input v-model="cloudtentaclesForm.baseUrl" placeholder="https://123.207.217.176" /> <el-input v-model="cloudtentaclesForm.baseUrl" placeholder="https://123.207.217.176" />
@@ -242,6 +280,17 @@ defineProps<Props>()
flex-wrap: wrap; flex-wrap: wrap;
} }
.source-selector {
display: flex;
align-items: center;
gap: var(--space-2);
margin-bottom: var(--space-4);
}
.source-select {
width: 180px;
}
.result-grid { .result-grid {
display: grid; display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-columns: repeat(3, minmax(0, 1fr));
@@ -1,6 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import type { import type {
AdminCloudtentaclesPersistedSession, AdminCloudtentaclesPersistedSession,
AdminCloudtentaclesSessionItem,
AdminCloudtentaclesSessionsMap,
} from '@/types/admin' } from '@/types/admin'
import { formatAdminDateTime } from '@/utils/admin-time' import { formatAdminDateTime } from '@/utils/admin-time'
@@ -8,9 +10,12 @@ type Props = {
cloudtentaclesFilePath: string cloudtentaclesFilePath: string
cloudtentaclesSessionFilePath: string cloudtentaclesSessionFilePath: string
cloudtentaclesPersistedSession: AdminCloudtentaclesPersistedSession | null cloudtentaclesPersistedSession: AdminCloudtentaclesPersistedSession | null
sources: AdminCloudtentaclesSourceItem[]
sessions: AdminCloudtentaclesSessionsMap
selectedSourceKey: string
} }
defineProps<Props>() const props = defineProps<Props>()
</script> </script>
<template> <template>
@@ -25,17 +30,31 @@ defineProps<Props>()
<el-descriptions-item label="会话文件"> <el-descriptions-item label="会话文件">
<code>{{ cloudtentaclesSessionFilePath || '-' }}</code> <code>{{ cloudtentaclesSessionFilePath || '-' }}</code>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="账号数量">
{{ sources.length }}
</el-descriptions-item>
<el-descriptions-item label="当前选中账号">
{{ selectedSourceKey }}
</el-descriptions-item>
<el-descriptions-item label="职责"> <el-descriptions-item label="职责">
管理 cloudtentacles 外部履约平台的账号短信验证码登录与 token 管理 cloudtentacles 外部履约平台的账号短信验证码登录与 token
探活该区域不处理订单来源同步 探活该区域不处理订单来源同步
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="已保存 token"> <el-descriptions-item label="当前账号已保存 token">
{{ {{
cloudtentaclesPersistedSession?.hasToken cloudtentaclesPersistedSession?.hasToken
? `${cloudtentaclesPersistedSession.tokenMasked} / ${formatAdminDateTime(cloudtentaclesPersistedSession.loggedInAt)}` ? `${cloudtentaclesPersistedSession.tokenMasked} / ${formatAdminDateTime(cloudtentaclesPersistedSession.loggedInAt)}`
: '未保存' : '未保存'
}} }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item v-if="Object.keys(sessions).length > 0" label="各账号会话状态">
<div class="session-list">
<div v-for="(session, key) in sessions" :key="key" class="session-item">
<el-tag :type="session.hasToken ? 'success' : 'info'" size="small">{{ key }}</el-tag>
<span>{{ session.hasToken ? session.tokenMasked : '未登录' }}</span>
</div>
</div>
</el-descriptions-item>
</el-descriptions> </el-descriptions>
</el-card> </el-card>
</template> </template>
@@ -50,4 +69,16 @@ defineProps<Props>()
font-weight: 600; font-weight: 600;
color: var(--text-primary); color: var(--text-primary);
} }
.session-list {
display: flex;
flex-direction: column;
gap: var(--space-1);
}
.session-item {
display: flex;
align-items: center;
gap: var(--space-2);
}
</style> </style>
@@ -3,6 +3,8 @@ import type {
AdminCloudtentaclesLoginTestResult, AdminCloudtentaclesLoginTestResult,
AdminCloudtentaclesPersistedSession, AdminCloudtentaclesPersistedSession,
AdminCloudtentaclesSendSmsResult, AdminCloudtentaclesSendSmsResult,
AdminCloudtentaclesSessionItem,
AdminCloudtentaclesSessionsMap,
AdminCloudtentaclesValidateSessionResult, AdminCloudtentaclesValidateSessionResult,
} from '@/types/admin' } from '@/types/admin'
import AdminCloudtentaclesInfoCard from './AdminCloudtentaclesInfoCard.vue' import AdminCloudtentaclesInfoCard from './AdminCloudtentaclesInfoCard.vue'
@@ -25,10 +27,16 @@ type CloudtentaclesForm = {
deviceType: number deviceType: number
} }
type SourceOption = {
key: string
label: string
}
type CloudtentaclesStats = { type CloudtentaclesStats = {
hasCredential: boolean hasCredential: boolean
smsSent: boolean smsSent: boolean
validated: boolean validated: boolean
sourceCount: number
} }
type Props = { type Props = {
@@ -47,6 +55,10 @@ type Props = {
cloudtentaclesDebugResult: string cloudtentaclesDebugResult: string
cloudtentaclesPersistedSession: AdminCloudtentaclesPersistedSession | null cloudtentaclesPersistedSession: AdminCloudtentaclesPersistedSession | null
cloudtentaclesStats: CloudtentaclesStats cloudtentaclesStats: CloudtentaclesStats
sources: AdminCloudtentaclesSourceItem[]
sessions: AdminCloudtentaclesSessionsMap
selectedSourceKey: string
sourceOptions: SourceOption[]
handleCloudtentaclesSaveSource: () => void | Promise<void> handleCloudtentaclesSaveSource: () => void | Promise<void>
handleCloudtentaclesSendSmsCode: () => void | Promise<void> handleCloudtentaclesSendSmsCode: () => void | Promise<void>
handleCloudtentaclesTestLogin: () => void | Promise<void> handleCloudtentaclesTestLogin: () => void | Promise<void>
@@ -65,6 +77,9 @@ type Props = {
handleCloudtentaclesFetchBindUrl: () => void | Promise<void> handleCloudtentaclesFetchBindUrl: () => void | Promise<void>
handleCloudtentaclesBackVn: () => void | Promise<void> handleCloudtentaclesBackVn: () => void | Promise<void>
handleCloudtentaclesRunFullFlow: () => void | Promise<void> handleCloudtentaclesRunFullFlow: () => void | Promise<void>
switchSource: (sourceKey: string) => void
addSource: () => void
removeSource: (sourceKey: string) => void
} }
defineProps<Props>() defineProps<Props>()
@@ -76,6 +91,9 @@ defineProps<Props>()
:cloudtentacles-file-path="cloudtentaclesFilePath" :cloudtentacles-file-path="cloudtentaclesFilePath"
:cloudtentacles-session-file-path="cloudtentaclesSessionFilePath" :cloudtentacles-session-file-path="cloudtentaclesSessionFilePath"
:cloudtentacles-persisted-session="cloudtentaclesPersistedSession" :cloudtentacles-persisted-session="cloudtentaclesPersistedSession"
:sources="sources"
:sessions="sessions"
:selected-source-key="selectedSourceKey"
/> />
<AdminCloudtentaclesConfigCard <AdminCloudtentaclesConfigCard
@@ -88,10 +106,16 @@ defineProps<Props>()
:cloudtentacles-sms-result="cloudtentaclesSmsResult" :cloudtentacles-sms-result="cloudtentaclesSmsResult"
:cloudtentacles-login-result="cloudtentaclesLoginResult" :cloudtentacles-login-result="cloudtentaclesLoginResult"
:cloudtentacles-validate-result="cloudtentaclesValidateResult" :cloudtentacles-validate-result="cloudtentaclesValidateResult"
:selected-source-key="selectedSourceKey"
:source-options="sourceOptions"
:sources="sources"
:handle-cloudtentacles-save-source="handleCloudtentaclesSaveSource" :handle-cloudtentacles-save-source="handleCloudtentaclesSaveSource"
:handle-cloudtentacles-send-sms-code="handleCloudtentaclesSendSmsCode" :handle-cloudtentacles-send-sms-code="handleCloudtentaclesSendSmsCode"
:handle-cloudtentacles-test-login="handleCloudtentaclesTestLogin" :handle-cloudtentacles-test-login="handleCloudtentaclesTestLogin"
:handle-cloudtentacles-validate-session="handleCloudtentaclesValidateSession" :handle-cloudtentacles-validate-session="handleCloudtentaclesValidateSession"
:switch-source="switchSource"
:add-source="addSource"
:remove-source="removeSource"
/> />
<AdminCloudtentaclesDebugCard <AdminCloudtentaclesDebugCard
@@ -2,6 +2,7 @@ import { computed, ref } from 'vue'
import { showError, showSuccess } from '@/lib/feedback' import { showError, showSuccess } from '@/lib/feedback'
import { import {
deleteAdminCloudtentaclesSource,
saveAdminCloudtentaclesSourceConfig, saveAdminCloudtentaclesSourceConfig,
sendAdminCloudtentaclesSmsCode, sendAdminCloudtentaclesSmsCode,
testAdminCloudtentaclesLogin, testAdminCloudtentaclesLogin,
@@ -11,7 +12,10 @@ import type {
AdminCloudtentaclesLoginTestResult, AdminCloudtentaclesLoginTestResult,
AdminCloudtentaclesPersistedSession, AdminCloudtentaclesPersistedSession,
AdminCloudtentaclesSendSmsResult, AdminCloudtentaclesSendSmsResult,
AdminCloudtentaclesSourceConfig, AdminCloudtentaclesSourceItem,
AdminCloudtentaclesSessionsMap,
AdminCloudtentaclesSourceConfigResponse,
AdminCloudtentaclesSourcesConfig,
AdminCloudtentaclesValidateSessionResult, AdminCloudtentaclesValidateSessionResult,
} from '@/types/admin' } from '@/types/admin'
@@ -21,6 +25,11 @@ import { useCloudtentaclesDebugActions } from './useCloudtentaclesDebugActions'
export function useAdminCloudtentaclesPlatform() { export function useAdminCloudtentaclesPlatform() {
const cloudtentaclesFilePath = ref('') const cloudtentaclesFilePath = ref('')
const cloudtentaclesSessionFilePath = ref('') const cloudtentaclesSessionFilePath = ref('')
const selectedSourceKey = ref('default')
const sources = ref<AdminCloudtentaclesSourceItem[]>([])
const sessions = ref<AdminCloudtentaclesSessionsMap>({})
const cloudtentaclesForm = ref<CloudtentaclesForm>({ const cloudtentaclesForm = ref<CloudtentaclesForm>({
baseUrl: 'https://123.207.217.176', baseUrl: 'https://123.207.217.176',
username: '', username: '',
@@ -45,7 +54,23 @@ export function useAdminCloudtentaclesPlatform() {
const cloudtentaclesValidateResult = ref<AdminCloudtentaclesValidateSessionResult | null>(null) const cloudtentaclesValidateResult = ref<AdminCloudtentaclesValidateSessionResult | null>(null)
const cloudtentaclesPersistedSession = ref<AdminCloudtentaclesPersistedSession | null>(null) const cloudtentaclesPersistedSession = ref<AdminCloudtentaclesPersistedSession | null>(null)
const debugActions = useCloudtentaclesDebugActions(cloudtentaclesForm, cloudtentaclesResultError) const debugActions = useCloudtentaclesDebugActions(
cloudtentaclesForm,
cloudtentaclesResultError,
selectedSourceKey,
)
const sourceOptions = computed(() =>
sources.value.map((s) => ({ key: s.key, label: s.label })),
)
const currentSource = computed(
() => sources.value.find((s) => s.key === selectedSourceKey.value) || sources.value[0],
)
const currentSession = computed(
() => sessions.value[selectedSourceKey.value] || null,
)
const cloudtentaclesStats = computed(() => ({ const cloudtentaclesStats = computed(() => ({
hasCredential: Boolean( hasCredential: Boolean(
@@ -55,56 +80,153 @@ export function useAdminCloudtentaclesPlatform() {
), ),
smsSent: Boolean(cloudtentaclesSmsResult.value), smsSent: Boolean(cloudtentaclesSmsResult.value),
validated: Boolean(cloudtentaclesValidateResult.value || cloudtentaclesLoginResult.value), validated: Boolean(cloudtentaclesValidateResult.value || cloudtentaclesLoginResult.value),
sourceCount: sources.value.length,
})) }))
function hydrateCloudtentaclesConfig(data: { function hydrateCloudtentaclesConfig(data: AdminCloudtentaclesSourceConfigResponse) {
filePath: string
sessionFilePath: string
session: AdminCloudtentaclesPersistedSession
source: {
baseUrl?: string
username?: string
password?: string
phone?: string
deviceId?: string
deviceType?: number
}
}) {
cloudtentaclesFilePath.value = data.filePath cloudtentaclesFilePath.value = data.filePath
cloudtentaclesSessionFilePath.value = data.sessionFilePath cloudtentaclesSessionFilePath.value = data.sessionFilePath
cloudtentaclesPersistedSession.value = data.session sources.value = data.sources || []
sessions.value = data.sessions || {}
// Ensure 'default' always exists
if (!sources.value.length) {
sources.value.push({
key: 'default',
label: '默认账号',
baseUrl: 'https://123.207.217.176',
username: '',
password: '',
phone: '',
deviceId: '-',
deviceType: 0,
})
}
// Default selectedSourceKey to 'default' or first source
if (!sources.value.find((s) => s.key === selectedSourceKey.value)) {
selectedSourceKey.value = sources.value[0].key
}
// Hydrate form from the currently selected source
hydrateFormFromSource(selectedSourceKey.value)
}
function hydrateFormFromSource(sourceKey: string) {
const source = sources.value.find((s) => s.key === sourceKey)
const session = sessions.value[sourceKey]
if (source) {
cloudtentaclesForm.value = { cloudtentaclesForm.value = {
baseUrl: data.source.baseUrl || 'https://123.207.217.176', baseUrl: source.baseUrl || 'https://123.207.217.176',
username: data.source.username || '', username: source.username || '',
password: data.source.password || '', password: source.password || '',
phone: data.source.phone || '', phone: source.phone || '',
code: '', code: '',
token: data.session?.token || '', token: session?.token || '',
vnKey: '1', vnKey: '1',
vnId: 0, vnId: 0,
skuId: 5, skuId: 5,
skuCount: 1, skuCount: 1,
deviceId: data.source.deviceId || '-', deviceId: source.deviceId || '-',
deviceType: data.source.deviceType || 0, deviceType: source.deviceType || 0,
}
}
cloudtentaclesPersistedSession.value = session || null
}
function switchSource(sourceKey: string) {
selectedSourceKey.value = sourceKey
// Clear transient results when switching
cloudtentaclesSmsResult.value = null
cloudtentaclesLoginResult.value = null
cloudtentaclesValidateResult.value = null
cloudtentaclesResultError.value = ''
hydrateFormFromSource(sourceKey)
}
function addSource() {
const newKey = `account${sources.value.length + 1}`
const newSource: AdminCloudtentaclesSourceItem = {
key: newKey,
label: `备用账号 ${sources.value.length}`,
baseUrl: 'https://123.207.217.176',
username: '',
password: '',
phone: '',
deviceId: '-',
deviceType: 0,
}
sources.value.push(newSource)
selectedSourceKey.value = newKey
hydrateFormFromSource(newKey)
}
async function removeSource(sourceKey: string) {
if (sourceKey === 'default') {
showError('默认账号不可删除')
return
}
try {
cloudtentaclesSaving.value = true
await deleteAdminCloudtentaclesSource(sourceKey)
sources.value = sources.value.filter((s) => s.key !== sourceKey)
delete sessions.value[sourceKey]
if (selectedSourceKey.value === sourceKey) {
selectedSourceKey.value = 'default'
hydrateFormFromSource('default')
}
showSuccess('账号已删除')
} catch (error) {
showError(error instanceof Error ? error.message : '删除账号失败')
} finally {
cloudtentaclesSaving.value = false
} }
} }
function buildCloudtentaclesConfigPayload(): AdminCloudtentaclesSourceConfig { function buildCloudtentaclesConfigPayload(): AdminCloudtentaclesSourcesConfig {
// Update current source from form
const current = sources.value.find((s) => s.key === selectedSourceKey.value)
if (current) {
current.baseUrl = cloudtentaclesForm.value.baseUrl.trim() || 'https://123.207.217.176'
current.username = cloudtentaclesForm.value.username.trim()
current.password = cloudtentaclesForm.value.password.trim()
current.phone = cloudtentaclesForm.value.phone.trim()
current.deviceId = cloudtentaclesForm.value.deviceId.trim() || '-'
current.deviceType = Number(cloudtentaclesForm.value.deviceType || 0)
}
return { return {
enabled: true, enabled: true,
sources: sources.value.map((s) => ({
key: s.key,
label: s.label,
baseUrl: s.baseUrl,
username: s.username,
password: s.password,
phone: s.phone,
deviceId: s.deviceId,
deviceType: s.deviceType,
})),
}
}
function buildCloudtentaclesLoginPayload() {
return {
...buildCloudtentaclesSourcePayload(),
code: cloudtentaclesForm.value.code.trim(),
sourceKey: selectedSourceKey.value,
}
}
function buildCloudtentaclesSourcePayload() {
return {
baseUrl: cloudtentaclesForm.value.baseUrl.trim() || 'https://123.207.217.176', baseUrl: cloudtentaclesForm.value.baseUrl.trim() || 'https://123.207.217.176',
username: cloudtentaclesForm.value.username.trim(), username: cloudtentaclesForm.value.username.trim(),
password: cloudtentaclesForm.value.password.trim(), password: cloudtentaclesForm.value.password.trim(),
phone: cloudtentaclesForm.value.phone.trim(), phone: cloudtentaclesForm.value.phone.trim(),
deviceId: cloudtentaclesForm.value.deviceId.trim() || '-', deviceId: cloudtentaclesForm.value.deviceId.trim() || '-',
deviceType: Number(cloudtentaclesForm.value.deviceType || 0), deviceType: Number(cloudtentaclesForm.value.deviceType || 0),
} sourceKey: selectedSourceKey.value,
}
function buildCloudtentaclesLoginPayload() {
return {
...buildCloudtentaclesConfigPayload(),
code: cloudtentaclesForm.value.code.trim(),
} }
} }
@@ -142,8 +264,11 @@ export function useAdminCloudtentaclesPlatform() {
const response = await saveAdminCloudtentaclesSourceConfig(buildCloudtentaclesConfigPayload()) const response = await saveAdminCloudtentaclesSourceConfig(buildCloudtentaclesConfigPayload())
cloudtentaclesFilePath.value = response.data.filePath cloudtentaclesFilePath.value = response.data.filePath
cloudtentaclesSessionFilePath.value = response.data.sessionFilePath cloudtentaclesSessionFilePath.value = response.data.sessionFilePath
cloudtentaclesPersistedSession.value = response.data.session sources.value = response.data.sources
cloudtentaclesForm.value.token = response.data.session?.token || '' sessions.value = response.data.sessions
const session = sessions.value[selectedSourceKey.value]
cloudtentaclesPersistedSession.value = session || null
cloudtentaclesForm.value.token = session?.token || ''
showSuccess('cloudtentacles 履约平台配置已保存') showSuccess('cloudtentacles 履约平台配置已保存')
} catch (error) { } catch (error) {
cloudtentaclesResultError.value = cloudtentaclesResultError.value =
@@ -163,7 +288,7 @@ export function useAdminCloudtentaclesPlatform() {
cloudtentaclesResultError.value = '' cloudtentaclesResultError.value = ''
try { try {
const response = await sendAdminCloudtentaclesSmsCode(buildCloudtentaclesConfigPayload()) const response = await sendAdminCloudtentaclesSmsCode(buildCloudtentaclesSourcePayload())
cloudtentaclesSmsResult.value = response.data cloudtentaclesSmsResult.value = response.data
showSuccess('cloudtentacles 短信验证码已发送') showSuccess('cloudtentacles 短信验证码已发送')
} catch (error) { } catch (error) {
@@ -198,6 +323,8 @@ export function useAdminCloudtentaclesPlatform() {
deviceType: Number(cloudtentaclesForm.value.deviceType || 0), deviceType: Number(cloudtentaclesForm.value.deviceType || 0),
hasToken: Boolean(response.data.token), hasToken: Boolean(response.data.token),
} }
// Update sessions map
sessions.value[selectedSourceKey.value] = cloudtentaclesPersistedSession.value
showSuccess('cloudtentacles 登录测试成功') showSuccess('cloudtentacles 登录测试成功')
} catch (error) { } catch (error) {
cloudtentaclesResultError.value = cloudtentaclesResultError.value =
@@ -224,6 +351,7 @@ export function useAdminCloudtentaclesPlatform() {
token, token,
deviceId: cloudtentaclesForm.value.deviceId.trim() || '-', deviceId: cloudtentaclesForm.value.deviceId.trim() || '-',
deviceType: Number(cloudtentaclesForm.value.deviceType || 0), deviceType: Number(cloudtentaclesForm.value.deviceType || 0),
sourceKey: selectedSourceKey.value,
}) })
cloudtentaclesValidateResult.value = response.data cloudtentaclesValidateResult.value = response.data
cloudtentaclesPersistedSession.value = { cloudtentaclesPersistedSession.value = {
@@ -239,6 +367,8 @@ export function useAdminCloudtentaclesPlatform() {
deviceType: Number(cloudtentaclesForm.value.deviceType || 0), deviceType: Number(cloudtentaclesForm.value.deviceType || 0),
hasToken: Boolean(token), hasToken: Boolean(token),
} }
// Update sessions map
sessions.value[selectedSourceKey.value] = cloudtentaclesPersistedSession.value
showSuccess('cloudtentacles 会话校验成功') showSuccess('cloudtentacles 会话校验成功')
} catch (error) { } catch (error) {
cloudtentaclesResultError.value = cloudtentaclesResultError.value =
@@ -265,7 +395,16 @@ export function useAdminCloudtentaclesPlatform() {
cloudtentaclesDebugResult: debugActions.cloudtentaclesDebugResult, cloudtentaclesDebugResult: debugActions.cloudtentaclesDebugResult,
cloudtentaclesPersistedSession, cloudtentaclesPersistedSession,
cloudtentaclesStats, cloudtentaclesStats,
sources,
sessions,
selectedSourceKey,
sourceOptions,
currentSource,
currentSession,
hydrateCloudtentaclesConfig, hydrateCloudtentaclesConfig,
switchSource,
addSource,
removeSource,
handleCloudtentaclesSaveSource, handleCloudtentaclesSaveSource,
handleCloudtentaclesSendSmsCode, handleCloudtentaclesSendSmsCode,
handleCloudtentaclesTestLogin, handleCloudtentaclesTestLogin,
@@ -35,6 +35,7 @@ export type CloudtentaclesForm = {
export function useCloudtentaclesDebugActions( export function useCloudtentaclesDebugActions(
cloudtentaclesForm: { value: CloudtentaclesForm }, cloudtentaclesForm: { value: CloudtentaclesForm },
cloudtentaclesResultError: { value: string }, cloudtentaclesResultError: { value: string },
selectedSourceKey: { value: string },
) { ) {
const cloudtentaclesDebugLoading = ref(false) const cloudtentaclesDebugLoading = ref(false)
const cloudtentaclesDebugResult = ref('') const cloudtentaclesDebugResult = ref('')
@@ -45,6 +46,7 @@ export function useCloudtentaclesDebugActions(
token: cloudtentaclesForm.value.token.trim(), token: cloudtentaclesForm.value.token.trim(),
deviceId: cloudtentaclesForm.value.deviceId.trim() || '-', deviceId: cloudtentaclesForm.value.deviceId.trim() || '-',
deviceType: Number(cloudtentaclesForm.value.deviceType || 0), deviceType: Number(cloudtentaclesForm.value.deviceType || 0),
sourceKey: selectedSourceKey.value,
} }
} }