mall-app-t/pages/product/manageGoods.vue

588 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<template>
<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"
: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"
: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"
: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"
placeholderStyle="color:#8a8a8a"
:clearable="false"
:inputBorder="false"
placeholder="请选择商品分类"
disabled
>
<template v-slot:right>
<uni-icons type="right" />
</template>
</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
>
<template v-slot:right>
<uni-icons type="right" />
</template>
</uni-easyinput>
</uni-forms-item>
<uni-forms-item label="商品规格" name="skus" required label-position="left">
<view class="btn-group">
<button class="ss-reset-button ss-set-property" @tap="clickSetProperty">规格设置</button>
</view>
</uni-forms-item>
<uni-forms-item label="商品关键词" name="keyword" required>
<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"
: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
>
<template v-slot:right>
<uni-icons type="right" />
</template>
</uni-easyinput>
</uni-forms-item>
<uni-forms-item label="虚拟销量" name="virtualSalesCount" required>
<uni-easyinput
v-model="formData.virtualSalesCount"
type="number"
:disabled="!canEdit"
placeholder="请输入虚拟销量"
/>
</uni-forms-item>
<uni-forms-item label="商品详情" required>
<piaoyiEditor
:values="richValues"
@changes="saveContens"
:maxlength="3000"
:readOnly="richReadOnly"
:photoUrl="photoUrl"
:api="richApi"
/>
</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>
</pb-layout>
</template>
<script setup>
import { ref, computed } from 'vue'
import { onLoad, onPageScroll, onShow } from '@dcloudio/uni-app'
import _ from 'lodash'
import GoodsApi from '@/peach/api/trade/goods'
import piaoyiEditor from '@/uni_modules/piaoyi-editor/components/piaoyi-editor/piaoyi-editor.vue'
import peach from '@/peach'
import { baseUrl, apiPath } from '@/peach/config'
import { handleTree, floatToFixed2, convertToInteger } from '@/peach/utils'
import { validateSku } from './js/sku'
const bgStyle = {
backgroundImage: '',
backgroundColor: '#fff',
description: '',
}
const DELIVERY_TYPES = [
{
value: 3,
label: '到店核销',
},
{
value: 4,
label: '商家配送',
},
]
const selfStyles = {
backgroundColor: '#f9f9f9',
}
const pickerRef = ref()
const richValues = ref('')
const photoUrl = baseUrl + apiPath
const richApi = '/infra/file/upload'
const richReadOnly = ref(true)
const formData = ref({
picUrl: '',
sliderPicUrls: [],
name: '',
categoryId: '',
categoryText: '',
brandId: '',
keyword: '',
deliveryTypes: [],
deliveryText: '',
sort: 0,
giveIntegral: 0,
virtualSalesCount: 0,
subCommissionType: false,
introduction: '',
})
const rules = {
name: {
rules: [
{
required: true,
errorMessage: '请输入商品名称',
},
],
},
picUrl: {
rules: [
{
required: true,
errorMessage: '请上传商品封面图',
},
],
},
sliderPicUrls: {
rules: [
{
required: true,
errorMessage: '请上传商品轮播图',
},
],
},
categoryId: {
rules: [
{
required: true,
errorMessage: '请选择商品分类',
},
],
},
brandId: {
rules: [
{
required: true,
errorMessage: '请选择商品品牌',
},
],
},
skus: {
rules: [
{
required: true,
errorMessage: '请选择商品规格',
},
],
},
keyword: {
rules: [
{
required: true,
errorMessage: '请输入商品关键字',
},
],
},
introduction: {
rules: [
{
required: true,
errorMessage: '请输入商品简介',
},
],
},
deliveryTypes: {
rules: [
{
required: true,
errorMessage: '请选择商品物流',
},
],
},
}
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') {
optionsCols.value = DELIVERY_TYPES
pickerRef.value.onOpen([0])
} else if (mark === 'category') {
optionsCols.value = categoryList.value
pickerRef.value.onOpen([0, 0])
} else if (mark === 'brand') {
optionsCols.value = brandList.value
pickerRef.value.onOpen([0])
}
}
function onRDPickerConfirm(e) {
if (popMark.value === 'delivery') {
formData.value.deliveryTypes = []
formData.value.deliveryText = DELIVERY_TYPES[e.value[0]].label
formData.value.deliveryTypes.push(DELIVERY_TYPES[e.value[0]].value)
}
if (popMark.value === 'category') {
formData.value.categoryId = categoryList.value[e.value[0]].children[e.value[1]].id
formData.value.categoryText =
categoryList.value[e.value[0]].name + '/' + categoryList.value[e.value[0]].children[e.value[1]].name
}
if (popMark.value === 'brand') {
formData.value.brandId = brandList.value[e.value[0]].id
formData.value.brandText = brandList.value[e.value[0]].name
}
}
function clickSetProperty() {
if (formData.value.skus) {
// 如果是多规格,处理格式问题,合并属性
let temp = formData.value.skus
.map((item) => {
return item.properties.map((sitem) => ({
id: sitem.propertyId,
children: [sitem.valueId],
}))
})
.flat(1)
// 去除重复数据
let result = temp.reduce((pre, cur) => {
let index = pre.findIndex((item) => item.id === cur.id)
if (index !== -1) {
pre[index].children.push(...new Set(cur.children))
} else {
pre.push(cur)
}
return pre
}, [])
peach.$store('trade').$patch({
selectedProperty: result,
})
}
peach.$router.go('/pages/product/sku')
}
function getProduct(id) {
GoodsApi.getProduct({ id }).then((res) => {
formData.value = res.data
// 内容为图片时,需要在末尾插入空行
richValues.value = res.data.description ? res.data.description + '<p><br/></p>' : ''
// 循环遍历 categoryList从二级分类找出和 formData.value.categoryId 相等的
let tempCategory = categoryList.value.find((item) => {
return item.children?.find((child) => {
return child.id === formData.value.categoryId
})
})
formData.value.categoryText =
tempCategory.name +
'/' +
tempCategory.children.find((item) => {
return item.id === formData.value.categoryId
}).name
// 循环遍历 brandList, 从一级分类找出和 formData.value.brandId 相等的
let tempBrand = brandList.value.find((item) => {
return item.id === formData.value.brandId
})
formData.value.brandText = tempBrand.name
// 从 DELIVERY_TYPES 找出和 formData.value.deliveryTypes 相等的
formData.value.deliveryText = DELIVERY_TYPES.find((item) => {
return item.value === formData.value.deliveryTypes[0]
}).label
formData.value.skus.forEach((item) => {
item.price = floatToFixed2(item.price)
item.marketPrice = floatToFixed2(item.marketPrice)
item.costPrice = floatToFixed2(item.costPrice)
})
peach.$store('trade').$patch({
goodsInfo: formData.value,
skus: formData.value.skus,
specType: formData.value.specType,
})
})
}
function saveContens(e) {
formData.value.description = e.html
}
function onSubmit() {
formData.value.skus = peach.$store('trade').skus
formRef.value
.validate()
.then(async (res) => {
// 校验 skus 是否正确填写完成
validateSku()
let tempObj = _.cloneDeep(formData.value)
tempObj.skus.forEach((item) => {
item.name = formData.value.name
item.price = convertToInteger(item.price)
item.marketPrice = convertToInteger(item.marketPrice)
item.costPrice = convertToInteger(item.costPrice)
})
tempObj.specType = peach.$store('trade').specType
let msg = ''
if (formData.value.id) {
tempObj.id = formData.value.id
await GoodsApi.editProduct(tempObj)
msg = '修改成功'
} else {
await GoodsApi.addProduct(tempObj)
msg = '添加成功'
}
uni.showToast({
title: msg,
icon: 'none',
duration: 4000,
})
setTimeout(() => {
peach.$router.redirect('/pages/index/product')
}, 1000)
})
.catch((err) => {
console.log('err', err)
if (err) {
uni.showToast({
title: err[0]?.errorMessage,
icon: 'none',
duration: 4000,
})
}
})
}
// 获得商品分类
async function getCategoryList() {
let { data } = await GoodsApi.getGoodsCategory()
categoryList.value = handleTree(data)
}
// 获得商品品牌
async function getBrandList() {
let { data } = await GoodsApi.getBrand()
brandList.value = data
}
onLoad(async (options) => {
await getCategoryList()
await getBrandList()
goodsTitle.value = options.title
if (options.id) {
getProduct(options.id)
peach.$store('trade').detailTag = options.mark
}
})
onShow(() => {
let isSave = peach.$store('trade').isSave
if (isSave) {
formData.value.skus = peach.$store('trade').skus
formData.value.specType = peach.$store('trade').specType
peach.$store('trade').isSave = false
} else {
peach.$store('trade').$patch({
skus: formData.value.skus || [],
specType: formData.value.specType,
})
}
})
onPageScroll((e) => {
if (canEdit.value && e.scrollTop > 200) {
richReadOnly.value = false
}
})
</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;
:deep() {
.uni-easyinput__content-input {
font-size: 28rpx !important;
color: #333333 !important;
line-height: normal !important;
}
.uni-easyinput__placeholder-class {
font-size: 14px;
}
.is-direction-left {
.uni-forms-item__label {
padding-left: 10px;
background-color: #f9f9f9;
border-radius: 10px 0 0 10px;
}
uni-icons {
margin-right: 10px;
}
.uni-easyinput__content {
border-radius: 0 10px 10px 0;
}
}
.is-direction-left {
.is-disabled {
color: #333333;
text-align: right;
}
.uni-forms-item__error {
left: -160rpx !important;
}
}
}
.btn-group {
height: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
background-color: #f9f9f9;
border-radius: 0 10px 10px 0;
.ss-set-property {
@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>