This commit is contained in:
gyq 2025-11-19 10:23:24 +08:00
commit b39b458fe7
47 changed files with 13163 additions and 4599 deletions

View File

@ -160,6 +160,8 @@ App.vue本身不是页面这里不能编写视图元素也就是没有<tem
</script>
<style lang="scss">
@import "uview-plus/index.scss";
/** 每个页面公共css */
@import '@/commons/style/global.scss';
@import '@/commons/style/common.scss';
@ -167,5 +169,4 @@ App.vue本身不是页面这里不能编写视图元素也就是没有<tem
/** uni 组件样式覆盖 */
@import '@/commons/style/uni-overwrite.scss';
@import "uview-plus/index.scss";
</style>

View File

@ -1,14 +1,5 @@
import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'
// 密钥对生成 http://web.chacuo.net/netrsakeypair
const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD\n' +
'2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ=='
// 加密
export function encrypt(txt) {
const encryptor = new JSEncrypt()
encryptor.setPublicKey(publicKey) // 设置公钥
return encryptor.encrypt(txt) // 对需要加密的数据进行加密
return txt
}

View File

@ -0,0 +1,17 @@
import http from "@/http/http.js";
const request = http.request;
const urlType = "market";
/**
* 新客立减
* @returns
*/
export function getDiscountByUserId(params) {
return request({
url: marketUrl + `/admin/consumeDiscount/getDiscountByUserId`,
method: "get",
params: {
...params,
},
});
}

View File

@ -38,3 +38,18 @@ export function del(id) {
})
}
/**
* 满减活动
* @returns
*/
export function discountActivity(params) {
return request({
url: urlType+`/admin/discountActivity`,
method: 'get',
params: {
...params
}
})
}

View File

@ -0,0 +1,17 @@
import http from "@/http/http.js";
const request = http.request;
const urlType = "market";
/**
* 限时折扣
* @returns
*/
export function limitTimeDiscount(params) {
return request({
url: urlType + `/admin/limitTimeDiscount`,
method: "get",
params: {
...params,
},
});
}

View File

@ -8,7 +8,7 @@ const request = http.request
export function getOrderPayUrl(data, urlType = 'order') {
return request({
url: `${urlType}/pay/shopPayApi/orderPayUrl`,
method: "GET",
method: "POST",
data: {
...data
}

View File

@ -21,7 +21,7 @@ export function getShopTable(data, urlType = 'account') {
*/
export function getShopTableDetail(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopTable/detail`,
url: `/account/admin/shopTable/detail`,
method: "GET",
data: {
...data

View File

@ -15,6 +15,7 @@ import infoBox from "@/commons/utils/infoBox.js"
import go from '@/commons/utils/go.js';
import { reject } from 'lodash';
// 设置node环境
// envConfig.changeEnv(storageManage.env('production'))
envConfig.changeEnv(storageManage.env('development'))
// 测试服

415
http/yskApi/Instead.js Normal file
View File

@ -0,0 +1,415 @@
// 代课下单
import http from '@/http/yskApi/http.js'
import { accountUrl, marketUrl } from './prveUrl.js'
const request = http.request
//就餐形式,默认堂食后付费
const useType = 'dine-in-after'
function getUseType() {
const type = uni.getStorageSync("useType")
return type ? type : useType
}
// import {
// webscoketUtill
// } from '../websock.js'
// let wxObj = null
// wx初始化购物车
// export function getWXCart(params) {
// let wxUrl = 'ws://192.168.1.31:2348/?' + objectToString(params)
// wxObj = new webscoketUtill(wxUrl,3000,9,(e)=>{
// console.log('收到消息');
// console.log(e);
// })
// return uni.getStorageSync('wxList')
// }
// 新增\删除\修改到购物车
// export function addWXCart(params) {
// wxObj.ws.send(params)
// }
function objectToString(obj) {
let result = '';
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
result += `${key}=${obj[key]}&`;
}
}
// 去掉最后一个多余的 &
return result.slice(0, -1);
}
/**
* 获取当前台桌订单信息
* @returns
*/
export function getCart(params) {
return request({
url: `/api/place/cart`,
method: "get",
params: {
shopId: uni.getStorageSync("shopId"),
useType: getUseType(),
...params
}
});
}
/**
* 已上架商品列表
* @returns
*/
export function getGoodsLists(params, showLoading = true) {
return request({
url: `/product/admin/product/list`,
method: "get",
params: {
shopId: uni.getStorageSync("shopId"),
...params
},
showLoading
});
}
/**
* 点单
* @returns
*/
export function addCart(data) {
return request({
url: `/api/place/addCart`,
method: "post",
data: {
shopId: uni.getStorageSync("shopId"),
useType: getUseType(),
...data
}
});
}
/**
* 清空购物车/支付订单
* @returns
*/
export function $clearCart(data) {
return request({
url: `/api/place/clearCart`,
method: "delete",
data: {
shopId: uni.getStorageSync("shopId"),
useType: getUseType(),
...data
}
});
}
/**
* 删除购物车某个商品
* @returns
*/
export function $removeCart(data) {
return request({
url: `/api/place/removeCart`,
method: "delete",
data: {
shopId: uni.getStorageSync("shopId"),
useType: getUseType(),
...data
}
});
}
/**
* 更新规格
* @returns
*/
export function $updateCart(data) {
return request({
url: `/api/place/updateCart`,
method: "put",
data: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
/**
* 批量打包
* @returns
*/
export function $allPack(data) {
return request({
url: `/api/place/pack`,
method: "put",
data: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
/**
* 获取取餐号
* @returns
*/
export function $getMasterId(data) {
return request({
url: `/api/place/masterId`,
method: "get",
params: {
shopId: uni.getStorageSync("shopId"),
useType: getUseType(),
...data
}
});
}
/**
* 支付方式获取
* @returns
*/
export function $getPayType(data) {
return request({
url: `/account/admin/payType`,
method: "get",
params: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
/**
* 创建订单
* @returns
*/
export function $createOrder(data) {
return request({
url: `/api/place/order`,
method: "post",
data: {
shopId: uni.getStorageSync("shopId"),
useType: getUseType(),
...data
}
});
}
/**
* 挂起订单
* @returns
*/
export function $cacheOrder(data) {
return request({
url: `/api/place/pending`,
method: "post",
data: {
shopId: uni.getStorageSync("shopId"),
useType: getUseType(),
...data
}
});
}
/**
* 获取已挂起订单
* @returns
*/
export function $getCacheOrder(data) {
return request({
url: `/api/place/pending/cart`,
method: "get",
params: {
shopId: uni.getStorageSync("shopId"),
useType: getUseType(),
...data
}
});
}
// 会员点单/取消会员点单
export function $setUser(data) {
return request({
url: `/api/place/updateVip`,
method: "put",
data: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
// 删除订单
export function $delOrder(data) {
return request({
url: `/api/place/order`,
method: "delete",
data: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
// 支付订单
export function $payOrder(data) {
return request({
url: '/api/place/pay',
method: "put",
data: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
//退单
export function $returnCart(data) {
return request({
url: '/api/place/returnCart',
method: "put",
data: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
// 选择台桌
export function $choseTable(data) {
return request({
url: '/api/place/choseTable',
method: "put",
data: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
// 用餐人数
export function $choseCount(data) {
return request({
url: '/api/place/choseCount',
method: "put",
data: {
shopId: uni.getStorageSync("shopId"),
useType: getUseType(),
...data
}
});
}
// 批量生成台桌
export function $fastCreateTable(data) {
return request({
url: '/api/tbShopTable/generate',
method: "post",
data: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
//打印当前台桌订单
export function $printOrder(data) {
return request({
url: '/api/place/printOrder',
method: "post",
data: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
//打印当前台桌菜品
export function $printDishes(data) {
return request({
url: '/api/place/printDishes',
method: "post",
data: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
// 就餐模式切换
export function $changeUseType(data) {
return request({
url: '/api/place/choseModel',
method: "put",
data: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
// 退款
export function $returnOrder(data) {
return request({
url: '/api/place/returnOrder',
method: "post",
data: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
//获取用户可用优惠券
export function $findCoupon(data) {
return request({
url: marketUrl+'/admin/coupon/findCoupon',
method: "get",
params: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
//会员积分列表
export function $returnMemberPointsList(data) {
return request({
url: '/api/points/member-points/page',
method: "get",
params: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
// 会员积分账户信息
export function $returnMemberPoints(memberId) {
return request({
url: '/api/points/member-points/' + memberId,
method: "get",
params: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
//002-获取订单可用积分及抵扣金额(支付页面使用)
export function $calcUsablePoints(data) {
return request({
url: '/api/points/member-points/calc-usable-points',
method: "get",
params: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}
// 003-根据积分计算可抵扣金额
export function $calcDeDuctionPoints(data) {
return request({
url: '/api/points/member-points/calc-deduction-amount',
method: "get",
params: {
shopId: uni.getStorageSync("shopId"),
...data
}
});
}

235
http/yskApi/http.js Normal file
View File

@ -0,0 +1,235 @@
/**
* HTTP的封装 基于uni.request
* 包括 通用响应结果的处理 业务的增删改查函数
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2021/12/16 18:35
*/
// 设置env配置文件
import envConfig from '@/env/config.js'
// 导入全局属性
import appConfig from '@/config/appConfig.js'
import storageManage from '@/commons/utils/storageManage.js'
import infoBox from "@/commons/utils/infoBox.js"
import go from '@/commons/utils/go.js';
import { reject } from 'lodash';
// 设置node环境
// envConfig.changeEnv(storageManage.env('production'))
envConfig.changeEnv(storageManage.env('development'))
// 测试服
// #ifdef H5
let baseUrl = '/api/'
// #endif
// #ifndef H5
// let baseUrl = 'https://tapi.cashier.sxczgkj.cn/'
//预发布
// let baseUrl = 'https://pre-cashieradmin.sxczgkj.cn'
//正式
// let baseUrl = 'https://cashier.sxczgkj.com/'
let baseUrl = appConfig.env.JEEPAY_BASE_URL
// #endif
const loadingShowTime = 200
function getHeader(){
const headerObject={}
headerObject["token"] = storageManage.token()
headerObject["shopId"] = uni.getStorageSync("shopInfo").id
headerObject["platformType"] = 'APP'
return headerObject
}
// 通用处理逻辑
function commonsProcess(showLoading, httpReqCallback) {
// 判断是否请求完成(用作 是否loading
// 包括: 'ing', 'ingLoading', 'finish'
let reqState = 'ing'
// 是否已经提示的错误信息
let isShowErrorToast = false
// 请求完成, 需要处理的动作
let reqFinishFunc = () => {
if (reqState == 'ingLoading') { // 关闭loading弹层
infoBox.hideLoading()
}
reqState = 'finish' // 请求完毕
}
// 明确显示loading
if (showLoading) {
// xx ms内响应完成不提示loading
setTimeout(() => {
if (reqState == 'ing') {
reqState = 'ingLoading'
infoBox.showLoading()
}
}, loadingShowTime)
}
return httpReqCallback().then((httpData) => {
reqFinishFunc(); // 请求完毕的动作
// 从http响应数据中解构响应数据 [ 响应码、 bodyData ]
let {
statusCode,
data
} = httpData
// 避免混淆重新命名
let bodyData = data
if (statusCode == 500) {
isShowErrorToast = true
return Promise.reject(bodyData) // 跳转到catch函数
}
if (statusCode == 501) {
// storageManage.token(null, true)
// 提示信息
isShowErrorToast = true
// infoBox.showErrorToast('请登录').then(() => {
// go.to("PAGES_LOGIN", {}, go.GO_TYPE_RELAUNCH)
// })
return Promise.reject(bodyData) // 跳转到catch函数
}
// http响应码不正确
if (statusCode != 200 && statusCode != 204 && statusCode != 201) {
isShowErrorToast = true
bodyData.msg=bodyData.msg=='Bad credentials'?'用户名或密码错误':bodyData.msg
infoBox.showToast(bodyData.msg || '服务器异常')
return Promise.reject(bodyData) // 跳转到catch函数
}
// // 业务响应异常
if (bodyData.hasOwnProperty('code') && bodyData.code != 200) {
isShowErrorToast = true
infoBox.showToast(bodyData.msg)
// if (bodyData.code == 5005) { // 密码已过期, 直接跳转到更改密码页面
// uni.reLaunch({
// url: '/pageUser/setting/updatePwd'
// })
// }
// if(bodyData.code == 500){ // 密码已过期, 直接跳转到更改密码页面
// uni.redirectTo({url: '/pages/login/index'})
// }
return Promise.reject(bodyData) // 跳转到catch函数
}
// 构造请求成功的响应数据
return Promise.resolve(bodyData.data)
}).catch(res => {
console.log(res)
if(res.code==501){
storageManage.token(null, true)
infoBox.showToast('登录过期,请重新登录').then(() => {
uni.redirectTo({url: '/pages/login/index'})
reject()
})
}
// if(res.status==400){
// storageManage.token(null, true)
// infoBox.showErrorToast('').then(() => {
// go.to("PAGES_LOGIN", {}, go.GO_TYPE_RELAUNCH)
// })
// }
if(res.code==500){
infoBox.showToast(res.msg||'服务器异常').then(() => {})
}
// if(res&&res.msg){
// infoBox.showErrorToast(res.msg)
// }
reqFinishFunc(); // 请求完毕的动作
// 如果没有提示错误, 那么此处提示 异常。
if (!isShowErrorToast) {
infoBox.showToast(`请求网络异常`)
}
return Promise.reject(res)
}).finally(() => { // finally 是 then结束后再执行, 此处不适用。 需要在请求完成后立马调用: reqFinishFunc()
});
}
// 默认 显示loading(控制 xxs 内 不提示loading )
function req(uri, data, method = "GET", showLoading = true, extParams = {}) {
// headerObject[appConfig.tokenKey] = storageManage.token()
return commonsProcess(showLoading, () => {
return uni.request(
Object.assign({
url: baseUrl + uri,
data: data,
method: method,
header: getHeader()
}, extParams)
)
})
}
// 默认 显示loading(控制 xxs 内 不提示loading )
function request(args) {
const {
url,
data,
params,
method = "GET",
showLoading = true,
extParams = {}
} = args
let headerObject = {}
// headerObject[appConfig.tokenKey] = storageManage.token()
return commonsProcess(showLoading, () => {
return uni.request(
Object.assign({
url: baseUrl + url,
data: params||data,
method: method,
header: getHeader()
}, extParams)
)
})
}
// 上传
function upload(uri, data, file, showLoading = true, extParams = {}) {
// 放置token
let headerObject = {}
// headerObject[appConfig.tokenKey] = storageManage.token()
return commonsProcess(showLoading, () => {
return uni.uploadFile(
Object.assign({
url: baseUrl + uri,
formData: data,
name: "file",
filePath: file.path||file.url,
header: getHeader()
}, extParams)
).then((httpData) => {
// uni.upload 返回bodyData 的是 string类型。 需要解析。
httpData.data = JSON.parse(httpData.data)
return Promise.resolve(httpData)
}).catch(err=>{
uni.hideLoading()
infoBox.showErrorToast(`上传失败`)
})
})
}
export default {
req: req,
request,
upload: upload
}

View File

@ -0,0 +1,19 @@
import http from '@/http/yskApi/http.js'
const request = http.request
import {marketUrl} from './prveUrl.js'
/**
* 限时折扣
* @returns
*/
export function limitTimeDiscount(params) {
return request({
url: marketUrl+`/admin/limitTimeDiscount`,
method: 'get',
params: {
shopId: uni.getStorageSync('shopInfo').id,
...params
}
})
}

View File

@ -0,0 +1,20 @@
import http from '@/http/yskApi/http.js'
const request = http.request
import {marketUrl} from '../prveUrl.js'
/**
* 新客立减
* @returns
*/
export function getDiscountByUserId(params) {
return request({
url: marketUrl+`/admin/consumeDiscount/getDiscountByUserId`,
method: 'get',
params: {
shopId: uni.getStorageSync('shopInfo').id,
...params
}
})
}

View File

@ -0,0 +1,21 @@
import http from '@/http/yskApi/http.js'
const request = http.request
import {marketUrl} from '../prveUrl.js'
/**
* 满减活动
* @returns
*/
export function discountActivity(params) {
console.log(uni.getStorageSync('shopInfo').id)
return request({
url: marketUrl+`/admin/discountActivity`,
method: 'get',
params: {
shopId: uni.getStorageSync('shopInfo').id,
...params
}
})
}

118
http/yskApi/order.js Normal file
View File

@ -0,0 +1,118 @@
import http from '@/http/yskApi/http.js'
const request = http.request
import {orderUrl} from './prveUrl.js'
/**
* 查询订单
* @param {*} data
* @returns
*/
export function tbOrderInfoData(data) {
return request({
url: "/order/admin/order",
method: "get",
data: {
shopId: uni.getStorageSync('shopId'),
...data
}
});
}
/**
* 导出数据
* @param {*} data
* @returns
*/
export function tbOrderInfoDownload(data) {
return request({
url: "/api/tbOrderInfo/download",
method: "post",
data: {
shopId: uni.getStorageSync('shopId'),
...data
},
responseType: "blob"
});
}
export function createOrder(data, urlType = 'order') {
return request({
url: `/${urlType}/admin/order/createOrder`,
method: "POST",
data: {
...data
}
})
}
/**
* 通过Id查询订单
* @param {*} id
* @returns
*/
export function tbOrderInfoDetail(id) {
return request({
url: orderUrl+ `/admin/order/historyOrder?orderId=${id}`,
method: "get"
});
}
/**
* 通过Id查询订单
* @param {*} createdAt
* @returns
*/
export function payCount(createdAt) {
console.log(createdAt);
return request({
url: `/api/tbOrderInfo/payCount`,
method: "post",
data: {
shopId: uni.getStorageSync('shopId'),
createdAt: createdAt
}
});
}
/**
* 订单列表
* @param {*} createdAt
* @returns
*/
export function tbGroupOrderInfo(params) {
return request({
url: `/api/tbGroupOrderInfo`,
method: "post",
data: {
shopId: uni.getStorageSync('shopId'),
...params
}
});
}
/**
* 退单
* @param {*} data
* @returns
*/
export function returnGpOrder(data) {
return request({
url: `/api/tbGroupOrderInfo/returnGpOrder`,
method: "post",
data
});
}
/**
* 店铺订单支付获取链接
*/
export function $getOrderPayUrl(data) {
return request({
url: `/api/shopPayApi/getOrderPayUrl`,
method: "get",
data: {
shopId: uni.getStorageSync('shopId'),
...data
}
});
}

3
http/yskApi/prveUrl.js Normal file
View File

@ -0,0 +1,3 @@
export const marketUrl = '/market'
export const accountUrl = '/account'
export const orderUrl = '/order'

59
http/yskApi/shop-user.js Normal file
View File

@ -0,0 +1,59 @@
// 用户管理
import http from './http.js'
import {accountUrl} from './prveUrl.js'
const request=http.request
// 获取店铺会员二维码
export function getwxacode(data) {
return request({
url: `/shop/storage/getwxacode`,
method: "post",
data
});
}
/**
* 商家用户列表
* @returns
*/
export function queryAllShopUser(params) {
return request({
url: accountUrl+`/admin/shopUser`,
method: "get",
params: {
shopId: uni.getStorageSync('shopId'),
...params
}
});
}
/**
* 查询商家用户概述信息
* @returns
*/
export function queryAllShopInfo(params) {
return request({
url: `/api/tbShopUser/summary`,
method: "get",
params: {
shopId: uni.getStorageSync('shopId'),
isVip:1,
...params
}
});
}
/**
* 获取店铺用户详情
* @returns
*/
export function shopUserDetail(params) {
return request({
url: accountUrl+`/admin/shopUser/detail`,
method: "get",
params: {
shopId: uni.getStorageSync('shopId'),
...params
}
});
}

0
lib/carts.ts Normal file
View File

852
lib/coupon.ts Normal file
View File

@ -0,0 +1,852 @@
import { BigNumber } from "bignumber.js";
import _ from "lodash";
import {
ShopInfo,
couponCalcParams,
BaseCartItem,
TimeLimitDiscountConfig,
CanDikouGoodsArrArgs,
Coupon,
ShopUserInfo,
GoodsType,
BackendCoupon,
ExchangeCalculationResult,
PointDeductionRule,
OrderCostSummary,
} from "./types";
import { getCompatibleFieldValue } from "./utils";
/**
*
* @param goods
* @param user
* @param {Object} shopInfo
*/
export function returnGoodsPrice(
goods: BaseCartItem,
user: ShopUserInfo,
shopInfo: ShopInfo,
limitTimeDiscount: TimeLimitDiscountConfig | null | undefined
) {
if (!goods) {
return 0;
}
//是否可以使用会员价
const canUseVipPrice =
user &&
user.isVip &&
user.isMemberPrice &&
goods.memberPrice * 1 > 0 &&
shopInfo &&
shopInfo.isMemberPrice;
// 商家改价
if (goods.discount_sale_amount && goods.discount_sale_amount * 1 > 0) {
return goods.salePrice;
}
// 限时折扣
if (limitTimeDiscount && limitTimeDiscount.id) {
//优先使用
// 兼容 isTimeDiscount/is_time_discount这里顺便处理该字段的命名兼容
const isTimeDiscount = getCompatibleFieldValue(
goods,
"isTimeDiscount",
"is_time_discount"
);
if (isTimeDiscount) {
return new BigNumber(goods.salePrice)
.times(limitTimeDiscount.discountRate / 100)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
}
const canUseFoods = limitTimeDiscount.foods.split(",");
const canUseLimit =
limitTimeDiscount.foodType == 1 ||
canUseFoods.includes(`${goods.productId}`);
if (canUseLimit && limitTimeDiscount.discountPriority == "limit-time") {
return new BigNumber(goods.salePrice)
.times(limitTimeDiscount.discountRate / 100)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
}
if (canUseLimit && limitTimeDiscount.discountPriority == "vip-price") {
if (canUseVipPrice) {
return goods.memberPrice;
} else {
return new BigNumber(goods.salePrice)
.times(limitTimeDiscount.discountRate / 100)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
}
}
}
if (canUseVipPrice) {
return goods.memberPrice;
}
return goods.salePrice;
}
/**
*
* @param arr
*/
export function returnGoodsGroupMap(arr: BaseCartItem[]) {
let map: { [key: string]: BaseCartItem[] } = {};
arr.forEach((v) => {
const key = v.productId + "_" + v.skuId;
if (!map[key]) {
map[key] = [];
}
map[key].push(v);
});
return map;
}
interface CouponTypes {
1: "满减券";
2: "商品券";
3: "折扣券";
4: "第二件半价券";
5: "消费送券";
6: "买一送一券";
7: "固定价格券";
8: "免配送费券";
}
/**
* 1-2-3-4-5-6-7-8-
* @param coupon
*/
export function returnCoupType(coupon: Coupon) {
const couponTypes: CouponTypes = {
1: "满减券",
2: "商品券",
3: "折扣券",
4: "第二件半价券",
5: "消费送券",
6: "买一送一券",
7: "固定价格券",
8: "免配送费券",
};
return couponTypes[coupon.type as keyof CouponTypes] || "未知类型";
}
/**
*
* @param canDikouGoodsArr
* @param selCoupon
* @param user
*/
export function returnCanDikouGoodsArr(args: CanDikouGoodsArrArgs) {
const { canDikouGoodsArr, selCoupon, user, shopInfo, limitTimeDiscount } =
args;
const types = [2, 4, 6];
// 收集已抵扣商品并关联对应的优惠券类型
const goodsCouponGoods = selCoupon
.filter((v) => types.includes(v.type))
.reduce((prev: BaseCartItem[], cur) => {
// 给每个抵扣商品添加所属优惠券类型
if (cur && cur.discount) {
const goodsWithType = cur.discount.hasDiscountGoodsArr.map((goods) => ({
...goods,
couponType: cur.type, // 记录该商品是被哪种类型的优惠券抵扣的
}));
prev.push(...goodsWithType);
}
return prev;
}, []);
const arr = _.cloneDeep(canDikouGoodsArr)
.map((v) => {
const findCart = goodsCouponGoods.find((carts) => carts.id == v.id);
if (findCart) {
// 根据优惠券类型判断扣减数量
if ([4, 6].includes(findCart.couponType ?? 0)) {
// 类型4第二件半价或6买一送一数量减2
if (v.num) {
v.num -= 2;
}
} else {
// 其他类型如类型2商品券按原逻辑扣减对应数量
if (v.num) {
v.num -= findCart.num ?? 0;
}
}
}
return v;
})
.filter((v) => {
const canUseNum = (v.num ?? 0) - (v.returnNum || 0);
// 兼容 is_temporary/isTemporary 和 is_gift/isGift
const isTemporary = getCompatibleFieldValue(
v,
"isTemporary",
"is_temporary"
);
const isGift = getCompatibleFieldValue(v, "isGift", "is_gift");
if (canUseNum <= 0 || isTemporary || isGift) {
return false;
}
return true;
}); // 过滤掉数量<=0的商品,赠菜,临时菜
return arr;
}
/**
* /
* @param {*} goods
*/
function returnGoodsIsUseVipPrice(
shopInfo: ShopInfo,
user: ShopUserInfo,
goods: BaseCartItem
) {
// 兼容 isTimeDiscount/is_time_discount
const isTimeDiscount = getCompatibleFieldValue(
goods,
"isTimeDiscount",
"is_time_discount"
);
if (isTimeDiscount) {
return false;
}
if (shopInfo.isMemberPrice != 1 || user.isVip != 1) {
return false;
}
if (shopInfo.isMemberPrice == 1 && user.isVip == 1) {
if (goods.memberPrice <= 0) {
return false;
} else {
return true;
}
}
return false;
}
/**
*
*/
function returnCanCalcGoodsList(
canCalcGoodsArr: BaseCartItem[],
coupon: Coupon,
shopInfo: ShopInfo,
user: ShopUserInfo
) {
return canCalcGoodsArr.filter((goods) => {
// 兼容 isTimeDiscount/is_time_discount
const isTimeDiscount = getCompatibleFieldValue(
goods,
"isTimeDiscount",
"is_time_discount"
);
if (!coupon.discountShare && isTimeDiscount) {
return false;
}
if (
!coupon.vipPriceShare &&
returnGoodsIsUseVipPrice(shopInfo, user, goods)
) {
return false;
}
return true;
});
}
/**
* 使
*
* @param {Object} args -
* @param {Array} args.canDikouGoodsArr -
* @param {Object} args.coupon -
* @param {boolean} args.coupon.use -
* @param {Array} args.coupon.useFoods - ID列表
* @param {number} args.coupon.fullAmount - 使
* @param {number} args.coupon.type -
* @param {number} args.goodsOrderPrice -
* @param {Object} args.user -
* @param {Object} args.selCoupon -
* @param {Object} args.shopInfo
* @param {boolean} args.limitTimeDiscount -
* @returns {Object} - { canUse: boolean, reason: string }
*/
export function returnCouponCanUse(args: couponCalcParams) {
let {
canDikouGoodsArr,
coupon,
goodsOrderPrice,
user,
selCoupon,
shopInfo,
isMemberPrice,
limitTimeDiscount,
} = args;
// 优惠券未启用
if (!coupon.use) {
return {
canUse: false,
reason: coupon.noUseRestrictions || "不在可用时间段内",
};
}
if (
limitTimeDiscount &&
limitTimeDiscount.id &&
limitTimeDiscount.foodType == 1 &&
!coupon.discountShare
) {
return {
canUse: false,
reason: coupon.noUseRestrictions || "不可与限时折扣同享",
};
}
// 计算门槛金额
let fullAmount = goodsOrderPrice;
canDikouGoodsArr = returnCanDikouGoodsArr(args);
//优惠券指定门槛商品列表
let canCalcGoodsArr = [...canDikouGoodsArr];
//部分商品参与门槛计算
if (coupon.thresholdFoods.length) {
canCalcGoodsArr = canDikouGoodsArr.filter((v) => {
return coupon.thresholdFoods.find((food) => food.id == v.productId);
});
}
canCalcGoodsArr = returnCanCalcGoodsList(
canCalcGoodsArr,
coupon,
shopInfo,
user
);
fullAmount = canCalcGoodsArr.reduce((pre, cur) => {
return (
pre +
returnGoodsPrice(cur, user, shopInfo, limitTimeDiscount) * (cur.num || 0)
);
}, 0);
// 是否全部商品可用
const isDikouAll = coupon.useFoods.length === 0;
// 订单可用商品列表
let canUseGoodsArr: BaseCartItem[] = [];
if (!isDikouAll) {
canUseGoodsArr = canDikouGoodsArr.filter((v) => {
return coupon.useFoods.find((food) => food.id == v.productId);
});
}
// if (user.isVip && !coupon.vipPriceShare) {
// return {
// canUse: false,
// reason: "非会员可用",
// };
// }
if (selCoupon.length > 0 && !selCoupon[0].otherCouponShare) {
return {
canUse: false,
reason: "当前选中的券不可与其他券同享",
};
}
if (selCoupon.length > 0 && !coupon.otherCouponShare) {
return {
canUse: false,
reason: "当前选中的券不可与其他券同享",
};
}
// 满减券和折扣券计算门槛金额是否满足
if ([1, 3].includes(coupon.type)) {
if (canCalcGoodsArr.length <= 0) {
return {
canUse: false,
reason: "没有可参与计算门槛的商品",
};
}
// 不满足门槛金额
if (fullAmount < (coupon.fullAmount || 0)) {
return {
canUse: false,
reason: `${coupon.fullAmount}元可用,当前可参与金额${fullAmount}`,
};
}
}
// 商品兑换券,第二件半价和买一送一判断是否有可用商品
if ([2, 4, 5].includes(coupon.type)) {
// 没有符合条件的商品
if (isDikouAll && canDikouGoodsArr.length === 0) {
return {
canUse: false,
reason: "没有符合条件的商品",
};
}
if (!isDikouAll && canUseGoodsArr.length === 0) {
return {
canUse: false,
reason: "没有符合条件的商品",
};
}
if (coupon.type == 2) {
if (canCalcGoodsArr.length <= 0) {
return {
canUse: false,
reason: "没有符合计算门槛条件的商品",
};
}
if (fullAmount < (coupon.fullAmount || 0)) {
return {
canUse: false,
reason: `${coupon.fullAmount}元可用,当前可参与金额${fullAmount}`,
};
}
}
}
//商品兑换券是否达到门槛金额
if (coupon.type == 2 && goodsOrderPrice < (coupon.fullAmount || 0)) {
return {
canUse: false,
reason: `${coupon.fullAmount}元可用,当前可参与金额${fullAmount}`,
};
}
// 买一送一券特殊验证
if (coupon.type === 6) {
let canUse = false;
if (isDikouAll) {
canUse = canDikouGoodsArr.some((v) => (v.num || 0) >= 2);
} else if (canUseGoodsArr.length > 0) {
canUse = canUseGoodsArr.some((v) => (v.num || 0) >= 2);
}
if (!canUse) {
return {
canUse: false,
reason: "需要购买至少2件相同的商品才能使用",
};
}
}
// 第二件半价券特殊验证
if (coupon.type === 4) {
let canUse = false;
if (isDikouAll) {
canUse = canDikouGoodsArr.some((v) => (v.num || 0) >= 2);
} else if (canUseGoodsArr.length > 0) {
canUse = canUseGoodsArr.some((v) => (v.num || 0) >= 2);
}
if (!canUse) {
return {
canUse: false,
reason: "需要购买至少2件相同的商品才能使用",
};
}
}
// 所有条件都满足
return {
canUse: true,
reason: "",
};
}
/**
*
* @param discountGoodsArr
* @param discountNum
* @param user
* @param {Object} shopInfo
*/
export function calcDiscountGoodsArrPrice(
discountGoodsArr: BaseCartItem[],
discountNum: number,
user: ShopUserInfo,
shopInfo: ShopInfo,
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
let hasCountNum = 0;
let discountPrice = 0;
let hasDiscountGoodsArr:BaseCartItem[] = [];
for (let i = 0; i < discountGoodsArr.length; i++) {
if (hasCountNum >= discountNum) {
break;
}
const goods = discountGoodsArr[i];
const shengyuNum = discountNum - hasCountNum;
const num = Math.min(goods.num || 0, shengyuNum);
const realPrice = returnGoodsPrice(
goods,
user,
shopInfo,
limitTimeDiscount
);
discountPrice += realPrice * num;
hasCountNum += num;
if(goods){
hasDiscountGoodsArr.push({
...goods,
num,
});
}
}
return {
discountPrice,
hasDiscountGoodsArr,
};
}
/**
*
* @param arr
* @param coupon
* @param user
* @param goodsOrderPrice
* @param selCoupon
* @param shopInfo
* @param limitTimeDiscount
*/
export function returnCouponDiscount(
arr: BaseCartItem[],
coupon: Coupon,
user: ShopUserInfo,
goodsOrderPrice: number,
selCoupon: Coupon[],
shopInfo: ShopInfo,
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
arr = returnCanDikouGoods(arr, user, shopInfo, limitTimeDiscount);
const canDikouGoodsArr = returnCanDikouGoodsArr({
canDikouGoodsArr: arr,
selCoupon,
user,
shopInfo,
limitTimeDiscount,
});
if (coupon.type == 2) {
return returnCouponProductDiscount(
canDikouGoodsArr,
coupon,
user,
shopInfo,
limitTimeDiscount
);
}
if (coupon.type == 6) {
const result = returnCouponBuyOneGiveOneDiscount(
canDikouGoodsArr,
coupon,
user,
shopInfo,
limitTimeDiscount
);
return result;
}
if (coupon.type == 4) {
return returnSecoendDiscount(
canDikouGoodsArr,
coupon,
user,
shopInfo,
limitTimeDiscount
);
}
if (coupon.type == 3) {
return returnCouponZhekouDiscount(
canDikouGoodsArr,
coupon,
user,
goodsOrderPrice,
selCoupon,
limitTimeDiscount
);
}
}
/**
*
* @param canDikouGoodsArr
* @param coupon
* @param user
* @param goodsOrderPrice
* @param selCoupon
* @param limitTimeDiscount
*/
export function returnCouponZhekouDiscount(
canDikouGoodsArr: BaseCartItem[],
coupon: Coupon,
user: ShopUserInfo,
goodsOrderPrice: number,
selCoupon: Coupon[],
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
let { discountRate, maxDiscountAmount } = coupon;
maxDiscountAmount = maxDiscountAmount || 0;
// 计算商品优惠券折扣总和使用BigNumber避免精度问题
const goodsCouponDiscount = selCoupon
.filter((v) => v.type == 2)
.reduce((prve, cur) => {
return new BigNumber(prve).plus(
new BigNumber(cur?.discount?.discountPrice || 0)
);
}, new BigNumber(0));
// 将商品订单价格转换为BigNumber并减去优惠券折扣
const adjustedGoodsOrderPrice = new BigNumber(goodsOrderPrice).minus(
goodsCouponDiscount
);
// 计算优惠比例:(100 - 折扣率) / 100
const discountAmountRatio = new BigNumber(100)
.minus(discountRate || 0)
.dividedBy(100);
// 计算折扣金额:调整后的商品订单金额 × 优惠比例
let discountPrice = adjustedGoodsOrderPrice
.times(discountAmountRatio)
.decimalPlaces(2, BigNumber.ROUND_FLOOR)
.toNumber();
// 应用最大折扣金额限制
if (maxDiscountAmount !== 0) {
discountPrice =
discountPrice >= maxDiscountAmount ? maxDiscountAmount : discountPrice;
}
return {
discountPrice, // 折扣抵扣金额(即优惠的金额)
hasDiscountGoodsArr: [],
};
}
/**
*
* @param canDikouGoodsArr
* @param coupon
* @param user
* @param shopInfo
*/
export function returnCouponProductDiscount(
canDikouGoodsArr: BaseCartItem[],
coupon: Coupon,
user: ShopUserInfo,
shopInfo: ShopInfo,
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
let { useFoods, discountNum, useRule } = coupon;
discountNum = discountNum || 0;
//抵扣商品数组
let discountGoodsArr:BaseCartItem[] = [];
//抵扣全部商品
if (useFoods.length === 0) {
if (useRule == "price_asc") {
discountGoodsArr = canDikouGoodsArr.slice(discountNum * -1).reverse();
} else {
discountGoodsArr = canDikouGoodsArr.slice(0, discountNum);
}
} else {
//抵扣选中商品
const discountSelGoodsArr = canDikouGoodsArr.filter((v) =>
useFoods.find((food) => food.id == v.productId)
);
if (useRule == "price_asc") {
discountGoodsArr = discountSelGoodsArr.slice(discountNum * -1).reverse();
} else {
discountGoodsArr = discountSelGoodsArr.slice(0, discountNum);
}
}
const result = calcDiscountGoodsArrPrice(
discountGoodsArr,
discountNum,
user,
shopInfo,
limitTimeDiscount
);
return result;
}
/**
*
* @param canDikouGoodsArr
* @param coupon
* @param user
* @param shopInfo
*/
function returnCouponBuyOneGiveOneDiscount(
canDikouGoodsArr: BaseCartItem[],
coupon: Coupon,
user: ShopUserInfo,
shopInfo: ShopInfo,
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
const { useFoods, useRule } = coupon;
//抵扣商品
let discountGoods:BaseCartItem | undefined = undefined;
//符合买一送一条件的商品(数量>=2 + 非临时/非赠品)
const canUseGoods = canDikouGoodsArr.filter((v) => {
const isTemporary = getCompatibleFieldValue(
v,
"isTemporary",
"is_temporary"
);
const isGift = getCompatibleFieldValue(v, "isGift", "is_gift");
return (v.num || 0) >= 2 && !isTemporary && !isGift;
});
//抵扣全部商品
if (useFoods.length === 0) {
if (useRule == "price_asc") {
discountGoods = canUseGoods[canUseGoods.length - 1];
} else {
discountGoods = canUseGoods[0];
}
} else {
//符合抵扣条件的商品
const canUseGoods1 = canUseGoods.filter((v) =>
useFoods.find((food) => food.id == v.productId)
);
if (useRule == "price_asc") {
discountGoods = canUseGoods1[canUseGoods1.length - 1];
} else {
discountGoods = canUseGoods1[0];
}
}
let discountPrice = 0;
let hasDiscountGoodsArr: BaseCartItem[] = [];
if (discountGoods) {
discountPrice = returnGoodsPrice(
discountGoods,
user,
shopInfo,
limitTimeDiscount
);
hasDiscountGoodsArr = [discountGoods];
}
return {
discountPrice: discountPrice <= 0 ? 0 : discountPrice,
hasDiscountGoodsArr,
};
}
/**
*
* @param canDikouGoodsArr
* @param coupon
* @param user
* @param shopInfo
*/
function returnSecoendDiscount(
canDikouGoodsArr: BaseCartItem[],
coupon: Coupon,
user: ShopUserInfo,
shopInfo: ShopInfo,
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
const { useFoods, useRule } = coupon;
//抵扣商品
let discountGoods:BaseCartItem | undefined = undefined;
//符合条件的商品(数量>=2 + 非临时/非赠品)
const canUseGoods = canDikouGoodsArr.filter((v) => {
const isTemporary = getCompatibleFieldValue(
v,
"isTemporary",
"is_temporary"
);
const isGift = getCompatibleFieldValue(v, "isGift", "is_gift");
return (v.num || 0) >= 2 && !isTemporary && !isGift;
});
//抵扣全部商品
if (useFoods.length === 0) {
if (useRule == "price_asc") {
discountGoods = canUseGoods[canUseGoods.length - 1];
} else {
discountGoods = canUseGoods[0];
}
} else {
//符合抵扣条件的商品
const canUseGoods1 = canUseGoods.filter((v) =>
useFoods.find((food) => food.id == v.productId)
);
if (useRule == "price_asc") {
discountGoods = canUseGoods1[canUseGoods1.length - 1];
} else {
discountGoods = canUseGoods1[0];
}
}
let discountPrice = 0;
let hasDiscountGoodsArr: BaseCartItem[] = [];
if (discountGoods) {
discountPrice = returnGoodsPrice(
discountGoods,
user,
shopInfo,
limitTimeDiscount
);
hasDiscountGoodsArr = [discountGoods];
}
//返回半价价格
return {
discountPrice:
discountPrice <= 0
? 0
: new BigNumber(discountPrice).dividedBy(2).toNumber(),
hasDiscountGoodsArr,
};
}
/**
* ,,
* @param arr
* @param user
* @param shopInfo
* @param limitTimeDiscount
*/
export function returnCanDikouGoods(
arr: BaseCartItem[],
user: ShopUserInfo,
shopInfo: ShopInfo,
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
const result = arr
.filter((v) => {
// 兼容 is_temporary/isTemporary 和 is_gift/isGift
const isTemporary = getCompatibleFieldValue(
v,
"isTemporary",
"is_temporary"
);
const isGift = getCompatibleFieldValue(v, "isGift", "is_gift");
return !isTemporary && !isGift;
})
.filter((v) => {
return (v.num || 0) > 0;
})
.sort((a, b) => {
return (
returnGoodsPrice(b, user, shopInfo, limitTimeDiscount) -
returnGoodsPrice(a, user, shopInfo, limitTimeDiscount)
);
});
return result;
}
export const utils = {
returnGoodsPrice,
returnGoodsGroupMap,
returnCoupType,
returnCanDikouGoods,
returnCanDikouGoodsArr,
returnCouponCanUse,
calcDiscountGoodsArrPrice,
returnCouponDiscount,
returnCouponProductDiscount,
returnCouponZhekouDiscount,
};
export default utils;

1275
lib/goods-1.0.47-back.ts Normal file

File diff suppressed because it is too large Load Diff

1382
lib/goods.ts Normal file

File diff suppressed because it is too large Load Diff

11
lib/index.ts Normal file
View File

@ -0,0 +1,11 @@
export * from "./types";
import OrderPriceCalculator from "./goods";
import couponUtils from "./coupon";
import limitUtils from "./limit";
export { OrderPriceCalculator, couponUtils, limitUtils };
export default {
OrderPriceCalculator,
couponUtils,
limitUtils,
};

216
lib/limit.ts Normal file
View File

@ -0,0 +1,216 @@
import BigNumber from "bignumber.js";
import _ from "lodash";
import {
BaseCartItem,
ShopUserInfo,
ShopInfo,
TimeLimitDiscountConfig,
CanReturnMemberPriceArgs,
returnPriceArgs,
} from "./types";
/**
* 使
* @param goods
* @param limitTimeDiscountRes
* @param shopInfo
* @param shopUserInfo
* @param idKey ID键名"id"
* @returns
*/
export function canUseLimitTimeDiscount(
goods: BaseCartItem,
limitTimeDiscountRes: TimeLimitDiscountConfig | null | undefined,
shopInfo: ShopInfo,
shopUserInfo: ShopUserInfo,
idKey = "id" as keyof BaseCartItem
) {
shopInfo = shopInfo || {};
shopUserInfo = shopUserInfo || {};
if(shopInfo.isMemberPrice){
shopUserInfo.isMemberPrice=1
}
if (!limitTimeDiscountRes || !limitTimeDiscountRes.id) {
return false;
}
const canUseFoods = (limitTimeDiscountRes.foods || "").split(",");
const goodsCanUse =
limitTimeDiscountRes.foodType == 1 ||
canUseFoods.includes(`${goods[idKey]}`);
if (!goodsCanUse) {
return false;
}
if (limitTimeDiscountRes.discountPriority == "limit-time") {
return true;
}
if (limitTimeDiscountRes.discountPriority == "vip-price") {
if (
shopUserInfo.isVip == 1 &&
shopUserInfo.isMemberPrice == 1 &&
goods.memberPrice * 1 > 0
) {
return false;
}
return true;
}
return false;
}
/**
*
* @params {*} args
* @params {*} args.goods
* @params {*} args.shopInfo
* @params {*} args.limitTimeDiscountRes
* @params {*} args.shopUserInfo
* @returns
*/
export function returnPrice(args: returnPriceArgs) {
let {
goods,
shopInfo,
limitTimeDiscountRes,
shopUserInfo,
idKey = "product_id",
} = args;
limitTimeDiscountRes = limitTimeDiscountRes || {
foods: "",
foodType: 2,
discountPriority: "",
discountRate: 0,
id: 0,
shopId: 0,
useType: "",
};
const canUseFoods = (limitTimeDiscountRes.foods || "").split(",");
const includesGoods =
limitTimeDiscountRes.foodType == 1 ||
canUseFoods.includes("" + goods[idKey]);
shopInfo = shopInfo || {};
shopUserInfo = shopUserInfo || {};
if (
shopUserInfo.isMemberPrice == 1 &&
shopUserInfo.isVip == 1 &&
shopInfo.isMemberPrice == 1
) {
const memberPrice = goods.memberPrice || goods.salePrice;
//是会员而且启用会员价
if (limitTimeDiscountRes) {
//使用限时折扣
//限时折扣优先
if (limitTimeDiscountRes.discountPriority == "limit-time") {
if (includesGoods) {
return returnLimitPrice({
price: goods.salePrice,
limitTimeDiscountRes,
});
} else {
return memberPrice;
}
}
if (
limitTimeDiscountRes.discountPriority == "vip-price" &&
includesGoods
) {
if (goods.memberPrice * 1 > 0) {
//会员优先
return memberPrice;
} else {
const price = returnLimitPrice({
price: goods.salePrice,
limitTimeDiscountRes,
goods: goods,
});
return price;
}
} else {
return memberPrice;
}
} else {
//是会员没有限时折扣
return memberPrice;
}
} else {
//不是会员或者没有启用会员价
if (limitTimeDiscountRes && limitTimeDiscountRes.id && includesGoods) {
const price = returnLimitPrice({
price: goods.salePrice,
limitTimeDiscountRes,
goods: goods,
});
return price;
} else {
return goods.salePrice;
}
}
}
interface returnLimitPriceArgs {
limitTimeDiscountRes: TimeLimitDiscountConfig | null | undefined;
price: number;
goods?: BaseCartItem;
}
/**
*
* @params {*} args
* @params {*} args.limitTimeDiscountRes
* @params {*} args.price
* @param {*} args.goods
* @returns
*/
export function returnLimitPrice(args: returnLimitPriceArgs) {
const { limitTimeDiscountRes, price, goods } = args;
const discountRate = new BigNumber(
limitTimeDiscountRes ? limitTimeDiscountRes.discountRate : 100
).dividedBy(100);
const result = BigNumber(price)
.times(discountRate)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
return result;
}
/**
*
* @param {*} args
* @param {*} args.shopInfo
* @param {*} args.shopUserInfo
* @returns
*/
export function canReturnMemberPrice(args: CanReturnMemberPriceArgs) {
const { shopInfo, shopUserInfo } = args;
if (shopUserInfo.isMemberPrice == 1 && shopUserInfo.isVip == 1) {
return true;
} else {
return false;
}
}
/**
*
* @param {*} goods
* @returns
*/
export function returnMemberPrice(goods: BaseCartItem) {
return goods.memberPrice || goods.salePrice;
}
export const utils = {
returnPrice,
canUseLimitTimeDiscount,
returnLimitPrice,
canReturnMemberPrice,
returnMemberPrice,
};
export default utils;

0
lib/socket.ts Normal file
View File

430
lib/types.ts Normal file
View File

@ -0,0 +1,430 @@
/** 商品类型枚举 */
export enum GoodsType {
NORMAL = "normal", // 普通商品
WEIGHT = "weight", // 称重商品
GIFT = "gift", // 赠菜(继承普通商品逻辑,标记用)
EMPTY = "", // 空字符串类型(后端未返回时默认归类为普通商品)
PACKAGE = "package", // 打包商品(如套餐/预打包商品,按普通商品逻辑处理,可扩展特殊规则)
}
/** 优惠券计算结果类型(新增细分字段) */
export interface CouponResult {
deductionAmount: number; // 抵扣金额
excludedProductIds: string[]; // 不适用商品ID列表注意是商品ID非购物车ID
usedCoupon: Coupon | undefined; // 实际使用的优惠券
productCouponDeduction: number; // 新增:商品优惠券抵扣(兑换券等)
fullCouponDeduction: number; // 新增:满减优惠券抵扣
}
/** 兑换券计算结果类型(新增细分字段) */
export interface ExchangeCalculationResult {
deductionAmount: number;
excludedProductIds: string[]; // 不适用商品ID列表商品ID
productCouponDeduction: number; // 新增:兑换券属于商品券,同步记录
}
export interface CouponTypes {
1: "满减券";
2: "商品券";
3: "折扣券";
4: "第二件半价券";
5: "消费送券";
6: "买一送一券";
7: "固定价格券";
8: "免配送费券";
}
/** 优惠券类型枚举 */
export enum CouponType {
FULL_REDUCTION = "full_reduction", // 满减券
DISCOUNT = "discount", // 折扣券
SECOND_HALF = "second_half", // 第二件半价券
BUY_ONE_GET_ONE = "buy_one_get_one", // 买一送一券
EXCHANGE = "exchange", // 商品兑换券
}
/** 后端返回的优惠券原始字段类型 */
export interface BackendCoupon {
id?: number; // 自增主键int64
shopId?: number; // 店铺IDint64
syncId?: number; // 同步Idint64
type?: number; // 优惠券类型1-满减券2-商品兑换券3-折扣券4-第二件半价券5-消费送券6-买一送一券7-固定价格券8-免配送费券
name?: string; // 券名称
useShopType?: string; // 可用门店类型only-仅本店all-所有门店custom-指定门店
useShops?: string; // 可用门店(逗号分隔字符串,如"1,2,3"
useType?: string; // 可使用类型dine堂食/pickup自取/deliv配送/express快递
validType?: string; // 有效期类型fixed固定时间custom自定义时间
validDays?: number; // 有效期(天)
validStartTime?: string; // 有效期开始时间(如"2024-01-01 00:00:00"
validEndTime?: string; // 有效期结束时间
daysToTakeEffect?: number; // 隔天生效
useDays?: string; // 可用周期(如"周一,周二"
useTimeType?: string; // 可用时间段类型all-全时段custom-指定时段
useStartTime?: string; // 可用开始时间(每日)
useEndTime?: string; // 可用结束时间(每日)
getType?: string; // 发放设置:不可自行领取/no可领取/yes
getMode?: string; // 用户领取方式
giveNum?: number; // 总发放数量,-10086为不限量
getUserType?: string; // 可领取用户:全部/all新用户一次/new仅会员/vip
getLimit?: number; // 每人领取限量,-10086为不限量
useLimit?: number; // 每人每日使用限量,-10086为不限量
discountShare?: number; // 与限时折扣同享0-否1-是
vipPriceShare?: number; // 与会员价同享0-否1-是
ruleDetails?: string; // 附加规则说明
status?: number; // 状态0-禁用1-启用
useNum?: number; // 已使用数量
leftNum?: number; // 剩余数量
foods?: string; // 指定门槛商品(逗号分隔字符串,如"101,102"此处为商品ID
fullAmount?: number; // 使用门槛:满多少金额(元)
discountAmount?: number; // 使用门槛:减多少金额(元)
discountRate?: number; // 折扣%如90=9折
maxDiscountAmount?: number; // 可抵扣最大金额(元)
useRule?: string; // 使用规则price_asc-价格低到高price_desc-高到低
discountNum?: number; // 抵扣数量
otherCouponShare?: number; // 与其它优惠共享0-否1-是
createTime?: string; // 创建时间
updateTime?: string; // 更新时间
}
/** 营销活动类型枚举 */
export enum ActivityType {
TIME_LIMIT_DISCOUNT = "time_limit_discount", // 限时折扣
}
/** 基础购物车商品项核心修正新增product_id明确各ID含义 */
export interface BaseCartItem {
id: string | number; // 购物车ID唯一标识购物车中的条目如购物车项主键
product_id: string | number; // 商品ID唯一标识商品用于优惠券/活动匹配,必选)
productId?: string | number; // 商品ID
salePrice: number; // 商品原价(元)
number: number; // 商品数量
num?: number; // 商品数量
isTimeDiscount?: boolean; // 是否限时折扣商品默认false
is_time_discount?: boolean; // 是否限时折扣商品默认false
product_type: GoodsType; // 商品类型
is_temporary?: boolean; // 是否临时菜默认false
isTemporary?: boolean; // 是否临时菜默认false
is_gift?: boolean; // 是否赠菜默认false
isGift?: boolean; // 是否赠菜默认false
returnNum?: number; // 退货数量历史订单用默认0
memberPrice: number; // 商品会员价(元,优先级:商品会员价 > 会员折扣)
discountSaleAmount?: number; // 商家改价后单价(元,优先级最高)
discount_sale_amount?: number; // 商家改价后单价(元,优先级最高)
packFee?: number; // 单份打包费默认0
packNumber?: number; // 堂食打包数量默认0
activityInfo?: {
// 商品参与的营销活动(如限时折扣)
type: ActivityType;
discountRate: number; // 折扣率如0.8=8折
vipPriceShare: boolean; // 是否与会员优惠同享默认false
};
skuData?: {
// SKU扩展数据可选
id: string | number; // SKU ID唯一标识商品规格如颜色/尺寸)
memberPrice: number; // SKU会员价
salePrice?: number; // SKU原价
};
skuId?: string | number; // SKU ID唯一标识商品规格如颜色/尺寸)
couponType?: number; // 优惠券类型1-满减券2-商品兑换券3-折扣券4-第二件半价券5-消费送券6-买一送一券7-固定价格券8-免配送费券
}
export interface CouponFoods {
id: string;
name: string;
images: string;
}
/** 基础优惠券接口(所有券类型继承,包含统一门槛商品字段) */
export interface BaseCoupon {
otherCouponShare?: number; // 与其它优惠共享0-否1-是
id: string | number; // 优惠券ID
type: number; // 工具库字符串枚举由后端couponType转换
name: string; // 对应后端title
available: boolean; // 基于BackendCoupon字段计算的可用性
useShopType?: string; // only-仅本店all-所有门店custom-指定门店
useShops: string[]; // 可用门店ID列表
discountShare: boolean; // 与限时折扣同享0-否1-是(后端字段转换为布尔值)
vipPriceShare: boolean; // 与会员价同享0-否1-是(后端字段转换为布尔值)
useType?: string[]; // 可使用类型dine堂食/pickup自取/deliv配送/express快递
isValid: boolean; // 是否在有效期内
discountAmount?: number; // 减免金额 (满减券有)
fullAmount?: number; // 使用门槛:满多少金额
maxDiscountAmount?: number; // 可抵扣最大金额 元
use: boolean;
discountNum?: number; // 抵扣数量
useRule?: string; // 使用规则price_asc-价格低到高price_desc-高到低
discountRate?: number; // 折扣%如90=9折
noUseRestrictions?: boolean; // 是不可用原因
thresholdFoods: CouponFoods[]; // 门槛商品ID列表空数组=全部商品,非空=指定商品ID
useFoods: CouponFoods[]; // 可用商品ID列表空数组=全部商品,非空=指定商品ID
}
export interface couponDiscount {
discountPrice: number;
hasDiscountGoodsArr: BaseCartItem[];
}
/** 满减券(适配后端字段) */
export interface FullReductionCoupon extends BaseCoupon {
fullAmount: number; // 对应后端fullAmount满减门槛
discountAmount: number; // 对应后端discountAmount减免金额
maxDiscountAmount?: number; // 对应后端maxDiscountAmount最大减免
discount?: couponDiscount;
}
/** 折扣券(适配后端字段) */
export interface DiscountCoupon extends BaseCoupon {
discountRate: number; // 后端discountRate%转小数如90→0.9
maxDiscountAmount: number; // 对应后端maxDiscountAmount最大减免
discount?: couponDiscount;
}
/** 第二件半价券(适配后端字段) */
export interface SecondHalfPriceCoupon extends BaseCoupon {
maxUseCountPerOrder?: number; // 对应后端useLimit-10086=不限)
discount?: couponDiscount;
}
/** 买一送一券(适配后端字段) */
export interface BuyOneGetOneCoupon extends BaseCoupon {
maxUseCountPerOrder?: number; // 对应后端useLimit-10086=不限)
discount?: couponDiscount;
}
/** 商品兑换券(适配后端字段) */
export interface ExchangeCoupon extends BaseCoupon {
deductCount: number; // 对应后端discountNum抵扣数量
sortRule: "low_price_first" | "high_price_first"; // 后端useRule转换
discount?: couponDiscount;
}
/** 所有优惠券类型联合 */
export type Coupon =
| FullReductionCoupon
| DiscountCoupon
| SecondHalfPriceCoupon
| BuyOneGetOneCoupon
| ExchangeCoupon;
/** 营销活动配置如限时折扣applicableProductIds为商品ID列表 */
export interface ActivityConfig {
type: ActivityType;
applicableProductIds?: string[]; // 适用商品ID列表与BaseCartItem.product_id匹配
discountRate: number; // 折扣率如0.8=8折
vipPriceShare: boolean; // 是否与会员优惠同享
}
/** 积分抵扣规则 */
export interface PointDeductionRule {
pointsPerYuan: number; // X积分=1元如100=100积分抵1元
maxDeductionAmount?: number; // 最大抵扣金额(元,默认不限)
}
/** 餐位费配置 */
export interface SeatFeeConfig {
pricePerPerson: number; // 每人餐位费(元)
personCount: number; // 用餐人数默认1
isEnabled: boolean; // 是否启用餐位费默认false
}
/** 商家减免类型枚举 */
export enum MerchantReductionType {
FIXED_AMOUNT = "fixed_amount", // 固定金额减免(如直接减 10 元)
DISCOUNT_RATE = "discount_rate", // 比例折扣减免(如打 9 折,即减免 10%
}
/** 商家减免配置(新增,替代原单一金额字段) */
export interface MerchantReductionConfig {
type: MerchantReductionType; // 减免类型(二选一)
fixedAmount?: number; // 固定减免金额(元,仅 FIXED_AMOUNT 生效≥0
discountRate?: number; // 折扣率(%,仅 DISCOUNT_RATE 生效0-100如 90 代表 9 折)
}
/**商家霸王餐配置 */
export interface FreeDineConfig {
enable: boolean; //是否开启
rechargeThreshold: number; //订单满多少元可以使用
rechargeTimes: number; //充值多少倍免单
withCoupon: boolean; //与优惠券同享
withPoints: boolean; //与积分同享
useType?: string[]; //使用类型 dine-in店内 takeout 自取 post快递takeaway外卖
useShopType?: string; //all 全部 part部分
shopIdList?: number[]; //可用门店id
}
//限时折扣配置
export interface TimeLimitDiscountConfig {
/**
* limit-time/vip-price
*/
discountPriority: string;
/**
* % 1-99
*/
discountRate: number;
/**
*
*/
foods: string;
/**
* 1 2
*/
foodType: number;
/**
*
*/
id: number;
/**
* ID
*/
shopId: number;
/**
* 使 dine-in take-out take-away post
*/
useType: string;
[property: string]: any;
}
//用户信息
export interface ShopUserInfo {
isVip: number | null; //是否会员
discount: number | null; //用户折扣
isMemberPrice: number | null; //会员折扣与会员价是否同时使用
id?: number; //用户ID
}
/** 订单额外费用配置 */
export interface OrderExtraConfig {
// merchantReduction: number; // 商家减免金额默认0
// 替换原单一金额字段,支持两种减免形式
merchantReduction: MerchantReductionConfig;
additionalFee: number; // 附加费如余额充值、券包默认0
pointDeductionRule: PointDeductionRule; // 积分抵扣规则
seatFeeConfig: SeatFeeConfig; // 餐位费配置
currentStoreId: string; // 当前门店ID用于验证优惠券适用门店
userPoints: number; // 用户当前积分(用于积分抵扣)
isMember: boolean; // 用户是否会员(用于会员优惠)
memberDiscountRate?: number; // 会员折扣率如0.95=95折无会员价时用
newUserDiscount?: number; // 新用户减免金额默认0
fullReductionActivities: FullReductionActivity[]; // 当前店铺的满减活动列表(后端返回结构)
currentDinnerType: "dine-in" | "take-out" | "take-away" | "post"; // 当前就餐类型匹配useType
isFreeDine?: boolean; //是否霸王餐
freeDineConfig?: FreeDineConfig;
limitTimeDiscount?: TimeLimitDiscountConfig; //限时折扣
shopUserInfo: ShopUserInfo; // 用户信息
}
/** 订单费用汇总(修改:补充商家减免类型和明细) */
export interface OrderCostSummary {
goodsList: BaseCartItem[];
// 商品总件数
goodsTotal: number;
totalDiscountAmount: number;
goodsRealAmount: number; // 商品真实原价总和
goodsOriginalAmount: number; // 商品原价总和
goodsDiscountAmount: number; // 商品折扣金额
couponDeductionAmount: number; // 优惠券总抵扣
productCouponDeduction: number; // 商品优惠券抵扣
fullCouponDeduction: number; // 满减优惠券抵扣
pointDeductionAmount: number; // 积分抵扣金额
seatFee: number; // 餐位费
packFee: number; // 打包费
scoreMaxMoney: number; // 积分最大可抵扣金额
// 新增:商家减免明细
merchantReduction: {
type: MerchantReductionType; // 实际使用的减免类型
originalConfig: MerchantReductionConfig; // 原始配置(便于前端展示)
actualAmount: number; // 实际减免金额计算后的值≥0
};
additionalFee: number; // 附加费
finalPayAmount: number; // 最终实付金额
couponUsed?: Coupon; // 实际使用的优惠券
pointUsed: number; // 实际使用的积分
newUserDiscount: number; // 新用户减免金额默认0
dinnerType?: "dine-in" | "take-out"; // 就餐类型(堂食/自取/配送/快递)
config: OrderExtraConfig; // 订单额外费用配置
//满减活动
fullReduction: {
usedFullReductionActivityFullAmount: number; // 计算出的满减活动的门槛金额
usedActivity?: FullReductionActivity; // 实际使用的满减活动
usedThreshold?: FullReductionThreshold; // 实际使用的满减阈值(多门槛中选最优)
actualAmount: number; // 满减实际减免金额(元)
};
vipDiscountAmount: number; //会员折扣减免金额
// 订单原支付金额
orderOriginFinalPayAmount: number; //订单原金额(包含打包费+餐位费)
}
/** 满减活动阈值单条满减规则满X减Y- 对应 MkDiscountThresholdInsertGroupDefaultGroup */
export interface FullReductionThreshold {
activityId?: number; // 关联满减活动ID
fullAmount?: number; // 满多少金额(元,必填)
discountAmount?: number; // 减多少金额(元,必填)
}
/** 满减活动主表 - 对应 Request 接口(后端真实字段) */
export interface FullReductionActivity {
id?: number; // 自增主键后端字段id
shopId?: number; // 店铺ID后端字段shopId
status?: number; // 活动状态1=未开始2=进行中3=已结束后端字段status
sort?: number; // 排序值越大优先级越高后端字段sort
createTime?: string; // 创建时间后端字段createTime格式如"2025-10-14 13:56:07"
updateTime?: string; // 最新修改时间后端字段updateTime用于优先级排序
validStartTime?: string; // 有效期开始时间后端字段validStartTime格式如"2025-10-14"
validEndTime?: string; // 有效期结束时间后端字段validEndTime格式如"2025-12-14"
useType?: string; // 可使用类型后端字段useType如"dine,pickup,deliv,express"
useDays?: string; // 可用周期后端字段useDays如"周一,周二,周三,周四,周五,周六,周日"
useTimeType?: string; // 可用时间段类型后端字段useTimeTypeall=全时段custom=指定时段)
useStartTime?: string; // 每日可用开始时间后端字段useStartTime如"09:00:00"仅custom时有效
useEndTime?: string; // 每日可用结束时间后端字段useEndTime如"22:00:00"仅custom时有效
couponShare?: number; // 与优惠券同享0=否1=是后端字段couponShare
discountShare?: number; // 与限时折扣同享0=否1=是后端字段discountShare
vipPriceShare?: number; // 与会员价同享0=否1=是后端字段vipPriceShare
pointsShare?: number; // 与积分抵扣同享0=否1=是后端字段pointsShare
thresholds?: FullReductionThreshold[]; // 满减阈值列表多门槛后端字段thresholds
isDel?: boolean; // 是否删除0=否1=是后端字段isDel默认false
}
// 辅助枚举星期映射用于useDays校验
export const WEEKDAY_MAP = {
周一: 1,
周二: 2,
周三: 3,
周四: 4,
周五: 5,
周六: 6,
周日: 0, // JS中getDay()返回0=周日
};
export interface ShopInfo {
isMemberPrice: number; // 是否开启会员价 1是开启
[property: string]: any;
}
export interface couponCalcParams {
canDikouGoodsArr: BaseCartItem[];
coupon: Coupon;
user: ShopUserInfo;
shopInfo: ShopInfo;
selCoupon: Coupon[];
goodsOrderPrice: number; //商品订单总价
isMemberPrice: number; // 是否开启会员价 1是开启
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined;
}
export interface CanDikouGoodsArrArgs {
canDikouGoodsArr: BaseCartItem[];
selCoupon: Coupon[];
user: ShopUserInfo;
shopInfo: ShopInfo;
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined;
}
export interface returnPriceArgs {
goods: BaseCartItem;
selCoupon: Coupon[];
user: ShopUserInfo;
shopInfo: ShopInfo;
shopUserInfo: ShopUserInfo;
limitTimeDiscountRes?: TimeLimitDiscountConfig | null | undefined;
idKey?: keyof BaseCartItem;
}
export interface CanReturnMemberPriceArgs {
shopInfo?: ShopInfo;
shopUserInfo: ShopUserInfo;
}

33
lib/utils.ts Normal file
View File

@ -0,0 +1,33 @@
/**
* /线
* @param obj BaseCartItem
* @param camelCaseKey 'isTemporary'
* @param snakeCaseKey 线 'is_temporary'
* @param defaultValue false
* @returns
*/
export function getCompatibleFieldValue(
obj: Record<string, any>,
camelCaseKey: string,
snakeCaseKey: string,
defaultValue: boolean = false
): boolean {
// 优先判断驼峰字段(如果存在且不是 undefined/null
if (
obj.hasOwnProperty(camelCaseKey) &&
obj[camelCaseKey] !== undefined &&
obj[camelCaseKey] !== null
) {
return Boolean(obj[camelCaseKey]);
}
// 再判断下划线字段
if (
obj.hasOwnProperty(snakeCaseKey) &&
obj[snakeCaseKey] !== undefined &&
obj[snakeCaseKey] !== null
) {
return Boolean(obj[snakeCaseKey]);
}
// 都不存在时返回默认值(布尔类型字段默认 false
return defaultValue;
}

View File

@ -7,6 +7,9 @@ import dict from '@/commons/utils/dict.js'
import {utils} from '@/commons/utils/index.js'
import uviewPlus from 'uview-plus'
import * as Pinia from 'pinia';
import {
createUnistorage
} from "pinia-plugin-unistorage";
// 设置node环境
envConfig.changeEnv(storageManage.env())
@ -39,7 +42,9 @@ export function createApp() {
const app = createSSRApp(App)
app.use(uviewPlus)
app.use(Pinia.createPinia());
const store = Pinia.createPinia();
store.use(createUnistorage());
app.use(store)
app.config.globalProperties.$appName = appConfig.appName
uni.$appName = appConfig.appName
app.config.globalProperties.$utils = utils

View File

@ -1,5 +1,6 @@
{
"dependencies": {
"bignumber.js": "^9.3.1",
"clipboard": "^2.0.11",
"dayjs": "^1.11.13",
"gm-crypto": "^0.1.8",
@ -8,8 +9,10 @@
"jsbn": "^1.1.0",
"jsencrypt": "^3.3.2",
"lodash": "^4.17.21",
"pinia-plugin-unistorage": "^0.1.2",
"to-arraybuffer": "^1.0.1",
"uview-plus": "^3.3.32"
"uview-plus": "^3.3.32",
"ysk-utils": "^1.0.78"
},
"devDependencies": {
"copy-webpack-plugin": "^12.0.2",

View File

@ -4,7 +4,7 @@
<view class="goods">
<view class="u-m-t-24 u-flex u-col-top u-relative">
<view class="img">
<up--image :width="63" :height="63" :radius="3" :src="data.coverImg"></up--image>
<up-image :width="63" :height="63" :radius="3" :src="data.coverImg"></up-image>
</view>
<view class="w-full info u-p-l-30">
<view class="color-333 u-flex u-row-between">

View File

@ -41,10 +41,10 @@
<view class="u-flex u-row-between u-m-b-32">
<text class="font-bold color-333">活动日期</text>
</view>
<timeArea
<my-time-area
v-model:startDate="form.validStartTime"
v-model:endDate="form.validEndTime"
></timeArea>
></my-time-area>
</view>
<view class="u-m-t-32">
<up-line ></up-line>
@ -53,7 +53,7 @@
<view class="u-flex u-row-between">
<text class="font-bold color-333 u-m-b-32">可用周期</text>
</view>
<weekSel v-model="form.useDays"></weekSel>
<my-week-sel v-model="form.useDays"></my-week-sel>
</view>
</view>
@ -61,11 +61,11 @@
<view class="u-flex u-row-between">
<text class="font-bold color-333 u-m-b-32">指定时间段</text>
</view>
<hourSel
<my-hour-area
v-model:useTimeType="form.useTimeType"
v-model:startValue="form.useStartTime"
v-model:endValue="form.useEndTime"
></hourSel>
></my-hour-area>
</view>
<view class="u-m-t-32 container">
<view class="u-flex u-row-between">
@ -144,15 +144,11 @@
></up-switch>
</view>
</view>
<bottomBtnGroup @save="save" @cancel="cancel"></bottomBtnGroup>
<my-bottom-btn-group @save="save" @cancel="cancel"></my-bottom-btn-group>
</view>
</template>
<script setup>
import timeArea from "./components/time-area.vue";
import weekSel from "./components/week-sel.vue";
import hourSel from "./components/hour-area.vue";
import bottomBtnGroup from "./components/bottom-btn-group.vue";
import { reactive } from "vue";
import * as discountActivityApi from "@/http/api/market/discountActivity.js";
import {

View File

@ -1,29 +0,0 @@
<template>
<view>
<view style="height: 180rpx"></view>
<view class="fixed-bottom u-flex gap-20">
<view class="u-flex-1">
<my-button type="primary" @click="save" shape="circle">
保存
</my-button>
</view>
<view class="u-flex-1">
<my-button bgColor="#fff" type="default" @click="cancel" shape="circle">
取消
</my-button>
</view>
</view>
</view>
</template>
<script setup>
const emit= defineEmits(["save", "cancel"]);
function save() {
emit("save");
}
function cancel() {
emit("cancel");
}
</script>

View File

@ -26,7 +26,7 @@
</label>
</view>
<view class="img">
<up--image :width="63" :height="63" :radius="3" :src="data.coverImg"></up--image>
<up-image :width="63" :height="63" :radius="3" :src="data.coverImg"></up-image>
</view>
<view class="w-full info">
<view class="info-p-l color-333 u-flex u-row-between">

View File

@ -1,12 +1,17 @@
<template>
<view class="container">
<view class="row" v-for="(item, index) in menuList" :key="index">
<view class="row" v-for="(item, index) in computedMenus" :key="index">
<view class="header">
<text class="t">{{ item.label }}</text>
</view>
<view class="menu-wrap">
<view class="item" v-for="(val, i) in item.menus" :key="i" @click="go.to(val.pageUrl)">
<image :src="`/static/applocation/${val.icon}.png`" mode="aspectFit" class="icon"></image>
<view
class="item"
v-for="(val, i) in item.menus"
:key="i"
@click="go.to(val.pageUrl)"
>
<image :src="val.icon" mode="aspectFit" class="icon"></image>
<view class="info">
<view class="title">
<text class="t">{{ val.title }}</text>
@ -22,78 +27,147 @@
</template>
<script setup>
import { ref, computed } from 'vue';
import go from '@/commons/utils/go.js';
import { useMenusStore } from '@/store/menus.js';
import { ref, computed } from "vue";
import go from "@/commons/utils/go.js";
import { useMenusStore } from "@/store/menus.js";
const menusStore = useMenusStore();
const menuList = ref([
{
label: '营销',
label: "营销",
menus: [
{
icon: 'xszk',
pageUrl: 'PAGES_LIMIT_DISCOUNT',
title: '限时折扣',
intro: '批量设置商品折扣'
title: "霸王餐",
icon: "",
intro: "设置充值消费的N倍当前订单立即免单",
pageUrl: "PAGES_BWC",
},
{
icon: 'czdhm',
pageUrl: 'LIMIT_DISCOUNT',
title: '充值兑换码',
intro: '兑换码直充余额,可当作礼品赠送'
},
{
title: '优惠券',
icon: '/static/indexImg/icon-order.svg',
pageUrl: 'PAGES_ORDER_INDEX'
title: "积分锁客",
icon: "",
pageUrl: "",
intro: "设置充值消费的N倍当前订单立即免单",
},
{
title: '霸王餐',
icon: '/static/indexImg/icon-order.svg',
pageUrl: 'PAGES_ORDER_INDEX'
title: "弹窗广告",
icon: "",
pageUrl: "PAGES_ORDER_INDEX",
intro: "设置弹窗广告",
},
{
title: '邀请裂变',
icon: '/static/indexImg/icon-order.svg',
pageUrl: 'PAGES_ORDER_INDEX'
title: "超级会员",
icon: "",
pageUrl: "PAGES_ORDER_INDEX",
intro: "用户会员管理设置",
},
{
title: '积分锁客',
icon: '/static/indexImg/icon-order.svg',
pageUrl: 'PAGES_ORDER_INDEX'
title: "新客立减",
icon: "",
pageUrl: "PAGES_ORDER_INDEX",
intro: "首单下单减免金额",
},
{
title: '满减活动',
icon: '/static/indexImg/icon-order.svg',
pageUrl: 'PAGES_MARKET_DISCOUNT_ACTIVITY'
title: "智慧充值",
icon: "",
pageUrl: "PAGES_ORDER_INDEX",
intro: "允许客户充值并使用余额支付",
},
{
title: '私域引流',
icon: '/static/indexImg/icon-order.svg',
pageUrl: 'PAGES_MARKET_DRAINAGE_CONFIG'
title: "分销",
icon: "",
pageUrl: "PAGES_PAY",
intro: "用户成为业务员,可促进消费",
},
{
title: '消费返现',
icon: '/static/indexImg/icon-order.svg',
pageUrl: 'PAGES_MARKET_CONSUME_CASHBACK'
title: "消费返现",
icon: "",
pageUrl: "PAGES_MARKET_CONSUME_CASHBACK",
intro: "用户下单后返现一定的金额到余额,可促进复购",
},
{
title: '分销',
icon: '/static/indexImg/icon-order.svg',
pageUrl: 'PAGES_PAY'
}
]
}
title: "私域引流",
icon: "",
pageUrl: "PAGES_MARKET_DRAINAGE_CONFIG",
intro: "可设置用户下单成功后的群二维码",
},
{
title: "满减活动",
icon: "",
pageUrl: "PAGES_MARKET_DISCOUNT_ACTIVITY",
intro: "达到指定支付金额享受减价",
},
{
title: "生日有礼",
icon: "",
pageUrl: "",
intro: "用户生日管理设置",
},
{
title: "点餐智能推荐",
icon: "",
pageUrl: "",
intro: "进入点单页X秒未点自动推荐商品此推荐设置启用即生效",
},
{
title: "超值券包",
icon: "",
pageUrl: "",
intro: "下单加购",
},
{
title: "套餐推广",
icon: "",
pageUrl: "",
intro: "下单通过用户邀请好友减免金额的方式裂变宣传套餐加购",
},
{
title: "充值兑换码",
icon: "",
pageUrl: "",
intro: "兑换码直充余额,可当作礼品赠送",
},
{
title: "券兑换码",
icon: "",
pageUrl: "",
intro: "可添加多券组合兑换",
},
{
icon: "xszk",
pageUrl: "PAGES_LIMIT_DISCOUNT",
title: "限时折扣",
intro: "批量设置商品折扣",
},
{
icon: "xszk",
pageUrl: "PAGES_LIMIT_DISCOUNT",
title: "商品拼团",
intro: "拼团",
},
],
},
]);
console.log(menusStore.adminPages);
const computedMenus = computed(() => {
const arr = menusStore.adminPages.filter((v) => {
return navList.find((navItem) => navItem.title == v.title);
// const arr = menusStore.adminPages.filter((v) => {
// return navList.find((navItem) => navItem.title == v.title);
// });
return menuList.value.map((v) => {
v.menus = v.menus.filter((menu) => {
const hasPermission = menusStore.adminPages.find(
(navItem) => navItem.title == menu.title
);
console.log("hasPermission", hasPermission);
if (hasPermission) {
menu.icon = hasPermission.miniIcon;
console.log(menu);
}
return hasPermission;
});
return v;
});
console.log(arr);
return arr;
});
</script>

View File

@ -79,7 +79,6 @@
name: '',
totalElements: 0,
size: 10,
isVip: 1
})
const list = reactive([])
let hasAjax = ref(false)

View File

@ -0,0 +1,610 @@
<template>
<view
class="bg-fff border-r-24 u-m-t-32"
v-if="orderInfo && orderInfo.detailMap"
>
<view
class="u-m-b-20"
v-for="(goods, orderIndex) in orderInfo.detailMap"
:key="orderIndex"
>
<view class="u-p-t-24"> {{ orderIndex }}次下单 </view>
<view class="u-m-t-24 list">
<view class="item u-m-b-32" v-for="(item, index) in goods" :key="index">
<view class="u-flex u-col-top">
<view class="u-flex u-relative">
<view class="limit-discount" v-if="item.isTimeDiscount"
>限时折扣</view
>
<image
v-if="item.isTemporary == 0"
class="img"
:src="item.coverImg || item.productImg"
mode=""
></image>
<view
v-else
style="
background-color: #3f9eff;
width: 152rpx;
height: 152rpx;
line-height: 152rpx;
text-align: center;
color: #fff;
"
>
临时菜
</view>
</view>
<view class="u-p-l-32 u-flex-1">
<view class="u-flex u-row-between u-col-top">
<view class="">
<view class="u-flex">
<view class="tui" v-if="isTui(item)">
{{
item.status == "part_refund" ? "部分已退" : "全部已退"
}}
</view>
<view
:class="{
'line-th':
item.status == 'return' ||
item.status == 'refund' ||
item.status == 'refunding',
}"
>
{{ item.name || item.productName }}
</view>
</view>
<view
class="u-flex u-m-t-8"
style="flex-direction: column; align-items: flex-start"
>
<view class="u-flex u-m-b-8">
<view class="u-m-r-20 u-flex" v-if="item.isGift">
<uni-tag
text="赠送"
custom-style="background-color: #FFF0DF; border-color: #FFF0DF; color: #FF9F2E;"
>
</uni-tag>
</view>
<view class="u-m-r-20 u-flex" v-if="item.userCouponId">
<uni-tag
:text="productCouponDikou(item)"
custom-style="background-color: #FFF0DF; border-color: #FFF0DF; color: #FF9F2E;"
>
</uni-tag>
</view>
<view class="u-m-r-20 u-flex" v-if="item.packNumber > 0">
<uni-tag
custom-style="background-color: #E6F0FF; border-color: #E6F0FF; color: #318AFE;"
size="small"
text="打包"
inverted
type="success"
/>
</view>
</view>
<view class="u-flex u-m-t-8">
<view
class="u-m-r-20 u-font-24 u-flex"
v-if="item.refundNum > 0"
>
<view class="color-666">退款金额:</view>
<view class="color-999 u-m-l-6">{{
item.refundNum * item.unitPrice
}}</view>
</view>
<view
class="u-m-r-20 u-font-24 u-flex"
v-if="item.returnNum"
>
<view class="color-666">退菜数量:</view>
<view class="color-999 u-m-l-6">{{
item.returnNum
}}</view>
</view>
</view>
</view>
<view class="color-999 u-font-24 u-m-t-8">{{
item.skuName || ""
}}</view>
<view class="u-m-t-12 color-666 u-font-24" v-if="item.remark">
备注{{ item.remark }}
</view>
</view>
<view class="u-text-right u-m-t-28">
<view class="u-relative">
<template v-if="item.isGift">
<text class="line-th color-999"
>{{ toFixed(item.price * item.num, item) }}</text
>
<view class="u-absolute" style="right: 0; bottom: 100%">
<text class="font-bold">0</text>
</view>
</template>
<template v-else>
<template
v-if="
item.discountSaleAmount &&
item.discountSaleAmount * 1 > 0
"
>
<text class="line-th color-999"
>{{ toFixed(item.price * item.num, item) }}</text
>
<view class="u-absolute" style="right: 0; bottom: 100%">
<text class="font-bold"
>{{
toFixed(item.discountSaleAmount * item.num, item)
}}</text
>
</view>
</template>
<template v-else-if="item.isTimeDiscount">
<text class="line-th color-999"
>{{ toFixed(item.price * item.num, item) }}</text
>
<view
class="u-absolute xianshi"
style="right: 0; bottom: 100%"
>
<text class="font-bold"
>{{ returnLimitTotalMoney(item) }}</text
>
</view>
</template>
<template
v-else-if="
isVip &&
item.price &&
item.price * 1 != item.memberPrice * 1
"
>
<text class="line-th color-999"
>{{ toFixed(item.price * item.num, item) }}</text
>
<view class="u-absolute" style="right: 0; bottom: 100%">
<text class="font-bold"
>{{
toFixed(item.memberPrice * item.num, item)
}}</text
>
</view>
</template>
<template v-else>
<view class="font-bold">
<text></text>
<text class="">{{
toFixed(item.price * item.num, item)
}}</text>
</view>
</template>
</template>
</view>
<view class="u-m-t-22 color-999 u-font-24"
>X{{ item.num || item.num }}</view
>
</view>
</view>
</view>
</view>
<!-- <template v-if="canTuicai(orderInfo, item)"> -->
<template v-if="false">
<view
class="u-flex u-row-right gap-20 u-m-t-24"
v-if="item.returnNum * item.unitPrice < item.num * item.unitPrice"
>
<my-button
:width="128"
:height="48"
plain
shape="circle"
@tap="tuicai(item, index)"
><text class="no-wrap">退菜</text></my-button
>
</view>
</template>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { computed, reactive,inject } from "vue";
import BigNumber from "bignumber.js";
import { hasPermission } from "@/commons/utils/hasPermission.js";
import {
isTui,
isTuiCai,
isGift,
canTuiKuan,
canTuicai,
mathFloorPrice,
} from "@/commons/utils/goodsUtil.js";
const emits = defineEmits(["tuicai", "tuikuan", "printOrder"]);
const yskUtils = inject("yskUtils");
const shopInfo = inject("shopInfo");
const pageData = inject("pageData");
const pop = reactive({
youhui: false,
});
const props = defineProps({
orderInfo: {
type: Object,
default: () => {},
},
data: {
type: Array,
default: () => [],
},
seatFee: {
type: Object,
default: () => {},
},
user: {
type: Object,
default: () => {
return {
id: "",
isVip: false,
};
},
},
});
/**
* 计算菜品数量
*/
const goodsNumber = computed(() => {
let result = 0;
result = props.data.reduce((a, b) => {
const bTotal = b.info.length;
return a + bTotal;
}, 0);
return result.toFixed(0);
});
/**
* 桌位费
*/
const seatFeePrice = computed(() => {
const n =
props.orderInfo.seatNum > 0
? props.orderInfo.seatNum * uni.getStorageSync("shopInfo").tableFee
: 0;
return n.toFixed(2);
});
function toFixed(price, item) {
if (item) {
if (item.productType == "weight" || item.type == "weight") {
return (Math.floor(price * 100) / 100).toFixed(2);
} else {
return parseFloat(price).toFixed(2);
}
} else {
return parseFloat(price).toFixed(2);
}
}
/**
* 判断是否是会员
*/
const isVip = computed(() => {
return (
uni.getStorageSync("shopInfo").isMemberPrice &&
props.user &&
props.user.id &&
props.user.isVip
);
});
function returnLimitTotalMoney(data) {
const price = yskUtils.limitUtils.returnPrice({
goods: data,
shopInfo: pageData.shopInfo,
limitTimeDiscountRes: pageData.limitTimeDiscount,
shopUserInfo: pageData.user,
idKey: "product_id",
});
return BigNumber(price).times(data.number).toNumber();
}
const vipDiscountPrice = computed(() => {
if (!isVip.value) {
return 0;
}
const goodsPrice = props.data.reduce((prve, cur) => {
const curTotal = cur.info
.filter(
(v) =>
v.discountSaleAmount <= 0 &&
v.isGift != 1 &&
v.status !== "return" &&
v.price != v.unitPrice &&
v.memberPrice != v.price
)
.reduce((a, b) => {
return a + b.num * (b.price - b.memberPrice);
}, 0);
return prve + curTotal;
}, 0);
return goodsPrice.toFixed(2);
});
/**
* 单品打折优惠
*/
const discountSaleAmount = computed(() => {
const goodsPrice = props.data.reduce((prve, cur) => {
const curTotal = cur.info
.filter(
(v) =>
v.discountSaleAmount > 0 && v.isGift != 1 && v.status !== "return"
)
.reduce((a, b) => {
return a + b.num * (b.price - b.discountSaleAmount);
}, 0);
return prve + curTotal;
}, 0);
return goodsPrice.toFixed(2);
});
/**
* 打折优惠
*/
const discountAmount = computed(() => {
return props.orderInfo.discountAmount || 0;
});
/**
* 总优惠金额
*/
const discountsPrice = computed(() => {
//
let fullCouponDiscountAmount =
props.orderInfo.status == "done"
? props.orderInfo.fullCouponDiscountAmount
: 0;
//
let productCouponDiscountAmount =
props.orderInfo.status == "done"
? props.orderInfo.productCouponDiscountAmount
: 0;
//
let pointsDiscountAmount =
props.orderInfo.status == "done" ? props.orderInfo.pointsDiscountAmount : 0;
return (
parseFloat(vipDiscountPrice.value) +
parseFloat(discountSaleAmount.value) +
discountAmount.value +
fullCouponDiscountAmount +
productCouponDiscountAmount +
pointsDiscountAmount
).toFixed(2);
});
//
const productCoupPrice = computed(() => {
if (props.orderInfo.status == "done") {
return props.orderInfo.productCouponDiscountAmount;
}
const goodsPrice = props.data.reduce((a, b) => {
const curTotal = b.info
.filter((v) => !v.isGift)
.reduce((prve, cur) => {
let memberPrice = cur.memberPrice ? cur.memberPrice : cur.price;
let tPrice = isVip.value ? memberPrice : cur.price;
tPrice =
cur.memberPrice != cur.unitPrice && cur.price != cur.unitPrice
? cur.unitPrice
: tPrice;
let Total = Math.floor(tPrice * cur.num * 100) / 100;
return (
prve + Total - cur.returnNum * tPrice - cur.refundNum * cur.unitPrice
);
}, 0);
return a + curTotal;
}, 0);
// console.log("==",goodsPrice)
return goodsPrice.toFixed(2);
});
const allPpackFee = computed(() => {
//退
const goodsPrice = props.data.reduce((prve, cur) => {
const curTotal = cur.info
.filter((v) => v.packNumber > 0)
.reduce((a, b) => {
return a + parseFloat(b.packAmount * b.packNumber).toFixed(2) * 1;
}, 0);
return prve + curTotal;
}, 0);
return goodsPrice.toFixed(2);
});
const packFee = computed(() => {
//退
const goodsPrice = props.data.reduce((prve, cur) => {
const curTotal = cur.info
.filter((v) => v.status !== "return" && v.returnNum + v.refundNum < v.num)
.reduce((a, b) => {
return (
a +
parseFloat(
(
b.packAmount *
(b.num - (b.returnNum + b.refundNum) > b.packNumber
? b.packNumber
: b.num - (b.returnNum + b.refundNum))
).toFixed(2)
)
);
}, 0);
return prve + curTotal;
}, 0);
return goodsPrice.toFixed(2);
});
const allPrice = computed(() => {
let seatAmount = props.orderInfo.seatAmount || 0;
const total = productCoupPrice.value * 1 + seatAmount * 1 + packFee.value * 1;
return (total <= 0 ? 0 : total).toFixed(2);
});
/**
* 已优惠金额
*/
const youhuiAllPrice = computed(() => {
const n = vipDiscountPrice.value * 1;
return (n < 0 ? 0 : n).toFixed(2);
});
function youhuiDetailShow() {
pop.youhui = true;
}
function productCouponDikou(item) {
return "商品券抵扣¥" + returnProductCoupPrice(item);
}
function youhuiDetailHide() {
pop.youhui = false;
}
/**
* 转桌/并桌
*/
function rotatingTables() {
let arr = [];
props.data.forEach((ele) => {
ele.info.forEach((res) => {
// coverImg
res.coverImg = res.productImg;
// name
res.name = res.productName;
// price
res.price = res.price;
// number
res.number = res.num;
res.masterId = props.orderInfo.masterId;
res.useType = props.orderInfo.useType;
res.tableId = props.orderInfo.tableId;
arr.push(res);
});
});
uni.navigateTo({
url:
"/pagesCreateOrder/confirm-order/rotatingTables?item=" +
JSON.stringify(arr) +
"&tableId=" +
props.orderInfo.tableId,
});
}
function returnProductCoupPrice(item) {
if (!item.isMember) {
return item.price * item.num;
}
const price = item.memberPrice ? item.memberPrice : item.price;
return price * item.num;
}
function returnCanTuiMoney(item) {
// if (props.orderInfo.status == 'unpaid') {
// return returnTotalMoney(item)
// } else {
if (
props.orderInfo.pointsDiscountAmount > 0 ||
props.orderInfo.fullCouponDiscountAmount > 0
) {
return item.canReturnAmount;
} else if (item.price != item.unitPrice) {
return item.price * item.num;
} else {
return (Math.floor(item.num * item.unitPrice * 100) / 100).toFixed(2);
}
// }
}
function tuicai(item, index) {
emits("tuicai", item, index);
}
</script>
<style lang="scss" scoped>
.img {
width: 152rpx;
height: 152rpx;
border-radius: 6px;
}
.border-top {
border-color: #f6f6f6;
}
.border-r-24 {
border-radius: 24rpx;
}
.border-bottom {
// border-color: rgb(240, 240, 240);
border-color: #f6f6f6;
}
.line-th {
text-decoration: line-through;
}
.tag {
padding: 4rpx 8rpx 2rpx 10rpx;
border-radius: 8rpx;
font-size: 24rpx;
&.no-pay {
background-color: rgb(170, 170, 170);
color: #fff;
}
&.refund {
background-color: #fce7e7;
padding: 8rpx 20rpx 6rpx 22rpx;
color: #eb4f4f;
}
}
.tui {
background-color: rgb(239, 239, 239);
border-radius: 4rpx;
margin-right: 6rpx;
color: #666;
padding: 0 4rpx;
font-size: 20rpx;
}
.limit-discount {
background-color: #cc5617;
padding: 2rpx 10rpx;
white-space: nowrap;
text-align: center;
position: absolute;
top: 0;
left: 0;
font-weight: 400;
font-size: 24rpx;
color: #ffffff;
border-radius: 20rpx 0rpx 20rpx 0rpx;
z-index: 9;
color: #fff;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -3,16 +3,31 @@
<view class="mask" @tap="hideGoods" v-if="switchGoods"></view>
<view class="car border-top u-flex u-row-between u-col-bottom u-relative">
<view class="u-absolute goods bg-fff">
<view class="u-p-t-32 color-666 border-bottom bg-fff u-absolute total u-p-r-28 u-p-b-32 u-p-l-28 u-flex u-row-between">
<view
class="u-p-t-32 color-666 border-bottom bg-fff u-absolute total u-p-r-28 u-p-b-32 u-p-l-28 u-flex u-row-between"
>
<view>已添加{{ goodsNumber.toFixed(0) }}件商品</view>
<view class="color-666">
<uni-icons color="#666" type="trash"></uni-icons>
<text class="u-m-l-10" @tap="setModalShow('clear', true, 'cart', '是否清空全部已添加的商品')">清空购物车</text>
<text
class="u-m-l-10"
@tap="
setModalShow('clear', true, 'cart', '是否清空全部已添加的商品')
"
>清空购物车</text
>
</view>
</view>
<scroll-view scroll-y="true" class="tranistion" :style="{ height: switchGoods ? '50vh' : 0 }">
<scroll-view
scroll-y="true"
class="tranistion"
:style="{ height: switchGoods ? '50vh' : 0 }"
>
<!-- 占位 -->
<view class="u-p-t-32 color-666 border-bottom u-p-r-28 u-p-b-32 u-p-l-28 u-flex u-row-between" style="opacity: 0">
<view
class="u-p-t-32 color-666 border-bottom u-p-r-28 u-p-b-32 u-p-l-28 u-flex u-row-between"
style="opacity: 0"
>
<view>已添加{{ goodsNumber.toFixed(0) }}件商品</view>
<view class="color-666">
<uni-icons color="#666" type="trash"></uni-icons>
@ -20,15 +35,32 @@
</view>
</view>
<!-- 占位 -->
<view class="color-333 item border-top u-flex u-row-center u-row-between" v-for="(item, index) in data" :key="index">
<view
class="color-333 item border-top u-flex u-row-center u-row-between"
v-for="(item, index) in data"
:key="index"
>
<view>
<view class="up-line-1">{{ item.name }}</view>
<view class="u-m-t-10 u-font-24 color-666 up-line-1">{{ item.specInfo || '' }}</view>
<view class="u-m-t-10 u-font-24 color-666 up-line-1">{{
item.specInfo || ""
}}</view>
</view>
<view class="u-flex" style="flex-shrink: 0">
<view class="font-bold red u-m-r-32">{{ formatPrice(item.lowPrice * item.number) }}</view>
<view class="font-bold red" v-if="item.is_time_discount"
>{{ returnLimitTotalPrice(item) }}
</view>
<view
class="font-bold red u-m-r-32"
:class="[item.is_time_discount ? 'old-price' : '']"
>{{ formatPrice(item.lowPrice * item.number) }}</view
>
<view class="u-flex" @tap="updateNumber(false, index, item)">
<image src="/pagesCreateOrder/static/images/icon-reduce-black.svg" class="icon" mode="" />
<image
src="/pagesCreateOrder/static/images/icon-reduce-black.svg"
class="icon"
mode=""
/>
</view>
<view class="u-m-l-30 u-m-r-30 color-333">
{{ item.number.toFixed(2) }}
@ -37,7 +69,11 @@
<image
src="/pagesCreateOrder/static/images/icon-add-black.svg"
class="icon"
:class="{ grayscale: item.type == 'package' && item.groupType == 1 }"
:class="[
item.type == 'package' && item.groupType == 1
? grayscale
: '',
]"
mode=""
/>
</view>
@ -47,24 +83,55 @@
<my-empty text="暂未有添加商品"></my-empty>
</view>
<!-- 历史订单 -->
<view v-if="historyOrder.length > 0" class="u-p-t-32 u-p-b-32 u-p-r-28 u-p-l-28 u-m-t-40 bg-fff u-flex u-row-between">
<view
v-if="historyOrder.length > 0"
class="u-p-t-32 u-p-b-32 u-p-r-28 u-p-l-28 u-m-t-40 bg-fff u-flex u-row-between"
>
<view class="color-333" style="font-weight: bold">历史订单</view>
<view class="color-666">
<uni-icons color="#666" type="trash"></uni-icons>
<text class="u-m-l-10" @tap="setModalShow('clear', true, 'allHistoryOrder', '清空历史订单')">清空历史订单</text>
<text
class="u-m-l-10"
@tap="
setModalShow('clear', true, 'allHistoryOrder', '清空历史订单')
"
>清空历史订单</text
>
</view>
</view>
<view v-for="(item, index) in historyOrder" :key="index">
<view v-if="historyOrder.length > 0" class="u-p-t-32 border-top bg-fff u-p-r-28 u-p-b-32 u-p-l-28 u-flex u-row-between">
<view class="color-333" style="font-size: 30rpx">{{ item.placeNum }}次下单</view>
<view
v-if="historyOrder.length > 0"
class="u-p-t-32 border-top bg-fff u-p-r-28 u-p-b-32 u-p-l-28 u-flex u-row-between"
>
<view class="color-333" style="font-size: 30rpx"
>{{ item.placeNum }}次下单</view
>
<view class="color-666">
<uni-icons color="#666" type="trash"></uni-icons>
<text class="u-m-l-10" @tap="setModalShow('clear', true, item.placeNum, '清空第' + item.placeNum + '次下单历史订单')">清空</text>
<text
class="u-m-l-10"
@tap="
setModalShow(
'clear',
true,
item.placeNum,
'清空第' + item.placeNum + '次下单历史订单'
)
"
>清空</text
>
</view>
</view>
<view class="color-333 item border-top u-flex u-row-center u-row-between" v-for="(v, i) in item.info" :key="i">
<view
class="color-333 item border-top u-flex u-row-center u-row-between"
v-for="(v, i) in item.info"
:key="i"
>
<view style="display: flex; align-items: center">
<view class="up-line-1" style="margin-right: 10rpx">{{ v.productName }}</view>
<view class="up-line-1" style="margin-right: 10rpx">{{
v.productName
}}</view>
<uni-tag
v-if="v.returnNum > 0"
:text="'退菜X' + v.returnNum"
@ -72,15 +139,22 @@
></uni-tag>
</view>
<view class="u-flex" style="flex-shrink: 0">
<view class="font-bold red u-m-r-32">{{ formatPrice(v.price * (v.num - v.returnNum)) }}</view>
<view class="u-m-l-30 u-m-r-30 color-333">X{{ v.num.toFixed(2) }}</view>
<view class="font-bold red u-m-r-32"
>{{ formatPrice(v.price * (v.num - v.returnNum)) }}</view
>
<view class="u-m-l-30 u-m-r-30 color-333"
>X{{ v.num.toFixed(2) }}</view
>
</view>
</view>
</view>
</scroll-view>
</view>
<view class="icon-car-box" @tap="toggleGoods">
<image src="/pagesCreateOrder/static/images/icon-car.svg" class="icon-car" />
<image
src="/pagesCreateOrder/static/images/icon-car.svg"
class="icon-car"
/>
<view class="dot" v-if="goodsNumber > 0">{{ goodsNumber }}</view>
</view>
<view class="price font-bold u-flex">
@ -88,7 +162,9 @@
<view>{{ allPrice }}</view>
</view>
<my-button shape="circle" height="80" width="220" @tap="toConfimOrder">
<text class="u-font-32 font-bold">{{ table.type == 'add' ? '确认加菜' : '去下单' }}</text>
<text class="u-font-32 font-bold">{{
table.type == "add" ? "确认加菜" : "去下单"
}}</text>
</my-button>
</view>
<up-modal
@ -106,59 +182,100 @@
</template>
<script setup>
import { computed, reactive, ref, watch } from 'vue';
import myButton from '@/components/my-components/my-button.vue';
import go from '@/commons/utils/go.js';
import infoBox from '@/commons/utils/infoBox.js';
import { formatPrice } from '@/commons/utils/format.js';
import { $trturnPayAfter } from '../util.js'
import { computed, reactive, ref, watch, inject } from "vue";
import myButton from "@/components/my-components/my-button.vue";
import go from "@/commons/utils/go.js";
import BigNumber from "bignumber.js";
import infoBox from "@/commons/utils/infoBox.js";
import { formatPrice } from "@/commons/utils/format.js";
import { $trturnPayAfter } from "../util.js";
const yskUtils = inject("yskUtils");
const shopInfo = uni.getStorageSync("shopInfo");
const props = defineProps({
data: {
type: Array,
default: () => {
return [];
}
},
},
historyOrder: {
type: Array,
default: () => {
return [];
}
},
},
isCreateOrderToDetail: {
type: Boolean,
default: false
default: false,
},
orderInfo: {
type: Object,
default: () => {
return {
id: ''
id: "",
};
}
},
},
table: {
type: Object,
default: () => {
return {
tableId: ''
tableId: "",
};
}
}
},
},
limitTimeDiscount: {
type: Object,
default: () => {
return {};
},
},
});
function returnLimitPrice(data) {
const price = yskUtils.limitUtils.returnPrice({
goods: data,
shopInfo: shopInfo,
limitTimeDiscountRes: props.limitTimeDiscount,
shopUserInfo: null,
idKey: "product_id",
});
return price;
}
function returnLimitTotalPrice(data) {
console.log('returnLimitTotalPrice',data)
const price = yskUtils.limitUtils.returnPrice({
goods: data,
shopInfo: shopInfo,
limitTimeDiscountRes: props.limitTimeDiscount,
shopUserInfo: null,
idKey: "product_id",
});
return BigNumber(price).times(data.number).toNumber();
}
let allHistoryOrder = ref([]);
const allPrice = computed(() => {
let cartPrice = props.data.reduce((prve, cur) => {
let price = Math.floor(cur.lowPrice * cur.number * 100) / 100;
return prve + price;
let price =
(cur.is_time_discount ? returnLimitPrice(cur) : cur.lowPrice) *
cur.number;
return BigNumber(prve).plus(price);
}, 0);
let historyOrderPrice = allHistoryOrder.value.reduce((prve, cur) => {
let price = Math.floor(cur.price * (cur.num - cur.returnNum) * 100) / 100;
return prve + price;
let price =
(cur.isTimeDiscount
? returnLimitPrice({ ...cur, salePrice: cur.price })
: cur.price) *
(cur.num - cur.returnNum);
return BigNumber(prve).plus(price);
}, 0);
return (cartPrice + historyOrderPrice).toFixed(2);
return BigNumber(cartPrice)
.plus(historyOrderPrice)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
});
const goodsNumber = computed(() => {
@ -184,19 +301,19 @@ watch(
}
);
const modal = reactive({
key: '',
title: '',
type: '',
clear: false
key: "",
title: "",
type: "",
clear: false,
});
function confirmModelConfirm() {
if (modal.key == 'clear') {
if (modal.key == "clear") {
clear();
}
}
function setModalShow(key = 'show', show = true, type = '', title = '') {
function setModalShow(key = "show", show = true, type = "", title = "") {
// if (key == 'clear' && show && props.data.length <= 0) {
// return infoBox.showToast('')
// }
@ -211,7 +328,7 @@ function setModalShow(key = 'show', show = true, type = '', title = '') {
console.log(modal);
}
const edmits = defineEmits(['clear', 'updateNumber']);
const edmits = defineEmits(["clear", "updateNumber"]);
// mask
let switchGoods = ref(false);
@ -230,56 +347,56 @@ function toggleGoods() {
function toConfimOrder() {
if (props.data.length <= 0 && allHistoryOrder.value.length <= 0) {
return infoBox.showToast('还没有选择商品');
return infoBox.showToast("还没有选择商品");
}
const { name, status, type } = props.table;
if (props.data.length <= 0 && allHistoryOrder.value.length > 0) {
go.to('PAGES_ORDER_PAY', {
orderId: props.orderInfo.id
go.to("PAGES_ORDER_PAY", {
orderId: props.orderInfo.id,
});
return;
}
if (props.table.id == '' && props.table.tableCode == '') {
go.to('PAGES_CONFIRM_ORDER', {
isCreateOrderToDetail: props.isCreateOrderToDetail ? 1 : 0
if (props.table.id == "" && props.table.tableCode == "") {
go.to("PAGES_CONFIRM_ORDER", {
isCreateOrderToDetail: props.isCreateOrderToDetail ? 1 : 0,
});
return;
}
let shopInfo = uni.getStorageSync('shopInfo');
let shopInfo = uni.getStorageSync("shopInfo");
console.log($trturnPayAfter(shopInfo));
go.to('PAGES_CONFIRM_ORDER', {
go.to("PAGES_CONFIRM_ORDER", {
type: type,
tableId: props.table.id,
tableCode: props.table.tableCode,
name: name,
status: status,
isCreateOrderToDetail: props.isCreateOrderToDetail ? 1 : 0
isCreateOrderToDetail: props.isCreateOrderToDetail ? 1 : 0,
});
}
function updateNumber(isAdd, index, goods) {
const step = isAdd ? 1 : -1;
const newval = goods.number + step;
if (goods.type == 'package' && goods.groupType == 1 && isAdd) {
if (goods.type == "package" && goods.groupType == 1 && isAdd) {
return;
}
const par = {
num: newval,
index: index,
goods: goods
goods: goods,
};
edmits('updateNumber', par);
edmits("updateNumber", par);
}
function clear() {
if (modal.type == 'cart') {
if (modal.type == "cart") {
hideGoods();
}
setModalShow('clear', false);
edmits('clear', modal.type);
setModalShow("clear", false);
edmits("clear", modal.type);
}
</script>
@ -388,4 +505,8 @@ $car-top: -16rpx;
height: $car-size;
}
}
.old-price {
color: #999;
text-decoration: line-through;
}
</style>

View File

@ -1,15 +1,23 @@
<template>
<my-model ref="model" borderRadius="12" :title="title">
<template #desc>
<scroll-view scroll-y="true" style="height: 50vh;" class="u-p-30 guigeModel">
<scroll-view
scroll-y="true"
style="height: 50vh"
class="u-p-30 guigeModel"
>
<view class="u-m-b-40" v-for="(item, index) in skus" :key="index">
<view class="u-text-left">
<view class="color-333 up-line-1">{{ item.name }}</view>
</view>
<view class="u-flex u-m-t-20 u-flex-wrap">
<view class="item" @tap="chooseSkd(index,skd)"
<view
class="item"
@tap="chooseSkd(index, skd)"
:class="{ active: item.sel === skd.name, disabled: skd.disabled }"
v-for="(skd,skdIndex) in item.values" :key="skdIndex">
v-for="(skd, skdIndex) in item.values"
:key="skdIndex"
>
{{ skd.name }}
</view>
</view>
@ -21,20 +29,32 @@
<view class="u-flex u-p-b-30 u-row-between">
<view class="price">
<template v-if="goods && goods.isGrounding">
<text></text>
<text>{{to2(goods.salePrice*number) }}</text>
<text v-if="is_time_discount"
>{{ returnLimitPrice() }}</text
>
<text :class="{ oldPrice: is_time_discount }"
>{{ goods.salePrice }}</text
>
</template>
</view>
<view class="u-flex">
<view class="u-flex" @tap="reduce">
<image src="/pagesCreateOrder/static/images/icon-reduce-black.svg" class="icon" mode="">
<image
src="/pagesCreateOrder/static/images/icon-reduce-black.svg"
class="icon"
mode=""
>
</image>
</view>
<view class="u-m-l-30 u-m-r-30 color-333">
{{ number }}
</view>
<view class="u-flex" @tap="add">
<image src="/pagesCreateOrder/static/images/icon-add-black.svg" class="icon" mode="">
<image
src="/pagesCreateOrder/static/images/icon-add-black.svg"
class="icon"
mode=""
>
</image>
</view>
</view>
@ -51,74 +71,87 @@
</template>
<script setup>
import { computed, reactive, ref, watch } from 'vue';
import util from '../util.js';
import infobox from '@/commons/utils/infoBox.js'
import myModel from '@/components/my-components/my-model.vue'
import myButton from '@/components/my-components/my-button.vue'
import { computed, reactive, ref, watch,inject } from "vue";
import util from "../util.js";
import infobox from "@/commons/utils/infoBox.js";
import myModel from "@/components/my-components/my-model.vue";
import myButton from "@/components/my-components/my-button.vue";
import BigNumber from "bignumber.js";
const yskUtils = inject("yskUtils");
const shopInfo = uni.getStorageSync("shopInfo");
const shopUserInfo = uni.getStorageSync("shopUserInfo");
const props = defineProps({
goodsData: {
type: Object,
default: () => {}
default: () => {},
},
title: {
type: String,
default: ''
default: "",
},
skuMap: {
type: Object,
default: () => {
return {}
}
return {};
},
},
skus: {
type: Array,
default: () => {
return []
}
return [];
},
})
const emits = defineEmits(['confirm', 'updateSku'])
const model = ref(null)
let number = ref(1)
},
limitTimeDiscount: {
type: Object,
default: () => {
return {};
},
},
});
const emits = defineEmits(["confirm", "updateSku"]);
const model = ref(null);
let number = ref(1);
function to2(number) {
return Number(number).toFixed(2)
return Number(number).toFixed(2);
}
const selSku = computed(() => {
return props.skus.reduce((prve, cur) => {
prve.push(cur.sel)
return prve
}, []).join()
})
return props.skus
.reduce((prve, cur) => {
prve.push(cur.sel);
return prve;
}, [])
.join();
});
const goods = computed(() => {
return props.skuMap[selSku.value]
})
watch(() => goods.value, (newval) => {
number.value = newval.suitNum || 1
})
return props.skuMap[selSku.value];
});
watch(
() => goods.value,
(newval) => {
number.value = newval.suitNum || 1;
}
);
const isCanBuy = computed(() => {
if (!goods.value) {
return false
return false;
}
return util.isCanBuy(
goods.value,
props.goodsData
)
})
return util.isCanBuy(goods.value, props.goodsData);
});
/**
* 全部规格是否都无法使用
*/
const isAllDisabled = computed(() => {
return props.skus.reduce((prve, cur) => {
return prve && cur.values.filter(v => v.disabled).length === cur.values.length
}, true)
})
return (
prve && cur.values.filter((v) => v.disabled).length === cur.values.length
);
}, true);
});
/**
* 规格选择
@ -126,12 +159,12 @@
* @param {Object} skd
*/
function chooseSkd(skusIndex, skd) {
const { name, disabled } = skd
const { name, disabled } = skd;
if (disabled) {
return
return;
}
if (props.skus[skusIndex].sel != name) {
emits('updateSku', skusIndex, name)
emits("updateSku", skusIndex, name);
}
}
@ -139,22 +172,22 @@
* 禁止操作
*/
const isDisabled = computed(() => {
return isAllDisabled.value || !isCanBuy.value
})
return isAllDisabled.value || !isCanBuy.value;
});
/**
* 数量减少
*/
function reduce() {
if (isDisabled.value) {
return
return;
}
const suitNum = goods.value.suitNum || 1
const newval = number.value - 1
const suitNum = goods.value.suitNum || 1;
const newval = number.value - 1;
if (newval < suitNum) {
return infobox.showToast(suitNum + '个起售')
return infobox.showToast(suitNum + "个起售");
}
number.value = newval <= 1 ? 1 : newval
number.value = newval <= 1 ? 1 : newval;
}
/**
@ -162,38 +195,68 @@
*/
function add() {
if (isDisabled.value) {
return
return;
}
number.value = number.value + 1
number.value = number.value + 1;
}
/**
* 都规格选择确认
*/
function confirm() {
close()
close();
if (isDisabled.value) {
return
return;
}
emits('confirm', goods.value, number.value)
emits("confirm", goods.value, number.value,is_time_discount.value?1:0);
}
function open() {
model.value.open()
model.value.open();
}
function close() {
model.value.close()
model.value.close();
}
const is_time_discount = computed(() => {
if (!props.limitTimeDiscount || !props.limitTimeDiscount.id) {
return false;
}
const isCanuse = yskUtils.limitUtils.canUseLimitTimeDiscount(
goods.value,
props.limitTimeDiscount,
shopInfo,
shopUserInfo,
"productId"
);
console.log('isCanuse');
console.log( goods.value);
return isCanuse;
});
function returnLimitPrice() {
const price = yskUtils.limitUtils.returnPrice({
goods: goods.value,
shopInfo: shopInfo,
limitTimeDiscountRes: props.limitTimeDiscount,
shopUserInfo: shopUserInfo,
idKey: "productId",
});
return BigNumber(price).times(number.value).toNumber();
}
defineExpose({
open,
close
})
close,
});
</script>
<style lang="scss">
.border-top {}
.border-top {
}
.icon {
width: 40rpx;
@ -205,11 +268,11 @@
color: #666;
font-size: 24rpx;
padding: 4rpx 28rpx;
border: 1px solid #E5E5E5;
border: 1px solid #e5e5e5;
border-radius: 8rpx;
margin-right: 20rpx;
margin-bottom: 20rpx;
transition: all .2s ease-in-out;
transition: all 0.2s ease-in-out;
&.active {
border-color: $my-main-color;
@ -224,10 +287,13 @@
}
.price {
color: #EB4F4F;
color: #eb4f4f;
}
.oldPrice {
color: #999;
text-decoration: line-through;
}
.border-top {
border-top: 1px solid #E5E5E5;
border-top: 1px solid #e5e5e5;
}
</style>

View File

@ -1,55 +1,106 @@
<template>
<view class="u-relative u-flex item">
<up-image :src="data.coverImg" mode="aspectFill" :width="img.width" :height="img.height"></up-image>
<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>
<view>
<text class="up-line-1">{{ data.name }}</text>
</view>
<view class="u-font-32 font-bold u-m-t-16">
<view>
<text class="u-font-32 font-bold u-m-t-16" v-if="is_time_discount"> {{ limitPrice }} </text>
<text
class="u-font-32 font-bold u-m-t-16"
:class="[is_time_discount ? 'line-through' : '']"
>
{{ data.lowPrice }}
</text>
</view>
<template v-if="data.type == 'weight'">
<view class="btnweigh">称重</view>
</template>
</view>
<view class="u-flex" v-if="!isSellout">
<template v-if="data.type == 'sku' || data.groupType == 1">
<button class="btn" hover-class="btn-hover-class" @tap="emitEvent('chooseGuige')">选规格</button>
<button
class="btn"
hover-class="btn-hover-class"
@tap="emitEvent('chooseGuige')"
>
选规格
</button>
</template>
<template v-else>
<view class="u-flex icon-btn">
<view class="u-flex" @tap.stop="emitEvent(data.type=='weight'?'tapweigh':'add')">
<image src="/pagesCreateOrder/static/images/icon-add.svg" class="icon" mode=""></image>
<view
class="u-flex"
@tap.stop="emitEvent(data.type == 'weight' ? 'tapweigh' : 'add')"
>
<image
src="/pagesCreateOrder/static/images/icon-add.svg"
class="icon"
mode=""
></image>
</view>
<template v-if="data.chooseNumber">
<view class="u-font-32">
{{(data.chooseNumber).toFixed(2)}}
{{ data.chooseNumber.toFixed(2) }}
</view>
<view class="u-flex" @tap.stop="emitEvent('reduce')">
<image src="/pagesCreateOrder/static/images/icon-reduce.svg" class="icon" mode="">
<image
src="/pagesCreateOrder/static/images/icon-reduce.svg"
class="icon"
mode=""
>
</image>
</view>
</template>
</view>
</template>
</view>
<template v-if="isSellout">
<view class="isSellout" v-if="data.isSale == 0">
<image class="isSellout_icon" src="/pagesCreateOrder/static/images/no-toDown.svg" mode=""></image>
<image
class="isSellout_icon"
src="/pagesCreateOrder/static/images/no-toDown.svg"
mode=""
></image>
</view>
<view class="isSellout" v-else-if="!isProductAvailable(data.days,data.startTime,data.endTime)" >
<image class="isSellout_icon" src="/pagesCreateOrder/static/images/no-saleTime.svg" mode=""></image>
<view
class="isSellout"
v-else-if="
!isProductAvailable(data.days, data.startTime, data.endTime)
"
>
<image
class="isSellout_icon"
src="/pagesCreateOrder/static/images/no-saleTime.svg"
mode=""
></image>
</view>
<view class="isSellout" v-else-if="data.isSoldStock == 1">
<image class="isSellout_icon" src="/pagesCreateOrder/static/images/no-sold.svg" mode=""></image>
<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" >
<image class="isSellout_icon" src="/pagesCreateOrder/static/images/no-stock.svg" mode=""></image>
<view
class="isSellout"
v-else-if="data.isStock == 1 && data.stockNumber <= 0"
>
<image
class="isSellout_icon"
src="/pagesCreateOrder/static/images/no-stock.svg"
mode=""
></image>
</view>
</template>
</view>
@ -57,19 +108,21 @@
</template>
<script setup>
import { computed, toRef } from 'vue';
import util from '../util.js';
import { computed, toRef, inject } from "vue";
import util from "../util.js";
import dayjs from "dayjs";
import isBetween from "dayjs/plugin/isBetween.js";
dayjs.extend(isBetween)
const yskUtils = inject("yskUtils");
const shopInfo = inject("shopInfo");
dayjs.extend(isBetween);
const props = defineProps({
img: {
type: Object,
default: {
width: '250rpx',
height: '272rpx'
}
width: "250rpx",
height: "272rpx",
},
},
index: {
type: [Number, String],
@ -77,76 +130,117 @@
isSeatFee: {
//
type: Boolean,
default: false
default: false,
},
data: {
type: Object,
default: () => {
return {
chooseNumber: 0
chooseNumber: 0,
};
},
},
limitTimeDiscount: {
type: Object,
default: () => {
return {};
},
},
});
//
const is_time_discount = computed(() => {
if (!props.limitTimeDiscount || !props.limitTimeDiscount.id) {
return false;
}
const isCanuse = yskUtils.limitUtils.canUseLimitTimeDiscount(
props.data,
props.limitTimeDiscount,
shopInfo,
null,
"id"
);
return isCanuse;
});
const limitPrice = computed(() => {
if (!is_time_discount.value) {
return 0;
}
}
})
console.log("props.data", props.data);
const price = yskUtils.limitUtils.returnPrice({
goods: props.data,
shopInfo: shopInfo,
limitTimeDiscountRes: props.limitTimeDiscount,
shopUserInfo: null,
idKey: "id",
});
return price;
});
/**
* 判断是否是菜品
*/
function isGoods() {
return props.data.hasOwnProperty('id')
return props.data.hasOwnProperty("id");
}
/**
* 判断商品是否售尽
*/
const isSellout = computed(() => {
const item = props.data
const item = props.data;
if (!isGoods()) {
return false
return false;
}
return (
(item.isStock == 1 && item.stockNumber <= 0) || item.isSoldStock == 1 || item.isSale == 0 || !isProductAvailable(item.days,item.startTime,item.endTime)
(item.isStock == 1 && item.stockNumber <= 0) ||
item.isSoldStock == 1 ||
item.isSale == 0 ||
!isProductAvailable(item.days, item.startTime, item.endTime)
);
})
});
//
function isProductAvailable(sellDaysStr, startTimeStr, endTimeStr) {
//
const sellDays = sellDaysStr.split(',');
    const now = dayjs();
    const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const sellDays = sellDaysStr.split(",");
const now = dayjs();
const days = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
const currentDay = days[now.day()];
    const currentTime = now.format('HH:mm:ss');
const currentTime = now.format("HH:mm:ss"); //
// console.log(':', currentDay);
// console.log(':', sellDays);
    //
    if (!sellDays.includes(currentDay)) {
        // console.log('');
        return false;
    }
    const startTime = dayjs(`${now.format('YYYY-MM-DD')} ${startTimeStr}`);
    let endTime = dayjs(`${now.format('YYYY-MM-DD')} ${endTimeStr}`);
if (!sellDays.includes(currentDay)) {
// console.log('');
return false;
}
const startTime = dayjs(`${now.format("YYYY-MM-DD")} ${startTimeStr}`);
let endTime = dayjs(`${now.format("YYYY-MM-DD")} ${endTimeStr}`);
//
    if (endTime.isBefore(startTime)) {
        endTime = endTime.add(1, 'day');
    }
if (endTime.isBefore(startTime)) {
endTime = endTime.add(1, "day");
} // console.log('开始时间:', startTime.format('YYYY-MM-DD HH:mm:ss')); // console.log('结束时间:', endTime.format('YYYY-MM-DD HH:mm:ss'));
// console.log(':', now.format('YYYY-MM-DD HH:mm:ss'));
    // console.log(':', startTime.format('YYYY-MM-DD HH:mm:ss'));
    // console.log(':', endTime.format('YYYY-MM-DD HH:mm:ss'));
    const isInRange = now.isBetween(startTime, endTime, null, '[)');
    // console.log(':', isInRange);
    return isInRange;
const isInRange = now.isBetween(startTime, endTime, null, "[)"); // console.log(':', isInRange);
return isInRange;
}
const emits = defineEmits(['add', 'reduce', 'chooseGuige','tapweigh'])
const emits = defineEmits(["add", "reduce", "chooseGuige", "tapweigh"]);
function emitEvent(emitName) {
if (isGoods()) {
emits(emitName, props.index)
emits(emitName, props.index);
}
}
</script>
@ -162,7 +256,7 @@
}
.btn {
background: #EB4F4F;
background: #eb4f4f;
border-radius: 100rpx;
font-size: 28rpx;
height: 56rpx;
@ -181,17 +275,17 @@
}
.btn-hover-class {
opacity: .6;
opacity: 0.6;
}
image {
will-change: transform
will-change: transform;
}
.item {
// width: 250rpx;
// height: 272rpx;
background: #F9B798;
background: #f9b798;
border-radius: 8rpx 8rpx 8rpx 8rpx;
overflow: hidden;
@ -206,7 +300,7 @@
right: 0;
bottom: 0;
color: #fff;
padding: 32rpx 24rpx 24rpx 24rpx;
padding: 52rpx 24rpx 24rpx 24rpx;
top: 0;
background: rgba(37, 22, 15, 0.5);
border-radius: 8rpx 8rpx 8rpx 8rpx;
@ -229,4 +323,23 @@
width: 60%;
}
}
.limit-discount {
background-color: #cc5617;
padding: 10rpx 20rpx;
white-space: nowrap;
text-align: center;
position: absolute;
top: 0;
left: 0;
font-weight: 400;
font-size: 24rpx;
color: #ffffff;
border-radius: 0 0rpx 20rpx 0rpx;
color: #fff;
}
.line-through{
font-size: 24rpx;
color: rgba(255, 255, 255, 0.8);
text-decoration: line-through;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,8 @@ export function getNowCart(carItem,goodsList,user) {
// console.log("carItem===",carItem)
// console.log("goodsList===",goodsList)
// const nowCart = records.find(v => v.placeNum == 0)
console.log("carItem===",carItem)
const arr = []
if( carItem.is_temporary != 1 ){
carItem.isGrounding = false;
@ -13,8 +15,9 @@ export function getNowCart(carItem,goodsList,user) {
if(carItem.sku_id == item.id){
carItem.lowPrice = item.salePrice
carItem.lowMemberPrice = item.memberPrice
carItem.memberPrice = item.memberPrice
carItem.specInfo = item.specInfo
carItem.suitNum = item.suitNum
carItem.salePrice = item.salePrice
if( uni.getStorageSync('shopInfo').isMemberPrice && user && user.id && user.isVip ){
carItem.salePrice = item.memberPrice
@ -38,8 +41,10 @@ export function getNowCart(carItem,goodsList,user) {
carItem.number = parseFloat(carItem.number)
carItem.name = carItem.product_name
carItem.lowPrice = carItem.discount_sale_amount
carItem.discount_sale_amount = 0
}
carItem.discount_sale_amount = carItem.discount_sale_amount?carItem.discount_sale_amount*1:0
carItem.discountSaleAmount = carItem.discount_sale_amount
// carItem.discount_sale_amount = 0
}
return carItem
}

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +1,41 @@
<template>
<view class="u-p-l-30 u-p-r-30 u-p-t-30 u-font-28">
<up-sticky offset-top="0">
<my-tabs v-model="pageData.types.sel" @change="tabChange" :list="pageData.types.list"></my-tabs>
<my-tabs v-model="myQuan.types.sel" :list="myQuan.types.list"></my-tabs>
</up-sticky>
<view class="u-m-t-32">
<template v-if="pageData.types.sel==0">
<view class="" @click="changeFullReductionCouponSel(item)"
v-for="(item,index) in pageData.fullReductionCoupon" :class="{filtergray:!item.use}" :key="index">
<view class="quan u-row-between u-flex u-col-center u-m-b-32 border-r-10 ">
<view
class=""
@click="changeSelCoupon(item)"
v-for="(item, index) in list.canUseCoupons"
:class="{ filtergray: !item.use }"
:key="index"
>
<view
class="quan u-row-between u-flex u-col-center u-m-b-32 border-r-10"
>
<view class="no-use" v-if="!item.use">
<image class="img" src="/pagesOrder/static/image/no-use.svg" mode=""></image>
<image
class="img"
src="/pagesOrder/static/image/no-use.svg"
mode=""
></image>
</view>
<view class="sel u-abso" v-if="item.id == pageData.fullReductionCouponSel.id ">
<view class="sel u-abso" v-if="isActive(item)">
<up-icon name="checkbox-mark" color="#fff"></up-icon>
</view>
<view class="u-p-t-32 u-p-b-32 u-p-l-24 u-p-r-24 left">
<view class="u-flex">
<view class="u-flex" v-if="item.type != 2">
<view class="hui"></view>
<view class="u-m-l-18">{{ item.name }}</view>
</view>
<view v-else>{{ item.name }}</view>
<view class="u-m-t-20 u-flex">
<view>有效期:</view>
<view class="u-font-24 u-m-l-6"> {{dayjs(item.endTime).format('YYYY-MM-DD HH:mm:ss') }}
<view class="u-font-24 u-m-l-6">
{{ dayjs(item.effectStartTime).format("YYYY-MM-DD HH:mm:ss") }}
-
{{ dayjs(item.effectEndTime).format("YYYY-MM-DD HH:mm:ss") }}
</view>
</view>
<view class="u-m-t-10 color-999 u-font-24">
@ -29,67 +43,86 @@
</view>
</view>
<view class="right u-flex u-flex-col u-row-between">
<view class="u-flex u-row-center u-font-36 ">
<view class="u-flex u-row-center u-font-36" v-if="item.type != 2">
{{ item.discountAmount }}
</view>
<view class="u-flex u-font-24">
{{item.fullAmount}}可用
</view>
<view class="u-flex u-font-24"> {{ item.fullAmount }}可用 </view>
<view class="u-flex">
<view class="use-btn" @click.stop="toEmitChooseQuan(item)">去使用</view>
<!-- <view class="use-btn" @click.stop="toEmitChooseQuan(item)"
>去使用</view
> -->
</view>
</view>
</view>
</view>
<template v-if="pageData.fullReductionCoupon.length <= 0 && pageData.hasAjax">
<template v-if="list.canUseCoupons.length <= 0 && myQuan.hasAjax">
<my-img-empty tips="暂无可用优惠券"></my-img-empty>
</template>
</template>
<template v-if="pageData.types.sel==1">
<view class="" @click="changeProductCoupon(item)" v-for="(item,index) in pageData.productCoupon"
:class="{filtergray:!item.use}" :key="index">
<view class="quan goods u-row-between u-flex u-col-center u-m-b-32 border-r-10 u-relative">
<view class="no-use" v-if="!item.use">
<image class="img" src="/pagesOrder/static/image/no-use.svg" mode=""></image>
<view style="height: 40rpx"></view>
<view
v-for="(item, index) in list.noCanUseCoupons"
class="filtergray"
:key="index"
>
<view
class="quan u-row-between u-flex u-col-center u-m-b-32 border-r-10"
>
<view class="no-use">
<image
class="img"
src="/pagesOrder/static/image/no-use.svg"
mode=""
></image>
</view>
<view class="sel u-abso" v-if="item.checked">
<view class="sel u-abso" v-if="isActive(item)">
<up-icon name="checkbox-mark" color="#fff"></up-icon>
</view>
<view class="u-p-t-32 u-p-b-32 u-p-l-24 u-p-r-24">
<view class="u-p-t-32 u-p-b-32 u-p-l-24 u-p-r-24 left">
<view class="u-flex" v-if="item.type != 2">
<view class="hui"></view>
<view class="u-m-l-18">{{ item.name }}</view>
</view>
<template v-else>
<view class="u-flex">
<up-image width="80rpx" height="80rpx" :src="item.productCover"></up-image>
<view class="u-m-l-18">
<view class="u-m-l-18">{{item.name}}{{item.productName?' | '+item.productName : ''}}</view>
<!-- <view class="u-m-l-18 u-m-t-10 u-font-24 color-666">x{{item.num}}</view> -->
{{ item.foods }}
</view>
<view class="u-flex">
{{ item.name }}
</view>
<view class=" u-m-t-14 u-flex">
</template>
<view class="u-m-t-20 u-flex">
<view>有效期:</view>
<view class="u-font-24 u-m-l-6"> {{dayjs(item.endTime).format('YYYY-MM-DD HH:mm:ss') }}
<view class="u-font-24 u-m-l-6">
{{ dayjs(item.effectStartTime).format("YYYY-MM-DD HH:mm:ss") }}
-
{{ dayjs(item.effectEndTime).format("YYYY-MM-DD HH:mm:ss") }}
</view>
</view>
<view class="u-m-t-10 color-999 u-font-24">
{{ item.useRestrictions }}
{{ formatStr(item.useRestrictions) }}
</view>
<view class="u-m-t-10 color-999 u-font-24">
{{ returnNoUseRestrictions(item) }}
</view>
</view>
<view class="right u-flex u-flex-col u-col-bottom u-row-center" style="flex-shrink: 1;">
<view class="use-btn" @click.stop="toEmitChooseQuan(item)" style="flex-shrink: 1;">去使用</view>
<view class="right u-flex u-flex-col u-row-between">
<view class="u-flex u-row-center u-font-36" v-if="item.type != 2">
{{ item.discountAmount }}
</view>
<view class="u-flex u-font-24"> {{ item.fullAmount }}可用 </view>
<view class="u-flex">
<!-- <view class="use-btn" @click.stop="toEmitChooseQuan(item)"
>去使用</view
> -->
</view>
</view>
</view>
</view>
<template v-if="pageData.productCoupon.length <= 0 && pageData.hasAjax">
<my-img-empty tips="暂无可用优惠券"></my-img-empty>
</template>
</template>
</view>
<view :style="{ height: safebottomHeight + 'px' }"></view>
<view class="fixed-b bottom safe-bottom border-top">
<view class="u-m-b-32 u-flex u-row-between u-p-t-10">
<view class="u-flex">
<text>抵扣金额</text>
@ -100,8 +133,11 @@
<text>支付金额</text>
<text class="color-red"></text>
<text class="color-red">{{ payPrice }}</text>
<view class="u-absolute u-flex u-row-between" style="bottom: 100%;right: 0;"
v-if="payPrice*1!=option.orderPrice*1">
<view
class="u-absolute u-flex u-row-between"
style="bottom: 100%; right: 0"
v-if="payPrice * 1 != option.orderPrice * 1"
>
<view class="u-flex line-th color-999">
<text class=""></text>
<text class="">{{ option.orderPrice }}</text>
@ -117,289 +153,456 @@
<view class="font-bold">确定</view>
</up-button>
</view>
</view>
<up-modal :title="modal.title" :content="modal.content" :show="modal.clear" :confirmText="modal.confirmText"
:cancelText="modal.cancelText" showCancelButton closeOnClickOverlay @confirm="confirmModelConfirm"
@cancel="confirmModelCancel" @close="setModalShow('clear',false)" width="300px" />
<up-modal
:title="modal.title"
:content="modal.content"
:show="modal.clear"
:confirmText="modal.confirmText"
:cancelText="modal.cancelText"
showCancelButton
closeOnClickOverlay
@confirm="confirmModelConfirm"
@cancel="confirmModelCancel"
@close="setModalShow('clear', false)"
width="300px"
/>
</view>
</template>
<script setup>
import { onLoad, onReady } from '@dcloudio/uni-app'
import { ref, reactive, watch, computed, onMounted } from 'vue';
import dayjs from 'dayjs';
import { getSafeBottomHeight } from '@/commons/utils/safe-bottom.js'
import go from '@/commons/utils/go.js'
import infoBox from '@/commons/utils/infoBox.js'
import {
returnNewGoodsList,
returnCoupCanUse,
returnCouponAllPrice,
returnProductCoupon,
returnCanUseFullReductionCoupon,
returnProductAllCoup
} from '../quan_util.js'
import { getHistoryOrder } from '@/http/api/order.js'
import { shopUserDetail } from '@/http/api/shopUser.js'
import { getFindCoupon } from '@/http/api/coupon.js'
import { ref, reactive, watch, computed, onMounted, toRaw } from "vue";
import dayjs from "dayjs";
import { getSafeBottomHeight } from "@/commons/utils/safe-bottom.js";
import go from "@/commons/utils/go.js";
import { onLoad, onReady } from "@dcloudio/uni-app";
import * as orderApi from "@/http/yskApi/order.js";
import { $findCoupon } from "@/http/yskApi/Instead.js";
import infoBox from "@/commons/utils/infoBox.js";
import { queryAllShopUser, shopUserDetail } from "@/http/yskApi/shop-user.js";
// import {
// returnNewGoodsList,
// returnCoupCanUse,
// returnCouponAllPrice,
// returnProductCoupon,
// returnCanUseFullReductionCoupon,
// } from "../quan_util.js";
// const yskUtils = {
// couponUtils,
// };
import yskUtils from "ysk-utils";
// import {couponUtils} from "@/lib/index";
// const yskUtils={
// couponUtils
// }
const modal = reactive({
title: '提示',
cancelText: '取消',
confirmText: '确定',
content: '',
key: '',
title: "提示",
cancelText: "取消",
confirmText: "确定",
content: "",
key: "",
clear: false,
data: ''
})
const option = reactive({
orderId: '',
shopUserId: '',
orderPrice: 0
})
const pageData = reactive({
order: null,
user: null,
types: {
list: ['满减券(单选)', '商品券(多选)'],
sel: 0
},
fullReductionCouponSel: {
id: ''
},
fullReductionCoupon: [],
productCoupon: [],
hasAjax: false
})
let canDikouGoodsArr = []
let safebottomHeight = ref(0)
onLoad((opt) => {
Object.assign(option, opt)
getQuan()
})
watch(() => pageData.types.sel, (newval) => {
if (newval == 0) {
pageData.fullReductionCoupon = returnCanUseFullReductionCoupon(pageData.fullReductionCoupon, payPrice.value,
pageData.fullReductionCouponSel)
}
if (newval == 1) {
}
})
onReady(() => {
getSafeBottomHeight('bottom', 0).then(height => {
safebottomHeight.value = height
})
})
function tabChange () {
getQuan()
}
/**
* 抵扣金额
*/
const discountAmount = computed(() => {
const goodsQuan = pageData.productCoupon.filter(v => v.checked)
const fullReductionCoupon = pageData.fullReductionCouponSel.id ? [pageData.fullReductionCouponSel] : []
let coupArr = [...fullReductionCoupon, ...goodsQuan]
return returnCouponAllPrice(coupArr, canDikouGoodsArr, pageData.user)
})
const payPrice = computed(() => {
const pay = option.orderPrice - discountAmount.value
return (pay < 0 ? 0 : pay).toFixed(2)
})
/**
* 获取优惠券
*/
async function getQuan() {
shopUserDetail({ id: option.shopUserId }).then(res=>{
pageData.user = res
})
pageData.order = await getHistoryOrder({orderId:option.orderId})
const res = await getFindCoupon({
shopUserId: option.shopUserId,
type: pageData.types.sel+1
})
let fullReductionCoupon = res ? res.filter(v => v.type == 1) : []
let productCoupon = res ? res.filter(v => v.type == 2) : []
canDikouGoodsArr = returnNewGoodsList(pageData.order.detailMap || [])
fullReductionCoupon = fullReductionCoupon.map((v) => {
if(option.orderPrice<=0){
return {...v,use:false}
}else{
return{
...v,
use:v.use && option.orderPrice * 1 >= v
.fullAmount * 1
}
}
})
productCoupon = productCoupon.map(v => {
const calcCoup = returnProductCoupon(v, pageData.order.detailMap, pageData.user)
return {
...calcCoup,
checked: false,
use: option.orderPrice<=0?false:v.use
}
})
// .filter((v) => v.use);
pageData.fullReductionCoupon = fullReductionCoupon
pageData.productCoupon = productCoupon
pageData.hasAjax = true;
}
data: "",
});
function confirmModelCancel() {
setModalShow('clear', false, '')
setModalShow("clear", false, "");
}
/**
* 继续选择
*/
async function confirmModelConfirm() {
if (modal.key == 'clear') {
if( modal.data ){
pageData.fullReductionCouponSel = {
id: ''
}
const item = modal.data
item.checked = !item.checked
const CheckedArr = pageData.productCoupon.filter(v => v.checked)
const noCheckedArr = pageData.productCoupon.filter(v => !v.checked)
noCheckedArr.map(v => {
v.use = returnCoupCanUse(canDikouGoodsArr, v, CheckedArr)
})
}
setModalShow('clear', false, '')
if (modal.key == "clear") {
myQuan.fullReductionCouponSel = {
id: "",
};
const item = modal.data;
item.checked = !item.checked;
const CheckedArr = myQuan.res.productCoupon.filter((v) => v.checked);
const noCheckedArr = myQuan.res.productCoupon.filter((v) => !v.checked);
noCheckedArr.map((v) => {
console.log(returnCoupCanUse(canDikouGoodsArr, v, CheckedArr));
v.use = returnCoupCanUse(canDikouGoodsArr, v, CheckedArr);
});
setModalShow("clear", false, "");
}
}
function setModalShow(key = 'show', show = true, data) {
modal.key = key
modal[key] = show
modal.data = data
function setModalShow(key = "show", show = true, data) {
modal.key = key;
modal[key] = show;
modal.data = data;
}
function back() {
uni.navigateBack()
uni.navigateBack();
}
let order = ref({});
let canDikouGoodsArr = [];
const myQuan = reactive({
fullReductionCouponSel: {
id: "",
},
res: {
fullReductionCoupon: [],
productCoupon: [],
},
types: {
list: ["优惠券(单选)", "商品券(单选)"],
sel: 0,
},
list: [],
sel: -1,
hasAjax: false,
});
/**
* 商品券选择
* @param {Object} item
*/
function changeProductCoupon(item) {
if (!item.use) { return }
if ( payPrice.value <= 0 ) {
modal.content = '当前支付金额不满足选择商品券的最低使用需求,无法选择'
modal.cancelText = '取消'
modal.confirmText = '确定'
setModalShow('clear', true)
return
}
if (!item.checked) {
const goodsQuan = pageData.productCoupon.filter(v => v.checked)
let coupArr = [...goodsQuan, item]
const payPrice = option.orderPrice - returnCouponAllPrice(coupArr, canDikouGoodsArr, pageData.user)
if (payPrice<=0) {
modal.content = '选择该商品券后支付金额将为0继续选择将取消选择的满减券'
modal.cancelText = '取消'
modal.confirmText = '继续选择'
setModalShow('clear', true, item)
return
}
if (pageData.fullReductionCouponSel.fullAmount > payPrice) {
modal.content = '选择该商品券后将不满足选择抵扣券的最低满减需求,继续选择将取消选择的满减券'
modal.cancelText = '取消'
modal.confirmText = '继续选择'
setModalShow('clear', true, item)
return
}
}
item.checked = !item.checked
const CheckedArr = pageData.productCoupon.filter(v => v.checked)
if (CheckedArr.length <= 0) {
return pageData.productCoupon.map(v => {
v.use = true
})
}
const noCheckedArr = pageData.productCoupon.filter(v => !v.checked)
noCheckedArr.map(v => {
v.use = returnCoupCanUse(canDikouGoodsArr, v, CheckedArr)
})
}
/**
* 优惠券选择
* @param {Object} item
*/
function changeFullReductionCouponSel(item) {
if (!item.use) {
return
}
if (item.id == pageData.fullReductionCouponSel.id) {
pageData.fullReductionCouponSel = {
id: ''
function changeSelCoupon(item) {
if (myQuan.types.sel == 0) {
if (couponSel.value.id == item.id) {
couponSel.value = {
id: "",
};
} else {
couponSel.value = item;
}
} else {
pageData.fullReductionCouponSel = item
if (goodsCouponSel.value.id == item.id) {
goodsCouponSel.value = {
id: "",
};
} else {
goodsCouponSel.value = item;
}
}
pageData.fullReductionCoupon = returnCanUseFullReductionCoupon(pageData.fullReductionCoupon, payPrice.value, pageData
.fullReductionCouponSel)
}
function formatStr(str) {
// return str.replaceAll('"', '')
console.log(str);
if (!str) {
return "";
}
const reg = /^[,]+|[,]+$/g;
return `${str}`.replace(reg, "");
}
/**
* 优惠券选择确认
* @param {Object} item
*/
function toEmitChooseQuan(item) {
let arr = []
let discountAmount = 0;
if (item) {
arr = [item]
function isActive(item) {
if (myQuan.types.sel == 0) {
return couponSel.value.id == item.id;
} else {
if (pageData.fullReductionCouponSel.id) {
arr.push(pageData.fullReductionCouponSel)
return goodsCouponSel.value.id == item.id;
}
let goodsQuan = pageData.productCoupon.filter(v => v.checked)
arr.push(...goodsQuan)
}
arr.map(item=>{
discountAmount += item.discountAmount
})
if( discountAmount > option.orderPrice){
}
console.log(arr)
uni.$emit('choose-quan', arr)
back()
}
const shopUserInfo = ref(null);
//
function returnAllGoodsList() {
let goodsArr = [];
for (let key in order.value.detailMap) {
console.log(order.value.detailMap[key]);
for (let goods of order.value.detailMap[key]) {
goods.salePrice = goods.salePrice || goods.price;
goods.number = goods.num || 0;
goodsArr.push(toRaw(goods));
}
}
return goodsArr;
}
//
function returnNoUseRestrictions(item) {
if (item.noUseRestrictions) {
return item.noUseRestrictions;
}
if (item.canuseResult) {
return item.canuseResult.reason;
}
return "";
}
//
const couponList = ref([]);
//
const goodsCouponSel = ref({
id: "",
});
//
const couponSel = ref({
id: "",
});
//
const limitTimeDiscount = reactive({ id: "" });
//
const quansSelArr = computed(() => {
return [couponSel.value, goodsCouponSel.value].filter((v) => v.id);
});
const list = reactive({
page: 1,
size: 10,
status: "nomore",
data: [],
noCanUseCoupons: [],
canUseCoupons: [],
});
//
function formatCoupon() {
let canUseGoodsCoupon = [];
let canUseDiscountCoupon = [];
let noUseGoodsCoupon = [];
let noUseDiscountCoupon = [];
const user = shopUserInfo.value;
let shopInfo = uni.getStorageSync("shopInfo") || {};
const goodsOrderPrice = option.orderPrice || 0;
const dinnerType = option.dinnerType || "dine-in";
let goodsArr = returnAllGoodsList();
const canDikouGoodsArr = yskUtils.couponUtils.returnCanDikouGoods(
goodsArr,
user,
shopInfo
);
for (let i = 0; i < couponList.value.length; i++) {
const coupon = couponList.value[i];
console.log('quansSelArr',quansSelArr.value)
const selCoupon =
myQuan.types.sel ==1
? quansSelArr.value.filter((v) => v.type != 2)
: quansSelArr.value.filter((v) => v.type == 2);
const canuseResult = yskUtils.couponUtils.returnCouponCanUse({
canDikouGoodsArr,
coupon,
goodsOrderPrice,
user,
selCoupon: selCoupon,
shopInfo,
limitTimeDiscount: limitTimeDiscount,
});
const { canUse, reason } = canuseResult;
if (coupon.type == 2) {
if (canUse || goodsCouponSel.value.id == coupon.id) {
canUseGoodsCoupon.push(coupon);
} else {
noUseGoodsCoupon.push({
...coupon,
canuseResult,
});
}
} else {
if (canUse || couponSel.value.id == coupon.id) {
canUseDiscountCoupon.push(coupon);
} else {
noUseDiscountCoupon.push({
...coupon,
canuseResult,
});
}
}
}
//
canUseGoodsCoupon = canUseGoodsCoupon.map((v) => {
const discount = yskUtils.couponUtils.returnCouponDiscount(
canDikouGoodsArr,
v,
user,
goodsOrderPrice,
quansSelArr.value.filter((v) => v.type != 2),
shopInfo,
limitTimeDiscount
);
return {
...v,
discount,
discountAmount: discount ? discount.discountPrice : v.discountAmount,
};
});
//
canUseDiscountCoupon = canUseDiscountCoupon.map((v) => {
const discount = yskUtils.couponUtils.returnCouponDiscount(
canDikouGoodsArr,
v,
user,
goodsOrderPrice,
quansSelArr.value.filter((v) => v.type == 2),
shopInfo,
limitTimeDiscount
);
return {
...v,
discount,
discountAmount: discount ? discount.discountPrice : v.discountAmount,
};
});
if (myQuan.types.sel == 1) {
list.noCanUseCoupons = noUseGoodsCoupon;
list.canUseCoupons = canUseGoodsCoupon;
} else {
list.noCanUseCoupons = noUseDiscountCoupon;
list.canUseCoupons = canUseDiscountCoupon;
}
console.log("list", list);
console.log("canUseGoodsCoupon", canUseGoodsCoupon);
console.log("noUseGoodsCoupon", noUseGoodsCoupon);
console.log("canUseDiscountCoupon", canUseDiscountCoupon);
console.log("noUseDiscountCoupon", noUseDiscountCoupon);
}
async function getQuan() {
const orderRes = await orderApi.tbOrderInfoDetail(option.orderId);
if (orderRes) {
order.value = orderRes;
Object.assign(limitTimeDiscount,orderRes.limitRate)
}
console.log(order.value);
const res = await $findCoupon({
shopUserId: option.shopUserId,
});
couponList.value = res || [];
formatCoupon();
myQuan.hasAjax = true;
}
const option = reactive({
orderId: "",
shopUserId: "",
orderPrice: 0,
});
function toEmitChooseQuan(item) {
let arr = [];
if (item) {
arr = [item];
} else {
if (myQuan.fullReductionCouponSel.id) {
arr.push(myQuan.fullReductionCouponSel);
}
const goodsQuan = myQuan.res.productCoupon.filter((v) => v.checked);
arr.push(...goodsQuan);
}
uni.$emit("choose-quan", arr);
back();
}
const discountAmount = computed(() => {
return quansSelArr.value.reduce((pre, cur) => pre + cur.discountAmount, 0);
});
const payPrice = computed(() => {
const pay = option.orderPrice - discountAmount.value;
return (pay < 0 ? 0 : pay).toFixed(2);
});
watch(
() => myQuan.types.sel,
(newval) => {
formatCoupon();
}
);
watch(
() => couponSel.value.id,
(newval) => {
formatCoupon();
}
);
watch(
() => goodsCouponSel.value.id,
(newval) => {
formatCoupon();
}
);
watch(
() => quansSelArr.value,
(newval) => {
const user = shopUserInfo.value;
let shopInfo = uni.getStorageSync("shopInfo") || {};
const goodsOrderPrice = option.orderPrice || 0;
const dinnerType = option.dinnerType || "dine-in";
let goodsArr = returnAllGoodsList();
const canDikouGoodsArr = yskUtils.couponUtils.returnCanDikouGoods(
goodsArr,
user,
shopInfo
);
console.log('canDikouGoodsArr');
console.log(canDikouGoodsArr);
let goodsCoupon = newval.filter((v) => v.type == 2);
let otherCoupon = newval.filter((v) => v.type != 2);
goodsCoupon = goodsCoupon.map((v) => {
const discount = yskUtils.couponUtils.returnCouponDiscount(
canDikouGoodsArr,
v,
user,
goodsOrderPrice,
[],
shopInfo,
limitTimeDiscount
);
return {
...v,
discount,
discountAmount: discount ? discount.discountPrice : v.discountAmount,
};
});
otherCoupon = otherCoupon.map((v) => {
const discount = yskUtils.couponUtils.returnCouponDiscount(
canDikouGoodsArr,
v,
user,
goodsOrderPrice,
goodsCoupon,
shopInfo,
limitTimeDiscount
);
return {
...v,
discount,
discountAmount: discount ? discount.discountPrice : v.discountAmount,
};
});
uni.$emit("selCoupon", [...goodsCoupon, ...otherCoupon]);
},
{
deep: true,
}
);
async function getShopUser() {
const res = await shopUserDetail({
id: option.shopUserId,
});
if (res) {
shopUserInfo.value = res;
}
}
onLoad(async (opt) => {
Object.assign(option, opt);
const selCoupon=uni.getStorageSync("selCoupon")||[];
for(let i=0;i<selCoupon.length;i++){
if(selCoupon[i].type==2){
goodsCouponSel.value=selCoupon[i];
}else{
couponSel.value=selCoupon[i];
}
}
await getShopUser();
getQuan();
});
let safebottomHeight = ref(0);
onReady(() => {
getSafeBottomHeight("bottom", 0).then((height) => {
console.log(height);
safebottomHeight.value = height;
});
});
</script>
<style lang="scss" scoped>
// $quan-color:rgb(233, 77, 60);
$quan-color: #318AFE;
$quan-color: #318afe;
.no-use {
position: absolute;
@ -445,7 +648,6 @@
height: 40rpx;
border-radius: 40rpx;
opacity: 0;
}
.active {
@ -459,7 +661,7 @@
position: relative;
&::after {
content: '';
content: "";
position: absolute;
left: -30rpx;
display: block;
@ -483,7 +685,8 @@
height: 40rpx;
border-radius: 40rpx;
&.active {}
&.active {
}
}
.use-btn {
@ -522,7 +725,11 @@
.hui {
// background-color: $quan-color;
background-image: linear-gradient(to right bottom, rgb(254, 103, 4), rgb(241, 50, 42));
background-image: linear-gradient(
to right bottom,
rgb(254, 103, 4),
rgb(241, 50, 42)
);
padding: 4rpx 10rpx;
border-radius: 10rpx;
font-size: 24rpx;
@ -536,7 +743,7 @@
box-shadow: 0 0 5px #eee;
overflow: hidden;
.left {
max-width: 80%;
max-width: 70%;
}
.sel {
padding: 2rpx 4rpx;
@ -558,11 +765,13 @@
flex-direction: column;
background-color: $quan-color;
height: 100%;
min-width: 180rpx;
}
&.goods {
.right {
background-color: #fff;
position: initial;
.use-btn {
padding: 10rpx 40rpx;

1321
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -64,4 +64,6 @@ export const useMenusStore = defineStore('menus', {
}
},
});
unistorage: true, // 开启后对 state 的数据读写都将持久化
}
);