优化履约账号优先级配置
This commit is contained in:
@@ -11,7 +11,7 @@ export interface AdminKuaishouCloudFulfillmentItem {
|
||||
externalItemId: string
|
||||
externalSkuName: string
|
||||
resolvedSkuName: string
|
||||
cloudSourceKey: string
|
||||
cloudSourceKeys: string[]
|
||||
cloudSkuId: number
|
||||
cloudSkuName: string
|
||||
vnKey: string
|
||||
@@ -22,7 +22,6 @@ export interface AdminKuaishouCloudFulfillmentItem {
|
||||
kuaishouConsumeShopId: string
|
||||
kuaishouConsumeShopName: string
|
||||
notes: string
|
||||
cloudSourceKeyFallbacks?: string[]
|
||||
}
|
||||
|
||||
export interface AdminKuaishouCloudFulfillmentConfig {
|
||||
|
||||
@@ -126,8 +126,7 @@ export interface AdminTaskDetail {
|
||||
}
|
||||
binding: {
|
||||
prepareStatus: string
|
||||
cloudSourceKey: string
|
||||
cloudSourceKeyFallbacks: string[]
|
||||
cloudSourceKeys: string[]
|
||||
resolvedSourceKey: string
|
||||
skuId: number
|
||||
skuName: string
|
||||
|
||||
@@ -74,7 +74,8 @@ export interface ClaimKuaishouCloudFlowInfo {
|
||||
}
|
||||
binding: {
|
||||
prepareStatus: string
|
||||
cloudSourceKey: string
|
||||
cloudSourceKeys: string[]
|
||||
resolvedSourceKey: string
|
||||
skuId: number
|
||||
skuName: string
|
||||
vnKey: string
|
||||
|
||||
+2
@@ -58,6 +58,7 @@ onMounted(config.loadConfigs)
|
||||
:get-card-summary="config.getCardSummary"
|
||||
:get-rule-state="config.getRuleState"
|
||||
:get-external-match-summary="config.getExternalMatchSummary"
|
||||
:get-cloud-source-summary="config.getCloudSourceSummary"
|
||||
:get-cloud-sku-summary="config.getCloudSkuSummary"
|
||||
:get-consume-shop-summary="config.getConsumeShopSummary"
|
||||
:get-cloud-sku-options="cloudSku.getCloudSkuOptions"
|
||||
@@ -78,6 +79,7 @@ onMounted(config.loadConfigs)
|
||||
(item, visible) => cloudSku.handleCloudSkuDropdownVisible(item, visible)
|
||||
"
|
||||
@handle-kuaishou-consume-shop-selected="config.handleKuaishouConsumeShopSelected($event)"
|
||||
@handle-cloud-source-keys-changed="config.handleCloudSourceKeysChanged($event)"
|
||||
@remove-item="config.removeItem($event)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
+13
-20
@@ -16,6 +16,7 @@ defineProps<{
|
||||
getCardSummary: (item: EditableItem) => string
|
||||
getRuleState: (item: EditableItem) => { label: string; tone: string }
|
||||
getExternalMatchSummary: (item: EditableItem) => string
|
||||
getCloudSourceSummary: (item: EditableItem) => string
|
||||
getCloudSkuSummary: (item: EditableItem) => string
|
||||
getConsumeShopSummary: (item: EditableItem) => string
|
||||
getCloudSkuOptions: (item: EditableItem) => AdminCloudtentaclesSkuItem[]
|
||||
@@ -29,6 +30,7 @@ const emit = defineEmits<{
|
||||
handleCloudSkuSelected: [value: number | string | undefined]
|
||||
handleCloudSkuDropdownVisible: [visible: boolean]
|
||||
handleKuaishouConsumeShopSelected: []
|
||||
handleCloudSourceKeysChanged: []
|
||||
remove: []
|
||||
}>()
|
||||
</script>
|
||||
@@ -66,6 +68,9 @@ const emit = defineEmits<{
|
||||
<el-descriptions-item label="内部 SKU">{{
|
||||
item.internalSkuCode || '-'
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="cloud 账号">{{
|
||||
getCloudSourceSummary(item)
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="cloud 资源">{{ getCloudSkuSummary(item) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="核销店铺">{{
|
||||
getConsumeShopSummary(item)
|
||||
@@ -178,11 +183,15 @@ const emit = defineEmits<{
|
||||
placeholder="展示用,可选但建议填"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="cloud 主账号">
|
||||
<el-form-item label="cloud 账号优先级" class="field-wide">
|
||||
<el-select
|
||||
v-model="item.cloudSourceKey"
|
||||
v-model="item.cloudSourceKeys"
|
||||
class="text-input"
|
||||
placeholder="选择 cloud 账号"
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
placeholder="按顺序选择可用于履约的 cloud 账号"
|
||||
@change="emit('handleCloudSourceKeysChanged')"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in cloudtentaclesSourceOptions"
|
||||
@@ -191,23 +200,7 @@ const emit = defineEmits<{
|
||||
:value="opt.key"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="备选 cloud 账号" class="field-wide">
|
||||
<el-select
|
||||
v-model="item.cloudSourceKeyFallbacks"
|
||||
class="text-input"
|
||||
multiple
|
||||
placeholder="主账号不可用时自动尝试备选"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in cloudtentaclesSourceOptions.filter(
|
||||
(o) => o.key !== item.cloudSourceKey,
|
||||
)"
|
||||
:key="opt.key"
|
||||
:label="opt.label || opt.key"
|
||||
:value="opt.key"
|
||||
/>
|
||||
</el-select>
|
||||
<small class="field-help">执行时会从左到右尝试,SKU 列表使用第一个账号加载。</small>
|
||||
</el-form-item>
|
||||
<el-form-item label="cloud SKU ID">
|
||||
<el-select
|
||||
|
||||
+4
@@ -21,6 +21,7 @@ defineProps<{
|
||||
getCardSummary: (item: EditableItem) => string
|
||||
getRuleState: (item: EditableItem) => { label: string; tone: string }
|
||||
getExternalMatchSummary: (item: EditableItem) => string
|
||||
getCloudSourceSummary: (item: EditableItem) => string
|
||||
getCloudSkuSummary: (item: EditableItem) => string
|
||||
getConsumeShopSummary: (item: EditableItem) => string
|
||||
getCloudSkuOptions: (item: EditableItem) => AdminCloudtentaclesSkuItem[]
|
||||
@@ -42,6 +43,7 @@ const emit = defineEmits<{
|
||||
handleCloudSkuSelected: [item: EditableItem, value: number | string | undefined]
|
||||
handleCloudSkuDropdownVisible: [item: EditableItem, visible: boolean]
|
||||
handleKuaishouConsumeShopSelected: [item: EditableItem]
|
||||
handleCloudSourceKeysChanged: [item: EditableItem]
|
||||
removeItem: [localId: string]
|
||||
}>()
|
||||
</script>
|
||||
@@ -125,6 +127,7 @@ const emit = defineEmits<{
|
||||
:get-card-summary="getCardSummary"
|
||||
:get-rule-state="getRuleState"
|
||||
:get-external-match-summary="getExternalMatchSummary"
|
||||
:get-cloud-source-summary="getCloudSourceSummary"
|
||||
:get-cloud-sku-summary="getCloudSkuSummary"
|
||||
:get-consume-shop-summary="getConsumeShopSummary"
|
||||
:get-cloud-sku-options="getCloudSkuOptions"
|
||||
@@ -135,6 +138,7 @@ const emit = defineEmits<{
|
||||
@handle-cloud-sku-selected="emit('handleCloudSkuSelected', item, $event)"
|
||||
@handle-cloud-sku-dropdown-visible="emit('handleCloudSkuDropdownVisible', item, $event)"
|
||||
@handle-kuaishou-consume-shop-selected="emit('handleKuaishouConsumeShopSelected', item)"
|
||||
@handle-cloud-source-keys-changed="emit('handleCloudSourceKeysChanged', item)"
|
||||
@remove="emit('removeItem', item.localId)"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { AdminKuaishouCloudFulfillmentItem } from '@/types/admin'
|
||||
|
||||
export type EditableItem = AdminKuaishouCloudFulfillmentItem & {
|
||||
localId: string
|
||||
cloudSourceKeys: string[]
|
||||
}
|
||||
|
||||
export type ValidationState = {
|
||||
|
||||
+46
-11
@@ -61,6 +61,7 @@ export function useKuaishouCloudConfig() {
|
||||
|
||||
function createEmptyItem(): EditableItem {
|
||||
const defaultShop = getDefaultKuaishouConsumeShop()
|
||||
const sourceKeys = getDefaultCloudSourceKeys()
|
||||
return {
|
||||
localId: crypto.randomUUID(),
|
||||
id: '',
|
||||
@@ -75,7 +76,7 @@ export function useKuaishouCloudConfig() {
|
||||
externalItemId: '',
|
||||
externalSkuName: '',
|
||||
resolvedSkuName: '',
|
||||
cloudSourceKey: 'default',
|
||||
cloudSourceKeys: sourceKeys,
|
||||
cloudSkuId: 0,
|
||||
cloudSkuName: '',
|
||||
vnKey: '1',
|
||||
@@ -86,7 +87,6 @@ export function useKuaishouCloudConfig() {
|
||||
kuaishouConsumeShopId: defaultShop?.shopId || '',
|
||||
kuaishouConsumeShopName: defaultShop?.kshopName || '',
|
||||
notes: '',
|
||||
cloudSourceKeyFallbacks: [],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ export function useKuaishouCloudConfig() {
|
||||
item.kuaishouConsumeShopId,
|
||||
item.kuaishouConsumeShopName,
|
||||
)
|
||||
const sourceKeys = normalizeCloudSourceKeys(item.cloudSourceKeys)
|
||||
return {
|
||||
localId: crypto.randomUUID(),
|
||||
id: item.id || crypto.randomUUID(),
|
||||
@@ -109,7 +110,7 @@ export function useKuaishouCloudConfig() {
|
||||
externalItemId: item.externalItemId || '',
|
||||
externalSkuName: item.externalSkuName || '',
|
||||
resolvedSkuName: item.resolvedSkuName || '',
|
||||
cloudSourceKey: item.cloudSourceKey || 'default',
|
||||
cloudSourceKeys: sourceKeys,
|
||||
cloudSkuId: Number(item.cloudSkuId || 0) || 0,
|
||||
cloudSkuName: item.cloudSkuName || '',
|
||||
vnKey: item.vnKey || '',
|
||||
@@ -120,9 +121,6 @@ export function useKuaishouCloudConfig() {
|
||||
kuaishouConsumeShopId: matchedShop?.shopId || item.kuaishouConsumeShopId || '',
|
||||
kuaishouConsumeShopName: matchedShop?.kshopName || item.kuaishouConsumeShopName || '',
|
||||
notes: item.notes || '',
|
||||
cloudSourceKeyFallbacks: Array.isArray(item.cloudSourceKeyFallbacks)
|
||||
? item.cloudSourceKeyFallbacks
|
||||
: [],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +129,7 @@ export function useKuaishouCloudConfig() {
|
||||
item.kuaishouConsumeShopId,
|
||||
item.kuaishouConsumeShopName,
|
||||
)
|
||||
const sourceKeys = normalizeCloudSourceKeys(item.cloudSourceKeys)
|
||||
return {
|
||||
id: item.id.trim() || item.internalSkuCode.trim() || item.localId,
|
||||
enabled: item.enabled,
|
||||
@@ -144,7 +143,7 @@ export function useKuaishouCloudConfig() {
|
||||
externalItemId: item.externalItemId.trim(),
|
||||
externalSkuName: item.externalSkuName.trim(),
|
||||
resolvedSkuName: item.resolvedSkuName.trim(),
|
||||
cloudSourceKey: item.cloudSourceKey.trim() || 'default',
|
||||
cloudSourceKeys: sourceKeys,
|
||||
cloudSkuId: Number(item.cloudSkuId || 0) || 0,
|
||||
cloudSkuName: item.cloudSkuName.trim(),
|
||||
vnKey: item.vnKey.trim(),
|
||||
@@ -157,12 +156,20 @@ export function useKuaishouCloudConfig() {
|
||||
matchedShop?.kshopName || item.kuaishouConsumeShopName,
|
||||
).trim(),
|
||||
notes: item.notes.trim(),
|
||||
cloudSourceKeyFallbacks: Array.isArray(item.cloudSourceKeyFallbacks)
|
||||
? item.cloudSourceKeyFallbacks.filter(Boolean)
|
||||
: [],
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeCloudSourceKeys(values: unknown[] = []) {
|
||||
const keys = values
|
||||
.map((value) => String(value || '').trim())
|
||||
.filter(Boolean)
|
||||
return Array.from(new Set(keys))
|
||||
}
|
||||
|
||||
function getDefaultCloudSourceKeys() {
|
||||
return normalizeCloudSourceKeys([cloudtentaclesSourceOptions.value[0]?.key])
|
||||
}
|
||||
|
||||
// ── validation helpers ────────────────────────────────
|
||||
|
||||
function hasExternalMatch(
|
||||
@@ -181,7 +188,7 @@ export function useKuaishouCloudConfig() {
|
||||
item.externalItemId.trim() ||
|
||||
item.externalSkuName.trim() ||
|
||||
item.resolvedSkuName.trim() ||
|
||||
item.cloudSourceKey.trim() !== 'default' ||
|
||||
item.cloudSourceKeys.length > 0 ||
|
||||
Number(item.cloudSkuId || 0) > 0 ||
|
||||
item.cloudSkuName.trim() ||
|
||||
item.vnKey.trim() ||
|
||||
@@ -203,6 +210,7 @@ export function useKuaishouCloudConfig() {
|
||||
function isItemComplete(item: EditableItem) {
|
||||
return Boolean(
|
||||
item.internalSkuCode.trim() &&
|
||||
item.cloudSourceKeys.length > 0 &&
|
||||
Number(item.cloudSkuId || 0) > 0 &&
|
||||
(!item.autoConsumeAfterDispatch || Boolean(item.kuaishouConsumeShopId.trim())) &&
|
||||
hasExternalMatch(item),
|
||||
@@ -220,6 +228,10 @@ export function useKuaishouCloudConfig() {
|
||||
return { localId: item.localId, message: `${title} 缺少内部 SKU 编码` }
|
||||
}
|
||||
|
||||
if (item.cloudSourceKeys.length === 0) {
|
||||
return { localId: item.localId, message: `${title} 需要选择至少一个 cloud 账号` }
|
||||
}
|
||||
|
||||
if (Number(item.cloudSkuId || 0) <= 0) {
|
||||
return { localId: item.localId, message: `${title} 需要填写 cloud SKU ID` }
|
||||
}
|
||||
@@ -340,6 +352,20 @@ export function useKuaishouCloudConfig() {
|
||||
return name || id || '未绑定核销店铺'
|
||||
}
|
||||
|
||||
function getCloudSourceSummary(item: EditableItem) {
|
||||
const keys = normalizeCloudSourceKeys(item.cloudSourceKeys)
|
||||
if (keys.length === 0) {
|
||||
return '未选择 cloud 账号'
|
||||
}
|
||||
|
||||
return keys
|
||||
.map((key, index) => {
|
||||
const option = cloudtentaclesSourceOptions.value.find((source) => source.key === key)
|
||||
return `${index + 1}. ${option?.label || key}`
|
||||
})
|
||||
.join(' / ')
|
||||
}
|
||||
|
||||
function getCloudSkuSummary(item: EditableItem) {
|
||||
if (item.cloudSkuId > 0 && item.cloudSkuName.trim()) {
|
||||
return `${item.cloudSkuName.trim()} · #${item.cloudSkuId}`
|
||||
@@ -441,6 +467,13 @@ export function useKuaishouCloudConfig() {
|
||||
setCollapsed(localId, false)
|
||||
}
|
||||
|
||||
function handleCloudSourceKeysChanged(item: EditableItem) {
|
||||
const sourceKeys = normalizeCloudSourceKeys(item.cloudSourceKeys)
|
||||
item.cloudSourceKeys = sourceKeys
|
||||
item.cloudSkuId = 0
|
||||
item.cloudSkuName = ''
|
||||
}
|
||||
|
||||
async function focusValidationTarget(localId: string) {
|
||||
if (!localId) {
|
||||
return
|
||||
@@ -524,6 +557,7 @@ export function useKuaishouCloudConfig() {
|
||||
getRuleState,
|
||||
getExternalMatchSummary,
|
||||
getCloudSkuSummary,
|
||||
getCloudSourceSummary,
|
||||
getConsumeShopSummary,
|
||||
// consume shops
|
||||
getKuaishouConsumeShopOptions,
|
||||
@@ -531,6 +565,7 @@ export function useKuaishouCloudConfig() {
|
||||
getDefaultKuaishouConsumeShop,
|
||||
formatKuaishouConsumeShopOption,
|
||||
handleKuaishouConsumeShopSelected,
|
||||
handleCloudSourceKeysChanged,
|
||||
// collapse
|
||||
isCollapsed,
|
||||
setCollapsed,
|
||||
|
||||
+4
-1
@@ -42,6 +42,9 @@ export function useKuaishouCloudNinetyone(
|
||||
const defaultShop = config.getDefaultKuaishouConsumeShop()
|
||||
const shopOpts = config.getKuaishouConsumeShopOptions()
|
||||
const shop = defaultShop || (shopOpts.length > 0 ? shopOpts[0] : null)
|
||||
const sourceKeys = config.cloudtentaclesSourceOptions.value[0]?.key
|
||||
? [config.cloudtentaclesSourceOptions.value[0].key]
|
||||
: []
|
||||
return {
|
||||
localId: crypto.randomUUID(),
|
||||
id: '',
|
||||
@@ -56,7 +59,7 @@ export function useKuaishouCloudNinetyone(
|
||||
externalItemId: productNo,
|
||||
externalSkuName: productName,
|
||||
resolvedSkuName: productName,
|
||||
cloudSourceKey: 'default',
|
||||
cloudSourceKeys: sourceKeys,
|
||||
cloudSkuId: 0,
|
||||
cloudSkuName: '',
|
||||
vnKey: '1',
|
||||
|
||||
+3
-11
@@ -12,7 +12,7 @@ export function useKuaishouCloudSku(cloudtentaclesSourceOptions?: { value: { key
|
||||
const cloudSkuCatalogBySourceKey = ref<Record<string, AdminCloudtentaclesSkuItem[]>>({})
|
||||
|
||||
function getSourceKey(item: EditableItem) {
|
||||
return String(item.cloudSourceKey || 'default').trim()
|
||||
return String(item.cloudSourceKeys[0] || '').trim()
|
||||
}
|
||||
|
||||
async function ensureCloudSkuCatalogLoaded(item: EditableItem, force = false) {
|
||||
@@ -149,19 +149,13 @@ export function useKuaishouCloudSku(cloudtentaclesSourceOptions?: { value: { key
|
||||
const count = cloudSkuCatalogBySourceKey.value[sourceKey]?.length ?? 0
|
||||
showSuccess(`cloud SKU 列表(${sourceKey})已刷新,共 ${count} 条`)
|
||||
} else {
|
||||
// No item provided — refresh all configured sourceKeys, or at least 'default'
|
||||
const cachedKeys = Object.keys(cloudSkuCatalogBySourceKey.value)
|
||||
const configuredKeys = cloudtentaclesSourceOptions?.value?.map((s) => s.key) || []
|
||||
const keysToRefresh =
|
||||
cachedKeys.length > 0
|
||||
? cachedKeys
|
||||
: configuredKeys.length > 0
|
||||
? configuredKeys
|
||||
: ['default']
|
||||
const keysToRefresh = cachedKeys.length > 0 ? cachedKeys : configuredKeys
|
||||
|
||||
for (const key of keysToRefresh) {
|
||||
await ensureCloudSkuCatalogLoaded(
|
||||
{ cloudSourceKey: key, localId: '' } as EditableItem,
|
||||
{ cloudSourceKeys: [key], localId: '' } as EditableItem,
|
||||
true,
|
||||
)
|
||||
}
|
||||
@@ -177,8 +171,6 @@ export function useKuaishouCloudSku(cloudtentaclesSourceOptions?: { value: { key
|
||||
}
|
||||
|
||||
const cloudSkuCatalogLoading = ref(false)
|
||||
// Maintain backward-compat: derive a combined loading state
|
||||
// The template uses cloudSkuCatalogLoading for the refresh button spinner
|
||||
function syncCloudSkuCatalogLoading() {
|
||||
cloudSkuCatalogLoading.value = Object.values(cloudSkuCatalogLoadingBySourceKey.value).some(
|
||||
Boolean,
|
||||
|
||||
@@ -221,19 +221,14 @@ const emit = defineEmits<{
|
||||
<el-collapse-item name="cloud" title="Cloud 资源与发货">
|
||||
<div class="flow-meta-list flow-meta-list--two-column">
|
||||
<div>
|
||||
<span>规则主账号</span><strong>{{ flow.binding.cloudSourceKey || '-' }}</strong>
|
||||
<span>账号优先级</span>
|
||||
<strong>{{
|
||||
flow.binding.cloudSourceKeys?.length ? flow.binding.cloudSourceKeys.join(' / ') : '-'
|
||||
}}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>实际使用账号</span>
|
||||
<strong>{{ flow.binding.resolvedSourceKey || flow.binding.cloudSourceKey || '-' }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>备选账号</span>
|
||||
<strong>{{
|
||||
flow.binding.cloudSourceKeyFallbacks?.length
|
||||
? flow.binding.cloudSourceKeyFallbacks.join(' / ')
|
||||
: '-'
|
||||
}}</strong>
|
||||
<strong>{{ flow.binding.resolvedSourceKey || '-' }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>cloud SKU</span>
|
||||
|
||||
Reference in New Issue
Block a user