feat(商品属性)

This commit is contained in:
unknown 2024-06-06 02:20:25 +08:00
parent 50e03907e7
commit c188d92c11
4 changed files with 515 additions and 551 deletions

View File

@ -9,12 +9,8 @@
<view class="property-value ss-flex ss-gap-40"> <view class="property-value ss-flex ss-gap-40">
<view class="property-value-text">规格值</view> <view class="property-value-text">规格值</view>
<view class="property-value-value ss-flex ss-gap-10"> <view class="property-value-value ss-flex ss-gap-10">
<view <view v-for="sitem in item.propertyValues" @tap="chooseProperty(item)"
v-for="sitem in item.propertyValues" :class="['item', sitem.checked ? 'active' : '']">{{ sitem.name }}</view>
@tap="chooseProperty(item)"
:class="['item', item.checked ? 'active' : '']"
>{{ sitem.name }}</view
>
</view> </view>
</view> </view>
</view> </view>
@ -24,6 +20,7 @@
<script setup> <script setup>
import { defineProps, ref, computed } from 'vue' import { defineProps, ref, computed } from 'vue'
import { goodsPropertyList } from '../js/sku';
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -58,6 +55,7 @@ function chooseProperty(item) {
.property-value-text { .property-value-text {
color: #606266; color: #606266;
} }
.property-value-value { .property-value-value {
.item { .item {
text-align: center; text-align: center;
@ -67,6 +65,7 @@ function chooseProperty(item) {
border-radius: 10px; border-radius: 10px;
background-color: var(--ui-BG-4); background-color: var(--ui-BG-4);
} }
.active { .active {
color: #fff; color: #fff;
background-color: var(--ui-BG-Main); background-color: var(--ui-BG-Main);

View File

@ -6,12 +6,8 @@
<view class="button-link" @click="onConfirmPopup">确定</view> <view class="button-link" @click="onConfirmPopup">确定</view>
</view> </view>
<view class="popup-content"> <view class="popup-content">
<view <view v-for="item in nowGoodsPropertyList" :key="item.id"
v-for="item in goodsPropertyList" :class="['property-item', item.checked ? 'active' : '']" @tap="chooseProperty(item)">
:key="item.id"
:class="['property-item', item.checked ? 'active' : '']"
@tap="chooseProperty(item)"
>
{{ item.name }} {{ item.name }}
</view> </view>
</view> </view>
@ -22,6 +18,7 @@
<script setup> <script setup>
import { ref, computed, defineEmits, defineProps, defineExpose } from 'vue' import { ref, computed, defineEmits, defineProps, defineExpose } from 'vue'
import peach from '@/peach' import peach from '@/peach'
import { cloneDeep } from 'lodash';
/** /**
* todo 底部高度配置 * todo 底部高度配置
@ -40,7 +37,9 @@ const props = defineProps({
}, },
}) })
const emit = defineEmits(['update:modelValue']) const nowGoodsPropertyList = ref([])
const emit = defineEmits(['update:modelValue', 'confirm'])
const propertyListPopupRef = ref() const propertyListPopupRef = ref()
@ -53,7 +52,8 @@ function chooseProperty(item) {
} }
function onConfirmPopup() { function onConfirmPopup() {
let resut = props.goodsPropertyList
let result = nowGoodsPropertyList.value
.filter((item) => { .filter((item) => {
if (item.checked) { if (item.checked) {
return item.propertyValues.filter((sitem) => sitem.checked) return item.propertyValues.filter((sitem) => sitem.checked)
@ -67,12 +67,15 @@ function onConfirmPopup() {
} }
}) })
console.log(resut)
// emit('update:modelValue', props.goodsPropertyList.filter((item) => item.checked).map((item) => item.id) ?? []) peach.$store('trade').selectedProperty = result
emit('confirm')
emit('update:modelValue', result)
onClosePopup() onClosePopup()
} }
function onOpen() { function onOpen() {
nowGoodsPropertyList.value = cloneDeep(props.goodsPropertyList)
propertyListPopupRef.value.open('bottom') propertyListPopupRef.value.open('bottom')
} }
@ -90,6 +93,7 @@ defineExpose({
flex-wrap: wrap; flex-wrap: wrap;
gap: 20rpx; gap: 20rpx;
justify-content: flex-start; justify-content: flex-start;
.property-item { .property-item {
text-align: center; text-align: center;
line-height: 60rpx; line-height: 60rpx;
@ -98,6 +102,7 @@ defineExpose({
border-radius: 10px; border-radius: 10px;
background-color: var(--ui-BG-4); background-color: var(--ui-BG-4);
} }
.active { .active {
color: #fff; color: #fff;
background-color: var(--ui-BG-Main); background-color: var(--ui-BG-Main);
@ -108,10 +113,12 @@ defineExpose({
color: #1892ea; color: #1892ea;
font-size: 28rpx; font-size: 28rpx;
} }
.button-cancel { .button-cancel {
color: #888; color: #888;
font-size: 28rpx; font-size: 28rpx;
} }
.popup-header { .popup-header {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -1,78 +1,82 @@
import { ref, computed } from 'vue' import { ref, computed } from "vue";
import { onLoad } from '@dcloudio/uni-app' import { onLoad } from "@dcloudio/uni-app";
import peach from '@/peach' import peach from "@/peach";
import GoodsApi from '@/peach/api/trade/goods' import GoodsApi from "@/peach/api/trade/goods";
import { SPEC_TYPE } from './config' import { SPEC_TYPE } from "./config";
const pickerRef = ref(null) const pickerRef = ref(null);
const propertyList = ref([ const propertyList = ref([]);
{
id: 36,
children: [68],
},
{
id: 37,
children: [],
},
])
const goodsPropertyList = ref([]) const goodsPropertyList = ref([]);
const propertyListRef = ref(null) const propertyListRef = ref(null);
const formData = ref({ const formData = ref({
specType: true, specType: true,
specText: SPEC_TYPE[0].label, specText: SPEC_TYPE[0].label,
}) });
async function showPropertyList() { async function showPropertyList() {
await getGoodsProperty() await getGoodsProperty();
propertyListRef.value.onOpen() propertyListRef.value.onOpen();
} }
function onRDPickerConfirm(e) { function onRDPickerConfirm(e) {
peach.$store('trade').specType = SPEC_TYPE[e.value[0]].value peach.$store("trade").specType = SPEC_TYPE[e.value[0]].value;
formData.value.specText = SPEC_TYPE[e.value[0]].label formData.value.specText = SPEC_TYPE[e.value[0]].label;
formData.value.specType = SPEC_TYPE[e.value[0]].value formData.value.specType = SPEC_TYPE[e.value[0]].value;
} }
function pickerProperty() { function pickerProperty() {
let index = specType ? 1 : 0 let index = specType ? 1 : 0;
pickerRef.value.onOpen([index]) pickerRef.value.onOpen([index]);
} }
function onPropertyConfirm(e) { function onPropertyConfirm(e) {
console.log(e) getGoodsProperty();
console.log(e);
} }
async function getGoodsProperty() { async function getGoodsProperty() {
let { data } = await GoodsApi.getHistoryProperty() let { data } = await GoodsApi.getHistoryProperty();
propertyList.value = [];
// 把 propertyList 中 id 相同的属性合并,并去重
propertyList.value = peach.$store("trade").selectedProperty;
// 根据已经选择数据,设置默认选中 // 根据已经选择数据,设置默认选中
data.forEach((item) => { data.forEach((item) => {
// 判断属性是否已经选中 // 判断属性是否已经选中
let propertyParent = propertyList.value.find((sitem) => sitem?.id === item.id) let propertyParent = propertyList.value.find(
(sitem) => sitem?.id === item.id
);
item.checked = propertyParent ? true : false item.checked = propertyParent ? true : false;
// 如果属性已经选中,查询子类中是否有选中 // 如果属性已经选中,查询子类中是否有选中
if (item.checked) { if (item.checked) {
item.propertyValues.forEach((child) => { item.propertyValues.forEach((child) => {
let childResult = propertyParent?.children.some((schild) => schild?.id === child.id) let childResult = propertyParent?.children.some(
child.checked = childResult ? true : false (schild) => schild?.id === child.id
}) );
console.log(childResult);
child.checked = childResult ? true : false;
});
} }
}) });
goodsPropertyList.value = data
goodsPropertyList.value = data;
} }
const specType = computed(() => peach.$store('trade').specType) const specType = computed(() => peach.$store("trade").specType);
function initial() { function initial() {
onLoad(() => { onLoad(() => {
formData.value.specType = specType ? true : false formData.value.specType = specType ? true : false;
formData.value.specText = SPEC_TYPE[specType ? 1 : 0].label formData.value.specText = SPEC_TYPE[specType ? 1 : 0].label;
}) getGoodsProperty();
});
} }
export { export {
@ -86,4 +90,4 @@ export {
propertyList, propertyList,
showPropertyList, showPropertyList,
goodsPropertyList, goodsPropertyList,
} };

View File

@ -1,75 +1,31 @@
<template> <template>
<pb-layout <pb-layout class="manage-goods" title="发布商品" leftIcon="leftIcon" navbar="normal" :bgStyle="bgStyle"
class="manage-goods" opacityBgUi="bg-white" color="black">
title="发布商品"
leftIcon="leftIcon"
navbar="normal"
:bgStyle="bgStyle"
opacityBgUi="bg-white"
color="black"
>
<view class="goods-form"> <view class="goods-form">
<uni-forms ref="formRef" v-model="formData" :rules="rules" label-position="top" label-width="160"> <uni-forms ref="formRef" v-model="formData" :rules="rules" label-position="top" label-width="160">
<uni-forms-item label="商品封面图" name="picUrl" required> <uni-forms-item label="商品封面图" name="picUrl" required>
<p-uploader <p-uploader v-model:url="formData.picUrl" fileMediatype="image" limit="1" mode="grid"
v-model:url="formData.picUrl" :imageStyles="{ width: '168rpx', height: '168rpx' }" />
fileMediatype="image"
limit="1"
mode="grid"
:imageStyles="{ width: '168rpx', height: '168rpx' }"
/>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="商品轮播图" name="sliderPicUrls" required> <uni-forms-item label="商品轮播图" name="sliderPicUrls" required>
<p-uploader <p-uploader v-model:url="formData.sliderPicUrls" fileMediatype="image" limit="6" mode="grid"
v-model:url="formData.sliderPicUrls" :imageStyles="{ width: '168rpx', height: '168rpx' }" />
fileMediatype="image"
limit="6"
mode="grid"
:imageStyles="{ width: '168rpx', height: '168rpx' }"
/>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="商品名称" name="name" required> <uni-forms-item label="商品名称" name="name" required>
<uni-easyinput type="text" trim="all" v-model="formData.name" placeholder="请输入商品名称" /> <uni-easyinput type="text" trim="all" v-model="formData.name" placeholder="请输入商品名称" />
</uni-forms-item> </uni-forms-item>
<uni-forms-item <uni-forms-item label="商品分类" @tap="openPicker('category', 'multiple')" name="categoryId" label-position="left"
label="商品分类" required>
@tap="openPicker('category', 'multiple')" <uni-easyinput type="text" v-model="formData.categoryText" :styles="selfStyles"
name="categoryId" placeholderStyle="color:#8a8a8a" :clearable="false" :inputBorder="false" placeholder="请选择商品分类" disabled>
label-position="left"
required
>
<uni-easyinput
type="text"
v-model="formData.categoryText"
:styles="selfStyles"
placeholderStyle="color:#8a8a8a"
:clearable="false"
:inputBorder="false"
placeholder="请选择商品分类"
disabled
>
<template v-slot:right> <template v-slot:right>
<uni-icons type="right" /> <uni-icons type="right" />
</template> </template>
</uni-easyinput> </uni-easyinput>
</uni-forms-item> </uni-forms-item>
<uni-forms-item <uni-forms-item label="商品品牌" name="brandId" label-position="left" required @tap="openPicker('brand', 'single')">
label="商品品牌" <uni-easyinput type="text" v-model="formData.brandText" :styles="selfStyles" placeholderStyle="color:#8a8a8a"
name="brandId" :clearable="false" :inputBorder="false" placeholder="请选择商品品牌" disabled>
label-position="left"
required
@tap="openPicker('brand', 'single')"
>
<uni-easyinput
type="text"
v-model="formData.brandText"
:styles="selfStyles"
placeholderStyle="color:#8a8a8a"
:clearable="false"
:inputBorder="false"
placeholder="请选择商品品牌"
disabled
>
<template v-slot:right> <template v-slot:right>
<uni-icons type="right" /> <uni-icons type="right" />
</template> </template>
@ -84,31 +40,12 @@
<uni-easyinput type="text" v-model="formData.keyword" placeholder="请输入商品关键词" /> <uni-easyinput type="text" v-model="formData.keyword" placeholder="请输入商品关键词" />
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="商品简介" name="introduction" required> <uni-forms-item label="商品简介" name="introduction" required>
<uni-easyinput <uni-easyinput type="textarea" trim="all" autoHeight v-model="formData.introduction" placeholder="请输入商品简介" />
type="textarea"
trim="all"
autoHeight
v-model="formData.introduction"
placeholder="请输入商品简介"
/>
</uni-forms-item> </uni-forms-item>
<uni-forms-item <uni-forms-item label="物流设置" @tap="openPicker('delivery', 'single')" name="deliveryTypes" label-position="left"
label="物流设置" required>
@tap="openPicker('delivery', 'single')" <uni-easyinput type="text" :clearable="false" :styles="selfStyles" placeholderStyle="color:#8a8a8a"
name="deliveryTypes" :inputBorder="false" v-model="formData.deliveryText" placeholder="请选择配送方式" disabled>
label-position="left"
required
>
<uni-easyinput
type="text"
:clearable="false"
:styles="selfStyles"
placeholderStyle="color:#8a8a8a"
:inputBorder="false"
v-model="formData.deliveryText"
placeholder="请选择配送方式"
disabled
>
<template v-slot:right> <template v-slot:right>
<uni-icons type="right" /> <uni-icons type="right" />
</template> </template>
@ -117,12 +54,7 @@
</uni-forms> </uni-forms>
</view> </view>
<p-picker <p-picker ref="pickerRef" :mode="pickerMode" :options-cols="optionsCols" @confirm="onRDPickerConfirm"></p-picker>
ref="pickerRef"
:mode="pickerMode"
:options-cols="optionsCols"
@confirm="onRDPickerConfirm"
></p-picker>
</pb-layout> </pb-layout>
</template> </template>
@ -289,8 +221,29 @@ function onRDPickerConfirm(e) {
} }
function clickSetProperty() { function clickSetProperty() {
//
let temp = formData.value.skus.map((item) => {
return item.properties.map((sitem) => ({
id: sitem.propertyId,
children: [sitem.valueId],
}));
})
.flat(1);
//
let result = temp.reduce((pre, cur) => {
let index = pre.findIndex((item) => item.id === cur.id);
if (index !== -1) {
pre[index].children.push(...new Set(cur.children));
} else {
pre.push(cur);
}
return pre;
}, []);
peach.$store('trade').$patch({ peach.$store('trade').$patch({
selectedProperty: formData.value.skus, selectedProperty: result,
goodsInfo: formData.value, goodsInfo: formData.value,
}) })
peach.$router.go('/pages/product/sku') peach.$router.go('/pages/product/sku')
@ -406,6 +359,7 @@ onLoad(async (options) => {
text-align: right; text-align: right;
} }
} }
.btn-group { .btn-group {
height: 100%; height: 100%;
display: flex; display: flex;