| | |
| | | <template> |
| | | <el-dialog v-model="visible" title="选择产品" width="900px" destroy-on-close :close-on-click-modal="false"> |
| | | <el-form :inline="true" :model="query" class="mb-2"> |
| | | <el-form-item label="产品大类"> |
| | | <el-input v-model="query.productName" placeholder="输入产品大类" clearable @keyup.enter="onSearch" /> |
| | | <el-dialog v-model="visible" |
| | | title="选择产品" |
| | | width="1000px" |
| | | destroy-on-close |
| | | :close-on-click-modal="false"> |
| | | <el-form :inline="true" |
| | | :model="query" |
| | | class="mb-2 search-form"> |
| | | <el-form-item label="产品名称"> |
| | | <el-input v-model="query.materialName" |
| | | size="small" |
| | | placeholder="输入产品名称" |
| | | clearable |
| | | @keyup.enter="onSearch" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="型号名称"> |
| | | <el-input v-model="query.model" placeholder="输入型号名称" clearable @keyup.enter="onSearch" /> |
| | | <el-form-item label="规格"> |
| | | <el-input v-model="query.specification" |
| | | size="small" |
| | | placeholder="输入规格" |
| | | clearable |
| | | @keyup.enter="onSearch" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item> |
| | | <el-button type="primary" @click="onSearch">搜索</el-button> |
| | | <el-button @click="onReset">重置</el-button> |
| | | <el-form-item label="物料编码"> |
| | | <el-input v-model="query.materialCode" |
| | | size="small" |
| | | placeholder="输入物料编码" |
| | | clearable |
| | | @keyup.enter="onSearch" /> |
| | | </el-form-item> |
| | | <el-form-item style="200px"> |
| | | <el-button type="primary" |
| | | size="small" |
| | | @click="onSearch">搜索</el-button> |
| | | <el-button size="small" |
| | | @click="onReset">重置</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- 列表 --> |
| | | <el-table ref="tableRef" v-loading="loading" :data="tableData" height="420" highlight-current-row row-key="id" |
| | | @selection-change="handleSelectionChange" @select="handleSelect"> |
| | | <el-table-column type="selection" width="55" /> |
| | | <el-table-column type="index" label="序号" width="60" /> |
| | | <el-table-column prop="productName" label="产品大类" min-width="160" /> |
| | | <el-table-column prop="model" label="型号名称" min-width="200" /> |
| | | <el-table-column prop="unit" label="单位" min-width="160" /> |
| | | <el-table ref="tableRef" |
| | | v-loading="loading" |
| | | :data="tableData" |
| | | height="420" |
| | | highlight-current-row |
| | | row-key="skuId" |
| | | @selection-change="handleSelectionChange" |
| | | @select="handleSelect"> |
| | | <el-table-column type="selection" |
| | | width="55" /> |
| | | <el-table-column type="index" |
| | | label="序号" |
| | | width="60" /> |
| | | <el-table-column prop="materialName" |
| | | label="产品名称" |
| | | min-width="160" /> |
| | | <el-table-column prop="materialCode" |
| | | label="物料编码" |
| | | min-width="200" /> |
| | | <el-table-column prop="specification" |
| | | label="规格" |
| | | min-width="200" /> |
| | | <el-table-column prop="baseUnit" |
| | | label="单位" |
| | | min-width="160" /> |
| | | </el-table> |
| | | |
| | | <div class="mt-3 flex justify-end"> |
| | | <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="total" |
| | | v-model:page-size="page.pageSize" v-model:current-page="page.pageNum" :page-sizes="[10, 20, 50, 100]" |
| | | @size-change="onPageChange" @current-change="onPageChange" /> |
| | | <el-pagination background |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :total="total" |
| | | v-model:page-size="page.pageSize" |
| | | v-model:current-page="page.pageNum" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | @size-change="onPageChange" |
| | | @current-change="onPageChange" /> |
| | | </div> |
| | | |
| | | <template #footer> |
| | | <el-button @click="close()">取消</el-button> |
| | | <el-button type="primary" :disabled="multipleSelection.length === 0" @click="onConfirm"> |
| | | <el-button type="primary" |
| | | :disabled="multipleSelection.length === 0" |
| | | @click="onConfirm"> |
| | | 确定 |
| | | </el-button> |
| | | </template> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { computed, onMounted, reactive, ref, watch, nextTick } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { productModelList } from '@/api/basicData/productModel' |
| | | import { computed, onMounted, reactive, ref, watch, nextTick } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { modelListPage } from "@/api/basicData/newProduct"; |
| | | |
| | | export type ProductRow = { |
| | | id: number; |
| | | productName: string; |
| | | model: string; |
| | | unit?: string; |
| | | }; |
| | | export type ProductRow = { |
| | | skuId: number; |
| | | specification: string; |
| | | materialCode: string; |
| | | baseUnit?: string; |
| | | materialName?: string; |
| | | }; |
| | | |
| | | const props = defineProps<{ |
| | | modelValue: boolean; |
| | | single?: boolean; // 是否只能选择一个,默认false(可选择多个) |
| | | }>(); |
| | | const props = defineProps<{ |
| | | modelValue: boolean; |
| | | single?: boolean; // 是否只能选择一个,默认false(可选择多个) |
| | | }>(); |
| | | |
| | | const emit = defineEmits(['update:modelValue', 'confirm']); |
| | | const emit = defineEmits(["update:modelValue", "confirm"]); |
| | | |
| | | const visible = computed({ |
| | | get: () => props.modelValue, |
| | | set: (v) => emit("update:modelValue", v), |
| | | }); |
| | | const visible = computed({ |
| | | get: () => props.modelValue, |
| | | set: v => emit("update:modelValue", v), |
| | | }); |
| | | |
| | | const query = reactive({ |
| | | productName: "", |
| | | model: "", |
| | | }); |
| | | const query = reactive({ |
| | | specification: "", |
| | | materialCode: "", |
| | | materialName: "", |
| | | }); |
| | | |
| | | const page = reactive({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | }); |
| | | const page = reactive({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | }); |
| | | |
| | | const loading = ref(false); |
| | | const tableData = ref<ProductRow[]>([]); |
| | | const total = ref(0); |
| | | const multipleSelection = ref<ProductRow[]>([]); |
| | | const tableRef = ref(); |
| | | const loading = ref(false); |
| | | const tableData = ref<ProductRow[]>([]); |
| | | const total = ref(0); |
| | | const multipleSelection = ref<ProductRow[]>([]); |
| | | const tableRef = ref(); |
| | | |
| | | function close() { |
| | | visible.value = false; |
| | | } |
| | | |
| | | const handleSelectionChange = (val: ProductRow[]) => { |
| | | if (props.single && val.length > 1) { |
| | | // 如果限制为单个选择,只保留最后一个选中的 |
| | | const lastSelected = val[val.length - 1]; |
| | | multipleSelection.value = [lastSelected]; |
| | | // 清空表格选中状态,然后重新选中最后一个 |
| | | nextTick(() => { |
| | | if (tableRef.value) { |
| | | tableRef.value.clearSelection(); |
| | | tableRef.value.toggleRowSelection(lastSelected, true); |
| | | } |
| | | }); |
| | | } else { |
| | | multipleSelection.value = val; |
| | | function close() { |
| | | visible.value = false; |
| | | } |
| | | } |
| | | |
| | | // 处理单个选择 |
| | | const handleSelect = (selection: ProductRow[], row: ProductRow) => { |
| | | if (props.single) { |
| | | // 如果限制为单个,清空其他选择,只保留当前行 |
| | | if (selection.includes(row)) { |
| | | // 选中当前行时,清空其他选中 |
| | | multipleSelection.value = [row]; |
| | | const handleSelectionChange = (val: ProductRow[]) => { |
| | | if (props.single && val.length > 1) { |
| | | // 如果限制为单个选择,只保留最后一个选中的 |
| | | const lastSelected = val[val.length - 1]; |
| | | multipleSelection.value = [lastSelected]; |
| | | // 清空表格选中状态,然后重新选中最后一个 |
| | | nextTick(() => { |
| | | if (tableRef.value) { |
| | | tableData.value.forEach((item) => { |
| | | if (item.id !== row.id) { |
| | | tableRef.value.toggleRowSelection(item, false); |
| | | } |
| | | }); |
| | | tableRef.value.clearSelection(); |
| | | tableRef.value.toggleRowSelection(lastSelected, true); |
| | | } |
| | | }); |
| | | } else { |
| | | multipleSelection.value = val; |
| | | } |
| | | }; |
| | | |
| | | // 处理单个选择 |
| | | const handleSelect = (selection: ProductRow[], row: ProductRow) => { |
| | | if (props.single) { |
| | | // 如果限制为单个,清空其他选择,只保留当前行 |
| | | if (selection.includes(row)) { |
| | | // 选中当前行时,清空其他选中 |
| | | multipleSelection.value = [row]; |
| | | nextTick(() => { |
| | | if (tableRef.value) { |
| | | tableData.value.forEach(item => { |
| | | if (item.skuId !== row.skuId) { |
| | | tableRef.value.toggleRowSelection(item, false); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | function onSearch() { |
| | | page.pageNum = 1; |
| | | loadData(); |
| | | } |
| | | |
| | | function onReset() { |
| | | query.specification = ""; |
| | | query.materialCode = ""; |
| | | query.materialName = ""; |
| | | page.pageNum = 1; |
| | | loadData(); |
| | | } |
| | | |
| | | function onPageChange() { |
| | | loadData(); |
| | | } |
| | | |
| | | function onConfirm() { |
| | | if (multipleSelection.value.length === 0) { |
| | | ElMessage.warning("请选择一条产品"); |
| | | return; |
| | | } |
| | | if (props.single && multipleSelection.value.length > 1) { |
| | | ElMessage.warning("只能选择一个产品"); |
| | | return; |
| | | } |
| | | emit( |
| | | "confirm", |
| | | props.single ? [multipleSelection.value[0]] : multipleSelection.value |
| | | ); |
| | | close(); |
| | | } |
| | | |
| | | async function loadData() { |
| | | loading.value = true; |
| | | try { |
| | | multipleSelection.value = []; // 翻页/搜索后清空选择更符合预期 |
| | | const res: any = await modelListPage({ |
| | | specification: query.specification.trim(), |
| | | materialCode: query.materialCode.trim(), |
| | | materialName: query.materialName.trim(), |
| | | type: 1, |
| | | current: page.pageNum, |
| | | size: page.pageSize, |
| | | }); |
| | | tableData.value = res.data.records; |
| | | total.value = res.data.total; |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | function onSearch() { |
| | | page.pageNum = 1; |
| | | loadData(); |
| | | } |
| | | // 监听弹窗打开,重置选择 |
| | | watch( |
| | | () => props.modelValue, |
| | | visible => { |
| | | if (visible) { |
| | | multipleSelection.value = []; |
| | | } |
| | | } |
| | | ); |
| | | |
| | | function onReset() { |
| | | query.productName = ""; |
| | | query.model = ""; |
| | | page.pageNum = 1; |
| | | loadData(); |
| | | } |
| | | |
| | | function onPageChange() { |
| | | loadData(); |
| | | } |
| | | |
| | | function onConfirm() { |
| | | if (multipleSelection.value.length === 0) { |
| | | ElMessage.warning("请选择一条产品"); |
| | | return; |
| | | } |
| | | if (props.single && multipleSelection.value.length > 1) { |
| | | ElMessage.warning("只能选择一个产品"); |
| | | return; |
| | | } |
| | | emit("confirm", props.single ? [multipleSelection.value[0]] : multipleSelection.value); |
| | | close(); |
| | | } |
| | | |
| | | async function loadData() { |
| | | loading.value = true; |
| | | try { |
| | | multipleSelection.value = []; // 翻页/搜索后清空选择更符合预期 |
| | | const res: any = await productModelList({ |
| | | productName: query.productName.trim(), |
| | | model: query.model.trim(), |
| | | current: page.pageNum, |
| | | size: page.pageSize, |
| | | }); |
| | | tableData.value = res.records; |
| | | total.value = res.total; |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | } |
| | | |
| | | // 监听弹窗打开,重置选择 |
| | | watch(() => props.modelValue, (visible) => { |
| | | if (visible) { |
| | | multipleSelection.value = []; |
| | | } |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | loadData() |
| | | }) |
| | | onMounted(() => { |
| | | loadData(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .search-form { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .search-form .el-form-item { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .search-form .el-input { |
| | | width: 180px; |
| | | } |
| | | .el-form--inline .el-form-item { |
| | | margin-right: 5px; |
| | | } |
| | | .justify-end { |
| | | margin-top: 10px; |
| | | } |
| | | </style> |