<script setup lang="ts"> import { ref, onMounted } from "vue"; import { PureTableBar } from "@/components/RePureTableBar"; import { onBeforeRouteUpdate, useRoute } from "vue-router"; import { useRenderIcon } from "@/components/ReIcon/src/hooks"; import { getCabinetCellList, deleteCabinetCell, CabinetCellDTO, changeGoodsCellsStock, clearGoodsCells } from "@/api/cabinet/cabinet-cell"; import { allCabinets, SmartCabinetDTO } from "@/api/cabinet/smart-cabinet"; import EditPen from "@iconify-icons/ep/edit-pen"; import Delete from "@iconify-icons/ep/delete"; import AddFill from "@iconify-icons/ri/add-circle-line"; import Search from "@iconify-icons/ep/search"; import Refresh from "@iconify-icons/ep/refresh"; import { ElMessage, ElMessageBox } from "element-plus"; import { on } from "events"; import CabinetGoodsConfigModal from "./cabinet-goods-config-modal.vue"; import { getGoodsInfo } from "@/api/shop/goods"; import { useRouter } from "vue-router"; defineOptions({ name: "CabinetGoods" }); const router = useRouter(); const formRef = ref(); const tableRef = ref(); const searchFormParams = ref({ cabinetId: null, cellNo: null, cellType: null }); const pagination = ref({ pageSize: 5, currentPage: 1, total: 0 }); const loading = ref(false); const dataList = ref([]); const multipleSelection = ref<number[]>([]); const currentRow = ref<CabinetCellDTO>(); const configVisible = ref(false); const currentCellId = ref<number>(); const route = useRoute(); const cabinets = ref<SmartCabinetDTO[]>([]); onMounted(async () => { const { data } = await allCabinets(); cabinets.value = data; if (data.length > 0) { searchFormParams.value.cabinetId = data[0].cabinetId; getList(); } }); onBeforeRouteUpdate(async () => { const { data } = await allCabinets(); cabinets.value = data; if (data.length > 0) { searchFormParams.value.cabinetId = data[0].cabinetId; getList(); } }); const getList = async () => { try { loading.value = true; const { data } = await getCabinetCellList({ ...searchFormParams.value, pageSize: pagination.value.pageSize, pageNum: pagination.value.currentPage }); dataList.value = data.rows; pagination.value.total = data.total; } finally { loading.value = false; } }; const onSearch = () => { pagination.value.currentPage = 1; getList(); }; const resetForm = () => { formRef.value.resetFields(); onSearch(); }; const onSizeChange = (val: number) => { pagination.value.pageSize = val; getList(); }; const onCurrentChange = (val: number) => { pagination.value.currentPage = val; getList(); }; const handleDelete = async (row: CabinetCellDTO) => { try { await deleteCabinetCell(row.cellId!.toString()); ElMessage.success("删除成功"); getList(); } catch (error) { console.error("删除失败", error); } }; const handleBulkDelete = async () => { if (multipleSelection.value.length === 0) return; try { await ElMessageBox.confirm( `确认删除选中的${multipleSelection.value.length}项单元格吗?`, "警告", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning" } ); await deleteCabinetCell(multipleSelection.value.join(",")); ElMessage.success("批量删除成功"); multipleSelection.value = []; getList(); } catch (error) { console.error("删除取消或失败", error); } }; const handleSelectionChange = (rows: CabinetCellDTO[]) => { multipleSelection.value = rows.map(row => row.cellId!); }; const handleEdit = (row: CabinetCellDTO) => { currentRow.value = row; }; const handleConfigure = (row: CabinetCellDTO) => { currentCellId.value = row.cellId; configVisible.value = true; }; const switchCellType = (cellType: number) => { switch (cellType) { case 1: return "小格"; case 2: return "中格"; case 3: return "大格"; case 4: return "超大格"; default: return "未知"; } }; const handleStockConfig = async (row: CabinetCellDTO) => { try { // 获取商品详细信息 const { data } = await getGoodsInfo(row.goodsId!); const remainingStock = data.stock - data.totalStock + row.stock; const { value } = await ElMessageBox.prompt( `请输入${row.goodsName || '未配置商品'}的库存数量(本次最多可分配:${remainingStock})。 若可分配数量不足,请先调整商品列表中的库存。`, '配置库存', { inputPattern: /^0$|^[1-9]\d*$/, inputValue: row.stock?.toString(), inputErrorMessage: '请输入有效的非负整数', inputValidator: (inputValue: string) => { const num = Number(inputValue); if (num > remainingStock) { return '分配数量不能超过剩余库存'; } return true; } } ); if (Number(value) > remainingStock) { ElMessage.warning('分配数量不能超过剩余库存'); return; } await changeGoodsCellsStock(row.cellId!, Number(value)); ElMessage.success('库存更新成功'); getList(); } catch (error) { console.error('库存配置取消或失败', error); } }; const handleClearGoods = async (row: CabinetCellDTO) => { try { await ElMessageBox.confirm( `确认要下架${row.goodsName || '未配置商品'}吗?`, '警告', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' } ); await clearGoodsCells(row.cellId!); ElMessage.success('商品下架成功'); getList(); } catch (error) { console.error('操作取消或失败', error); } }; </script> <template> <div class="main flex"> <!-- 左侧柜机列表 --> <div class="w-[200px] pr-4 border-r h-full left-list"> <div class="text-lg font-bold mb-4 px-2">柜机列表</div> <div class="h-[calc(100vh-180px)] overflow-y-auto"> <div class="cabinet-list"> <div v-for="cabinet in cabinets" :key="cabinet.cabinetId" class="cabinet-item p-3 mb-2 cursor-pointer rounded hover:bg-gray-100 transition-colors" :class="{ 'bg-blue-50': searchFormParams.cabinetId === cabinet.cabinetId }" @click="searchFormParams.cabinetId = cabinet.cabinetId; onSearch()"> {{ cabinet.cabinetName }} </div> </div> </div> </div> <!-- 右侧内容 --> <div class="flex-1 pl-4"> <el-form ref="formRef" :inline="true" :model="searchFormParams" class="search-form bg-bg_color w-full pt-[12px]"> <el-form-item label="单元格号:" prop="cellNo"> <el-input v-model.number="searchFormParams.cellNo" placeholder="请输入单元格号" clearable class="!w-[180px]" /> </el-form-item> <el-form-item label="单元格类型:" prop="cellType"> <el-select v-model="searchFormParams.cellType" placeholder="请选择类型" clearable class="!w-[180px]"> <el-option label="小格" :value="1" /> <el-option label="中格" :value="2" /> <el-option label="大格" :value="3" /> <el-option label="超大格" :value="4" /> </el-select> </el-form-item> <el-form-item> <el-button type="primary" :icon="useRenderIcon(Search)" @click="onSearch"> 搜索 </el-button> <el-button :icon="useRenderIcon(Refresh)" @click="resetForm"> 重置 </el-button> </el-form-item> </el-form> <div title="柜体单元格管理" @refresh="getList" class="cell-list"> <!-- <template #buttons> <el-button type="danger" :icon="useRenderIcon(Delete)" :disabled="multipleSelection.length === 0" @click="handleBulkDelete"> 批量删除 </el-button> </template> --> <el-table ref="tableRef" v-loading="loading" :data="dataList" row-key="cellId" @selection-change="handleSelectionChange" border> <el-table-column label="格口ID" prop="cellId" width="80" /> <el-table-column label="商品图片" width="120"> <template #default="{ row }"> <el-image :src="row.coverImg" :preview-src-list="[row.coverImg]" :z-index="9999" :preview-teleported="true" :hide-on-click-modal="true" fit="cover" class="rounded" width="60" height="60" /> </template> </el-table-column> <el-table-column label="商品名称"> <template #default="{ row }"> {{ row.goodsId ? row.goodsName : '未配置商品' }} </template> </el-table-column> <el-table-column label="价格" prop="price" width="80" /> <el-table-column label="库存" prop="stock" width="80" /> <el-table-column label="单元格类型" prop="cellType"> <template #default="{ row }"> {{ switchCellType(row.cellType) }} </template> </el-table-column> <el-table-column label="相关信息" width="150" fixed="right"> <template #default="{ row }"> <el-button type="primary" link :icon="useRenderIcon('document')" @click="router.push({ path: '/shop/order/index', query: { cellId: row.cellId } })"> 购买记录 </el-button> </template> </el-table-column> <el-table-column label="操作" width="150" fixed="right"> <template #default="{ row }"> <el-button type="success" link :icon="useRenderIcon(AddFill)" @click="handleConfigure(row)"> 配置商品 </el-button> <el-button v-if="row.goodsId" type="warning" link :icon="useRenderIcon(EditPen)" @click="handleStockConfig(row)"> 配置库存 </el-button> <el-button v-if="row.goodsId" type="danger" link :icon="useRenderIcon(Delete)" @click="handleClearGoods(row)"> 下架商品 </el-button> </template> </el-table-column> </el-table> <el-pagination v-model:current-page="pagination.currentPage" v-model:page-size="pagination.pageSize" :page-sizes="[5, 10, 20, 50]" layout="total, sizes, prev, pager, next, jumper" :total="pagination.total" @size-change="onSizeChange" @current-change="onCurrentChange" class="pagination" /> </div> <el-dialog v-model="configVisible" title="配置商品" width="80%"> <CabinetGoodsConfigModal v-model="configVisible" :cell-id="currentCellId" @refresh="getList" /> </el-dialog> </div> </div> </template> <style scoped> .flex { display: flex; } .border-r { border-right: 1px solid #ebeef5; } .left-list { background: #FFFFFF; padding: 15px; } .search-form { padding-left: 10px; } .pagination { margin-top: 10px; background: #FFFFFF; padding: 7px; } .cell-list { margin-top: 10px; } </style>