From 40660f5bebed8f2715f55c7810216a6c453b5fbd Mon Sep 17 00:00:00 2001 From: 97694731 <97694731@qq.com> Date: Tue, 30 Jun 2026 15:19:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=80=E9=94=AE=E5=8F=91=E5=B8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/config.js | 2 +- src/api/inventory.js | 7 +- src/api/outbound.js | 3 +- src/api/product.js | 28 ++ src/api/salesOrder.js | 14 +- src/api/shippingOrder.js | 3 +- src/components/inventory/byGoods/index.vue | 18 +- src/components/inventory/byLocation/index.vue | 29 +- src/components/product/byGoods/index.vue | 283 +++++++++++++++++- src/components/warehouseSelect/index.vue | 143 +++++++++ src/components/wave/goosList.vue | 6 +- src/utils/printFlow/printFlow.js | 4 + src/views/config/config.vue | 12 +- src/views/inventory/Inventory.vue | 15 +- src/views/outbound/Outbound.vue | 40 ++- src/views/salesOrder/salesInfoList.vue | 23 +- src/views/salesOrder/salesOrder.vue | 34 ++- src/views/shippingOrder/shippingOrder.vue | 28 +- 18 files changed, 642 insertions(+), 50 deletions(-) create mode 100644 src/components/warehouseSelect/index.vue diff --git a/src/api/config.js b/src/api/config.js index 20c6ac5b..09aec6d4 100644 --- a/src/api/config.js +++ b/src/api/config.js @@ -58,7 +58,7 @@ export const kongfzLogin = (username, password, ip, port) => { /** * 批量提交 Token 到核价器 - * @param {Array<{username: string, token: string}>} tokens - 账号 Token 列表 + * @param {Array<{username: string, token: string, login_name: string}>} tokens - 账号 Token 列表 * @param {string} ip - 核价器 IP * @param {string} port - 核价器端口 * @returns {Promise} diff --git a/src/api/inventory.js b/src/api/inventory.js index 7c9c3921..7be22441 100644 --- a/src/api/inventory.js +++ b/src/api/inventory.js @@ -63,13 +63,16 @@ export const fetchInventoryStats = async (warehouse_id) => { * 按库位分组获取商品库存列表 GET /api/inventory/grouped-list * 返回按库位分组的库存数据,每组包含库位信息和该库位下的商品列表 * @param {Object} params - 请求参数 - * @param {string} [params.keyword] - 搜索关键词(库位编号/商品名称/条码) + * @param {number} [params.warehouse_id] - 仓库ID + * @param {number} [params.location_id] - 库位ID * @param {number} [params.page] - 当前页码 * @param {number} [params.pageSize] - 每页条数 * @returns {Promise<{ list: Array, total: number }>} */ -export const fetchGoodsListByLocation = async ({ keyword, page, pageSize } = {}) => { +export const fetchGoodsListByLocation = async ({ warehouse_id, location_id, keyword, page, pageSize } = {}) => { const params = { + warehouse_id: warehouse_id || undefined, + location_id: location_id || undefined, keyword: keyword || undefined, page, page_size: pageSize diff --git a/src/api/outbound.js b/src/api/outbound.js index 23ba7f26..a0021141 100644 --- a/src/api/outbound.js +++ b/src/api/outbound.js @@ -43,11 +43,12 @@ const normalizeListResponse = (payload) => { * @param {string} [params.page_size] - 每页条数 * @returns {Promise<{ list: Array, total: number }>} 标准化后的出库单列表 */ -export const fetchOutboundList = async ({ out_no, status, warehouse_id, customer_id, shop_type, sales_order_id, start_date, end_date, association_order_no, logistics_no, page, page_size }) => { +export const fetchOutboundList = async ({ out_no, status, warehouse_id, location_id, customer_id, shop_type, sales_order_id, start_date, end_date, association_order_no, logistics_no, page, page_size }) => { const params = { out_no: out_no || undefined, status: status || undefined, warehouse_id: warehouse_id || undefined, + location_id: location_id || undefined, customer_id: customer_id || undefined, shop_type: shop_type || undefined, sales_order_id: sales_order_id || undefined, diff --git a/src/api/product.js b/src/api/product.js index c6805eb5..89531537 100644 --- a/src/api/product.js +++ b/src/api/product.js @@ -1,8 +1,13 @@ import request from '@/utils/request' +import axios from 'axios' /** 商品模块 API 基础路径 */ const API_BASE = '/product' +/** 不知鱼书 API 基础地址 */ +// const BZY_API_BASE = 'http://192.168.101.127:8080' +const BZY_API_BASE = 'https://api.buzhiyushu.cn' + /** * 标准化列表接口返回的数据格式 * @param {Object} payload - 接口返回的原始响应对象,通常包含 data 字段 @@ -397,4 +402,27 @@ export const restoreProduct = async ({ destroy_log_id }) => { */ export const syncGoodsFromWdt = async ({ start_time, end_time }) => { return request.get('/wangdian/query-goods', { params: { start_time, end_time } }) +} + +/** + * 发布商品到选中店铺 + * @param {Object} params + * @param {number} params.oneClick - 是否一键发布 1=是 0=否 + * @param {number} params.userId - 用户的 about_id + * @param {string} [params.shopIds] - 选中的店铺ID,逗号分隔(一键发布时使用) + * @param {string} [params.productIds] - 选中的商品ID,逗号分隔(普通发布时使用) + * @returns {Promise} + */ +export const releaseGoods = async ({ oneClick, userId, shopIds, productIds }) => { + const res = await axios.post(`${BZY_API_BASE}/zhishu/product/releaseGoods`, { + oneClick, + userId, + ...(shopIds !== undefined && { shopIds }), + ...(productIds !== undefined && { productIds }) + }) + const data = res.data + if (data && data.code !== 200) { + throw { response: { data } } + } + return data } \ No newline at end of file diff --git a/src/api/salesOrder.js b/src/api/salesOrder.js index 82bb9391..bc8184c2 100644 --- a/src/api/salesOrder.js +++ b/src/api/salesOrder.js @@ -25,6 +25,7 @@ const normalizeListResponse = (payload) => { * @param {number} [params.status] - 订单状态筛选 * @param {number} [params.customer_id] - 平台ID筛选 * @param {number} [params.warehouse_id] - 仓库ID筛选 + * @param {number} [params.location_id] - 库位ID筛选 * @param {number} [params.page] - 当前页码 * @param {number} [params.pageSize] - 每页条数 * @param {string} [params.sort_by] - 排序字段 @@ -33,12 +34,13 @@ const normalizeListResponse = (payload) => { * @param {string} [params.logistics_no] - 快递单号 * @returns {Promise<{ list: Array, total: number }>} 标准化后的销售订单列表 */ -export const fetchSalesOrderList = async ({ keyword, status, shop_type, warehouse_id, page, pageSize, sort_by, sort_order, association_order_no, logistics_no }) => { +export const fetchSalesOrderList = async ({ keyword, status, shop_type, warehouse_id, location_id, page, pageSize, sort_by, sort_order, association_order_no, logistics_no }) => { const params = { so_no: keyword || undefined, status, shop_type: shop_type || undefined, warehouse_id, + location_id: location_id || undefined, page, page_size: pageSize, sort_by: sort_by || 'updated_at', @@ -139,14 +141,22 @@ export const returnSalesOrderItem = async (data) => { * @param {Object} params - 请求参数 * @param {number} params.page - 当前页码 * @param {number} params.pageSize - 每页条数 + * @param {number} [params.warehouse_id] - 仓库ID + * @param {number} [params.location_id] - 库位ID + * @param {number} [params.status] - 状态 + * @param {string} [params.keyword] - 销售订单号 * @param {string} [params.association_order_no] - 第三方订单编号 * @param {string} [params.logistics_no] - 快递单号 * @returns {Promise<{list: Array, total: number}>} */ -export const fetchSalesOrderDetails = async ({ page, pageSize, shop_type, association_order_no, logistics_no }) => { +export const fetchSalesOrderDetails = async ({ page, pageSize, warehouse_id, location_id, status, keyword, shop_type, association_order_no, logistics_no }) => { const params = { page, page_size: pageSize, + warehouse_id: warehouse_id || undefined, + location_id: location_id || undefined, + status: status || undefined, + so_no: keyword || undefined, shop_type: shop_type || undefined, association_order_no: association_order_no || undefined, logistics_no: logistics_no || undefined diff --git a/src/api/shippingOrder.js b/src/api/shippingOrder.js index 917b534c..9043a4b0 100644 --- a/src/api/shippingOrder.js +++ b/src/api/shippingOrder.js @@ -38,12 +38,13 @@ const normalizeListResponse = (payload) => { * @param {number} [params.pageSize] - 每页条数 * @returns {Promise<{ list: Array, total: number }>} 标准化后的发货单列表 */ -export const fetchShippingOrderList = async ({ check_no, status, shop_type, warehouse_id, sales_order_id, wave_task_id, association_order_no, logistics_no, page, pageSize }) => { +export const fetchShippingOrderList = async ({ check_no, status, shop_type, warehouse_id, location_id, sales_order_id, wave_task_id, association_order_no, logistics_no, page, pageSize }) => { const params = { check_no: check_no || undefined, status, shop_type: shop_type || undefined, warehouse_id, + location_id: location_id || undefined, sales_order_id, wave_task_id, association_order_no: association_order_no || undefined, diff --git a/src/components/inventory/byGoods/index.vue b/src/components/inventory/byGoods/index.vue index 9d96a769..d5d08bda 100644 --- a/src/components/inventory/byGoods/index.vue +++ b/src/components/inventory/byGoods/index.vue @@ -62,9 +62,7 @@ - - - + 搜索 重置 @@ -74,8 +72,7 @@ - + @@ -173,6 +170,7 @@ import { Search, Refresh, Box, Goods, CircleCheckFilled, CircleCheck, Location } import dayjs from 'dayjs' import { fetchInventoryList, fetchInventoryDetailList, inventorySummary } from '@/api/inventory' import { fetchWarehouseList } from '@/api/warehouse' +import WarehouseSelect from '@/components/warehouseSelect/index.vue' defineOptions({ name: 'InventoryByGoods' }) @@ -207,7 +205,8 @@ const summaryList = ref([]) const summaryParams = reactive({ isbn: '', name: '', - warehouse_id: null as number | null + warehouse_id: null as number | null, + location_id: null as number | null }) const summaryPagination = reactive({ current: 1, pageSize: 20, total: 0 }) @@ -248,6 +247,7 @@ const loadSummaryList = async (): Promise => { isbn: summaryParams.isbn || undefined, name: summaryParams.name || undefined, warehouse_id: summaryParams.warehouse_id || undefined, + location_id: summaryParams.location_id || undefined, page: summaryPagination.current, page_size: summaryPagination.pageSize }) @@ -309,10 +309,16 @@ const navigateToShippingOrder = (shippingNo: string) => { } // ==================== 重置 ==================== +const onSummaryWarehouseChange = (warehouseId: number | null) => { + summaryParams.warehouse_id = warehouseId + summaryParams.location_id = null +} + const resetSummaryParams = (): void => { summaryParams.isbn = '' summaryParams.name = '' summaryParams.warehouse_id = null + summaryParams.location_id = null summaryPagination.current = 1 loadSummaryList() } diff --git a/src/components/inventory/byLocation/index.vue b/src/components/inventory/byLocation/index.vue index dea0cfa2..c7c37d33 100644 --- a/src/components/inventory/byLocation/index.vue +++ b/src/components/inventory/byLocation/index.vue @@ -39,6 +39,12 @@ +
+ + 搜索 + 重置 +
+ ([]) +// 查询参数 +const queryParams = reactive({ + warehouse_id: null as number | null, + location_id: null as number | null +}) + // 下拉选项(用于明细弹窗中的仓库名称显示) const warehouseOptions = ref([]) const warehouseMap = ref>({}) @@ -267,10 +280,24 @@ const loadOptions = async (): Promise => { } } +const onLocationWarehouseChange = (warehouseId: number | null) => { + queryParams.warehouse_id = warehouseId + queryParams.location_id = null +} + +const resetQueryParams = (): void => { + queryParams.warehouse_id = null + queryParams.location_id = null + loadList() +} + const loadList = async (): Promise => { summaryLoading.value = true try { - const res = await fetchGoodsListByLocation() + const res = await fetchGoodsListByLocation({ + warehouse_id: queryParams.warehouse_id || undefined, + location_id: queryParams.location_id || undefined + }) summaryList.value = res.list || [] } catch (error) { ElMessage.error({ message: '加载库位库存失败', customClass: 'scan-error-message' }) diff --git a/src/components/product/byGoods/index.vue b/src/components/product/byGoods/index.vue index cc9459c6..5b576426 100644 --- a/src/components/product/byGoods/index.vue +++ b/src/components/product/byGoods/index.vue @@ -48,13 +48,13 @@ 导出 导出模板 导入 - 发布 - 一键发布 + 发布 + 一键发布 库存同步 批量修改货区 - @@ -244,6 +244,49 @@ + + + +
+ + +
+ +
@@ -253,8 +296,9 @@ import { ElMessage, ElMessageBox } from 'element-plus' import { Search, Refresh, MoreFilled, Upload, Edit, Delete } from '@element-plus/icons-vue' import GoodsPop from '@/components/goodsPop/index.vue' import dayjs from 'dayjs' -import { fetchProductList, retryProductPublish, importProductsByExcel, deleteProduct, destroyProduct, syncGoodsFromWdt } from '@/api/product' +import { fetchProductList, retryProductPublish, importProductsByExcel, deleteProduct, destroyProduct, syncGoodsFromWdt, releaseGoods } from '@/api/product' import { fetchWarehouseList } from '@/api/warehouse' +import { fetchShopList } from '@/api/shop' interface ShopListItem { shop_alias_name: string @@ -305,6 +349,7 @@ export default defineComponent({ const loading = ref(false) const tableData = ref([]) const selectedRows = ref([]) + const productTableRef = ref | null>(null) const loadedOnce = ref(false) const searchParams = reactive<{ @@ -568,6 +613,153 @@ export default defineComponent({ } // ========== 导入 Excel End ========== + // ========== 发布 / 一键发布 ========== + const publishMode = ref<'normal' | 'oneClick'>('normal') + const publishDialogVisible = ref(false) + const publishLoading = ref(false) + const publishSubmitting = ref(false) + + interface PublishShopItem { + shop_id: number + shop_alias_name: string + shop_name: string + shop_type: number + shop_type_name: string + } + + interface PublishShopGroup { + shop_type: number + label: string + shops: PublishShopItem[] + checkedIds: number[] + } + + const publishShopGroups = ref([]) + + const SHOP_TYPE_MAP: Record = { + 1: '拼多多', + 2: '孔夫子', + 5: '闲鱼' + } + + const TARGET_SHOP_TYPES = [1, 2, 5] + + const toggleGroupAll = (group: PublishShopGroup, val: boolean) => { + group.checkedIds = val ? group.shops.map(s => s.shop_id) : [] + } + + const loadPublishShops = async () => { + publishLoading.value = true + try { + const res = await fetchShopList({ pageSize: 100 }) + const allShops = (res as any).list || [] + const groups: PublishShopGroup[] = TARGET_SHOP_TYPES.map(type => ({ + shop_type: type, + label: SHOP_TYPE_MAP[type] || `类型${type}`, + shops: [], + checkedIds: [] + })) + for (const shop of allShops) { + const rawType = Number(shop.shopType ?? shop.shop_type) + const group = groups.find(g => g.shop_type === rawType) + if (group) { + group.shops.push({ + shop_id: Number(shop.id || shop.shop_id), + shop_alias_name: shop.shopAliasName || shop.shop_alias_name || shop.shopName || shop.shop_name || '', + shop_name: shop.shopName || shop.shop_name || '', + shop_type: rawType, + shop_type_name: SHOP_TYPE_MAP[rawType] || '' + }) + } + } + publishShopGroups.value = groups.filter(g => g.shops.length > 0) + } catch { + ElMessage.error({ message: '获取店铺列表失败', customClass: 'scan-error-message' }) + publishShopGroups.value = [] + } finally { + publishLoading.value = false + } + } + + const handlePublish = () => { + if (selectedRows.value.length === 0) { + ElMessage.warning({ message: '请先选择要发布的商品', customClass: 'scan-error-message' }) + return + } + + // 检查未落位商品 + const unplacedRows = selectedRows.value.filter(r => !r.warehouse_name) + if (unplacedRows.length > 0) { + ElMessage.warning({ + message: `当前勾选 ${unplacedRows.length} 个未落位商品,请重新选择`, + customClass: 'scan-error-message' + }) + return + } + + publishMode.value = 'normal' + publishShopGroups.value = [] + publishDialogVisible.value = true + } + + const handleOneClickPublish = () => { + publishMode.value = 'oneClick' + publishShopGroups.value = [] + publishDialogVisible.value = true + } + + const confirmPublish = async () => { + const allIds = publishShopGroups.value.flatMap(g => g.checkedIds) + if (allIds.length === 0) { + ElMessage.warning({ message: '请至少选择一个店铺', customClass: 'scan-error-message' }) + return + } + + const userInfoStr = localStorage.getItem('admin_userInfo') + if (!userInfoStr) { + ElMessage.error({ message: '未获取到用户信息', customClass: 'scan-error-message' }) + return + } + let aboutId: string + try { + const userInfo = JSON.parse(userInfoStr) + aboutId = userInfo.about_id + if (!aboutId) { + ElMessage.error({ message: '用户信息中缺少 about_id', customClass: 'scan-error-message' }) + return + } + } catch { + ElMessage.error({ message: '用户信息解析失败', customClass: 'scan-error-message' }) + return + } + + const baseParams: Record = { + userId: Number(aboutId), + shopIds: allIds.join(',') + } + if (publishMode.value === 'normal') { + const productIds = selectedRows.value.map(r => r.id).join(',') + baseParams.oneClick = 0 + baseParams.productIds = productIds + } else { + baseParams.oneClick = 1 + } + + publishSubmitting.value = true + try { + await releaseGoods(baseParams) + ElMessage.success({ message: `已成功发布到 ${allIds.length} 个店铺`, customClass: 'scan-success-message' }) + publishDialogVisible.value = false + } catch (err: any) { + console.error('发布失败', err) + const msg = err?.response?.data?.msg || err?.response?.data?.message || '发布失败,请稍后重试' + ElMessage.error({ message: msg, customClass: 'scan-error-message' }) + } finally { + publishSubmitting.value = false + } + } + // ========== 发布 End ========== + onMounted(() => { void loadProductList() }) @@ -583,7 +775,13 @@ export default defineComponent({ refreshList, selectedRows, handleSelectionChange, // 导入 importDialogVisible, importWarehouseId, importFile, importLoading, uploadRef, warehouseOptions, - handleImportClick, handleFileChange, handleImportSubmit + handleImportClick, handleFileChange, handleImportSubmit, + // 发布 / 一键发布 + publishMode, publishDialogVisible, publishLoading, publishSubmitting, publishShopGroups, + handleOneClickPublish, loadPublishShops, toggleGroupAll, confirmPublish, + // 发布 + handlePublish, + productTableRef } } }) @@ -667,4 +865,79 @@ export default defineComponent({ .shop-item { line-height: 1.4; } + +/* ========== 一键发布弹窗 ========== */ +.publish-dialog-body { + min-height: 200px; + max-height: 55vh; + overflow-y: auto; +} + +.publish-shop-group { + margin-bottom: 24px; +} + +.publish-group-header { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 12px; + padding: 8px 12px; + background: #f5f7fa; + border-radius: 8px; +} + +.publish-group-title { + font-size: 15px; + font-weight: 600; + color: #303133; +} + +.publish-group-count { + font-size: 13px; + color: #909399; +} + +.publish-shop-cards { + display: flex; + flex-wrap: wrap; + gap: 12px; + padding-left: 4px; +} + +.publish-shop-card { + width: 200px; + height: auto !important; + margin-right: 0 !important; +} + +.publish-shop-card :deep(.el-checkbox__input) { + align-self: center; + margin-top: 0; +} + +.publish-shop-card :deep(.el-checkbox__label) { + width: 100%; + padding: 0; + display: flex; + align-items: center; +} + +.shop-card-content { + padding: 12px 8px 12px 8px; + width: 100%; +} + +.shop-card-name { + font-size: 14px; + font-weight: 500; + color: #303133; + word-break: break-all; + margin-bottom: 4px; +} + +.shop-card-type { + font-size: 12px; + color: #909399; +} diff --git a/src/components/warehouseSelect/index.vue b/src/components/warehouseSelect/index.vue new file mode 100644 index 00000000..dcf19b18 --- /dev/null +++ b/src/components/warehouseSelect/index.vue @@ -0,0 +1,143 @@ + + + + + diff --git a/src/components/wave/goosList.vue b/src/components/wave/goosList.vue index 3541beca..47e2e8b1 100644 --- a/src/components/wave/goosList.vue +++ b/src/components/wave/goosList.vue @@ -237,10 +237,12 @@ async function refreshSalePrices() { } }) - // 核价检查 + // 核价检查:从核价器配置中读取统一默认价格(元→分) + const newPriceStr = localStorage.getItem('new_price') + const failPrice = newPriceStr ? parseFloat(newPriceStr) * 100 : 999900 if (list.length > 0) { const lastItem = list[list.length - 1] - if (lastItem.sale_price === 999900) { + if (lastItem.sale_price === failPrice) { const productId = lastItem.id if (productId !== lastFailedProductId) { isAlertShowing = true diff --git a/src/utils/printFlow/printFlow.js b/src/utils/printFlow/printFlow.js index c02b2ceb..a1466156 100644 --- a/src/utils/printFlow/printFlow.js +++ b/src/utils/printFlow/printFlow.js @@ -115,6 +115,10 @@ async function printWaybillForGroup(group, logisticsCompany = 'YUNDA') { }) console.log('createOrderBatch 返回:', createRes) + // 报错之后需要停下来 + if (createRes?.code !== 0) { + throw new Error(createRes?.msg || createRes?.message || '创建快递面单失败,请检查参数后重试') + } // 校验快递打印机配置 const expressPrinter = localStorage.getItem('printer_express') diff --git a/src/views/config/config.vue b/src/views/config/config.vue index edbbc395..9dc5be68 100644 --- a/src/views/config/config.vue +++ b/src/views/config/config.vue @@ -522,7 +522,7 @@ export default { try { // 依次登录每个已填写的账号 - const successfulAccounts: { username: string; token: string }[] = [] + const successfulAccounts: { username: string; token: string; login_name: string }[] = [] for (let i = 0; i < accounts.value.length; i++) { const item = accounts.value[i] if (item.account && item.password) { @@ -530,7 +530,7 @@ export default { const loginRes = await kongfzLogin(item.account, item.password, ip.value, port.value) console.log('核价器登录响应:', loginRes) if (loginRes?.code === 200 && loginRes?.data) { - const { token, nickname: username } = loginRes.data + const { token, nickname: username, mobile } = loginRes.data accounts.value[i].token = token accounts.value[i].username = username localStorage.setItem(username, token) @@ -539,7 +539,7 @@ export default { username, token }) - successfulAccounts.push({ username, token }) + successfulAccounts.push({ username, token, login_name: mobile }) console.log(`账号 ${item.account} 登录成功,username: ${username}`) } else { console.log(`账号 ${item.account} 登录失败:`, loginRes?.message) @@ -605,14 +605,14 @@ export default { appendLoading.value = true try { - const successfulAccounts: { username: string; token: string }[] = [] + const successfulAccounts: { username: string; token: string; login_name: string }[] = [] for (let i = 0; i < appendAccounts.value.length; i++) { const item = appendAccounts.value[i] if (item.account && item.password) { try { const loginRes = await kongfzLogin(item.account, item.password, ip.value, port.value) if (loginRes?.code === 200 && loginRes?.data) { - const { token, nickname: username } = loginRes.data + const { token, nickname: username, mobile } = loginRes.data appendAccounts.value[i].token = token appendAccounts.value[i].username = username localStorage.setItem(username, token) @@ -621,7 +621,7 @@ export default { username, token }) - successfulAccounts.push({ username, token }) + successfulAccounts.push({ username, token, login_name: mobile }) } } catch (loginError: any) { console.log(`追加账号 ${item.account} 登录失败:`, loginError.message) diff --git a/src/views/inventory/Inventory.vue b/src/views/inventory/Inventory.vue index 284e691e..4a709f2f 100644 --- a/src/views/inventory/Inventory.vue +++ b/src/views/inventory/Inventory.vue @@ -53,9 +53,7 @@ - - - + @@ -134,6 +132,7 @@ import { fetchInventoryLogList } from '@/api/inventory' import { fetchWarehouseList } from '@/api/warehouse' import InventoryByGoods from '@/components/inventory/byGoods/index.vue' import InventoryByLocation from '@/components/inventory/byLocation/index.vue' +import WarehouseSelect from '@/components/warehouseSelect/index.vue' /** 变动类型映射(对齐后端 change_type 枚举) */ const CHANGE_TYPE_MAP: Record = { @@ -147,7 +146,7 @@ const CHANGE_TYPE_MAP: Record = { export default defineComponent({ name: 'Inventory', - components: { Search, Refresh, InventoryByGoods, InventoryByLocation }, + components: { Search, Refresh, InventoryByGoods, InventoryByLocation, WarehouseSelect }, setup() { const activeTab = ref('summary') const queryMode = ref<'goods' | 'location'>('goods') @@ -167,6 +166,7 @@ export default defineComponent({ book_name: '', related_order_no: '', warehouse_id: null as number | null, + location_id: null as number | null, change_type: null as number | null }) const logDateRange = ref([]) @@ -201,6 +201,10 @@ export default defineComponent({ } // ==================== 变动记录 ==================== + const onLogWarehouseChange = (warehouseId: number | null) => { + logParams.warehouse_id = warehouseId + } + const loadLogList = async (): Promise => { logLoading.value = true try { @@ -210,6 +214,7 @@ export default defineComponent({ isbn: logParams.isbn || undefined, book_name: logParams.book_name || undefined, warehouse_id: logParams.warehouse_id || undefined, + location_id: logParams.location_id || undefined, change_type: logParams.change_type || undefined, related_order_no: logParams.related_order_no || undefined } @@ -234,6 +239,7 @@ export default defineComponent({ logParams.book_name = '' logParams.related_order_no = '' logParams.warehouse_id = null + logParams.location_id = null logParams.change_type = null logDateRange.value = [] logPagination.current = 1 @@ -256,6 +262,7 @@ export default defineComponent({ warehouseOptions, warehouseMap, // 变动记录 + onLogWarehouseChange, logLoading, logList, logParams, diff --git a/src/views/outbound/Outbound.vue b/src/views/outbound/Outbound.vue index c67f2b33..c421a4bd 100644 --- a/src/views/outbound/Outbound.vue +++ b/src/views/outbound/Outbound.vue @@ -36,9 +36,11 @@ - - - + @@ -58,7 +60,7 @@ + 已选 {{ selectedOutboundOrders.length }} @@ -216,6 +223,7 @@ import { } from '@/api/outbound' import { createShippingOrder } from '@/api/shippingOrder' import { fetchWarehouseList } from '@/api/warehouse' +import WarehouseSelect from '@/components/warehouseSelect/index.vue' /** 状态映射 */ const STATUS_MAP: Record = { 1: { label: '待审核', type: 'warning' }, @@ -247,6 +255,7 @@ interface OutboundForm { export default defineComponent({ name: 'Outbound', + components: { WarehouseSelect }, setup() { const loading = ref(false) const submitLoading = ref(false) @@ -261,6 +270,7 @@ export default defineComponent({ keyword: string status: number | null warehouse_id: number | null + location_id: number | null shop_type: number | null association_order_no: string logistics_no: string @@ -268,6 +278,7 @@ export default defineComponent({ keyword: '', status: null, warehouse_id: null, + location_id: null, shop_type: null, association_order_no: '', logistics_no: '' @@ -328,6 +339,8 @@ export default defineComponent({ const outboundOrderList = ref([]) const outboundLoading = ref(false) const outboundTableRef = ref(null) + const outboundWarehouseId = ref(null) + const outboundLocationId = ref(null) const outboundPagination = reactive({ current: 1, pageSize: 10, @@ -390,6 +403,7 @@ export default defineComponent({ out_no: searchParams.keyword || undefined, status: searchParams.status !== null ? String(searchParams.status) : undefined, warehouse_id: searchParams.warehouse_id !== null ? String(searchParams.warehouse_id) : undefined, + location_id: searchParams.location_id || undefined, shop_type: searchParams.shop_type !== null ? searchParams.shop_type : undefined, association_order_no: searchParams.association_order_no || undefined, logistics_no: searchParams.logistics_no || undefined, @@ -431,6 +445,12 @@ export default defineComponent({ if (outboundSearchKeyword.value) { params.out_no = outboundSearchKeyword.value } + if (outboundWarehouseId.value) { + params.warehouse_id = String(outboundWarehouseId.value) + } + if (outboundLocationId.value) { + params.location_id = String(outboundLocationId.value) + } const res = await fetchOutboundList(params) outboundOrderList.value = res.list || [] outboundPagination.total = res.total || 0 @@ -548,6 +568,15 @@ export default defineComponent({ } } + /** 按当前搜索条件过滤明细(库位筛选时仅展示匹配库位的商品) */ + const getFilteredDetailItems = (rowId: number) => { + const items = detailCache.value[rowId]?.items || [] + if (searchParams.location_id) { + return items.filter((item: any) => String(item.location_id) === String(searchParams.location_id)) + } + return items + } + /** 添加商品明细行 */ const addItem = (): void => { formData.items.push({ @@ -665,6 +694,7 @@ export default defineComponent({ handleSizeChange, handleCurrentChange, handleExpandChange, + getFilteredDetailItems, addItem, removeItem, handleApprove, @@ -677,6 +707,8 @@ export default defineComponent({ outboundOrderList, outboundLoading, outboundTableRef, + outboundWarehouseId, + outboundLocationId, formatAmount, handleOutboundSearch, handleOutboundSelectionChange, diff --git a/src/views/salesOrder/salesInfoList.vue b/src/views/salesOrder/salesInfoList.vue index 181da372..6d0b17cc 100644 --- a/src/views/salesOrder/salesInfoList.vue +++ b/src/views/salesOrder/salesInfoList.vue @@ -15,10 +15,11 @@ - - - + @@ -95,6 +96,9 @@
+ + + @@ -200,6 +204,7 @@ import { useRoute } from 'vue-router' import { ElMessage, ElMessageBox } from 'element-plus' // added by copilot: useRoute for query params import { Search, Refresh, Plus, Edit, Delete, View, Check } from '@element-plus/icons-vue' +import WarehouseSelect from '@/components/warehouseSelect/index.vue' import dayjs from 'dayjs' import { fetchSalesOrderList, @@ -242,6 +247,7 @@ interface SalesOrderForm { export default defineComponent({ name: 'SalesOrder', + components: { WarehouseSelect }, setup() { const loading = ref(false) const submitLoading = ref(false) @@ -256,6 +262,7 @@ export default defineComponent({ keyword: string status: number | null warehouse_id: number | null + location_id: number | null shop_type: number | null association_order_no: string logistics_no: string @@ -263,6 +270,7 @@ export default defineComponent({ keyword: '', status: null, warehouse_id: null, + location_id: null, shop_type: null, association_order_no: '', logistics_no: '' @@ -377,6 +385,10 @@ export default defineComponent({ const res = await fetchSalesOrderDetails({ page: pagination.current, pageSize: pagination.pageSize, + warehouse_id: searchParams.warehouse_id || undefined, + location_id: searchParams.location_id || undefined, + status: searchParams.status || undefined, + keyword: searchParams.keyword, shop_type: searchParams.shop_type !== null ? searchParams.shop_type : undefined, association_order_no: searchParams.association_order_no, logistics_no: searchParams.logistics_no @@ -402,6 +414,7 @@ export default defineComponent({ searchParams.keyword = '' searchParams.status = null searchParams.warehouse_id = null + searchParams.location_id = null searchParams.shop_type = null searchParams.association_order_no = '' searchParams.logistics_no = '' @@ -585,8 +598,6 @@ export default defineComponent({ formRef, formData, formRules, - warehouseOptions, - warehouseLoading, loadWarehouses, warehouseMap, customerMap, diff --git a/src/views/salesOrder/salesOrder.vue b/src/views/salesOrder/salesOrder.vue index fd9cd941..7a6ea31a 100644 --- a/src/views/salesOrder/salesOrder.vue +++ b/src/views/salesOrder/salesOrder.vue @@ -37,7 +37,11 @@ - + @@ -124,6 +128,9 @@ + + + @@ -212,7 +219,7 @@ @close="outboundGenerated = false"> @@ -282,7 +294,7 @@ import { useRoute } from 'vue-router' import { ElMessage, ElMessageBox } from 'element-plus' // added by copilot: useRoute for query params import { Search, Refresh, Plus, Edit, Delete, View, Loading, Check } from '@element-plus/icons-vue' -import LocationSelect from '@/components/locationSelect/index.vue' +import WarehouseSelect from '@/components/warehouseSelect/index.vue' import dayjs from 'dayjs' import { fetchSalesOrderList, @@ -330,7 +342,7 @@ interface SalesOrderForm { export default defineComponent({ name: 'SalesOrder', - components: { LocationSelect }, + components: { WarehouseSelect }, setup() { const loading = ref(false) const submitLoading = ref(false) @@ -345,6 +357,7 @@ export default defineComponent({ keyword: string status: number | null warehouse_id: number | null + location_id: number | null shop_type: number | null association_order_no: string logistics_no: string @@ -352,6 +365,7 @@ export default defineComponent({ keyword: '', status: null, warehouse_id: null, + location_id: null, shop_type: null, association_order_no: '', logistics_no: '' @@ -403,6 +417,8 @@ export default defineComponent({ const generateLoading = ref(false) const outboundOrderList = ref([]) const outboundSearchKeyword = ref('') + const outboundWarehouseId = ref(null) + const outboundLocationId = ref(null) const selectedOutboundOrders = ref([]) const outboundTableRef = ref(null) const outboundRemark = ref('') @@ -467,6 +483,7 @@ export default defineComponent({ keyword: searchParams.keyword, status: searchParams.status || undefined, warehouse_id: searchParams.warehouse_id || undefined, + location_id: searchParams.location_id || undefined, shop_type: searchParams.shop_type !== null ? searchParams.shop_type : undefined, association_order_no: searchParams.association_order_no || undefined, logistics_no: searchParams.logistics_no || undefined, @@ -496,6 +513,7 @@ export default defineComponent({ searchParams.keyword = '' searchParams.status = null searchParams.warehouse_id = null + searchParams.location_id = null searchParams.shop_type = null searchParams.association_order_no = '' searchParams.logistics_no = '' @@ -577,12 +595,16 @@ export default defineComponent({ outboundDialogVisible.value = true outboundGenerated.value = false outboundSearchKeyword.value = '' + outboundWarehouseId.value = null + outboundLocationId.value = null selectedOutboundOrders.value = [] outboundLoading.value = true try { const res = await fetchSalesOrderList({ keyword: '', status: 3, // 只加载已确认状态的订单 + warehouse_id: outboundWarehouseId.value || undefined, + location_id: outboundLocationId.value || undefined, page: 1, pageSize: 100 }) @@ -602,6 +624,8 @@ export default defineComponent({ const res = await fetchSalesOrderList({ keyword: outboundSearchKeyword.value, status: 3, + warehouse_id: outboundWarehouseId.value || undefined, + location_id: outboundLocationId.value || undefined, page: 1, pageSize: 100 }) @@ -723,6 +747,8 @@ export default defineComponent({ outboundLoading, outboundOrderList, outboundSearchKeyword, + outboundWarehouseId, + outboundLocationId, selectedOutboundOrders, outboundTableRef, outboundRemark, diff --git a/src/views/shippingOrder/shippingOrder.vue b/src/views/shippingOrder/shippingOrder.vue index 1b8aae51..fb51a50b 100644 --- a/src/views/shippingOrder/shippingOrder.vue +++ b/src/views/shippingOrder/shippingOrder.vue @@ -152,9 +152,11 @@ - - - + @@ -177,7 +179,7 @@