目录
需求背景
需要在统一个列表下,实现商品和规格得管理和联动
解决效果
index.vue
<!--/** * @author: liuk * @date: 2023/7/7 * @describe: 商品列表 */--> <template> <div class="container"> <h1>商品列表</h1> <div class="creatbtn" style="margin-bottom: 15px"> <div class="creatbtn1"> <el-button class="btn" @click="editShop('')">+ 新增商品</el-button> </div> </div> <el-row justify="space-between" style="margin-bottom: 15px"> <el-col :span="12"> <el-radio-group v-model="fromData.putShelf" @change="getList" size="large"> <el-radio-button label="">全部</el-radio-button> <el-radio-button label="1">已发布</el-radio-button> <el-radio-button label="0">未发布</el-radio-button> </el-radio-group> </el-col> <el-col :span="12"> <el-form-item label="名称"> <el-input v-model="fromData.productName" style="width: 400px;marginRight:30px " placeholder="请输入内容" @keyup.enter="getList"> <template #append> <el-icon @click="getList"> <Search/> </el-icon> </template> </el-input> <el-button type="danger" @click="resetBtn">重置</el-button> </el-form-item> </el-col> </el-row> <el-table v-if="shopTableList.length" v-loading="loading" :data="shopTableList" class="cemetery-table" border width="1200px" @expand-change="expandChange" :row-key="(row) => row.id" :expand-row-keys="expands"> <el-table-column min-width="50" type="expand"> <template #default="props"> <div> <el-table :data="props.row.bMallGoodsSpecifications" border> <el-table-column width="80" type="index" label="序号" align="center"/> <el-table-column label="图片" align="center" prop="image"> <template #default="scope"> <image-upload class="img-specif-box" v-model="scope.row.image" :limit="1" :disabled="!scope.row.specificationEdit" ></image-upload> </template> </el-table-column> <el-table-column label="规格描述" align="center" prop="specificationDescription"> <template #default="scope"> <el-input v-model="scope.row.specificationDescription" :disabled="!scope.row.specificationEdit" style="width: 60px"/> </template> </el-table-column> <el-table-column label="规格" align="center" prop="specifications"> <template #default="scope"> <el-input v-model="scope.row.specifications" :disabled="!scope.row.specificationEdit" style="width: 60px"/> </template> </el-table-column> <el-table-column label="价格" align="center" prop="price"> <template #header> <span class="red">*</span> <el-icon> <Edit/> </el-icon> 价格 </template> <template #default="scope"> <el-input v-model="scope.row.price" :disabled="!scope.row.specificationEdit" style="width: 60px"/> </template> </el-table-column> <el-table-column label="单位" align="center" prop="unitName"> <template #default="scope"> <el-select v-model="scope.row.unitId" :disabled="!scope.row.specificationEdit"> <el-option v-for="(item,i) in units" :key="i" :label="item.label" :value="item.value"/> </el-select> </template> </el-table-column> <el-table-column label="划线价" align="center" prop="crossedPrice"> <template #header> <el-icon> <Edit/> </el-icon> 划线价 </template> <template #default="scope"> <el-input v-model="scope.row.crossedPrice" :disabled="!scope.row.specificationEdit" style="width: 60px"/> </template> </el-table-column> <el-table-column label="库存" align="center" prop="stock"> <template #default="scope"> <el-input v-model="scope.row.stock" :disabled="!scope.row.specificationEdit" style="width: 60px"/> </template> </el-table-column> <el-table-column label="可否调价" align="center" prop="adjustThePrice"> <template #default="scope"> <el-switch v-model="scope.row.adjustThePrice" :active-value="1" :inactive-value="0" :disabled="!scope.row.specificationEdit" style="--el-switch-on-color: rgb(19, 206, 102); --el-switch-off-color: rgb(255, 73, 73)"/> </template> </el-table-column> <el-table-column fixed="right" label="操作" align="center" class-name="small-padding fixed-width" min-width="210"> <template #default="scope"> <el-button v-show="!scope.row.specificationEdit" type="success" @click="editSpecifications(scope.row,props)">编辑 </el-button> <el-button v-show="scope.row.specificationEdit" type="success" @click="updateSpecification(scope.row)"> 保存 </el-button> <el-button v-show="scope.row.specificationEdit" @click="scope.row.specificationEdit = false">取消 </el-button> <el-button v-show="!scope.row.specificationEdit" type="danger" @click="delSpecifica(scope.row,props)">删除 </el-button> </template> </el-table-column> </el-table> </div> </template> </el-table-column> <el-table-column min-width="80" type="index" align="center" label="序号"/> <el-table-column min-width="100" label="商品名称" align="center" prop="productName" sortable> <template #header> 商品名称 <el-icon> <QuestionFilled/> </el-icon> </template> </el-table-column> <el-table-column min-width="150" label="图片" align="center" prop="productImage"> <template #default="scope"> <el-image style="width: 40px; height: 40px" :src="scope.row.productImage" :zoom-rate="1.2" :preview-src-list="[scope.row.productImage]" :initial-index="4" preview-teleported fit="cover"/> </template> </el-table-column> <el-table-column min-width="100" label="库存策略" align="center" prop="inventoryStrategy"> <template #default="scope"> {{ formatInventoryStrategy(scope.row.inventoryStrategy) }} </template> </el-table-column> <el-table-column min-width="100" label="顺序" prop="sort" align="center" sortable> <template #header> 顺序 <el-icon> <QuestionFilled/> </el-icon> </template> </el-table-column> <el-table-column min-width="100" label="是否已发布" align="center" prop="putShelf"> <template #default="scope"> <el-switch v-model="scope.row.putShelf" :active-value="1" :inactive-value="0" style="--el-switch-on-color: rgb(19, 206, 102); --el-switch-off-color: rgb(255, 73, 73)"/> </template> </el-table-column> <el-table-column min-width="100" label="是否静态" align="center" prop="staticState"> <template #default="scope"> <el-switch v-model="scope.row.staticState" :active-value="1" :inactive-value="0" :before-change="staticStateChange.bind(null, scope.row)" :disabled="scope.row.staticState == 1" style="--el-switch-on-color: rgb(19, 206, 102); --el-switch-off-color: rgb(255, 73, 73)"/> </template> </el-table-column> <el-table-column min-width="100" label="SKU数量" align="center" prop="productNum"> <template #default="scope"> <span :class="{red:scope.row.productNum == 0}">{{ scope.row.productNum }}</span> </template> </el-table-column> <el-table-column min-width="100" label="价格" align="center" prop="productPrice"/> <el-table-column label="操作" fixed="right" min-width="250" align="center" class-name="small-padding fixed-width"> <template #default="scope"> <el-button @click="addSpecif(scope.row,scope)">增加规格</el-button> <el-button type="primary" @click="editShop(scope.row.id)">编辑</el-button> <el-button type="danger" @click="delShop(scope.row)">删除</el-button> </template> </el-table-column> </el-table> <el-empty description="暂无商品" v-else/> <pagination v-show="pages.total>0" :total="pages.total" v-model:page="pages.pageNum" v-model:limit="pages.pageSize" @pagination="getList" /> </div> </template> <script setup> import {listGoods, delGoods, previewGoods} from "@/api/retailmall/goods"; import {updateSpecifications, addSpecifications, delSpecifications} from "@/api/retailmall/specifications"; import {listUnits,} from "@/api/mall/units"; import {useRoute, useRouter} from "vue-router"; import {onMounted} from "vue"; // Emit const emit = defineEmits(['editShopOpen']) // route const route = useRoute() // store import useMallStore from '@/store/modules/mall' const mallStore = useMallStore() const router = useRouter() const {proxy} = getCurrentInstance(); const model = reactive({ fromData: {}, pages: { pageNum: 1, pageSize: 10, total: 0 }, expands: [],//表格展开行 shopTableList: [],//商品列表 loading: true, units: [],//单位列表 }); const {fromData, expands, pages, shopTableList, loading, units} = toRefs(model); // 编辑商品 const editShop = (id) => { emit('editShopOpen') mallStore.setCurGoodId(id) } // 增加规格 const addSpecif = (row, props) => { let params = { commodityId: row.id, crossedPrice: 0, stock: 0, price: 0, specifications: 0, specificationDescription: "" } addSpecifications(params).then(res => { if (+res.code === 200) { previewGoods(props.row.id).then((res) => { if (+res.code === 200) { model.expands = [] // 展开行 model.expands.push(row.id) props.row.bMallGoodsSpecifications = res.data.bMallGoodsSpecifications proxy.$message.success("新增成功") } }) } }) } // 修改规格 const updateSpecification = (row) => { updateSpecifications(row).then((res) => { if (+res.code === 200) { row.specificationEdit = false proxy.$message.success("编辑成功") } }) } // 表格展开变化 -- 只能展开一行 const expandChange = (row, expandedRows) => { if (expandedRows.length) { model.expands = [] if (row) { model.expands.push(row.id) } } else { model.expands = [] } } // 删除商品 const delShop = (row) => { proxy.$modal.confirm(`确定要删除${row.productName}`).then(function () { return delGoods(row.id) }).then(() => { getList(); proxy.$modal.msgSuccess("删除成功"); }) } // 是否静态开关变化 const staticStateChange = (item) => { return new Promise((resolve, reject) => { proxy.$modal.confirm('一旦商品开启静态,该商品不可进行任何操作(删除编辑发布隐藏),是否确定要 修改 商品 ?').then(() => { resolve(true) }) }) } // 编辑规格 const editSpecifications = (row) => { row.specificationEdit = true } // 删除规格 const delSpecifica = (row, props) => { proxy.$modal.confirm(`确定要删除${row.productName}`).then(function () { return delSpecifications(row.id) }).then(() => { previewGoods(props.row.id).then((res) => { props.row.bMallGoodsSpecifications = res.data.bMallGoodsSpecifications }) proxy.$modal.msgSuccess("删除成功"); }) } // 获取商品列表 function getList() { let params = { ...model.fromData, ...model.pages, shopIds: [route.query.id], total: undefined } model.loading = true; listGoods(params).then(response => { model.expands = [] // 不展开行 model.shopTableList = response.rows || {bMallGoodsSpecifications: []}; model.pages.total = response.total; model.loading = false; }) } // 表单重置 function reset() { form.value = {}; } // 获取全部单位 const getlistUnits = () => { let params = { pageNum: 1, pageSize: 999 } listUnits(params).then(res => { model.units = res.rows.map((item) => { return { label: item.name, value: item.id } }) }) } // 重置 const resetBtn = () => { fromData.value = {} getList() } onMounted(() => { getList(); getlistUnits() }) const formatInventoryStrategy = (val) => { let str = '' switch (val) { case 0: str = '无需库存' break case 1: str = '下单后减少' break case 2: str = '支付后减少' break case 3: str = '使用后减少' break } return str } </script>