修复小店核销bug, 链接10分钟
This commit is contained in:
@@ -5,6 +5,7 @@ import { showError, showSuccess } from '@/lib/feedback'
|
||||
import {
|
||||
fetchAdminCloudtentaclesSkuList,
|
||||
fetchAdminKuaishouCloudFulfillmentConfig,
|
||||
fetchAdminKuaishouEticketSourceConfig,
|
||||
fetchAdminNinetyoneOrders,
|
||||
saveAdminKuaishouCloudFulfillmentConfig,
|
||||
} from '@/services/admin'
|
||||
@@ -12,6 +13,7 @@ import type {
|
||||
AdminCloudtentaclesSkuItem,
|
||||
AdminKuaishouCloudFulfillmentConfig,
|
||||
AdminKuaishouCloudFulfillmentItem,
|
||||
AdminKuaishouEticketShopConfigItem,
|
||||
AdminNinetyoneOrderItem,
|
||||
} from '@/types/admin'
|
||||
import { hasAdminRole } from '@/utils/admin-auth'
|
||||
@@ -43,6 +45,7 @@ const importedNinetyoneOrderKeys = ref<string[]>([])
|
||||
const cloudSkuCatalogLoading = ref(false)
|
||||
const cloudSkuCatalogErrorMessage = ref('')
|
||||
const cloudSkuCatalog = ref<AdminCloudtentaclesSkuItem[]>([])
|
||||
const kuaishouConsumeShops = ref<AdminKuaishouEticketShopConfigItem[]>([])
|
||||
const ninetyoneLookupForm = reactive({
|
||||
status: 'pending_config' as 'pending_config' | 'all' | 'manual_failed',
|
||||
page: 1,
|
||||
@@ -83,6 +86,7 @@ const ninetyoneLookupMetrics = computed(() => {
|
||||
})
|
||||
|
||||
function createEmptyItem(): EditableItem {
|
||||
const defaultShop = getDefaultKuaishouConsumeShop()
|
||||
return {
|
||||
localId: crypto.randomUUID(),
|
||||
id: '',
|
||||
@@ -105,13 +109,14 @@ function createEmptyItem(): EditableItem {
|
||||
minAssetReserve: 0,
|
||||
autoReturnNumberAfterDispatch: false,
|
||||
autoConsumeAfterDispatch: false,
|
||||
kuaishouConsumeShopId: '',
|
||||
kuaishouConsumeShopName: '',
|
||||
kuaishouConsumeShopId: defaultShop?.shopId || '',
|
||||
kuaishouConsumeShopName: defaultShop?.kshopName || '',
|
||||
notes: '',
|
||||
}
|
||||
}
|
||||
|
||||
function mapEditableItem(item: AdminKuaishouCloudFulfillmentItem): EditableItem {
|
||||
const matchedShop = findKuaishouConsumeShop(item.kuaishouConsumeShopId, item.kuaishouConsumeShopName)
|
||||
return {
|
||||
localId: crypto.randomUUID(),
|
||||
id: item.id || crypto.randomUUID(),
|
||||
@@ -134,13 +139,14 @@ function mapEditableItem(item: AdminKuaishouCloudFulfillmentItem): EditableItem
|
||||
minAssetReserve: Number(item.minAssetReserve || 0) || 0,
|
||||
autoReturnNumberAfterDispatch: item.autoReturnNumberAfterDispatch === true,
|
||||
autoConsumeAfterDispatch: item.autoConsumeAfterDispatch === true,
|
||||
kuaishouConsumeShopId: item.kuaishouConsumeShopId || '',
|
||||
kuaishouConsumeShopName: item.kuaishouConsumeShopName || '',
|
||||
kuaishouConsumeShopId: matchedShop?.shopId || item.kuaishouConsumeShopId || '',
|
||||
kuaishouConsumeShopName: matchedShop?.kshopName || item.kuaishouConsumeShopName || '',
|
||||
notes: item.notes || '',
|
||||
}
|
||||
}
|
||||
|
||||
function mapSaveItem(item: EditableItem): AdminKuaishouCloudFulfillmentItem {
|
||||
const matchedShop = findKuaishouConsumeShop(item.kuaishouConsumeShopId, item.kuaishouConsumeShopName)
|
||||
return {
|
||||
id: item.id.trim() || item.internalSkuCode.trim() || item.localId,
|
||||
enabled: item.enabled,
|
||||
@@ -162,8 +168,8 @@ function mapSaveItem(item: EditableItem): AdminKuaishouCloudFulfillmentItem {
|
||||
minAssetReserve: Math.max(0, Number(item.minAssetReserve || 0) || 0),
|
||||
autoReturnNumberAfterDispatch: item.autoReturnNumberAfterDispatch,
|
||||
autoConsumeAfterDispatch: item.autoConsumeAfterDispatch,
|
||||
kuaishouConsumeShopId: item.kuaishouConsumeShopId.trim(),
|
||||
kuaishouConsumeShopName: item.kuaishouConsumeShopName.trim(),
|
||||
kuaishouConsumeShopId: String(matchedShop?.shopId || item.kuaishouConsumeShopId).trim(),
|
||||
kuaishouConsumeShopName: String(matchedShop?.kshopName || item.kuaishouConsumeShopName).trim(),
|
||||
notes: item.notes.trim(),
|
||||
}
|
||||
}
|
||||
@@ -193,6 +199,8 @@ function hasMeaningfulContent(item: EditableItem) {
|
||||
|| item.minAssetReserve !== 0
|
||||
|| item.autoReturnNumberAfterDispatch
|
||||
|| item.autoConsumeAfterDispatch
|
||||
|| item.kuaishouConsumeShopId.trim()
|
||||
|| item.kuaishouConsumeShopName.trim()
|
||||
|| item.enabled !== true,
|
||||
)
|
||||
}
|
||||
@@ -201,7 +209,7 @@ function isItemComplete(item: EditableItem) {
|
||||
return Boolean(
|
||||
item.internalSkuCode.trim()
|
||||
&& Number(item.cloudSkuId || 0) > 0
|
||||
&& true
|
||||
&& (!item.autoConsumeAfterDispatch || Boolean(item.kuaishouConsumeShopId.trim()))
|
||||
&& hasExternalMatch(item),
|
||||
)
|
||||
}
|
||||
@@ -225,6 +233,10 @@ function resolveValidation(item: EditableItem, index: number): ValidationState {
|
||||
return { localId: item.localId, message: `${title} 至少填写一种外部匹配条件` }
|
||||
}
|
||||
|
||||
if (item.autoConsumeAfterDispatch && !item.kuaishouConsumeShopId.trim()) {
|
||||
return { localId: item.localId, message: `${title} 已开启发货后核销,需要选择快手核销店铺` }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -280,9 +292,36 @@ function getExternalMatchSummary(item: EditableItem) {
|
||||
return parts.length > 0 ? parts.join(' / ') : '未设置外部命中条件'
|
||||
}
|
||||
|
||||
function getKuaishouConsumeShopOptions() {
|
||||
return kuaishouConsumeShops.value.filter((shop) => shop.enabled !== false && shop.hasCookie)
|
||||
}
|
||||
|
||||
function findKuaishouConsumeShop(shopId = '', shopName = '') {
|
||||
const normalizedShopId = String(shopId || '').trim()
|
||||
const normalizedShopName = String(shopName || '').trim()
|
||||
return getKuaishouConsumeShopOptions().find((shop) => (
|
||||
(normalizedShopId && shop.shopId === normalizedShopId)
|
||||
|| (normalizedShopName && shop.kshopName === normalizedShopName)
|
||||
)) || null
|
||||
}
|
||||
|
||||
function getDefaultKuaishouConsumeShop() {
|
||||
return getKuaishouConsumeShopOptions()[0] || null
|
||||
}
|
||||
|
||||
function formatKuaishouConsumeShopOption(shop: AdminKuaishouEticketShopConfigItem) {
|
||||
return `${shop.kshopName || '未命名快手小店'} · ${shop.shopId}`
|
||||
}
|
||||
|
||||
function handleKuaishouConsumeShopSelected(item: EditableItem) {
|
||||
const matchedShop = findKuaishouConsumeShop(item.kuaishouConsumeShopId)
|
||||
item.kuaishouConsumeShopName = matchedShop?.kshopName || ''
|
||||
}
|
||||
|
||||
function getConsumeShopSummary(item: EditableItem) {
|
||||
const name = item.kuaishouConsumeShopName.trim()
|
||||
const id = item.kuaishouConsumeShopId.trim()
|
||||
const matchedShop = findKuaishouConsumeShop(item.kuaishouConsumeShopId, item.kuaishouConsumeShopName)
|
||||
const name = String(matchedShop?.kshopName || item.kuaishouConsumeShopName).trim()
|
||||
const id = String(matchedShop?.shopId || item.kuaishouConsumeShopId).trim()
|
||||
|
||||
if (name && id) {
|
||||
return `${name} · ${id}`
|
||||
@@ -343,7 +382,11 @@ async function loadConfigs() {
|
||||
errorMessage.value = ''
|
||||
|
||||
try {
|
||||
const response = await fetchAdminKuaishouCloudFulfillmentConfig()
|
||||
const [response, eticketResponse] = await Promise.all([
|
||||
fetchAdminKuaishouCloudFulfillmentConfig(),
|
||||
fetchAdminKuaishouEticketSourceConfig(),
|
||||
])
|
||||
kuaishouConsumeShops.value = Array.isArray(eticketResponse.data.source.shops) ? eticketResponse.data.source.shops : []
|
||||
filePath.value = response.data.filePath
|
||||
enabled.value = response.data.source.enabled !== false
|
||||
items.value = (response.data.source.items || []).map(mapEditableItem)
|
||||
@@ -373,6 +416,7 @@ function removeItem(localId: string) {
|
||||
function createItemFromNinetyoneOrder(item: AdminNinetyoneOrderItem): EditableItem {
|
||||
const productNo = String(item.productNo || '').trim()
|
||||
const productName = String(item.productName || productNo).trim()
|
||||
const defaultShop = getDefaultKuaishouConsumeShop()
|
||||
return {
|
||||
localId: crypto.randomUUID(),
|
||||
id: '',
|
||||
@@ -395,8 +439,8 @@ function createItemFromNinetyoneOrder(item: AdminNinetyoneOrderItem): EditableIt
|
||||
minAssetReserve: 0,
|
||||
autoReturnNumberAfterDispatch: false,
|
||||
autoConsumeAfterDispatch: false,
|
||||
kuaishouConsumeShopId: '',
|
||||
kuaishouConsumeShopName: '',
|
||||
kuaishouConsumeShopId: defaultShop?.shopId || '',
|
||||
kuaishouConsumeShopName: defaultShop?.kshopName || '',
|
||||
notes: `从 91卡券订单 ${item.orderNo} 导入`,
|
||||
}
|
||||
}
|
||||
@@ -978,13 +1022,31 @@ onMounted(loadConfigs)
|
||||
</div>
|
||||
|
||||
<div v-if="!isCollapsed(item.localId)" class="mapping-extra">
|
||||
<label class="field-block">
|
||||
<span>快手核销店铺 ID</span>
|
||||
<input v-model="item.kuaishouConsumeShopId" class="text-input" maxlength="80" placeholder="预留给后续自动核销" />
|
||||
<label class="field-block field-wide">
|
||||
<span>快手核销店铺</span>
|
||||
<select
|
||||
v-model="item.kuaishouConsumeShopId"
|
||||
class="text-input"
|
||||
@change="handleKuaishouConsumeShopSelected(item)"
|
||||
>
|
||||
<option value="">请选择已配置 Cookie 的快手小店</option>
|
||||
<option
|
||||
v-for="shop in getKuaishouConsumeShopOptions()"
|
||||
:key="shop.shopId"
|
||||
:value="shop.shopId"
|
||||
>
|
||||
{{ formatKuaishouConsumeShopOption(shop) }}
|
||||
</option>
|
||||
</select>
|
||||
<small class="field-help">来自“平台店铺 -> 快手小店核销”配置,保存时会自动带出店铺名。</small>
|
||||
</label>
|
||||
<label class="field-block">
|
||||
<span>快手核销店铺名</span>
|
||||
<input v-model="item.kuaishouConsumeShopName" class="text-input" maxlength="120" placeholder="便于快速确认" />
|
||||
<span>核销店铺 ID</span>
|
||||
<input :value="item.kuaishouConsumeShopId || '-'" class="text-input text-input--readonly" readonly />
|
||||
</label>
|
||||
<label class="field-block">
|
||||
<span>核销店铺名</span>
|
||||
<input :value="item.kuaishouConsumeShopName || '-'" class="text-input text-input--readonly" readonly />
|
||||
</label>
|
||||
<label class="field-block field-wide">
|
||||
<span>备注</span>
|
||||
|
||||
Reference in New Issue
Block a user