Files
cashier_app/pageProduct/add-Product/add-Product.vue
2025-12-25 15:38:00 +08:00

1676 lines
41 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 typeEnum">
<uni-forms-item label="商品类型" required showRequired>
<up-radio-group v-model="FormData.type" @change="changeFormDatatype">
<view style="display: flex; flex-wrap: wrap; justify-content: flex-start">
<view v-for="(item, index) in pageData.types" :key="index" style="margin-right: 30rpx">
<up-radio :label="item.name" :name="item.value"></up-radio>
</view>
</view>
</up-radio-group>
</uni-forms-item>
</view>
<view class="" v-if="FormData.type === 'package'">
<uni-forms-item label="套餐商品">
<up-radio-group v-model="FormData.groupType" placement="row">
<up-radio
:custom-style="{ marginRight: '30px' }"
v-for="(item, index) in packageType.list"
:key="index"
:label="item.name"
:name="item.value"
></up-radio>
</up-radio-group>
</uni-forms-item>
</view>
<uni-forms-item required name="name" label="商品名称" showRequired>
<uni-easyinput
:paddingNone="inputPaddingNone"
:placeholderStyle="placeholderStyle"
:inputBorder="inputBorder"
v-model="FormData.name"
placeholder="请输入商品名称"
/>
</uni-forms-item>
<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>
<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>
<view class="">
<uni-forms-item label="单位" required showRequired name="units">
<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.type === 'package'">
<view class="border-top" v-if="FormData.proGroupVo">
<view
class=""
v-if="
(FormData.groupType == 1 && FormData.proGroupVo.length) ||
(FormData.groupType == 0 && FormData.proGroupVo.length && FormData.proGroupVo[0].goods.length)
"
>
<view class="border-bottom u-p-b-32" v-for="(item, index) in FormData.proGroupVo" :key="index">
<view class="u-p-t-24" v-if="FormData.groupType == 1">
<view class="u-flex u-row-between">
<view class="u-flex">
<text class="color-red">*</text>
<text class="font-bold">套餐名称</text>
</view>
<view class="u-flex color-999" @tap="delproGroupVo(index)">
<uni-icons type="minus-filled" :size="16" :color="$utils.ColorRed"></uni-icons>
<view class="u-m-l-10">删除套餐组</view>
</view>
</view>
<view class="u-flex u-m-t-16">
<up-input v-model="item.title" placeholder="请输入套餐名称"></up-input>
<view class="u-flex color-main u-font-24 u-m-l-24" @click="proGroupVoAddGoods(index, item.goods)">
<up-icon name="plus" :size="12" :color="$utils.ColorMain"></up-icon>
<view class="font-bold">添加商品</view>
</view>
</view>
</view>
<view class="u-m-t-24" v-if="item.goods.length > 0">
<!-- <view class="font-bold">商品信息</view> -->
<view class="u-font-24 table">
<view class="u-flex title">
<view class="u-flex-1">名称</view>
<view class="u-flex-1 u-text-center">规格</view>
<view class="u-flex-1 u-text-center">价格</view>
<view class="u-flex-1 u-text-right">
<view class="u-p-r-40">数量</view>
</view>
</view>
<view class="u-flex row u-p-24 u-row-between" v-for="(product, goodsIndex) in item.goods" :key="goodsIndex">
<view class="u-flex u-flex-1">
<view class=" ">
{{ product.name || product.proName }}
</view>
</view>
<view class="u-flex u-row-center u-flex-1">
<view @click="refChooseGuigeOpen(product.skuList, index, goodsIndex)" class="">
<template v-if="!product.skuName && product.type == 'sku'">
<up-button type="primary" size="mini">设置规格</up-button>
</template>
<template v-else>
<text class="color-main">{{ product.skuName }}</text>
</template>
</view>
</view>
<view class="u-flex u-flex-1 u-row-center">
<view class="u-text-center">
{{ product.lowPrice || product.price }}
</view>
</view>
<view class="u-flex u-text-right u-flex-1 u-row-right">
<view class="u-flex u-p-r-30">
<up-number-box :button-size="14" integer v-model="product.number">
<template #minus>
<view class="minus">
<up-icon name="minus" size="12"></up-icon>
</view>
</template>
<template #plus>
<view class="plus">
<up-icon name="plus" size="12"></up-icon>
</view>
</template>
</up-number-box>
</view>
<up-icon @click="proGroupVoGoodsDel(index, goodsIndex)" size="14" name="trash" :color="$utils.ColorMain"></up-icon>
</view>
</view>
</view>
</view>
<template v-if="FormData.groupType == 1">
<view class="u-m-t-24">
<text class="color-red">*</text>
<text class="font-bold">几选几</text>
</view>
<view class="u-flex u-m-t-16">
<uni-number-box :min="1" :max="item.goods.length" :width="200" v-model="item.number" placeholder="几选几"></uni-number-box>
</view>
</template>
</view>
</view>
<template v-if="FormData.groupType == 1">
<view class="bg-fff u-flex u-p-t-24 u-p-b-24 border-r-12" @tap="proGroupVoPush">
<uni-icons type="plus-filled" :color="$utils.ColorMain" :size="20"></uni-icons>
<view class="u-m-l-16">添加套餐组</view>
</view>
</template>
<template v-else>
<view class="bg-fff u-flex u-p-t-24 u-p-b-24 border-r-12" @tap="proGroupVoAddGoods()">
<uni-icons type="plus-filled" :color="$utils.ColorMain" :size="20"></uni-icons>
<view class="u-m-l-16">添加商品</view>
</view>
</template>
</view>
</template>
<view class="">
<uni-forms-item label="商品描述">
<uni-easyinput
:paddingNone="inputPaddingNone"
:placeholderStyle="placeholderStyle"
type="textarea"
v-model="FormData.shortTitle"
placeholder="请填写商品简述"
/>
</uni-forms-item>
</view>
</view>
<template v-if="FormData.type == '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.specName">{{ FormData.specName }}</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>
</view>
</template>
<template v-if="FormData.type != 'sku'">
<view class="block u-p-t-32 u-p-b-32" v-for="(sku, index) in skuList.list" :key="index">
<view class="font-bold u-m-b-32 u-text-center">规格属性</view>
<view class="u-flex w-full gap-26 u-row-between">
<view class="u-flex-1">
<view>
<text class="color-red">*</text>
<text>原价</text>
</view>
<view class="u-m-t-16">
<price-number-box placeholder="请输入原价" v-model="sku.originPrice"></price-number-box>
</view>
</view>
<view class="u-flex-1">
<view>
<text class="color-red">*</text>
<text>售价</text>
</view>
<view class="u-m-t-16">
<price-number-box placeholder="请输入售价" v-model="sku.salePrice"></price-number-box>
</view>
</view>
</view>
<view class="u-flex w-full gap-26 u-row-between u-m-t-24">
<view class="u-flex-1">
<view>
<text class="color-red">*</text>
<text>会员价</text>
</view>
<view class="u-m-t-16">
<price-number-box placeholder="请输入会员价(元)" v-model="sku.memberPrice"></price-number-box>
</view>
</view>
<view class="u-flex-1">
<view>
<text class="color-red">*</text>
<text>成本价</text>
</view>
<view class="u-m-t-16">
<price-number-box placeholder="请输入成本价" v-model="sku.costPrice"></price-number-box>
</view>
</view>
</view>
<view class="u-m-t-24">
<view>
<text class="color-red">*</text>
<text>起售数量</text>
</view>
<view class="u-m-t-16">
<price-number-box inputType="number" placeholder="请输入起售数量" v-model="sku.suitNum"></price-number-box>
</view>
</view>
<view class="u-m-t-24">
<view class="">商品条形码</view>
<view class="u-m-t-16 barCode color-999">
{{ sku.barCode }}
</view>
</view>
</view>
</template>
<template v-if="FormData.type == 'weight'">
<view class="block u-p-t-32 u-p-b-32">
<view class="font-bold">
<text class="color-red">*</text>
<text>单位</text>
</view>
<view class="u-m-t-16">
<up-input v-model="FormData.weight">
<template #suffix>
<view class="bg-gray">{{ activeinHouseList }}</view>
</template>
</up-input>
<view class="u-m-t-16 color-999 u-font-24">用于快递或配送运费计重</view>
</view>
</view>
</template>
<template v-if="FormData.type != 'group'">
<view class="block">
<view>
<uni-forms-item label="">
<view class="u-flex u-row-between" @tap="toTimerPage">
<view style="display: flex">
<text class="color-red">*</text>
<view class="label-title">定时上下架</view>
</view>
<view class="u-flex u-font-24">
<view>
<view class="color-666">{{ returnTimerDayText() }}</view>
<view class="color-666 u-m-t-4" v-if="FormData.days">
{{ returnTimerTimeText() }}
</view>
</view>
<uni-icons type="right"></uni-icons>
</view>
</view>
</uni-forms-item>
</view>
<view class="">
<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.isSale"></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="打包费">
<uni-easyinput
@blur="priceFormat(FormData, 'packFee')"
:paddingNone="inputPaddingNone"
:placeholderStyle="placeholderStyle"
:inputBorder="inputBorder"
v-model="FormData.packFee"
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>
<uni-forms-item label="关联推荐商品">
<view class="tips">
<text class="t">设置商品后,用户可以在商品详情页中看到推荐商品,最多设置{{ goodsListMax }}个商品</text>
</view>
<view class="table">
<view class="tabhead">
<view class="tr">
<view class="td">
<text class="t">图片</text>
</view>
<view class="td">
<text class="t">商品名称</text>
</view>
<view class="td">
<text class="t">操作</text>
</view>
</view>
</view>
<view class="tbbody">
<view class="tr" v-for="(item, index) in FormData.relatedRecommendJson" :key="index">
<view class="td">
<image class="cover" :src="item.coverImg" mode="aspectFill"></image>
</view>
<view class="td">
<text class="t">{{ item.name }}</text>
</view>
<view class="td">
<u-text type="error" text="删除" @click="FormData.relatedRecommendJson.splice(index, 1)"></u-text>
</view>
</view>
<view class="table-tips" v-if="!FormData.relatedRecommendJson.length">
<text class="t">暂无数据</text>
</view>
</view>
</view>
<view class="add-goods" v-if="FormData.relatedRecommendJson.length < goodsListMax">
<view class="btn">
<u-text type="primary" text="添加商品" prefixIcon="plus" iconStyle="color:#409EFF;" @click="toSelectGoodsPage"></u-text>
</view>
</view>
</uni-forms-item>
</view>
</template>
</uni-forms>
<view style="height: 100rpx"></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="delmodelConfirm" ref="delModel" desc="确认删除"></my-model>
<!-- 选择商品 -->
<choose-goods ref="refChooseGoods" @confirm="refChooseGoodsConfirm" :category="pageData.category"></choose-goods>
<!-- 选择规格 -->
<choose-guige ref="refChooseGuige" @confirm="refChooseGuigeConfirm"></choose-guige>
</view>
</template>
<script setup>
import { computed, onBeforeUnmount, reactive, ref, watch, nextTick } from 'vue';
import { onLoad, onShow, onReady } from '@dcloudio/uni-app';
import dayjs from 'dayjs';
import { formatPrice } from '@/commons/utils/format.js';
import go from '@/commons/utils/go.js';
import chooseGoods from './components/choose-goods';
import chooseGuige from './components/choose-guige';
import editHaocai from './components/edit-haocai.vue';
import chooseGroupCategory from './components/choose-coupon-category';
import priceNumberBox from './components/price-number-box';
import infoBox from '@/commons/utils/infoBox.js';
import { hasPermission } from '@/commons/utils/hasPermission.js';
import { $defaultSku } from '@/commons/goodsData.js';
import { getCategoryList, getProdUnitList, getProductDetail, addProduct, updateProduct, delProduct, productBindCons } from '@/http/api/product.js';
import { uploadFile } from '@/http/api/index.js';
const imageStyles = reactive({
width: 82,
height: 82,
border: {
radius: '4px'
}
});
let option = reactive({
type: 'add',
productId: ''
});
// 表单样式
//可以不使用ref但是小程序一堆wraning 改为了ref
const placeholderStyle = ref('font-size:28rpx;');
const inputPaddingNone = ref(true);
// ================== 关联商品 start
const goodsListMax = ref(9);
// 跳转去选择商品
function toSelectGoodsPage() {
uni.navigateTo({
url: '/pageMarket/packagePopularize/selectGoods'
});
}
// 从本地获取选择的商品
function getLocalSelectGoods() {
let res = uni.getStorageSync('packageSelectGoods');
if (res && res.id) {
if (res.id === FormData.id) {
uni.showToast({
title: '不能选择当前商品',
icon: 'none'
});
return;
}
let obj = FormData.relatedRecommendJson.find((item) => item.id == res.id);
if (obj && obj.id) {
uni.showToast({
title: '该商品已选择',
icon: 'none'
});
return;
}
FormData.relatedRecommendJson.push({ ...res });
}
uni.setStorageSync('packageSelectGoods', '');
}
// ================== 关联商品 end
//表单边框
const inputBorder = ref(false);
const FormData = reactive({
id: '',
name: '', //商品名称
shortTitle: '', //商品介绍
unitId: '', //单位id
categoryId: '', //商品分类id
coverImg: '', //封面图url
images: [], //详情图urls
type: 'single', //商品类型single-单规格商品 sku-多规格商品 package-套餐商品 weight-称重商品 coupon-团购券
specId: '', //规格ID
skuList: [], //规格数据
groupType: null, //套餐类型
proGroupVo: [], //套餐数据
weight: 0, //重量
isAllowTempModifyPrice: 1, //是否允许改价
days: 'Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday', //定时上下架周期
startTime: '00:00:00', //开始时间
endTime: '23:59:00', //结束时间
isSale: 1, //是否上架
isStock: 0, //是否开启库存
isHot: 0, //设为推荐
stockNumber: 0, //库存数量
packFee: 0, //打包费
sort: 1, //排序值
specName: '', //规格模版名称
unitName: '',
specificationsGroup: '',
relatedRecommendJson: [] // 关联商品
});
//页面全部数据
const pageData = reactive({
// 商品类型
types: [
{
name: '单规格商品',
value: 'single'
},
{
name: '多规格商品',
value: 'sku'
},
{
name: '套餐商品',
value: 'package'
},
{
name: '称重商品',
value: 'weight'
}
// {
// name: '团购券',
// value: 'coupon'
// },
],
// 单位
units: [],
// 分类
category: [],
//库存
skuList: []
});
const skuList = reactive({
list: [
{
...$defaultSku,
barCode: `${uni.getStorageSync('shopId')}${dayjs().valueOf()}`
}
]
});
let $goodsData = {};
// 商品图片组件
const refFile = ref(null);
/**
* 监听商品类型变化
*/
console.log(FormData);
watch(
() => FormData.type,
(newval) => {
if (option.type == 'edit') {
FormData.specId = newval != 'sku' ? '' : $goodsData.specId || '';
console.log($goodsData);
if (newval == $goodsData.type) {
skuList.list = $goodsData.skuList;
if ($goodsData.groupSnap) {
FormData.proGroupVo = $goodsData.groupSnap || [];
} else {
initDefaultProGroupVo();
}
} else {
if (newval != 'sku') {
skuList.list = [
{
...$defaultSku,
barCode: `${uni.getStorageSync('shopId')}${dayjs().valueOf()}`
}
];
} else {
skuList.list = [];
}
}
if (FormData.groupType == null) {
FormData.groupType = 0;
}
} else {
FormData.specId = '';
if (newval != 'sku') {
skuList.list = [
{
...$defaultSku,
barCode: `${uni.getStorageSync('shopId')}${dayjs().valueOf()}`
}
];
} else {
skuList.list = [];
}
if (newval == 'package') {
initDefaultProGroupVo();
}
}
}
);
/**
* 监听套餐类型变化
*/
watch(
() => FormData.groupType,
(newval) => {
if (newval == 0) {
return initDefaultProGroupVo();
}
if (option.type == 'edit') {
if (newval == $goodsData.groupType) {
FormData.proGroupVo = $goodsData.groupSnap;
}
return;
}
initDefaultProGroupVo();
}
);
watch(
() => pageData.types,
(newval) => {
Forms.value.setRules(rules);
}
);
watch(
() => skuList.list,
(newval) => {
console.log(newval);
}
);
onLoad((params) => {
if (params && JSON.stringify(params) !== '{}') {
option.type = params.type ? params.type : 'add';
option.productId = params.productId;
}
canEditGoodsCategory();
uni.setNavigationBarTitle({
title: option.type === 'add' ? '添加商品' : '编辑商品'
});
if (option.type === 'edit') {
getGoodsDetail();
}
getCategory();
getTbShopUnit();
uni.setStorageSync('packageSelectGoods', '');
});
onReady(() => {
Forms.value && Forms.value.setRules(rules);
});
onShow(() => {
watchSpecificationsSave();
watchTimerSave();
getLocalSelectGoods();
});
function getGoodsDetail() {
getProductDetail(option.productId).then((res) => {
res.images = res.images.map((v) => {
return {
url: v
};
});
res.consList.map((v) => {
const item = res.skuList.find((v) => v.productId == v.productId);
if (item) {
if (item.hasOwnProperty('haoCaiList')) {
item.haoCaiList.push(v);
} else {
item.haoCaiList = [v];
}
}
});
res.skuList = res.skuList.length ? res.skuList : [];
$goodsData = res;
skuList.list = res.skuList;
Object.assign(FormData, res);
//多规格
if (res.type == 'sku') {
FormData.specificationsGroup = {
specId: res.specId,
selectSpecInfo: res.selectSpecInfo,
result: res.skuList.map((v) => {
const names = v.specInfo.split(',').reduce((prve, cur) => {
let key;
for (var oe in res.selectSpecInfo) {
res.selectSpecInfo[oe].map((i) => {
if (i == cur) {
key = oe;
}
});
}
prve[key] = cur;
return prve;
}, {});
return {
skus: {
...v
},
names,
specInfo: v.specInfo,
coverImg: v.coverImg
};
})
};
} else {
// 单规格
}
});
}
/**
* 获取分类
*/
function getCategory() {
getCategoryList({
page: 1,
size: 200
}).then((res) => {
pageData.category = res;
});
}
/**
* 获取单位数据
*/
function getTbShopUnit() {
getProdUnitList().then((res) => {
pageData.units = res;
});
}
/**
* 耗材取消监听
* @param {Object} newval
*/
function changeTabsCurrent(newval) {
tabsCurrent.value = newval;
}
/**
* 分类选择监听
*/
const changeFormDatatype = (e) => {
if (FormData.type == 'package') {
FormData.groupType = 0;
} else {
FormData.groupType = null;
}
console.log(FormData);
};
/**
* 选择单位监听
* @param {Object} e
*/
function unitIdChange(e) {
FormData.unitName = e.detail.value[0].text;
}
async function isGroundingChange(e) {
// if (option.type == 'add') {
// FormData.isSale = FormData.isSale ? 0 : 1
// return
// }
// const res = await hasPermission('允许上下架商品')
// if (!res) {
// return
// }
FormData.isSale = FormData.isSale ? 0 : 1;
}
/**
* 固定套餐设置规格
*/
const refChooseGuige = ref(null);
let proGroupVoGoodsIndex = undefined;
/**
* 规格打开
* @param {Object} skuList
* @param {Object} groupIndex
* @param {Object} goodsIndex
*/
function refChooseGuigeOpen(skuList, groupIndex, goodsIndex) {
proGroupVoIndex = groupIndex;
proGroupVoGoodsIndex = goodsIndex;
console.log(skuList);
refChooseGuige.value.open(skuList);
}
/**
* 规格确认
* @param {Object} sku
*/
function refChooseGuigeConfirm(sku) {
FormData.proGroupVo[proGroupVoIndex].goods[proGroupVoGoodsIndex].skuName = sku.specInfo || sku.name;
FormData.proGroupVo[proGroupVoIndex].goods[proGroupVoGoodsIndex].skuId = sku.id;
proGroupVoIndex = undefined;
proGroupVoGoodsIndex = undefined;
}
/**
* 套餐商品选择
*/
const refChooseGoods = ref(null);
let proGroupVoIndex = undefined;
/**
* 添加商品
* @param {Object} index
* @param {Object} arr
*/
function proGroupVoAddGoods(index, arr) {
proGroupVoIndex = index;
if (!FormData.proGroupVo) {
initDefaultProGroupVo();
}
if (FormData.groupType == 0) {
const goods = FormData.proGroupVo[0].goods;
refChooseGoods.value.open(goods);
} else {
refChooseGoods.value.open(arr);
}
}
/**
* 添加套餐组
*/
function proGroupVoPush() {
FormData.proGroupVo.push({
title: '',
count: 1,
goods: []
});
console.log(FormData.proGroupVo);
}
/**
* 删除套餐组
* @param {Object} index
*/
function delproGroupVo(index) {
FormData.proGroupVo.splice(index, 1);
}
/**
* 删除套餐商品
* @param {Object} index
* @param {Object} goodsIndex
*/
function proGroupVoGoodsDel(index, goodsIndex) {
FormData.proGroupVo[index].goods.splice(goodsIndex, 1);
}
function refChooseGoodsClose() {
refChooseGoods.value.close();
}
/**
* 套餐选择商品
* @param {Object} arr
*/
function refChooseGoodsConfirm(arr) {
refChooseGoodsClose();
arr = arr.map((v) => {
const { proId, id, name, unitName, lowPrice, type, skuList } = v;
if (proId) {
return v;
}
return {
proId: id,
proName: name,
unitName,
price: lowPrice,
number: 1,
type,
skuList,
skuId: '',
skuName: ''
};
});
if (FormData.groupType == 0) {
return (FormData.proGroupVo[0].goods = arr);
}
if (FormData.groupType == 1 && proGroupVoIndex !== undefined) {
return (FormData.proGroupVo[proGroupVoIndex].goods = arr);
}
FormData.proGroupVo.push({
title: '',
count: 1,
goods: arr
});
}
/**
* number类型数据限制
* @param {Object} item
* @param {Object} key
*/
function priceFormat(item, key) {
nextTick(() => {
const min = 0;
const max = 100000000;
if (item[key] === '') {
return;
}
const newval = formatPrice(item[key], min, max, true);
if (typeof newval !== 'number') {
item[key] = newval.value;
uni.showToast({
title: `请输入${min}到${max}范围内的数字`,
icon: 'none'
});
} else {
item[key] = newval;
}
});
}
/**
* 套餐商品类型
*/
const packageType = reactive({
list: [
{
name: '固定套餐',
value: 0
},
{
name: '可选套餐',
value: 1
}
],
sel: 0
});
const tabsList = ['基础设置', '耗材绑定'];
let tabsCurrent = ref(0);
const Forms = 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: '请填写商品底价'
}
]
}
};
/**
* 删除提示打开
*/
function delModelShow() {
delModel.value.open();
}
/**
* 删除商品
*/
function delmodelConfirm() {
delProduct(option.productId).then((res) => {
uni.showToast({
icon: 'none',
title: '删除成功'
});
setTimeout(() => {
uni.$emit('del:productIndex', option.productId);
go.back();
}, 500);
});
}
function updateGoodsDetail() {
getGoodsDetail();
}
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 { groupType, type } = FormData;
const images = refFile.value.getFileList();
if (images.length <= 0) {
return infoBox.showToast('请上传商品图片');
}
let selectSpecInfo = $goodsData.selectSpecInfo;
if (FormData.specificationsGroup.specAllList) {
selectSpecInfo = {};
for (let i of FormData.specificationsGroup.selectSpecInfo) {
if (i.selectSpecResult.length) {
selectSpecInfo[i.name] = i.selectSpecResult;
}
}
}
if (type != 'sku') {
let lowPrice = skuList.list[0] ? skuList.list[0].salePrice : FormData.salePrice;
let suitNum = skuList.list[0] ? skuList.list[0].suitNum : 0;
if (lowPrice === '') {
return infoBox.showToast('请输入售价');
}
if (suitNum <= 0) {
return infoBox.showToast('起售数量不能小于0');
}
if (FormData.stockNumber === '') {
return infoBox.showToast('请输入库存数量!');
}
}
if (type == 'sku') {
if (selectSpecInfo.length == 0 || JSON.stringify(selectSpecInfo) == '{}') {
return infoBox.showToast('请选择规格!');
}
}
if (type == 'package') {
if (groupType == 0 && FormData.proGroupVo[0].goods.length <= 0) {
// 固定套餐
return infoBox.showToast('套餐组合至少需要包含一种商品,请添加商品');
}
if (groupType == 1) {
let ispase = FormData.proGroupVo.length > 0 ? true : false;
let tips = ispase ? '' : '请添加至少一种套餐';
for (let i in FormData.proGroupVo) {
FormData.proGroupVo[i].count = FormData.proGroupVo[i].goods.length;
const item = FormData.proGroupVo[i];
if (item.goods.length <= 0) {
ispase = false;
tips = '套餐组合至少需要包含一种商品,请添加商品';
break;
}
if (!item.title) {
ispase = false;
tips = '请输入套餐名称';
break;
}
}
if (!ispase) {
return infoBox.showToast(tips);
}
// 可选套餐
} else {
FormData.proGroupVo[0].count = FormData.proGroupVo[0].goods.length;
FormData.proGroupVo[0].number = 1;
}
}
if (type == 'weight') {
if (!FormData.weight) {
return infoBox.showToast('请输入重量');
}
}
const submitData = {
...FormData,
proGroupVo: type != 'package' ? '' : FormData.proGroupVo,
images: images,
coverImg: images[0] || '',
skuList: skuList.list,
selectSpecInfo: selectSpecInfo
};
//编辑
if (option.type === 'edit') {
return updateProduct(submitData).then((res) => {
infoBox.showSuccessToast('更新成功');
settimeoutBack(1500);
});
}
// 如果套餐没选择规格,默认选中第一条
if (submitData.proGroupVo) {
submitData.proGroupVo.forEach((res, index) => {
submitData.proGroupVo[index].goods.forEach((ele) => {
if (!ele.skuId) {
ele.skuId = ele.skuList[0].id;
ele.skuName = ele.skuList[0].specInfo || ele.skuList[0].name;
}
});
});
}
addProduct(submitData).then((res) => {
infoBox.showSuccessToast('添加成功');
settimeoutBack(1500);
});
})
.catch((err) => {
console.log(err);
});
}
/**
* 监听规格保存,拿到数据
*/
function watchSpecificationsSave() {
uni.$off('emitspecificationsSave');
uni.$on('emitspecificationsSave', function (data) {
console.log(data);
FormData.specificationsGroup = data;
FormData.specId = data.specId;
FormData.specName = data.specName;
skuList.list = data.result.map((v) => {
return {
...v.skus,
...v.names,
specInfo: v.specInfo,
coverImg: v.coverImg || ''
};
});
});
}
/**
* 编辑规格
*/
function toGuige() {
console.log(FormData.specificationsGroup);
uni.setStorageSync('guige', FormData.specificationsGroup);
go.to('PAGES_PRODUCT_GUIGE_CHOOSE', {
emitName: 'emitspecificationsSave',
type: option.type
});
}
/**
* 监听定时器保存,拿到数据
* @param {Boolean} open //控制开启或关闭监听
*/
function watchTimerSave(open = true) {
uni.$off('timerSave');
uni.$on('timerSave', function (timer) {
Object.assign(FormData, timer);
});
}
/**
* 设置定时上下级
*/
function toTimerPage() {
go.to('PAGES_PRODUCT_TIMER', {
days: FormData.days,
startTime: FormData.startTime,
endTime: FormData.endTime
});
}
const $week = {
Monday: '周一',
Tuesday: '周二',
Wednesday: '周三',
Thursday: '周四',
Friday: '周五',
Saturday: '周六',
Sunday: '周日'
};
/**
* 定时数据显示处理
*/
function returnTimerDayText() {
if (!FormData.days) {
return '';
}
return FormData.days
.split(',')
.filter((v) => v)
.map((v) => $week[v])
.join(',');
// return FormData.timer.length ? `当前有${FormData.timer.length}个定时器` : '没有定时器'
}
/**
* 定时数据显示处理
*/
function returnTimerTimeText() {
if (!FormData.startTime || !FormData.endTime) {
return '';
}
return FormData.startTime + '-' + FormData.endTime;
}
function initDefaultProGroupVo() {
FormData.proGroupVo = [
{
title: '',
count: 1,
number: 1,
goods: []
}
];
console.log(FormData.proGroupVo);
}
/**
* 权限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;
}
}
const activeinHouseList = computed(() => {
try {
return pageData.units.filter((item) => {
if (item.id == FormData.unitId) {
return item.name;
}
})[0].name;
} catch (error) {
//TODO handle the exception
}
});
/**
* 销毁
*/
onBeforeUnmount(() => {
clearTimeout(timer);
});
</script>
<style scoped>
page {
background: #f9f9f9;
}
</style>
<style lang="scss" scoped>
.tips {
font-size: 28upx;
color: #999;
}
.barCode {
border: 1px solid #e5e5e5;
border-radius: 8rpx 8rpx 8rpx 8rpx;
padding: 22rpx 24rpx;
background: #fcfcfc;
}
.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: 60px;
z-index: 9;
}
.minus {
}
.plus {
}
.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 .typeEnum .u-radio-group--row {
flex-wrap: nowrap;
justify-content: space-between;
}
::v-deep .typeEnum .u-checkbox-group--row {
flex-wrap: nowrap;
justify-content: space-between;
}
::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;
}
.gap-26 {
gap: 26rpx;
}
::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: 0.6;
}
.zuofa {
padding: 28rpx 0;
background: #f9f9f9;
padding-left: 42rpx;
border-radius: 14rpx 14rpx 14rpx 14rpx;
}
::v-deep .uni-input-placeholder {
font-size: 28rpx;
}
.table {
background: #f9f9f9;
border-radius: 8rpx;
overflow: hidden;
.title {
padding: 12rpx 24rpx 12rpx 24rpx;
background: #aebad2;
border-radius: 8rpx 8rpx 0rpx 0rpx;
color: #fff;
}
.row:nth-of-type(2n + 1) {
background: #f0f0f0;
}
}
.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, 0.3);
}
.gou {
opacity: 0.5;
}
.title {
color: #999;
}
}
}
}
.table {
border: 1px solid #ececec;
margin-top: 28upx;
.table-tips {
padding: 28upx;
display: flex;
justify-content: center;
.t {
font-size: 28upx;
color: #999;
}
}
.tabhead {
background-color: #f8f8f8;
border-bottom: 1px solid #ececec;
.t {
font-weight: bold;
}
}
.tr {
display: flex;
&:not(:last-child) {
border-bottom: 1px solid #ececec;
}
.td {
flex: 1;
min-height: 80upx;
display: flex;
align-items: center;
padding: 20upx;
&:not(:last-child) {
border-right: 1px solid #ececec;
}
&:nth-child(2) {
flex: 2;
}
.cover {
$size: 80upx;
width: $size;
height: $size;
border-radius: 8upx;
}
.t {
font-size: 28upx;
color: #333;
}
}
}
}
.add-goods {
display: flex;
justify-content: center;
padding-top: 28upx;
}
</style>