<template>
|
<ElCard class="art-table-card" shadow="never">
|
<template #header>
|
<div class="flex items-center justify-between gap-4">
|
<div>
|
<div class="text-base font-medium text-[var(--art-text-primary)]">关系管理</div>
|
<div class="text-xs text-[var(--art-text-secondary)]">
|
{{ panelSubtitle }}
|
</div>
|
</div>
|
|
<ElSpace wrap>
|
<ElButton size="small" @click="handleRefresh" v-ripple>刷新</ElButton>
|
<ElButton size="small" type="primary" @click="openBindMatnrDialog" v-ripple>绑定物料</ElButton>
|
<ElButton size="small" type="success" @click="openBindLocDialog" v-ripple>绑定库位</ElButton>
|
<ElButton
|
size="small"
|
type="danger"
|
:disabled="selectedRows.length === 0"
|
@click="handleBatchDelete"
|
v-ripple
|
>
|
批量删除
|
</ElButton>
|
</ElSpace>
|
</div>
|
</template>
|
|
<ArtTable
|
:loading="loading"
|
:data="data"
|
:columns="columns"
|
:pagination="pagination"
|
@selection-change="handleSelectionChange"
|
@pagination:size-change="handleSizeChange"
|
@pagination:current-change="handleCurrentChange"
|
/>
|
|
<LocAreaMatBindMatnrDialog
|
v-model:visible="bindMatnrDialogVisible"
|
:bind-data="bindMatnrData"
|
:warehouse-options="warehouseOptions"
|
:area-options="areaOptions"
|
:group-options="groupOptions"
|
:matnr-options="matnrOptions"
|
:loc-type-options="locTypeOptions"
|
@submit="handleBindMatnrSubmit"
|
/>
|
|
<LocAreaMatBindLocDialog
|
v-model:visible="bindLocDialogVisible"
|
:bind-data="bindLocData"
|
:warehouse-options="warehouseOptions"
|
:area-options="areaOptions"
|
:group-options="groupOptions"
|
:loc-options="locOptions"
|
@submit="handleBindLocSubmit"
|
/>
|
</ElCard>
|
</template>
|
|
<script setup>
|
import { computed, h, onMounted, ref, watch } from 'vue'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { useTable } from '@/hooks/core/useTable'
|
import { defaultResponseAdapter } from '@/utils/table/tableUtils'
|
import { guardRequestWithMessage } from '@/utils/sys/requestGuard'
|
import { fetchWarehouseAreasList, fetchWarehouseList, fetchLocPage, fetchLocTypeList } from '@/api/loc'
|
import { fetchMatnrGroupTree, fetchMatnrPage } from '@/api/wh-mat'
|
import {
|
fetchBindLocAreaMatByMatnr,
|
fetchDeleteLocAreaMatRela,
|
fetchLocAreaMatRelaPage
|
} from '@/api/loc-area-mat'
|
import {
|
buildLocAreaMatRelationBindMatnrModel,
|
buildLocAreaMatRelationBindLocModel,
|
normalizeLocAreaMatRelationRow,
|
normalizeLocAreaMatGroupTreeOptions,
|
resolveLocAreaMatAreaOptions,
|
resolveLocAreaMatLocOptions,
|
resolveLocAreaMatLocTypeOptions,
|
resolveLocAreaMatMatnrOptions,
|
resolveLocAreaMatWarehouseOptions
|
} from '../locAreaMatPage.helpers'
|
import { createLocAreaMatRelationBindMatnrState } from '../locAreaMatPage.helpers'
|
import LocAreaMatBindMatnrDialog from './loc-area-mat-bind-matnr-dialog.vue'
|
import LocAreaMatBindLocDialog from './loc-area-mat-bind-loc-dialog.vue'
|
import ArtButtonMore from '@/components/core/forms/art-button-more/index.vue'
|
|
const props = defineProps({
|
areaMatData: { type: Object, default: () => ({}) }
|
})
|
|
const warehouseOptions = ref([])
|
const areaOptions = ref([])
|
const groupOptions = ref([])
|
const matnrOptions = ref([])
|
const locTypeOptions = ref([])
|
const locOptions = ref([])
|
const bindMatnrDialogVisible = ref(false)
|
const bindLocDialogVisible = ref(false)
|
|
const areaMatId = computed(() =>
|
props.areaMatData?.id !== void 0 && props.areaMatData?.id !== null && props.areaMatData?.id !== ''
|
? Number(props.areaMatData.id)
|
: void 0
|
)
|
|
const bindMatnrData = computed(() =>
|
buildLocAreaMatRelationBindMatnrModel({
|
...createLocAreaMatRelationBindMatnrState(areaMatId.value),
|
areaMatId: areaMatId.value,
|
warehouseId: props.areaMatData?.warehouseId,
|
areaId: props.areaMatData?.areaId
|
})
|
)
|
|
const bindLocData = computed(() =>
|
buildLocAreaMatRelationBindLocModel({
|
areaMatId: areaMatId.value,
|
warehouseId: props.areaMatData?.warehouseId,
|
areaId: props.areaMatData?.areaId
|
})
|
)
|
|
const panelSubtitle = computed(() => {
|
if (!areaMatId.value) {
|
return '请选择库区物料查看关系明细'
|
}
|
const code = String(props.areaMatData?.code || '').trim()
|
const depict = String(props.areaMatData?.depict || '').trim()
|
return [code, depict].filter(Boolean).join(' · ') || `主单ID ${areaMatId.value}`
|
})
|
|
const columns = computed(() => [
|
{ type: 'selection', width: 48, align: 'center' },
|
{ type: 'globalIndex', label: '序号', width: 72, align: 'center' },
|
{
|
prop: 'relationTypeText',
|
label: '绑定类型',
|
width: 110,
|
align: 'center',
|
formatter: (row) => row.relationTypeText || '--'
|
},
|
{
|
prop: 'warehouseIdText',
|
label: '仓库',
|
minWidth: 140,
|
showOverflowTooltip: true,
|
formatter: (row) => row.warehouseIdText || '--'
|
},
|
{
|
prop: 'areaIdText',
|
label: '库区',
|
minWidth: 140,
|
showOverflowTooltip: true,
|
formatter: (row) => row.areaIdText || '--'
|
},
|
{
|
prop: 'groupIdText',
|
label: '物料分组',
|
minWidth: 140,
|
showOverflowTooltip: true,
|
formatter: (row) => row.groupIdText || '--'
|
},
|
{
|
prop: 'matnrIdText',
|
label: '物料',
|
minWidth: 160,
|
showOverflowTooltip: true,
|
formatter: (row) => row.matnrIdText || '--'
|
},
|
{
|
prop: 'locTypeIdText',
|
label: '库位类型',
|
minWidth: 140,
|
showOverflowTooltip: true,
|
formatter: (row) => row.locTypeIdText || '--'
|
},
|
{
|
prop: 'locIdText',
|
label: '库位',
|
minWidth: 160,
|
showOverflowTooltip: true,
|
formatter: (row) => row.locIdText || '--'
|
},
|
{
|
prop: 'memo',
|
label: '备注',
|
minWidth: 160,
|
showOverflowTooltip: true,
|
formatter: (row) => row.memo || '--'
|
},
|
{
|
prop: 'updateTimeText',
|
label: '更新时间',
|
minWidth: 170,
|
showOverflowTooltip: true,
|
formatter: (row) => row.updateTimeText || '--'
|
},
|
{
|
prop: 'operation',
|
label: '操作',
|
width: 120,
|
align: 'right',
|
formatter: (row) =>
|
h(ArtButtonMore, {
|
list: [{ key: 'delete', label: '删除', icon: 'ri:delete-bin-5-line', color: 'var(--art-error)' }],
|
onClick: (item) => {
|
if (item.key === 'delete') {
|
handleDeleteRelation(row)
|
}
|
}
|
})
|
}
|
])
|
|
const {
|
data,
|
loading,
|
pagination,
|
getData,
|
replaceSearchParams,
|
handleSizeChange,
|
handleCurrentChange,
|
refreshData
|
} = useTable({
|
core: {
|
apiFn: fetchLocAreaMatRelaPage,
|
apiParams: {
|
current: 1,
|
pageSize: 20
|
},
|
immediate: false,
|
columnsFactory: () => columns.value,
|
paginationKey: {
|
current: 'current',
|
size: 'pageSize'
|
}
|
},
|
transform: {
|
dataTransformer: (records) => {
|
if (!Array.isArray(records)) {
|
return []
|
}
|
return records.map((item) => normalizeLocAreaMatRelationRow(item))
|
}
|
}
|
})
|
|
const selectedRows = ref([])
|
|
const handleSelectionChange = (rows) => {
|
selectedRows.value = Array.isArray(rows) ? rows : []
|
}
|
|
const handleRefresh = async () => {
|
await refreshData()
|
}
|
|
async function loadRelationData() {
|
if (!areaMatId.value) {
|
selectedRows.value = []
|
replaceSearchParams({ areaMatId: void 0 })
|
return
|
}
|
replaceSearchParams({
|
areaMatId: areaMatId.value
|
})
|
await getData({
|
areaMatId: areaMatId.value
|
})
|
}
|
|
async function handleDeleteRelation(record) {
|
try {
|
await ElMessageBox.confirm(`确定要删除关系「${record?.relationTypeText || record?.id}」吗?`, '删除确认', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning'
|
})
|
await fetchDeleteLocAreaMatRela(record.id)
|
ElMessage.success('删除成功')
|
await refreshData()
|
} catch (error) {
|
if (error !== 'cancel') {
|
ElMessage.error(error?.message || '删除失败')
|
}
|
}
|
}
|
|
async function handleBatchDelete() {
|
if (!selectedRows.value.length) {
|
return
|
}
|
const ids = selectedRows.value
|
.map((item) => item.id)
|
.filter((id) => id !== void 0 && id !== null)
|
if (!ids.length) {
|
return
|
}
|
try {
|
await ElMessageBox.confirm(`确定要批量删除选中的 ${ids.length} 条关系吗?`, '批量删除确认', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning'
|
})
|
await fetchDeleteLocAreaMatRela(ids.join(','))
|
ElMessage.success('批量删除成功')
|
selectedRows.value = []
|
await refreshData()
|
} catch (error) {
|
if (error !== 'cancel') {
|
ElMessage.error(error?.message || '批量删除失败')
|
}
|
}
|
}
|
|
function openBindMatnrDialog() {
|
if (!areaMatId.value) {
|
ElMessage.warning('请先选择库区物料主单')
|
return
|
}
|
bindMatnrDialogVisible.value = true
|
}
|
|
function openBindLocDialog() {
|
if (!areaMatId.value) {
|
ElMessage.warning('请先选择库区物料主单')
|
return
|
}
|
bindLocDialogVisible.value = true
|
}
|
|
async function handleBindMatnrSubmit(formData) {
|
try {
|
await fetchBindLocAreaMatByMatnr({
|
areaMatId: areaMatId.value,
|
warehouseId: formData.warehouseId,
|
areaId: formData.areaId,
|
groupId: formData.groupId,
|
matnrId: formData.matnrId,
|
typeId: formData.typeId
|
})
|
ElMessage.success('物料绑定成功')
|
bindMatnrDialogVisible.value = false
|
await refreshData()
|
} catch (error) {
|
ElMessage.error(error?.message || '物料绑定失败')
|
}
|
}
|
|
async function handleBindLocSubmit(formData) {
|
try {
|
await fetchBindLocAreaMatByMatnr({
|
areaMatId: areaMatId.value,
|
warehouseId: formData.warehouseId,
|
areaId: formData.areaId,
|
groupId: formData.groupId,
|
locId: formData.locId
|
})
|
ElMessage.success('库位绑定成功')
|
bindLocDialogVisible.value = false
|
await refreshData()
|
} catch (error) {
|
ElMessage.error(error?.message || '库位绑定失败')
|
}
|
}
|
|
async function loadWarehouseOptions() {
|
const records = await guardRequestWithMessage(fetchWarehouseList(), [], {
|
timeoutMessage: '仓库选项加载超时,已停止等待'
|
})
|
warehouseOptions.value = resolveLocAreaMatWarehouseOptions(defaultResponseAdapter(records).records)
|
}
|
|
async function loadAreaOptions() {
|
const records = await guardRequestWithMessage(fetchWarehouseAreasList(), [], {
|
timeoutMessage: '库区选项加载超时,已停止等待'
|
})
|
areaOptions.value = resolveLocAreaMatAreaOptions(defaultResponseAdapter(records).records)
|
}
|
|
async function loadGroupOptions() {
|
const records = await guardRequestWithMessage(fetchMatnrGroupTree({}), [], {
|
timeoutMessage: '物料分组选项加载超时,已停止等待'
|
})
|
groupOptions.value = normalizeLocAreaMatGroupTreeOptions(defaultResponseAdapter(records).records)
|
}
|
|
async function loadMatnrOptions() {
|
const response = await guardRequestWithMessage(
|
fetchMatnrPage({ current: 1, pageSize: 200 }),
|
{ records: [] },
|
{ timeoutMessage: '物料选项加载超时,已停止等待' }
|
)
|
matnrOptions.value = resolveLocAreaMatMatnrOptions(defaultResponseAdapter(response).records)
|
}
|
|
async function loadLocTypeOptions() {
|
const records = await guardRequestWithMessage(fetchLocTypeList(), [], {
|
timeoutMessage: '库位类型选项加载超时,已停止等待'
|
})
|
locTypeOptions.value = resolveLocAreaMatLocTypeOptions(defaultResponseAdapter(records).records)
|
}
|
|
async function loadLocOptions() {
|
const response = await guardRequestWithMessage(
|
fetchLocPage({ current: 1, pageSize: 200 }),
|
{ records: [] },
|
{ timeoutMessage: '库位选项加载超时,已停止等待' }
|
)
|
locOptions.value = resolveLocAreaMatLocOptions(defaultResponseAdapter(response).records)
|
}
|
|
watch(
|
() => props.areaMatData,
|
() => {
|
loadRelationData()
|
},
|
{ deep: true, immediate: true }
|
)
|
|
onMounted(async () => {
|
await Promise.all([
|
loadWarehouseOptions(),
|
loadAreaOptions(),
|
loadGroupOptions(),
|
loadMatnrOptions(),
|
loadLocTypeOptions(),
|
loadLocOptions()
|
])
|
})
|
</script>
|