移除了 khhao 平台相关
This commit is contained in:
Vendored
-1
@@ -14,7 +14,6 @@ declare module 'vue' {
|
||||
AdminPaginationBar: typeof import('./components/admin/AdminPaginationBar.vue')['default']
|
||||
AdminPlatformAgisoSection: typeof import('./components/admin/AdminPlatformAgisoSection.vue')['default']
|
||||
AdminPlatformCloudtentaclesSection: typeof import('./components/admin/AdminPlatformCloudtentaclesSection.vue')['default']
|
||||
AdminPlatformKhhaoSection: typeof import('./components/admin/AdminPlatformKhhaoSection.vue')['default']
|
||||
AdminPlatformKuaishouEticketSection: typeof import('./components/admin/AdminPlatformKuaishouEticketSection.vue')['default']
|
||||
AdminPlatformNinetyoneSection: typeof import('./components/admin/AdminPlatformNinetyoneSection.vue')['default']
|
||||
AdminResultCard: typeof import('./components/admin/AdminResultCard.vue')['default']
|
||||
|
||||
@@ -31,7 +31,7 @@ defineProps<Props>()
|
||||
</div>
|
||||
<div class="meta-line">
|
||||
<span class="meta-label">职责</span>
|
||||
<span>管理 Agiso 默认消息模板、店铺 AccessToken 以及店铺级模板覆盖。该区域不处理 khhao 登录与拉单。</span>
|
||||
<span>管理 Agiso 默认消息模板、店铺 AccessToken 以及店铺级模板覆盖。</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import AdminResultCard from '@/components/admin/AdminResultCard.vue'
|
||||
import type {
|
||||
AdminKhhaoLoginTestResult,
|
||||
AdminKhhaoOrderQueryResult,
|
||||
AdminKhhaoOrderSyncResult,
|
||||
AdminKhhaoSyncState,
|
||||
} from '@/types/admin'
|
||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
||||
|
||||
type KhhaoForm = {
|
||||
baseUrl: string
|
||||
username: string
|
||||
password: string
|
||||
page: number
|
||||
limit: number
|
||||
maxCaptchaAttempts: number
|
||||
autoSyncEnabled: boolean
|
||||
autoSyncIntervalMinutes: number
|
||||
autoSyncPages: number
|
||||
autoSyncPageSize: number
|
||||
}
|
||||
|
||||
type Props = {
|
||||
khhaoFilePath: string
|
||||
khhaoStateFilePath: string
|
||||
khhaoForm: KhhaoForm
|
||||
khhaoSaving: boolean
|
||||
khhaoTesting: boolean
|
||||
khhaoQuerying: boolean
|
||||
khhaoSyncing: boolean
|
||||
khhaoResultError: string
|
||||
khhaoLoginResult: AdminKhhaoLoginTestResult | null
|
||||
khhaoQueryResult: AdminKhhaoOrderQueryResult | null
|
||||
khhaoSyncResult: AdminKhhaoOrderSyncResult | null
|
||||
khhaoAutoSyncState: AdminKhhaoSyncState | null
|
||||
handleKhhaoSaveSource: () => void | Promise<void>
|
||||
handleKhhaoTestLogin: () => void | Promise<void>
|
||||
handleKhhaoQueryOrders: () => void | Promise<void>
|
||||
handleKhhaoSyncOrders: () => void | Promise<void>
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="meta-card">
|
||||
<div class="meta-line">
|
||||
<span class="meta-label">配置文件</span>
|
||||
<code>{{ khhaoFilePath || '-' }}</code>
|
||||
</div>
|
||||
<div class="meta-line">
|
||||
<span class="meta-label">状态文件</span>
|
||||
<code>{{ khhaoStateFilePath || '-' }}</code>
|
||||
</div>
|
||||
<div class="meta-line">
|
||||
<span class="meta-label">职责</span>
|
||||
<span>管理 khhao 的来源地址、登录账号、密码与验证码重试次数,并执行测试登录、查询订单与手动同步。</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="table-card">
|
||||
<div class="section-title-row">
|
||||
<div>
|
||||
<h3>khhao 来源配置</h3>
|
||||
<p>先保存 khhao 凭据,再按需执行登录测试、订单查询或同步。履约规则请前往“履约配置”页处理。</p>
|
||||
</div>
|
||||
<div class="section-actions">
|
||||
<el-button :loading="khhaoSaving" round @click="handleKhhaoSaveSource">保存来源配置</el-button>
|
||||
<el-button :loading="khhaoTesting" round @click="handleKhhaoTestLogin">测试登录</el-button>
|
||||
<el-button :loading="khhaoQuerying" round @click="handleKhhaoQueryOrders">查询订单</el-button>
|
||||
<el-button :loading="khhaoSyncing" round type="primary" @click="handleKhhaoSyncOrders">同步订单</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-grid">
|
||||
<label class="field-block field-wide">
|
||||
<span>Base URL</span>
|
||||
<input v-model="khhaoForm.baseUrl" class="text-input" placeholder="https://admin.khhao.com" />
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>账号</span>
|
||||
<input v-model="khhaoForm.username" class="text-input" placeholder="khhao 登录账号" />
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>密码</span>
|
||||
<input v-model="khhaoForm.password" class="text-input" type="password" placeholder="khhao 登录密码" />
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>页码</span>
|
||||
<input v-model.number="khhaoForm.page" class="text-input" type="number" min="1" />
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>每页条数</span>
|
||||
<input v-model.number="khhaoForm.limit" class="text-input" type="number" min="1" max="50" />
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>验证码重试次数</span>
|
||||
<input v-model.number="khhaoForm.maxCaptchaAttempts" class="text-input" type="number" min="1" max="5" />
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>自动同步开关</span>
|
||||
<label class="checkbox-line checkbox-box">
|
||||
<input v-model="khhaoForm.autoSyncEnabled" type="checkbox" />
|
||||
<span>启用自动同步</span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>同步间隔(分钟)</span>
|
||||
<input v-model.number="khhaoForm.autoSyncIntervalMinutes" class="text-input" type="number" min="1" max="60" />
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>同步页数</span>
|
||||
<input v-model.number="khhaoForm.autoSyncPages" class="text-input" type="number" min="1" max="5" />
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>每页条数</span>
|
||||
<input v-model.number="khhaoForm.autoSyncPageSize" class="text-input" type="number" min="1" max="50" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<p v-if="khhaoResultError" class="error-copy">{{ khhaoResultError }}</p>
|
||||
|
||||
<div class="result-grid">
|
||||
<AdminResultCard label="登录结果" :value="khhaoLoginResult ? '成功' : '未执行'">
|
||||
<p v-if="khhaoLoginResult">
|
||||
第 {{ khhaoLoginResult.attempt }} 次成功,验证码识别 {{ khhaoLoginResult.captcha.recognizedText || '-' }},
|
||||
{{ formatAdminDateTime(khhaoLoginResult.loggedInAt) }}
|
||||
</p>
|
||||
<p v-else>可先点击“测试登录”验证账号密码与 OCR。</p>
|
||||
</AdminResultCard>
|
||||
|
||||
<AdminResultCard label="查询结果" :value="`${khhaoQueryResult?.itemCount || 0} 条`">
|
||||
<p v-if="khhaoQueryResult">当前页 {{ khhaoQueryResult.page }} / 总计 {{ khhaoQueryResult.total }} 条</p>
|
||||
<p v-else>可先点击“查询订单”验证拉单链路。</p>
|
||||
</AdminResultCard>
|
||||
|
||||
<AdminResultCard label="同步结果" :value="`${khhaoSyncResult?.syncedCount || 0} 条`">
|
||||
<p v-if="khhaoSyncResult">忽略 {{ khhaoSyncResult.ignoredCount }} 条,拉取 {{ khhaoSyncResult.fetchedCount }} 条</p>
|
||||
<p v-else>完成履约配置后可在这里手动同步。</p>
|
||||
</AdminResultCard>
|
||||
</div>
|
||||
|
||||
<div v-if="khhaoAutoSyncState" class="meta-card compact-meta">
|
||||
<div class="meta-line">
|
||||
<span class="meta-label">自动同步状态</span>
|
||||
<span>{{ khhaoAutoSyncState.lastRunStatus || 'idle' }}</span>
|
||||
</div>
|
||||
<div class="meta-line">
|
||||
<span class="meta-label">当前节奏</span>
|
||||
<span>{{ khhaoAutoSyncState.watchMode === 'boosted' ? '提频观察中(3-5 秒)' : '常规同步' }}</span>
|
||||
</div>
|
||||
<div class="meta-line">
|
||||
<span class="meta-label">同步基线</span>
|
||||
<span>{{ formatAdminDateTime(khhaoAutoSyncState.syncFromCreatedAt) }}</span>
|
||||
</div>
|
||||
<div class="meta-line">
|
||||
<span class="meta-label">最近开始</span>
|
||||
<span>{{ formatAdminDateTime(khhaoAutoSyncState.lastRunStartedAt) }}</span>
|
||||
</div>
|
||||
<div class="meta-line">
|
||||
<span class="meta-label">最近完成</span>
|
||||
<span>{{ formatAdminDateTime(khhaoAutoSyncState.lastRunFinishedAt) }}</span>
|
||||
</div>
|
||||
<div class="meta-line">
|
||||
<span class="meta-label">最近结果</span>
|
||||
<span>拉取 {{ khhaoAutoSyncState.fetchedCount }} 条,成功 {{ khhaoAutoSyncState.syncedCount }} 条,忽略 {{ khhaoAutoSyncState.ignoredCount }} 条</span>
|
||||
</div>
|
||||
<div v-if="khhaoAutoSyncState.watchOrders.length > 0" class="meta-line">
|
||||
<span class="meta-label">观察订单</span>
|
||||
<span>{{ khhaoAutoSyncState.watchOrders.map((item) => `${item.shopName || item.shopId || '-'} / ${item.platformOrderId}`).join(';') }}</span>
|
||||
</div>
|
||||
<div v-if="khhaoAutoSyncState.lastErrorMessage" class="meta-line">
|
||||
<span class="meta-label">最近错误</span>
|
||||
<span class="error-copy">{{ khhaoAutoSyncState.lastErrorMessage }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-if="khhaoQueryResult" class="table-card">
|
||||
<div class="section-title-row">
|
||||
<div>
|
||||
<h3>khhao 查询结果</h3>
|
||||
<p>当前页 {{ khhaoQueryResult.page }},本页 {{ khhaoQueryResult.itemCount }} 条,总数 {{ khhaoQueryResult.total }}。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>订单</th>
|
||||
<th>店铺</th>
|
||||
<th>商品</th>
|
||||
<th>金额</th>
|
||||
<th>状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in khhaoQueryResult.items" :key="`${item.platformOrderId}:${item.skuCode}:${item.itemId}`">
|
||||
<td>
|
||||
<div class="cell-stack">
|
||||
<strong>{{ item.platformOrderId }}</strong>
|
||||
<span class="cell-subtle">{{ item.platformLabel || item.platform || '-' }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="cell-stack">
|
||||
<strong>{{ item.shopName || item.shopId || '-' }}</strong>
|
||||
<span class="cell-subtle">ID: {{ item.shopId || '-' }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="cell-stack">
|
||||
<strong>{{ item.itemTitle || '-' }}</strong>
|
||||
<span class="cell-subtle">SKU: {{ item.skuCode || '-' }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ (item.totalAmountFen / 100).toFixed(2) }}</td>
|
||||
<td>{{ item.statusLabel || item.status || '-' }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section v-if="khhaoSyncResult" class="table-card">
|
||||
<div class="section-title-row">
|
||||
<div>
|
||||
<h3>khhao 同步结果</h3>
|
||||
<p>拉取 {{ khhaoSyncResult.fetchedCount }} 条,成功 {{ khhaoSyncResult.syncedCount }} 条,忽略 {{ khhaoSyncResult.ignoredCount }} 条。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>订单</th>
|
||||
<th>店铺</th>
|
||||
<th>商品</th>
|
||||
<th>结果</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in khhaoSyncResult.results" :key="`${item.platformOrderId}:${item.skuCode}`">
|
||||
<td>{{ item.platformOrderId }}</td>
|
||||
<td>{{ item.shopId || '-' }}</td>
|
||||
<td>{{ item.itemTitle || item.skuCode || '-' }}</td>
|
||||
<td>
|
||||
<span v-if="item.ignored">已忽略:{{ item.ignoreReason || '-' }}</span>
|
||||
<span v-else>已入库,订单 {{ item.orderId || '-' }},任务 {{ item.taskCount }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</template>
|
||||
@@ -1,4 +1,4 @@
|
||||
export type PlatformTab = 'agiso' | 'khhao' | 'ninetyone' | 'kuaishouEticket' | 'cloudtentacles'
|
||||
export type PlatformTab = 'agiso' | 'ninetyone' | 'kuaishouEticket' | 'cloudtentacles'
|
||||
|
||||
export type EditableDefaults = {
|
||||
messageTemplate: string
|
||||
|
||||
@@ -1,215 +0,0 @@
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { showError, showSuccess } from '@/lib/feedback'
|
||||
import {
|
||||
queryAdminKhhaoOrders,
|
||||
saveAdminKhhaoSourceConfig,
|
||||
syncAdminKhhaoOrders,
|
||||
testAdminKhhaoLogin,
|
||||
} from '@/services/admin'
|
||||
import type {
|
||||
AdminKhhaoLoginTestResult,
|
||||
AdminKhhaoOrderQueryResult,
|
||||
AdminKhhaoOrderSyncResult,
|
||||
AdminKhhaoSyncState,
|
||||
} from '@/types/admin'
|
||||
|
||||
export function useAdminKhhaoPlatform() {
|
||||
const khhaoFilePath = ref('')
|
||||
const khhaoStateFilePath = ref('')
|
||||
const khhaoForm = ref({
|
||||
baseUrl: 'https://admin.khhao.com',
|
||||
username: '',
|
||||
password: '',
|
||||
page: 1,
|
||||
limit: 10,
|
||||
maxCaptchaAttempts: 3,
|
||||
autoSyncEnabled: false,
|
||||
autoSyncIntervalMinutes: 3,
|
||||
autoSyncPages: 2,
|
||||
autoSyncPageSize: 20,
|
||||
})
|
||||
const khhaoSaving = ref(false)
|
||||
const khhaoTesting = ref(false)
|
||||
const khhaoQuerying = ref(false)
|
||||
const khhaoSyncing = ref(false)
|
||||
const khhaoResultError = ref('')
|
||||
const khhaoLoginResult = ref<AdminKhhaoLoginTestResult | null>(null)
|
||||
const khhaoQueryResult = ref<AdminKhhaoOrderQueryResult | null>(null)
|
||||
const khhaoSyncResult = ref<AdminKhhaoOrderSyncResult | null>(null)
|
||||
const khhaoAutoSyncState = ref<AdminKhhaoSyncState | null>(null)
|
||||
|
||||
const khhaoStats = computed(() => ({
|
||||
hasCredential: Boolean(khhaoForm.value.username.trim() && khhaoForm.value.password.trim()),
|
||||
queryCount: khhaoQueryResult.value?.itemCount || 0,
|
||||
syncedCount: khhaoAutoSyncState.value?.syncedCount || khhaoSyncResult.value?.syncedCount || 0,
|
||||
ignoredCount: khhaoAutoSyncState.value?.ignoredCount || khhaoSyncResult.value?.ignoredCount || 0,
|
||||
}))
|
||||
|
||||
function hydrateKhhaoConfig(data: {
|
||||
filePath: string
|
||||
stateFilePath: string
|
||||
syncState: AdminKhhaoSyncState
|
||||
source: {
|
||||
baseUrl?: string
|
||||
username?: string
|
||||
password?: string
|
||||
maxCaptchaAttempts?: number
|
||||
autoSync?: {
|
||||
enabled?: boolean
|
||||
intervalMinutes?: number
|
||||
pages?: number
|
||||
pageSize?: number
|
||||
}
|
||||
}
|
||||
}) {
|
||||
khhaoFilePath.value = data.filePath
|
||||
khhaoStateFilePath.value = data.stateFilePath
|
||||
khhaoAutoSyncState.value = data.syncState
|
||||
khhaoForm.value = {
|
||||
baseUrl: data.source.baseUrl || 'https://admin.khhao.com',
|
||||
username: data.source.username || '',
|
||||
password: data.source.password || '',
|
||||
page: 1,
|
||||
limit: 10,
|
||||
maxCaptchaAttempts: data.source.maxCaptchaAttempts || 3,
|
||||
autoSyncEnabled: data.source.autoSync?.enabled === true,
|
||||
autoSyncIntervalMinutes: data.source.autoSync?.intervalMinutes || 3,
|
||||
autoSyncPages: data.source.autoSync?.pages || 2,
|
||||
autoSyncPageSize: data.source.autoSync?.pageSize || 20,
|
||||
}
|
||||
}
|
||||
|
||||
function buildKhhaoPayload() {
|
||||
return {
|
||||
baseUrl: khhaoForm.value.baseUrl.trim() || 'https://admin.khhao.com',
|
||||
username: khhaoForm.value.username.trim(),
|
||||
password: khhaoForm.value.password.trim(),
|
||||
page: Number(khhaoForm.value.page || 1),
|
||||
limit: Number(khhaoForm.value.limit || 10),
|
||||
maxCaptchaAttempts: Number(khhaoForm.value.maxCaptchaAttempts || 3),
|
||||
}
|
||||
}
|
||||
|
||||
function ensureKhhaoCredentials() {
|
||||
if (!khhaoForm.value.username.trim() || !khhaoForm.value.password.trim()) {
|
||||
khhaoResultError.value = '请先填写 khhao 账号和密码'
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async function handleKhhaoSaveSource() {
|
||||
khhaoSaving.value = true
|
||||
khhaoResultError.value = ''
|
||||
|
||||
try {
|
||||
const response = await saveAdminKhhaoSourceConfig({
|
||||
enabled: true,
|
||||
baseUrl: khhaoForm.value.baseUrl.trim() || 'https://admin.khhao.com',
|
||||
username: khhaoForm.value.username.trim(),
|
||||
password: khhaoForm.value.password.trim(),
|
||||
maxCaptchaAttempts: Number(khhaoForm.value.maxCaptchaAttempts || 3),
|
||||
autoSync: {
|
||||
enabled: Boolean(khhaoForm.value.autoSyncEnabled),
|
||||
intervalMinutes: Number(khhaoForm.value.autoSyncIntervalMinutes || 3),
|
||||
pages: Number(khhaoForm.value.autoSyncPages || 2),
|
||||
pageSize: Number(khhaoForm.value.autoSyncPageSize || 20),
|
||||
},
|
||||
})
|
||||
khhaoFilePath.value = response.data.filePath
|
||||
khhaoStateFilePath.value = response.data.stateFilePath
|
||||
khhaoAutoSyncState.value = response.data.syncState
|
||||
showSuccess('khhao 来源配置已保存')
|
||||
} catch (error) {
|
||||
khhaoResultError.value = error instanceof Error ? error.message : 'khhao 来源配置保存失败'
|
||||
showError(khhaoResultError.value)
|
||||
} finally {
|
||||
khhaoSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleKhhaoTestLogin() {
|
||||
if (!ensureKhhaoCredentials()) {
|
||||
return
|
||||
}
|
||||
|
||||
khhaoTesting.value = true
|
||||
khhaoResultError.value = ''
|
||||
|
||||
try {
|
||||
const response = await testAdminKhhaoLogin({
|
||||
...buildKhhaoPayload(),
|
||||
includeImageBase64: false,
|
||||
})
|
||||
khhaoLoginResult.value = response.data
|
||||
showSuccess('khhao 登录测试成功')
|
||||
} catch (error) {
|
||||
khhaoResultError.value = error instanceof Error ? error.message : 'khhao 登录测试失败'
|
||||
showError(khhaoResultError.value)
|
||||
} finally {
|
||||
khhaoTesting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleKhhaoQueryOrders() {
|
||||
if (!ensureKhhaoCredentials()) {
|
||||
return
|
||||
}
|
||||
|
||||
khhaoQuerying.value = true
|
||||
khhaoResultError.value = ''
|
||||
|
||||
try {
|
||||
const response = await queryAdminKhhaoOrders(buildKhhaoPayload())
|
||||
khhaoQueryResult.value = response.data
|
||||
showSuccess(`khhao 订单查询成功,共返回 ${response.data.itemCount} 条`)
|
||||
} catch (error) {
|
||||
khhaoResultError.value = error instanceof Error ? error.message : 'khhao 订单查询失败'
|
||||
showError(khhaoResultError.value)
|
||||
} finally {
|
||||
khhaoQuerying.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleKhhaoSyncOrders() {
|
||||
if (!ensureKhhaoCredentials()) {
|
||||
return
|
||||
}
|
||||
|
||||
khhaoSyncing.value = true
|
||||
khhaoResultError.value = ''
|
||||
|
||||
try {
|
||||
const response = await syncAdminKhhaoOrders(buildKhhaoPayload())
|
||||
khhaoSyncResult.value = response.data
|
||||
showSuccess(`khhao 同步完成:拉取 ${response.data.fetchedCount} 条,成功 ${response.data.syncedCount} 条`)
|
||||
} catch (error) {
|
||||
khhaoResultError.value = error instanceof Error ? error.message : 'khhao 订单同步失败'
|
||||
showError(khhaoResultError.value)
|
||||
} finally {
|
||||
khhaoSyncing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
khhaoFilePath,
|
||||
khhaoStateFilePath,
|
||||
khhaoForm,
|
||||
khhaoSaving,
|
||||
khhaoTesting,
|
||||
khhaoQuerying,
|
||||
khhaoSyncing,
|
||||
khhaoResultError,
|
||||
khhaoLoginResult,
|
||||
khhaoQueryResult,
|
||||
khhaoSyncResult,
|
||||
khhaoAutoSyncState,
|
||||
khhaoStats,
|
||||
hydrateKhhaoConfig,
|
||||
handleKhhaoSaveSource,
|
||||
handleKhhaoTestLogin,
|
||||
handleKhhaoQueryOrders,
|
||||
handleKhhaoSyncOrders,
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,6 @@ import type {
|
||||
AdminCloudtentaclesValidateSessionResult,
|
||||
AdminFulfillmentBindingConfigItem,
|
||||
AdminFulfillmentLookupResult,
|
||||
AdminKhhaoLoginTestResult,
|
||||
AdminKhhaoOrderQueryResult,
|
||||
AdminKhhaoOrderSyncResult,
|
||||
AdminKhhaoSourceConfig,
|
||||
AdminKhhaoSyncState,
|
||||
AdminNinetyoneOrderActionResult,
|
||||
AdminNinetyoneOrderListResult,
|
||||
AdminKuaishouCloudFulfillmentConfig,
|
||||
@@ -46,56 +41,6 @@ export function saveAdminAgisoShopConfigs(payload: {
|
||||
}>('/api/v1/admin/platform-config/agiso-shops', payload)
|
||||
}
|
||||
|
||||
export function fetchAdminKhhaoSourceConfig() {
|
||||
return apiGet<{
|
||||
filePath: string
|
||||
source: AdminKhhaoSourceConfig
|
||||
stateFilePath: string
|
||||
syncState: AdminKhhaoSyncState
|
||||
}>('/api/v1/admin/platform-config/khhao-source')
|
||||
}
|
||||
|
||||
export function saveAdminKhhaoSourceConfig(payload: AdminKhhaoSourceConfig) {
|
||||
return apiPost<{
|
||||
filePath: string
|
||||
source: AdminKhhaoSourceConfig
|
||||
stateFilePath: string
|
||||
syncState: AdminKhhaoSyncState
|
||||
}>('/api/v1/admin/platform-config/khhao-source', payload as unknown as Record<string, unknown>)
|
||||
}
|
||||
|
||||
export function testAdminKhhaoLogin(payload: {
|
||||
baseUrl?: string
|
||||
username: string
|
||||
password: string
|
||||
maxCaptchaAttempts?: number
|
||||
includeImageBase64?: boolean
|
||||
}) {
|
||||
return apiPost<AdminKhhaoLoginTestResult>('/api/v1/admin/platform-config/khhao/test-login', payload)
|
||||
}
|
||||
|
||||
export function queryAdminKhhaoOrders(payload: {
|
||||
baseUrl?: string
|
||||
username: string
|
||||
password: string
|
||||
page?: number
|
||||
limit?: number
|
||||
maxCaptchaAttempts?: number
|
||||
}) {
|
||||
return apiPost<AdminKhhaoOrderQueryResult>('/api/v1/admin/platform-config/khhao/query-orders', payload)
|
||||
}
|
||||
|
||||
export function syncAdminKhhaoOrders(payload: {
|
||||
baseUrl?: string
|
||||
username: string
|
||||
password: string
|
||||
page?: number
|
||||
limit?: number
|
||||
maxCaptchaAttempts?: number
|
||||
}) {
|
||||
return apiPost<AdminKhhaoOrderSyncResult>('/api/v1/admin/platform-config/khhao/sync-orders', payload)
|
||||
}
|
||||
|
||||
export function fetchAdminNinetyoneOrders(params: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
|
||||
@@ -80,37 +80,6 @@ export interface AdminAgisoObservedShopItem {
|
||||
configured: boolean
|
||||
}
|
||||
|
||||
export interface AdminKhhaoLoginTestResult {
|
||||
baseUrl: string
|
||||
username: string
|
||||
loggedInAt: string
|
||||
attempt: number
|
||||
responseMessage: string
|
||||
captcha: {
|
||||
recognizedText: string
|
||||
imageBase64: string
|
||||
}
|
||||
session: {
|
||||
cookieKeys: string[]
|
||||
cookieCount: number
|
||||
cookieHeaderMasked: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface AdminKhhaoSourceConfig {
|
||||
enabled: boolean
|
||||
baseUrl: string
|
||||
username: string
|
||||
password: string
|
||||
maxCaptchaAttempts: number
|
||||
autoSync: {
|
||||
enabled: boolean
|
||||
intervalMinutes: number
|
||||
pages: number
|
||||
pageSize: number
|
||||
}
|
||||
}
|
||||
|
||||
export interface AdminKuaishouEticketSourceConfig {
|
||||
enabled: boolean
|
||||
baseUrl: string
|
||||
@@ -195,82 +164,6 @@ export interface AdminKuaishouEticketConsumeResult {
|
||||
raw: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface AdminKhhaoSyncState {
|
||||
syncFromCreatedAt: string
|
||||
lastRunStartedAt: string
|
||||
lastRunFinishedAt: string
|
||||
lastRunStatus: string
|
||||
lastErrorMessage: string
|
||||
fetchedCount: number
|
||||
syncedCount: number
|
||||
ignoredCount: number
|
||||
watchMode: string
|
||||
watchOrders: Array<{
|
||||
platformOrderId: string
|
||||
shopId: string
|
||||
shopName: string
|
||||
itemTitle: string
|
||||
payStatus: string
|
||||
detectedAt: string
|
||||
lastSeenAt: string
|
||||
}>
|
||||
}
|
||||
|
||||
export interface AdminKhhaoOrderPreview {
|
||||
provider: string
|
||||
platform: string
|
||||
platformLabel: string
|
||||
platformOrderId: string
|
||||
shopId: string
|
||||
kuaishouShopId: string
|
||||
khhaoShopId: string
|
||||
shopName: string
|
||||
itemId: string
|
||||
itemTitle: string
|
||||
skuCode: string
|
||||
quantity: number
|
||||
totalAmountFen: number
|
||||
status: string
|
||||
statusLabel: string
|
||||
orderCreatedAt: string
|
||||
raw: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface AdminKhhaoOrderQueryResult {
|
||||
baseUrl: string
|
||||
page: number
|
||||
limit: number
|
||||
total: number
|
||||
itemCount: number
|
||||
items: AdminKhhaoOrderPreview[]
|
||||
rawItems: Record<string, unknown>[]
|
||||
}
|
||||
|
||||
export interface AdminKhhaoOrderSyncItem {
|
||||
platformOrderId: string
|
||||
provider: string
|
||||
platform: string
|
||||
shopId: string
|
||||
skuCode: string
|
||||
itemTitle: string
|
||||
ignored: boolean
|
||||
ignoreReason: string
|
||||
orderId: number | null
|
||||
orderItemCount: number
|
||||
taskCount: number
|
||||
}
|
||||
|
||||
export interface AdminKhhaoOrderSyncResult {
|
||||
baseUrl: string
|
||||
page: number
|
||||
limit: number
|
||||
total: number
|
||||
fetchedCount: number
|
||||
syncedCount: number
|
||||
ignoredCount: number
|
||||
results: AdminKhhaoOrderSyncItem[]
|
||||
}
|
||||
|
||||
export interface AdminNinetyoneOrderItem {
|
||||
orderId: number
|
||||
orderNo: string
|
||||
@@ -389,7 +282,6 @@ export interface AdminFulfillmentBindingConfigItem {
|
||||
platform: string
|
||||
shopId: string
|
||||
shopName: string
|
||||
khhaoShopId: string
|
||||
skuCode: string
|
||||
skuName: string
|
||||
profileKey: string
|
||||
@@ -411,7 +303,6 @@ export interface AdminKuaishouCloudFulfillmentItem {
|
||||
provider: string
|
||||
platform: string
|
||||
shopId: string
|
||||
khhaoShopId: string
|
||||
internalSkuCode: string
|
||||
internalSkuName: string
|
||||
externalSkuCode: string
|
||||
|
||||
@@ -4,7 +4,6 @@ import { computed, nextTick, onMounted, reactive, ref } from 'vue'
|
||||
import { showSuccess } from '@/lib/feedback'
|
||||
import {
|
||||
fetchAdminFulfillmentBindingConfigs,
|
||||
fetchAdminKuaishouEticketSourceConfig,
|
||||
lookupAdminFulfillmentBindingOrder,
|
||||
saveAdminFulfillmentBindingConfigs,
|
||||
} from '@/services/admin'
|
||||
@@ -12,7 +11,6 @@ import type {
|
||||
AdminFulfillmentBindingConfigItem,
|
||||
AdminFulfillmentLookupItem,
|
||||
AdminFulfillmentLookupResult,
|
||||
AdminKuaishouEticketShopConfigItem,
|
||||
AdminObservedProductItem,
|
||||
} from '@/types/admin'
|
||||
import { hasAdminRole } from '@/utils/admin-auth'
|
||||
@@ -24,7 +22,6 @@ type EditableBinding = {
|
||||
platform: string
|
||||
shopId: string
|
||||
shopName: string
|
||||
khhaoShopId: string
|
||||
skuCode: string
|
||||
skuName: string
|
||||
profileKey: string
|
||||
@@ -41,7 +38,6 @@ type SaveBindingPayload = {
|
||||
platform: string
|
||||
shopId: string
|
||||
shopName: string
|
||||
khhaoShopId: string
|
||||
skuCode: string
|
||||
skuName: string
|
||||
profileKey: string
|
||||
@@ -57,7 +53,7 @@ type SaveBindingPayload = {
|
||||
}
|
||||
}
|
||||
|
||||
type ValidationField = 'skuCode' | 'match' | 'profileKey' | 'shopId' | 'khhaoShopId'
|
||||
type ValidationField = 'skuCode' | 'match' | 'profileKey' | 'shopId'
|
||||
|
||||
type ValidationState = {
|
||||
bindingId: string
|
||||
@@ -78,7 +74,6 @@ const errorMessage = ref('')
|
||||
const filePath = ref('')
|
||||
const bindings = ref<EditableBinding[]>([])
|
||||
const observedProducts = ref<AdminObservedProductItem[]>([])
|
||||
const kuaishouShopOptions = ref<AdminKuaishouEticketShopConfigItem[]>([])
|
||||
const lookupLoading = ref(false)
|
||||
const lookupErrorMessage = ref('')
|
||||
const lookupResult = ref<AdminFulfillmentLookupResult | null>(null)
|
||||
@@ -113,7 +108,6 @@ type ImportableProductCandidate = Pick<
|
||||
AdminObservedProductItem,
|
||||
'provider' | 'platform' | 'shopId' | 'shopName' | 'externalSkuCode' | 'externalItemId' | 'externalSkuName'
|
||||
> & {
|
||||
khhaoShopId?: string
|
||||
}
|
||||
|
||||
function createEmptyBinding(): EditableBinding {
|
||||
@@ -123,7 +117,6 @@ function createEmptyBinding(): EditableBinding {
|
||||
platform: '',
|
||||
shopId: '',
|
||||
shopName: '',
|
||||
khhaoShopId: '',
|
||||
skuCode: '',
|
||||
skuName: '',
|
||||
profileKey: 'manual_review',
|
||||
@@ -137,14 +130,12 @@ function createEmptyBinding(): EditableBinding {
|
||||
}
|
||||
|
||||
function mapEditableBinding(item: AdminFulfillmentBindingConfigItem): EditableBinding {
|
||||
const matchedShop = resolveKuaishouShopById(item.shopId) || resolveKuaishouShopByName(item.shopName || '')
|
||||
const binding = {
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
provider: item.provider || 'agiso',
|
||||
platform: item.platform,
|
||||
shopId: matchedShop?.shopId || item.shopId,
|
||||
shopName: item.shopName || matchedShop?.kshopName || '',
|
||||
khhaoShopId: item.khhaoShopId || '',
|
||||
shopId: item.shopId,
|
||||
shopName: item.shopName || '',
|
||||
skuCode: item.skuCode,
|
||||
skuName: item.skuName,
|
||||
profileKey: item.profileKey || 'manual_review',
|
||||
@@ -155,9 +146,6 @@ function mapEditableBinding(item: AdminFulfillmentBindingConfigItem): EditableBi
|
||||
externalSkuName: item.match.externalSkuName,
|
||||
resolvedSkuName: String(item.match.config?.resolvedSkuName || ''),
|
||||
}
|
||||
|
||||
syncBindingShopSelection(binding)
|
||||
return binding
|
||||
}
|
||||
|
||||
function hasMatchCondition(item: Pick<EditableBinding, 'externalSkuCode' | 'externalItemId' | 'externalSkuName'>) {
|
||||
@@ -205,64 +193,16 @@ function getBindingStatusLabel(binding: EditableBinding) {
|
||||
}
|
||||
|
||||
function getBindingSummary(binding: EditableBinding) {
|
||||
const shopLabel = isKhhaoKuaishouBinding(binding)
|
||||
? [
|
||||
binding.shopName.trim() || binding.shopId.trim() || '未选快手店铺',
|
||||
binding.khhaoShopId.trim() ? `khhao#${binding.khhaoShopId.trim()}` : '',
|
||||
].filter(Boolean).join(' / ')
|
||||
: (binding.shopName.trim() || binding.shopId.trim() || '跨店铺')
|
||||
const parts = [
|
||||
binding.provider.trim() || 'agiso',
|
||||
binding.platform.trim() || '未选平台',
|
||||
shopLabel,
|
||||
binding.shopName.trim() || binding.shopId.trim() || '跨店铺',
|
||||
binding.profileKey.trim() || 'manual_review',
|
||||
]
|
||||
|
||||
return parts.join(' / ')
|
||||
}
|
||||
|
||||
function isKhhaoKuaishouBinding(binding: Pick<EditableBinding, 'provider' | 'platform'>) {
|
||||
return binding.provider.trim() === 'khhao' && binding.platform.trim() === 'kuaishou'
|
||||
}
|
||||
|
||||
function resolveKuaishouShopById(shopId: string) {
|
||||
const normalizedShopId = shopId.trim()
|
||||
return kuaishouShopOptions.value.find((item) => item.shopId === normalizedShopId) || null
|
||||
}
|
||||
|
||||
function resolveKuaishouShopByName(shopName: string) {
|
||||
const normalizedShopName = shopName.trim()
|
||||
return kuaishouShopOptions.value.find((item) => item.kshopName === normalizedShopName) || null
|
||||
}
|
||||
|
||||
function getKuaishouShopOptionLabel(item: AdminKuaishouEticketShopConfigItem) {
|
||||
return item.kshopName.trim()
|
||||
? `${item.kshopName} (${item.shopId})`
|
||||
: item.shopId
|
||||
}
|
||||
|
||||
function syncBindingShopSelection(binding: EditableBinding) {
|
||||
if (!isKhhaoKuaishouBinding(binding)) {
|
||||
return
|
||||
}
|
||||
|
||||
const matchedById = resolveKuaishouShopById(binding.shopId)
|
||||
if (matchedById) {
|
||||
binding.shopId = matchedById.shopId
|
||||
binding.shopName = matchedById.kshopName
|
||||
return
|
||||
}
|
||||
|
||||
const matchedByName = resolveKuaishouShopByName(binding.shopName)
|
||||
if (matchedByName) {
|
||||
binding.shopId = matchedByName.shopId
|
||||
binding.shopName = matchedByName.kshopName
|
||||
return
|
||||
}
|
||||
|
||||
binding.shopId = ''
|
||||
}
|
||||
|
||||
async function loadConfigs() {
|
||||
if (!hasAdminRole('admin')) {
|
||||
loading.value = false
|
||||
@@ -273,12 +213,8 @@ async function loadConfigs() {
|
||||
errorMessage.value = ''
|
||||
|
||||
try {
|
||||
const [response, kuaishouSourceResponse] = await Promise.all([
|
||||
fetchAdminFulfillmentBindingConfigs(),
|
||||
fetchAdminKuaishouEticketSourceConfig(),
|
||||
])
|
||||
const response = await fetchAdminFulfillmentBindingConfigs()
|
||||
filePath.value = response.data.filePath
|
||||
kuaishouShopOptions.value = kuaishouSourceResponse.data.source.shops.filter((item) => item.enabled !== false)
|
||||
const nextBindings = response.data.bindings.map(mapEditableBinding)
|
||||
bindings.value = nextBindings
|
||||
collapsedBindingIds.value = buildCollapsedIds(nextBindings)
|
||||
@@ -312,7 +248,6 @@ function createBindingFromProductCandidate(item: ImportableProductCandidate): Ed
|
||||
platform: item.platform,
|
||||
shopId: item.shopId,
|
||||
shopName: item.shopName,
|
||||
khhaoShopId: item.khhaoShopId || '',
|
||||
skuCode: '',
|
||||
skuName: item.externalSkuName,
|
||||
profileKey: 'manual_review',
|
||||
@@ -324,7 +259,6 @@ function createBindingFromProductCandidate(item: ImportableProductCandidate): Ed
|
||||
resolvedSkuName: item.externalSkuName,
|
||||
}
|
||||
|
||||
syncBindingShopSelection(binding)
|
||||
return binding
|
||||
}
|
||||
|
||||
@@ -347,14 +281,11 @@ function isLookupProductImported(lineId: string) {
|
||||
}
|
||||
|
||||
function normalizeBindingForSave(item: EditableBinding): SaveBindingPayload {
|
||||
syncBindingShopSelection(item)
|
||||
|
||||
return {
|
||||
provider: item.provider.trim() || 'agiso',
|
||||
platform: item.platform.trim(),
|
||||
shopId: item.shopId.trim(),
|
||||
shopName: item.shopName.trim(),
|
||||
khhaoShopId: item.khhaoShopId.trim(),
|
||||
skuCode: item.skuCode.trim(),
|
||||
skuName: item.skuName.trim(),
|
||||
profileKey: item.profileKey.trim() || 'manual_review',
|
||||
@@ -376,7 +307,6 @@ function hasBindingContent(item: SaveBindingPayload) {
|
||||
item.platform
|
||||
|| item.shopId
|
||||
|| item.shopName
|
||||
|| item.khhaoShopId
|
||||
|| item.skuCode
|
||||
|| item.skuName
|
||||
|| item.match.externalSkuCode
|
||||
@@ -392,24 +322,6 @@ function hasBindingContent(item: SaveBindingPayload) {
|
||||
|
||||
function resolveBindingValidationState(item: SaveBindingPayload, index: number, bindingId: string): ValidationState {
|
||||
const label = `第 ${index + 1} 条规则`
|
||||
const provider = item.provider.trim() || 'agiso'
|
||||
const platform = item.platform.trim()
|
||||
|
||||
if (provider === 'khhao' && platform === 'kuaishou' && (!item.shopId || !item.shopName)) {
|
||||
return {
|
||||
bindingId,
|
||||
field: 'shopId',
|
||||
message: `${label} 需要选择已配置的快手官方店铺`,
|
||||
}
|
||||
}
|
||||
|
||||
if (provider === 'khhao' && platform === 'kuaishou' && !item.khhaoShopId) {
|
||||
return {
|
||||
bindingId,
|
||||
field: 'khhaoShopId',
|
||||
message: `${label} 需要填写 khhao 店铺 ID`,
|
||||
}
|
||||
}
|
||||
|
||||
if (!item.skuCode) {
|
||||
return {
|
||||
@@ -454,7 +366,6 @@ async function focusValidationTarget(state: ValidationState) {
|
||||
card.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
||||
|
||||
const selectors: Record<ValidationField, string> = {
|
||||
khhaoShopId: '[data-field="khhaoShopId"]',
|
||||
shopId: '[data-field="shopId"]',
|
||||
skuCode: '[data-field="skuCode"]',
|
||||
match: '[data-field="externalSkuCode"]',
|
||||
@@ -485,16 +396,6 @@ function isFieldInvalid(bindingId: string, field: ValidationField | 'externalSku
|
||||
return validationState.value.field === field
|
||||
}
|
||||
|
||||
function handleBindingProviderPlatformChange(binding: EditableBinding) {
|
||||
syncBindingShopSelection(binding)
|
||||
clearValidationState()
|
||||
}
|
||||
|
||||
function handleKuaishouShopChange(binding: EditableBinding) {
|
||||
syncBindingShopSelection(binding)
|
||||
clearValidationState()
|
||||
}
|
||||
|
||||
async function saveConfigs() {
|
||||
const normalizedBindings = bindings.value.map(normalizeBindingForSave)
|
||||
const nonEmptyBindings = normalizedBindings.filter(hasBindingContent)
|
||||
@@ -694,7 +595,7 @@ onMounted(loadConfigs)
|
||||
v-model="binding.provider"
|
||||
class="text-input"
|
||||
placeholder="agiso"
|
||||
@input="handleBindingProviderPlatformChange(binding)"
|
||||
@input="clearValidationState"
|
||||
/>
|
||||
</label>
|
||||
|
||||
@@ -704,76 +605,30 @@ onMounted(loadConfigs)
|
||||
v-model="binding.platform"
|
||||
class="text-input"
|
||||
placeholder="xianyu / taobao / pdd"
|
||||
@input="handleBindingProviderPlatformChange(binding)"
|
||||
@input="clearValidationState"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<template v-if="isKhhaoKuaishouBinding(binding)">
|
||||
<label class="field-block">
|
||||
<span>khhao 店铺 ID</span>
|
||||
<input
|
||||
v-model="binding.khhaoShopId"
|
||||
:class="['text-input', { 'text-input--invalid': isFieldInvalid(binding.id, 'khhaoShopId') }]"
|
||||
data-field="khhaoShopId"
|
||||
placeholder="例如 12 / 13 / 14"
|
||||
@input="clearValidationState"
|
||||
/>
|
||||
<small class="field-help">这里填 khhao 系统里的店铺编号,专门用于同步订单命中规则。</small>
|
||||
</label>
|
||||
<label class="field-block">
|
||||
<span>店铺 ID</span>
|
||||
<input
|
||||
v-model="binding.shopId"
|
||||
:class="['text-input', { 'text-input--invalid': isFieldInvalid(binding.id, 'shopId') }]"
|
||||
data-field="shopId"
|
||||
placeholder="留空表示跨店铺通用"
|
||||
@input="clearValidationState"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>快手店铺</span>
|
||||
<select
|
||||
v-model="binding.shopId"
|
||||
:class="['text-input', { 'text-input--invalid': isFieldInvalid(binding.id, 'shopId') }]"
|
||||
data-field="shopId"
|
||||
@change="handleKuaishouShopChange(binding)"
|
||||
>
|
||||
<option value="">请选择已配置的快手官方店铺</option>
|
||||
<option
|
||||
v-for="shop in kuaishouShopOptions"
|
||||
:key="shop.shopId"
|
||||
:value="shop.shopId"
|
||||
>
|
||||
{{ getKuaishouShopOptionLabel(shop) }}
|
||||
</option>
|
||||
</select>
|
||||
<small class="field-help">这里会直接写入快手官方店铺 ID,不再使用 khhao 内部店铺编号。</small>
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>快手店铺名</span>
|
||||
<input
|
||||
:value="binding.shopName || ''"
|
||||
class="text-input text-input--readonly"
|
||||
placeholder="选择店铺后自动带出"
|
||||
readonly
|
||||
/>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<label class="field-block">
|
||||
<span>店铺 ID</span>
|
||||
<input
|
||||
v-model="binding.shopId"
|
||||
:class="['text-input', { 'text-input--invalid': isFieldInvalid(binding.id, 'shopId') }]"
|
||||
data-field="shopId"
|
||||
placeholder="留空表示跨店铺通用"
|
||||
@input="clearValidationState"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>店铺名称</span>
|
||||
<input
|
||||
v-model="binding.shopName"
|
||||
class="text-input"
|
||||
placeholder="用于保存和识别店铺"
|
||||
@input="clearValidationState"
|
||||
/>
|
||||
</label>
|
||||
</template>
|
||||
<label class="field-block">
|
||||
<span>店铺名称</span>
|
||||
<input
|
||||
v-model="binding.shopName"
|
||||
class="text-input"
|
||||
placeholder="用于保存和识别店铺"
|
||||
@input="clearValidationState"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="field-block">
|
||||
<span>优先级</span>
|
||||
@@ -1213,7 +1068,6 @@ onMounted(loadConfigs)
|
||||
}
|
||||
|
||||
.lookup-toolbar,
|
||||
.khhao-toolbar,
|
||||
.lookup-summary {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
@@ -1224,11 +1078,6 @@ onMounted(loadConfigs)
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.khhao-toolbar {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.field-block--action :deep(.el-button) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -4,15 +4,12 @@ import { computed, nextTick, onMounted, reactive, ref } from 'vue'
|
||||
import { showError, showSuccess } from '@/lib/feedback'
|
||||
import {
|
||||
fetchAdminCloudtentaclesSkuList,
|
||||
fetchAdminKhhaoSourceConfig,
|
||||
fetchAdminKuaishouCloudFulfillmentConfig,
|
||||
fetchAdminNinetyoneOrders,
|
||||
queryAdminKhhaoOrders,
|
||||
saveAdminKuaishouCloudFulfillmentConfig,
|
||||
} from '@/services/admin'
|
||||
import type {
|
||||
AdminCloudtentaclesSkuItem,
|
||||
AdminKhhaoOrderPreview,
|
||||
AdminKuaishouCloudFulfillmentConfig,
|
||||
AdminKuaishouCloudFulfillmentItem,
|
||||
AdminNinetyoneOrderItem,
|
||||
@@ -39,10 +36,6 @@ const enabled = ref(true)
|
||||
const items = ref<EditableItem[]>([])
|
||||
const collapsedIds = ref<string[]>([])
|
||||
const ruleFilter = ref<RuleFilter>('all')
|
||||
const khhaoLookupLoading = ref(false)
|
||||
const khhaoLookupErrorMessage = ref('')
|
||||
const khhaoLookupResults = ref<AdminKhhaoOrderPreview[]>([])
|
||||
const importedKhhaoOrderKeys = ref<string[]>([])
|
||||
const ninetyoneLookupLoading = ref(false)
|
||||
const ninetyoneLookupErrorMessage = ref('')
|
||||
const ninetyoneLookupResults = ref<AdminNinetyoneOrderItem[]>([])
|
||||
@@ -50,14 +43,6 @@ const importedNinetyoneOrderKeys = ref<string[]>([])
|
||||
const cloudSkuCatalogLoading = ref(false)
|
||||
const cloudSkuCatalogErrorMessage = ref('')
|
||||
const cloudSkuCatalog = ref<AdminCloudtentaclesSkuItem[]>([])
|
||||
const khhaoLookupForm = reactive({
|
||||
baseUrl: 'https://admin.khhao.com',
|
||||
username: '',
|
||||
password: '',
|
||||
page: 1,
|
||||
limit: 10,
|
||||
maxCaptchaAttempts: 3,
|
||||
})
|
||||
const ninetyoneLookupForm = reactive({
|
||||
status: 'pending_config' as 'pending_config' | 'all' | 'manual_failed',
|
||||
page: 1,
|
||||
@@ -86,21 +71,6 @@ const ruleFilterOptions = computed<Array<{ value: RuleFilter; label: string; cou
|
||||
{ value: 'disabled', label: '已停用', count: metrics.value.disabledCount },
|
||||
])
|
||||
|
||||
const khhaoLookupMetrics = computed(() => {
|
||||
const importedCount = khhaoLookupResults.value.filter((item) => isKhhaoProductImported(item)).length
|
||||
const shopCount = new Set(
|
||||
khhaoLookupResults.value
|
||||
.map((item) => String(item.shopName || item.kuaishouShopId || item.shopId || '').trim())
|
||||
.filter(Boolean),
|
||||
).size
|
||||
return {
|
||||
total: khhaoLookupResults.value.length,
|
||||
importedCount,
|
||||
availableCount: Math.max(khhaoLookupResults.value.length - importedCount, 0),
|
||||
shopCount,
|
||||
}
|
||||
})
|
||||
|
||||
const ninetyoneLookupMetrics = computed(() => {
|
||||
const importedCount = ninetyoneLookupResults.value.filter((item) => isNinetyoneProductImported(item)).length
|
||||
const pendingCount = ninetyoneLookupResults.value.filter((item) => item.orderStatus === 'pending_config').length
|
||||
@@ -118,10 +88,9 @@ function createEmptyItem(): EditableItem {
|
||||
id: '',
|
||||
enabled: true,
|
||||
priority: 100,
|
||||
provider: 'khhao',
|
||||
provider: '91kaquan',
|
||||
platform: 'kuaishou',
|
||||
shopId: '',
|
||||
khhaoShopId: '',
|
||||
internalSkuCode: '',
|
||||
internalSkuName: '',
|
||||
externalSkuCode: '',
|
||||
@@ -148,10 +117,9 @@ function mapEditableItem(item: AdminKuaishouCloudFulfillmentItem): EditableItem
|
||||
id: item.id || crypto.randomUUID(),
|
||||
enabled: item.enabled !== false,
|
||||
priority: item.priority || 100,
|
||||
provider: item.provider || 'khhao',
|
||||
provider: item.provider || '91kaquan',
|
||||
platform: item.platform || 'kuaishou',
|
||||
shopId: item.shopId || '',
|
||||
khhaoShopId: item.khhaoShopId || '',
|
||||
internalSkuCode: item.internalSkuCode || '',
|
||||
internalSkuName: item.internalSkuName || '',
|
||||
externalSkuCode: item.externalSkuCode || '',
|
||||
@@ -177,10 +145,9 @@ function mapSaveItem(item: EditableItem): AdminKuaishouCloudFulfillmentItem {
|
||||
id: item.id.trim() || item.internalSkuCode.trim() || item.localId,
|
||||
enabled: item.enabled,
|
||||
priority: Number(item.priority || 100) || 100,
|
||||
provider: item.provider.trim() || 'khhao',
|
||||
provider: item.provider.trim() || '91kaquan',
|
||||
platform: item.platform.trim() || 'kuaishou',
|
||||
shopId: item.shopId.trim(),
|
||||
khhaoShopId: item.khhaoShopId.trim(),
|
||||
internalSkuCode: item.internalSkuCode.trim(),
|
||||
internalSkuName: item.internalSkuName.trim(),
|
||||
externalSkuCode: item.externalSkuCode.trim(),
|
||||
@@ -218,9 +185,8 @@ function hasMeaningfulContent(item: EditableItem) {
|
||||
|| item.cloudSkuName.trim()
|
||||
|| item.vnKey.trim()
|
||||
|| item.shopId.trim()
|
||||
|| item.khhaoShopId.trim()
|
||||
|| item.notes.trim()
|
||||
|| item.provider.trim() !== 'khhao'
|
||||
|| item.provider.trim() !== '91kaquan'
|
||||
|| item.platform.trim() !== 'kuaishou'
|
||||
|| item.priority !== 100
|
||||
|| item.autoBuyEnabled !== true
|
||||
@@ -268,7 +234,7 @@ function getCardTitle(item: EditableItem, index: number) {
|
||||
|
||||
function getCardSummary(item: EditableItem) {
|
||||
const parts = [
|
||||
item.provider.trim() || 'khhao',
|
||||
item.provider.trim() || '91kaquan',
|
||||
item.platform.trim() || 'kuaishou',
|
||||
item.shopId.trim() || '跨店铺',
|
||||
item.cloudSkuId > 0 ? `cloud#${item.cloudSkuId}` : '待填 cloud SKU',
|
||||
@@ -337,10 +303,6 @@ function getCloudSkuSummary(item: EditableItem) {
|
||||
return '待选择 cloud SKU'
|
||||
}
|
||||
|
||||
function formatAmountFen(value: number) {
|
||||
return (Number(value || 0) / 100).toFixed(2)
|
||||
}
|
||||
|
||||
function isCollapsed(localId: string) {
|
||||
return collapsedIds.value.includes(localId)
|
||||
}
|
||||
@@ -381,18 +343,11 @@ async function loadConfigs() {
|
||||
errorMessage.value = ''
|
||||
|
||||
try {
|
||||
const [response, khhaoSourceResponse] = await Promise.all([
|
||||
fetchAdminKuaishouCloudFulfillmentConfig(),
|
||||
fetchAdminKhhaoSourceConfig(),
|
||||
])
|
||||
const response = await fetchAdminKuaishouCloudFulfillmentConfig()
|
||||
filePath.value = response.data.filePath
|
||||
enabled.value = response.data.source.enabled !== false
|
||||
items.value = (response.data.source.items || []).map(mapEditableItem)
|
||||
rebuildCollapsedState()
|
||||
khhaoLookupForm.baseUrl = khhaoSourceResponse.data.source.baseUrl || 'https://admin.khhao.com'
|
||||
khhaoLookupForm.username = khhaoSourceResponse.data.source.username || ''
|
||||
khhaoLookupForm.password = khhaoSourceResponse.data.source.password || ''
|
||||
khhaoLookupForm.maxCaptchaAttempts = khhaoSourceResponse.data.source.maxCaptchaAttempts || 3
|
||||
} catch (error) {
|
||||
errorMessage.value = error instanceof Error ? error.message : '读取新履约配置失败'
|
||||
} finally {
|
||||
@@ -415,36 +370,6 @@ function removeItem(localId: string) {
|
||||
setCollapsed(localId, false)
|
||||
}
|
||||
|
||||
function createItemFromKhhaoOrder(item: AdminKhhaoOrderPreview): EditableItem {
|
||||
return {
|
||||
localId: crypto.randomUUID(),
|
||||
id: '',
|
||||
enabled: true,
|
||||
priority: 100,
|
||||
provider: item.provider || 'khhao',
|
||||
platform: item.platform || 'kuaishou',
|
||||
shopId: item.kuaishouShopId || item.shopId || '',
|
||||
khhaoShopId: item.khhaoShopId || item.shopId || '',
|
||||
internalSkuCode: '',
|
||||
internalSkuName: item.itemTitle || '',
|
||||
externalSkuCode: item.skuCode || '',
|
||||
externalItemId: item.itemId || '',
|
||||
externalSkuName: item.itemTitle || '',
|
||||
resolvedSkuName: item.itemTitle || '',
|
||||
cloudSourceKey: 'default',
|
||||
cloudSkuId: 0,
|
||||
cloudSkuName: '',
|
||||
vnKey: '1',
|
||||
autoBuyEnabled: true,
|
||||
minAssetReserve: 0,
|
||||
autoReturnNumberAfterDispatch: false,
|
||||
autoConsumeAfterDispatch: false,
|
||||
kuaishouConsumeShopId: item.kuaishouShopId || item.shopId || '',
|
||||
kuaishouConsumeShopName: item.shopName || '',
|
||||
notes: `从 khhao 订单 ${item.platformOrderId} 导入`,
|
||||
}
|
||||
}
|
||||
|
||||
function createItemFromNinetyoneOrder(item: AdminNinetyoneOrderItem): EditableItem {
|
||||
const productNo = String(item.productNo || '').trim()
|
||||
const productName = String(item.productName || productNo).trim()
|
||||
@@ -456,7 +381,6 @@ function createItemFromNinetyoneOrder(item: AdminNinetyoneOrderItem): EditableIt
|
||||
provider: '91kaquan',
|
||||
platform: 'kuaishou',
|
||||
shopId: item.shopId || '91kaquan',
|
||||
khhaoShopId: '',
|
||||
internalSkuCode: '',
|
||||
internalSkuName: productName,
|
||||
externalSkuCode: productNo,
|
||||
@@ -477,24 +401,6 @@ function createItemFromNinetyoneOrder(item: AdminNinetyoneOrderItem): EditableIt
|
||||
}
|
||||
}
|
||||
|
||||
function findExistingItemFromKhhaoOrder(order: AdminKhhaoOrderPreview) {
|
||||
const orderShopId = String(order.kuaishouShopId || order.shopId || '').trim()
|
||||
const orderItemId = String(order.itemId || '').trim()
|
||||
const orderSkuCode = String(order.skuCode || '').trim()
|
||||
const orderTitle = String(order.itemTitle || '').trim()
|
||||
|
||||
return items.value.find((item) => {
|
||||
const sameShop = !orderShopId
|
||||
|| item.shopId.trim() === orderShopId
|
||||
|| item.khhaoShopId.trim() === String(order.khhaoShopId || '').trim()
|
||||
|| item.kuaishouConsumeShopId.trim() === orderShopId
|
||||
const sameItemId = orderItemId && item.externalItemId.trim() === orderItemId
|
||||
const sameSkuCode = orderSkuCode && item.externalSkuCode.trim() === orderSkuCode
|
||||
const sameTitle = orderTitle && [item.externalSkuName, item.internalSkuName, item.resolvedSkuName].some((value) => value.trim() === orderTitle)
|
||||
return sameShop && (sameItemId || sameSkuCode || sameTitle)
|
||||
}) || null
|
||||
}
|
||||
|
||||
function findExistingItemFromNinetyoneOrder(order: AdminNinetyoneOrderItem) {
|
||||
const productNo = String(order.productNo || '').trim()
|
||||
const productName = String(order.productName || '').trim()
|
||||
@@ -512,31 +418,6 @@ function findExistingItemFromNinetyoneOrder(order: AdminNinetyoneOrderItem) {
|
||||
}) || null
|
||||
}
|
||||
|
||||
async function importKhhaoProduct(item: AdminKhhaoOrderPreview) {
|
||||
validationState.value = null
|
||||
const importKey = getKhhaoOrderImportKey(item)
|
||||
const existing = findExistingItemFromKhhaoOrder(item)
|
||||
if (existing) {
|
||||
setCollapsed(existing.localId, false)
|
||||
if (!importedKhhaoOrderKeys.value.includes(importKey)) {
|
||||
importedKhhaoOrderKeys.value = [...importedKhhaoOrderKeys.value, importKey]
|
||||
}
|
||||
showSuccess('已定位到现有规则草稿,直接继续完善即可')
|
||||
await focusValidationTarget(existing.localId)
|
||||
return
|
||||
}
|
||||
|
||||
const next = createItemFromKhhaoOrder(item)
|
||||
items.value.unshift(next)
|
||||
setCollapsed(next.localId, false)
|
||||
|
||||
if (!importedKhhaoOrderKeys.value.includes(importKey)) {
|
||||
importedKhhaoOrderKeys.value = [...importedKhhaoOrderKeys.value, importKey]
|
||||
}
|
||||
|
||||
await focusValidationTarget(next.localId)
|
||||
}
|
||||
|
||||
async function importNinetyoneProduct(item: AdminNinetyoneOrderItem) {
|
||||
validationState.value = null
|
||||
const importKey = getNinetyoneOrderImportKey(item)
|
||||
@@ -562,21 +443,6 @@ async function importNinetyoneProduct(item: AdminNinetyoneOrderItem) {
|
||||
await focusValidationTarget(next.localId)
|
||||
}
|
||||
|
||||
function getKhhaoOrderImportKey(item: AdminKhhaoOrderPreview) {
|
||||
return [
|
||||
item.platformOrderId,
|
||||
item.itemId,
|
||||
item.skuCode,
|
||||
item.kuaishouShopId || item.shopId,
|
||||
]
|
||||
.map((value) => String(value || '').trim())
|
||||
.join(':')
|
||||
}
|
||||
|
||||
function isKhhaoProductImported(item: AdminKhhaoOrderPreview) {
|
||||
return importedKhhaoOrderKeys.value.includes(getKhhaoOrderImportKey(item))
|
||||
}
|
||||
|
||||
function getNinetyoneOrderImportKey(item: AdminNinetyoneOrderItem) {
|
||||
return [
|
||||
item.orderNo,
|
||||
@@ -768,34 +634,6 @@ async function saveConfigs() {
|
||||
}
|
||||
}
|
||||
|
||||
async function lookupKhhaoProducts() {
|
||||
if (!khhaoLookupForm.username.trim() || !khhaoLookupForm.password.trim()) {
|
||||
khhaoLookupErrorMessage.value = '请先填写 khhao 账号和密码'
|
||||
return
|
||||
}
|
||||
|
||||
khhaoLookupLoading.value = true
|
||||
khhaoLookupErrorMessage.value = ''
|
||||
|
||||
try {
|
||||
const response = await queryAdminKhhaoOrders({
|
||||
baseUrl: khhaoLookupForm.baseUrl.trim() || 'https://admin.khhao.com',
|
||||
username: khhaoLookupForm.username.trim(),
|
||||
password: khhaoLookupForm.password.trim(),
|
||||
page: Number(khhaoLookupForm.page || 1),
|
||||
limit: Number(khhaoLookupForm.limit || 10),
|
||||
maxCaptchaAttempts: Number(khhaoLookupForm.maxCaptchaAttempts || 3),
|
||||
})
|
||||
khhaoLookupResults.value = response.data.items
|
||||
importedKhhaoOrderKeys.value = []
|
||||
} catch (error) {
|
||||
khhaoLookupResults.value = []
|
||||
khhaoLookupErrorMessage.value = error instanceof Error ? error.message : 'khhao 订单查询失败'
|
||||
} finally {
|
||||
khhaoLookupLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function lookupNinetyoneProducts() {
|
||||
ninetyoneLookupLoading.value = true
|
||||
ninetyoneLookupErrorMessage.value = ''
|
||||
@@ -824,7 +662,7 @@ onMounted(loadConfigs)
|
||||
<header class="panel-header">
|
||||
<div class="panel-header-copy">
|
||||
<h1>快手 Cloud 新履约</h1>
|
||||
<p>维护 khhao 快手订单到内部 SKU、cloud SKU、虚拟号与后续动作的映射规则。</p>
|
||||
<p>维护 91卡券快手订单到内部 SKU、cloud SKU、虚拟号与后续动作的映射规则。</p>
|
||||
</div>
|
||||
<div class="header-tags">
|
||||
<span class="header-tag">独立新流程</span>
|
||||
@@ -874,7 +712,6 @@ onMounted(loadConfigs)
|
||||
</div>
|
||||
|
||||
<div class="overview-notes">
|
||||
<span class="overview-note">khhao 订单只用于取样导入,不写入订单库</span>
|
||||
<span class="overview-note">91卡券订单来自已接收的待补全队列</span>
|
||||
<span class="overview-note">内部 SKU 决定最终任务与库存绑定</span>
|
||||
<span class="overview-note">cloud SKU 决定自动购买、发货与退号资源</span>
|
||||
@@ -885,112 +722,6 @@ onMounted(loadConfigs)
|
||||
<div v-if="loading" class="empty-block">新履约配置加载中</div>
|
||||
|
||||
<template v-else>
|
||||
<section class="table-card table-card--dense">
|
||||
<div class="section-title-row section-title-row--tight">
|
||||
<div>
|
||||
<h3>khhao 订单取样导入</h3>
|
||||
<p>先查快手订单样本,再导入到下面的规则草稿里继续补齐内部 SKU 和 cloud 资源。</p>
|
||||
</div>
|
||||
<div class="section-mini-stats">
|
||||
<span class="mini-stat-chip">结果 {{ khhaoLookupMetrics.total }}</span>
|
||||
<span class="mini-stat-chip">店铺 {{ khhaoLookupMetrics.shopCount }}</span>
|
||||
<span class="mini-stat-chip">待导入 {{ khhaoLookupMetrics.availableCount }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="khhao-toolbar">
|
||||
<label class="field-block field-wide">
|
||||
<span>Base URL</span>
|
||||
<input v-model="khhaoLookupForm.baseUrl" class="text-input" placeholder="https://admin.khhao.com" />
|
||||
</label>
|
||||
<label class="field-block">
|
||||
<span>账号</span>
|
||||
<input v-model="khhaoLookupForm.username" class="text-input" placeholder="khhao 登录账号" />
|
||||
</label>
|
||||
<label class="field-block">
|
||||
<span>密码</span>
|
||||
<input v-model="khhaoLookupForm.password" class="text-input" placeholder="khhao 登录密码" type="password" />
|
||||
</label>
|
||||
<label class="field-block">
|
||||
<span>页码</span>
|
||||
<input v-model.number="khhaoLookupForm.page" class="text-input" min="1" type="number" />
|
||||
</label>
|
||||
<label class="field-block">
|
||||
<span>每页条数</span>
|
||||
<input v-model.number="khhaoLookupForm.limit" class="text-input" max="50" min="1" type="number" />
|
||||
</label>
|
||||
<label class="field-block">
|
||||
<span>验证码重试</span>
|
||||
<input v-model.number="khhaoLookupForm.maxCaptchaAttempts" class="text-input" max="5" min="1" type="number" />
|
||||
</label>
|
||||
<div class="field-block field-block--action">
|
||||
<span>操作</span>
|
||||
<el-button :loading="khhaoLookupLoading" round type="primary" @click="lookupKhhaoProducts">查询 khhao 订单</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="toolbar-hint">查询结果只用于补配置,不会写入订单库,也不会影响现有订单数据。</p>
|
||||
|
||||
<p v-if="khhaoLookupErrorMessage" class="error-copy lookup-error">{{ khhaoLookupErrorMessage }}</p>
|
||||
<div v-else-if="khhaoLookupLoading" class="empty-inline">正在查询 khhao 订单…</div>
|
||||
|
||||
<table v-else class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>订单</th>
|
||||
<th>店铺</th>
|
||||
<th>商品</th>
|
||||
<th>金额 / 状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in khhaoLookupResults" :key="getKhhaoOrderImportKey(item)">
|
||||
<td>
|
||||
<div class="cell-stack">
|
||||
<strong>{{ item.platformOrderId || '-' }}</strong>
|
||||
<span class="cell-subtle">{{ item.platformLabel || item.platform || 'kuaishou' }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="cell-stack">
|
||||
<strong>{{ item.shopName || item.shopId || '-' }}</strong>
|
||||
<span class="cell-subtle">khhao ID: {{ item.khhaoShopId || item.shopId || '-' }}</span>
|
||||
<span class="cell-subtle">快手 ID: {{ item.kuaishouShopId || '-' }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="cell-stack">
|
||||
<strong>{{ item.itemTitle || '-' }}</strong>
|
||||
<span class="cell-subtle">SKU: {{ item.skuCode || '-' }}</span>
|
||||
<span class="cell-subtle">ItemId: {{ item.itemId || '-' }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="cell-stack">
|
||||
<strong>{{ formatAmountFen(item.totalAmountFen) }}</strong>
|
||||
<span class="cell-subtle">{{ item.statusLabel || item.status || '-' }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<el-button
|
||||
v-if="!isKhhaoProductImported(item)"
|
||||
link
|
||||
type="primary"
|
||||
@click="importKhhaoProduct(item)"
|
||||
>
|
||||
导入到规则
|
||||
</el-button>
|
||||
<span v-else class="cell-subtle">已导入草稿</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="khhaoLookupResults.length === 0">
|
||||
<td colspan="5" class="empty-inline">还没有 khhao 查询结果。</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section class="table-card table-card--dense">
|
||||
<div class="section-title-row section-title-row--tight">
|
||||
<div>
|
||||
@@ -1004,7 +735,7 @@ onMounted(loadConfigs)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="khhao-toolbar">
|
||||
<div class="lookup-toolbar">
|
||||
<label class="field-block">
|
||||
<span>订单状态</span>
|
||||
<select v-model="ninetyoneLookupForm.status" class="text-input">
|
||||
@@ -1159,7 +890,7 @@ onMounted(loadConfigs)
|
||||
<div class="mapping-grid">
|
||||
<label class="field-block">
|
||||
<span>来源 provider</span>
|
||||
<input v-model="item.provider" class="text-input" maxlength="32" placeholder="khhao / 91kaquan" />
|
||||
<input v-model="item.provider" class="text-input" maxlength="32" placeholder="默认 91kaquan" />
|
||||
</label>
|
||||
<label class="field-block">
|
||||
<span>来源 platform</span>
|
||||
@@ -1169,13 +900,9 @@ onMounted(loadConfigs)
|
||||
<span>店铺 ID</span>
|
||||
<input v-model="item.shopId" class="text-input" maxlength="80" placeholder="留空表示跨店铺共用" />
|
||||
</label>
|
||||
<label class="field-block">
|
||||
<span>khhao 店铺 ID</span>
|
||||
<input v-model="item.khhaoShopId" class="text-input" maxlength="80" placeholder="仅 khhao 使用,例如 10" />
|
||||
</label>
|
||||
<label class="field-block">
|
||||
<span>外部 SKU</span>
|
||||
<input v-model="item.externalSkuCode" class="text-input" maxlength="120" placeholder="例如 khhao 的 skuCode" />
|
||||
<input v-model="item.externalSkuCode" class="text-input" maxlength="120" placeholder="例如 91卡券 productNo" />
|
||||
</label>
|
||||
<label class="field-block">
|
||||
<span>外部商品 ID</span>
|
||||
@@ -2102,9 +1829,9 @@ onMounted(loadConfigs)
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.khhao-toolbar {
|
||||
.lookup-toolbar {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(220px, 1.6fr) minmax(140px, 1fr) minmax(140px, 1fr) 90px 110px 120px 150px;
|
||||
grid-template-columns: minmax(180px, 1fr) 110px 130px 180px;
|
||||
gap: 12px;
|
||||
align-items: end;
|
||||
}
|
||||
@@ -2407,7 +2134,7 @@ onMounted(loadConfigs)
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.overview-stats,
|
||||
.khhao-toolbar,
|
||||
.lookup-toolbar,
|
||||
.binding-grid,
|
||||
.mapping-editor {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
@@ -2433,7 +2160,7 @@ onMounted(loadConfigs)
|
||||
}
|
||||
|
||||
.overview-stats,
|
||||
.khhao-toolbar,
|
||||
.lookup-toolbar,
|
||||
.binding-grid,
|
||||
.mapping-editor,
|
||||
.mapping-grid,
|
||||
|
||||
@@ -3,19 +3,16 @@ import { onMounted, ref } from 'vue'
|
||||
|
||||
import AdminPlatformAgisoSection from '@/components/admin/AdminPlatformAgisoSection.vue'
|
||||
import AdminPlatformCloudtentaclesSection from '@/components/admin/AdminPlatformCloudtentaclesSection.vue'
|
||||
import AdminPlatformKhhaoSection from '@/components/admin/AdminPlatformKhhaoSection.vue'
|
||||
import AdminPlatformNinetyoneSection from '@/components/admin/AdminPlatformNinetyoneSection.vue'
|
||||
import AdminPlatformKuaishouEticketSection from '@/components/admin/AdminPlatformKuaishouEticketSection.vue'
|
||||
import { useAdminAgisoPlatform } from '@/composables/admin/platform-shops/useAdminAgisoPlatform'
|
||||
import { useAdminCloudtentaclesPlatform } from '@/composables/admin/platform-shops/useAdminCloudtentaclesPlatform'
|
||||
import { useAdminKhhaoPlatform } from '@/composables/admin/platform-shops/useAdminKhhaoPlatform'
|
||||
import { useAdminNinetyonePlatform } from '@/composables/admin/platform-shops/useAdminNinetyonePlatform'
|
||||
import { useAdminKuaishouEticketPlatform } from '@/composables/admin/platform-shops/useAdminKuaishouEticketPlatform'
|
||||
import type { PlatformTab } from '@/composables/admin/platform-shops/types'
|
||||
import {
|
||||
fetchAdminAgisoShopConfigs,
|
||||
fetchAdminCloudtentaclesSourceConfig,
|
||||
fetchAdminKhhaoSourceConfig,
|
||||
fetchAdminKuaishouEticketSourceConfig,
|
||||
} from '@/services/admin'
|
||||
import { hasAdminRole } from '@/utils/admin-auth'
|
||||
@@ -45,27 +42,6 @@ const {
|
||||
saveAgisoConfigs: persistAgisoConfigs,
|
||||
} = useAdminAgisoPlatform()
|
||||
|
||||
const {
|
||||
khhaoFilePath,
|
||||
khhaoStateFilePath,
|
||||
khhaoForm,
|
||||
khhaoSaving,
|
||||
khhaoTesting,
|
||||
khhaoQuerying,
|
||||
khhaoSyncing,
|
||||
khhaoResultError,
|
||||
khhaoLoginResult,
|
||||
khhaoQueryResult,
|
||||
khhaoSyncResult,
|
||||
khhaoAutoSyncState,
|
||||
khhaoStats,
|
||||
hydrateKhhaoConfig,
|
||||
handleKhhaoSaveSource,
|
||||
handleKhhaoTestLogin,
|
||||
handleKhhaoQueryOrders,
|
||||
handleKhhaoSyncOrders,
|
||||
} = useAdminKhhaoPlatform()
|
||||
|
||||
const {
|
||||
ninetyoneLoading,
|
||||
ninetyoneActionLoadingId,
|
||||
@@ -156,15 +132,13 @@ async function loadConfigs() {
|
||||
errorMessage.value = ''
|
||||
|
||||
try {
|
||||
const [agisoResponse, khhaoResponse, kuaishouEticketResponse, cloudtentaclesResponse] = await Promise.all([
|
||||
const [agisoResponse, kuaishouEticketResponse, cloudtentaclesResponse] = await Promise.all([
|
||||
fetchAdminAgisoShopConfigs(),
|
||||
fetchAdminKhhaoSourceConfig(),
|
||||
fetchAdminKuaishouEticketSourceConfig(),
|
||||
fetchAdminCloudtentaclesSourceConfig(),
|
||||
])
|
||||
|
||||
hydrateAgisoConfig(agisoResponse.data)
|
||||
hydrateKhhaoConfig(khhaoResponse.data)
|
||||
hydrateKuaishouEticketConfig(kuaishouEticketResponse.data)
|
||||
hydrateCloudtentaclesConfig(cloudtentaclesResponse.data)
|
||||
await loadNinetyoneOrders(1)
|
||||
@@ -191,7 +165,7 @@ onMounted(loadConfigs)
|
||||
<header class="hero-card">
|
||||
<div class="hero-copy">
|
||||
<h1>平台配置</h1>
|
||||
<p>按平台分别管理来源接入、凭据与店铺能力。Agiso 负责 webhook / 店铺消息配置,khhao 负责来源拉单,快手小店核销负责独立券核销调试,cloudtentacles 负责外部履约平台登录。</p>
|
||||
<p>按平台分别管理来源接入、凭据与店铺能力。Agiso 负责 webhook / 店铺消息配置,91卡券负责新订单来源,快手小店核销负责独立券核销调试,cloudtentacles 负责外部履约平台登录。</p>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<el-button round @click="loadConfigs">刷新全部配置</el-button>
|
||||
@@ -241,23 +215,6 @@ onMounted(loadConfigs)
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
:class="['platform-overview-card', { 'is-active': activePlatform === 'khhao' }]"
|
||||
@click="switchPlatform('khhao')"
|
||||
>
|
||||
<div class="platform-head">
|
||||
<span class="platform-badge">khhao</span>
|
||||
<span class="platform-tag">账号 / 拉单</span>
|
||||
</div>
|
||||
<strong>{{ khhaoStats.hasCredential ? '已配置' : '未配置' }}</strong>
|
||||
<span>来源凭据</span>
|
||||
<div class="platform-metrics">
|
||||
<span>最近查询 {{ khhaoStats.queryCount }} 条</span>
|
||||
<span>最近同步成功 {{ khhaoStats.syncedCount }} 条</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
:class="['platform-overview-card', { 'is-active': activePlatform === 'kuaishouEticket' }]"
|
||||
@@ -302,13 +259,6 @@ onMounted(loadConfigs)
|
||||
>
|
||||
Agiso 店铺与消息
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
:class="['switch-chip', { 'is-active': activePlatform === 'khhao' }]"
|
||||
@click="switchPlatform('khhao')"
|
||||
>
|
||||
khhao 来源与同步
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
:class="['switch-chip', { 'is-active': activePlatform === 'ninetyone' }]"
|
||||
@@ -350,26 +300,6 @@ onMounted(loadConfigs)
|
||||
:save-agiso-configs="saveAgisoConfigs"
|
||||
/>
|
||||
|
||||
<AdminPlatformKhhaoSection
|
||||
v-else-if="activePlatform === 'khhao'"
|
||||
:khhao-file-path="khhaoFilePath"
|
||||
:khhao-state-file-path="khhaoStateFilePath"
|
||||
:khhao-form="khhaoForm"
|
||||
:khhao-saving="khhaoSaving"
|
||||
:khhao-testing="khhaoTesting"
|
||||
:khhao-querying="khhaoQuerying"
|
||||
:khhao-syncing="khhaoSyncing"
|
||||
:khhao-result-error="khhaoResultError"
|
||||
:khhao-login-result="khhaoLoginResult"
|
||||
:khhao-query-result="khhaoQueryResult"
|
||||
:khhao-sync-result="khhaoSyncResult"
|
||||
:khhao-auto-sync-state="khhaoAutoSyncState"
|
||||
:handle-khhao-save-source="handleKhhaoSaveSource"
|
||||
:handle-khhao-test-login="handleKhhaoTestLogin"
|
||||
:handle-khhao-query-orders="handleKhhaoQueryOrders"
|
||||
:handle-khhao-sync-orders="handleKhhaoSyncOrders"
|
||||
/>
|
||||
|
||||
<AdminPlatformNinetyoneSection
|
||||
v-else-if="activePlatform === 'ninetyone'"
|
||||
:ninetyone-loading="ninetyoneLoading"
|
||||
|
||||
Reference in New Issue
Block a user