merchapp/java-mall-app-shop-admin/pages/warehouse/manage/specificationOfGood.vue
2025-08-06 10:11:54 +08:00

1170 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="specificationOfGood-container">
<navBar
class="nav-bar"
:statusBar="true"
:border="false"
:fixed="true"
:height="'44px'"
:rightWidth="0"
:leftWidth="30"
title="售卖规格"
backgroundColor="#fff"
>
<block slot="left">
<u-icon
name="arrow-left"
color="#000"
size="20"
@click="pageBack()"
></u-icon>
</block>
</navBar>
<view class="tips">
注意这个是每个分类下对应的规格不是当前商品的规格
</view>
<view class="specificationOfGood-content">
<view class="specificationOfGood-tips">
<view class="">
{{ commoditSpecificationBaseInfo2.specs[0].spec_name }}
</view>
<view>
<text
@click="handerShowAddClassifySpecification(true)"
style="margin-right: 40rpx"
>
新增
</text>
<text @click="handerShowClassifySpeciflcationList">编辑</text>
</view>
</view>
<view
class="specificationOfGood-tips-name"
v-if="commoditSpecificationBaseInfo2.specs[0].specItems.length > 0"
>
规格列表
</view>
<!-- <view
class="specificationOfGood-input-content"
v-for="(item, index) of specificationList"
:key="index"
>
<u--input
class="specification-input"
placeholder="请输入自定义规格值"
:border="'surround'"
v-model="item.spec_item_name"
@change="handerAddInfo($event, index)"
></u--input>
<u-icon
name="trash"
class="specification-icon"
size="20"
@click="handerDelectSpecification(index)"
></u-icon>
</view>
<u-button
class="add-btn"
:hairline="true"
:plain="true"
shape="circle"
@click="handerAddItem()"
>
<u-icon
name="plus"
size="10"
style="margin-right: 16rpx"
color="#000"
></u-icon>
添加规格值
</u-button> -->
<u-checkbox-group
v-if="classifySpecificationList.length > 0"
v-model="checkboxValue"
placement="row"
class="checkbox-group"
@change="handerChangeCheckboxGroup"
>
<u-checkbox
class="checkbox-item"
:customStyle="{ marginBottom: '8px' }"
v-for="(item, index) in classifySpecificationList"
:key="index"
:label="item.spec_item_name"
:name="item.spec_item_id"
></u-checkbox>
</u-checkbox-group>
<view
class="specificationOfGood-tips"
v-if="specificationInfoList.length > 0"
>
设置售卖信息
</view>
<view class="commodity-content" v-if="specificationInfoList.length > 0">
<view
class="commodity-item"
v-for="(item, index) of specificationInfoList"
:key="index"
>
<view class="commodity-info">
<view class="commodity-info-name-content">
<view class="commodity-info-name">
规格{{ index + 1 }} {{ item.spec_item_name }}
</view>
<view class="commodity-info-switch">
<text class="switch-label">是否默认</text>
<u-switch
v-model="item.item_is_default"
:activeValue="true"
:inactiveValue="false"
activeColor="#5ac725"
></u-switch>
</view>
</view>
<view class="commodity-info-item">
<view class="commodity-info-lable">属性编号</view>
<u--input
class="input-price"
placeholder="请输入属性编号(货号)"
border="surround"
v-model="item.item_number"
type="number"
clearable
></u--input>
</view>
<view class="commodity-info-item">
<view class="commodity-info-lable required-label">市场价</view>
<u--input
class="input-price"
:placeholder="String(item.item_market_price) || '请输入'"
border="surround"
v-model="item.item_market_price_2"
prefixIcon="¥"
type="number"
clearable
@change="handerChangeMarketPrice($event, index)"
></u--input>
</view>
<view class="commodity-info-item">
<view class="commodity-info-lable required-label">零售价</view>
<u--input
class="input-price"
:placeholder="String(item.item_unit_price) || '请输入'"
border="surround"
v-model="item.item_unit_price_2"
prefixIcon="¥"
type="number"
clearable
@change="handerChangeUnitPrice($event, index)"
></u--input>
</view>
<view class="commodity-info-item">
<view class="commodity-info-lable required-label">库存</view>
<u--input
class="input-price"
:placeholder="String(item.item_quantity) || '请填写商品库存'"
border="surround"
type="number"
clearable
v-model="item.item_quantity_2"
@change="handerChangeQuantity($event, index)"
></u--input>
</view>
</view>
</view>
</view>
</view>
<view class="bottom-btn">
<view class="bottom-list">
<u-button
class="bottom-btn-item"
:hairline="true"
:plain="true"
shape="circle"
@click="handerAddAndEditPopup()"
>
保存
</u-button>
</view>
</view>
<u-popup
class="classify-specification-popup"
:show="showBottomPopup"
mode="bottom"
:closeable="true"
zIndex="10075"
@close="handerCloseBottomPopup"
>
<view class="classify-specification-popup-content">
<view class="classify-specification-popup-title">管理分类规格</view>
<view class="classify-specification-list">
<scroll-view
v-if="classifySpecificationList.length > 0"
scroll-y
class="classify-specification-scroll-view"
:show-scrollbar="false"
:style="{
maxHeight:
classifySpecificationList.length >= 7 ? '500px' : 'none',
overflowY:
classifySpecificationList.length >= 7 ? 'auto' : 'visible',
}"
>
<view
class="classify-specification-item"
v-for="(item, index) of classifySpecificationList"
:key="index"
>
<view class="classify-specification-name">
{{ item.spec_item_name }}
</view>
<view class="classify-specification-btn-list">
<view class="btn_item" @click="handerShowDelectPopup(item)">
<u-icon
class="u-icon-jianhao"
custom-prefix="custom-icon-jianhao_fangxing custom-icon"
size="18"
color="#FE411B"
></u-icon>
删除
</view>
<view
class="btn_item"
@click="handerShowAddClassifySpecification(false, item)"
>
<u-icon
class="u-icon-bianji"
custom-prefix="custom-icon-icon_519 custom-icon"
size="18"
color="#FE411B"
></u-icon>
编辑
</view>
</view>
</view>
</scroll-view>
<view class="no-data" v-if="classifySpecificationList.length <= 0">
<view class="no-data-bg"></view>
<view
class="no-data-tips"
@click="handerShowAddClassifySpecification"
>
还无更多规格,立即添加
<u-icon
style="display: inline-block"
name="arrow-right"
color="red"
></u-icon>
</view>
</view>
</view>
</view>
</u-popup>
<u-popup
class="add-popup"
zIndex="10077"
:show="showAddAndEditClassifySpecification"
mode="center"
@close="closeAddAndEditClassifySpecification"
>
<view class="add-popup-content">
<view class="add-popup-title">
{{ isAddClassifySpecification ? "新建" : "编辑" }} 分类规格
</view>
<view class="add-tips">
注意,绑定商品后不可修改名称,和删除分类规格!
</view>
<u--form
labelPosition="left"
:model="form"
ref="uForm"
label-width="100"
:rules="rules"
>
<u-form-item
label="规格名称"
prop="spec_item_name"
class="form-item"
required
>
<u--textarea
class="u-textarea"
v-model="form.spec_item_name"
count
autoHeight
maxlength="8"
placeholder="请输入规格名称"
></u--textarea>
</u-form-item>
<u-form-item
label="规格排序"
prop="spec_item_order"
class="form-item"
>
<u--input
v-model="form.spec_item_order"
type="number"
placeholder="请输入规格排序"
border="none"
clearable
></u--input>
</u-form-item>
</u--form>
<view class="popup-btn-list">
<u-button
class="btn-item"
:hairline="true"
:plain="true"
shape="circle"
@click="showAddAndEditClassifySpecification = false"
>
取消
</u-button>
<u-button
class="btn-item btn-item-2"
:hairline="true"
:plain="true"
shape="circle"
@click="updateCommoditSpecification"
>
{{ isAddClassifySpecification ? "添加" : "修改" }}
</u-button>
</view>
</view>
</u-popup>
<u-popup
class="affirm-popup"
zIndex="10077"
:show="showDelectPopup"
mode="center"
>
<view class="affirm-popup-content">
<view class="affirm-popup-title">
确认删除"{{ currDelectItem.spec_item_name }}"规格?
</view>
<view class="popup-btn-list">
<u-button
class="btn-item"
:hairline="true"
:plain="true"
shape="circle"
@click="showDelectPopup = false"
>
取消
</u-button>
<u-button
class="btn-item btn-item-2"
:hairline="true"
:plain="true"
shape="circle"
@click="handerDelectClassify"
>
确认
</u-button>
</view>
</view>
</u-popup>
<u-popup
class="affirm-popup"
zIndex="10077"
:show="showBackPopup"
mode="center"
>
<view class="affirm-popup-content">
<view class="affirm-popup-title">确认退出</view>
<view class="affirm-popup-tips">
退出后已编辑规格信息将不被保存,是否退出
</view>
<view class="popup-btn-list">
<u-button
class="btn-item"
:hairline="true"
:plain="true"
shape="circle"
@click="showBackPopup = false"
>
取消
</u-button>
<u-button
class="btn-item btn-item-2"
:hairline="true"
:plain="true"
shape="circle"
@click="handerPageBack"
>
退出
</u-button>
</view>
</view>
</u-popup>
<u-toast ref="uToast" zIndex="12000" class="u-toast"></u-toast>
</view>
</template>
<script>
import navBar from "@/components/uni-nav-bar/uni-nav-bar";
import {
GetCommoditSpecification,
UpdateCommoditSpecification,
DelectCommoditSpecification,
GetClassifySpecificationList,
} from "@/api/warehouse/commodity";
export default {
name: "specificationOfGood",
props: {
classifyName: {
type: String,
default: "",
},
isAdd: {
type: Boolean,
default: true,
},
commoditSpecificationBaseInfo: {
type: Object,
default: () => ({
assists: [],
brands: {},
specs: [
{
specItems: [],
spec_name: "",
},
],
}),
},
productInfoByPid: {
type: Object,
default: () => ({
shop_product_assist_index: [],
shop_product_detail: {},
shop_product_image: [],
shop_product_index: {},
shop_product_info: {},
}),
},
typeId: {
type: Number,
default: 0,
},
sonSpecificationInfoList: {
typeof: Object,
default: () => [],
},
},
components: {
navBar,
},
data() {
return {
specificationList: [
{
spec_item_name: "",
spec_item_order: "",
},
],
specificationInfoList: [
{
item_is_default: false,
item_number: "",
item_market_price_2: "",
item_market_price: "",
item_unit_price: "",
item_unit_price_2: "",
item_quantity: "",
item_quantity_2: "",
},
],
time: null,
checkboxValue: [],
showBottomPopup: false,
classifySpecificationList: [],
form: {
spec_id: "",
spec_item_name: "",
spec_item_order: "",
},
isAddClassifySpecification: true,
showAddAndEditClassifySpecification: false,
rules: {
spec_item_name: [
{
required: true,
message: "请输入规格名称",
// 可以单个或者同时写两个触发验证方式
trigger: ["change", "blur"],
},
],
},
commoditSpecificationBaseInfo2: {
assists: [],
brands: {},
specs: [
{
specItems: [],
spec_name: "",
},
],
},
showDelectPopup: false,
currDelectItem: {},
showBackPopup: false,
};
},
computed: {},
onLoad: function (options) {},
onReady() {},
onShow() {
// this.classifyItem = form;
},
mounted() {
this.commoditSpecificationBaseInfo2 = JSON.parse(
JSON.stringify(this.commoditSpecificationBaseInfo)
);
if (this.commoditSpecificationBaseInfo2.specs[0].specItems.length > 0) {
console.log(this.commoditSpecificationBaseInfo2);
}
this.checkboxValue = this.sonSpecificationInfoList.map(
(item) => item.spec_item_id
);
console.log(this.checkboxValue);
if (this.sonSpecificationInfoList.length > 0) {
this.specificationInfoList = JSON.parse(
JSON.stringify(this.sonSpecificationInfoList)
);
}
this.getClassifySpecificationList();
},
methods: {
pageBack(isSave = false) {
if (!isSave && this.specificationInfoList.length > 0) {
this.showBackPopup = true;
} else {
this.$emit("pageBack");
}
},
handerPageBack() {
this.$emit("pageBack");
},
handerAddItem() {
this.specificationList.push({
spec_item_name: "",
spec_item_order: "",
});
},
handerDelectSpecification(index) {
this.specificationList.splice(index, 1);
this.specificationInfoList.splice(index, 1);
},
handerShowClassifySpeciflcationList() {
this.showBottomPopup = true;
},
async getClassifySpecificationList() {
let params = {
spec_id: this.commoditSpecificationBaseInfo2.specs[0].spec_id,
};
let res = await GetClassifySpecificationList(params);
if (res && res.status == 200) {
this.classifySpecificationList = res.data;
}
this.showBottomPopup = false;
},
handerCloseBottomPopup() {
this.showBottomPopup = false;
},
async updateCommoditSpecification() {
this.form.spec_id = this.commoditSpecificationBaseInfo2.specs[0].spec_id;
let params = this.form;
let res = await UpdateCommoditSpecification(params);
if (res && res.status == 200) {
this.$refs.uToast.show({
message: this.isAddClassifySpecification ? "添加成功" : "修改成功",
type: "succeed",
duration: 1000,
zIndex: 12000,
position: "top",
});
this.getClassifySpecificationList();
}
this.showAddAndEditClassifySpecification = false;
},
handerChangeCheckboxGroup(e) {
if (e.length === 0) {
this.specificationInfoList = [
{
item_is_default: false,
item_number: "",
item_market_price_2: "",
item_market_price: "",
item_unit_price: "",
item_unit_price_2: "",
item_quantity: "",
item_quantity_2: "",
},
];
return;
}
// 1. 处理取消勾选的规格从specificationInfoList中移除
this.specificationInfoList = this.specificationInfoList.filter((item) =>
e.includes(item.spec_item_id)
);
// 2. 处理新增勾选的规格添加到specificationInfoList
e.forEach((specItemId) => {
// 检查是否已存在
const exists = this.specificationInfoList.some(
(item) => item.spec_item_id === specItemId
);
if (!exists) {
// 从分类规格列表中查找对应的规格
const selectedItem = this.classifySpecificationList.find(
(item) => item.spec_item_id === specItemId
);
if (selectedItem) {
this.specificationInfoList.push({
spec_item_id: selectedItem.spec_item_id,
spec_item_name: selectedItem.spec_item_name,
item_is_default: false, // 默认不选中
item_number: "",
item_market_price_2: "",
item_market_price: "",
item_unit_price: "",
item_unit_price_2: "",
item_quantity: "",
...selectedItem,
});
}
}
});
},
handerShowAddClassifySpecification(isAddClassifySpecification, item) {
if (!isAddClassifySpecification) {
this.form = JSON.parse(JSON.stringify(item));
} else {
this.form = {
spec_item_name: "",
spec_item_order: "",
};
}
this.isAddClassifySpecification = isAddClassifySpecification;
this.showAddAndEditClassifySpecification = true;
},
closeAddAndEditClassifySpecification() {
this.showAddAndEditClassifySpecification = false;
},
handerShowDelectPopup(item) {
this.currDelectItem = item;
this.showDelectPopup = true;
},
async handerDelectClassify() {
let params = {
spec_item_id: this.currDelectItem.spec_item_id,
};
let res = await DelectCommoditSpecification(params);
if (res && res.status == 200) {
this.$refs.uToast.show({
message: "删除成功",
type: "succeed",
duration: 1000,
});
this.getClassifySpecificationList();
}
this.showDelectPopup = false;
},
handerChangeMarketPrice(e, index) {
this.specificationInfoList[index].item_market_price = e;
},
handerChangeUnitPrice(e, index) {
this.specificationInfoList[index].item_unit_price = e;
},
handerChangeQuantity(e, index) {
this.specificationInfoList[index].item_quantity = e;
},
handerAddAndEditPopup() {
let isVerify = true;
if (this.isAdd) {
for (let i = 0; i < this.specificationInfoList.length; i++) {
const item = this.specificationInfoList[i];
if (item.item_market_price_2 == "") {
this.$refs.uToast.show({
message: "存在未填写的市场价",
type: "error",
duration: 1000,
});
isVerify = false;
break;
}
if (item.item_unit_price_2 == "") {
this.$refs.uToast.show({
message: "存在未填写的零售价",
type: "error",
duration: 1000,
});
isVerify = false;
break;
}
if (item.item_quantity_2 == "") {
this.$refs.uToast.show({
message: "存在未填写的库存",
type: "error",
duration: 1000,
});
isVerify = false;
break;
}
}
} else {
for (let i = 0; i < this.specificationInfoList.length; i++) {
const item = this.specificationInfoList[i];
if (item.item_market_price == "") {
this.$refs.uToast.show({
message: "存在未填写的市场价",
type: "error",
duration: 1000,
});
isVerify = false;
break;
}
if (item.item_unit_price == "") {
this.$refs.uToast.show({
message: "存在未填写的零售价",
type: "error",
duration: 1000,
});
isVerify = false;
break;
}
if (item.item_unit_price == 0) {
this.$refs.uToast.show({
message: "零售价不能为0",
type: "error",
duration: 1000,
});
isVerify = false;
break;
}
if (item.item_quantity == "") {
this.$refs.uToast.show({
message: "存在未填写的库存",
type: "error",
duration: 1000,
});
isVerify = false;
break;
}
}
}
if (!isVerify) return;
this.$emit(
"handerSpecificationInfoList",
this.specificationInfoList,
this.checkboxValue
);
this.pageBack(true);
},
},
};
</script>
<style lang="scss" scoped>
@import "@/styles/variables.scss";
.specificationOfGood-container {
width: 100vw;
height: calc(100vh - 120rpx);
overflow: auto;
.tips {
margin: 20rpx;
padding: 20rpx;
border-radius: 16rpx;
background: #f5f6fa;
color: red;
}
.specificationOfGood-content {
.specificationOfGood-tips {
display: flex;
justify-content: space-between;
padding: 28rpx;
font-size: 30rpx;
background: #f5f6fa;
color: #5b5b5b;
}
.specificationOfGood-tips-name {
padding: 28rpx;
font-weight: bold;
}
.specificationOfGood-input-content {
display: flex;
margin-bottom: 20rpx;
padding: 0 24rpx;
.specification-input {
border: 1px solid #e7e7e7;
}
.specification-icon {
margin-left: 24rpx;
}
}
.add-btn {
width: 94%;
margin: 28rpx;
border-color: #979797;
color: #000;
&::after {
border: none;
}
}
.commodity-content {
background: #f5f6fa;
.commodity-item {
margin-bottom: 20px;
background: #fff;
.commodity-info {
.commodity-info-name-content {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 24rpx;
.commodity-info-name {
font-size: 36rpx;
font-weight: bold;
}
.commodity-info-switch {
display: flex;
align-items: center;
.switch-label {
margin-right: 20rpx;
}
}
}
.commodity-info-item {
display: flex;
align-items: center;
padding: 24rpx 36rpx;
border-bottom: 1px solid #efefef;
background: #fff;
.commodity-info-lable {
position: relative;
margin-right: 60rpx;
}
.required-label {
&::before {
content: "*";
position: absolute;
left: -20rpx;
top: 8rpx;
color: red;
}
}
::v-deep .input-price {
font-weight: bold;
color: 0 !important;
.u-icon__icon {
color: #000 !important;
}
}
}
}
}
}
}
.no-data {
.no-data-bg {
margin: 15% auto;
margin-bottom: 0;
width: 300rpx;
height: 200rpx;
background-image: url("../../../static/warehouse/no-classify.png");
background-size: 100%;
}
.no-data-tips {
margin: 80rpx auto;
color: red;
text-align: center;
}
}
.checkbox-group {
flex-flow: wrap;
padding: 0 20rpx;
.checkbox-item {
margin: 20rpx;
}
}
.classify-specification-popup {
::v-deep.u-popup__content {
border-top-left-radius: 16rpx;
border-top-right-radius: 16rpx;
background: #f8f8f8;
}
.classify-specification-popup-content {
// width: 100%;
.classify-specification-popup-title {
padding: 40rpx;
text-align: center;
font-weight: 500;
background: #fff;
border-top-left-radius: 16rpx;
border-top-right-radius: 16rpx;
}
.classify-specification-list {
background: #f8f8f8;
}
.classify-specification-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 40rpx;
padding-bottom: 20px;
background: #fff;
.classify-specification-btn-list {
display: flex;
align-items: center;
.btn_item {
margin-right: 20rpx;
display: flex;
align-items: center;
}
}
.popup-commodity-info {
.popup-commodity-info-name {
font-size: 36rpx;
font-weight: bold;
padding-left: 24rpx;
padding-top: 20rpx;
}
.commodity-info-item {
display: flex;
align-items: center;
padding: 12px;
border-bottom: 1px solid #efefef;
.popup-commodity-info-lable {
margin-right: 60px;
}
::v-deep .input-price {
font-weight: bold;
color: 0 !important;
.u-icon__icon {
color: #000 !important;
}
}
}
}
}
}
.classify-specification-bottom-btn {
padding: 40rpx;
background: #fff;
.btn-item {
height: 80rpx;
background: $base-color;
color: #fff;
&::after {
border: none;
}
}
}
}
.affirm-popup {
::v-deep.u-popup__content {
border-radius: 16rpx;
}
::v-deep.u-fade-enter-to {
z-index: 10076 !important;
}
.affirm-popup-content {
width: 600rpx;
.affirm-popup-title {
padding: 40rpx;
text-align: center;
font-weight: bold;
}
.affirm-popup-tips {
padding: 0 60rpx;
font-size: 28rpx;
text-align: center;
}
.popup-btn-list {
display: flex;
margin: 50rpx;
.btn-item {
width: 46%;
height: 80rpx;
border-color: #909193;
&::after {
border: none;
}
}
.btn-item-2 {
background: $base-color;
color: #fff;
border: none;
}
}
}
}
.add-popup {
::v-deep.u-popup__content {
border-radius: 16rpx;
}
::v-deep.u-fade-enter-to {
z-index: 10076 !important;
}
.add-popup-content {
width: 700rpx;
.add-popup-title {
padding: 40rpx;
text-align: center;
font-weight: bold;
font-size: 36rpx;
}
.add-tips {
padding: 0 24rpx;
text-align: center;
color: red;
}
.u-form {
margin: 0 40rpx;
.form-item {
margin: 28rpx 0;
}
}
.popup-btn-list {
display: flex;
margin: 50rpx;
.btn-item {
width: 46%;
height: 80rpx;
border-color: #909193;
&::after {
border: none;
}
}
.btn-item-2 {
background: $base-color;
color: #fff;
border: none;
}
}
}
}
.u-toast {
::v-deep.u-transition {
z-index: 12000;
}
}
.bottom-btn {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx;
background: #fff;
border-top: 2rpx solid $uni-border-color;
z-index: 2;
.bottom-list {
display: flex;
align-items: center;
justify-content: flex-end;
.bottom-btn-item {
font-size: 28rpx;
border-color: $base-color;
color: #fff;
background: $base-color;
.bottom-icon {
margin-right: 8rpx;
}
&::after {
border: none;
}
}
}
}
}
</style>