feat(商品属性): 多 sku
This commit is contained in:
parent
b10f8458af
commit
b999d59bfc
|
@ -1,43 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<pb-layout
|
<pb-layout class="product-list" title="产品" navbar="normal" tabbar="/pages/index/product" :bgStyle="bgStyle"
|
||||||
class="product-list"
|
opacityBgUi="bg-white" color="black">
|
||||||
title="产品"
|
<view v-if="state.pagination.total > 0" class="goods-list ss-m-t-20">
|
||||||
navbar="normal"
|
<view class="ss-p-l-20 ss-p-r-20 ss-m-b-20" v-for="item in state.pagination.list" :key="item.id">
|
||||||
tabbar="/pages/index/product"
|
<p-goods-column size="lg" :data="item" :topRadius="10" :bottomRadius="10"
|
||||||
:bgStyle="bgStyle"
|
@click="peach.$router.go('/pages/product/manageGoods', { id: item.id, mark: 'detail' })" />
|
||||||
opacityBgUi="bg-white"
|
</view>
|
||||||
color="black"
|
</view>
|
||||||
>
|
|
||||||
<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' })"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<uni-load-more
|
<uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
|
||||||
v-if="state.pagination.total > 0"
|
contentdown: '上拉加载更多',
|
||||||
:status="state.loadStatus"
|
}" @click="loadMore" />
|
||||||
:content-text="{
|
|
||||||
contentdown: '上拉加载更多',
|
|
||||||
}"
|
|
||||||
@click="loadMore"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<view class="_icon-add-round add-product" @click="addGoods"></view>
|
<view class="_icon-add-round add-product" @click="addGoods"></view>
|
||||||
|
|
||||||
<p-empty
|
<p-empty v-if="state.pagination.total === 0" icon="/static/soldout-empty.png" text="暂无产品" bgColor="transparent" />
|
||||||
v-if="state.pagination.total === 0"
|
</pb-layout>
|
||||||
icon="/static/soldout-empty.png"
|
|
||||||
text="暂无产品"
|
|
||||||
bgColor="transparent"
|
|
||||||
/>
|
|
||||||
</pb-layout>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
@ -49,165 +27,167 @@ import _ from 'lodash'
|
||||||
import { resetPagination } from '@/peach/utils'
|
import { resetPagination } from '@/peach/utils'
|
||||||
|
|
||||||
const bgStyle = {
|
const bgStyle = {
|
||||||
backgroundImage: '',
|
backgroundImage: '',
|
||||||
backgroundColor: 'var(--ui-BG-1)',
|
backgroundColor: 'var(--ui-BG-1)',
|
||||||
description: '',
|
description: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = ref({
|
const state = ref({
|
||||||
pagination: {
|
pagination: {
|
||||||
list: [],
|
list: [],
|
||||||
total: 0,
|
total: 0,
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 6,
|
pageSize: 6,
|
||||||
name: '',
|
name: '',
|
||||||
createTime: [],
|
createTime: [],
|
||||||
},
|
},
|
||||||
loadStatus: '',
|
loadStatus: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
function emptyList() {
|
function emptyList() {
|
||||||
resetPagination(state.value.pagination)
|
resetPagination(state.value.pagination)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSearch() {
|
function onSearch() {
|
||||||
emptyList()
|
emptyList()
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getList() {
|
async function getList() {
|
||||||
let { data } = await GoodApi.getProductList({
|
let { data } = await GoodApi.getProductList({
|
||||||
pageNo: state.value.pagination.pageNo,
|
pageNo: state.value.pagination.pageNo,
|
||||||
pageSize: state.value.pagination.pageSize,
|
pageSize: state.value.pagination.pageSize,
|
||||||
})
|
})
|
||||||
|
|
||||||
state.value.pagination.list = _.concat(state.value.pagination.list, data.list)
|
state.value.pagination.list = _.concat(state.value.pagination.list, data.list)
|
||||||
state.value.pagination.total = data.total
|
state.value.pagination.total = data.total
|
||||||
let currentPageTotal = state.value.pagination.length
|
let currentPageTotal = state.value.pagination.length
|
||||||
|
|
||||||
state.value.loadStatus = currentPageTotal < state.value.pagination.total ? 'more' : 'noMore'
|
state.value.loadStatus = currentPageTotal < state.value.pagination.total ? 'more' : 'noMore'
|
||||||
}
|
}
|
||||||
|
|
||||||
function addGoods() {
|
function addGoods() {
|
||||||
peach.$router.go('/pages/product/manageGoods')
|
peach.$router.go('/pages/product/manageGoods', {
|
||||||
|
title: '添加商品'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadMore() {
|
function loadMore() {
|
||||||
if (state.value.loadStatus === 'noMore') {
|
if (state.value.loadStatus === 'noMore') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
state.value.pagination.pageNo++
|
state.value.pagination.pageNo++
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoad(async (options) => {
|
onLoad(async (options) => {
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onReachBottom(() => {
|
onReachBottom(() => {
|
||||||
loadMore()
|
loadMore()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.product-list {
|
.product-list {
|
||||||
.add-product {
|
.add-product {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
color: var(--ui-BG-Main);
|
color: var(--ui-BG-Main);
|
||||||
bottom: 70px;
|
bottom: 70px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
font-size: 80rpx;
|
font-size: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-list-box {
|
||||||
|
width: 50%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.left-list {
|
||||||
|
margin-right: 10rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.goods-list-box {
|
.right-list {
|
||||||
width: 50%;
|
margin-left: 10rpx;
|
||||||
box-sizing: border-box;
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.left-list {
|
.goods-box {
|
||||||
margin-right: 10rpx;
|
&:nth-last-of-type(1) {
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 0 !important;
|
||||||
}
|
|
||||||
|
|
||||||
.right-list {
|
|
||||||
margin-left: 10rpx;
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.goods-box {
|
&:nth-child(2n) {
|
||||||
&:nth-last-of-type(1) {
|
margin-right: 0;
|
||||||
margin-bottom: 0 !important;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:nth-child(2n) {
|
.list-icon {
|
||||||
margin-right: 0;
|
width: 80rpx;
|
||||||
}
|
|
||||||
|
.sicon-goods-card {
|
||||||
|
font-size: 40rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-icon {
|
.sicon-goods-list {
|
||||||
width: 80rpx;
|
font-size: 40rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.sicon-goods-card {
|
.goods-card {
|
||||||
font-size: 40rpx;
|
margin-left: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sicon-goods-list {
|
.list-filter-tabs {
|
||||||
font-size: 40rpx;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter-list-box {
|
||||||
|
padding: 28rpx 52rpx;
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333333;
|
||||||
|
line-height: normal;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
|
||||||
|
&:nth-last-child(1) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.goods-card {
|
.filter-item-active {
|
||||||
margin-left: 20rpx;
|
color: var(--ui-BG-Main);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item {
|
||||||
|
height: 50px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 11;
|
||||||
|
|
||||||
|
.tab-title {
|
||||||
|
font-size: 30rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-filter-tabs {
|
.cur-tab-title {
|
||||||
background-color: #fff;
|
font-weight: $font-weight-bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-list-box {
|
.tab-line {
|
||||||
padding: 28rpx 52rpx;
|
width: 60rpx;
|
||||||
|
height: 6rpx;
|
||||||
.filter-item {
|
border-radius: 6rpx;
|
||||||
font-size: 28rpx;
|
position: absolute;
|
||||||
font-weight: 500;
|
left: 50%;
|
||||||
color: #333333;
|
transform: translateX(-50%);
|
||||||
line-height: normal;
|
bottom: 10rpx;
|
||||||
margin-bottom: 24rpx;
|
background-color: var(--ui-BG-Main);
|
||||||
|
z-index: 12;
|
||||||
&:nth-last-child(1) {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-item-active {
|
|
||||||
color: var(--ui-BG-Main);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-item {
|
|
||||||
height: 50px;
|
|
||||||
position: relative;
|
|
||||||
z-index: 11;
|
|
||||||
|
|
||||||
.tab-title {
|
|
||||||
font-size: 30rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cur-tab-title {
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-line {
|
|
||||||
width: 60rpx;
|
|
||||||
height: 6rpx;
|
|
||||||
border-radius: 6rpx;
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
bottom: 10rpx;
|
|
||||||
background-color: var(--ui-BG-Main);
|
|
||||||
z-index: 12;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -11,29 +11,31 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<uni-forms-item label="商品封面图" name="picUrl" label-position="top">
|
<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' }" />
|
:imageStyles="{ width: '168rpx', height: '168rpx' }" />
|
||||||
</uni-forms-item>
|
</uni-forms-item>
|
||||||
<uni-forms-item label="商品条码" name="barCode">
|
<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>
|
||||||
<uni-forms-item label="销售价" name="price">
|
<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>
|
||||||
<uni-forms-item label="市场价" name="marketPrice">
|
<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>
|
||||||
<uni-forms-item label="成本价" name="costPrice">
|
<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>
|
||||||
<uni-forms-item label="库存" name="stock">
|
<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>
|
||||||
<uni-forms-item label="重量(kg)" name="weight">
|
<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>
|
||||||
<uni-forms-item label="体积(m³)" name="volume">
|
<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-item>
|
||||||
</uni-forms>
|
</uni-forms>
|
||||||
</div>
|
</div>
|
||||||
|
@ -42,6 +44,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch, computed, defineProps } from 'vue'
|
import { ref, watch, computed, defineProps } from 'vue'
|
||||||
import peach from '@/peach'
|
import peach from '@/peach'
|
||||||
|
import { canEdit } from '../js/sku';
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
skus: {
|
skus: {
|
||||||
type: Array,
|
type: Array,
|
||||||
|
@ -53,6 +56,11 @@ const specType = computed(() => peach.$store("trade").goodsInfo.specType);
|
||||||
|
|
||||||
watch(() => props.skus, (newVal) => {
|
watch(() => props.skus, (newVal) => {
|
||||||
console.log(newVal)
|
console.log(newVal)
|
||||||
|
// 如果是单规格,取 sku 第一条数据
|
||||||
|
if (!specType.value) {
|
||||||
|
formData.value = newVal[0] ?? {}
|
||||||
|
return
|
||||||
|
}
|
||||||
formData.value = newVal ?? {}
|
formData.value = newVal ?? {}
|
||||||
}, { immediate: true })
|
}, { immediate: true })
|
||||||
|
|
||||||
|
|
|
@ -1,84 +1,82 @@
|
||||||
<template>
|
<template>
|
||||||
<view class="property-detail">
|
<view class="property-detail">
|
||||||
<template v-for="item in goodsPropertyList" :key="item.id">
|
<template v-for="item in goodsPropertyList" :key="item.id">
|
||||||
<view class="property-item ss-p-40 ss-gap-40" v-if="item.checked">
|
<view class="property-item ss-p-40 ss-gap-40" v-if="item.checked">
|
||||||
<view class="property-name ss-flex ss-gap-40 ss-m-b-20">
|
<view class="property-name ss-flex ss-gap-40 ss-m-b-20">
|
||||||
<view class="property-name-text">规格名</view>
|
<view class="property-name-text">规格名</view>
|
||||||
<view class="property-name-value">{{ item.name }}</view>
|
<view class="property-name-value">{{ item.name }}</view>
|
||||||
</view>
|
</view>
|
||||||
<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(sitem)"
|
||||||
v-for="sitem in item.propertyValues"
|
:class="['item', sitem.checked ? 'active' : '']">{{ sitem.name }}</view>
|
||||||
@tap="chooseProperty(sitem)"
|
</view>
|
||||||
:class="['item', sitem.checked ? 'active' : '']"
|
</view>
|
||||||
>{{ sitem.name }}</view
|
</view>
|
||||||
>
|
</template>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
</view>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineProps, defineEmits, ref, computed } from 'vue'
|
import { defineProps, defineEmits, ref, computed } from 'vue'
|
||||||
import { goodsPropertyList } from '../js/sku'
|
import { goodsPropertyList, canEdit } from '../js/sku'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
goodsPropertyList: {
|
goodsPropertyList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['changeSubProperty'])
|
const emit = defineEmits(['changeSubProperty'])
|
||||||
|
|
||||||
function chooseProperty(item) {
|
function chooseProperty(item) {
|
||||||
|
if (canEdit.value) {
|
||||||
item.checked = !item.checked
|
item.checked = !item.checked
|
||||||
emit('changeSubProperty')
|
emit('changeSubProperty')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.property-detail {
|
.property-detail {
|
||||||
.property-item {
|
.property-item {
|
||||||
margin: 0 40rpx 20rpx;
|
margin: 0 40rpx 20rpx;
|
||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
|
|
||||||
.property-name {
|
.property-name {
|
||||||
.property-name-text {
|
.property-name-text {
|
||||||
color: #606266;
|
color: #606266;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.property-value {
|
|
||||||
.property-value-text {
|
|
||||||
color: #606266;
|
|
||||||
}
|
|
||||||
|
|
||||||
.property-value-value {
|
|
||||||
.item {
|
|
||||||
text-align: center;
|
|
||||||
line-height: 60rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
padding: 0 10px;
|
|
||||||
border-radius: 10px;
|
|
||||||
background-color: var(--ui-BG-4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.active {
|
|
||||||
color: #fff;
|
|
||||||
background-color: var(--ui-BG-Main);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.property-value {
|
||||||
|
.property-value-text {
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-value-value {
|
||||||
|
.item {
|
||||||
|
text-align: center;
|
||||||
|
line-height: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: var(--ui-BG-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
color: #fff;
|
||||||
|
background-color: var(--ui-BG-Main);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,163 +1,179 @@
|
||||||
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);
|
||||||
|
|
||||||
// 多属性商品 sku 列表
|
// 多属性商品 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({
|
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.value ? 1 : 0
|
if (canEdit.value) {
|
||||||
pickerRef.value.onOpen([index])
|
let index = specType.value ? 1 : 0;
|
||||||
|
pickerRef.value.onOpen([index]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onPropertyConfirm(e) {
|
async function onPropertyConfirm(e) {
|
||||||
await getGoodsProperty()
|
await getGoodsProperty();
|
||||||
console.log(e)
|
console.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onConfirm() {
|
||||||
|
console.log(skus.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getGoodsProperty() {
|
async function getGoodsProperty() {
|
||||||
let { data } = await GoodsApi.getHistoryProperty()
|
let { data } = await GoodsApi.getHistoryProperty();
|
||||||
|
|
||||||
// 把 propertyList 中 id 相同的属性合并,并去重
|
// 把 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) => {
|
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 === child.id)
|
let childResult = propertyParent?.children.some(
|
||||||
child.checked = childResult ? true : false
|
(schild) => schild === child.id
|
||||||
})
|
);
|
||||||
}
|
child.checked = childResult ? true : false;
|
||||||
})
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
goodsPropertyList.value = data
|
goodsPropertyList.value = data;
|
||||||
console.log(goodsPropertyList.value)
|
console.log(goodsPropertyList.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeSubProperty() {
|
function changeSubProperty() {
|
||||||
// 修改子属性状态,需要同步更新 skus 的显示
|
// 修改子属性状态,需要同步更新 skus 的显示
|
||||||
console.log(goodsPropertyList.value)
|
console.log(goodsPropertyList.value);
|
||||||
// 过滤父属性 checked 选项,深拷贝避免后面循环改变元数据内容
|
// 过滤父属性 checked 选项,深拷贝避免后面循环改变元数据内容
|
||||||
let temp = JSON.parse(JSON.stringify(goodsPropertyList.value.filter((item) => item.checked)))
|
let temp = JSON.parse(
|
||||||
temp.forEach((item) => {
|
JSON.stringify(goodsPropertyList.value.filter((item) => item.checked))
|
||||||
item.propertyValues = item.propertyValues.filter((child) => child.checked)
|
);
|
||||||
})
|
temp.forEach((item) => {
|
||||||
|
item.propertyValues = item.propertyValues.filter((child) => child.checked);
|
||||||
|
});
|
||||||
|
|
||||||
let result = temp.map((item) => {
|
let result = temp.map((item) => {
|
||||||
return item.propertyValues.map((child) => ({
|
return item.propertyValues.map((child) => ({
|
||||||
propertyId: item.id,
|
propertyId: item.id,
|
||||||
propertyName: item.name,
|
propertyName: item.name,
|
||||||
valueId: child.id,
|
valueId: child.id,
|
||||||
valueName: child.name,
|
valueName: child.name,
|
||||||
}))
|
}));
|
||||||
})
|
});
|
||||||
|
|
||||||
let tempSkus = []
|
let tempSkus = [];
|
||||||
|
|
||||||
for (let item of reduceArr(result)) {
|
for (let item of reduceArr(result)) {
|
||||||
let obj = {
|
let obj = {
|
||||||
picUrl: '',
|
picUrl: "",
|
||||||
barCode: '',
|
barCode: "",
|
||||||
price: 0,
|
price: 0,
|
||||||
marketPrice: 0,
|
marketPrice: 0,
|
||||||
costPrice: 0,
|
costPrice: 0,
|
||||||
stock: 0,
|
stock: 0,
|
||||||
weight: 0,
|
weight: 0,
|
||||||
volume: 0,
|
volume: 0,
|
||||||
properties: item,
|
properties: item,
|
||||||
}
|
};
|
||||||
tempSkus.push(obj)
|
tempSkus.push(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
skus.value = tempSkus
|
skus.value = tempSkus;
|
||||||
}
|
}
|
||||||
|
|
||||||
function reduceArr(arr) {
|
function reduceArr(arr) {
|
||||||
return arr.reduce((acc, cur) => {
|
return arr.reduce((acc, cur) => {
|
||||||
let tempAcc = []
|
let tempAcc = [];
|
||||||
|
|
||||||
if (acc.length < 1) {
|
if (acc.length < 1) {
|
||||||
cur.forEach((item, index) => {
|
cur.forEach((item, index) => {
|
||||||
if (tempAcc[index]) {
|
if (tempAcc[index]) {
|
||||||
tempAcc[index].push(item)
|
tempAcc[index].push(item);
|
||||||
} else {
|
|
||||||
tempAcc[index] = [item]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
acc.forEach((item, index) => {
|
tempAcc[index] = [item];
|
||||||
cur.forEach((sitem, sindex) => {
|
|
||||||
tempAcc.push([...item, sitem])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
if (cur.length < 1) {
|
|
||||||
tempAcc = acc
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return tempAcc
|
});
|
||||||
}, [])
|
} else {
|
||||||
|
acc.forEach((item, index) => {
|
||||||
|
cur.forEach((sitem, sindex) => {
|
||||||
|
tempAcc.push([...item, sitem]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (cur.length < 1) {
|
||||||
|
tempAcc = acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tempAcc;
|
||||||
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
const specType = computed(() => peach.$store('trade').goodsInfo.specType)
|
const specType = computed(() => peach.$store("trade").goodsInfo.specType);
|
||||||
|
|
||||||
function initial() {
|
function initial() {
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
formData.value.specType = specType.value ? true : false
|
formData.value.specType = specType.value ? true : false;
|
||||||
formData.value.specText = SPEC_TYPE[specType.value ? 1 : 0].label
|
formData.value.specText = SPEC_TYPE[specType.value ? 1 : 0].label;
|
||||||
skus.value = peach.$store('trade').skus
|
skus.value = peach.$store("trade").skus;
|
||||||
if (specType.value) {
|
if (specType.value) {
|
||||||
getGoodsProperty()
|
getGoodsProperty();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
initial,
|
initial,
|
||||||
skus,
|
canEdit,
|
||||||
pickerRef,
|
skus,
|
||||||
pickerProperty,
|
pickerRef,
|
||||||
propertyListRef,
|
pickerProperty,
|
||||||
formData,
|
onConfirm,
|
||||||
onRDPickerConfirm,
|
propertyListRef,
|
||||||
onPropertyConfirm,
|
formData,
|
||||||
propertyList,
|
onRDPickerConfirm,
|
||||||
showPropertyList,
|
onPropertyConfirm,
|
||||||
goodsPropertyList,
|
propertyList,
|
||||||
changeSubProperty,
|
showPropertyList,
|
||||||
}
|
goodsPropertyList,
|
||||||
|
changeSubProperty,
|
||||||
|
};
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
<template>
|
<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">
|
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 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' }" />
|
: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 v-model:url="formData.sliderPicUrls" fileMediatype="image" limit="6" mode="grid"
|
<p-uploader v-model:url="formData.sliderPicUrls" :readonly="!canEdit" fileMediatype="image" limit="6"
|
||||||
:imageStyles="{ width: '168rpx', height: '168rpx' }" />
|
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" :disabled="!canEdit" placeholder="请输入商品名称" />
|
||||||
</uni-forms-item>
|
</uni-forms-item>
|
||||||
<uni-forms-item label="商品分类" @tap="openPicker('category', 'multiple')" name="categoryId" label-position="left"
|
<uni-forms-item label="商品分类" @tap="openPicker('category', 'multiple')" name="categoryId" label-position="left"
|
||||||
required>
|
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>
|
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" />
|
||||||
|
@ -24,8 +24,8 @@
|
||||||
</uni-easyinput>
|
</uni-easyinput>
|
||||||
</uni-forms-item>
|
</uni-forms-item>
|
||||||
<uni-forms-item label="商品品牌" name="brandId" label-position="left" required @tap="openPicker('brand', 'single')">
|
<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"
|
<uni-easyinput type="text" v-model="formData.brandText" :disabled="!canEdit" :styles="selfStyles"
|
||||||
:clearable="false" :inputBorder="false" placeholder="请选择商品品牌" disabled>
|
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>
|
||||||
|
@ -37,21 +37,25 @@
|
||||||
</view>
|
</view>
|
||||||
</uni-forms-item>
|
</uni-forms-item>
|
||||||
<uni-forms-item label="商品关键词" name="keyword" required>
|
<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>
|
||||||
<uni-forms-item label="商品简介" name="introduction" required>
|
<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>
|
||||||
<uni-forms-item label="物流设置" @tap="openPicker('delivery', 'single')" name="deliveryTypes" label-position="left"
|
<uni-forms-item label="物流设置" @tap="openPicker('delivery', 'single')" name="deliveryTypes" label-position="left"
|
||||||
required>
|
required>
|
||||||
<uni-easyinput type="text" :clearable="false" :styles="selfStyles" placeholderStyle="color:#8a8a8a"
|
<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>
|
<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>
|
</uni-forms>
|
||||||
|
<view @tap="onSubmit" v-if="canEdit">
|
||||||
|
<button class="ss-reset-button submit-button ui-Shadow-Main">提交</button>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<p-picker ref="pickerRef" :mode="pickerMode" :options-cols="optionsCols" @confirm="onRDPickerConfirm"></p-picker>
|
<p-picker ref="pickerRef" :mode="pickerMode" :options-cols="optionsCols" @confirm="onRDPickerConfirm"></p-picker>
|
||||||
|
@ -59,7 +63,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } 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 { handleTree } from '@/peach/utils'
|
import { handleTree } from '@/peach/utils'
|
||||||
|
@ -183,11 +187,14 @@ const rules = {
|
||||||
const formRef = ref(null)
|
const formRef = ref(null)
|
||||||
const pickerMode = ref('single')
|
const pickerMode = ref('single')
|
||||||
const popMark = ref('')
|
const popMark = ref('')
|
||||||
|
const goodsTitle = ref('')
|
||||||
const categoryList = ref([])
|
const categoryList = ref([])
|
||||||
const brandList = ref([])
|
const brandList = ref([])
|
||||||
const optionsCols = ref([])
|
const optionsCols = ref([])
|
||||||
|
const canEdit = computed(() => peach.$store('trade').canEdit)
|
||||||
|
|
||||||
function openPicker(mark, mode) {
|
function openPicker(mark, mode) {
|
||||||
|
if (!canEdit.value) return
|
||||||
pickerMode.value = mode
|
pickerMode.value = mode
|
||||||
popMark.value = mark
|
popMark.value = mark
|
||||||
if (mark === 'delivery') {
|
if (mark === 'delivery') {
|
||||||
|
@ -290,12 +297,12 @@ function onSubmit() {
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
let tempObj = { ...res }
|
let tempObj = { ...res }
|
||||||
|
|
||||||
if (formData.value.id) {
|
// if (formData.value.id) {
|
||||||
tempObj.id = formData.value.id
|
// tempObj.id = formData.value.id
|
||||||
await GoodsApi.editProduct(tempObj)
|
// await GoodsApi.editProduct(tempObj)
|
||||||
} else {
|
// } else {
|
||||||
await GoodsApi.addProduct(tempObj)
|
// await GoodsApi.addProduct(tempObj)
|
||||||
}
|
// }
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log('err', err)
|
console.log('err', err)
|
||||||
|
@ -317,13 +324,28 @@ async function getBrandList() {
|
||||||
onLoad(async (options) => {
|
onLoad(async (options) => {
|
||||||
await getCategoryList()
|
await getCategoryList()
|
||||||
await getBrandList()
|
await getBrandList()
|
||||||
|
|
||||||
|
goodsTitle.value = options.title
|
||||||
|
|
||||||
if (options.id) {
|
if (options.id) {
|
||||||
getProduct(options.id)
|
getProduct(options.id)
|
||||||
|
peach.$store('trade').detailTag = options.mark
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<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 {
|
.manage-goods {
|
||||||
.goods-form {
|
.goods-form {
|
||||||
margin: 40rpx;
|
margin: 40rpx;
|
||||||
|
@ -355,10 +377,18 @@ onLoad(async (options) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-disabled {
|
.is-direction-left {
|
||||||
color: #333333;
|
|
||||||
text-align: right;
|
.is-disabled {
|
||||||
|
color: #333333;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-forms-item__error {
|
||||||
|
left: -160rpx !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-group {
|
.btn-group {
|
||||||
|
@ -370,16 +400,17 @@ onLoad(async (options) => {
|
||||||
border-radius: 0 10px 10px 0;
|
border-radius: 0 10px 10px 0;
|
||||||
|
|
||||||
.ss-set-property {
|
.ss-set-property {
|
||||||
width: 80px;
|
@include ss-set-property
|
||||||
height: 60rpx;
|
|
||||||
line-height: normal;
|
|
||||||
background: var(--ui-BG-Main);
|
|
||||||
border-radius: 28rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #fff;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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>
|
</style>
|
||||||
|
|
|
@ -1,57 +1,45 @@
|
||||||
<template>
|
<template>
|
||||||
<pb-layout
|
<pb-layout class="goods-property" title="商品属性" leftIcon="leftIcon" navbar="normal" :bgStyle="bgStyle"
|
||||||
class="goods-property"
|
opacityBgUi="bg-white" color="black">
|
||||||
title="商品属性"
|
<view class="property">
|
||||||
leftIcon="leftIcon"
|
<uni-forms ref="formRef" v-model="formData" :rules="rules" label-position="top" label-width="160">
|
||||||
navbar="normal"
|
<uni-forms-item label="商品规格" @tap="pickerProperty" name="specType" label-position="left" required>
|
||||||
:bgStyle="bgStyle"
|
<uni-easyinput type="text" :clearable="false" :styles="selfStyles" placeholderStyle="color:#8a8a8a"
|
||||||
opacityBgUi="bg-white"
|
:inputBorder="false" v-model="formData.specText" placeholder="请选择商品规格" disabled>
|
||||||
color="black"
|
<template v-slot:right>
|
||||||
>
|
<uni-icons type="right" />
|
||||||
<view class="property">
|
</template>
|
||||||
<uni-forms ref="formRef" v-model="formData" :rules="rules" label-position="top" label-width="160">
|
</uni-easyinput>
|
||||||
<uni-forms-item label="商品规格" @tap="pickerProperty" name="specType" label-position="left" required>
|
</uni-forms-item>
|
||||||
<uni-easyinput
|
</uni-forms>
|
||||||
type="text"
|
</view>
|
||||||
:clearable="false"
|
<template v-if="formData.specType">
|
||||||
:styles="selfStyles"
|
<!-- 添加商品 -->
|
||||||
placeholderStyle="color:#8a8a8a"
|
<button v-if="canEdit" class="ss-reset-button add-property" @tap="showPropertyList">+添加规格</button>
|
||||||
:inputBorder="false"
|
<!-- 商品属性展示 -->
|
||||||
v-model="formData.specText"
|
<property-detail v-if="propertyList.length > 0" v-model="propertyList" :goodsPropertyList="goodsPropertyList"
|
||||||
placeholder="请选择商品规格"
|
@changeSubProperty="changeSubProperty"></property-detail>
|
||||||
disabled
|
<!-- 多规格商品 -->
|
||||||
>
|
<mutiple-sku :skus="skus"></mutiple-sku>
|
||||||
<template v-slot:right>
|
</template>
|
||||||
<uni-icons type="right" />
|
|
||||||
</template>
|
|
||||||
</uni-easyinput>
|
|
||||||
</uni-forms-item>
|
|
||||||
</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>
|
|
||||||
<mutiple-sku :skus="skus"></mutiple-sku>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<SkuItem :skus="skus" />
|
<!-- 单规格商品 -->
|
||||||
</template>
|
<SkuItem :skus="skus" />
|
||||||
|
</template>
|
||||||
|
|
||||||
<p-picker ref="pickerRef" mode="single" :options-cols="SPEC_TYPE" @confirm="onRDPickerConfirm"></p-picker>
|
<!-- 确认选择 -->
|
||||||
|
<view style="padding: 0 40rpx 40rpx;" @tap="onConfirm" v-if="canEdit">
|
||||||
|
<button class="ss-reset-button submit-button ui-Shadow-Main">提交</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
<PropertyList
|
<!-- 商品规格 -->
|
||||||
ref="propertyListRef"
|
<p-picker ref="pickerRef" mode="single" :options-cols="SPEC_TYPE" @confirm="onRDPickerConfirm"></p-picker>
|
||||||
v-model="propertyList"
|
|
||||||
:goodsPropertyList="goodsPropertyList"
|
<!-- 商品属性列表 -->
|
||||||
@confirm="onPropertyConfirm"
|
<PropertyList ref="propertyListRef" v-model="propertyList" :goodsPropertyList="goodsPropertyList"
|
||||||
/>
|
@confirm="onPropertyConfirm" />
|
||||||
</pb-layout>
|
</pb-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
@ -61,24 +49,25 @@ import PropertyList from './components/propertyList'
|
||||||
import PropertyDetail from './components/propertyDetail'
|
import PropertyDetail from './components/propertyDetail'
|
||||||
import { SPEC_TYPE } from './js/config'
|
import { SPEC_TYPE } from './js/config'
|
||||||
import {
|
import {
|
||||||
initial,
|
initial,
|
||||||
pickerRef,
|
canEdit,
|
||||||
propertyListRef,
|
pickerRef,
|
||||||
onRDPickerConfirm,
|
propertyListRef,
|
||||||
formData,
|
onRDPickerConfirm,
|
||||||
propertyList,
|
formData,
|
||||||
onPropertyConfirm,
|
propertyList,
|
||||||
showPropertyList,
|
onPropertyConfirm,
|
||||||
goodsPropertyList,
|
showPropertyList,
|
||||||
pickerProperty,
|
goodsPropertyList,
|
||||||
skus,
|
pickerProperty,
|
||||||
changeSubProperty,
|
skus,
|
||||||
|
changeSubProperty,
|
||||||
} from './js/sku'
|
} from './js/sku'
|
||||||
|
|
||||||
const bgStyle = {
|
const bgStyle = {
|
||||||
backgroundImage: '',
|
backgroundImage: '',
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
description: '',
|
description: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
initial()
|
initial()
|
||||||
|
@ -86,49 +75,57 @@ initial()
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.goods-property {
|
.goods-property {
|
||||||
.property {
|
.property {
|
||||||
margin: 40rpx;
|
margin: 40rpx;
|
||||||
|
|
||||||
:deep() {
|
:deep() {
|
||||||
.uni-easyinput__content-input {
|
.uni-easyinput__content-input {
|
||||||
font-size: 28rpx !important;
|
font-size: 28rpx !important;
|
||||||
color: #333333 !important;
|
color: #333333 !important;
|
||||||
line-height: normal !important;
|
line-height: normal !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.uni-easyinput__placeholder-class {
|
.uni-easyinput__placeholder-class {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-direction-left {
|
.is-direction-left {
|
||||||
.uni-forms-item__label {
|
.uni-forms-item__label {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
border-radius: 10px 0 0 10px;
|
border-radius: 10px 0 0 10px;
|
||||||
}
|
|
||||||
|
|
||||||
uni-icons {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uni-easyinput__content {
|
|
||||||
border-radius: 0 10px 10px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-disabled {
|
|
||||||
color: #333333;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.add-property {
|
uni-icons {
|
||||||
margin: 40rpx;
|
margin-right: 10px;
|
||||||
border: 1px dotted var(--ui-BG-Main);
|
}
|
||||||
color: var(--ui-BG-Main);
|
|
||||||
border-radius: 10px;
|
.uni-easyinput__content {
|
||||||
text-align: center;
|
border-radius: 0 10px 10px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-disabled {
|
||||||
|
color: #333333;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-property {
|
||||||
|
margin: 40rpx;
|
||||||
|
border: 1px dotted var(--ui-BG-Main);
|
||||||
|
color: var(--ui-BG-Main);
|
||||||
|
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>
|
</style>
|
||||||
|
|
|
@ -1,58 +1,46 @@
|
||||||
<template>
|
<template>
|
||||||
<view class="ss-goods-wrap">
|
<view class="ss-goods-wrap">
|
||||||
<view v-if="size === 'lg'" class="lg-goods-card ss-flex ss-col-stretch" :style="[elStyles]" @click="onClick">
|
<view v-if="size === 'lg'" class="lg-goods-card ss-flex ss-col-stretch" :style="[elStyles]" @click="onClick">
|
||||||
<image class="lg-img-box" :src="peach.$url.cdn(data.image || data.picUrl)" mode="aspectFill"></image>
|
<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 class="lg-goods-content ss-flex-1 ss-flex-col ss-row-between ss-p-b-10 ss-p-t-20">
|
||||||
<view>
|
<view>
|
||||||
<view
|
<view v-if="goodsFields.title?.show || goodsFields.name?.show" class="lg-goods-title ss-line-2"
|
||||||
v-if="goodsFields.title?.show || goodsFields.name?.show"
|
:style="[{ color: titleColor }]">
|
||||||
class="lg-goods-title ss-line-2"
|
{{ data.title || data.name }}
|
||||||
:style="[{ color: titleColor }]"
|
</view>
|
||||||
>
|
<view v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
|
||||||
{{ data.title || data.name }}
|
class="lg-goods-subtitle ss-m-t-10 ss-line-1"
|
||||||
</view>
|
:style="[{ color: subTitleColor, background: subTitleBackground }]">
|
||||||
<view
|
{{ data.subtitle || data.introduction }}
|
||||||
v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
|
</view>
|
||||||
class="lg-goods-subtitle ss-m-t-10 ss-line-1"
|
</view>
|
||||||
:style="[{ color: subTitleColor, background: subTitleBackground }]"
|
<view>
|
||||||
>
|
<view class="ss-flex ss-col-bottom ss-m-t-10">
|
||||||
{{ data.subtitle || data.introduction }}
|
<view v-if="goodsFields.price?.show" class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS"
|
||||||
</view>
|
:style="[{ color: goodsFields.price.color }]">
|
||||||
</view>
|
<text class="ss-font-24">{{ priceUnit }}</text>
|
||||||
<view>
|
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
||||||
<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 }]"
|
|
||||||
>
|
|
||||||
<text class="ss-font-24">{{ priceUnit }}</text>
|
|
||||||
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
|
||||||
</view>
|
|
||||||
<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 }]"
|
|
||||||
>
|
|
||||||
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
|
|
||||||
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="ss-m-t-8 ss-flex ss-col-center ss-flex-wrap">
|
|
||||||
<view class="sales-text">{{ salesAndStock }}</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
<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 }]">
|
||||||
|
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
|
||||||
|
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ss-m-t-8 ss-flex ss-col-center ss-flex-wrap">
|
||||||
|
<view class="sales-text">{{ salesAndStock }}</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="ss-flex ss-row-around" :style="btnStyles">
|
</view>
|
||||||
<button class="ss-reset-button btn-group" @click="clickGoods('detail')">详情</button>
|
|
||||||
<button class="ss-reset-button btn-group" @click="clickGoods('edit')">编辑</button>
|
|
||||||
<button class="ss-reset-button btn-group btn-del" @click="clickGoods('del')">删除</button>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
<view class="ss-flex ss-row-around" :style="btnStyles">
|
||||||
|
<button class="ss-reset-button btn-group" @click="clickGoods('detail')">详情</button>
|
||||||
|
<button class="ss-reset-button btn-group" @click="clickGoods('edit')">编辑</button>
|
||||||
|
<button class="ss-reset-button btn-group btn-del" @click="clickGoods('del')">删除</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
@ -63,167 +51,171 @@ import { fen2yuan, formatSales, formatStock } from '@/peach/hooks/useGoods'
|
||||||
import { unix } from 'dayjs'
|
import { unix } from 'dayjs'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
goodsFields: {
|
goodsFields: {
|
||||||
type: [Array, Object],
|
type: [Array, Object],
|
||||||
default() {
|
default() {
|
||||||
return {
|
return {
|
||||||
price: { show: true },
|
price: { show: true },
|
||||||
stock: { show: true },
|
stock: { show: true },
|
||||||
name: { show: true },
|
name: { show: true },
|
||||||
introduction: { show: true },
|
introduction: { show: true },
|
||||||
marketPrice: { show: true },
|
marketPrice: { show: true },
|
||||||
salesCount: { show: true },
|
salesCount: { show: true },
|
||||||
}
|
}
|
||||||
},
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
default: {},
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
originPriceColor: {
|
|
||||||
type: String,
|
|
||||||
default: '#C4C4C4',
|
|
||||||
},
|
|
||||||
topRadius: {
|
|
||||||
type: Number,
|
|
||||||
default: 0,
|
|
||||||
},
|
|
||||||
bottomRadius: {
|
|
||||||
type: Number,
|
|
||||||
default: 0,
|
|
||||||
},
|
|
||||||
priceUnit: {
|
|
||||||
type: String,
|
|
||||||
default: '¥',
|
|
||||||
},
|
|
||||||
titleColor: {
|
|
||||||
type: String,
|
|
||||||
default: '#333',
|
|
||||||
},
|
|
||||||
subTitleColor: {
|
|
||||||
type: String,
|
|
||||||
default: '#999999',
|
|
||||||
},
|
|
||||||
subTitleBackground: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
originPriceColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#C4C4C4',
|
||||||
|
},
|
||||||
|
topRadius: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
bottomRadius: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
priceUnit: {
|
||||||
|
type: String,
|
||||||
|
default: '¥',
|
||||||
|
},
|
||||||
|
titleColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#333',
|
||||||
|
},
|
||||||
|
subTitleColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#999999',
|
||||||
|
},
|
||||||
|
subTitleBackground: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const emits = defineEmits(['click'])
|
const emits = defineEmits(['click'])
|
||||||
|
|
||||||
function onClick() {
|
function onClick() {
|
||||||
emits('click')
|
emits('click')
|
||||||
}
|
}
|
||||||
|
|
||||||
const elStyles = computed(() => {
|
const elStyles = computed(() => {
|
||||||
return {
|
return {
|
||||||
background: props.background,
|
background: props.background,
|
||||||
'border-top-left-radius': props.topRadius + 'px',
|
'border-top-left-radius': props.topRadius + 'px',
|
||||||
'border-top-right-radius': props.topRadius + 'px',
|
'border-top-right-radius': props.topRadius + 'px',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const btnStyles = computed(() => {
|
const btnStyles = computed(() => {
|
||||||
return {
|
return {
|
||||||
background: '#fff',
|
background: '#fff',
|
||||||
'border-bottom-left-radius': props.bottomRadius + 'px',
|
'border-bottom-left-radius': props.bottomRadius + 'px',
|
||||||
'border-bottom-right-radius': props.bottomRadius + 'px',
|
'border-bottom-right-radius': props.bottomRadius + 'px',
|
||||||
padding: '8px 0',
|
padding: '8px 0',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 格式化销量、库存信息
|
// 格式化销量、库存信息
|
||||||
const salesAndStock = computed(() => {
|
const salesAndStock = computed(() => {
|
||||||
let text = []
|
let text = []
|
||||||
if (props.goodsFields.salesCount?.show) {
|
if (props.goodsFields.salesCount?.show) {
|
||||||
text.push(formatSales(props.data.sales_show_type, props.data.salesCount))
|
text.push(formatSales(props.data.sales_show_type, props.data.salesCount))
|
||||||
}
|
}
|
||||||
if (props.goodsFields.stock?.show) {
|
if (props.goodsFields.stock?.show) {
|
||||||
text.push(formatStock(props.data.stock_show_type, props.data.stock))
|
text.push(formatStock(props.data.stock_show_type, props.data.stock))
|
||||||
}
|
}
|
||||||
return text.join(' | ')
|
return text.join(' | ')
|
||||||
})
|
})
|
||||||
|
|
||||||
function clickGoods(mark) {
|
function clickGoods(mark) {
|
||||||
if (mark === 'detail' || mark === 'edit') {
|
|
||||||
peach.$router.go('/pages/product/manageGoods', {
|
if (mark === 'detail' || mark === 'edit') {
|
||||||
id: props.data.id,
|
peach.$router.go('/pages/product/manageGoods', {
|
||||||
mark: mark,
|
id: props.data.id,
|
||||||
})
|
mark: mark,
|
||||||
} else if (mark === 'del') {
|
title: mark === 'detail' ? '商品详情' : '编辑商品'
|
||||||
uni.showModal({
|
})
|
||||||
title: '提示',
|
} else if (mark === 'del') {
|
||||||
content: '是否删除该商品?',
|
uni.showModal({
|
||||||
success: (res) => {
|
title: '提示',
|
||||||
if (res.confirm) {
|
content: '是否删除该商品?',
|
||||||
}
|
success: (res) => {
|
||||||
},
|
if (res.confirm) {
|
||||||
})
|
}
|
||||||
}
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.ss-goods-wrap {
|
.ss-goods-wrap {
|
||||||
.lg-goods-card {
|
.lg-goods-card {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
background-color: $white;
|
background-color: $white;
|
||||||
height: 280rpx;
|
height: 280rpx;
|
||||||
|
|
||||||
.lg-img-box {
|
.lg-img-box {
|
||||||
width: 280rpx;
|
width: 280rpx;
|
||||||
height: 280rpx;
|
height: 280rpx;
|
||||||
margin-right: 20rpx;
|
margin-right: 20rpx;
|
||||||
}
|
|
||||||
|
|
||||||
.lg-goods-title {
|
|
||||||
font-size: 28rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #333333;
|
|
||||||
// line-height: 36rpx;
|
|
||||||
// width: 410rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lg-goods-subtitle {
|
|
||||||
font-size: 24rpx;
|
|
||||||
font-weight: 400;
|
|
||||||
color: #999999;
|
|
||||||
// line-height: 30rpx;
|
|
||||||
// width: 410rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lg-goods-price {
|
|
||||||
font-size: 30rpx;
|
|
||||||
color: $red;
|
|
||||||
line-height: 36rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sales-text {
|
|
||||||
display: table;
|
|
||||||
font-size: 24rpx;
|
|
||||||
transform: scale(0.8);
|
|
||||||
margin-left: 0rpx;
|
|
||||||
color: #c4c4c4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.btn-group {
|
|
||||||
width: 120rpx;
|
.lg-goods-title {
|
||||||
height: 50rpx;
|
font-size: 28rpx;
|
||||||
background: var(--ui-BG-1);
|
font-weight: 500;
|
||||||
border-radius: 25rpx;
|
color: #333333;
|
||||||
font-size: 24rpx;
|
// line-height: 36rpx;
|
||||||
color: #000;
|
// width: 410rpx;
|
||||||
}
|
}
|
||||||
.btn-del {
|
|
||||||
color: var(--ui-BG-Main);
|
.lg-goods-subtitle {
|
||||||
background-color: var(--ui-BG-Main-opacity-1);
|
font-size: 24rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #999999;
|
||||||
|
// line-height: 30rpx;
|
||||||
|
// width: 410rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lg-goods-price {
|
||||||
|
font-size: 30rpx;
|
||||||
|
color: $red;
|
||||||
|
line-height: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sales-text {
|
||||||
|
display: table;
|
||||||
|
font-size: 24rpx;
|
||||||
|
transform: scale(0.8);
|
||||||
|
margin-left: 0rpx;
|
||||||
|
color: #c4c4c4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-group {
|
||||||
|
width: 120rpx;
|
||||||
|
height: 50rpx;
|
||||||
|
background: var(--ui-BG-1);
|
||||||
|
border-radius: 25rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-del {
|
||||||
|
color: var(--ui-BG-Main);
|
||||||
|
background-color: var(--ui-BG-Main-opacity-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,47 +1,35 @@
|
||||||
<template>
|
<template>
|
||||||
<view class="custom-picker">
|
<view class="custom-picker">
|
||||||
<!-- 普通弹窗 -->
|
<!-- 普通弹窗 -->
|
||||||
<uni-popup type="bottom" ref="pickerPopupRef" background-color="#fff">
|
<uni-popup type="bottom" ref="pickerPopupRef" background-color="#fff">
|
||||||
<view class="popup-header">
|
<view class="popup-header">
|
||||||
<view class="button-cancel" @click="onClosePopup">取消</view>
|
<view class="button-cancel" @click="onClosePopup">取消</view>
|
||||||
<view class="button-link" @click="onConfirmPopup">确定</view>
|
<view class="button-link" @click="onConfirmPopup">确定</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="popup-content">
|
<view class="popup-content">
|
||||||
<picker-view
|
<picker-view :indicator-style="indicatorStyle" :value="pickerViewValue" @change="bindChange"
|
||||||
:indicator-style="indicatorStyle"
|
class="picker-view">
|
||||||
:value="pickerViewValue"
|
<template v-if="mode === 'single'">
|
||||||
@change="bindChange"
|
<picker-view-column>
|
||||||
class="picker-view"
|
<view class="item" v-for="(item, index) in props.optionsCols" :key="`${item.value}-${index}`">{{
|
||||||
>
|
item.label ?? item.name }}</view>
|
||||||
<template v-if="mode === 'single'">
|
</picker-view-column>
|
||||||
<picker-view-column>
|
</template>
|
||||||
<view
|
<template v-else>
|
||||||
class="item"
|
<picker-view-column>
|
||||||
v-for="(item, index) in props.optionsCols"
|
<view class="item" v-for="(item, index) in props.optionsCols" :key="`${item.value}-${index}`">{{ item.name
|
||||||
:key="`${item.value}-${index}`"
|
}}</view>
|
||||||
>{{ item.label }}</view
|
</picker-view-column>
|
||||||
>
|
<picker-view-column>
|
||||||
</picker-view-column>
|
<view class="item" v-for="(item, index) in childrenList" :key="`${item.value}-${index}`">{{
|
||||||
</template>
|
item.name
|
||||||
<template v-else>
|
}}</view>
|
||||||
<picker-view-column>
|
</picker-view-column>
|
||||||
<view
|
</template>
|
||||||
class="item"
|
</picker-view>
|
||||||
v-for="(item, index) in props.optionsCols"
|
</view>
|
||||||
:key="`${item.value}-${index}`"
|
</uni-popup>
|
||||||
>{{ item.name }}</view
|
</view>
|
||||||
>
|
|
||||||
</picker-view-column>
|
|
||||||
<picker-view-column>
|
|
||||||
<view class="item" v-for="(item, index) in childrenList" :key="`${item.value}-${index}`">{{
|
|
||||||
item.name
|
|
||||||
}}</view>
|
|
||||||
</picker-view-column>
|
|
||||||
</template>
|
|
||||||
</picker-view>
|
|
||||||
</view>
|
|
||||||
</uni-popup>
|
|
||||||
</view>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
@ -49,20 +37,20 @@ import { defineEmits, defineProps, ref, onMounted, computed, defineExpose } from
|
||||||
const pickerViewValue = ref([])
|
const pickerViewValue = ref([])
|
||||||
const indicatorStyle = `height: 50px`
|
const indicatorStyle = `height: 50px`
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
// 传入pickerview列表 value label字段
|
// 传入pickerview列表 value label字段
|
||||||
optionsCols: {
|
optionsCols: {
|
||||||
default: () => [],
|
default: () => [],
|
||||||
required: true,
|
required: true,
|
||||||
type: Array,
|
type: Array,
|
||||||
},
|
},
|
||||||
mode: {
|
mode: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'single',
|
default: 'single',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const childrenList = computed(() => {
|
const childrenList = computed(() => {
|
||||||
return props.optionsCols[pickerViewValue.value[0]]?.children
|
return props.optionsCols[pickerViewValue.value[0]]?.children
|
||||||
})
|
})
|
||||||
|
|
||||||
// 暴露两个方法confirm change
|
// 暴露两个方法confirm change
|
||||||
|
@ -76,8 +64,8 @@ const pickerPopupRef = ref(null)
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
const onOpen = (defaultValue) => {
|
const onOpen = (defaultValue) => {
|
||||||
pickerViewValue.value = defaultValue
|
pickerViewValue.value = defaultValue
|
||||||
pickerPopupRef.value.open('bottom')
|
pickerPopupRef.value.open('bottom')
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @author: joey wong
|
* @author: joey wong
|
||||||
|
@ -86,17 +74,17 @@ const onOpen = (defaultValue) => {
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
const bindChange = (e) => {
|
const bindChange = (e) => {
|
||||||
pickerViewValue.value = e.detail.value
|
pickerViewValue.value = e.detail.value
|
||||||
|
|
||||||
if (props.mode === 'multiple') {
|
if (props.mode === 'multiple') {
|
||||||
if (pickerViewValue.value[0] !== e.detail.value[0]) {
|
if (pickerViewValue.value[0] !== e.detail.value[0]) {
|
||||||
pickerViewValue.value[1] = 0
|
pickerViewValue.value[1] = 0
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
emit('change', {
|
emit('change', {
|
||||||
value: pickerViewValue.value,
|
value: pickerViewValue.value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @author: joey wong
|
* @author: joey wong
|
||||||
|
@ -104,7 +92,7 @@ const bindChange = (e) => {
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
const onClosePopup = () => {
|
const onClosePopup = () => {
|
||||||
pickerPopupRef.value.close()
|
pickerPopupRef.value.close()
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @author: joey wong
|
* @author: joey wong
|
||||||
|
@ -112,56 +100,61 @@ const onClosePopup = () => {
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
const onConfirmPopup = () => {
|
const onConfirmPopup = () => {
|
||||||
emit('confirm', {
|
emit('confirm', {
|
||||||
value: pickerViewValue.value,
|
value: pickerViewValue.value,
|
||||||
})
|
})
|
||||||
onClosePopup()
|
onClosePopup()
|
||||||
}
|
}
|
||||||
defineExpose({
|
defineExpose({
|
||||||
onOpen,
|
onOpen,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.custom-picker {
|
.custom-picker {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&-text {
|
||||||
|
margin-right: 5.7rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
width: 19rpx;
|
||||||
|
height: 12rpx;
|
||||||
|
margin-bottom: 3rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-content {
|
||||||
|
height: 500rpx;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
text-align: center;
|
||||||
|
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;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
&-text {
|
padding: 24rpx 38rpx 0;
|
||||||
margin-right: 5.7rpx;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&-icon {
|
|
||||||
width: 19rpx;
|
|
||||||
height: 12rpx;
|
|
||||||
margin-bottom: 3rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popup-content {
|
|
||||||
height: 500rpx;
|
|
||||||
.item {
|
|
||||||
text-align: center;
|
|
||||||
line-height: 50px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.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;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 24rpx 38rpx 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -282,6 +282,7 @@ export default {
|
||||||
return this.uploadFiles(files);
|
return this.uploadFiles(files);
|
||||||
},
|
},
|
||||||
async setValue(newVal, oldVal) {
|
async setValue(newVal, oldVal) {
|
||||||
|
|
||||||
const newData = async (v) => {
|
const newData = async (v) => {
|
||||||
const reg = /cloud:\/\/([\w.]+\/?)\S*/;
|
const reg = /cloud:\/\/([\w.]+\/?)\S*/;
|
||||||
let url = '';
|
let url = '';
|
||||||
|
@ -512,6 +513,7 @@ export default {
|
||||||
* @param {Object} index
|
* @param {Object} index
|
||||||
*/
|
*/
|
||||||
delFile(index) {
|
delFile(index) {
|
||||||
|
|
||||||
this.$emit('delete', {
|
this.$emit('delete', {
|
||||||
tempFile: this.files[index],
|
tempFile: this.files[index],
|
||||||
tempFilePath: this.files[index].url,
|
tempFilePath: this.files[index].url,
|
||||||
|
@ -541,11 +543,13 @@ export default {
|
||||||
setEmit() {
|
setEmit() {
|
||||||
let data = [];
|
let data = [];
|
||||||
let updateUrl = [];
|
let updateUrl = [];
|
||||||
|
// 单文件
|
||||||
if (this.returnType === 'object') {
|
if (this.returnType === 'object') {
|
||||||
data = this.backObject(this.files)[0];
|
data = this.backObject(this.files)[0];
|
||||||
this.localValue = data ? data : null;
|
this.localValue = data ? data : null;
|
||||||
updateUrl = data ? data.url : '';
|
updateUrl = data ? data.url : '';
|
||||||
} else {
|
} else {
|
||||||
|
// 多文件
|
||||||
data = this.backObject(this.files);
|
data = this.backObject(this.files);
|
||||||
if (!this.localValue) {
|
if (!this.localValue) {
|
||||||
this.localValue = [];
|
this.localValue = [];
|
||||||
|
@ -568,16 +572,23 @@ export default {
|
||||||
backObject(files) {
|
backObject(files) {
|
||||||
let newFilesData = [];
|
let newFilesData = [];
|
||||||
files.forEach((v) => {
|
files.forEach((v) => {
|
||||||
newFilesData.push({
|
if (v.fileID) {
|
||||||
extname: v.extname,
|
|
||||||
fileType: v.fileType,
|
newFilesData.push({
|
||||||
image: v.image,
|
extname: v.extname,
|
||||||
name: v.name,
|
fileType: v.fileType,
|
||||||
path: v.path,
|
image: v.image,
|
||||||
size: v.size,
|
name: v.name,
|
||||||
fileID: v.fileID,
|
path: v.path,
|
||||||
url: v.url,
|
size: v.size,
|
||||||
});
|
fileID: v.fileID,
|
||||||
|
url: v.url,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
newFilesData.push({
|
||||||
|
url: v
|
||||||
|
})
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return newFilesData;
|
return newFilesData;
|
||||||
},
|
},
|
||||||
|
|
|
@ -69,6 +69,7 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
list() {
|
list() {
|
||||||
|
|
||||||
if (typeof this.filesList === 'string') {
|
if (typeof this.filesList === 'string') {
|
||||||
if (this.filesList) {
|
if (this.filesList) {
|
||||||
return [this.filesList];
|
return [this.filesList];
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ref } from "vue";
|
import { ref, computed } from "vue";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
const useTradeStore = defineStore("trade", () => {
|
const useTradeStore = defineStore("trade", () => {
|
||||||
|
@ -8,13 +8,21 @@ const useTradeStore = defineStore("trade", () => {
|
||||||
// 商品信息
|
// 商品信息
|
||||||
const goodsInfo = ref(null);
|
const goodsInfo = ref(null);
|
||||||
|
|
||||||
|
// 详情标记
|
||||||
|
const detailTag = ref("edit");
|
||||||
|
|
||||||
// 商品属性
|
// 商品属性
|
||||||
const skus = ref(null);
|
const skus = ref(null);
|
||||||
|
|
||||||
|
// 商品是否可编辑
|
||||||
|
const canEdit = computed(() => (detailTag.value === "detail" ? false : true));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
selectedProperty,
|
selectedProperty,
|
||||||
goodsInfo,
|
goodsInfo,
|
||||||
skus,
|
skus,
|
||||||
|
canEdit,
|
||||||
|
detailTag,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue