feat(商品属性): 多 sku
This commit is contained in:
parent
b10f8458af
commit
b999d59bfc
|
@ -1,42 +1,20 @@
|
|||
<template>
|
||||
<pb-layout
|
||||
class="product-list"
|
||||
title="产品"
|
||||
navbar="normal"
|
||||
tabbar="/pages/index/product"
|
||||
:bgStyle="bgStyle"
|
||||
opacityBgUi="bg-white"
|
||||
color="black"
|
||||
>
|
||||
<pb-layout class="product-list" title="产品" navbar="normal" tabbar="/pages/index/product" :bgStyle="bgStyle"
|
||||
opacityBgUi="bg-white" color="black">
|
||||
<view v-if="state.pagination.total > 0" class="goods-list ss-m-t-20">
|
||||
<view class="ss-p-l-20 ss-p-r-20 ss-m-b-20" v-for="item in state.pagination.list" :key="item.id">
|
||||
<p-goods-column
|
||||
size="lg"
|
||||
:data="item"
|
||||
:topRadius="10"
|
||||
:bottomRadius="10"
|
||||
@click="peach.$router.go('/pages/product/manageGoods', { id: item.id, mark: 'detail' })"
|
||||
/>
|
||||
<p-goods-column size="lg" :data="item" :topRadius="10" :bottomRadius="10"
|
||||
@click="peach.$router.go('/pages/product/manageGoods', { id: item.id, mark: 'detail' })" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uni-load-more
|
||||
v-if="state.pagination.total > 0"
|
||||
:status="state.loadStatus"
|
||||
:content-text="{
|
||||
<uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
|
||||
contentdown: '上拉加载更多',
|
||||
}"
|
||||
@click="loadMore"
|
||||
/>
|
||||
}" @click="loadMore" />
|
||||
|
||||
<view class="_icon-add-round add-product" @click="addGoods"></view>
|
||||
|
||||
<p-empty
|
||||
v-if="state.pagination.total === 0"
|
||||
icon="/static/soldout-empty.png"
|
||||
text="暂无产品"
|
||||
bgColor="transparent"
|
||||
/>
|
||||
<p-empty v-if="state.pagination.total === 0" icon="/static/soldout-empty.png" text="暂无产品" bgColor="transparent" />
|
||||
</pb-layout>
|
||||
</template>
|
||||
|
||||
|
@ -89,7 +67,9 @@ async function getList() {
|
|||
}
|
||||
|
||||
function addGoods() {
|
||||
peach.$router.go('/pages/product/manageGoods')
|
||||
peach.$router.go('/pages/product/manageGoods', {
|
||||
title: '添加商品'
|
||||
})
|
||||
}
|
||||
|
||||
function loadMore() {
|
||||
|
|
|
@ -11,29 +11,31 @@
|
|||
</template>
|
||||
|
||||
<uni-forms-item label="商品封面图" name="picUrl" label-position="top">
|
||||
<p-uploader v-model:url="formData.picUrl" fileMediatype="image" limit="1" mode="grid"
|
||||
<p-uploader v-model:url="formData.picUrl" :readonly="!canEdit" fileMediatype="image" limit="1" mode="grid"
|
||||
:imageStyles="{ width: '168rpx', height: '168rpx' }" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="商品条码" name="barCode">
|
||||
<uni-easyinput type="text" trim="all" v-model="formData.barCode" placeholder="请输入商品条码" />
|
||||
<uni-easyinput type="text" trim="all" v-model="formData.barCode" :disabled="!canEdit" placeholder="请输入商品条码" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="销售价" name="price">
|
||||
<uni-easyinput type="number" trim="all" v-model="formData.price" placeholder="请输入商品销售价" />
|
||||
<uni-easyinput type="number" trim="all" v-model="formData.price" :disabled="!canEdit" placeholder="请输入商品销售价" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="市场价" name="marketPrice">
|
||||
<uni-easyinput type="number" trim="all" v-model="formData.marketPrice" placeholder="请输入商品销售价" />
|
||||
<uni-easyinput type="number" trim="all" v-model="formData.marketPrice" :disabled="!canEdit"
|
||||
placeholder="请输入商品销售价" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="成本价" name="costPrice">
|
||||
<uni-easyinput type="number" trim="all" v-model="formData.costPrice" placeholder="请输入商品销售价" />
|
||||
<uni-easyinput type="number" trim="all" v-model="formData.costPrice" :disabled="!canEdit"
|
||||
placeholder="请输入商品销售价" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="库存" name="stock">
|
||||
<uni-easyinput type="number" trim="all" v-model="formData.stock" placeholder="请输入商品库存" />
|
||||
<uni-easyinput type="number" trim="all" v-model="formData.stock" :disabled="!canEdit" placeholder="请输入商品库存" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="重量(kg)" name="weight">
|
||||
<uni-easyinput type="number" trim="all" v-model="formData.weight" placeholder="请输入商品重量" />
|
||||
<uni-easyinput type="number" trim="all" v-model="formData.weight" :disabled="!canEdit" placeholder="请输入商品重量" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="体积(m³)" name="volume">
|
||||
<uni-easyinput type="number" trim="all" v-model="formData.volume" placeholder="请输入商品体积" />
|
||||
<uni-easyinput type="number" trim="all" v-model="formData.volume" :disabled="!canEdit" placeholder="请输入商品体积" />
|
||||
</uni-forms-item>
|
||||
</uni-forms>
|
||||
</div>
|
||||
|
@ -42,6 +44,7 @@
|
|||
<script setup>
|
||||
import { ref, watch, computed, defineProps } from 'vue'
|
||||
import peach from '@/peach'
|
||||
import { canEdit } from '../js/sku';
|
||||
const props = defineProps({
|
||||
skus: {
|
||||
type: Array,
|
||||
|
@ -53,6 +56,11 @@ const specType = computed(() => peach.$store("trade").goodsInfo.specType);
|
|||
|
||||
watch(() => props.skus, (newVal) => {
|
||||
console.log(newVal)
|
||||
// 如果是单规格,取 sku 第一条数据
|
||||
if (!specType.value) {
|
||||
formData.value = newVal[0] ?? {}
|
||||
return
|
||||
}
|
||||
formData.value = newVal ?? {}
|
||||
}, { immediate: true })
|
||||
|
||||
|
|
|
@ -9,12 +9,8 @@
|
|||
<view class="property-value ss-flex ss-gap-40">
|
||||
<view class="property-value-text">规格值</view>
|
||||
<view class="property-value-value ss-flex ss-gap-10">
|
||||
<view
|
||||
v-for="sitem in item.propertyValues"
|
||||
@tap="chooseProperty(sitem)"
|
||||
:class="['item', sitem.checked ? 'active' : '']"
|
||||
>{{ sitem.name }}</view
|
||||
>
|
||||
<view v-for="sitem in item.propertyValues" @tap="chooseProperty(sitem)"
|
||||
:class="['item', sitem.checked ? 'active' : '']">{{ sitem.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
@ -24,7 +20,7 @@
|
|||
|
||||
<script setup>
|
||||
import { defineProps, defineEmits, ref, computed } from 'vue'
|
||||
import { goodsPropertyList } from '../js/sku'
|
||||
import { goodsPropertyList, canEdit } from '../js/sku'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
|
@ -40,8 +36,10 @@ const props = defineProps({
|
|||
const emit = defineEmits(['changeSubProperty'])
|
||||
|
||||
function chooseProperty(item) {
|
||||
if (canEdit.value) {
|
||||
item.checked = !item.checked
|
||||
emit('changeSubProperty')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,82 +1,96 @@
|
|||
import { ref, computed } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import peach from '@/peach'
|
||||
import GoodsApi from '@/peach/api/trade/goods'
|
||||
import { SPEC_TYPE } from './config'
|
||||
import { ref, computed } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import peach from "@/peach";
|
||||
import GoodsApi from "@/peach/api/trade/goods";
|
||||
import { SPEC_TYPE } from "./config";
|
||||
|
||||
const pickerRef = ref(null)
|
||||
const pickerRef = ref(null);
|
||||
|
||||
// 多属性商品 sku 列表
|
||||
const skus = ref([])
|
||||
const skus = ref([]);
|
||||
|
||||
const propertyList = ref([])
|
||||
const propertyList = ref([]);
|
||||
|
||||
const goodsPropertyList = ref([])
|
||||
const goodsPropertyList = ref([]);
|
||||
|
||||
const propertyListRef = ref(null)
|
||||
const propertyListRef = ref(null);
|
||||
|
||||
const canEdit = computed(() => peach.$store("trade").canEdit);
|
||||
|
||||
const formData = ref({
|
||||
specType: true,
|
||||
specText: SPEC_TYPE[0].label,
|
||||
})
|
||||
});
|
||||
|
||||
async function showPropertyList() {
|
||||
await getGoodsProperty()
|
||||
propertyListRef.value.onOpen()
|
||||
await getGoodsProperty();
|
||||
propertyListRef.value.onOpen();
|
||||
}
|
||||
|
||||
function onRDPickerConfirm(e) {
|
||||
peach.$store('trade').specType = SPEC_TYPE[e.value[0]].value
|
||||
formData.value.specText = SPEC_TYPE[e.value[0]].label
|
||||
formData.value.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.specType = SPEC_TYPE[e.value[0]].value;
|
||||
}
|
||||
|
||||
function pickerProperty() {
|
||||
let index = specType.value ? 1 : 0
|
||||
pickerRef.value.onOpen([index])
|
||||
if (canEdit.value) {
|
||||
let index = specType.value ? 1 : 0;
|
||||
pickerRef.value.onOpen([index]);
|
||||
}
|
||||
}
|
||||
|
||||
async function onPropertyConfirm(e) {
|
||||
await getGoodsProperty()
|
||||
console.log(e)
|
||||
await getGoodsProperty();
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
function onConfirm() {
|
||||
console.log(skus.value);
|
||||
}
|
||||
|
||||
async function getGoodsProperty() {
|
||||
let { data } = await GoodsApi.getHistoryProperty()
|
||||
let { data } = await GoodsApi.getHistoryProperty();
|
||||
|
||||
// 把 propertyList 中 id 相同的属性合并,并去重
|
||||
propertyList.value = peach.$store('trade').selectedProperty
|
||||
propertyList.value = peach.$store("trade").selectedProperty;
|
||||
|
||||
console.log(propertyList.value)
|
||||
console.log(propertyList.value);
|
||||
|
||||
// 根据已经选择数据,设置默认选中
|
||||
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) {
|
||||
item.propertyValues.forEach((child) => {
|
||||
let childResult = propertyParent?.children.some((schild) => schild === child.id)
|
||||
child.checked = childResult ? true : false
|
||||
})
|
||||
let childResult = propertyParent?.children.some(
|
||||
(schild) => schild === child.id
|
||||
);
|
||||
child.checked = childResult ? true : false;
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
goodsPropertyList.value = data
|
||||
console.log(goodsPropertyList.value)
|
||||
goodsPropertyList.value = data;
|
||||
console.log(goodsPropertyList.value);
|
||||
}
|
||||
|
||||
function changeSubProperty() {
|
||||
// 修改子属性状态,需要同步更新 skus 的显示
|
||||
console.log(goodsPropertyList.value)
|
||||
console.log(goodsPropertyList.value);
|
||||
// 过滤父属性 checked 选项,深拷贝避免后面循环改变元数据内容
|
||||
let temp = JSON.parse(JSON.stringify(goodsPropertyList.value.filter((item) => item.checked)))
|
||||
let temp = JSON.parse(
|
||||
JSON.stringify(goodsPropertyList.value.filter((item) => item.checked))
|
||||
);
|
||||
temp.forEach((item) => {
|
||||
item.propertyValues = item.propertyValues.filter((child) => child.checked)
|
||||
})
|
||||
item.propertyValues = item.propertyValues.filter((child) => child.checked);
|
||||
});
|
||||
|
||||
let result = temp.map((item) => {
|
||||
return item.propertyValues.map((child) => ({
|
||||
|
@ -84,15 +98,15 @@ function changeSubProperty() {
|
|||
propertyName: item.name,
|
||||
valueId: child.id,
|
||||
valueName: child.name,
|
||||
}))
|
||||
})
|
||||
}));
|
||||
});
|
||||
|
||||
let tempSkus = []
|
||||
let tempSkus = [];
|
||||
|
||||
for (let item of reduceArr(result)) {
|
||||
let obj = {
|
||||
picUrl: '',
|
||||
barCode: '',
|
||||
picUrl: "",
|
||||
barCode: "",
|
||||
price: 0,
|
||||
marketPrice: 0,
|
||||
costPrice: 0,
|
||||
|
@ -100,58 +114,60 @@ function changeSubProperty() {
|
|||
weight: 0,
|
||||
volume: 0,
|
||||
properties: item,
|
||||
}
|
||||
tempSkus.push(obj)
|
||||
};
|
||||
tempSkus.push(obj);
|
||||
}
|
||||
|
||||
skus.value = tempSkus
|
||||
skus.value = tempSkus;
|
||||
}
|
||||
|
||||
function reduceArr(arr) {
|
||||
return arr.reduce((acc, cur) => {
|
||||
let tempAcc = []
|
||||
let tempAcc = [];
|
||||
|
||||
if (acc.length < 1) {
|
||||
cur.forEach((item, index) => {
|
||||
if (tempAcc[index]) {
|
||||
tempAcc[index].push(item)
|
||||
tempAcc[index].push(item);
|
||||
} else {
|
||||
tempAcc[index] = [item]
|
||||
tempAcc[index] = [item];
|
||||
}
|
||||
})
|
||||
});
|
||||
} else {
|
||||
acc.forEach((item, index) => {
|
||||
cur.forEach((sitem, sindex) => {
|
||||
tempAcc.push([...item, sitem])
|
||||
})
|
||||
})
|
||||
tempAcc.push([...item, sitem]);
|
||||
});
|
||||
});
|
||||
|
||||
if (cur.length < 1) {
|
||||
tempAcc = acc
|
||||
tempAcc = acc;
|
||||
}
|
||||
}
|
||||
return tempAcc
|
||||
}, [])
|
||||
return tempAcc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
const specType = computed(() => peach.$store('trade').goodsInfo.specType)
|
||||
const specType = computed(() => peach.$store("trade").goodsInfo.specType);
|
||||
|
||||
function initial() {
|
||||
onLoad(() => {
|
||||
formData.value.specType = specType.value ? true : false
|
||||
formData.value.specText = SPEC_TYPE[specType.value ? 1 : 0].label
|
||||
skus.value = peach.$store('trade').skus
|
||||
formData.value.specType = specType.value ? true : false;
|
||||
formData.value.specText = SPEC_TYPE[specType.value ? 1 : 0].label;
|
||||
skus.value = peach.$store("trade").skus;
|
||||
if (specType.value) {
|
||||
getGoodsProperty()
|
||||
getGoodsProperty();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
initial,
|
||||
canEdit,
|
||||
skus,
|
||||
pickerRef,
|
||||
pickerProperty,
|
||||
onConfirm,
|
||||
propertyListRef,
|
||||
formData,
|
||||
onRDPickerConfirm,
|
||||
|
@ -160,4 +176,4 @@ export {
|
|||
showPropertyList,
|
||||
goodsPropertyList,
|
||||
changeSubProperty,
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
<template>
|
||||
<pb-layout class="manage-goods" title="发布商品" leftIcon="leftIcon" navbar="normal" :bgStyle="bgStyle"
|
||||
<pb-layout class="manage-goods" :title="goodsTitle" leftIcon="leftIcon" navbar="normal" :bgStyle="bgStyle"
|
||||
opacityBgUi="bg-white" color="black">
|
||||
<view class="goods-form">
|
||||
<uni-forms ref="formRef" v-model="formData" :rules="rules" label-position="top" label-width="160">
|
||||
<uni-forms-item label="商品封面图" name="picUrl" required>
|
||||
<p-uploader v-model:url="formData.picUrl" fileMediatype="image" limit="1" mode="grid"
|
||||
<p-uploader v-model:url="formData.picUrl" :readonly="!canEdit" fileMediatype="image" limit="1" mode="grid"
|
||||
:imageStyles="{ width: '168rpx', height: '168rpx' }" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="商品轮播图" name="sliderPicUrls" required>
|
||||
<p-uploader v-model:url="formData.sliderPicUrls" fileMediatype="image" limit="6" mode="grid"
|
||||
:imageStyles="{ width: '168rpx', height: '168rpx' }" />
|
||||
<p-uploader v-model:url="formData.sliderPicUrls" :readonly="!canEdit" fileMediatype="image" limit="6"
|
||||
mode="grid" :imageStyles="{ width: '168rpx', height: '168rpx' }" />
|
||||
</uni-forms-item>
|
||||
<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" :disabled="!canEdit" placeholder="请输入商品名称" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="商品分类" @tap="openPicker('category', 'multiple')" name="categoryId" label-position="left"
|
||||
required>
|
||||
<uni-easyinput type="text" v-model="formData.categoryText" :styles="selfStyles"
|
||||
<uni-easyinput type="text" v-model="formData.categoryText" :disabled="!canEdit" :styles="selfStyles"
|
||||
placeholderStyle="color:#8a8a8a" :clearable="false" :inputBorder="false" placeholder="请选择商品分类" disabled>
|
||||
<template v-slot:right>
|
||||
<uni-icons type="right" />
|
||||
|
@ -24,8 +24,8 @@
|
|||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="商品品牌" name="brandId" 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>
|
||||
<uni-easyinput type="text" v-model="formData.brandText" :disabled="!canEdit" :styles="selfStyles"
|
||||
placeholderStyle="color:#8a8a8a" :clearable="false" :inputBorder="false" placeholder="请选择商品品牌" disabled>
|
||||
<template v-slot:right>
|
||||
<uni-icons type="right" />
|
||||
</template>
|
||||
|
@ -37,21 +37,25 @@
|
|||
</view>
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="商品关键词" name="keyword" required>
|
||||
<uni-easyinput type="text" v-model="formData.keyword" placeholder="请输入商品关键词" />
|
||||
<uni-easyinput type="text" v-model="formData.keyword" :disabled="!canEdit" placeholder="请输入商品关键词" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="商品简介" name="introduction" required>
|
||||
<uni-easyinput type="textarea" trim="all" autoHeight v-model="formData.introduction" placeholder="请输入商品简介" />
|
||||
<uni-easyinput type="textarea" :disabled="!canEdit" trim="all" autoHeight v-model="formData.introduction"
|
||||
placeholder="请输入商品简介" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="物流设置" @tap="openPicker('delivery', 'single')" name="deliveryTypes" label-position="left"
|
||||
required>
|
||||
<uni-easyinput type="text" :clearable="false" :styles="selfStyles" placeholderStyle="color:#8a8a8a"
|
||||
:inputBorder="false" v-model="formData.deliveryText" placeholder="请选择配送方式" disabled>
|
||||
:inputBorder="false" v-model="formData.deliveryText" :disabled="!canEdit" placeholder="请选择配送方式" disabled>
|
||||
<template v-slot:right>
|
||||
<uni-icons type="right" />
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
</uni-forms>
|
||||
<view @tap="onSubmit" v-if="canEdit">
|
||||
<button class="ss-reset-button submit-button ui-Shadow-Main">提交</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<p-picker ref="pickerRef" :mode="pickerMode" :options-cols="optionsCols" @confirm="onRDPickerConfirm"></p-picker>
|
||||
|
@ -59,7 +63,7 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import peach from '@/peach'
|
||||
import { handleTree } from '@/peach/utils'
|
||||
|
@ -183,11 +187,14 @@ const rules = {
|
|||
const formRef = ref(null)
|
||||
const pickerMode = ref('single')
|
||||
const popMark = ref('')
|
||||
const goodsTitle = ref('')
|
||||
const categoryList = ref([])
|
||||
const brandList = ref([])
|
||||
const optionsCols = ref([])
|
||||
const canEdit = computed(() => peach.$store('trade').canEdit)
|
||||
|
||||
function openPicker(mark, mode) {
|
||||
if (!canEdit.value) return
|
||||
pickerMode.value = mode
|
||||
popMark.value = mark
|
||||
if (mark === 'delivery') {
|
||||
|
@ -290,12 +297,12 @@ function onSubmit() {
|
|||
.then(async (res) => {
|
||||
let tempObj = { ...res }
|
||||
|
||||
if (formData.value.id) {
|
||||
tempObj.id = formData.value.id
|
||||
await GoodsApi.editProduct(tempObj)
|
||||
} else {
|
||||
await GoodsApi.addProduct(tempObj)
|
||||
}
|
||||
// if (formData.value.id) {
|
||||
// tempObj.id = formData.value.id
|
||||
// await GoodsApi.editProduct(tempObj)
|
||||
// } else {
|
||||
// await GoodsApi.addProduct(tempObj)
|
||||
// }
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('err', err)
|
||||
|
@ -317,13 +324,28 @@ async function getBrandList() {
|
|||
onLoad(async (options) => {
|
||||
await getCategoryList()
|
||||
await getBrandList()
|
||||
|
||||
goodsTitle.value = options.title
|
||||
|
||||
if (options.id) {
|
||||
getProduct(options.id)
|
||||
peach.$store('trade').detailTag = options.mark
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@mixin ss-set-property {
|
||||
width: 80px;
|
||||
height: 60rpx;
|
||||
line-height: normal;
|
||||
background: var(--ui-BG-Main);
|
||||
border-radius: 28rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.manage-goods {
|
||||
.goods-form {
|
||||
margin: 40rpx;
|
||||
|
@ -355,10 +377,18 @@ onLoad(async (options) => {
|
|||
}
|
||||
}
|
||||
|
||||
.is-direction-left {
|
||||
|
||||
.is-disabled {
|
||||
color: #333333;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.uni-forms-item__error {
|
||||
left: -160rpx !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
|
@ -370,16 +400,17 @@ onLoad(async (options) => {
|
|||
border-radius: 0 10px 10px 0;
|
||||
|
||||
.ss-set-property {
|
||||
width: 80px;
|
||||
height: 60rpx;
|
||||
line-height: normal;
|
||||
background: var(--ui-BG-Main);
|
||||
border-radius: 28rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
@include ss-set-property
|
||||
}
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,26 +1,11 @@
|
|||
<template>
|
||||
<pb-layout
|
||||
class="goods-property"
|
||||
title="商品属性"
|
||||
leftIcon="leftIcon"
|
||||
navbar="normal"
|
||||
:bgStyle="bgStyle"
|
||||
opacityBgUi="bg-white"
|
||||
color="black"
|
||||
>
|
||||
<pb-layout class="goods-property" title="商品属性" leftIcon="leftIcon" navbar="normal" :bgStyle="bgStyle"
|
||||
opacityBgUi="bg-white" color="black">
|
||||
<view class="property">
|
||||
<uni-forms ref="formRef" v-model="formData" :rules="rules" label-position="top" label-width="160">
|
||||
<uni-forms-item label="商品规格" @tap="pickerProperty" name="specType" label-position="left" required>
|
||||
<uni-easyinput
|
||||
type="text"
|
||||
:clearable="false"
|
||||
:styles="selfStyles"
|
||||
placeholderStyle="color:#8a8a8a"
|
||||
:inputBorder="false"
|
||||
v-model="formData.specText"
|
||||
placeholder="请选择商品规格"
|
||||
disabled
|
||||
>
|
||||
<uni-easyinput type="text" :clearable="false" :styles="selfStyles" placeholderStyle="color:#8a8a8a"
|
||||
:inputBorder="false" v-model="formData.specText" placeholder="请选择商品规格" disabled>
|
||||
<template v-slot:right>
|
||||
<uni-icons type="right" />
|
||||
</template>
|
||||
|
@ -29,28 +14,31 @@
|
|||
</uni-forms>
|
||||
</view>
|
||||
<template v-if="formData.specType">
|
||||
<button class="ss-reset-button add-property" @tap="showPropertyList">+添加规格</button>
|
||||
<property-detail
|
||||
v-if="propertyList.length > 0"
|
||||
v-model="propertyList"
|
||||
:goodsPropertyList="goodsPropertyList"
|
||||
@changeSubProperty="changeSubProperty"
|
||||
></property-detail>
|
||||
<!-- 添加商品 -->
|
||||
<button v-if="canEdit" class="ss-reset-button add-property" @tap="showPropertyList">+添加规格</button>
|
||||
<!-- 商品属性展示 -->
|
||||
<property-detail v-if="propertyList.length > 0" v-model="propertyList" :goodsPropertyList="goodsPropertyList"
|
||||
@changeSubProperty="changeSubProperty"></property-detail>
|
||||
<!-- 多规格商品 -->
|
||||
<mutiple-sku :skus="skus"></mutiple-sku>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<!-- 单规格商品 -->
|
||||
<SkuItem :skus="skus" />
|
||||
</template>
|
||||
|
||||
<!-- 确认选择 -->
|
||||
<view style="padding: 0 40rpx 40rpx;" @tap="onConfirm" v-if="canEdit">
|
||||
<button class="ss-reset-button submit-button ui-Shadow-Main">提交</button>
|
||||
</view>
|
||||
|
||||
<!-- 商品规格 -->
|
||||
<p-picker ref="pickerRef" mode="single" :options-cols="SPEC_TYPE" @confirm="onRDPickerConfirm"></p-picker>
|
||||
|
||||
<PropertyList
|
||||
ref="propertyListRef"
|
||||
v-model="propertyList"
|
||||
:goodsPropertyList="goodsPropertyList"
|
||||
@confirm="onPropertyConfirm"
|
||||
/>
|
||||
<!-- 商品属性列表 -->
|
||||
<PropertyList ref="propertyListRef" v-model="propertyList" :goodsPropertyList="goodsPropertyList"
|
||||
@confirm="onPropertyConfirm" />
|
||||
</pb-layout>
|
||||
</template>
|
||||
|
||||
|
@ -62,6 +50,7 @@ import PropertyDetail from './components/propertyDetail'
|
|||
import { SPEC_TYPE } from './js/config'
|
||||
import {
|
||||
initial,
|
||||
canEdit,
|
||||
pickerRef,
|
||||
propertyListRef,
|
||||
onRDPickerConfirm,
|
||||
|
@ -130,5 +119,13 @@ initial()
|
|||
border-radius: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,39 +4,27 @@
|
|||
<image class="lg-img-box" :src="peach.$url.cdn(data.image || data.picUrl)" mode="aspectFill"></image>
|
||||
<view class="lg-goods-content ss-flex-1 ss-flex-col ss-row-between ss-p-b-10 ss-p-t-20">
|
||||
<view>
|
||||
<view
|
||||
v-if="goodsFields.title?.show || goodsFields.name?.show"
|
||||
class="lg-goods-title ss-line-2"
|
||||
:style="[{ color: titleColor }]"
|
||||
>
|
||||
<view v-if="goodsFields.title?.show || goodsFields.name?.show" class="lg-goods-title ss-line-2"
|
||||
:style="[{ color: titleColor }]">
|
||||
{{ data.title || data.name }}
|
||||
</view>
|
||||
<view
|
||||
v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
|
||||
<view v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
|
||||
class="lg-goods-subtitle ss-m-t-10 ss-line-1"
|
||||
:style="[{ color: subTitleColor, background: subTitleBackground }]"
|
||||
>
|
||||
:style="[{ color: subTitleColor, background: subTitleBackground }]">
|
||||
{{ data.subtitle || data.introduction }}
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<view class="ss-flex ss-col-bottom ss-m-t-10">
|
||||
<view
|
||||
v-if="goodsFields.price?.show"
|
||||
class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS"
|
||||
:style="[{ color: goodsFields.price.color }]"
|
||||
>
|
||||
<view v-if="goodsFields.price?.show" class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS"
|
||||
:style="[{ color: goodsFields.price.color }]">
|
||||
<text class="ss-font-24">{{ priceUnit }}</text>
|
||||
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
||||
</view>
|
||||
<view
|
||||
v-if="
|
||||
<view v-if="
|
||||
(goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
|
||||
(data.original_price > 0 || data.marketPrice > 0)
|
||||
"
|
||||
class="goods-origin-price ss-flex ss-col-bottom font-OPPOSANS"
|
||||
:style="[{ color: originPriceColor }]"
|
||||
>
|
||||
" class="goods-origin-price ss-flex ss-col-bottom font-OPPOSANS" :style="[{ color: originPriceColor }]">
|
||||
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
|
||||
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
|
||||
</view>
|
||||
|
@ -150,10 +138,12 @@ const salesAndStock = computed(() => {
|
|||
})
|
||||
|
||||
function clickGoods(mark) {
|
||||
|
||||
if (mark === 'detail' || mark === 'edit') {
|
||||
peach.$router.go('/pages/product/manageGoods', {
|
||||
id: props.data.id,
|
||||
mark: mark,
|
||||
title: mark === 'detail' ? '商品详情' : '编辑商品'
|
||||
})
|
||||
} else if (mark === 'del') {
|
||||
uni.showModal({
|
||||
|
@ -213,6 +203,7 @@ function clickGoods(mark) {
|
|||
color: #c4c4c4;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
width: 120rpx;
|
||||
height: 50rpx;
|
||||
|
@ -221,6 +212,7 @@ function clickGoods(mark) {
|
|||
font-size: 24rpx;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.btn-del {
|
||||
color: var(--ui-BG-Main);
|
||||
background-color: var(--ui-BG-Main-opacity-1);
|
||||
|
|
|
@ -7,30 +7,18 @@
|
|||
<view class="button-link" @click="onConfirmPopup">确定</view>
|
||||
</view>
|
||||
<view class="popup-content">
|
||||
<picker-view
|
||||
:indicator-style="indicatorStyle"
|
||||
:value="pickerViewValue"
|
||||
@change="bindChange"
|
||||
class="picker-view"
|
||||
>
|
||||
<picker-view :indicator-style="indicatorStyle" :value="pickerViewValue" @change="bindChange"
|
||||
class="picker-view">
|
||||
<template v-if="mode === 'single'">
|
||||
<picker-view-column>
|
||||
<view
|
||||
class="item"
|
||||
v-for="(item, index) in props.optionsCols"
|
||||
:key="`${item.value}-${index}`"
|
||||
>{{ item.label }}</view
|
||||
>
|
||||
<view class="item" v-for="(item, index) in props.optionsCols" :key="`${item.value}-${index}`">{{
|
||||
item.label ?? item.name }}</view>
|
||||
</picker-view-column>
|
||||
</template>
|
||||
<template v-else>
|
||||
<picker-view-column>
|
||||
<view
|
||||
class="item"
|
||||
v-for="(item, index) in props.optionsCols"
|
||||
:key="`${item.value}-${index}`"
|
||||
>{{ item.name }}</view
|
||||
>
|
||||
<view class="item" v-for="(item, index) in props.optionsCols" :key="`${item.value}-${index}`">{{ item.name
|
||||
}}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="item" v-for="(item, index) in childrenList" :key="`${item.value}-${index}`">{{
|
||||
|
@ -139,24 +127,29 @@ defineExpose({
|
|||
|
||||
.popup-content {
|
||||
height: 500rpx;
|
||||
|
||||
.item {
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
line-height: 34px;
|
||||
}
|
||||
}
|
||||
|
||||
.picker-view {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.button-link {
|
||||
color: #1892ea;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.button-cancel {
|
||||
color: #888;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
@ -282,6 +282,7 @@ export default {
|
|||
return this.uploadFiles(files);
|
||||
},
|
||||
async setValue(newVal, oldVal) {
|
||||
|
||||
const newData = async (v) => {
|
||||
const reg = /cloud:\/\/([\w.]+\/?)\S*/;
|
||||
let url = '';
|
||||
|
@ -512,6 +513,7 @@ export default {
|
|||
* @param {Object} index
|
||||
*/
|
||||
delFile(index) {
|
||||
|
||||
this.$emit('delete', {
|
||||
tempFile: this.files[index],
|
||||
tempFilePath: this.files[index].url,
|
||||
|
@ -541,11 +543,13 @@ export default {
|
|||
setEmit() {
|
||||
let data = [];
|
||||
let updateUrl = [];
|
||||
// 单文件
|
||||
if (this.returnType === 'object') {
|
||||
data = this.backObject(this.files)[0];
|
||||
this.localValue = data ? data : null;
|
||||
updateUrl = data ? data.url : '';
|
||||
} else {
|
||||
// 多文件
|
||||
data = this.backObject(this.files);
|
||||
if (!this.localValue) {
|
||||
this.localValue = [];
|
||||
|
@ -568,6 +572,8 @@ export default {
|
|||
backObject(files) {
|
||||
let newFilesData = [];
|
||||
files.forEach((v) => {
|
||||
if (v.fileID) {
|
||||
|
||||
newFilesData.push({
|
||||
extname: v.extname,
|
||||
fileType: v.fileType,
|
||||
|
@ -578,6 +584,11 @@ export default {
|
|||
fileID: v.fileID,
|
||||
url: v.url,
|
||||
});
|
||||
} else {
|
||||
newFilesData.push({
|
||||
url: v
|
||||
})
|
||||
}
|
||||
});
|
||||
return newFilesData;
|
||||
},
|
||||
|
|
|
@ -69,6 +69,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
list() {
|
||||
|
||||
if (typeof this.filesList === 'string') {
|
||||
if (this.filesList) {
|
||||
return [this.filesList];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ref } from "vue";
|
||||
import { ref, computed } from "vue";
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
const useTradeStore = defineStore("trade", () => {
|
||||
|
@ -8,13 +8,21 @@ const useTradeStore = defineStore("trade", () => {
|
|||
// 商品信息
|
||||
const goodsInfo = ref(null);
|
||||
|
||||
// 详情标记
|
||||
const detailTag = ref("edit");
|
||||
|
||||
// 商品属性
|
||||
const skus = ref(null);
|
||||
|
||||
// 商品是否可编辑
|
||||
const canEdit = computed(() => (detailTag.value === "detail" ? false : true));
|
||||
|
||||
return {
|
||||
selectedProperty,
|
||||
goodsInfo,
|
||||
skus,
|
||||
canEdit,
|
||||
detailTag,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue