perf: 库位选择器改为按需懒加载——新增 /warehouse/children 接口,WarehouseSelector 移除全量树依赖
This commit is contained in:
@ -54,6 +54,41 @@ def get_tree():
|
|||||||
}), 500
|
}), 500
|
||||||
|
|
||||||
|
|
||||||
|
@warehouse_bp.route('/children', methods=['GET'])
|
||||||
|
def get_children():
|
||||||
|
"""
|
||||||
|
懒加载:获取指定库位的直接子节点(parent_id 省略/为空 = 顶层)。
|
||||||
|
每个节点附带 has_children 标记,前端据此渲染「进入下级」而非点进去才知道。
|
||||||
|
与 /tree 行为一致(不额外过滤 is_enabled、按 name 升序)。
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
parent_id = request.args.get('parent_id', type=int)
|
||||||
|
if parent_id is None:
|
||||||
|
nodes = SysWarehouseLocation.query.filter(
|
||||||
|
SysWarehouseLocation.parent_id.is_(None)
|
||||||
|
).order_by(SysWarehouseLocation.name.asc()).all()
|
||||||
|
else:
|
||||||
|
nodes = SysWarehouseLocation.query.filter(
|
||||||
|
SysWarehouseLocation.parent_id == parent_id
|
||||||
|
).order_by(SysWarehouseLocation.name.asc()).all()
|
||||||
|
|
||||||
|
# 一次查询所有"有子节点"的 parent_id,用于 has_children 判断(避免 N+1)
|
||||||
|
parent_with_children = set(
|
||||||
|
cid for (cid,) in db.session.query(SysWarehouseLocation.parent_id)
|
||||||
|
.filter(SysWarehouseLocation.parent_id.isnot(None)).distinct().all()
|
||||||
|
)
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for node in nodes:
|
||||||
|
d = node.to_dict()
|
||||||
|
d['has_children'] = node.id in parent_with_children
|
||||||
|
data.append(d)
|
||||||
|
|
||||||
|
return jsonify({'code': 200, 'msg': 'success', 'data': data})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({'code': 500, 'msg': str(e), 'data': None}), 500
|
||||||
|
|
||||||
|
|
||||||
@warehouse_bp.route('', methods=['POST'])
|
@warehouse_bp.route('', methods=['POST'])
|
||||||
@jwt_required()
|
@jwt_required()
|
||||||
@audit_log(
|
@audit_log(
|
||||||
|
|||||||
@ -8,6 +8,15 @@ export function getWarehouseTree() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 懒加载:获取指定库位的直接子节点(parentId 省略/为空 = 顶层)
|
||||||
|
export function getWarehouseChildren(parentId?: number | null) {
|
||||||
|
return request({
|
||||||
|
url: '/v1/warehouse/children',
|
||||||
|
method: 'get',
|
||||||
|
params: parentId != null ? { parent_id: parentId } : {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 创建库位
|
// 创建库位
|
||||||
export function createWarehouse(data: any) {
|
export function createWarehouse(data: any) {
|
||||||
return request({
|
return request({
|
||||||
|
|||||||
@ -69,18 +69,18 @@
|
|||||||
<!-- 左侧热区:点击进入下级或选中 -->
|
<!-- 左侧热区:点击进入下级或选中 -->
|
||||||
<div
|
<div
|
||||||
class="item-main"
|
class="item-main"
|
||||||
:class="{ 'has-children': item.children && item.children.length > 0 }"
|
:class="{ 'has-children': hasChild(item) }"
|
||||||
@click="handleItemClick(item)"
|
@click="handleItemClick(item)"
|
||||||
>
|
>
|
||||||
<el-icon class="item-icon"><Location /></el-icon>
|
<el-icon class="item-icon"><Location /></el-icon>
|
||||||
<span class="item-name">{{ item.name }}</span>
|
<span class="item-name">{{ item.name }}</span>
|
||||||
<el-icon v-if="item.children && item.children.length > 0" class="item-arrow">
|
<el-icon v-if="hasChild(item)" class="item-arrow">
|
||||||
<ArrowRight />
|
<ArrowRight />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
<!-- 右侧操作区 -->
|
<!-- 右侧操作区 -->
|
||||||
<div class="item-actions">
|
<div class="item-actions">
|
||||||
<el-tag v-if="!item.children || item.children.length === 0" type="info" size="small">
|
<el-tag v-if="!hasChild(item)" type="info" size="small">
|
||||||
末级
|
末级
|
||||||
</el-tag>
|
</el-tag>
|
||||||
<el-button
|
<el-button
|
||||||
@ -102,26 +102,27 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, watch } from 'vue'
|
import { ref, reactive, computed, watch } from 'vue'
|
||||||
import { ArrowDown, ArrowLeft, ArrowRight, Location } from '@element-plus/icons-vue'
|
import { ArrowDown, ArrowLeft, ArrowRight, Location } from '@element-plus/icons-vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { getWarehouseChildren } from '@/api/common/warehouse'
|
||||||
|
|
||||||
interface WarehouseItem {
|
interface WarehouseItem {
|
||||||
id: number
|
id: number
|
||||||
|
parent_id: number | null
|
||||||
name: string
|
name: string
|
||||||
full_path: string
|
full_path: string
|
||||||
level: number
|
level: number
|
||||||
|
has_children?: boolean
|
||||||
children?: WarehouseItem[]
|
children?: WarehouseItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
modelValue?: string
|
modelValue?: string
|
||||||
options: WarehouseItem[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
modelValue: '',
|
modelValue: ''
|
||||||
options: () => []
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@ -131,83 +132,86 @@ const emit = defineEmits<{
|
|||||||
const popoverRef = ref()
|
const popoverRef = ref()
|
||||||
const popoverVisible = ref(false)
|
const popoverVisible = ref(false)
|
||||||
const triggerRef = ref<HTMLElement>()
|
const triggerRef = ref<HTMLElement>()
|
||||||
|
const loadingKey = ref<string | null>(null)
|
||||||
|
|
||||||
// 当前导航路径(保存每一层的节点信息)
|
// 当前导航路径(保存每一层的节点信息)
|
||||||
const currentPath = ref<WarehouseItem[]>([])
|
const currentPath = ref<WarehouseItem[]>([])
|
||||||
|
|
||||||
// 当前显示的列表数据
|
// ★ 懒加载缓存:key = 'root'(顶层)或 String(parentId)
|
||||||
const currentList = computed(() => {
|
const cache = reactive<Record<string, WarehouseItem[]>>({})
|
||||||
if (currentPath.value.length === 0) {
|
|
||||||
// 顶层:显示根节点列表
|
// 是否有下一级(优先用后端 has_children,兼容旧树结构的 children 字段)
|
||||||
return props.options
|
const hasChild = (item: WarehouseItem): boolean =>
|
||||||
}
|
!!item.has_children || !!(item.children && item.children.length > 0)
|
||||||
// 非顶层:显示当前层级最后一个节点的 children
|
|
||||||
const lastNode = currentPath.value[currentPath.value.length - 1]
|
// 当前层缓存 key('root' 或父节点 id)
|
||||||
return lastNode?.children || []
|
const currentParentKey = computed<string>(() => {
|
||||||
|
if (currentPath.value.length === 0) return 'root'
|
||||||
|
return String(currentPath.value[currentPath.value.length - 1].id)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听弹窗显示状态,恢复选中层级
|
// 当前层父 id(null = 顶层)
|
||||||
watch(popoverVisible, (visible) => {
|
const currentParentId = computed<number | null>(() => {
|
||||||
|
if (currentPath.value.length === 0) return null
|
||||||
|
return currentPath.value[currentPath.value.length - 1].id
|
||||||
|
})
|
||||||
|
|
||||||
|
// 当前显示的列表(懒加载缓存)
|
||||||
|
const currentList = computed<WarehouseItem[]>(() => cache[currentParentKey.value] || [])
|
||||||
|
|
||||||
|
// 懒加载某层子节点(已缓存则跳过)
|
||||||
|
const ensureLoaded = async (key: string, parentId: number | null) => {
|
||||||
|
if (cache[key]) return
|
||||||
|
if (loadingKey.value === key) return
|
||||||
|
loadingKey.value = key
|
||||||
|
try {
|
||||||
|
const res: any = await getWarehouseChildren(parentId)
|
||||||
|
cache[key] = res.data || []
|
||||||
|
} catch (e) {
|
||||||
|
cache[key] = [] // 失败置空,避免下次重复请求
|
||||||
|
} finally {
|
||||||
|
loadingKey.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开弹窗:加载顶层,有选中值时逐级恢复导航路径
|
||||||
|
watch(popoverVisible, async (visible) => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
restoreSelection()
|
currentPath.value = []
|
||||||
|
await ensureLoaded('root', null)
|
||||||
|
if (props.modelValue) {
|
||||||
|
await restoreSelection(props.modelValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 根据 modelValue 恢复选择状态
|
// 按 full_path 逐级懒加载并恢复路径(不含末级节点本身,末级是待选中的)
|
||||||
const restoreSelection = () => {
|
const restoreSelection = async (fullPath: string) => {
|
||||||
if (!props.modelValue) {
|
const parts = fullPath.split('/').filter(Boolean)
|
||||||
// 无选中值,重置到顶层
|
if (parts.length <= 1) return // 顶层库位无需恢复子路径
|
||||||
currentPath.value = []
|
for (let i = 0; i < parts.length - 1; i++) {
|
||||||
return
|
const key = i === 0 ? 'root' : String(currentPath.value[i - 1]?.id ?? '')
|
||||||
}
|
const parentId = i === 0 ? null : (currentPath.value[i - 1]?.id ?? null)
|
||||||
|
await ensureLoaded(key, parentId)
|
||||||
// 根据 full_path 查找父级路径
|
const list = cache[key] || []
|
||||||
const path = findPathByFullPath(props.options, props.modelValue)
|
const expected = parts.slice(0, i + 1).join('/')
|
||||||
if (path) {
|
const node = list.find((n) => n.full_path === expected)
|
||||||
// 找到路径:还原 currentPath(不包含最后一个节点,因为它是当前选中的节点)
|
if (!node) {
|
||||||
currentPath.value = path
|
currentPath.value = [] // 树结构可能变化,回到顶层
|
||||||
} else {
|
return
|
||||||
// 未找到(可能树结构已变化),重置到顶层
|
}
|
||||||
currentPath.value = []
|
currentPath.value.push(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据 full_path 在树中查找从根到目标节点的路径
|
// 弹窗可见性变化
|
||||||
const findPathByFullPath = (
|
|
||||||
tree: WarehouseItem[],
|
|
||||||
targetFullPath: string,
|
|
||||||
currentPath: WarehouseItem[] = []
|
|
||||||
): WarehouseItem[] | null => {
|
|
||||||
for (const node of tree) {
|
|
||||||
// 检查当前节点是否匹配
|
|
||||||
if (node.full_path === targetFullPath) {
|
|
||||||
return currentPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// 递归检查子节点
|
|
||||||
if (node.children && node.children.length > 0) {
|
|
||||||
const result = findPathByFullPath(node.children, targetFullPath, [...currentPath, node])
|
|
||||||
if (result) {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理弹窗显示/隐藏
|
|
||||||
const handleVisibleChange = (visible: boolean) => {
|
const handleVisibleChange = (visible: boolean) => {
|
||||||
popoverVisible.value = visible
|
popoverVisible.value = visible
|
||||||
if (!visible) {
|
if (!visible) currentPath.value = []
|
||||||
// 关闭时重置导航
|
|
||||||
currentPath.value = []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
const handleOpen = () => {
|
const handleOpen = () => { popoverVisible.value = true }
|
||||||
popoverVisible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清空选择
|
// 清空选择
|
||||||
const handleClear = () => {
|
const handleClear = () => {
|
||||||
@ -217,28 +221,23 @@ const handleClear = () => {
|
|||||||
|
|
||||||
// 返回上一级
|
// 返回上一级
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
if (currentPath.value.length > 0) {
|
if (currentPath.value.length > 0) currentPath.value.pop()
|
||||||
currentPath.value.pop()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回顶层
|
// 返回顶层
|
||||||
const handleGoHome = () => {
|
const handleGoHome = () => { currentPath.value = [] }
|
||||||
currentPath.value = []
|
|
||||||
}
|
|
||||||
|
|
||||||
// 进入下一级
|
// 进入下一级:先确保子级已加载,再推入导航
|
||||||
const handleDrillDown = (item: WarehouseItem) => {
|
const handleDrillDown = async (item: WarehouseItem) => {
|
||||||
|
await ensureLoaded(String(item.id), item.id)
|
||||||
currentPath.value.push(item)
|
currentPath.value.push(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点击列表项 - 左侧热区逻辑
|
// 点击列表项
|
||||||
const handleItemClick = (item: WarehouseItem) => {
|
const handleItemClick = (item: WarehouseItem) => {
|
||||||
if (item.children && item.children.length > 0) {
|
if (hasChild(item)) {
|
||||||
// 有子节点:进入下一级
|
|
||||||
handleDrillDown(item)
|
handleDrillDown(item)
|
||||||
} else {
|
} else {
|
||||||
// 末级:直接选中
|
|
||||||
handleSelect(item)
|
handleSelect(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -384,10 +384,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form-item label="库位" prop="warehouse_location">
|
<el-form-item label="库位" prop="warehouse_location">
|
||||||
<WarehouseSelector
|
<WarehouseSelector v-model="form.warehouse_location" />
|
||||||
v-model="form.warehouse_location"
|
|
||||||
:options="warehouseOptions"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -806,7 +803,6 @@ import {
|
|||||||
} from '@/api/inbound/buy'
|
} from '@/api/inbound/buy'
|
||||||
import { getApprovedUnstockedRequests } from '@/api/purchase'
|
import { getApprovedUnstockedRequests } from '@/api/purchase'
|
||||||
import {getLabelPreview, executePrint} from '@/api/common/print'
|
import {getLabelPreview, executePrint} from '@/api/common/print'
|
||||||
import { getWarehouseTree } from '@/api/common/warehouse'
|
|
||||||
import { usePasteUpload } from '@/hooks/usePasteUpload'
|
import { usePasteUpload } from '@/hooks/usePasteUpload'
|
||||||
import WebRtcCamera from '@/components/Camera/WebRtcCamera.vue'
|
import WebRtcCamera from '@/components/Camera/WebRtcCamera.vue'
|
||||||
import WarehouseSelector from '@/components/WarehouseSelector.vue'
|
import WarehouseSelector from '@/components/WarehouseSelector.vue'
|
||||||
@ -980,9 +976,6 @@ const purchaseImportPage = ref(1)
|
|||||||
const purchaseImportKeyword = ref('')
|
const purchaseImportKeyword = ref('')
|
||||||
const purchaseImportSelected = ref<any>(null)
|
const purchaseImportSelected = ref<any>(null)
|
||||||
|
|
||||||
// 库位级联选择器数据
|
|
||||||
const warehouseOptions = ref<any[]>([])
|
|
||||||
|
|
||||||
const advancedFilterVisible = ref(false)
|
const advancedFilterVisible = ref(false)
|
||||||
const advancedConditions = ref([{ field: '', operator: '', value: '' }])
|
const advancedConditions = ref([{ field: '', operator: '', value: '' }])
|
||||||
const fieldOptions = computed(() => {
|
const fieldOptions = computed(() => {
|
||||||
@ -1575,17 +1568,6 @@ const buildCategoryTree = (categories: string[]) => {
|
|||||||
return root;
|
return root;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 加载库位树数据
|
|
||||||
const loadWarehouseTree = async () => {
|
|
||||||
try {
|
|
||||||
const res = await getWarehouseTree()
|
|
||||||
if (res.code === 200) {
|
|
||||||
warehouseOptions.value = res.data || []
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('加载库位树失败', e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryParams.keyword = ''
|
queryParams.keyword = ''
|
||||||
@ -2130,7 +2112,6 @@ onMounted(() => {
|
|||||||
initColumnPermissions()
|
initColumnPermissions()
|
||||||
fetchData()
|
fetchData()
|
||||||
fetchOptions()
|
fetchOptions()
|
||||||
loadWarehouseTree()
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -354,10 +354,7 @@
|
|||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col :span="6"><el-form-item label="SKU" prop="sku"><el-input v-model="form.sku" placeholder="自动生成" disabled /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="SKU" prop="sku"><el-input v-model="form.sku" placeholder="自动生成" disabled /></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="库位" prop="warehouse_location">
|
<el-col :span="6"><el-form-item label="库位" prop="warehouse_location">
|
||||||
<WarehouseSelector
|
<WarehouseSelector v-model="form.warehouse_location" />
|
||||||
v-model="form.warehouse_location"
|
|
||||||
:options="warehouseOptions"
|
|
||||||
/>
|
|
||||||
</el-form-item></el-col>
|
</el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="入库日期"><el-date-picker v-model="form.in_date" type="date" value-format="YYYY-MM-DD" style="width:100%" disabled /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="入库日期"><el-date-picker v-model="form.in_date" type="date" value-format="YYYY-MM-DD" style="width:100%" disabled /></el-form-item></el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -620,7 +617,6 @@ import WarehouseSelector from '@/components/WarehouseSelector.vue'
|
|||||||
import SmartScannerDialog from '@/components/SmartScannerDialog.vue'
|
import SmartScannerDialog from '@/components/SmartScannerDialog.vue'
|
||||||
import TrackScanDialog from '@/components/TrackScanDialog.vue'
|
import TrackScanDialog from '@/components/TrackScanDialog.vue'
|
||||||
import { getLabelPreview, executePrint } from '@/api/common/print'
|
import { getLabelPreview, executePrint } from '@/api/common/print'
|
||||||
import { getWarehouseTree } from '@/api/common/warehouse'
|
|
||||||
import { usePasteUpload } from '@/hooks/usePasteUpload'
|
import { usePasteUpload } from '@/hooks/usePasteUpload'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
|
|
||||||
@ -759,9 +755,6 @@ const scannerDialogVisible = ref(false)
|
|||||||
// 顶部扫码入库面板 (Track 身份证自动填充物料+序列号+订单号)
|
// 顶部扫码入库面板 (Track 身份证自动填充物料+序列号+订单号)
|
||||||
const trackScanVisible = ref(false)
|
const trackScanVisible = ref(false)
|
||||||
|
|
||||||
// 库位级联选择器数据
|
|
||||||
const warehouseOptions = ref<any[]>([])
|
|
||||||
|
|
||||||
// ================= 第一步:声明基础数据 =================
|
// ================= 第一步:声明基础数据 =================
|
||||||
|
|
||||||
// [核心优化] 所有列定义
|
// [核心优化] 所有列定义
|
||||||
@ -1208,18 +1201,6 @@ const buildCategoryTree = (categories: string[]) => {
|
|||||||
return root;
|
return root;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 加载库位树数据
|
|
||||||
const loadWarehouseTree = async () => {
|
|
||||||
try {
|
|
||||||
const res = await getWarehouseTree()
|
|
||||||
if (res.code === 200) {
|
|
||||||
warehouseOptions.value = res.data || []
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('加载库位树失败', e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryParams.keyword = ''
|
queryParams.keyword = ''
|
||||||
queryParams.searchField = 'all'
|
queryParams.searchField = 'all'
|
||||||
@ -1532,7 +1513,6 @@ onMounted(() => {
|
|||||||
initColumnPermissions()
|
initColumnPermissions()
|
||||||
fetchData()
|
fetchData()
|
||||||
fetchOptions()
|
fetchOptions()
|
||||||
loadWarehouseTree()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 成本计算监听
|
// 成本计算监听
|
||||||
|
|||||||
@ -393,10 +393,7 @@
|
|||||||
<el-col :span="6"><el-form-item label="编码/SKU" prop="sku"><el-input v-model="form.sku" placeholder="系统自动生成" disabled/></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="编码/SKU" prop="sku"><el-input v-model="form.sku" placeholder="系统自动生成" disabled/></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="入库日期" prop="in_date"><el-date-picker v-model="form.in_date" type="date" value-format="YYYY-MM-DD" style="width:100%" disabled/></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="入库日期" prop="in_date"><el-date-picker v-model="form.in_date" type="date" value-format="YYYY-MM-DD" style="width:100%" disabled/></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="库位" prop="warehouse_location">
|
<el-col :span="6"><el-form-item label="库位" prop="warehouse_location">
|
||||||
<WarehouseSelector
|
<WarehouseSelector v-model="form.warehouse_location" />
|
||||||
v-model="form.warehouse_location"
|
|
||||||
:options="warehouseOptions"
|
|
||||||
/>
|
|
||||||
</el-form-item></el-col>
|
</el-form-item></el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
@ -664,7 +661,6 @@ import WarehouseSelector from '@/components/WarehouseSelector.vue'
|
|||||||
import SmartScannerDialog from '@/components/SmartScannerDialog.vue'
|
import SmartScannerDialog from '@/components/SmartScannerDialog.vue'
|
||||||
import TrackScanDialog from '@/components/TrackScanDialog.vue'
|
import TrackScanDialog from '@/components/TrackScanDialog.vue'
|
||||||
import {getLabelPreview, executePrint} from '@/api/common/print'
|
import {getLabelPreview, executePrint} from '@/api/common/print'
|
||||||
import { getWarehouseTree } from '@/api/common/warehouse'
|
|
||||||
import { usePasteUpload } from '@/hooks/usePasteUpload'
|
import { usePasteUpload } from '@/hooks/usePasteUpload'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
|
|
||||||
@ -826,9 +822,6 @@ const scannerDialogVisible = ref(false)
|
|||||||
// 顶部扫码入库面板 (Track 身份证自动填充物料+序列号)
|
// 顶部扫码入库面板 (Track 身份证自动填充物料+序列号)
|
||||||
const trackScanVisible = ref(false)
|
const trackScanVisible = ref(false)
|
||||||
|
|
||||||
// 库位级联选择器数据
|
|
||||||
const warehouseOptions = ref<any[]>([])
|
|
||||||
|
|
||||||
const entryMode = ref('batch')
|
const entryMode = ref('batch')
|
||||||
const modeLocked = ref(false)
|
const modeLocked = ref(false)
|
||||||
|
|
||||||
@ -1312,17 +1305,6 @@ const buildCategoryTree = (categories: string[]) => {
|
|||||||
return root;
|
return root;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 加载库位树数据
|
|
||||||
const loadWarehouseTree = async () => {
|
|
||||||
try {
|
|
||||||
const res = await getWarehouseTree()
|
|
||||||
if (res.code === 200) {
|
|
||||||
warehouseOptions.value = res.data || []
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('加载库位树失败', e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryParams.keyword = ''
|
queryParams.keyword = ''
|
||||||
@ -1649,7 +1631,6 @@ onMounted(() => {
|
|||||||
initColumnPermissions()
|
initColumnPermissions()
|
||||||
fetchData()
|
fetchData()
|
||||||
fetchOptions()
|
fetchOptions()
|
||||||
loadWarehouseTree()
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user