商品列表修改,商品修改去掉库存相关东西,增加退菜是否退库存的选项,分类增加退菜是否退库存的选项,店铺增加退菜退库存模式配置,增加退款退菜是否退库存弹窗,增加购物车重复物品提示弹窗

This commit is contained in:
2026-04-11 15:31:57 +08:00
parent bc7b6d41f5
commit 2db9f6811a
15 changed files with 3002 additions and 2373 deletions

View File

@@ -14,6 +14,16 @@ export function categoryPage(data, urlType = 'product') {
}
})
}
/**
* 获取分类详情
* @returns
*/
export function getCategoryDetail(id, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/category/`+id,
method: "GET",
})
}
/**
* 分类添加

View File

@@ -14,7 +14,19 @@ export function getConsPage(data, urlType = 'product') {
}
})
}
/**
* 耗材库存列表接口
* @returns
*/
export function getConsStock(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/cons/consStock`,
method: "GET",
data: {
...data
}
})
}
/**
* 获取耗材列表
* @returns

View File

@@ -13,15 +13,22 @@
</view>
<view class="">
<uni-forms-item label="分类名称" required name="name">
<uni-easyinput padding-none :placeholderStyle="'font-size:28rpx;'"
:inputBorder="false" v-model="category.name" placeholder="输入分类名称" />
<uni-easyinput padding-none :placeholderStyle="'font-size:28rpx;'" :inputBorder="false"
v-model="category.name" placeholder="输入分类名称" />
</uni-forms-item>
</view>
<view class="">
<uni-forms-item label="退菜是否退库存" required name=" refundMode">
<up-radio-group v-model="category.refundMode" placement="row">
<up-radio v-for="(item, index) in refundModes" :key="index" :label="item.name"
:name="item.value" activeColor="rgb(49, 138, 254)"></up-radio>
</up-radio-group>
</uni-forms-item>
</view>
<template v-if="option.type==='edit'">
<uni-forms-item label="排序" required name="sort">
<uni-easyinput padding-none :placeholderStyle="'font-size:28rpx;'"
:inputBorder="false" v-model="category.sort" type="number"
placeholder="排序越小越靠前" />
<uni-easyinput padding-none :placeholderStyle="'font-size:28rpx;'" :inputBorder="false"
v-model="category.sort" type="number" placeholder="排序越小越靠前" />
</uni-forms-item>
</template>
<uni-forms-item label="">
@@ -50,14 +57,35 @@
</template>
<script setup>
import { reactive, ref } from 'vue';
import {
reactive,
ref
} from 'vue';
import go from '@/commons/utils/go.js';
import infoBox from '@/commons/utils/infoBox.js';
import mySwitch from '@/components/my-components/my-switch'
import myUploadFile from '@/components/my-components/my-upload-file'
import { onLoad, onReady } from '@dcloudio/uni-app';
import { addCategory, putCategory } from '@/http/api/cateGory.js'
import {
onLoad,
onReady
} from '@dcloudio/uni-app';
import {
addCategory,
putCategory
} from '@/http/api/cateGory.js'
const refundModes = [{
name: "退菜退库存",
value: 1
},
{
name: "仅退菜不退库存",
value: 2
},
{
name: "每次询问-退菜后弹窗提示",
value: 3
},
]
// 构造分类的基础数据
const category = reactive({
@@ -121,6 +149,7 @@
}
}
}
function validateFunc(key, value) {
if (validateFuncObj.hasOwnProperty(key)) {
const func = validateFuncObj[key]

View File

@@ -18,6 +18,12 @@
<view>预警值</view>
<view><input type="number" placeholder="请输入预警值" v-model="datas.form.conWarning" name="" id="" /></view>
</view>
<view>
<view>是否检测耗材</view>
<up-switch size="20" :inactive-value="0" :active-value="1" v-model="datas.form.isStock"></up-switch>
</view>
<view v-if="!datas.form.id" style="justify-content: space-between">
<view>耗材类型</view>
<view style="width: 54%" @tap="datas.show = !datas.show">
@@ -55,7 +61,8 @@
<view class="label">默认入库单位</view>
<view class="ipt">
<u-radio-group v-model="datas.form.defaultUnit">
<u-radio :name="item" :label="item" v-for="(item, index) in unitList" :key="index"></u-radio>
<u-radio :name="item" :label="item" v-for="(item, index) in unitList"
:key="index"></u-radio>
</u-radio-group>
</view>
</view>
@@ -63,21 +70,32 @@
</view>
</template>
<view class="bottombutton">
<up-button type="primary" style="background-color: #318afe; color: #fff" @tap="sumbit" :plain="true" text="保存"></up-button>
<up-button type="primary" style="background-color: #318afe; color: #fff" @tap="sumbit" :plain="true"
text="保存"></up-button>
</view>
<up-picker :show="datas.show" :columns="datas.typeList" keyName="name" @cancel="datas.show = false" @confirm="confirmConsGroup"></up-picker>
<up-picker :show="datas.show" :columns="datas.typeList" keyName="name" @cancel="datas.show = false"
@confirm="confirmConsGroup"></up-picker>
<!-- 消息提示 -->
<up-toast ref="uToastRef"></up-toast>
<u-picker :show="unitShow" :columns="unitList"></u-picker>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import {
ref,
reactive
} from 'vue';
import {
onLoad
} from '@dcloudio/uni-app';
import { getConsGrpupList, addCons, editCons } from '@/http/api/cons.js';
import {
getConsGrpupList,
addCons,
editCons
} from '@/http/api/cons.js';
let datas = reactive({
let datas = reactive({
show: false,
form: {
conUnit: '',
@@ -87,13 +105,14 @@ let datas = reactive({
consGroupId: null,
conUnitTwo: '', // 第二单位
conUnitTwoConvert: '', // 第二单位转换数量
defaultUnit: ''
defaultUnit: '',
isStock: 1,
},
consGroupName: '',
typeList: []
});
});
onLoad((options) => {
onLoad((options) => {
if (options && options.item) {
let obj = JSON.parse(decodeURIComponent(options.item));
datas.form = obj;
@@ -113,27 +132,27 @@ onLoad((options) => {
uni.setNavigationBarTitle({
title: !datas.form.id ? '添加耗材' : '编辑耗材'
});
});
});
/**
/**
* 获取耗材类别
*/
let gettbConsTypeList = () => {
let gettbConsTypeList = () => {
getConsGrpupList({
page: 1,
size: 30
}).then((res) => {
datas.typeList = [res];
});
};
};
function confirmConsGroup(e) {
function confirmConsGroup(e) {
datas.show = false;
datas.form.consGroupId = e.value[0].id;
datas.consGroupName = e.value[0].name;
}
}
let sumbit = async () => {
let sumbit = async () => {
let conUnitdata = datas.form.conUnit.replace(/(^\s*)|(\s*$)/g, '');
if (!conUnitdata) {
uni.$utils.showToast('单位不能为空');
@@ -148,32 +167,36 @@ let sumbit = async () => {
return;
}
if (!datas.form.id) {
await addCons({ ...datas.form });
await addCons({
...datas.form
});
} else {
await editCons({ ...datas.form });
await editCons({
...datas.form
});
}
uni.navigateBack();
};
};
// 显示选择单位
const unitShow = ref(false);
// 单位列表
const unitList = ref([]);
// 显示选择单位
const unitShow = ref(false);
// 单位列表
const unitList = ref([]);
</script>
<style>
page {
page {
background-color: #f9f9f9;
}
}
</style>
<style scoped lang="less">
.topTitle {
.topTitle {
font-weight: 400;
font-size: 32rpx;
color: #333333;
margin: 32rpx 28rpx;
}
}
.addConsumables {
.addConsumables {
width: 694rpx;
background: #ffffff;
border-radius: 18rpx 18rpx 18rpx 18rpx;
@@ -181,8 +204,8 @@ page {
padding: 24rpx;
box-sizing: border-box;
> view {
> view {
>view {
>view {
width: 646rpx;
height: 84rpx;
background: #fcfcfc;
@@ -190,8 +213,8 @@ page {
margin-top: 32rpx;
.df;
> view:first-child {
width: 190rpx;
>view:first-child {
width: 240rpx;
height: 84rpx;
line-height: 84rpx;
// text-align: left;
@@ -206,20 +229,20 @@ page {
}
}
}
}
}
.bottombutton {
.bottombutton {
margin-top: 84rpx;
padding: 0 24rpx;
> button {
>button {
width: 530rpx;
height: 80rpx;
border-radius: 56rpx 56rpx 56rpx 56rpx;
}
}
}
.status {
.status {
margin: 0 32rpx;
position: absolute;
// top: 100%;
@@ -227,16 +250,18 @@ page {
right: 0;
z-index: 10;
background-color: #fff;
}
}
.df() {
.df() {
display: flex;
align-items: center;
}
.tips-wrap {
}
.tips-wrap {
--pColor: #e6a23c;
--iColor: #fdf6ec;
padding: 0 28upx;
.content {
display: flex;
align-items: center;
@@ -248,24 +273,29 @@ page {
flex-direction: column;
padding-left: 10px;
gap: 8upx;
.t1 {
font-size: 32upx;
color: var(--pColor);
}
.t2 {
font-size: 24upx;
color: var(--pColor);
}
}
}
}
.form-wrap {
}
.form-wrap {
padding: 28upx 28upx 0;
.form {
padding: 28upx;
background-color: #fff;
border-radius: 16upx;
}
.row {
height: 84upx;
display: flex;
@@ -273,16 +303,19 @@ page {
align-items: center;
background-color: #fcfcfc;
padding: 0 20upx;
&:not(:last-child) {
margin-bottom: 28upx;
}
.label {
font-size: 32upx;
color: #333;
}
.ipt {
flex: 1;
}
}
}
}
</style>

View File

@@ -11,26 +11,26 @@
</view>
<view>
<view> <text style="color: red;">*</text> 入库时间 </view>
<view >
<up-datetime-picker
hasInput
v-model="datas.form.inOutDate"
mode="date"
></up-datetime-picker>
<view>
<up-datetime-picker hasInput v-model="datas.form.inOutDate" mode="date"></up-datetime-picker>
</view>
</view>
<view>
<view> <text style="color: red;">*</text> 入库数量 </view>
<view> <input type="number" placeholder="请输入数量" v-model="datas.form.bodyList.inOutNumber" @change="datas.form.bodyList.inOutNumber = $utils.isNumber(datas.form.bodyList.inOutNumber)" name="" id=""> </view>
<view> <input type="number" placeholder="请输入数量" v-model="datas.form.bodyList.inOutNumber"
@change="datas.form.bodyList.inOutNumber = $utils.isNumber(datas.form.bodyList.inOutNumber)"
name="" id=""> </view>
</view>
<view>
<view> <text style="color: red;">*</text>单价 </view>
<view> <input type="number" placeholder="请输入单价(元)" v-model="datas.form.bodyList.purchasePrice" @change="datas.form.bodyList.purchasePrice = $utils.isMoney(datas.form.bodyList.purchasePrice)" name="" id=""> </view>
<view> <input type="number" placeholder="请输入单价(元)" v-model="datas.form.bodyList.purchasePrice"
@change="datas.form.bodyList.purchasePrice = $utils.isMoney(datas.form.bodyList.purchasePrice)"
name="" id=""> </view>
</view>
<view style="justify-content: space-between;">
<view> 单位 </view>
<view> <input type="text" placeholder="请输入单位" v-model="datas.form.bodyList.conUnit" name="" id=""> </view>
<view> <input type="text" placeholder="请输入单位" v-model="datas.form.bodyList.conUnit" name="" id="">
</view>
</view>
<view>
<view> 应付金额 </view>
@@ -43,7 +43,8 @@
<view style="justify-content: space-between;align-items: center;">
<view> 供应商 </view>
<picker @change="changeNowStatusIndex" :value="nowStatusIndex" :range="datas.status">
<view class="color-333" style="height: 84rpx;line-height: 84rpx;">{{datas.status[nowStatusIndex]}}</view>
<view class="color-333" style="height: 84rpx;line-height: 84rpx;">{{datas.status[nowStatusIndex]}}
</view>
</picker>
<uni-icons type="bottom" size="16"></uni-icons>
<view style="color: #318AFE;width: 80rpx;text-align: center;" @tap="toggle"> 新增 </view>
@@ -64,13 +65,24 @@
<script setup>
import { ref, computed, reactive } from 'vue';
import { onShow, onLoad } from '@dcloudio/uni-app';
import {
ref,
computed,
reactive
} from 'vue';
import {
onShow,
onLoad
} from '@dcloudio/uni-app';
import go from '@/commons/utils/go.js';
import dayjs from 'dayjs';
import { getVendorPage } from '@/http/api/vendor.js';
import { consStockIn } from '@/http/api/cons.js';
import {
getVendorPage
} from '@/http/api/vendor.js';
import {
consStockIn
} from '@/http/api/cons.js';
let showStatus = ref(false)
let datas = reactive({
@@ -95,7 +107,7 @@
datas.item = JSON.parse(options.item)
datas.form = Object.assign(datas.form, datas.item)
// 单位列表
datas.unitList = [ datas.form.conUnit, datas.form.conUnitTwo]
datas.unitList = [datas.form.conUnit, datas.form.conUnitTwo]
datas.form.bodyList.unit = datas.form.defaultUnit
datas.form.bodyList.conName = datas.form.conName
datas.form.bodyList.unitName = datas.form.unitName
@@ -157,10 +169,11 @@
datas.form.bodyList.conId = datas.item.id
datas.form.bodyList = [datas.form.bodyList]
datas.form.inOutDate = dayjs(datas.form.inOutDate).format('YYYY-MM-DD')
consStockIn({
...datas.form,
// 供应商id
vendorId: datas.list[nowStatusIndex.value].id,
vendorId: datas.list[nowStatusIndex.value]?datas.list[nowStatusIndex.value].id:'',
amountPayable: datas.form.bodyList[0].inOutNumber * datas.form.bodyList[0].purchasePrice,
}).then(res => {
uni.$utils.showToast("保存成功")
@@ -168,7 +181,7 @@
go.back()
}, 1000)
})
},1000)
}, 1000)
// 获取供应商
const statusHeight = computed(() => {
return 30 * datas.status.length + 14 + 'px'
@@ -194,9 +207,11 @@
list-style: none;
padding: 0;
}
::v-deep.u-input{
border: none!important;
::v-deep.u-input {
border: none !important;
}
.status {
margin: 0 32rpx;
position: absolute;

View File

@@ -42,7 +42,7 @@ async function getProductListAjax() {
mask: true
});
const res = await getProductList();
list.value = res;
list.value = res.productList;
} catch (error) {
console.log(error);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
<template>
<view>
<view class="default-box-padding bg-fff border-r-18">
<view class="font-bold u-m-b-32">绑定耗材</view>
<view class="u-flex u-row-between">
<view>商品名称</view>
</view>
@@ -58,8 +59,25 @@
</view>
</view>
<view class="default-box-padding bg-fff border-r-18 u-flex u-row-between u-m-t-32">
<view>当某个耗材的使用库存不足时商品自动售罄</view>
<view class="default-box-padding bg-fff border-r-18 u-m-t-32">
<view class="up-border-bottom u-p-b-32">
<view class="u-flex u-row-between ">
<view class="font-bold"> 自动售罄</view>
<up-switch :size="16" v-model="isAutoSoldStock" :inactive-value="0" :active-value="1"></up-switch>
</view>
<view class=" u-m-t-10">当某个耗材的使用库存不足时商品自动售罄</view>
</view>
<view class=" u-p-t-32">
<view class="">
<view class="font-bold u-m-b-16"> 退菜是否退库存</view>
<up-radio-group v-model="refundMode">
<up-radio v-for="(item,index) in tuiStockTypes" :key="index" :label="item.label"
:name="item.key"></up-radio>
</up-radio-group>
<view class="color-red u-m-t-10">当前店铺退菜退库存规则跟随商品分类</view>
</view>
</view>
</view>
<view class="bottom">
@@ -72,15 +90,42 @@
</template>
<script setup>
import { ref, reactive, watch, computed, onMounted } from 'vue';
import {
ref,
reactive,
watch,
computed,
onMounted
} from 'vue';
import infoBox from '@/commons/utils/infoBox.js'
import chooseHaocai from './choose-haocai.vue';
import chooseDanwei from './choose-danwei.vue';
import { hasPermission } from '@/commons/utils/hasPermission.js';
import {
hasPermission
} from '@/commons/utils/hasPermission.js';
import { getConsList } from '@/http/api/cons.js';
import { productBindCons } from '@/http/api/product.js';
import {
getConsList
} from '@/http/api/cons.js';
import {
productBindCons
} from '@/http/api/product.js';
const tuiStockTypes = ref([{
label: '退菜退库存',
key: 1
},
{
label: '仅退菜不退库存',
key: 2
},
{
label: '每次询问-退菜后弹窗提示,可手动选择',
key: 3
},
])
const isAutoSoldStock=defineModel('isAutoSoldStock',0)
const refundMode=defineModel('refundMode',1)
const emits = defineEmits(['cancel', 'updateGoods'])
@@ -91,7 +136,9 @@
return {
consList: [],
skuList: [],
type: ''
type: '',
isAutoSoldStock:0,
isRefundStock:1,
}
}
}
@@ -104,7 +151,8 @@
let haoCaiList = ref([])
let $haocaiMap = reactive({})
const skuList = ref(props.goods.skuList)
const consList = ref(props.goods.consList||[])
const consList = ref(props.goods.consList || [])
watch(() => props.goods.consList, (newval) => {
consList.value = newval
})
@@ -207,7 +255,6 @@
emits('updateGoods')
infoBox.showToast('修改成功')
}
</script>
<style lang="scss" scoped>

View File

@@ -0,0 +1,11 @@
<template>
<view>
<view></view>
</view>
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>

View File

@@ -6,10 +6,10 @@
<text class="">排序</text>
<text class="u-m-l-20">{{data.sort}}</text>
</view>
<view class="color-333 u-m-l-42 u-flex">
<!-- <view class="color-333 u-m-l-42 u-flex">
<text class="stock u-m-l-4">库存:{{data.stockNumber}}</text>
<up-icon @click="editStock" name="edit-pen" :size="16" :color="$utils.ColorMain"></up-icon>
</view>
</view> -->
</view>
<view>
<!-- <text class="u-font-28 color-666" @click="changePrice">改价</text> -->

View File

@@ -3,39 +3,30 @@
<view class="page-cell">
<view class="label">头像</view>
<view class="right">
<up-avatar
class="fileImg"
:src="vdata.shopInfo.coverImg ? vdata.shopInfo.coverImg : ''"
mode="aspectFill"
></up-avatar>
<up-avatar class="fileImg" :src="vdata.shopInfo.coverImg ? vdata.shopInfo.coverImg : ''"
mode="aspectFill"></up-avatar>
<view class="file" @tap="chooseAndUploadAvatar('coverImg')"></view>
</view>
</view>
<!-- <view class="page-cell m" @tap="updateValue('商户名称','shopName',vdata.shopInfo.shopName)"> -->
<view
class="page-cell m"
@tap="
<view class="page-cell m" @tap="
go.to('PAGES_SHOP_EDITVAL', {
name: 'shopName',
value: vdata.shopInfo.shopName,
})
"
>
">
<view class="label">商户名称</view>
<view class="right">
<view>{{ vdata.shopInfo.shopName }}</view>
<up-icon name="arrow-right" color="#999999" size="15"></up-icon>
</view>
</view>
<view
class="page-cell m"
@tap="
<view class="page-cell m" @tap="
go.to('PAGES_SHOP_EDITVAL', {
name: 'phone',
value: vdata.shopInfo.phone,
})
"
>
">
<view class="label">商户电话</view>
<view class="right">
<view>{{ vdata.shopInfo.phone }}</view>
@@ -49,14 +40,8 @@
<view class="page-cell m">
<view class="label">营业状态</view>
<view class="right">
<up-switch
v-model="vdata.shopInfo.status"
size="20"
:inactiveValue="2"
:activeValue="1"
activeColor="#0FC161"
@change="switchChange('status')"
></up-switch>
<up-switch v-model="vdata.shopInfo.status" size="20" :inactiveValue="2" :activeValue="1"
activeColor="#0FC161" @change="switchChange('status')"></up-switch>
</view>
</view>
<view class="page-cell m" @tap="showMap">
@@ -72,58 +57,31 @@
</view> -->
<view class="page-cell">
<view class="label">允许打包</view>
<view class="right"
><up-switch
v-model="vdata.takeout"
size="20"
activeColor="#0FC161"
@change="switchChange('eatModel')"
></up-switch
></view>
<view class="right"><up-switch v-model="vdata.takeout" size="20" activeColor="#0FC161"
@change="switchChange('eatModel')"></up-switch></view>
</view>
<view class="page-cell m">
<view class="label">是否开启会员余额支付</view>
<view class="right">
<up-switch
v-model="vdata.shopInfo.isAccountPay"
size="20"
:inactiveValue="0"
:activeValue="1"
activeColor="#0FC161"
@change="switchChange('isAccountPay')"
></up-switch>
<up-switch v-model="vdata.shopInfo.isAccountPay" size="20" :inactiveValue="0" :activeValue="1"
activeColor="#0FC161" @change="switchChange('isAccountPay')"></up-switch>
</view>
</view>
<view class="page-cell m">
<view class="label">是否开启数签子</view>
<view class="right">
<up-switch
v-model="vdata.shopInfo.isCountStick"
size="20"
:inactiveValue="0"
:activeValue="1"
activeColor="#0FC161"
@change="switchChange('isCountStick')"
></up-switch>
<up-switch v-model="vdata.shopInfo.isCountStick" size="20" :inactiveValue="0" :activeValue="1"
activeColor="#0FC161" @change="switchChange('isCountStick')"></up-switch>
</view>
</view>
<view class="page-cell m" style="display: block">
<view class="u-flex u-row-between">
<view class="label">点餐电子围栏</view>
<view class="right"
><up-switch
v-model="vdata.shopInfo.isOrderFence"
size="20"
:inactiveValue="0"
:activeValue="1"
activeColor="#0FC161"
@change="switchChange('isOrderFence')"
></up-switch
></view>
<view class="right"><up-switch v-model="vdata.shopInfo.isOrderFence" size="20" :inactiveValue="0"
:activeValue="1" activeColor="#0FC161" @change="switchChange('isOrderFence')"></up-switch>
</view>
<view class="u-m-t-6 color-666 u-font-24"
>开启后用户只能在店铺附近两公里范围内点餐</view
>
</view>
<view class="u-m-t-6 color-666 u-font-24">开启后用户只能在店铺附近两公里范围内点餐</view>
</view>
<!-- <view class="page-cell m">
@@ -142,29 +100,20 @@
<view class="page-cell">
<view class="label">
桌位费
<view
v-if="!vdata.isTableFee"
class="tableFee"
@tap="
<view v-if="!vdata.isTableFee" class="tableFee" @tap="
go.to('PAGES_SHOP_EDITVAL', {
name: 'tableFee',
value: vdata.shopInfo.tableFee,
})
"
>
">
{{ vdata.shopInfo.tableFee }}
</view>
</view>
<view class="right">
<view>
<up-checkbox-group>
<up-checkbox
label="免桌位费"
v-model:checked="vdata.isTableFee"
activeColor="#0FC161"
shape="circle"
@change="isTableFeeChange"
></up-checkbox>
<up-checkbox label="免桌位费" v-model:checked="vdata.isTableFee" activeColor="#0FC161"
shape="circle" @change="isTableFeeChange"></up-checkbox>
</up-checkbox-group>
</view>
</view>
@@ -186,62 +135,130 @@
</view>
</view> -->
<view class="page-cell m">
<view class="page-cell">
<view class="label">付费模式</view>
<view class="right">
<up-radio-group v-model="vdata.shopInfo.registerType" placement="row">
<up-radio
:customStyle="{ marginRight: '10px' }"
v-for="(item, index) in vdata.registerTypeList"
:key="index"
:label="item.name"
:name="item.value"
activeColor="#0FC161"
@change="radioChange"
></up-radio>
<up-radio :customStyle="{ marginRight: '10px' }" v-for="(item, index) in vdata.registerTypeList"
:key="index" :label="item.name" :name="item.value" activeColor="#0FC161"
@change="radioChange"></up-radio>
</up-radio-group>
</view>
</view>
<view
class="page-cell"
@tap="
<view class="page-cell m">
<view class="label">退菜退库存模式</view>
<view class="right">
<up-radio-group v-model="vdata.shopInfo.refundMode" placement="row">
<up-radio v-for="(item, index) in vdata.refund_modes" :key="index" :label="item.name"
:name="item.value" activeColor="#0FC161" @change="refundModeChange"></up-radio>
</up-radio-group>
</view>
</view>
<view class="page-cell" @tap="
go.to('PAGES_SHOP_QRCODE', {
paymentQrcode: vdata.shopInfo.paymentQrcode,
})
"
>
">
<view class="label">店铺收款码</view>
<view class="right"
><up-icon name="arrow-right" color="#999999" size="15"></up-icon
></view>
<view class="right"><up-icon name="arrow-right" color="#999999" size="15"></up-icon></view>
</view>
<!-- <view class="cutShop" @tap="go.to('PAGES_SHOP_LIST')">切换门店</view> -->
<up-modal :show="refundMode.show" title="提示" asyncClose android-*=""
showCancelButton
@close="refundMode.show=false"
@cancel="refundModeCancel"
@confirm="refundModeConfirm"
>
<view>
<view class="u-font-28">
<text>当前操作退菜退库存模式切换为</text>
<text class="color-red">{{refundMode.mode}}</text>
</view>
<view class="u-font-28 color-666 u-m-t-12">
<text class="">修改后可前往商品管理-商品分类中编辑/查看配置</text>
</view>
<view class="u-m-t-40 u-font-28 color-red">
本操作将会影响耗材库存数量的统计请谨慎操作
</view>
</view>
</up-modal>
</view>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
import { onShow } from "@dcloudio/uni-app";
import go from "@/commons/utils/go.js";
import { uploadFile } from "@/http/api/index.js";
import {
import {
ref,
reactive,
onMounted
} from "vue";
import {
onShow
} from "@dcloudio/uni-app";
import go from "@/commons/utils/go.js";
import {
uploadFile
} from "@/http/api/index.js";
import {
getShopInfo,
editShopInfo,
getShopExtend,
editShopExtend,
} from "@/http/api/shop.js";
} from "@/http/api/shop.js";
const vdata = reactive({
const refundMode = reactive({
show: false,
mode: ''
})
function refundModeCancel(){
vdata.shopInfo.refundMode=vdata.shopInfo.refundMode==1?2:1
refundMode.show = false
}
function refundModeConfirm(){
let params = {
id: vdata.shopInfo.id,
refundMode: vdata.shopInfo.refundMode,
};
updateShopInfo(params);
refundMode.show = false
}
function refundModeChange(e) {
console.log(e);
const item = vdata.refund_modes.find(v => v.value == e)
if (item) {
refundMode.mode = item.name
}
refundMode.show = true
}
const vdata = reactive({
shopInfo: {
status: 2,
isAccountPay: 0,
isMemberPrice: 0,
},
extendList: [],
registerTypeList: [
{ name: "先付费", value: "before" },
{ name: "后付费", value: "after" },
registerTypeList: [{
name: "先付费",
value: "before"
},
{
name: "后付费",
value: "after"
},
],
refund_modes: [{
name: "跟随商品分类",
value: 1
},
{
name: "跟随单商品",
value: 2
},
],
extendIndex: 0,
extendInfo: {},
@@ -251,23 +268,23 @@ const vdata = reactive({
label: "",
type: "",
inputValue: "",
});
onMounted(() => {
});
onMounted(() => {
shopExtend();
});
});
onShow(() => {
onShow(() => {
shopInfo();
uni.$on("refreshPreviousPage", (params) => {
// 这里执行刷新数据的操作例如重新调用API获取数据
refreshData(params);
});
});
});
/**
/**
* 输入内容修改
*/
let refreshData = (e) => {
let refreshData = (e) => {
let params = {
id: vdata.shopInfo.id,
};
@@ -275,13 +292,15 @@ let refreshData = (e) => {
vdata.type = e.name;
vdata.inputValue = e.value;
updateShopInfo(params, "input");
};
};
/**
/**
* 获取店铺信息
*/
const shopInfo = () => {
getShopInfo({ id: uni.getStorageSync("shopInfo").id }).then((res) => {
const shopInfo = () => {
getShopInfo({
id: uni.getStorageSync("shopInfo").id
}).then((res) => {
vdata.isTableFee = res.isTableFee == 1 ? true : false;
if (res.eatModel.split(",").indexOf("dine-in") != -1) {
vdata.dineIn = true;
@@ -291,12 +310,12 @@ const shopInfo = () => {
}
vdata.shopInfo = res;
});
};
};
/**
/**
* 获取店铺图片
*/
let shopExtend = () => {
let shopExtend = () => {
getShopExtend().then((res) => {
if (res && res.length > 0) {
vdata.extendList = res;
@@ -304,32 +323,33 @@ let shopExtend = () => {
vdata.extendInfo = res[0];
}
});
};
};
// 台桌清理模式修改
function tableClearChange(n) {
// 台桌清理模式修改
function tableClearChange(n) {
let params = {
id: vdata.shopInfo.id,
tableClearType: n,
};
updateShopInfo(params);
}
}
/**
/**
* 付费模式修改
*/
let radioChange = (n) => {
let radioChange = (n) => {
let params = {
id: vdata.shopInfo.id,
registerType: n,
};
updateShopInfo(params);
};
};
/**
/**
* 修改
*/
let updateShopInfo = (params, type) => {
let updateShopInfo = (params, type) => {
editShopInfo(params).then((res) => {
if (res) {
uni.showToast({
@@ -346,22 +366,22 @@ let updateShopInfo = (params, type) => {
vdata.shopInfo[vdata.type] = vdata.inputValue;
}
});
};
};
/**
/**
* 修改店铺图片
*/
let updateShopExtend = () => {
let updateShopExtend = () => {
editShopExtend({
autokey: vdata.extendInfo.autoKey,
value: vdata.extendInfo.value,
}).then((res) => {});
};
};
/**
/**
* 上传头像
*/
let chooseAndUploadAvatar = (type) => {
let chooseAndUploadAvatar = (type) => {
// 选择图片
uni.chooseImage({
count: 1, // 默认为1只选择一张图片
@@ -398,32 +418,32 @@ let chooseAndUploadAvatar = (type) => {
console.log("choose image fail:", chooseImageError);
},
});
};
};
/**
/**
* 店铺图片TAB切换
*/
let extendTabClick = (item, index) => {
let extendTabClick = (item, index) => {
vdata.extendInfo = item;
vdata.extendIndex = index;
};
};
/**
/**
* 是否免桌位费
*/
let isTableFeeChange = (e) => {
let isTableFeeChange = (e) => {
if (e) {
vdata.isTableFee = true;
} else {
vdata.isTableFee = false;
}
switchChange("isTableFee");
};
};
/**
/**
* 修改
*/
let switchChange = (type) => {
let switchChange = (type) => {
let params = {
id: vdata.shopInfo.id,
};
@@ -467,24 +487,24 @@ let switchChange = (type) => {
break;
}
updateShopInfo(params);
};
};
/**
/**
* 选择地图
*/
let showMap = () => {
let showMap = () => {
// 本地 测试选择
// 打开地图
uni.chooseLocation({
// type: 'wgs84',
success: function (res) {
success: function(res) {
vdata.shopInfo.lng = res.longitude.toFixed(6); // IOS 小程序中: 经纬度12位。
vdata.shopInfo.lat = res.latitude.toFixed(6);
vdata.shopInfo.address = res.name;
switchChange("address");
},
fail: function (err) {
fail: function(err) {
console.log(err);
// uni.showToast({
// title:err,
@@ -492,13 +512,14 @@ let showMap = () => {
// })
},
});
};
};
</script>
<style lang="scss" scoped>
.page-wrapper {
.page-wrapper {
background-color: #f8f8f8;
padding-bottom: 32rpx;
.page-cell {
display: flex;
justify-content: space-between;
@@ -506,6 +527,7 @@ let showMap = () => {
padding: 32rpx 28rpx;
box-sizing: border-box;
background-color: #fff;
.label {
font-weight: bold;
font-size: 28rpx;
@@ -514,6 +536,7 @@ let showMap = () => {
align-items: center;
flex-shrink: 0;
margin-right: 20rpx;
.tableFee {
width: 186rpx;
height: 54rpx;
@@ -528,14 +551,17 @@ let showMap = () => {
box-sizing: border-box;
}
}
.extendList {
width: 100%;
display: flex;
flex-direction: column;
margin-top: 24rpx;
.extendTab {
display: flex;
justify-content: flex-start;
.extendTab_item {
font-size: 24rpx;
font-weight: 400;
@@ -544,21 +570,25 @@ let showMap = () => {
border: 2rpx solid #e5e5e5;
margin-right: 20rpx;
}
.active {
background: #318afe;
border: 2rpx solid #318afe;
color: #fff;
}
}
.extend_content {
display: flex;
margin-top: 32rpx;
.preview {
min-width: 146rpx;
height: 342rpx;
position: relative;
margin-right: 32rpx;
background-color: #f7f7f7;
::v-deep .bg,
::v-deep .bg .u-image,
::v-deep .bg .u-image__image {
@@ -603,6 +633,7 @@ let showMap = () => {
position: absolute;
top: 0;
}
::v-deep .bg.ticket_logo,
::v-deep .bg.ticket_logo .u-image,
::v-deep .bg.ticket_logo .u-image__image {
@@ -611,6 +642,7 @@ let showMap = () => {
position: absolute;
top: 0;
}
::v-deep .ticket_logo.img .u-image,
::v-deep .ticket_logo.img .u-image__image {
width: 146rpx !important;
@@ -628,19 +660,23 @@ let showMap = () => {
background-color: #fff;
}
}
.extend_img {
display: flex;
flex-direction: column;
.extend_title {
font-weight: 400;
font-size: 24rpx;
color: #333333;
margin-bottom: 16rpx;
}
.fileUp {
width: 148rpx;
height: 148rpx;
position: relative;
.file {
width: 148rpx;
height: 148rpx;
@@ -648,6 +684,7 @@ let showMap = () => {
top: 0;
}
}
::v-deep .u-image,
::v-deep .u-image__image {
width: 148rpx !important;
@@ -657,15 +694,19 @@ let showMap = () => {
}
}
}
.column {
flex-direction: column;
.label {
align-self: flex-start;
}
}
.m {
margin-bottom: 12rpx;
}
.cutShop {
width: 530rpx;
height: 80rpx;
@@ -701,11 +742,16 @@ let showMap = () => {
.fileImg {
width: 112rpx !important;
height: 112rpx !important;
::v-deep .u-avatar__image {
width: 112rpx !important;
height: 112rpx !important;
}
}
}
}
}
.color-red {
color: red;
}
</style>

View File

@@ -3,7 +3,9 @@
<up-image :src="data.coverImg" mode="aspectFill" :width="img.width" :height="img.height"></up-image>
<view class="info u-flex u-row-between u-col-top u-flex-col">
<view class="limit-discount" v-if="is_time_discount">限时折扣</view>
<view class="nowStockerNumber" v-if="nowStockerNumber<=10">
剩余库存{{nowStockerNumber}}
</view>
<view>
<view>
<text class="up-line-1">{{ data.name }}</text>
@@ -32,7 +34,7 @@
<image src="/pagesCreateOrder/static/images/icon-reduce.svg" class="icon" mode="">
</image>
</view>
<view class="u-font-32" >
<view class="u-font-32">
{{ data.chooseNumber.toFixed(2) }}
</view>
@@ -56,7 +58,7 @@
<view class="isSellout" v-else-if="data.isSoldStock == 1">
<image class="isSellout_icon" src="/pagesCreateOrder/static/images/no-sold.svg" mode=""></image>
</view>
<view class="isSellout" v-else-if="data.isStock == 1 && data.stockNumber <= 0">
<view class="isSellout" v-else>
<image class="isSellout_icon" src="/pagesCreateOrder/static/images/no-stock.svg" mode=""></image>
</view>
</template>
@@ -107,6 +109,10 @@
return {};
},
},
consStockList: {
type: Array,
default:[]
}
});
//判断是否是时间折扣商品
@@ -156,12 +162,64 @@
return false;
}
return (
(item.isStock == 1 && item.stockNumber <= 0) ||
!consStockisFull(item) ||
item.isSoldStock == 1 ||
item.isSale == 0 ||
!isProductAvailable(item.days, item.startTime, item.endTime)
);
});
const stockNumber=computed(()=>{
})
// 1. 筛选匹配的耗材列表
const conslist=computed(()=>{
if(props.consStockList.length<=0){
return []
}
return props.consStockList.filter(v => {
return props.data.consList.find(i =>{
return i.consInfoId == v.consId
});
});
})
// 2. 找到 stockNumber 最小的那一项
const minConsItem=computed(()=>{
if(conslist.value.length<=0){
return null
}
return conslist.value.reduce((prev, current) => {
return prev.stockNumber < current.stockNumber ? prev : current;
});
})
// 3. 找到和 minItem 的 consId 一样的那个消耗配置项
const targetCons=computed(()=>{
if(!minConsItem.value){
return null
}
return props.data.consList.find(i => i.consInfoId == minConsItem.value.consId);
})
const nowStockerNumber=computed(()=>{
if(!targetCons.value||!minConsItem.value){
return 9999
}
return Math.floor(minConsItem.value.stockNumber/targetCons.value.surplusStock)
})
function consStockisFull(item) {
// 无数据直接返回 true或按你需求返回 false
if (!conslist.value.length) return true;
if(!minConsItem.value)return true;
if(!targetCons.value) return true;
// 4. 判断:最小库存 > 每份消耗库存 → 返回 true否则 false
if (nowStockerNumber.value>=1) {
return true;
} else {
return false;
}
}
// 判断商品是否在可售时间内
function isProductAvailable(sellDaysStr, startTimeStr, endTimeStr) {
// 将后端返回的字符串转换为数组
@@ -306,4 +364,14 @@
color: rgba(255, 255, 255, 0.8);
text-decoration: line-through;
}
.nowStockerNumber{
position: absolute;
left: 24rpx;
bottom: 80rpx;
background-color: rgba(255, 255, 255, .8);
color: red;
padding: 4rpx 8rpx;
font-size: 24rpx;
border-radius: 4rpx ;
}
</style>

View File

@@ -36,9 +36,7 @@
</view>
</scroll-view>
<scroll-view :scroll-top="data.scrollRightTop" scroll-y scroll-with-animation class="right-box"
@scroll="rightScroll"
@scrolltoupper="scrolltoupper"
>
@scroll="rightScroll" @scrolltoupper="scrolltoupper">
<view class="page-view u-p-l-24">
<view class="list-tight-top">
<template v-if="lingshi.show">
@@ -62,7 +60,7 @@
<view class="item-container">
<view class="thumb-box" v-for="(goodsItem, goodsIndex) in item.foods" :key="goodsIndex">
<list-goods-item :limitTimeDiscount="data.limitTimeDiscount"
@chooseGuige="chooseGuige($event, index)"
:consStockList="consStockList" @chooseGuige="chooseGuige($event, index)"
@add="goodsUpdate($event, index, true)"
@reduce="goodsUpdate($event, index, false)" @tapweigh="tapweigh($event, index)"
:index="goodsIndex" :data="goodsItem"></list-goods-item>
@@ -81,7 +79,7 @@
<view class="u-flex u-m-t-20 u-flex-wrap u-row-between">
<view class="u-m-b-30" v-for="(goodsItem, goodsIndex) in searchResult" :key="goodsIndex">
<list-goods-item :img="{ width: '330rpx', height: '330rpx' }"
:limitTimeDiscount="data.limitTimeDiscount"
:consStockList="consStockList" :limitTimeDiscount="data.limitTimeDiscount"
@chooseGuige="chooseGuige(goodsItem.goodsIndex, goodsItem.index)"
@add="searchGoodsUpdate(goodsItem, goodsIndex, true)"
@reduce="searchGoodsUpdate(goodsItem, goodsIndex, false)"
@@ -98,8 +96,7 @@
<view class="bottom w-full">
<my-car :isCreateOrderToDetail="isCreateOrderToDetail" @updateNumber="carsNumberChange" :table="data.table"
:data="cars" :orderInfo="data.orderInfo" :limitTimeDiscount="data.limitTimeDiscount"
@changeNumber="goodsChangeNumber"
@clear="cleaCart"></my-car>
@changeNumber="goodsChangeNumber" @clear="cleaCart"></my-car>
</view>
<!-- 套餐选择规格 -->
<taocanModel ref="taocanModelRef" @confirm="taocanConfirm" :goodsData="selGoods"></taocanModel>
@@ -117,7 +114,8 @@
</view>
<!-- 修改购物车数量 -->
<popupChangeNumber v-model="popupChangeNumberData.show" :goods="popupChangeNumberData.data" @confirm="carsNumberChange"></popupChangeNumber>
<popupChangeNumber v-model="popupChangeNumberData.show" :goods="popupChangeNumberData.data"
@confirm="carsNumberChange"></popupChangeNumber>
</view>
</template>
<script setup>
@@ -145,9 +143,9 @@
} from '@/http/api/product/stick.js'
import popupChangeNumber from './components/popup-change-number.vue'
const popupChangeNumberData=reactive({
show:false,
data:null
const popupChangeNumberData = reactive({
show: false,
data: null
})
import guigeModel from "./components/guige";
@@ -174,8 +172,8 @@
limitTimeDiscount
} from "@/http/api/market/limitTimeDiscount.js";
provide("yskUtils", yskUtils);
const shopInfo = reactive({}) ;
Object.assign(shopInfo,uni.getStorageSync("shopInfo"))
const shopInfo = reactive({});
Object.assign(shopInfo, uni.getStorageSync("shopInfo"))
provide("shopInfo", uni.getStorageSync("shopInfo"));
import {
@@ -196,6 +194,9 @@
cancelOrder,
rmPlaceOrder,
} from "@/http/api/order.js";
import {
getConsStock
} from '@/http/api/cons.js'
const modal = reactive({
key: "",
@@ -349,6 +350,24 @@
let $originGoods = [];
let $category = [];
const consStockList = ref([])
function getCons() {
return new Promise((resolve, reject) => {
try {
getConsStock({
shopId: uni.getStorageSync("shopInfo").id
}).then(res => {
consStockList.value = res || []
console.log('consStockList', consStockList.value);
resolve()
})
} catch (err) {
reject()
}
})
}
async function init() {
if (option.type == "add") {
setTabBar($category, $originGoods, []);
@@ -356,7 +375,7 @@
let shopInfoRes = await getShopInfo({
id: uni.getStorageSync("shopInfo").id
});
Object.assign(shopInfo,shopInfoRes)
Object.assign(shopInfo, shopInfoRes)
uni.setStorageSync("shopInfo", shopInfoRes);
// 获取分类数据
let categoryRes = await categoryPage({
@@ -364,6 +383,8 @@
size: 300
});
$category = categoryRes.records;
// 获取耗材数据
await getCons()
// 获取商品数据
const goodsRes = await getGoods();
const goods = goodsRes.filter((v) => {
@@ -387,6 +408,8 @@
initCart();
}
const allHistoryOrder=ref([])
/**
* 获取订单详情
*/
@@ -409,13 +432,13 @@
console.log("data.historyOrder===", data.historyOrder);
let allHistoryOrder = data.historyOrder.map((item) => {
allHistoryOrder.value = data.historyOrder.map((item) => {
return [...item.info];
});
}).flat();
// console.log('allHistoryOrder===', allHistoryOrder.flat());
data.historyOrderNum = 0;
allHistoryOrder.flat().map((item) => {
allHistoryOrder.value.map((item) => {
data.historyOrderNum += item.num;
});
// console.log('data.historyOrderNum===', data.historyOrderNum);
@@ -741,7 +764,22 @@
}
// initCart()
}
// 封装成 Promise 的确认弹窗
const showConfirmModal = (title, content) => {
return new Promise((resolve) => {
uni.showModal({
title: title,
content: content,
showCancel: true,
cancelText: '取消添加',
confirmText: '继续',
success(res) {
// 确认返回 true取消/关闭返回 false
resolve(res.confirm === true);
}
});
});
};
/**
* 菜品操作
* @param {Object} foodsindex
@@ -800,6 +838,29 @@
//更新
let cartItem = cars[goodsInCarIndex];
let number = isAdd ? cartItem.number + 1 : +cartItem.number - 1;
if(isAdd){
if (number == 2 ) {
// 等待用户点击
const isConfirm = await showConfirmModal(
'购物车已有该商品,请确认是否重复',
'菜名名称:《' + $goods.name + '》'
);
if (!isConfirm) {
return
}
}
if(allHistoryOrder.value.find(v=>v.productId==$goods.id)){
// 等待用户点击
const isConfirm = await showConfirmModal(
'该商品已下单过,请确认是否重复',
'菜名名称:《' + $goods.name + '》'
);
if (!isConfirm) {
return
}
}
}
if (!isAdd) {
if (number === 0 || number < suitNum) {
//移除
@@ -828,6 +889,7 @@
data.isGoodsAdd = false;
setSearchGoods(searchGoodsIndex, number);
} else {
// 不影响之前的代码 称重suit单独处理
if ($goods.type == "weight" && showCurrentInput) {
suitNum = showCurrentInput;
@@ -839,6 +901,16 @@
return;
}
}
if(allHistoryOrder.value.find(v=>v.productId==$goods.id)){
// 等待用户点击
const isConfirm = await showConfirmModal(
'该商品已下单过,请确认是否重复',
'菜名名称:《' + $goods.name + '》'
);
if (!isConfirm) {
return
}
}
// 套餐和单规格
if ($goods.groupType != 1) {
//增加
@@ -862,10 +934,10 @@
function goodsChangeNumber(e){
function goodsChangeNumber(e) {
console.log(e);
popupChangeNumberData.data=e;
popupChangeNumberData.show=true
popupChangeNumberData.data = e;
popupChangeNumberData.show = true
}
@@ -937,8 +1009,7 @@
tabbarItem.foods.find((v) => v.id == e.goods.product_id);
}
});
$sku = !e.goods.product_id ?
{
$sku = !e.goods.product_id ? {
suitNum: 1
} :
$goods.skuList.find((v) => v.id == e.goods.sku_id);
@@ -1018,13 +1089,22 @@
* @param {Object} skuList
*/
function returnSelGoodsSkuList(selectSpecInfo) {
// 👇 修复:如果是字符串,转成对象
if (typeof selectSpecInfo === 'string') {
selectSpecInfo = JSON.parse(selectSpecInfo);
}
let specInfo = [];
console.log('selectSpecInfo', selectSpecInfo);
for (var key in selectSpecInfo) {
console.log('key', key); // 现在会正确打印:口味、汤
specInfo.push({
name: key,
value: selectSpecInfo[key],
});
}
let result = specInfo.map((v, index) => {
return {
...v,
@@ -1062,9 +1142,31 @@
} = res;
let carGoods = cars[index];
let cartId = carGoods.id;
let newNumber = carGoods.number * 1 + suitNum;
let suitNum = goods.skuList[0].suitNum || 1;
let newNumber = carGoods.number * 1 + suitNum;
if (newNumber == 2&&carGoods.number<newNumber) {
// 等待用户点击
const isConfirm = await showConfirmModal(
'请确认当前菜品是否已上菜?',
'菜名名称' + goods.name + ''
);
if (!isConfirm) {
return
}
if(allHistoryOrder.value.find(v=>v.productId==goods.id)){
// 等待用户点击
const isConfirm = await showConfirmModal(
'该商品已下单过,请确认是否重复',
'菜名名称:《' + goods.name + '》'
);
if (!isConfirm) {
return
}
}
}
editCart({
id: cartId,
number: newNumber,
@@ -1079,6 +1181,17 @@
);
data.isGoodsAdd = false;
} else {
if(allHistoryOrder.value.find(v=>v.productId==goods.id)){
// 等待用户点击
const isConfirm = await showConfirmModal(
'该商品已下单过,请确认是否重复',
'菜名名称:《' + goods.name + '》'
);
if (!isConfirm) {
return
}
}
//添加
editCart({
number: suitNum,
@@ -1106,8 +1219,7 @@
return carsGoods.sku_id == sku_id && carsGoods.product_id == product_id;
});
const carGoods = cars[goodsInCarIndex];
return carGoods ?
{
return carGoods ? {
index: goodsInCarIndex,
carGoods,
} :
@@ -1362,7 +1474,7 @@
count: 1, //默认9
sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
sourceType: ["album", "camera "],
success: async function (res) {
success: async function(res) {
uni.showLoading({
title: "上传中",
});
@@ -1371,15 +1483,15 @@
console.log(fileRes)
uni.hideLoading();
if (fileRes) {
uni.setStorageSync('stickData',{
table:data.table,
orderInfo:data.orderInfo,
limitTimeDiscount:data.limitTimeDiscount
uni.setStorageSync('stickData', {
table: data.table,
orderInfo: data.orderInfo,
limitTimeDiscount: data.limitTimeDiscount
})
go.to("PAGES_CREATE_ORDER_STICK", {
tableCode: data.table.tableCode,
number:fileRes,
isCreateOrderToDetail:isCreateOrderToDetail.value,
number: fileRes,
isCreateOrderToDetail: isCreateOrderToDetail.value,
});
@@ -1425,7 +1537,7 @@
* @param {Object} index
*/
async function swichMenu(index) {
if (data.arr.length !=data.tabbar.length) {
if (data.arr.length != data.tabbar.length) {
await getMenuItemTop();
}
if (index == data.current) return;
@@ -1441,7 +1553,7 @@
data.scrollRightTop = data.arr[index] + data.topZhanwei;
console.log('scrollRightTop',data.scrollRightTop );
console.log('scrollRightTop', data.scrollRightTop);
data.current = index;
leftMenuStatus(index);
}
@@ -1518,7 +1630,7 @@
arr.push(rect.top - rects[0].top);
});
data.arr = arr;
console.log('每一项高度',data.arr);
console.log('每一项高度', data.arr);
resolve();
})
.exec();
@@ -1526,7 +1638,7 @@
}
function scrolltoupper(){
function scrolltoupper() {
data.current = 0;
}
@@ -1537,7 +1649,7 @@
async function rightScroll(e) {
data.oldScrollTop = e.detail.scrollTop;
if(e.detail.scrollTop<=0||e.detail.scrollTop<data.arr[1]){
if (e.detail.scrollTop <= 0 || e.detail.scrollTop < data.arr[1]) {
data.current = 0;
isTabClickOver = true;
return

View File

@@ -1,4 +1,5 @@
<template>
<view>
<my-model title="退菜" ref="model" @close="onModelClose" @open="onModelOpen">
<template #desc>
<view class="u-p-30 u-text-left">
@@ -36,8 +37,8 @@
<view class="u-flex u-m-r-16 u-m-b-16" v-for="(item,index) in tags" :key="index">
<up-tag @click="changeTagSel(item)" :text="item.label" plain borderColor="#E6FOFF"
color="#318AFE" v-if="item.checked"> </up-tag>
<up-tag @click="changeTagSel(item)" borderColor="#E5E5E5" color="#666" :text="item.label"
plain v-else> </up-tag>
<up-tag @click="changeTagSel(item)" borderColor="#E5E5E5" color="#666"
:text="item.label" plain v-else> </up-tag>
</view>
</view>
<view class="u-m-t-24">
@@ -50,16 +51,37 @@
<view class="u-p-t-18 u-p-l-30 u-p-r-30 u-p-b-10">
<my-button box-shadow shape="circle" @tap="confirm">确认退菜</my-button>
<view class="u-m-t-10">
<my-button @tap="onModelClose" shape="circle" bgColor="#fff" type="cancel" box-shadow>取消</my-button>
<my-button @tap="onModelClose" shape="circle" bgColor="#fff" type="cancel"
box-shadow>取消</my-button>
</view>
</view>
</template>
</my-model>
<up-modal :show="confirmModal.show" title="提示" @close="confirmModalClose" @cancel="confirmModalClose"
@confirm="confirmModalConfirm" showCancelButton>
<view>
<view>
<up-radio-group v-model="confirmModal.selRefundStock">
<up-radio v-for="(item,index) in confirmModal.refundStocks" :key="index" :label="item.name"
:name="item.key"></up-radio>
</up-radio-group>
</view>
</view>
</up-modal>
</view>
</template>
<script setup>
import { reactive, ref, watch } from 'vue';
import {
reactive,
ref,
watch
} from 'vue';
import infoBox from '@/commons/utils/infoBox.js'
const emits = defineEmits(['update:show', 'confirm'])
const props = defineProps({
@@ -76,6 +98,22 @@
default: false
}
})
const confirmModal = reactive({
show: false,
selRefundStock: false,
refundStocks: [{
name: '已上菜(仅退菜不退库存)',
key: false
}, {
name: '未上菜(退菜后退库存)',
key: true,
}]
})
function confirmModalClose() {
confirmModal.show = false
confirmModal.selRefundStock = false
}
const form = reactive({
note: ''
})
@@ -157,11 +195,51 @@
})
form.note = ''
}
import {
getProductDetail
} from '@/http/api/product.js'
import {
getCategoryDetail
} from '@/http/api/cateGory.js'
async function getGoodsCategory(goods) {
const res = await getProductDetail(goods.productId)
if (res) {
console.log('res', res);
const res1 = await getCategoryDetail(res.categoryId)
return res1
}
uni.showToast({
title: '获取该商品信息数据失败',
icon: 'none'
})
return null
}
function confirmModalConfirm() {
refundGoods()
confirmModalClose()
}
function refundGoods() {
const selTag = tags.value.filter(item => item.checked).map(item => item.label).join(",")
const note = selTag + (form.note.length > 0 ? "," + form.note : "");
let par = {
orderId: props.data.orderId,
refundAmount: number.value * props.data.unitPrice,
refundReason: note,
refundStock: confirmModal.selRefundStock,
refundDetails: [{
id: props.data.id,
returnAmount: number.value * props.data.unitPrice,
num: number.value,
}],
}
emits('confirm', par)
}
/**
* 确认退菜
*/
function confirm() {
async function confirm() {
const selTag = tags.value.filter(item => item.checked).map(item => item.label).join(",")
const note = selTag + (form.note.length > 0 ? "," + form.note : "");
console.log({
@@ -171,17 +249,22 @@
if (!note) {
return infoBox.showToast("请输入退菜原因");
}
let par = {
orderId: props.data.orderId,
refundAmount: number.value * props.data.unitPrice,
refundReason: note,
refundDetails: [{
id: props.data.id,
returnAmount: number.value * props.data.unitPrice,
num: number.value,
}],
const shopInfo = uni.getStorageSync('shopInfo')
if (shopInfo.refundMode == 1) {
const res = await getGoodsCategory(props.data)
if (res.refundMode === 3) {
confirmModal.show = true
return
}
emits('confirm', par)
}
if (shopInfo.refundMode == 2) {
const res = await getProductDetail(props.data.productId)
if (res.refundMode === 3) {
confirmModal.show = true
return
}
}
refundGoods()
}
</script>

View File

@@ -2,14 +2,17 @@
<view class="min-page bg-gray u-p-30">
<view class="bg-fff u-p-l-30 u-p-r-30 ">
<view class="myTabs u-m-t-20">
<my-tabs :list="pageData.tabsList" :modelValue="pageData.tabsIndex" :textKey="'label'" @change="tabsChange"></my-tabs>
<my-tabs :list="pageData.tabsList" :modelValue="pageData.tabsIndex" :textKey="'label'"
@change="tabsChange"></my-tabs>
</view>
</view>
<view v-if="pageData.tabsIndex == 2" class="bg-fff u-p-24 border-r-12 u-flex u-row-between" style="margin-top: 30rpx;">
<up-input type="digit" placeholder="请输入退款金额" @change="parseIntNumber($event)" border="surround" v-model="pageData.modify" >
<view v-if="pageData.tabsIndex == 2" class="bg-fff u-p-24 border-r-12 u-flex u-row-between"
style="margin-top: 30rpx;">
<up-input type="digit" placeholder="请输入退款金额" @change="parseIntNumber($event)" border="surround"
v-model="pageData.modify">
<template #prefix>
<up-text text="¥" margin="0 3px 0 0" type="tips" ></up-text>
<up-text text="¥" margin="0 3px 0 0" type="tips"></up-text>
</template>
</up-input>
</view>
@@ -27,7 +30,7 @@
</view>
<template v-if="item.productId=='-999'">
<view class="u-flex">
<view class="color-red" >{{item.priceAmount}}</view>
<view class="color-red">{{item.priceAmount}}</view>
<view class="u-flex u-m-l-32 u-col-center">
<view class="u-m-l-28 u-m-r-28">x{{item.number}}</view>
</view>
@@ -47,19 +50,19 @@
</view>
</view>
<template v-if="!option.userCouponId">
<view class="bg-fff u-m-t-32 u-p-24 border-r-12 u-flex u-row-between" >
<view class="bg-fff u-m-t-32 u-p-24 border-r-12 u-flex u-row-between">
<view>支付金额</view>
<view>
{{to2(orderDetail.info.payAmount)}}
</view>
</view>
<view class="bg-fff u-m-t-32 u-p-24 border-r-12 u-flex u-row-between" >
<view class="bg-fff u-m-t-32 u-p-24 border-r-12 u-flex u-row-between">
<view>剩余可退金额</view>
<view class="color-red">
{{to2(orderDetail.info.payAmount - orderDetail.info.refundAmount)}}
</view>
</view>
<view class="bg-fff u-m-t-32 u-p-24 border-r-12 u-flex u-row-between" >
<view class="bg-fff u-m-t-32 u-p-24 border-r-12 u-flex u-row-between">
<view>退款金额</view>
<view class="color-red">
{{to2(pageData.tabsIndex == 1 ? alltuikuanPrice : (pageData.tabsIndex == 2 ? pageData.modify : tuikuanPrice))}}
@@ -96,35 +99,67 @@
:color="$utils.ColorMain"></up-button>
</view>
<confirmRefundPopup ref="refundPopup" />
<up-modal :show="confirmModal.show" title="提示" @close="confirmModalClose" @cancel="confirmModalClose"
@confirm="confirmModalConfirm" showCancelButton>
<view>
<view>
<up-radio-group v-model="confirmModal.selRefundStock">
<up-radio v-for="(item,index) in confirmModal.refundStocks" :key="index" :label="item.name"
:name="item.key"></up-radio>
</up-radio-group>
</view>
</view>
</up-modal>
</view>
</template>
<script setup>
import { computed, reactive, ref, watch } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app';
import {
computed,
reactive,
ref,
watch
} from 'vue';
import {
onLoad,
onShow
} from '@dcloudio/uni-app';
import confirmRefundPopup from './components/confirmRefundPopup.vue';
import {hasPermission} from '@/commons/utils/hasPermission.js'
import { refundOrder } from '@/http/api/order.js'
import { mathFloorPrice } from '@/commons/utils/goodsUtil.js'
import {
hasPermission
} from '@/commons/utils/hasPermission.js'
import {
refundOrder
} from '@/http/api/order.js'
import {
mathFloorPrice
} from '@/commons/utils/goodsUtil.js'
let note = ref('')
const tuikuan = reactive({
list: ['点错', '数量点错', '客人要求', '协商退费'],
sel: -1
})
const pageData = reactive({
tabsList: [
{label: '部分退款', value: 0},
{label: '全部退款', value: 1},
{label: '自定义退款', value: 2},
tabsList: [{
label: '部分退款',
value: 0
},
{
label: '全部退款',
value: 1
},
{
label: '自定义退款',
value: 2
},
],
tabsIndex: 0,
modify: '',
})
const option=reactive({
productId:'-999'
const option = reactive({
productId: '-999'
})
const orderDetail = reactive({
goodsList: [],
@@ -148,17 +183,17 @@
*/
function tabsChange(i) {
pageData.tabsIndex = pageData.tabsList[i].value
if( pageData.tabsIndex == 0){ // 部分退款
if (pageData.tabsIndex == 0) { // 部分退款
orderDetail.goodsList.map(v => {
v.number = '0.00'
})
}
if( pageData.tabsIndex == 1){ // 全部退款
if (pageData.tabsIndex == 1) { // 全部退款
orderDetail.goodsList.map(v => {
v.number = v.num.toFixed(2)
})
}
if( pageData.tabsIndex == 2){ // 自定义退款
if (pageData.tabsIndex == 2) { // 自定义退款
orderDetail.goodsList.map(v => {
v.number = '0.00'
})
@@ -168,11 +203,12 @@
function changeTuiKuanSel(i) {
tuikuan.sel = i
}
function parseIntNumber (e) {
if ( e > (orderDetail.info.payAmount - orderDetail.info.refundAmount) ) {
setTimeout(()=>{
function parseIntNumber(e) {
if (e > (orderDetail.info.payAmount - orderDetail.info.refundAmount)) {
setTimeout(() => {
pageData.modify = (orderDetail.info.payAmount - orderDetail.info.refundAmount).toFixed(2)
},100)
}, 100)
}
}
/**
@@ -198,7 +234,7 @@
*/
const tuikuanPrice = computed(() => {
return orderDetail.goodsList.reduce((prve, cur) => {
const n= mathFloorPrice(cur.number * cur.unitPrice,cur)
const n = mathFloorPrice(cur.number * cur.unitPrice, cur)
return (parseFloat(prve) + parseFloat(n)).toFixed(2)
}, 0)
})
@@ -208,8 +244,8 @@
*/
const surplusRefundPrice = computed(() => {
return orderDetail.info.payAmount - orderDetail.goodsList.reduce((prve, cur) => {
const n = parseFloat( mathFloorPrice(cur.refundNum * cur.unitPrice,cur))
return (parseFloat(prve) + parseFloat(n)).toFixed(2)*1
const n = parseFloat(mathFloorPrice(cur.refundNum * cur.unitPrice, cur))
return (parseFloat(prve) + parseFloat(n)).toFixed(2) * 1
}, 0)
})
@@ -218,8 +254,8 @@
*/
const alltuikuanPrice = computed(() => {
return orderDetail.info.payAmount - orderDetail.goodsList.reduce((prve, cur) => {
const n = parseFloat( mathFloorPrice(cur.refundNum * cur.unitPrice,cur))
return (parseFloat(prve) + parseFloat(n)).toFixed(2)*1
const n = parseFloat(mathFloorPrice(cur.refundNum * cur.unitPrice, cur))
return (parseFloat(prve) + parseFloat(n)).toFixed(2) * 1
}, 0)
})
@@ -228,13 +264,13 @@
}
function changeItem(item, step) {
if( item.num <= 0){
if (item.num <= 0) {
return
}
if(item.productId=='-999'){
if (item.productId == '-999') {
return
}
if( pageData.tabsIndex != 0) {
if (pageData.tabsIndex != 0) {
return;
}
let newval = item.number * 1 + step * 1;
@@ -255,16 +291,16 @@
*/
let params;
async function tuikuanConfirm() {
const canTuikuan=await hasPermission('允许退款')
if(!canTuikuan){
const canTuikuan = await hasPermission('允许退款')
if (!canTuikuan) {
return uni.$utils.showToast('您没有退款权限')
}
if (pageData.tabsIndex != 2&&tuikuanNumber.value <= 0) {
if (pageData.tabsIndex != 2 && tuikuanNumber.value <= 0) {
return uni.$utils.showToast('退款商品数量不能为0')
}
const selTag=tuikuan.list[tuikuan.sel]
const noteResult=`${selTag?selTag:''}${note.value?(','+note.value):''}`
const selTag = tuikuan.list[tuikuan.sel]
const noteResult = `${selTag?selTag:''}${note.value?(','+note.value):''}`
if (!noteResult) {
return uni.$utils.showToast('请输入或选择退款原因!')
}
@@ -272,42 +308,103 @@
params = {
orderId: option.orderId,
refundReason: noteResult,
refundDetails: orderDetail.goodsList.filter(v=>v.number*1).map(v=>{
refundStock: confirmModal.selRefundStock,
refundDetails: orderDetail.goodsList.filter(v => v.number * 1).map(v => {
return {
id:v.id,
id: v.id,
returnAmount: v.number * 1 * v.unitPrice,
num: v.number * 1
}
})
}
if( pageData.tabsIndex == 2){
if (pageData.tabsIndex == 2) {
params.modify = true
params.refundAmount = (pageData.modify*1).toFixed(2)
params.refundAmount = (pageData.modify * 1).toFixed(2)
} else {
params.modify = false
params.refundAmount = pageData.tabsIndex == 1 ? alltuikuanPrice.value : tuikuanPrice.value
}
if ( pageData.tabsIndex == 2 && params.refundAmount > orderDetail.info.payAmount){
if (pageData.tabsIndex == 2 && params.refundAmount > orderDetail.info.payAmount) {
return uni.$utils.showToast('退款金额不能大于付款金额!')
}
if( uni.getStorageSync("shopInfo").isReturnPwd == 1){
if (uni.getStorageSync("shopInfo").isReturnPwd == 1) {
refundPopup.value.open(params.refundAmount, refundPost);
return;
}
refundPost()
}
async function refundPost (payPassword) {
if( payPassword ){
params.pwd = payPassword
}
await refundOrder(params)
uni.$utils.showToast('退款请求提交成功')
setTimeout(()=>{
uni.navigateBack({delta:1})
},500)
import {
getProductList,
getCategoryList
} from '@/http/api/product.js'
const confirmModal = reactive({
show: false,
selRefundStock: false,
payPassword: '',
refundStocks: [{
name: '已上菜(仅退菜不退库存)',
key: false
}, {
name: '未上菜(退菜后退库存)',
key: true,
}]
})
function confirmModalClose() {
confirmModal.show = false
confirmModal.selRefundStock = false
confirmModal.payPassword = ''
}
function confirmModalConfirm() {
refundSubmit(confirmModal.payPassword)
confirmModalClose()
}
async function refundSubmit(payPassword) {
if (payPassword) {
params.pwd = payPassword
}
params.refundStock = confirmModal.selRefundStock
await refundOrder(params)
uni.$utils.showToast('退款请求提交成功')
setTimeout(() => {
uni.navigateBack({
delta: 1
})
}, 500)
}
async function refundPost(payPassword) {
confirmModal.payPassword = confirmModal.payPassword
const shopInfo = uni.getStorageSync('shopInfo')
if (pageData.tabsIndex != 2) {
if (shopInfo.refundMode == 1) {
const res = await getCategoryList()
for (let goods of res) {
if (goods.refundMode == 3) {
confirmModal.show = true
return
}
}
}
if (shopInfo.refundMode == 2) {
const res = await getProductList()
for (let goods of res) {
console.log(goods);
if (goods.refundMode == 3) {
confirmModal.show = true
return
}
}
}
}
refundSubmit(payPassword)
}
</script>
<style lang="scss" scoped>