feat(warehouse): implement bulk delete and multi-level rule-based batch generation for locations
This commit is contained in:
@ -33,3 +33,21 @@ export function deleteWarehouse(id: number) {
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 批量删除库位
|
||||
export function batchDeleteWarehouse(ids: number[]) {
|
||||
return request({
|
||||
url: '/v1/warehouse/batch',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
|
||||
// 规则化批量生成库位
|
||||
export function batchGenerateWarehouse(data: { parent_id: number | null, rules: any[] }) {
|
||||
return request({
|
||||
url: '/v1/warehouse/batch-generate',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
@ -75,6 +75,12 @@
|
||||
<el-button type="primary" @click="handleAddTopLevel" :icon="Plus">
|
||||
新增顶级区域
|
||||
</el-button>
|
||||
<el-button type="success" @click="openBatchGenerate" :icon="Plus">
|
||||
批量生成
|
||||
</el-button>
|
||||
<el-button type="danger" @click="handleBatchDelete" :disabled="selectedIds.length === 0" :icon="Delete">
|
||||
批量删除 {{ selectedIds.length > 0 ? `(${selectedIds.length})` : '' }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-scrollbar height="450px">
|
||||
<el-tree
|
||||
@ -84,6 +90,8 @@
|
||||
:props="treeProps"
|
||||
:expand-on-click-node="false"
|
||||
:default-expand-all="false"
|
||||
show-checkbox
|
||||
@check="handleTreeCheck"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<div class="tree-node">
|
||||
@ -143,11 +151,54 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 批量生成库位弹窗 -->
|
||||
<el-dialog v-model="batchGenerateVisible" title="批量生成库位" width="600px">
|
||||
<el-form :model="batchGenerateForm" label-width="100px">
|
||||
<el-form-item label="父级库位">
|
||||
<el-input :value="batchGenerateForm.parentName" disabled />
|
||||
<el-button link size="small" @click="batchGenerateForm.parent_id = null; batchGenerateForm.parentName = '无(顶级)'">清空选择</el-button>
|
||||
</el-form-item>
|
||||
<el-divider>层级规则(按顺序生成)</el-divider>
|
||||
<div v-for="(rule, index) in batchGenerateForm.rules" :key="index" class="rule-item">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="6">
|
||||
<el-input v-model="rule.prefix" placeholder="前缀" />
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<el-input-number v-model="rule.start" :min="1" placeholder="起始" style="width: 100%" />
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<el-input-number v-model="rule.end" :min="1" placeholder="结束" style="width: 100%" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-input-number v-model="rule.pad" :min="1" :max="5" placeholder="补零" style="width: 100%" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-button type="danger" :icon="Delete" @click="batchGenerateForm.rules.splice(index, 1)" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-button type="primary" plain @click="batchGenerateForm.rules.push({ prefix: '', start: 1, end: 10, pad: 1 })" :icon="Plus">
|
||||
添加层级
|
||||
</el-button>
|
||||
<div class="batch-preview">
|
||||
<span v-if="previewCount > 0">即将生成 <strong>{{ previewCount }}</strong> 个库位</span>
|
||||
<span v-else>请完善规则</span>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="batchGenerateVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleBatchGenerate" :loading="batchLoading" :disabled="previewCount === 0 || previewCount > 3000">
|
||||
生成 {{ previewCount > 3000 ? '(超限)' : '' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
// 1. 引入 User Store
|
||||
import { useUserStore } from '@/stores/user'
|
||||
@ -155,7 +206,7 @@ import { useUserStore } from '@/stores/user'
|
||||
import { Box, TrendCharts, ShoppingCart, Operation, Setting, Location, Plus, Edit, Delete } from '@element-plus/icons-vue'
|
||||
import { getPrinterConfig, updatePrinterConfig } from '@/api/common/print'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { getWarehouseTree, createWarehouse, updateWarehouse, deleteWarehouse } from '@/api/common/warehouse'
|
||||
import { getWarehouseTree, createWarehouse, updateWarehouse, deleteWarehouse, batchDeleteWarehouse, batchGenerateWarehouse } from '@/api/common/warehouse'
|
||||
|
||||
const router = useRouter()
|
||||
// 2. 实例化 store
|
||||
@ -249,6 +300,93 @@ const locationForm = reactive({
|
||||
})
|
||||
const locationLoading = ref(false)
|
||||
|
||||
// 批量删除相关
|
||||
const selectedIds = ref<number[]>([])
|
||||
|
||||
const handleTreeCheck = (data: any, checked: any) => {
|
||||
selectedIds.value = checked.checkedKeys
|
||||
}
|
||||
|
||||
const handleBatchDelete = async () => {
|
||||
if (selectedIds.value.length === 0) {
|
||||
ElMessage.warning('请先选择要删除的库位')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定要删除选中的 ${selectedIds.value.length} 个库位吗?该操作将同时删除所有子库位。`,
|
||||
'警告',
|
||||
{ type: 'warning', confirmButtonText: '确定', cancelButtonText: '取消' }
|
||||
)
|
||||
|
||||
const res = await batchDeleteWarehouse(selectedIds.value)
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('批量删除成功')
|
||||
selectedIds.value = []
|
||||
await loadWarehouseTree()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '删除失败')
|
||||
}
|
||||
} catch (e) {
|
||||
// 用户取消
|
||||
}
|
||||
}
|
||||
|
||||
// 批量生成相关
|
||||
const batchGenerateVisible = ref(false)
|
||||
const batchGenerateForm = reactive({
|
||||
parent_id: null as number | null,
|
||||
parentName: '无(顶级)',
|
||||
rules: [{ prefix: '', start: 1, end: 10, pad: 1 }] as { prefix: string, start: number, end: number, pad: number }[]
|
||||
})
|
||||
const batchLoading = ref(false)
|
||||
|
||||
const previewCount = computed(() => {
|
||||
let count = 1
|
||||
for (const rule of batchGenerateForm.rules) {
|
||||
if (rule.start && rule.end && rule.start <= rule.end) {
|
||||
count *= (rule.end - rule.start + 1)
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return count
|
||||
})
|
||||
|
||||
const openBatchGenerate = () => {
|
||||
batchGenerateForm.parent_id = null
|
||||
batchGenerateForm.parentName = '无(顶级)'
|
||||
batchGenerateForm.rules = [{ prefix: '', start: 1, end: 10, pad: 1 }]
|
||||
batchGenerateVisible.value = true
|
||||
}
|
||||
|
||||
const handleBatchGenerate = async () => {
|
||||
if (previewCount.value === 0 || previewCount.value > 3000) {
|
||||
ElMessage.warning('生成数量无效或超过限制')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
batchLoading.value = true
|
||||
const res = await batchGenerateWarehouse({
|
||||
parent_id: batchGenerateForm.parent_id,
|
||||
rules: batchGenerateForm.rules
|
||||
})
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(`生成成功,共生成 ${res.data.generated_count} 个库位`)
|
||||
batchGenerateVisible.value = false
|
||||
await loadWarehouseTree()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '生成失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('请求异常')
|
||||
} finally {
|
||||
batchLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 打开库位管理弹窗
|
||||
const openWarehouseDialog = async () => {
|
||||
await loadWarehouseTree()
|
||||
@ -466,4 +604,23 @@ const handleNav = (path: string) => {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
/* 批量生成规则样式 */
|
||||
.rule-item {
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.batch-preview {
|
||||
margin-top: 15px;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
background: #ecf5ff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.batch-preview strong {
|
||||
color: #409eff;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user