修改商品表单,调整商品库存、商品分类、商品单位等字段,优化商品条码输入限制,修复所属门店列表,调整表单提交逻辑。

This commit is contained in:
mkm 2024-07-17 14:39:00 +08:00
parent 9bc0b0c80a
commit 1a2731cf2b
5 changed files with 726 additions and 434 deletions

View File

@ -2,7 +2,7 @@ NODE_ENV = 'development'
VITE_NOW_TYPE = 'dist' VITE_NOW_TYPE = 'dist'
# Base API # Base API
# VITE_APP_BASE_URL='http://192.168.1.22:8545' VITE_APP_BASE_URL='http://192.168.1.22:8545'
VITE_APP_BASE_URL='https://test-multi-store.lihaink.cn' # VITE_APP_BASE_URL='https://test-multi-store.lihaink.cn'
# VITE_APP_BASE_URL='https://multi-store.lihaink.cn' # VITE_APP_BASE_URL='https://multi-store.lihaink.cn'

View File

@ -1,24 +1,46 @@
<template> <template>
<div> <div>
<el-card class="!border-none mb-4" shadow="never"> <el-card class="!border-none mb-4" shadow="never">
<el-form <el-form class="mb-[-16px]" :model="queryParams" inline>
class="mb-[-16px]"
:model="queryParams"
inline
>
<el-form-item label="门店" prop="store_id"> <el-form-item label="门店" prop="store_id">
<!-- <el-input class="w-[280px]" v-model="queryParams.store_id" clearable placeholder="请输入门店" /> --> <!-- <el-input class="w-[280px]" v-model="queryParams.store_id" clearable placeholder="请输入门店" /> -->
<el-select v-model="queryParams.store_id" filterable remote reserve-keyword <el-select
placeholder="输入门店名称搜索" remote-show-suffix :remote-method="remoteMethod" :loading="storeloading" v-model="queryParams.store_id"
style="width: 240px" @change="resetPage"> filterable
<el-option v-for="item in storeList" :key="item.id" :label="item.name" :value="item.id" /> remote
reserve-keyword
placeholder="输入门店名称搜索"
remote-show-suffix
:remote-method="remoteMethod"
:loading="storeloading"
style="width: 240px"
@change="resetPage"
>
<el-option
v-for="item in storeList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="商品名称" prop="store_name"> <el-form-item label="商品名称" prop="store_name">
<el-input class="w-[280px]" v-model="queryParams.store_name" @keydown.enter="resetPage" clearable placeholder="请输入商品名称" /> <el-input
class="w-[280px]"
v-model="queryParams.store_name"
@keydown.enter="resetPage"
clearable
placeholder="请输入商品名称"
/>
</el-form-item> </el-form-item>
<el-form-item label="商品条码" prop="bar_code"> <el-form-item label="商品条码" prop="bar_code">
<el-input class="w-[280px]" v-model="queryParams.bar_code" @keydown.enter="resetPage" clearable placeholder="请输入商品条码" /> <el-input
class="w-[280px]"
v-model="queryParams.bar_code"
@keydown.enter="resetPage"
clearable
placeholder="请输入商品条码"
/>
</el-form-item> </el-form-item>
<!-- <el-form-item label="状态" prop="bar_code"> <!-- <el-form-item label="状态" prop="bar_code">
<el-select v-model="queryParams.status" <el-select v-model="queryParams.status"
@ -48,25 +70,73 @@
<el-table-column label="门店" prop="system_store_name" show-overflow-tooltip /> <el-table-column label="门店" prop="system_store_name" show-overflow-tooltip />
<el-table-column label="分类" prop="cate_name" show-overflow-tooltip /> <el-table-column label="分类" prop="cate_name" show-overflow-tooltip />
<el-table-column label="商品名称" prop="store_name" show-overflow-tooltip /> <el-table-column label="商品名称" prop="store_name" show-overflow-tooltip />
<el-table-column label="商品图片" prop="image" show-overflow-tooltip > <el-table-column label="商品图片" prop="image" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
<el-image class="w-[40px] h-[40px]" :src="row.image" :preview-teleported="true"/> <el-image
class="w-[40px] h-[40px]"
:src="row.image"
:preview-teleported="true"
/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="价格" prop="price" show-overflow-tooltip /> <el-table-column
label="供货价"
prop="purchase"
min-width="100"
show-overflow-tooltip
/>
<el-table-column
label="商户价"
prop="cost"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="会员价"
prop="vip_price"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="终端零售价"
prop="price"
min-width="120"
show-overflow-tooltip
/>
<el-table-column label="商品条码" prop="bar_code" show-overflow-tooltip /> <el-table-column label="商品条码" prop="bar_code" show-overflow-tooltip />
<el-table-column label="销量" prop="sales" show-overflow-tooltip /> <el-table-column label="销量" prop="sales" show-overflow-tooltip />
<el-table-column label="售卖库存" prop="stock" show-overflow-tooltip /> <el-table-column label="售卖库存" prop="stock" show-overflow-tooltip />
<el-table-column label="兑换库存" prop="swap" show-overflow-tooltip /> <el-table-column label="兑换库存" prop="swap" show-overflow-tooltip />
<el-table-column label="单位" prop="unit_name" show-overflow-tooltip /> <el-table-column label="单位" prop="unit_name" show-overflow-tooltip />
<el-table-column label="状态" prop="status" > <el-table-column label="状态" prop="status">
<template #default="{ row }"> <template #default="{ row }">
<el-switch size="large" @change="statusChange(row)" v-model="row.status" :active-value="1" :inactive-value="0" active-text="上架" inactive-text="下架" inline-prompt /> <el-switch
size="large"
@change="statusChange(row)"
v-model="row.status"
:active-value="1"
:inactive-value="0"
active-text="上架"
inactive-text="下架"
inline-prompt
/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" min-width="140" fixed="right" align="center" show-overflow-tooltip > <el-table-column
label="操作"
min-width="140"
fixed="right"
align="center"
show-overflow-tooltip
>
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" v-prems="['store_branch_product.store_branch_product/deit']" link @click="handleEdit(row)">编辑</el-button> <el-button
type="primary"
v-prems="['store_branch_product.store_branch_product/deit']"
link
@click="handleEdit(row)"
>编辑</el-button
>
<!-- 此处删除无效果 --> <!-- 此处删除无效果 -->
<!-- <el-button type="danger" v-perms="['store_branch_product.store_branch_product/delete']" link @click="handleDelete(row.id)">删除</el-button> --> <!-- <el-button type="danger" v-perms="['store_branch_product.store_branch_product/delete']" link @click="handleDelete(row.id)">删除</el-button> -->
</template> </template>
@ -77,7 +147,13 @@
<pagination v-model="pager" @change="getLists" /> <pagination v-model="pager" @change="getLists" />
</div> </div>
</el-card> </el-card>
<edit-popup v-if="showEdit" ref="editRef" :dict-data="dictData" @success="getLists" @close="showEdit = false" /> <edit-popup
v-if="showEdit"
ref="editRef"
:dict-data="dictData"
@success="getLists"
@close="showEdit = false"
/>
</div> </div>
</template> </template>
@ -96,7 +172,6 @@ const editRef = shallowRef<InstanceType<typeof EditPopup>>()
// //
const showEdit = ref(false) const showEdit = ref(false)
// //
const queryParams = reactive({ const queryParams = reactive({
store_id: '', store_id: '',
@ -148,26 +223,28 @@ const handleDelete = async (id: number | any[]) => {
getLists() getLists()
const storeloading = ref(false); const storeloading = ref(false)
const storeList = ref([]); const storeList = ref([])
const remoteMethod = (e:string='') => { const remoteMethod = (e = '') => {
storeloading.value = true; storeloading.value = true
apiSystemStoreLists({ apiSystemStoreLists({
name: e, name: e,
page_size: 50 page_size: 50
}).then(res => { })
storeList.value = res.lists; .then((res) => {
setTimeout(()=>{ storeList.value = res.lists
storeloading.value = false; setTimeout(() => {
},300) storeloading.value = false
}).catch(err => { }, 300)
setTimeout(()=>{ })
storeloading.value = false; .catch((err) => {
},300) setTimeout(() => {
storeloading.value = false
}, 300)
}) })
} }
const statusChange = (row:any)=>{ const statusChange = (row: any) => {
apiStoreBranchProductUpdate({ apiStoreBranchProductUpdate({
id: row.id, id: row.id,
store_name: row.store_name, store_name: row.store_name,
@ -179,24 +256,23 @@ const statusChange = (row:any)=>{
} }
const producStatus = ref('0') const producStatus = ref('0')
const changeProducStatus = (e: any)=>{ const changeProducStatus = (e: any) => {
if(e==0) { if (e == 0) {
queryParams.status = null; queryParams.status = null
queryParams.stock = null; queryParams.stock = null
}else if(e==1){ } else if (e == 1) {
queryParams.status = 1; queryParams.status = 1
queryParams.stock = null; queryParams.stock = null
}else if(e==2){ } else if (e == 2) {
queryParams.status = 0; queryParams.status = 0
queryParams.stock = null; queryParams.stock = null
}else if(e==3){ } else if (e == 3) {
queryParams.status = null; queryParams.status = null
queryParams.stock = 10; queryParams.stock = 10
}else if(e==4){ } else if (e == 4) {
queryParams.status = null; queryParams.status = null
queryParams.stock = 0; queryParams.stock = 0
} }
getLists(); getLists()
} }
</script> </script>

View File

@ -1,7 +1,7 @@
<template> <template>
<el-card> <el-card>
<div class="mb-4 text-lg font-bold"> <div class="mb-4 text-lg font-bold">
{{ mode == "add" ? "添加商品" : "编辑商品" }} {{ mode == 'add' ? '添加商品' : '编辑商品' }}
</div> </div>
<div> <div>
<el-form ref="formRef" :model="formData" label-width="120px" :rules="formRules"> <el-form ref="formRef" :model="formData" label-width="120px" :rules="formRules">
@ -9,16 +9,35 @@
<material-picker v-model="formData.image" :limit="1" /> <material-picker v-model="formData.image" :limit="1" />
</el-form-item> </el-form-item>
<el-form-item label="商品名称" prop="store_name"> <el-form-item label="商品名称" prop="store_name">
<el-input v-model="formData.store_name" class="w-[500px]" clearable placeholder="请输入商品名称" :readonly="false" /> <el-input
v-model="formData.store_name"
class="w-[500px]"
clearable
placeholder="请输入商品名称"
:readonly="false"
/>
</el-form-item> </el-form-item>
<el-form-item label="商品条码" prop="bar_code"> <el-form-item label="商品条码" prop="bar_code">
<el-input v-model="formData.bar_code" class="w-[500px]" @input="validateInput" clearable placeholder="请输入商品条码" :readonly="false" /> <el-input
v-model="formData.bar_code"
class="w-[500px]"
@input="validateInput"
clearable
placeholder="请输入商品条码"
:readonly="false"
/>
</el-form-item> </el-form-item>
<el-form-item label="商品规格" prop="store_info"> <el-form-item label="商品规格" prop="store_info">
<el-input v-model="formData.store_info" class="w-[500px]" clearable placeholder="请输入商品规格" :readonly="false" /> <el-input
v-model="formData.store_info"
class="w-[500px]"
clearable
placeholder="请输入商品规格"
:readonly="false"
/>
</el-form-item> </el-form-item>
<el-form-item label="商品类型" prop="product_type"> <el-form-item label="商品类型" prop="product_type">
<el-radio-group v-model="formData.product_type" :disabled="mode!='add'"> <el-radio-group v-model="formData.product_type" :disabled="mode != 'add'">
<el-radio :label="0">普通产品</el-radio> <el-radio :label="0">普通产品</el-radio>
<el-radio :label="1">供销系列产品</el-radio> <el-radio :label="1">供销系列产品</el-radio>
<el-radio :label="2">兑换产品</el-radio> <el-radio :label="2">兑换产品</el-radio>
@ -26,39 +45,102 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="商品分类" prop="cate_arr"> <el-form-item label="商品分类" prop="cate_arr">
<el-cascader class="w-[500px]" v-model="formData.cate_arr" filterable clearable <el-cascader
:before-filter="beforeFilter" :props="props" placeholder="请选择商品分类" /> class="w-[500px]"
v-model="formData.cate_arr"
filterable
clearable
:before-filter="beforeFilter"
:props="props"
placeholder="请选择商品分类"
/>
</el-form-item> </el-form-item>
<el-form-item label="商品单位" prop="unit"> <el-form-item label="商品单位" prop="unit">
<el-cascader class="w-[500px]" v-model="formData.unit" :options="unitList" :props="{ <el-cascader
class="w-[500px]"
v-model="formData.unit"
:options="unitList"
:props="{
value: 'id', value: 'id',
label: 'name', label: 'name',
emitPath: false, emitPath: false
}" placeholder="请选择商品单位" /> }"
placeholder="请选择商品单位"
/>
</el-form-item> </el-form-item>
<el-form-item :label="filterStockName(formData.product_type)" prop="stock"> <el-form-item :label="filterStockName(formData.product_type)" prop="stock">
<el-input v-model="formData.stock" type="number" class="w-[500px]" clearable placeholder="请输入库存" :readonly="false" /> <el-input
v-model="formData.stock"
type="number"
class="w-[500px]"
clearable
placeholder="请输入库存"
:readonly="false"
/>
</el-form-item> </el-form-item>
<!-- <el-form-item label="兑换库存" prop="swap"> <!-- <el-form-item label="兑换库存" prop="swap">
<el-input v-model="formData.swap" type="number" class="w-[500px]" clearable placeholder="请输入库存" :readonly="false" /> <el-input v-model="formData.swap" type="number" class="w-[500px]" clearable placeholder="请输入库存" :readonly="false" />
</el-form-item> --> </el-form-item> -->
<el-form-item label="供货价" prop="purchase"> <el-form-item label="供货价" prop="purchase">
<el-input v-model="formData.purchase" type="number" class="w-[500px]" clearable placeholder="请输入供货价" :readonly="false" /> <el-input
v-model="formData.purchase"
type="number"
class="w-[500px]"
clearable
placeholder="请输入供货价"
:readonly="false"
/>
</el-form-item> </el-form-item>
<el-form-item label="商户价" prop="cost"> <el-form-item label="商户价" prop="cost">
<el-input v-model="formData.cost" type="number" class="w-[500px]" clearable placeholder="请输入商户价" :readonly="false" /> <el-input
v-model="formData.cost"
type="number"
class="w-[500px]"
clearable
placeholder="请输入商户价"
:readonly="false"
/>
</el-form-item> </el-form-item>
<el-form-item label="会员价" prop="vip_price"> <el-form-item label="会员价" prop="vip_price">
<el-input v-model="formData.vip_price" type="number" class="w-[500px]" clearable placeholder="请输入会员价" :readonly="false" /> <el-input
v-model="formData.vip_price"
type="number"
class="w-[500px]"
clearable
placeholder="请输入会员价"
:readonly="false"
/>
</el-form-item> </el-form-item>
<el-form-item label="终端零售价" prop="price"> <el-form-item label="终端零售价" prop="price">
<el-input v-model="formData.price" type="number" class="w-[500px]" clearable placeholder="请输入终端零售价" :readonly="false" /> <el-input
v-model="formData.price"
type="number"
class="w-[500px]"
clearable
placeholder="请输入终端零售价"
:readonly="false"
/>
</el-form-item> </el-form-item>
<el-form-item label="起批量" prop="batch"> <el-form-item label="起批量" prop="batch">
<el-input v-model="formData.batch" type="number" class="w-[500px]" clearable placeholder="请输入起批量" :readonly="false" /> <el-input
v-model="formData.batch"
type="number"
class="w-[500px]"
clearable
placeholder="请输入起批量"
:readonly="false"
/>
</el-form-item> </el-form-item>
<el-form-item label="厂家备注" prop="manufacturer_information"> <el-form-item label="厂家备注" prop="manufacturer_information">
<el-input v-model="formData.manufacturer_information" type="textarea" autosize class="w-[500px]" clearable :placeholder="`厂家名称\n联系人姓名\n联系电话`" :readonly="false" /> <el-input
v-model="formData.manufacturer_information"
type="textarea"
autosize
class="w-[500px]"
clearable
:placeholder="`厂家名称\n联系人姓名\n联系电话`"
:readonly="false"
/>
</el-form-item> </el-form-item>
<!-- <el-form-item label="上浮比例" prop="rose"> <!-- <el-form-item label="上浮比例" prop="rose">
<el-input v-model="formData.rose" type="number" class="w-[500px]" clearable placeholder="请输入上浮比例" :readonly="false" > <el-input v-model="formData.rose" type="number" class="w-[500px]" clearable placeholder="请输入上浮比例" :readonly="false" >
@ -76,18 +158,31 @@
<el-radio :label="1">全部门店</el-radio> <el-radio :label="1">全部门店</el-radio>
<el-radio :label="0">部分门店</el-radio> <el-radio :label="0">部分门店</el-radio>
</el-radio-group> </el-radio-group>
<div class="w-full" style="color:#64748b">可选择将商品同步到哪些门店使用</div> <div class="w-full" style="color: #64748b">可选择将商品同步到哪些门店使用</div>
<div class="mb-2"> <div class="mb-2">
<el-button type="primary" v-if="formData.is_store_all == 0" @click="showStore = true">添加门店</el-button> <el-button
type="primary"
v-if="formData.is_store_all == 0"
@click="showStore = true"
>添加门店</el-button
>
</div> </div>
<el-table :data="storeList" v-if="formData.is_store_all == 0"> <el-table :data="storeList" v-if="formData.is_store_all == 0">
<el-table-column label="ID" prop="id" show-overflow-tooltip /> <el-table-column label="ID" prop="id" show-overflow-tooltip />
<el-table-column label="门店名称" prop="name" show-overflow-tooltip /> <el-table-column label="门店名称" prop="name" show-overflow-tooltip />
<el-table-column label="手机号码" prop="phone" show-overflow-tooltip /> <el-table-column label="手机号码" prop="phone" show-overflow-tooltip />
<el-table-column label="详细地址" prop="detailed_address" show-overflow-tooltip /> <el-table-column
label="详细地址"
prop="detailed_address"
show-overflow-tooltip
/>
<el-table-column label="门店logo" prop="image" show-overflow-tooltip> <el-table-column label="门店logo" prop="image" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
<el-image :src="row.image" class="w-[50px] h-[50px]" :preview-teleported="true"/> <el-image
:src="row.image"
class="w-[50px] h-[50px]"
:preview-teleported="true"
/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="营业状态" prop="is_show" show-overflow-tooltip> <el-table-column label="营业状态" prop="is_show" show-overflow-tooltip>
@ -97,8 +192,12 @@
</el-table-column> </el-table-column>
<el-table-column label="操作" width="120" fixed="right"> <el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }"> <template #default="{ row }">
<el-button v-perms="['system_store.system_store/delete']" type="danger" link <el-button
@click="handleDelete(row.id)"> v-perms="['system_store.system_store/delete']"
type="danger"
link
@click="handleDelete(row.id)"
>
删除 删除
</el-button> </el-button>
</template> </template>
@ -117,95 +216,92 @@
</template> </template>
<script lang="ts" setup name="storeProductEdit"> <script lang="ts" setup name="storeProductEdit">
import { ElMessage, type FormInstance } from "element-plus"; import { ElMessage, type FormInstance } from 'element-plus'
import useMultipleTabs from "@/hooks/useMultipleTabs"; import useMultipleTabs from '@/hooks/useMultipleTabs'
import { import { apiStoreProductAdd, apiStoreProductEdit, apiStoreProductDetail } from '@/api/store_product'
apiStoreProductAdd, import { timeFormat } from '@/utils/util'
apiStoreProductEdit, import type { PropType } from 'vue'
apiStoreProductDetail, import { onMounted } from 'vue'
} from "@/api/store_product"; import { useRouter, useRoute } from 'vue-router'
import { timeFormat } from "@/utils/util"; import { apiStoreCategoryLists } from '@/api/store_category'
import type { PropType } from "vue"; import { apiStoreProductUnitLists } from '@/api/store_product_unit'
import { onMounted } from "vue";
import { useRouter, useRoute } from "vue-router";
import { apiStoreCategoryLists } from "@/api/store_category";
import { apiStoreProductUnitLists } from "@/api/store_product_unit";
defineProps({ defineProps({
dictData: { dictData: {
type: Object as PropType<Record<string, any[]>>, type: Object as PropType<Record<string, any[]>>,
default: () => ({}), default: () => ({})
}, }
}); })
const emit = defineEmits(["success", "close"]); const emit = defineEmits(['success', 'close'])
const formRef = shallowRef<FormInstance>(); const formRef = shallowRef<FormInstance>()
const { removeTab } = useMultipleTabs(); const { removeTab } = useMultipleTabs()
const mode = ref("add"); const mode = ref('add')
const filterStockName = (e: any)=>{ const filterStockName = (e: any) => {
let str = "库存"; let str = '库存'
if(e==1) str = "供销库存"; if (e == 1) str = '供销库存'
if(e==2) str = "兑换库存"; if (e == 2) str = '兑换库存'
if(e==3) str = "赠品库存"; if (e == 3) str = '赠品库存'
return str; return str
} }
// //
const formData = reactive({ const formData = reactive({
id: "", id: '',
image: "", image: '',
store_name: "", store_name: '',
bar_code: "", bar_code: '',
store_info: "", store_info: '',
product_type: 0, product_type: 0,
cate_arr: [], cate_arr: [],
cate_id: "", cate_id: '',
price: "", price: '',
vip_price: "", vip_price: '',
unit: "", unit: '',
stock: "", stock: '',
swap: "", swap: '',
cost: "", cost: '',
purchase: "", purchase: '',
batch: "", batch: '',
manufacturer_information: "", manufacturer_information: '',
rose: "0", rose: '0',
is_return: 1, // 1退,2退 is_return: 1, // 1退,2退
is_store_all: 1, // 1 2 is_store_all: 1 // 1 2
}); })
// //
const validateInput = () => { const validateInput = () => {
// //
const inputValue = formData.bar_code; const inputValue = formData.bar_code
// 使 // 使
const filteredValue = inputValue.replace(/[^a-zA-Z0-9]/g, ''); const filteredValue = inputValue.replace(/[^a-zA-Z0-9]/g, '')
// //
formData.bar_code = filteredValue; formData.bar_code = filteredValue
}; }
const showStore = ref(false); // const showStore = ref(false) //
// //
const storeList = ref([]); const storeList = ref([])
// //
const handleDelete = (id: number) => { const handleDelete = (id: number) => {
storeList.value = storeList.value.filter((item: any) => item.id !== id); storeList.value = storeList.value.filter((item: any) => item.id !== id)
}; }
// //
const onBindStore = (e: any[]) => { const onBindStore = (e: any[]) => {
e.forEach((item: any) => { e.forEach((item: any) => {
if (!storeList.value.find((t: any) => t.id == item.id)) { if (!storeList.value.find((t: any) => t.id == item.id)) {
storeList.value.push(item); storeList.value.push(item)
} }
}); })
showStore.value = false; showStore.value = false
} }
let resolves; let resolves
let nodes; let nodes
let flag = ref(false); const flag = ref(false)
let name; let name
onMounted(() => { onMounted(() => {
// setTimeout(() => { // setTimeout(() => {
// let dom = document.getElementsByClassName('caser')[0] // let dom = document.getElementsByClassName('caser')[0]
@ -223,26 +319,26 @@ const beforeFilter = (value) => {
return false return false
} }
const props = { const props = {
value: "id", value: 'id',
label: "name", label: 'name',
lazy: true, lazy: true,
lazyLoad(node, resolve) { lazyLoad(node, resolve) {
if (!resolves) resolves = resolve; if (!resolves) resolves = resolve
if (!nodes) nodes = node; if (!nodes) nodes = node
let pid = node.value || 0; const pid = node.value || 0
let data = {} let data = {}
if (flag.value) { if (flag.value) {
data = { name: name } data = { name: name }
if (!name) { if (!name) {
data = { data = {
pid: pid, pid: pid,
page_size: 10000, page_size: 10000
} }
} }
} else { } else {
data = { data = {
pid: pid, pid: pid,
page_size: 10000, page_size: 10000
} }
} }
apiStoreCategoryLists({ apiStoreCategoryLists({
@ -250,178 +346,182 @@ const props = {
}).then((res) => { }).then((res) => {
resolve( resolve(
res.lists.map((item: any) => { res.lists.map((item: any) => {
item.leaf = item.is_children == 0; item.leaf = item.is_children == 0
flag.value = false flag.value = false
return item; return item
}) })
); )
}); })
}, }
}; }
const unitList = ref([]); const unitList = ref([])
const getUnitList = () => { const getUnitList = () => {
apiStoreProductUnitLists({}).then((res) => { apiStoreProductUnitLists({}).then((res) => {
unitList.value = res.lists; unitList.value = res.lists
}); })
}; }
getUnitList(); getUnitList()
// //
const formRules = reactive<any>({ const formRules = reactive<any>({
store_name: [ store_name: [
{ {
required: true, required: true,
message: "请输入商品名称", message: '请输入商品名称',
trigger: ["blur"], trigger: ['blur']
}, }
], ],
bar_code: [ bar_code: [
{ {
required: true, required: true,
message: "请输入商品条码", message: '请输入商品条码',
trigger: ["blur"], trigger: ['blur']
}, }
], ],
store_info: [ store_info: [
{ {
required: true, required: true,
message: "请输入商品规格", message: '请输入商品规格',
trigger: ["blur"], trigger: ['blur']
}, }
], ],
cate_id: [ cate_id: [
{ {
required: true, required: true,
message: "请输入商品分类", message: '请输入商品分类',
trigger: ["blur", "change"], trigger: ['blur', 'change']
}, }
], ],
cate_arr: [ cate_arr: [
{ {
required: true, required: true,
message: "请选择商品分类", message: '请选择商品分类',
trigger: ["blur", "change"], trigger: ['blur', 'change']
}, }
], ],
price: [ price: [
{ {
required: true, required: true,
message: "请输入终端零售价", message: '请输入终端零售价',
trigger: ["blur"], trigger: ['blur']
}, }
], ],
vip_price: [ vip_price: [
{ {
required: true, required: true,
message: "请输入会员价", message: '请输入会员价',
trigger: ["blur"], trigger: ['blur']
}, }
], ],
unit: [ unit: [
{ {
required: true, required: true,
message: "请输入商品单位", message: '请输入商品单位',
trigger: ["blur", "change"], trigger: ['blur', 'change']
}, }
], ],
stock: [ stock: [
{ {
required: true, required: true,
message: "请输入售卖库存", message: '请输入售卖库存',
trigger: ["blur"], trigger: ['blur']
}, }
], ],
swap: [ swap: [
{ {
required: true, required: true,
message: "请输入兑换库存", message: '请输入兑换库存',
trigger: ["blur"], trigger: ['blur']
}, }
], ],
cost: [ cost: [
{ {
required: true, required: true,
message: "请输入门店零售", message: '请输入门店零售',
trigger: ["blur"], trigger: ['blur']
}, }
], ],
purchase: [ purchase: [
{ {
required: true, required: true,
message: "请输入供货价", message: '请输入供货价',
trigger: ["blur"], trigger: ['blur']
}, }
], ],
batch: [ batch: [
{ {
required: true, required: true,
message: "请输入起批量", message: '请输入起批量',
trigger: ["blur"], trigger: ['blur']
}, }
], ],
image: [ image: [
{ {
required: true, required: true,
message: "请输入商品图片", message: '请输入商品图片',
trigger: ["blur", "change"], trigger: ['blur', 'change']
}, }
], ]
}); })
// //
const setFormData = async (data: Record<any, any>) => { const setFormData = async (data: Record<any, any>) => {
for (const key in formData) { for (const key in formData) {
if (data[key] != null && data[key] != undefined) { if (data[key] != null && data[key] != undefined) {
//@ts-ignore //@ts-ignore
formData[key] = data[key]; formData[key] = data[key]
} }
} }
if (formData.cate_arr[0]) { if (formData.cate_arr[0]) {
formData.cate_arr = formData.cate_arr.map((item: any) => Number(item)); formData.cate_arr = formData.cate_arr.map((item: any) => Number(item))
} }
}
};
const getDetail = async (row: Record<string, any>) => { const getDetail = async (row: Record<string, any>) => {
const data = await apiStoreProductDetail({ const data = await apiStoreProductDetail({
id: row.id, id: row.id
}); })
setFormData(data); setFormData(data)
}; }
const router = useRouter()
const route = useRoute()
const router = useRouter();
const route = useRoute();
// //
const handleSubmit = async () => { const handleSubmit = async () => {
await formRef.value?.validate(); await formRef.value?.validate()
let data: any = { ...formData }; const data: any = { ...formData }
if (formData.is_store_all == 0 && mode.value == 'add') { if (formData.is_store_all == 0 && mode.value == 'add') {
data.store_arr = storeList.value.map((item: any) => item.id); data.store_arr = storeList.value.map((item: any) => item.id)
} else if (mode.value == 'edit') data.is_store_all = 0; } else if (mode.value == 'edit') data.is_store_all = 0
if(!data.cate_arr.length) return ElMessage.error('请选择商品分类'); if (!data.cate_arr.length) return ElMessage.error('请选择商品分类')
data.cate_id = data.cate_arr[data.cate_arr.length - 1]; data.cate_id = data.cate_arr[data.cate_arr.length - 1]
delete data.cate_arr; delete data.cate_arr
mode.value == "edit" mode.value == 'edit' ? await apiStoreProductEdit(data) : await apiStoreProductAdd(data)
? await apiStoreProductEdit(data) // tabsStore.removeTab('/store/store_product?page_no' + route.query.page, router)
: await apiStoreProductAdd(data);
removeTab(); // removeTab()
router.push({ router.push({
path: "/store/store_product", path: '/store/store_product?=',
}); query: {
}; page_no: route.query.page
}
if (route.query.id && route.query.mode == 'edit') {
mode.value = 'edit';
getDetail({
id: route.query.id,
}) })
} }
if (route.query.id && route.query.mode == 'edit') {
mode.value = 'edit'
getDetail({
id: route.query.id
})
}
</script> </script>
<style> <style>
input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
</style> </style>

View File

@ -3,11 +3,25 @@
<el-card class="!border-none mb-4" shadow="never"> <el-card class="!border-none mb-4" shadow="never">
<el-form class="mb-[-16px]" :model="queryParams" inline> <el-form class="mb-[-16px]" :model="queryParams" inline>
<el-form-item label="商品名称" prop="store_name"> <el-form-item label="商品名称" prop="store_name">
<el-input class="w-[280px]" @keydown.enter="resetPage" v-model="queryParams.store_name" clearable placeholder="请输入商品名称" /> <el-input
class="w-[280px]"
@keydown.enter="resetPage"
v-model="queryParams.store_name"
clearable
placeholder="请输入商品名称"
/>
</el-form-item> </el-form-item>
<el-form-item label="商品分类" prop="store_name"> <el-form-item label="商品分类" prop="store_name">
<el-cascader class="w-[280px]" v-model="queryParams.class_all" filterable clearable <el-cascader
:before-filter="beforeFilter" :props="props" placeholder="请选择商品分类" @change="resetPage" /> class="w-[280px]"
v-model="queryParams.class_all"
filterable
clearable
:before-filter="beforeFilter"
:props="props"
placeholder="请选择商品分类"
@change="resetPage"
/>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button> <el-button type="primary" @click="resetPage">查询</el-button>
@ -16,24 +30,31 @@
</el-form> </el-form>
</el-card> </el-card>
<el-card class="!border-none" v-loading="pager.loading" shadow="never"> <el-card class="!border-none" v-loading="pager.loading" shadow="never">
<router-link :to="{ <router-link
:to="{
path: 'store_product_edit', path: 'store_product_edit',
query: { id: 0, mode: 'add' }, query: { id: 0, mode: 'add' }
}" class="mr-4" v-perms="['store_product.store_product/add']"> }"
<el-button type="primary" icon="Plus"> class="mr-4"
新增 v-perms="['store_product.store_product/add']"
</el-button> >
<el-button type="primary" icon="Plus"> 新增 </el-button>
</router-link> </router-link>
<el-button v-perms="['store_product.store_product/delete']" :disabled="!selectData.length" <el-button
@click="handleDelete(selectData)"> v-perms="['store_product.store_product/delete']"
:disabled="!selectData.length"
@click="handleDelete(selectData)"
>
删除 删除
</el-button> </el-button>
<router-link :to="{ <router-link
path: 'product_import', :to="{
}" class="ml-4" v-perms="['store_product.store_product/add']"> path: 'product_import'
<el-button type="primary"> }"
导入商品到门店 class="ml-4"
</el-button> v-perms="['store_product.store_product/add']"
>
<el-button type="primary"> 导入商品到门店 </el-button>
</router-link> </router-link>
<div class="mt-4"> <div class="mt-4">
<el-table :data="pager.lists" @selection-change="handleSelectionChange"> <el-table :data="pager.lists" @selection-change="handleSelectionChange">
@ -41,48 +62,118 @@
<el-table-column label="商品ID" prop="id" show-overflow-tooltip /> <el-table-column label="商品ID" prop="id" show-overflow-tooltip />
<el-table-column label="商品图片" prop="image" min-width="80"> <el-table-column label="商品图片" prop="image" min-width="80">
<template #default="{ row }"> <template #default="{ row }">
<el-image style="width: 50px; height: 50px" :src="row.image" :preview-teleported="true"/> <el-image
style="width: 50px; height: 50px"
:src="row.image"
:preview-teleported="true"
/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="商品名称" prop="store_name" min-width="200" show-overflow-tooltip /> <el-table-column
<el-table-column label="分类" prop="cate_name" min-width="120" show-overflow-tooltip /> label="商品名称"
<el-table-column label="单位" prop="unit_name" min-width="80" show-overflow-tooltip /> prop="store_name"
<el-table-column label="供货价" prop="purchase" min-width="100" show-overflow-tooltip /> min-width="200"
<el-table-column label="商户价" prop="cost" min-width="120" show-overflow-tooltip /> show-overflow-tooltip
<el-table-column label="会员价" prop="vip_price" min-width="120" show-overflow-tooltip /> />
<el-table-column label="终端零售价" prop="price" min-width="120" show-overflow-tooltip /> <el-table-column
<el-table-column label="起批量" prop="batch" min-width="100" show-overflow-tooltip /> label="分类"
<el-table-column label="售卖库存" prop="stock" min-width="100" show-overflow-tooltip /> prop="cate_name"
<el-table-column label="兑换库存" prop="swap" min-width="100" show-overflow-tooltip /> min-width="120"
<el-table-column label="销量" prop="sales" min-width="100" show-overflow-tooltip /> show-overflow-tooltip
/>
<el-table-column
label="单位"
prop="unit_name"
min-width="80"
show-overflow-tooltip
/>
<el-table-column
label="供货价"
prop="purchase"
min-width="100"
show-overflow-tooltip
/>
<el-table-column
label="商户价"
prop="cost"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="会员价"
prop="vip_price"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="终端零售价"
prop="price"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="起批量"
prop="batch"
min-width="100"
show-overflow-tooltip
/>
<el-table-column
label="售卖库存"
prop="stock"
min-width="100"
show-overflow-tooltip
/>
<el-table-column
label="兑换库存"
prop="swap"
min-width="100"
show-overflow-tooltip
/>
<el-table-column
label="销量"
prop="sales"
min-width="100"
show-overflow-tooltip
/>
<!-- <el-table-column label="商品来源" prop="system_store_name" min-width="200" show-overflow-tooltip /> --> <!-- <el-table-column label="商品来源" prop="system_store_name" min-width="200" show-overflow-tooltip /> -->
<el-table-column label="状态" prop="is_show"> <el-table-column label="状态" prop="is_show">
<template #default="{ row }"> <template #default="{ row }">
<el-tag type="success" v-if="row.is_show"> <el-tag type="success" v-if="row.is_show"> 上架 </el-tag>
上架 <el-tag type="info" v-else> 下架 </el-tag>
</el-tag>
<el-tag type="info" v-else>
下架
</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="条码" prop="bar_code" min-width="200" show-overflow-tooltip /> <el-table-column
label="条码"
prop="bar_code"
min-width="200"
show-overflow-tooltip
/>
<el-table-column label="操作" width="180" fixed="right"> <el-table-column label="操作" width="180" fixed="right">
<template #default="{ row }"> <template #default="{ row }">
<router-link :to="{ <router-link
:to="{
path: 'store_product_edit', path: 'store_product_edit',
query: { id: row.id, mode: 'edit' }, query: { id: row.id, mode: 'edit', page: pager.page }
}" class="mr-4" v-perms="['store_product.store_product/edit']"> }"
<el-button type="primary" link> class="mr-4"
编辑 v-perms="['store_product.store_product/edit']"
</el-button> >
<el-button type="primary" link> 编辑 </el-button>
</router-link> </router-link>
<el-button v-perms="['store_product.store_product/edit']" type="primary" link <el-button
@click="handleDetail(row)"> v-perms="['store_product.store_product/edit']"
type="primary"
link
@click="handleDetail(row)"
>
详情 详情
</el-button> </el-button>
<el-button v-perms="['store_product.store_product/delete']" type="danger" link <el-button
@click="handleDelete(row.id)"> v-perms="['store_product.store_product/delete']"
type="danger"
link
@click="handleDelete(row.id)"
>
删除 删除
</el-button> </el-button>
</template> </template>
@ -98,64 +189,60 @@
</template> </template>
<script lang="ts" setup name="storeProductLists"> <script lang="ts" setup name="storeProductLists">
import { usePaging } from "@/hooks/usePaging"; import { usePaging } from '@/hooks/usePaging'
import { useDictData } from "@/hooks/useDictOptions"; import { useDictData } from '@/hooks/useDictOptions'
import { import { apiStoreProductLists, apiStoreProductDelete } from '@/api/store_product'
apiStoreProductLists, import { timeFormat } from '@/utils/util'
apiStoreProductDelete, import feedback from '@/utils/feedback'
} from "@/api/store_product"; import Details from './details.vue'
import { timeFormat } from "@/utils/util"; import { apiStoreCategoryLists } from '@/api/store_category'
import feedback from "@/utils/feedback"; import { useRoute } from 'vue-router'
import Details from "./details.vue";
import { apiStoreCategoryLists } from "@/api/store_category";
const detailsRef = ref(null); const route = useRoute()
const detailsRef = ref(null)
// //
const queryParams = reactive({ const queryParams = reactive({
store_name: "", store_name: '',
class_all: "", class_all: ''
}); })
// //
const selectData = ref<any[]>([]); const selectData = ref<any[]>([])
// //
const handleSelectionChange = (val: any[]) => { const handleSelectionChange = (val: any[]) => {
console.log(val); selectData.value = val.map(({ id }) => id)
}
selectData.value = val.map(({ id }) => id);
};
// //
const { dictData } = useDictData(""); const { dictData } = useDictData('')
// //
let page_no = 1
if (route.query.page_no) {
page_no = parseInt(route.query.page_no)
}
const { pager, getLists, resetParams, resetPage } = usePaging({ const { pager, getLists, resetParams, resetPage } = usePaging({
page: page_no,
fetchFun: apiStoreProductLists, fetchFun: apiStoreProductLists,
params: queryParams, params: queryParams
}); })
// //
const handleAdd = async () => { const handleAdd = async () => {}
};
// //
const handleDetail = async (data: any) => { const handleDetail = async (data: any) => {
detailsRef.value?.open(); detailsRef.value?.open()
detailsRef.value?.setFormData(data); detailsRef.value?.setFormData(data)
}; }
// //
const handleEdit = async (data: any) => { const handleEdit = async (data: any) => {}
}; let resolves
let nodes
let resolves; const flag = ref(false)
let nodes; let name
let flag = ref(false);
let name;
const beforeFilter = (value) => { const beforeFilter = (value) => {
name = value name = value
flag.value = true flag.value = true
@ -163,27 +250,27 @@ const beforeFilter = (value) => {
return false return false
} }
const props = { const props = {
value: "id", value: 'id',
label: "name", label: 'name',
emitPath: false, emitPath: false,
lazy: true, lazy: true,
lazyLoad(node, resolve) { lazyLoad(node, resolve) {
if (!resolves) resolves = resolve; if (!resolves) resolves = resolve
if (!nodes) nodes = node; if (!nodes) nodes = node
let pid = node.value || 0; const pid = node.value || 0
let data = {} let data = {}
if (flag.value) { if (flag.value) {
data = { name: name } data = { name: name }
if (!name) { if (!name) {
data = { data = {
pid: pid, pid: pid,
page_size: 10000, page_size: 10000
} }
} }
} else { } else {
data = { data = {
pid: pid, pid: pid,
page_size: 10000, page_size: 10000
} }
} }
apiStoreCategoryLists({ apiStoreCategoryLists({
@ -192,21 +279,21 @@ const props = {
resolve( resolve(
res.lists.map((item: any) => { res.lists.map((item: any) => {
// item.leaf = item.is_children == 0; // item.leaf = item.is_children == 0;
item.leaf = true; item.leaf = true
flag.value = false flag.value = false
return item; return item
}) })
); )
}); })
}, }
}; }
// //
const handleDelete = async (id: number | any[]) => { const handleDelete = async (id: number | any[]) => {
await feedback.confirm("确定要删除?"); await feedback.confirm('确定要删除?')
await apiStoreProductDelete({ id }); await apiStoreProductDelete({ id })
getLists(); getLists()
}; }
getLists(); getLists()
</script> </script>

View File

@ -3,16 +3,31 @@
<el-card class="!border-none mb-4" shadow="never"> <el-card class="!border-none mb-4" shadow="never">
<el-form class="mb-[-16px]" :model="queryParams" inline> <el-form class="mb-[-16px]" :model="queryParams" inline>
<el-form-item label="用户昵称" prop="nickname"> <el-form-item label="用户昵称" prop="nickname">
<el-input class="w-[280px]" v-model="queryParams.nickname" @keydown.enter="resetPage" clearable <el-input
placeholder="请输入用户昵称" /> class="w-[280px]"
v-model="queryParams.nickname"
@keydown.enter="resetPage"
clearable
placeholder="请输入用户昵称"
/>
</el-form-item> </el-form-item>
<el-form-item label="用户账号" prop="account"> <el-form-item label="用户账号" prop="account">
<el-input class="w-[280px]" v-model="queryParams.account" @keydown.enter="resetPage" clearable <el-input
placeholder="请输入用户账号" /> class="w-[280px]"
v-model="queryParams.account"
@keydown.enter="resetPage"
clearable
placeholder="请输入用户账号"
/>
</el-form-item> </el-form-item>
<el-form-item label="用户电话" prop="mobile"> <el-form-item label="用户电话" prop="mobile">
<el-input class="w-[280px]" v-model="queryParams.mobile" @keydown.enter="resetPage" clearable <el-input
placeholder="请输入用户电话" /> class="w-[280px]"
v-model="queryParams.mobile"
@keydown.enter="resetPage"
clearable
placeholder="请输入用户电话"
/>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button> <el-button type="primary" @click="resetPage">查询</el-button>
@ -31,7 +46,7 @@
删除 删除
</el-button> --> </el-button> -->
<div class="mt-4"> <div class="mt-4">
<el-table :data="pager.lists" @selection-change="handleSelectionChange" > <el-table :data="pager.lists" @selection-change="handleSelectionChange">
<!-- <el-table-column type="selection" width="55" /> --> <!-- <el-table-column type="selection" width="55" /> -->
<el-table-column label="ID" prop="id" min-width="55" /> <el-table-column label="ID" prop="id" min-width="55" />
<el-table-column label="头像" prop="avatar" show-overflow-tooltip> <el-table-column label="头像" prop="avatar" show-overflow-tooltip>
@ -44,14 +59,14 @@
<el-table-column label="用户账号" prop="account" min-width="100" /> <el-table-column label="用户账号" prop="account" min-width="100" />
<!-- <el-table-column label="用户密码" prop="password" /> --> <!-- <el-table-column label="用户密码" prop="password" /> -->
<el-table-column label="用户电话" prop="mobile" min-width="100" /> <el-table-column label="用户电话" prop="mobile" min-width="100" />
<el-table-column label="用户性别" prop="sex"> <!-- <el-table-column label="用户性别" prop="sex">
<template #default="{ row }"> <template #default="{ row }">
<dict-value :options="dictData.sex" :value="row.sex" /> <dict-value :options="dictData.sex" :value="row.sex" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="注册渠道" prop="channel" /> <el-table-column label="注册渠道" prop="channel" /> -->
<el-table-column label="用户类型" prop="vip_name" /> <el-table-column label="用户类型" prop="vip_name" />
<el-table-column label="用户标签" prop="label_name" /> <!-- <el-table-column label="用户标签" prop="label_name" /> -->
<el-table-column label="礼品券" prop="integral" /> <el-table-column label="礼品券" prop="integral" />
<el-table-column label="返还金" prop="return_money"> <el-table-column label="返还金" prop="return_money">
<template #default="{ row }"> <template #default="{ row }">
@ -64,10 +79,20 @@
<el-table-column label="地址" prop="format_address" width="150" /> <el-table-column label="地址" prop="format_address" width="150" />
<el-table-column label="操作" width="120" fixed="right"> <el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }"> <template #default="{ row }">
<el-button v-perms="['user.user/edit']" type="primary" link @click="handleEdit(row)"> <el-button
v-perms="['user.user/edit']"
type="primary"
link
@click="handleEdit(row)"
>
编辑 编辑
</el-button> </el-button>
<el-button v-perms="['user.user/detail']" type="primary" link @click="handleDetail(row)"> <el-button
v-perms="['user.user/detail']"
type="primary"
link
@click="handleDetail(row)"
>
详情 详情
</el-button> </el-button>
<!-- <el-button v-perms="['user.user/delete']" type="danger" link @click="handleDelete(row.id)"> <!-- <el-button v-perms="['user.user/delete']" type="danger" link @click="handleDelete(row.id)">
@ -82,7 +107,13 @@
</div> </div>
</el-card> </el-card>
<Details ref="detailsRef" :dict-data="dictData"></Details> <Details ref="detailsRef" :dict-data="dictData"></Details>
<edit-popup v-if="showEdit" ref="editRef" :dict-data="dictData" @success="getLists" @close="showEdit = false" /> <edit-popup
v-if="showEdit"
ref="editRef"
:dict-data="dictData"
@success="getLists"
@close="showEdit = false"
/>
</div> </div>
</template> </template>
@ -93,15 +124,14 @@ import { apiUserLists, apiUserDelete } from '@/api/user'
import { timeFormat } from '@/utils/util' import { timeFormat } from '@/utils/util'
import feedback from '@/utils/feedback' import feedback from '@/utils/feedback'
import EditPopup from './edit.vue' import EditPopup from './edit.vue'
import Details from "./details.vue"; import Details from './details.vue'
const detailsRef = ref(null); const detailsRef = ref(null)
const editRef = shallowRef<InstanceType<typeof EditPopup>>() const editRef = shallowRef<InstanceType<typeof EditPopup>>()
// //
const showEdit = ref(false) const showEdit = ref(false)
// //
const queryParams = reactive({ const queryParams = reactive({
nickname: '', nickname: '',
@ -143,10 +173,9 @@ const handleEdit = async (data: any) => {
// //
const handleDetail = async (data: any) => { const handleDetail = async (data: any) => {
detailsRef.value?.open(); detailsRef.value?.open()
detailsRef.value?.setFormData(data); detailsRef.value?.setFormData(data)
}; }
// //
const handleDelete = async (id: number | any[]) => { const handleDelete = async (id: number | any[]) => {