cashier_admin_app/pageProduct/add-Product/add-Product.vue

1878 lines
48 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<template>
<view class="u-p-30 safe-page min-page">
<up-sticky v-if="option.type==='edit'" offset-top="20" zIndex="99">
<my-tabs :list="tabsList" v-model="tabsCurrent"></my-tabs>
</up-sticky>
<view class="box">
<template v-if="tabsCurrent===0">
<view class="basic">
<uni-forms :model="FormData" :rules="rules" :border="true" label-position="top"
err-show-type="toast" validateTrigger="submit" label-width="350" ref="Forms">
<view class="block">
<view class="border-top-0">
<uni-forms-item label="商品类型" required showRequired>
<up-radio-group v-model="FormData.typeEnum" placement="row">
<up-radio :customStyle="{marginRight: '30px'}"
v-for="(item, index) in pageData.types" :key="index" :label="item.name"
:name="item.value">
</up-radio>
</up-radio-group>
<!-- <view class="u-flex u-flex-wrap types " :class="{disabled:option.productId!==''}">
<view class="item" @tap="changeFormData('typeEnum',item.value)"
:class="{active:FormData.typeEnum===item.value}"
v-for="(item,index) in pageData.types" :key="index">
<view class="title">{{item.title}}</view>
<view class="u-font-24 color-999 u-m-t-10">
{{item.desc}}
</view>
</view>
</view> -->
</uni-forms-item>
</view>
<uni-forms-item ref="fileItem" label="图片" required showRequired>
<my-upload-file ref="refFile" :images="FormData.images"
:imageStyles="imageStyles"></my-upload-file>
<view class="u-m-t-16 color-999 u-font-24">
注:第一张图为商品封面图图片尺寸为750x750
</view>
</uni-forms-item>
<uni-forms-item required name="name" label="商品名称" showRequired>
<uni-easyinput :paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.name" placeholder="请输入商品名称" />
</uni-forms-item>
<view class="">
<uni-forms-item label="商品描述">
<uni-easyinput :paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
type="textarea" v-model="FormData.shortTitle" placeholder="请填写商品简述" />
</uni-forms-item>
</view>
<template v-if="FormData.typeEnum!='group'">
<view class="u-relative">
<uni-forms-item label="所属分类" required showRequired name="categoryId">
<uni-data-picker :clear-icon="false" :map="{text:'name',value:'id'}"
placeholder="请选择分类" popup-title="请选择分类" :localdata="pageData.category"
v-model="FormData.categoryId">
</uni-data-picker>
</uni-forms-item>
<view class="zhezhao u-absolute position-all" @click="canEditGoodsCategory(true)"
v-if="option.type=='edit'&&disabledChangeCategory">
</view>
</view>
</template>
<view class="border-top-0">
<uni-forms-item label="单位" required showRequired name="categoryId">
<uni-data-picker :clear-icon="false" @change="unitIdChange"
:map="{text:'name',value:'id'}" placeholder="请选择单位" popup-title="请选择单位"
:localdata="pageData.units" v-model="FormData.unitId">
</uni-data-picker>
</uni-forms-item>
</view>
<template v-if="FormData.typeEnum==='group'">
<view class="border-top-0">
<uni-forms-item label="团购券分类" required showRequired name="categoryId">
<view class="u-p-30 bg-gray u-m-b-20" v-if="FormData.groupCategoryId.length">
<view class="u-flex">
<view class="u-flex-1 u-p-r-30">名称</view>
<view class=" u-flex-1 u-p-l-30">操作</view>
</view>
<view class="u-flex u-m-t-20 u-row-between"
v-for="(item,index) in FormData.groupCategoryId" :key="index"
@tap="groupCategoryIdDel(index)">
<view class="u-flex-1 u-flex u-p-r-30">
<view class="bg-fff u-flex-1 u-p-10">
{{item.name}}
</view>
</view>
<view class="u-flex u-flex-1 u-p-l-30">
<uni-icons type="minus-filled" :size="26"
:color="color.ColorRed"></uni-icons>
</view>
</view>
</view>
<view class=" u-flex " @tap="refChooseGroupCategoryOpen">
<uni-icons type="plus-filled" :color="color.ColorMain"
:size="26"></uni-icons>
<view class="u-m-l-16">添加团购券分类</view>
</view>
</uni-forms-item>
</view>
<!-- 选择团购券分类 -->
<choose-group-category @confirm="refChooseCouponCategoryConfirm"
ref="refChooseGroupCategory"></choose-group-category>
</template>
</view>
<template v-if="FormData.typeEnum=='sku' ">
<view class="block border-top-0 u-p-t-32 u-p-b-32">
<view class="u-flex u-row-between " >
<view class="color-333 font-bold">
<text v-if="!skuList.list.length">选择规格</text>
<text v-else>编辑规格</text>
</view>
<view class="u-flex u-col-center" @tap="toGuige">
<view>
<text v-if="FormData.specsInfoName">{{FormData.specsInfoName}}</text>
<text class="color-999" v-else>请选择</text>
</view>
<view class="u-flex u-p-t-2">
<uni-icons type="right" :size="14" color="#999"></uni-icons>
</view>
</view>
</view>
<!-- <template >
<view class="u-text-left">
<view class="u-flex font-bold u-m-b-12">
<view class="u-flex-1 ">组合名称</view>
<view class="u-flex-1 ">售价</view>
</view>
<view class="u-flex u-p-b-12 u-p-t-12" v-for="(item,index) in skuList.list"
:key="index">
<view class="u-flex-1 ">{{item.specSnap}}</view>
<view class="u-flex-1 ">¥{{item.salePrice}}</view>
</view>
</view>
</template> -->
</view>
</template>
<template v-if="FormData.typeEnum==='group' ">
<!-- <view class="block border-top-0">
<uni-forms-item label="选择规格" required name="categoryId">
<uni-data-picker :clear-icon="false" @change="specIdChange"
:map="{text:'name',value:'id'}" placeholder="请选择规格" popup-title="请选择规格"
:localdata="pageData.specList" v-model="FormData.specId">
</uni-data-picker>
</uni-forms-item>
</view> -->
<view class="font-bold u-m-t-32 u-m-b-32">套餐商品 </view>
<view class=" " v-if="FormData.groupSnap.length">
<view class="u-m-t-30 block border-top-0" v-for="(item,index) in FormData.groupSnap"
:key="index">
<uni-forms-item label="套餐名称" showRequired required>
<uni-easyinput :paddingNone="inputPaddingNone"
:placeholderStyle="placeholderStyle" :inputBorder="inputBorder"
v-model="item.title" placeholder="请输入套餐名称" />
</uni-forms-item>
<view>
<view class="font-bold">商品信息</view>
<view class="u-p-30 bg-gray u-m-t-20">
<view class="u-flex">
<view class="u-flex-1">名称</view>
<view class="u-flex-1 ">数量</view>
<view class=" ">操作</view>
</view>
<view class="u-flex u-m-t-20 u-row-between"
v-for="(product,goodsIndex) in item.goods" :key="goodsIndex"
@tap="groupSnapGoodsDel(index,goodsIndex)">
<view class="u-flex-1 u-flex u-p-r-60">
<view class="bg-fff u-flex-1 u-p-10">
{{product.name}}
</view>
</view>
<view class="u-flex-1 u-flex u-p-r-60">
<view class="bg-fff u-flex-1 u-p-10">
x1
</view>
</view>
<view class="u-flex">
<uni-icons type="minus-filled" :size="26"
:color="color.ColorRed"></uni-icons>
</view>
</view>
<view class="u-flex u-m-t-30" @tap="groupSnapAddGoods(index,item.goods)">
<uni-icons type="plus-filled" :color="color.ColorMain"
:size="26"></uni-icons>
<view class="u-m-l-16">添加商品</view>
</view>
</view>
</view>
<uni-forms-item label="几选几" showRequired required>
<uni-number-box :max="item.goods.length" :width="200" v-model="item.number"
placeholder="几选几"></uni-number-box>
</uni-forms-item>
<view class="u-flex u-m-t-30 u-m-b-20" @tap="delGroupSnap(index)">
<uni-icons type="minus-filled" :size="26" :color="color.ColorRed"></uni-icons>
<view class="u-m-l-16">删除分组</view>
</view>
</view>
</view>
<view class="bg-fff u-flex u-m-t-32 border-r-12 default-box-padding"
@tap="refChooseGoodsOpen">
<uni-icons type="plus-filled" :color="color.ColorMain" :size="26"></uni-icons>
<view class="u-m-l-16">添加分组</view>
</view>
</template>
<template v-if="FormData.typeEnum!='sku'">
<!-- <view class="u-m-t-32 u-font-32 u-m-l-10 u-m-b-32">规格属性</view> -->
<view class="block" v-for="(sku,index) in skuList.list" :key="index">
<view class="border-top-0">
<uni-forms-item label="售价" required showRequired>
<uni-easyinput :paddingNone="inputPaddingNone"
@blur="priceFormat(sku,'salePrice')" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="sku.salePrice" type="digit"
placeholder="请输入售价(元)" />
</uni-forms-item>
</view>
<uni-forms-item label="会员价(元)">
<uni-easyinput @blur="priceFormat(sku,'memberPrice')"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="sku.memberPrice" type="digit"
placeholder="请输入会员价(元)" />
</uni-forms-item>
<!-- <uni-forms-item label="成本价(元)">
<uni-easyinput @blur="priceFormat(sku,'costPrice')" :paddingNone="inputPaddingNone"
:placeholderStyle="placeholderStyle" :inputBorder="inputBorder"
v-model="sku.costPrice" type="digit" placeholder="请输入成本价(元)" />
</uni-forms-item>
<uni-forms-item label="原价(元)">
<uni-easyinput @blur="priceFormat(sku,'originPrice')"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="sku.originPrice" type="digit"
placeholder="请输入原价(元)" />
</uni-forms-item> -->
<uni-forms-item label="起售数量" required showRequired>
<uni-easyinput @blur="priceFormat(sku,'suit')" :paddingNone="inputPaddingNone"
:placeholderStyle="placeholderStyle" :inputBorder="inputBorder"
v-model="sku.suit" type="digit" placeholder="请输入起售数量" />
</uni-forms-item>
<!-- <uni-forms-item label="库存数量">
<uni-easyinput @blur="priceFormat(sku,'stockNumber')"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="sku.stockNumber" type="digit"
placeholder="请输入库存数量" />
</uni-forms-item> -->
<uni-forms-item label="分销金额">
<uni-easyinput :paddingNone="inputPaddingNone"
@blur="priceFormat(sku,'firstShared')" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="sku.firstShared" type="digit"
placeholder="请输入分销金额" />
</uni-forms-item>
<uni-forms-item label="商品条码">
<uni-easyinput disabled :paddingNone="inputPaddingNone"
:placeholderStyle="placeholderStyle" :inputBorder="inputBorder"
v-model="sku.barCode" placeholder="请输入起售数量" />
</uni-forms-item>
</view>
</template>
<template v-if="FormData.typeEnum==='group'">
<view class="block">
<view class="border-top-0">
<uni-forms-item label="使用日期说明" required showRequired>
<view class="bg-gray">
<uni-easyinput type="textarea"
:styles="{backgroundColor:'rgb(246,246,246)'}"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.notices.dateUsed"
placeholder="请输入使用日期说明" />
</view>
</uni-forms-item>
</view>
<view class="border-top-0">
<uni-forms-item label="可用时间说明" required showRequired>
<view class="bg-gray">
<uni-easyinput type="textarea"
:styles="{backgroundColor:'rgb(246,246,246)'}"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.notices.availableTime"
placeholder="请输入可用时间说明" />
</view>
</uni-forms-item>
</view>
<view class="border-top-0">
<uni-forms-item label="预约方式" required showRequired>
<view class="bg-gray">
<uni-easyinput type="textarea"
:styles="{backgroundColor:'rgb(246,246,246)'}"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.notices.bookingType"
placeholder="请输入预约方式" />
</view>
</uni-forms-item>
</view>
<view class="border-top-0">
<uni-forms-item label="退款说明" required showRequired>
<view class="bg-gray">
<uni-easyinput type="textarea"
:styles="{backgroundColor:'rgb(246,246,246)'}"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.notices.refundPolicy"
placeholder="请输入退款说明" />
</view>
</uni-forms-item>
</view>
<view class="border-top-0">
<uni-forms-item label="团购价说明">
<view class="bg-gray">
<uni-easyinput type="textarea"
:styles="{backgroundColor:'rgb(246,246,246)'}"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.notices.groupPurInfo"
placeholder="请输入团购价说明" />
</view>
</uni-forms-item>
</view>
<view class="border-top-0">
<uni-forms-item label="门市价/划线价说明">
<view class="bg-gray">
<uni-easyinput type="textarea"
:styles="{backgroundColor:'rgb(246,246,246)'}"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.notices.marketPriceInfo"
placeholder="请输入门市价/划线价说明" />
</view>
</uni-forms-item>
</view>
<view class="border-top-0">
<uni-forms-item label="折扣说明">
<view class="bg-gray">
<uni-easyinput type="textarea"
:styles="{backgroundColor:'rgb(246,246,246)'}"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.notices.discountInfo"
placeholder="请输入折扣说明" />
</view>
</uni-forms-item>
</view>
<view class="border-top-0">
<uni-forms-item label="发票说明">
<view class="bg-gray">
<uni-easyinput type="textarea"
:styles="{backgroundColor:'rgb(246,246,246)'}"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.notices.invoiceInfo"
placeholder="请输入发票说明" />
</view>
</uni-forms-item>
</view>
<view class="border-top-0">
<uni-forms-item label="使用规则">
<view class="bg-gray">
<uni-easyinput type="textarea"
:styles="{backgroundColor:'rgb(246,246,246)'}"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.notices.usageRules"
placeholder="请输入使用规则" />
</view>
</uni-forms-item>
</view>
<view class="border-top-0">
<uni-forms-item label="排序">
<uni-easyinput @blur="priceFormat(FormData,'sort')"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.sort" type="digit"
placeholder="请输入排序" />
</uni-forms-item>
</view>
</view>
</template>
<template v-if="FormData.typeEnum!='group'">
<view class="block ">
<!-- <view class="border-top-0">
<uni-forms-item label="上架区域">
<view class="u-flex">
<view class="u-m-r-30">
<my-radio text="收银台" v-model="FormData.isShowCash"></my-radio>
</view>
<my-radio text="小程序商城" v-model="FormData.isShowMall"></my-radio>
</view>
</uni-forms-item>
</view> -->
<view class="border-top-0">
<uni-forms-item label="">
<view class="u-flex u-row-between">
<view class="label-title">上架</view>
<my-switch disabled :openDisabledClass="false" @click="isGroundingChange"
v-model="FormData.isGrounding"></my-switch>
</view>
</uni-forms-item>
</view>
<uni-forms-item label="">
<view class="u-flex u-row-between">
<view class="label-title">库存开关</view>
<my-switch v-model="FormData.isStock"></my-switch>
</view>
<view class="color-999 u-m-t-16 u-font-24">注:关闭则不计算出入库数据</view>
</uni-forms-item>
<template v-if="FormData.isStock">
<view class="u-relative">
<uni-forms-item label="库存数量">
<uni-easyinput @blur="priceFormat(FormData,'stockNumber')"
:paddingNone="inputPaddingNone" :disabled="disabledStock"
:placeholderStyle="placeholderStyle" :inputBorder="inputBorder"
v-model="FormData.stockNumber" type="digit" placeholder="请输入库存数量" />
</uni-forms-item>
<view class="u-absolute position-all" v-if="disabledStock"
@click="canEditGoodsStock(true)">
</view>
</view>
</template>
<uni-forms-item label="">
<view class="u-flex u-row-between">
<view class="label-title">设为推荐</view>
<my-switch v-model="FormData.isHot"></my-switch>
</view>
</uni-forms-item>
<!-- <uni-forms-item label="">
<view class="u-flex u-row-between">
<view class="label-title">标签打印</view>
<my-switch v-model="FormData.enableLabel"></my-switch>
</view>
<view class="color-999 u-m-t-16 u-font-24">开启后: 收银完成后会自动打印对应数量的标签数</view>
</uni-forms-item> -->
<uni-forms-item label="打包费">
<uni-easyinput @blur="priceFormat(FormData,'packFee')"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.packFee" type="digit"
placeholder="请输入打包费" />
</uni-forms-item>
<!-- <uni-forms-item label="虚拟销量">
<uni-easyinput @blur="priceFormat(FormData,'baseSalesNumber')"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.baseSalesNumber" type="digit"
placeholder="请输入虚拟销量" />
</uni-forms-item> -->
<template v-if="option.type==='edit'">
<uni-forms-item label="排序">
<uni-easyinput @blur="priceFormat(FormData,'sort')"
:paddingNone="inputPaddingNone" :placeholderStyle="placeholderStyle"
:inputBorder="inputBorder" v-model="FormData.sort" type="digit"
placeholder="请输入排序" />
</uni-forms-item>
</template>
</view>
</template>
</uni-forms>
<view style="height: 200rpx;"></view>
<view style="padding-left: 110rpx;padding-right: 110rpx;" class="u-m-t-20"
v-if="option.type==='edit'" @click="delModelShow">
<my-button bgColor="#F9F9F9" shape="circle" type="cancel">
<view class="color-red">删除该商品</view>
</my-button>
</view>
<view class="bootom">
<view class="save-btn-box">
<my-button fontWeight="700" shape="circle" @tap="save">保存</my-button>
</view>
</view>
</view>
</template>
<template v-if="tabsCurrent===1">
<edit-haocai @updateGoods="updateGoodsDetail" :goods="FormData"
@cancel="changeTabsCurrent(0)"></edit-haocai>
</template>
</view>
<my-model @confirm="modelConfirm" :showIcon="modelProps.showIcon" ref="model" :desc="modelProps.desc">
<template #btn>
<slot name="btn">
<view class="u-flex u-row-center u-p-b-40">
<my-button @click="closeModel" :width="500">确定</my-button>
</view>
</slot>
</template>
</my-model>
<!-- 删除弹窗 -->
<my-model @confirm="delmodelConfirm" ref="delModel" desc="确认删除">
</my-model>
<!-- 选择商品 -->
<choose-goods ref="refChooseGoods" @confirm="refChooseGoodsConfirm"
:category="pageData.category"></choose-goods>
<!-- 更多操作 -->
<my-action-sheet @itemClick="actionSheetClick" ref="refMoreSheet" :list="actionSheet.list"></my-action-sheet>
</view>
</template>
<script setup>
import {
ColorMain
} from '@/commons/color.js'
import dayjs from "dayjs";
import {
formatPrice
} from "@/commons/utils/format.js";
import go from '@/commons/utils/go.js';
import color from '@/commons/color.js';
import chooseGoods from './components/choose-goods'
import editHaocai from './components/edit-haocai.vue'
import chooseGroupCategory from './components/choose-coupon-category'
import infoBox from "@/commons/utils/infoBox.js"
import {
hasPermission
} from '@/commons/utils/hasPermission.js';
import {
$types,
$defaultSku
} from '@/commons/goodsData.js'
import {
$getProductDetail,
$tbShopCategory,
$tbShopUnit,
$addProduct,
$updateProduct,
$delProduct,
$productSpec,
$updateProductStatus,
$updateGrounding,
$goodsIsHot,
$tbProskuConV2,
$updateProductData
} from '@/http/yskApi/goods.js'
import {
$getProductSku
} from '@/http/yskApi/sku.js'
import {
onLoad,
onShow,
onReady
} from '@dcloudio/uni-app';
import {
computed,
onBeforeUnmount,
onUnmounted,
reactive,
ref,
watch,
nextTick
} from 'vue';
const imageStyles = reactive({
width: 82,
height: 82,
border: {
radius: '4px'
}
})
async function upDateGoods(par) {
const res = await $updateProductData([{
id: FormData.id,
isSku: 0,
shopId: uni.getStorageSync('shopId'),
...par
}])
uni.showToast({
title: '修改成功',
icon: 'none'
})
}
async function isPauseSaleChange(e) {
if (option.type == 'add') {
FormData.isPauseSale = FormData.isPauseSale ? 0 : 1
return
}
const res = await hasPermission('允许售罄商品')
if (!res) {
return
}
// await upDateGoods({
// key: 'pauseSale',
// value: FormData.isPauseSale ? 0 : 1
// })
FormData.isPauseSale = FormData.isPauseSale ? 0 : 1
}
async function isGroundingChange(e) {
if (option.type == 'add') {
FormData.isGrounding = FormData.isGrounding ? 0 : 1
return
}
const res = await hasPermission('允许上下架商品')
if (!res) {
return
}
// await upDateGoods({
// key: 'grounding',
// value: FormData.isGrounding ? 0 : 1
// })
FormData.isGrounding = FormData.isGrounding ? 0 : 1
}
function toRecoders() {
go.to('PAGES_PRODUCT_INVOICING_LIST', {
productId: FormData.id
})
}
function toCheck() {
go.to('PAGES_PRODUCT_INVOICING_CHECK', {
productId: $goodsData.id,
name: $goodsData.name,
skuId: $goodsData.skuList[0].id
})
}
function skuToCheck(item) {
go.to('PAGES_PRODUCT_INVOICING_CHECK', {
productId: $goodsData.id,
name: $goodsData.name,
skuId: $goodsData.skuList[0].id,
stock: item.stockNumber,
price: item.salePrice
})
}
// 更新库存设置
function updateProductStatus(id, key) {
if (key === 'isGrounding') {
return $updateGrounding({
skuId: id,
isGrounding: FormData[key] === 1
}).then(res => {
infoBox.showSuccessToast('更新成功')
})
}
const updateKey = key.replace('is', '')
$updateProductStatus({
updateKey: updateKey.substr(0, 1).toLowerCase() + updateKey.substr(1, updateKey.length),
updateValue: FormData[key],
targetId: id
}).then(res => {
infoBox.showSuccessToast('更新成功')
})
}
// 选择团购券分类
const refChooseGroupCategory = ref(null)
function refChooseCouponCategoryConfirm(arr) {
arr = arr.map(v => {
return {
name: v.name,
id: v.id
}
})
refChooseGroupCategoryClose()
FormData.groupCategoryId = arr
}
function groupCategoryIdDel(index) {
FormData.groupCategoryId.splice(index, 1)
}
function refChooseGroupCategoryOpen() {
refChooseGroupCategory.value.open()
}
function refChooseGroupCategoryClose() {
refChooseGroupCategory.value.close()
}
//套餐商品选择
const refChooseGoods = ref(null)
let groupSnapIndex = undefined
function groupSnapAddGoods(index, arr) {
console.log(arr);
groupSnapIndex = index
refChooseGoods.value.open(arr.map(v => v.id))
}
function refChooseGoodsOpen() {
groupSnapIndex = undefined
refChooseGoods.value.open()
}
function refChooseGoodsClose() {
refChooseGoods.value.close()
}
function refChooseGoodsConfirm(arr) {
console.log(arr);
refChooseGoodsClose()
arr = arr.map(v => {
const {
id,
name,
groupNum,
unitName,
categoryId
} = v
return {
id,
name,
groupNum,
unitName,
categoryId
}
})
if (groupSnapIndex !== undefined) {
return FormData.groupSnap[groupSnapIndex].goods = arr
}
FormData.groupSnap.push({
title: '',
number: 1,
goods: arr
})
}
function groupSnapGoodsDel(index, goodsIndex) {
FormData.groupSnap[index].goods.splice(goodsIndex, 1)
}
function delGroupSnap(index) {
FormData.groupSnap.splice(index, 1)
}
function back() {
uni.navigateBack()
}
// 商品图片组件
const refFile = ref(null)
//表单相关事件
function changeFormData(key, val) {
FormData[key] = val
}
function unitIdChange(e) {
console.log(e);
FormData.unitName = e.detail.value[0].text
}
function specIdChange(e) {
}
//number类型数据限制
function priceFormat(item, key) {
nextTick(() => {
const min = 0;
const max = 100000000;
console.log(item[key]);
const newval = formatPrice(item[key], min, max, true)
console.log(newval)
if (typeof newval !== 'number') {
item[key] = newval.value
uni.showToast({
title: `请输入${min}${max}范围内的数字`,
icon: 'none'
})
} else {
item[key] = newval
}
console.log(item);
})
}
// 库存模式
const InventoryModeData = [{
text: '传统模式',
value: 0
},
{
text: '进销存模式',
value: 1
}
]
const InventoryReset = [{
text: '不重置',
value: 0
},
{
text: '每天重置',
value: 1
}
]
const model = ref(null)
const delModel = ref(null)
const rules = {
images: {
rules: [{
validateFunction: function(rule, value, data, callback) {
console.log(value);
if (value.length < 1) {
callback('请上传商品图片')
}
return true
}
}]
},
name: {
rules: [{
required: true,
errorMessage: '请输入商品名称',
},
{
minLength: 1,
maxLength: 40,
errorMessage: '商品名称长度在 {minLength} 到 {maxLength} 个字符',
}
]
},
categoryId: {
rules: [{
required: true,
errorMessage: '请选择商品分类',
}]
},
floorPrice: {
rules: [{
required: true,
errorMessage: '请填写商品底价',
}]
}
}
let modelProps = {
desc: '1为只能预约当天大于1为今天及往后几天最多15天',
showIcon: false
}
function delmodelConfirm() {
console.log('delmodelConfirm');
$delProduct([option.productId]).then(res => {
uni.showToast({
icon: 'none',
title: '删除成功'
})
setTimeout(() => {
uni.$emit('del:productIndex', option.productId)
go.back()
}, 500)
})
}
function delModelShow() {
delModel.value.open()
}
function showModel(type) {
if (type === 'help') {
modelProps = {
desc: '1为只能预约当天大于1为今天及往后几天最多15天',
showIcon: false
}
model.value.open()
}
if (type === 'stockTips') {
modelProps = {
desc: '请先保存商品基础信息',
showIcon: false
}
model.value.open()
}
}
function modelConfirm() {
console.log('modelConfirm');
}
function closeModel() {
model.value.close()
if (tabsCurrent.value === 1) {
go.back()
}
}
// 售卖方式时间
const DeliveryTime = [{
value: '1',
name: '时间'
}, {
value: '2',
name: '付款'
}]
//返回当前时间多少天后的时间戳
function nowDateAfterDayTemp(day) {
const daytem = 1000 * 60 * 60 * 24
return Date.now() + daytem * day
}
const limitDay = 90
const limitDayTime = nowDateAfterDayTemp(limitDay)
let DeliveryTimeCurrent = ref(0)
function DeliveryTimeChange(e) {
console.log(e.detail.value);
}
const tabsList = ['基础设置', '耗材绑定']
let tabsCurrent = ref(0)
function changeTabsCurrent(newval) {
tabsCurrent.value = newval
}
const Forms = ref(null)
// 表单样式
//可以不使用ref但是小程序一堆wraning 改为了ref
const placeholderStyle = ref('font-size:28rpx;')
const inputPaddingNone = ref(true)
//规格模板类型
const specificationMode = [{
text: '普通',
value: '普通'
},
{
text: '图片式',
value: '图片式'
},
{
text: '规格模版',
value: '规格模版'
}
]
let myTest = ref(false)
//表单边框
const inputBorder = ref(false)
//商品表单数据
// const FormData = reactive({
// images: [],
// name: '',
// goodsCode: '',
// shortTitle: '',
// goodsDetail: '',
// goodsDetail: '',
// categoryId: '',
// salesMethod: 0,
// startTime: '',
// isStock: false,
// isVipDiscount: false,
// packagingFee: 0,
// weight: 0,
// integral: 0,
// openDailySalesLimit: false,
// dailySalesLimit: '',
// openOrderBuyLimit: false,
// orderBuyLimit: 0,
// openEveryoneBuyLimit: false,
// everyoneBuyLimit: 0,
// minBuyLimit: 0,
// specificationsPattern: '',
// specificationsGroup: '',
// paySuccessAfterDay: '',
// openDiscount: false,
// discountPrice: 0,
// isVipDiscount: false,
// vipPrice: 0,
// packagingFee: 0,
// virtualSales: 0,
// isRecommend: false,
// timer: [],
// isShowCash: 1,
// isShowMall: 1,
// })
const FormData = reactive({
specsInfoName: '',
id: "",
typeEnum: "normal",
specificationsGroup: '',
name: "",
shortTitle: "", //商品介绍
unitId: "",
unitName: "",
categoryId: "", // 商品分类id
coverImg: "",
images: [],
shopId: uni.getStorageSync('shopId'),
lowPrice: "",
skuList: [],
isShowMall: 1,
isShowCash: 1,
isStock: 0,
isStock: 0,
isHot: 0,
packFee: 0,
specId: "",
// baseSalesNumber: 0,
sort: 0,
groupSnap: [],
specInfo: [],
selectSpec: [],
specTableHeaders: [],
skuSnap: "",
groupCategoryId: [],
isGrounding: 1,
stockNumber: 0,
notices: {
availableTime: "",
bookingType: "",
dateUsed: "",
discountInfo: "",
groupPurInfo: "",
invoiceInfo: "",
marketPriceInfo: "",
platformTips: "",
refundPolicy: "",
usageRules: ""
}
})
const skuList = reactive({
list: [{
...$defaultSku,
barCode: `${uni.getStorageSync("shopId")}${dayjs().valueOf()}`
}]
})
watch(() => skuList.list, (newval) => {
console.log(newval);
})
//库存表单数据
const stockData = reactive({
inventoryMode: 0,
isStock: false,
stockNumbers: 0,
inventoryReset: 0
})
//售卖方式
const salesMethod = reactive({
list: ['现货', '预售', '仅展示商品'],
defaultIndex: 0,
})
function salesMethodChange(e) {
FormData.salesMethod = e.detail.value
salesMethod.defaultIndex = e.detail.value
}
// 判断是否为一个空对象
function isEmpty(obj) {
return obj && JSON.stringify(obj) !== '{}'
}
let option = reactive({
type: 'add',
productId: ''
})
let $goodsData = {}
function getGoodsDetail() {
$getProductDetail(option.productId).then(res => {
res.images = res.images.map(v => {
return {
url: v
}
})
for (let i in res.conInfos) {
const con = res.conInfos[i]
const item = res.skuList.find(v => v.id == con.productSkuId)
if (item) {
if (item.hasOwnProperty('haoCaiList')) {
item.haoCaiList.push(con)
} else {
item.haoCaiList = [con]
}
}
}
res.skuList = (res.skuList.length ? res.skuList : [])
let specsInfoName = ''
for (let i in res.specsInfo) {
specsInfoName = i
}
res.specsInfoName = specsInfoName
$goodsData = res
skuList.list = res.skuList
Object.assign(FormData, res)
//多规格
if (res.typeEnum === 'sku') {
const selectSpec = JSON.parse(res.selectSpec)
// const specInfo=JSON.parse(res.specInfo)
console.log(selectSpec);
// console.log(specInfo);
const specMap = selectSpec.reduce((prve, cur) => {
cur.value.map(v => {
prve[typeof v === 'string' ? v : v.text] = cur.name
})
return prve
}, {})
console.log(specMap);
FormData.specificationsGroup = {
specId: res.specId,
selectSpec: selectSpec.map(s => {
return {
...s,
value: s.value.map(v => {
return typeof v === 'string' ? {
text: v,
value: v
} : v
})
}
}),
result: res.skuList.map(v => {
const names = v.specSnap.split(',').reduce((prve, cur) => {
const key = specMap[cur]
prve[key] = cur
return prve
}, {})
return {
skus: {
...v
},
names,
specSnap: v.specSnap,
coverImg: v.coverImg
}
}),
specList: [],
}
} else {
// 单规格
}
})
}
//获取分类
function getCategory() {
$tbShopCategory({
page: 0,
size: 200
}).then(res => {
pageData.category = res.content.reduce((prve, cur) => {
prve.push(...[{
...cur,
name: '' + cur.name
}, ...cur.childrenList.map(v => {
return {
...v,
name: '' + v.name
}
})])
return prve
}, [])
// pageData.category = res.content.map(v => {
// return {
// ...v,
// children: v.childrenList,
// childrenList: undefined,
// }
// })
})
}
//默认值表单初始化
function defaultValueInit() {
if (option.productId === '') {
// FormData.typeEnum = pageData.types[0].value
FormData.barCode = `${uni.getStorageSync('shopId')}${dayjs().valueOf()}`
}
}
//获取单位数据
function getTbShopUnit() {
$tbShopUnit({
page: 0,
size: 200,
sort: "id"
}).then(res => {
pageData.units = res.content.map(v => {
return {
...v,
children: v.childrenList,
childrenList: undefined,
}
})
})
}
//获取规格数据
function getTbProductSpec() {
$productSpec.get({
page: 0,
size: 200,
sort: "id"
}).then(res => {
pageData.specList = res.content.map(v => {
return {
...v,
children: v.childrenList,
childrenList: undefined,
}
})
})
}
//页面全部数据
const pageData = reactive({
// 商品类型
// types: $types,
types: [{
name: '单规格',
value: 'normal'
},
{
name: '多规格',
value: 'sku'
}
],
// 单位
units: [],
// 分类
category: [],
// 规格
specList: [],
//库存
skuList: []
})
//查询商品库存
function getProductSku() {
$getProductSku(option.productId).then(res => {
pageData.skuList = res
})
}
function updateGoodsDetail() {
getGoodsDetail()
// getProductSku()
}
onLoad((params) => {
if (isEmpty(params)) {
option.type = params.type ? params.type : 'add'
option.productId = params.productId
// getGoodsDetail()
// getProductSku()
}
canEditGoodsCategory()
uni.setNavigationBarTitle({
title: option.type === 'add' ? '添加商品' : '编辑商品'
})
if (option.type === 'edit') {
getGoodsDetail()
// getProductSku()
}
defaultValueInit()
getCategory()
getTbShopUnit()
getTbProductSpec()
})
onShow(() => {
// if (option.type === 'edit') {
// getGoodsDetail()
// getProductSku()
// }
})
function openDiscountChange() {
}
let timer = null
function settimeoutBack(time) {
clearTimeout(timer)
timer = setTimeout(() => {
uni.$emit('update:productIndex')
uni.navigateBack()
}, time)
}
//保存
async function save() {
const bol = await hasPermission('允许修改商品')
if (!bol) {
return
}
Forms.value.validate().then(res => {
const {
typeEnum,
groupCategoryId
} = FormData
if (typeEnum === 'group' && !groupCategoryId.length) {
return infoBox.showToast('请选择团购券分类')
}
// if(typeEnum==='sku'){
// return infoBox.showErrorToast('请选择规格')
// }
const images = refFile.value.getFileList()
if (images.length <= 0) {
return infoBox.showToast('请上传商品图片')
}
const skuSnap = []
let submitSkuList = skuList.list || []
if (option.type == 'edit') {
submitSkuList = submitSkuList.map(v => {
return {
...v,
productId: FormData.id,
shopId: uni.getStorageSync('shopId')
}
})
}
// if(typeEnum!=$goodsData.typeEnum){
// if(typeEnum=='normal'){
// submitSkuList = skuList.list;
// }else{
// submitSkuList = skuList.list;
// }
// }else{
// submitSkuList = skuList.list;
// }
if (FormData.specificationsGroup) {
for (let i of FormData.specificationsGroup.selectSpec) {
if (i.selectSpecResult.length) {
skuSnap.push({
name: i.name,
value: i.selectSpecResult.join(',')
})
}
}
}
console.log(FormData.specificationsGroup);
const selectSpec = FormData.typeEnum != 'sku' ? '[]' : JSON.stringify((FormData.specificationsGroup
.selectSpec || []).map(spe => {
return {
...spe,
value: spe.value.map(v => {
return typeof v === 'string' ? v : v.text || v.value
})
}
}))
const lowPrice = submitSkuList[0] ? submitSkuList[0].salePrice : FormData.salePrice
// const lowPrice = submitSkuList[0] ? submitSkuList[0].salePrice : FormData.salePrice
const suit = submitSkuList[0] ? submitSkuList[0].suit : 0
const stockNumber = FormData.stockNumber
if (typeEnum == 'normal') {
if (lowPrice === '') {
return infoBox.showToast('请输入售价')
}
if (lowPrice === '') {
return infoBox.showToast('请输入售价')
}
if (suit <= 0) {
return infoBox.showToast('起售数量不能小于0')
}
if (stockNumber === '') {
return infoBox.showToast('请输入库存数量!')
}
}
const submitData = {
...FormData,
images: images,
coverImg: images[0] || '',
skuList: submitSkuList,
specInfo: JSON.stringify(submitSkuList),
lowPrice,
specificationsGroup: undefined,
selectSpec,
skuSnap: JSON.stringify(skuSnap)
}
//编辑
if (option.type === 'edit') {
return $updateProduct(submitData).then(res => {
$updateProductData([{
id: FormData.id,
isSku: 0,
shopId: uni.getStorageSync('shopId'),
key: 'grounding',
value: FormData.isGrounding
}]).then(() => {
infoBox.showSuccessToast('更新成功')
settimeoutBack(1500)
})
})
}
submitData.selectSpec =
$addProduct(submitData).then(res => {
infoBox.showSuccessToast('添加成功')
settimeoutBack(1500)
})
}).catch(err => {
console.log(err);
})
}
const returnSpecificationsGroup = computed(() => {
if (!FormData.specificationsGroup.length) {
return '添加规格组'
}
if (FormData.specificationsGroup.length) {
let result = FormData.specificationsGroup.reduce((prve, cur) => {
return prve + cur.GroupName + '、'
}, '')
return result.replace(/.$/, "")
}
})
/**
* 监听规格保存,拿到数据
*/
const newSkuList = reactive({
list: []
})
function watchSpecificationsSave() {
uni.$off('emitspecificationsSave')
uni.$on('emitspecificationsSave', function(data) {
FormData.specificationsGroup = data
FormData.specId = data.specId
FormData.specsInfoName=data.specsInfoName
skuList.list = data.result.map(v => {
return {
...v.skus,
...v.names,
specSnap: v.specSnap,
coverImg: v.coverImg || ''
}
})
newSkuList.list = data.result.map(v => {
return {
...v.skus,
...v.names,
specSnap: v.specSnap,
coverImg: v.coverImg || ''
}
})
console.log(skuList.list);
})
}
function toGroup() {
// go.to('PAGES_PRODUCT_GUIGE_CHOOSE', {
// productId: option.productId
// })
}
function toGuige() {
uni.setStorageSync('guige', FormData.specificationsGroup)
go.to('PAGES_PRODUCT_GUIGE_CHOOSE', {
emitName: 'emitspecificationsSave',
type: option.type,
productId: option.productId
})
// go.to('PAGES_PRODUCT_GUIGE_ADD', {
// emitName: 'emitspecificationsSave',
// })
}
/**
* 监听定时器保存,拿到数据
* @param {Boolean} open //控制开启或关闭监听
*/
function watchTimerSave(open = true) {
if (open) {
uni.$on('timerSave', function(timer) {
console.log('timerSave get');
console.log(timer);
FormData.timer = timer
})
} else {
uni.$off('timerSave', function(data) {
console.log('timerSave remove');
})
}
}
function toTimerPage() {
uni.setStorageSync('timer', FormData.timer)
go.to('PAGES_PRODUCT_TIMER')
}
function returnTimerText() {
return FormData.timer.length ? `当前有${FormData.timer.length}个定时器` : '没有定时器'
}
// 更多操作
const refMoreSheet = ref(null)
let selItem = {
data: '',
index: ''
}
const actionSheet = reactive({
list: ['库存记录', '库存盘点']
})
function moreShow(item, index) {
refMoreSheet.value.open()
selItem.data = item
selItem.index = index
}
function actionSheetClick(index) {
console.log(index);
if (index === 0) {
return go.to('PAGES_PRODUCT_INVOICING_LIST', {
productId: FormData.id
})
}
if (index === 1) {
return
}
}
watch(() => FormData.typeEnum, (newval) => {
if (option.type == 'edit') {
FormData.specId = newval == 'normal' ? '' : ($goodsData.specId || '')
if (newval == $goodsData.typeEnum) {
skuList.list = $goodsData.skuList
} else {
if (newval == 'normal') {
skuList.list = [{
...$defaultSku,
productId: FormData.id,
shopId: uni.getStorageSync('shopId'),
barCode: `${uni.getStorageSync("shopId")}${dayjs().valueOf()}`
}]
} else {
skuList.list = []
}
}
} else {
FormData.specId = ''
if (newval == 'normal') {
skuList.list = [{
...$defaultSku,
shopId: uni.getStorageSync('shopId'),
barCode: `${uni.getStorageSync("shopId")}${dayjs().valueOf()}`
}]
} else {
skuList.list = []
}
}
})
/**
* 权限start
*/
// 允许修改商品库存
let disabledStock = ref(false)
async function canEditGoodsStock(tips = false) {
console.log(tips);
if (option.type === 'edit') {
const res = await hasPermission({
text: '允许修改商品库存',
tips: tips
})
disabledStock.value = !res
}
}
watch(() => FormData.isStock, (newval) => {
if (newval) {
canEditGoodsStock()
}
})
// 允许修改商品分类
let disabledChangeCategory = ref(false)
async function canEditGoodsCategory(tips = false) {
if (option.type === 'edit') {
const res = await hasPermission({
text: '允许修改分类',
tips
})
disabledChangeCategory.value = !res
}
}
/**
* 权限end
*/
watch(() => pageData.types, (newval) => {
Forms.value.setRules(rules)
})
onShow(() => {
watchSpecificationsSave()
})
onReady(() => {
Forms.value && Forms.value.setRules(rules)
})
onBeforeUnmount(() => {
clearTimeout(timer)
})
</script>
<style scoped>
page {
background: #F9F9F9;
}
</style>
<style lang="scss" scoped>
.top {
position: fixed;
// left: 28rpx;
// right: 28rpx;
// /* #ifdef H5 */
// top: calc(44px + 24rpx);
// /* #endif */
// /* #ifndef H5 */
// top: calc(var(--status-bar-height) + 24rpx);
// /* #endif */
// z-index: 999;
}
::v-deep .uni-forms-item--border {
padding-top: 12px;
padding-bottom: 12px;
}
.stick-bottom {
top: 0;
z-index: 10;
}
::v-deep .stock .uni-data-checklist .checklist-group .checklist-box {
margin-right: 30rpx;
}
.stock .btns {
position: fixed;
bottom: 100rpx;
left: 110rpx;
right: 110rpx;
display: flex;
flex-direction: column;
gap: 20rpx;
}
.u-p-l-100 {
padding-left: 100rpx;
}
.bg-gray {
background: #F9F9F9;
padding: 0 20rpx;
}
.safe-page {
background: #F9F9F9;
}
.my-switch {
transform: scale(0.7);
}
.label-title {
font-size: 28rpx;
font-weight: bold;
font-family: Source Han Sans CN, Source Han Sans CN;
}
.lh40 {
line-height: 40rpx;
}
.bootom {
position: fixed;
left: 110rpx;
right: 110rpx;
bottom: 140rpx;
padding-bottom: env(safe-area-inset-bottom);
}
.box {
margin-top: 32rpx;
font-size: 28rpx;
.block {
background: #FFFFFF;
border-radius: 8rpx 18rpx 8rpx 18rpx;
padding: 12rpx 24rpx;
margin-bottom: 32rpx;
}
}
::v-deep.uni-forms-item {
align-items: inherit;
}
::v-deep .uni-forms-item .uni-forms-item__label {
text-indent: 0;
font-size: 28rpx !important;
font-weight: bold;
color: #333;
}
::v-deep .stock .uni-forms-item {
min-height: initial !important;
}
::v-deep .bg-gray .uni-forms-item {
background-color: transparent !important;
}
::v-deep .border-top-0 .uni-forms-item.is-direction-top {
border-color: transparent !important;
}
::v-deep .uni-data-checklist .checklist-group .checklist-box .checklist-content .checklist-text {
font-size: 28rpx;
color: #333;
}
::v-deep .none-label .uni-forms-item.is-direction-top {
padding: 0 !important;
min-height: initial !important;
}
::v-deep .uni-easyinput__content-input {
height: inherit;
}
::v-deep .none-label .uni-forms-item .uni-forms-item__label {
padding: 0 !important;
}
.save-btn {
background-color: $my-main-color;
color: #fff;
border-radius: 100rpx;
font-size: 28rpx;
}
.btn-hover-class {
opacity: .6;
}
.zuofa {
padding: 28rpx 0;
background: #F9F9F9;
padding-left: 42rpx;
border-radius: 14rpx 14rpx 14rpx 14rpx;
}
::v-deep .uni-input-placeholder {
font-size: 28rpx;
}
.types {
.item {
padding: 6rpx 20rpx;
border: 1px solid #bbb;
border-radius: 8rpx;
margin-right: 30rpx;
margin-bottom: 20rpx;
text-align: center;
position: relative;
.gou {
display: none;
position: absolute;
right: 0;
top: 0;
background-color: $my-main-color;
width: 32rpx;
height: 32rpx;
clip-path: polygon(100% 0, 0 0, 100% 100%);
}
}
.active {
border-color: $my-main-color;
.gou {
display: flex;
}
.title {
color: $my-main-color;
}
}
&.disabled {
position: relative;
&::after {
position: absolute;
content: '';
display: block;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.item {
background-color: #f9f9f9;
border-color: #eee;
&.active {
border-color: rgba(49, 138, 254, .3);
}
.gou {
opacity: .5;
}
.title {
color: #999;
}
}
}
}
</style>