diff --git a/src/utils/http/index.ts b/src/utils/http/index.ts index daf4bf8..9301d51 100644 --- a/src/utils/http/index.ts +++ b/src/utils/http/index.ts @@ -7,7 +7,7 @@ import { normalizeApiError } from '@/utils/business/apiError' import { syncCompatibleIdFields } from '@/utils/business/id' const axiosInstance = axios.create({ - timeout: 15000, // 请求超时时间(毫秒) + timeout: 90000, // 请求超时时间(毫秒) baseURL: import.meta.env.DEV ? '' : import.meta.env.VITE_API_URL, // 开发服务器使用代理,其他模式使用完整URL withCredentials: false, // 异步请求携带cookie transformRequest: [ diff --git a/src/views/asset-management/device-list/index.vue b/src/views/asset-management/device-list/index.vue index 7655a89..a3c64c6 100644 --- a/src/views/asset-management/device-list/index.vue +++ b/src/views/asset-management/device-list/index.vue @@ -108,6 +108,7 @@ v-model="allocateForm.target_shop_id" :options="shopCascadeOptions" :props="shopCascadeProps" + :before-filter="handleAllocateShopBeforeFilter" placeholder="请选择目标店铺" clearable filterable @@ -1049,6 +1050,62 @@ const batchRealnamePolicyError = ref('') const exportDialogVisible = ref(false) const shopCascadeOptions = ref([]) + let allocateShopSearchRequestId = 0 + const mapShopCascadeNodes = (items: any[]) => { + const seen = new Set() + + return items.reduce((nodes, item) => { + if (seen.has(item.id)) return nodes + + seen.add(item.id) + nodes.push({ + value: item.id, + label: item.shop_name, + leaf: !item.has_children + }) + return nodes + }, []) + } + const handleAllocateShopBeforeFilter = async (query: string) => { + const keyword = query.trim() + if (!keyword) return true + + const requestId = ++allocateShopSearchRequestId + try { + const shopResponse = await ShopService.getShops({ + page: 1, + page_size: 20, + shop_name: keyword + }) + if (requestId !== allocateShopSearchRequestId) return false + if (shopResponse.code !== 0) { + shopCascadeOptions.value = [] + return false + } + + const parentIds = Array.from( + new Set((shopResponse.data.items || []).map((shop) => shop.parent_id ?? null)) + ) + const cascadeResponses = await Promise.all( + parentIds.map((parentId) => + ShopService.getShopsCascade({ + shop_name: keyword, + parent_id: parentId ?? undefined + }) + ) + ) + if (requestId !== allocateShopSearchRequestId) return false + + shopCascadeOptions.value = mapShopCascadeNodes( + cascadeResponses.flatMap((response) => (response.code === 0 ? response.data || [] : [])) + ) + return true + } catch (error) { + if (requestId === allocateShopSearchRequestId) shopCascadeOptions.value = [] + console.error('搜索批量分配目标店铺失败:', error) + return false + } + } const shopCascadeProps = { lazy: true, checkStrictly: true, @@ -1059,12 +1116,7 @@ try { const res = await ShopService.getShopsCascade({ parent_id: parentId }) if (res.code === 0) { - const nodes = (res.data || []).map((item: any) => ({ - value: item.id, - label: item.shop_name, - leaf: !item.has_children - })) - resolve(nodes) + resolve(mapShopCascadeNodes(res.data || [])) } else { resolve([]) } @@ -1081,11 +1133,7 @@ try { const res = await ShopService.getShopsCascade({ parent_id: undefined }) if (res.code === 0) { - shopCascadeOptions.value = (res.data || []).map((item: any) => ({ - value: item.id, - label: item.shop_name, - leaf: !item.has_children - })) + shopCascadeOptions.value = mapShopCascadeNodes(res.data || []) } } catch (error) { console.error('加载顶级店铺失败:', error) @@ -2527,10 +2575,7 @@ const showEnterpriseDeviceAuthorizeDialog = async () => { resetEnterpriseDeviceAuthorizeForm() - await Promise.all([ - handleSearchEnterprise(), - loadTopLevelShopCascadeOptions() - ]) + await Promise.all([handleSearchEnterprise(), loadTopLevelShopCascadeOptions()]) enterpriseDeviceAuthorizeDialogVisible.value = true enterpriseDeviceAuthorizeFormRef.value?.clearValidate() } diff --git a/src/views/asset-management/exchange-management/index.vue b/src/views/asset-management/exchange-management/index.vue index 7cd4032..f3e8379 100644 --- a/src/views/asset-management/exchange-management/index.vue +++ b/src/views/asset-management/exchange-management/index.vue @@ -268,8 +268,8 @@ {{ createNewDeviceEmptyMessage }} - -
{{ createDirectInheritedShopHint }}
+ +
新资产会继承旧资产店铺
@@ -771,11 +771,6 @@ return undefined } - const createDirectInheritedShopHint = computed(() => { - const shopName = getShopDisplayName(createSelectedNewAsset.value) - return shopName ? `换货完成后将归属:${shopName}` : '' - }) - const shipInheritedShopDisplayText = computed(() => { const shopName = getShopDisplayName(shipSelectedNewAsset.value) diff --git a/src/views/asset-management/iot-card-management/index.vue b/src/views/asset-management/iot-card-management/index.vue index 7492da4..f3eccdc 100644 --- a/src/views/asset-management/iot-card-management/index.vue +++ b/src/views/asset-management/iot-card-management/index.vue @@ -112,6 +112,7 @@ v-model="allocateForm.to_shop_id" :options="shopCascadeOptions" :props="shopCascadeProps" + :before-filter="handleAllocateShopBeforeFilter" placeholder="请选择目标店铺" clearable filterable @@ -1523,6 +1524,62 @@ // 店铺相关 const shopCascadeOptions = ref([]) + let allocateShopSearchRequestId = 0 + const mapShopCascadeNodes = (items: any[]) => { + const seen = new Set() + + return items.reduce((nodes, item) => { + if (seen.has(item.id)) return nodes + + seen.add(item.id) + nodes.push({ + value: item.id, + label: item.shop_name, + leaf: !item.has_children + }) + return nodes + }, []) + } + const handleAllocateShopBeforeFilter = async (query: string) => { + const keyword = query.trim() + if (!keyword) return true + + const requestId = ++allocateShopSearchRequestId + try { + const shopResponse = await ShopService.getShops({ + page: 1, + page_size: 20, + shop_name: keyword + }) + if (requestId !== allocateShopSearchRequestId) return false + if (shopResponse.code !== 0) { + shopCascadeOptions.value = [] + return false + } + + const parentIds = Array.from( + new Set((shopResponse.data.items || []).map((shop) => shop.parent_id ?? null)) + ) + const cascadeResponses = await Promise.all( + parentIds.map((parentId) => + ShopService.getShopsCascade({ + shop_name: keyword, + parent_id: parentId ?? undefined + }) + ) + ) + if (requestId !== allocateShopSearchRequestId) return false + + shopCascadeOptions.value = mapShopCascadeNodes( + cascadeResponses.flatMap((response) => (response.code === 0 ? response.data || [] : [])) + ) + return true + } catch (error) { + if (requestId === allocateShopSearchRequestId) shopCascadeOptions.value = [] + console.error('搜索批量分配目标店铺失败:', error) + return false + } + } const shopCascadeProps = { lazy: true, checkStrictly: true, @@ -1533,12 +1590,7 @@ try { const res = await ShopService.getShopsCascade({ parent_id: parentId }) if (res.code === 0) { - const nodes = (res.data || []).map((item: any) => ({ - value: item.id, - label: item.shop_name, - leaf: !item.has_children - })) - resolve(nodes) + resolve(mapShopCascadeNodes(res.data || [])) } else { resolve([]) } @@ -1555,11 +1607,7 @@ try { const res = await ShopService.getShopsCascade({ parent_id: undefined }) if (res.code === 0) { - shopCascadeOptions.value = (res.data || []).map((item: any) => ({ - value: item.id, - label: item.shop_name, - leaf: !item.has_children - })) + shopCascadeOptions.value = mapShopCascadeNodes(res.data || []) } } catch (error) { console.error('加载顶级店铺失败:', error) @@ -2486,6 +2534,7 @@ return } allocateDialogVisible.value = true + shopCascadeOptions.value = [] Object.assign(allocateForm, { selection_type: CardSelectionType.LIST, to_shop_id: undefined, @@ -2700,10 +2749,7 @@ const showEnterpriseCardRecallDialog = async () => { resetEnterpriseCardRecallForm() - await Promise.all([ - handleSearchEnterprise(), - loadAllocateCarrierOptions() - ]) + await Promise.all([handleSearchEnterprise(), loadAllocateCarrierOptions()]) enterpriseCardRecallDialogVisible.value = true enterpriseCardRecallFormRef.value?.clearValidate() } @@ -2823,10 +2869,7 @@ selection_type: selectedCards.value.length > 0 ? CardSelectionType.LIST : CardSelectionType.FILTER }) - await Promise.all([ - loadPackageSeriesList(), - loadAllocateCarrierOptions() - ]) + await Promise.all([loadPackageSeriesList(), loadAllocateCarrierOptions()]) seriesBindingDialogVisible.value = true seriesBindingFormRef.value?.clearValidate() }