2025-06-14 10:30:10 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="pageBox">
|
|
|
|
|
|
<div class="searchBox">
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<span class="span">商品:</span>
|
|
|
|
|
|
<div class="right">
|
2025-06-18 10:08:52 +08:00
|
|
|
|
<el-select v-model="goodsIds" placeholder="请选择" clearable filterable class="wid100" multiple collapse-tags>
|
2025-06-14 10:30:10 +08:00
|
|
|
|
<el-option v-for="it in goodsList" :key="it.id" :label="it.title" :value="it.id" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<span class="span">规格名称:</span>
|
|
|
|
|
|
<div class="right"><el-input v-model="filter.title" class="wid100" clearable></el-input></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<span class="span">规格编码:</span>
|
|
|
|
|
|
<div class="right"><el-input v-model="filter.sku_code" class="wid100" clearable></el-input></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<span class="span">仓库:</span>
|
|
|
|
|
|
<div class="right">
|
|
|
|
|
|
<el-select v-model="filter.warehouse_id" placeholder="请选择" clearable class="wid100" filterable>
|
|
|
|
|
|
<el-option v-for="it in warehouseList" :key="it.id" :label="it.name" :value="it.id" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<span class="span">状态:</span>
|
|
|
|
|
|
<div class="right">
|
|
|
|
|
|
<el-select v-model="filter.status" placeholder="请选择" clearable class="wid100">
|
|
|
|
|
|
<el-option label="启用" :value="1" />
|
|
|
|
|
|
<el-option label="不启用" :value="0" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<span class="span"></span>
|
|
|
|
|
|
<div class="right"><el-button type="primary" @click="handleSearch"><el-icon><Search /></el-icon> 筛选</el-button></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<el-card shadow="never">
|
|
|
|
|
|
<div class="opaBox">
|
|
|
|
|
|
<el-button type="primary" @click="handleAdd"><el-icon><Plus /></el-icon> 新增</el-button>
|
|
|
|
|
|
<!-- <el-button type="warning" @click="handleExport"><span class="iconfont icon-daochu"></span> 导出</el-button> -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-table :data="tableList" style="width: 100%" border v-loading="loading">
|
|
|
|
|
|
<el-table-column prop="id" label="ID" width="80" align="center" />
|
|
|
|
|
|
<el-table-column prop="goods.title" label="商品名称" align="center" />
|
|
|
|
|
|
<el-table-column prop="goods.goods_code" label="商品货号" align="center" />
|
|
|
|
|
|
<el-table-column prop="title" label="规格名称" align="center" />
|
|
|
|
|
|
<el-table-column prop="sku_code" label="规格编码" align="center" />
|
|
|
|
|
|
<el-table-column prop="actual_inventory" label="实际库存" align="center" />
|
|
|
|
|
|
<el-table-column prop="total_lock_num" label="总锁定库存" align="center" />
|
|
|
|
|
|
<el-table-column prop="lock_in_stock" label="运营锁定库存" align="center" />
|
|
|
|
|
|
<el-table-column prop="after_sale_stock" label="售后锁定库存" align="center" />
|
|
|
|
|
|
<el-table-column prop="available_inventory" label="可售库存" align="center" />
|
|
|
|
|
|
<el-table-column prop="warehouse.name" label="仓库" align="center" />
|
|
|
|
|
|
<el-table-column label="状态" align="center">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<span>{{ scope.row.status ? '启用' : '不启用' }}</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="created_at" label="添加时间" align="center" />
|
|
|
|
|
|
<el-table-column label="操作" align="center" width="150">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-button type="primary" circle @click="handleEdit(scope.row)"><el-icon><Edit /></el-icon></el-button>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
<div class="page-pagination">
|
|
|
|
|
|
<el-pagination
|
|
|
|
|
|
:current-page="page"
|
|
|
|
|
|
background
|
|
|
|
|
|
layout="prev, pager, next, sizes, total"
|
|
|
|
|
|
:total="total"
|
|
|
|
|
|
:page-sizes="[10, 50, 100]"
|
|
|
|
|
|
:page-size="pageSize"
|
|
|
|
|
|
@size-change="handleSizeChange"
|
|
|
|
|
|
@current-change="handleCurrentChange"></el-pagination>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<el-dialog v-model="showDialog" width="600px" :title="opaType == 'add' ? '新增' : '编辑' ">
|
|
|
|
|
|
<el-form label-position="right" label-width="110px">
|
|
|
|
|
|
<el-form-item label="所属商品:">
|
|
|
|
|
|
<el-select v-model="itemInfo.goods_id" placeholder="请选择" clearable filterable :disabled="role && opaType == 'edit'">
|
|
|
|
|
|
<el-option v-for="it in goodsList" :key="it.id" :label="it.title" :value="it.id" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="规格名称:">
|
|
|
|
|
|
<el-input v-model="itemInfo.title" clearable :disabled="role && opaType == 'edit'"></el-input>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="规格编码:">
|
|
|
|
|
|
<el-input v-model="itemInfo.sku_code" clearable :disabled="role && opaType == 'edit'"></el-input>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="仓库:">
|
|
|
|
|
|
<el-select v-model="itemInfo.warehouse_id" placeholder="请选择" clearable filterable :disabled="role && opaType == 'edit'">
|
|
|
|
|
|
<el-option v-for="it in warehouseList" :key="it.id" :label="it.name" :value="it.id" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="总锁定库存:">
|
|
|
|
|
|
<el-input v-model="itemInfo.total_lock_num" disabled></el-input>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="运营锁定库存:">
|
|
|
|
|
|
<el-input v-model="itemInfo.lock_in_stock" clearable></el-input>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="售后锁定库存:">
|
|
|
|
|
|
<el-input v-model="itemInfo.after_sale_stock" clearable :disabled="role && opaType == 'edit'"></el-input>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="状态:">
|
|
|
|
|
|
<el-radio-group v-model="itemInfo.status" :disabled="role && opaType == 'edit'">
|
|
|
|
|
|
<el-radio :label="1">启用</el-radio>
|
|
|
|
|
|
<el-radio :label="0">不启用</el-radio>
|
|
|
|
|
|
</el-radio-group>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="赠品:">
|
|
|
|
|
|
<el-radio-group v-model="itemInfo.gift" :disabled="role && opaType == 'edit'">
|
|
|
|
|
|
<el-radio :label="0">不是</el-radio>
|
|
|
|
|
|
<el-radio :label="1">是</el-radio>
|
|
|
|
|
|
</el-radio-group>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="排序:">
|
|
|
|
|
|
<el-input-number v-model="itemInfo.sort" :min="0" :disabled="role && opaType == 'edit'" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<span class="dialog-footer" v-if="opaType != 'view'">
|
|
|
|
|
|
<el-button @click="showDialog = false">取消</el-button>
|
|
|
|
|
|
<el-button type="primary" @click="commitOpa()" :loading="opa_loading">确定</el-button>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 预览图片 -->
|
|
|
|
|
|
<el-dialog v-model="picVisible" center width="800px">
|
|
|
|
|
|
<img :src="dialogImageUrl" style="max-width: 700px; margin: 0 auto;display: block;" />
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import { onMounted, reactive, toRefs } from "vue"
|
|
|
|
|
|
import { get, post } from "@/api/request"
|
|
|
|
|
|
import { Search, Plus, Edit, ZoomIn, Delete } from '@element-plus/icons'
|
|
|
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
|
|
|
import { parseErrors } from 'components/common'
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
components: {
|
|
|
|
|
|
Search, Plus, Edit, ZoomIn, Delete
|
|
|
|
|
|
},
|
|
|
|
|
|
setup() {
|
|
|
|
|
|
const data = reactive({
|
|
|
|
|
|
filter: {},
|
|
|
|
|
|
tableList: [],
|
|
|
|
|
|
page: 1,
|
|
|
|
|
|
pageSize: 10,
|
|
|
|
|
|
total: 0,
|
|
|
|
|
|
loading: false,
|
|
|
|
|
|
opaType: '',
|
|
|
|
|
|
showDialog: false,
|
|
|
|
|
|
opa_loading: false,
|
|
|
|
|
|
warehouseList: [],
|
|
|
|
|
|
goodsList: [],
|
|
|
|
|
|
itemInfo: {},
|
2025-06-18 10:08:52 +08:00
|
|
|
|
role: localStorage.getItem('roleName') == '爆品运营',
|
|
|
|
|
|
goodsIds: []
|
2025-06-14 10:30:10 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
function handleSearch() {
|
|
|
|
|
|
data.page = 1
|
|
|
|
|
|
fetchData()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const fetchData = () => {
|
|
|
|
|
|
data.loading = true
|
|
|
|
|
|
let params = {
|
|
|
|
|
|
page: data.page,
|
|
|
|
|
|
pageSize: data.pageSize,
|
|
|
|
|
|
service_id: data.service_id,
|
2025-06-18 10:08:52 +08:00
|
|
|
|
...data.filter,
|
|
|
|
|
|
goods_ids: data.goodsIds.join(',')
|
2025-06-14 10:30:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
get(`/api/goods-skus`, params).then((res) => {
|
|
|
|
|
|
data.tableList = res.data
|
|
|
|
|
|
data.total = res.meta.total
|
|
|
|
|
|
data.loading = false
|
|
|
|
|
|
}).catch(() => {
|
|
|
|
|
|
data.loading = false
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleCurrentChange(e) {
|
|
|
|
|
|
data.page = e
|
|
|
|
|
|
fetchData()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleSizeChange(e) {
|
|
|
|
|
|
data.page = 1
|
|
|
|
|
|
data.pageSize = e
|
|
|
|
|
|
fetchData()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleAdd() {
|
|
|
|
|
|
data.opaType = 'add'
|
|
|
|
|
|
data.itemInfo = {
|
|
|
|
|
|
status: 1,
|
|
|
|
|
|
sort: 0,
|
|
|
|
|
|
gift: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
data.showDialog = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleEdit(item) {
|
|
|
|
|
|
data.opaType = 'edit'
|
|
|
|
|
|
data.itemInfo = JSON.parse(JSON.stringify(item))
|
|
|
|
|
|
data.showDialog = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function commitOpa() {
|
|
|
|
|
|
data.opa_loading = true
|
|
|
|
|
|
let params = {
|
|
|
|
|
|
...data.itemInfo
|
|
|
|
|
|
}
|
|
|
|
|
|
if(data.opaType == 'add') {
|
|
|
|
|
|
post(`/api/goods-skus`, params).then(() => {
|
|
|
|
|
|
data.page = 1
|
|
|
|
|
|
fetchData()
|
|
|
|
|
|
ElMessage({ type: 'success', message: '新增成功' })
|
|
|
|
|
|
data.showDialog = false
|
|
|
|
|
|
data.opa_loading = false
|
|
|
|
|
|
}).catch((err) => {
|
|
|
|
|
|
data.opa_loading = false
|
|
|
|
|
|
parseErrors(err.response.data.errors)
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if(data.role) {
|
|
|
|
|
|
params = {
|
|
|
|
|
|
lock_in_stock: data.itemInfo.lock_in_stock
|
|
|
|
|
|
}
|
|
|
|
|
|
post(`/api/goods/sku/lockInStock/${data.itemInfo.id}`, params, 'PUT').then(() => {
|
|
|
|
|
|
fetchData()
|
|
|
|
|
|
ElMessage({ type: 'success', message: '编辑成功' })
|
|
|
|
|
|
data.showDialog = false
|
|
|
|
|
|
data.opa_loading = false
|
|
|
|
|
|
}).catch((err) => {
|
|
|
|
|
|
data.opa_loading = false
|
|
|
|
|
|
parseErrors(err.response.data.errors)
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
post(`/api/goods-skus/${data.itemInfo.id}`, params, 'PUT').then(() => {
|
|
|
|
|
|
fetchData()
|
|
|
|
|
|
ElMessage({ type: 'success', message: '编辑成功' })
|
|
|
|
|
|
data.showDialog = false
|
|
|
|
|
|
data.opa_loading = false
|
|
|
|
|
|
}).catch((err) => {
|
|
|
|
|
|
data.opa_loading = false
|
|
|
|
|
|
parseErrors(err.response.data.errors)
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getWarehouseList() {
|
|
|
|
|
|
get(`/api/all/warehouses`).then((res) => {
|
|
|
|
|
|
data.warehouseList = res.data
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getGoodsList() {
|
|
|
|
|
|
get(`/api/all/goods`).then((res) => {
|
|
|
|
|
|
data.goodsList = res.data
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
fetchData()
|
|
|
|
|
|
getWarehouseList()
|
|
|
|
|
|
getGoodsList()
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
...toRefs(data),
|
|
|
|
|
|
handleSearch,
|
|
|
|
|
|
handleCurrentChange,
|
|
|
|
|
|
handleSizeChange,
|
|
|
|
|
|
fetchData,
|
|
|
|
|
|
handleAdd,
|
|
|
|
|
|
handleEdit,
|
|
|
|
|
|
commitOpa,
|
|
|
|
|
|
getWarehouseList,
|
|
|
|
|
|
getGoodsList
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.searchBox{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
padding: 15px 0 0 0;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
|
.row{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
width: 20%;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
|
&.row1{
|
|
|
|
|
|
width: 25%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.span{
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
width: 80px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
}
|
|
|
|
|
|
.right{
|
|
|
|
|
|
width: calc(100% - 100px);
|
|
|
|
|
|
}
|
|
|
|
|
|
.wid100{
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.opaBox{
|
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.imgBox{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
.el-image{
|
|
|
|
|
|
width: 60px;
|
|
|
|
|
|
height: 60px;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.skuBox{
|
|
|
|
|
|
border: 1px solid #e5e5e5;
|
|
|
|
|
|
border-radius: 5px;
|
|
|
|
|
|
padding: 15px 0;
|
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
|
background-color: #f3f3f3;
|
|
|
|
|
|
.tit{
|
|
|
|
|
|
padding-left: 40px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|