Explorar o código

限购处理与相关展示变动

shizhongqi hai 4 meses
pai
achega
2f0d33499e

+ 51 - 18
ghsApp/src/admin/item/detail.vue

@@ -63,6 +63,26 @@
           class="tui-input" name="reachNumDiscount" @focus="form.reachNumDiscount=''" placeholder="金额" type="digit" />元
         </tui-list-cell>
 
+        <view class="limit-buy-wrap">
+          <tui-list-cell class="line-cell limit-buy-line" :hover="false">
+            <view class="tui-title">每人限购</view>
+            <input v-model="form.limitBuy" style="width:105upx;" @focus="form.limitBuy=''" placeholder-class="phcolor" class="tui-input" name="limitBuy" placeholder="0不限购" maxlength="50" type="number" />
+
+            <button v-if="productData.id > 0" class="admin-button-com blue middle" @click.stop="clearBuyCache()" style="width:150upx;">清已购</button>
+            <button v-if="productData.id > 0" class="admin-button-com blue middle" style="width:180upx;margin-left:10upx;" @click.stop="hasBuyList">已购列表</button>
+          </tui-list-cell>
+          <tui-list-cell v-if="showClearTime" class="line-cell limit-buy-line" :hover="false">
+            <view class="tui-title">清空时间</view>
+            <datetime-picker
+              v-model="form.limitBuyClearTime"
+              type="datetime"
+              return-type="string"
+              class="limit-time-picker"
+              placeholder="留空则不自动清空"
+            />
+          </tui-list-cell>
+        </view>
+
         <tui-list-cell class="line-cell" :arrow="false" :hover="false">
         <view class="tui-title" style="color:#19b31f;">平均成本</view>
         <view style="color:#19b31f;width:300upx;" @click="showModifyAvCost(productData)">{{productData.avCost?parseFloat(productData.avCost):0}}</view>
@@ -154,15 +174,6 @@
           <button v-else class="admin-button-com default middle" style="width:150upx;" @click.stop="notAllowChange()">修改</button>
         </tui-list-cell>
 
-        <tui-list-cell class="line-cell" :hover="false">
-          <view class="tui-title">每人限购</view>
-          <input v-model="form.limitBuy" style="width:105upx;" @focus="form.limitBuy=''" placeholder-class="phcolor" class="tui-input" name="limitBuy" placeholder="0不限购" maxlength="50" type="number" />
-
-          <button v-if="productData.id > 0" class="admin-button-com blue middle" @click.stop="clearBuyCache()" style="width:150upx;">清已购</button>
-          <button v-if="productData.id > 0" class="admin-button-com blue middle" style="width:180upx;margin-left:10upx;" @click.stop="hasBuyList">已购列表</button>
-
-        </tui-list-cell>
-
         <tui-list-cell class="line-cell" :hover="false">
           <view class="tui-title">库存预警</view>
           <input v-model="form.stockWarning" style="width:300upx;" @focus="form.stockWarning=''" placeholder-class="phcolor" class="tui-input" name="stockWarning" placeholder="请填写" maxlength="50" type="number" />
@@ -449,6 +460,7 @@ import { mapGetters } from "vuex"
 //图片上传插件来源:https://ext.dcloud.net.cn/plugin?id=2922 已改造,不能再升级 shish 20211228
 import htzImageUpload from '@/components/htz-image-upload/htz-image-upload.vue'
 import ModalModule from "@/components/plugin/modal"
+import DatetimePicker from "@/components/mx-datepicker/datetime-picker.vue"
 import { getAllStaff } from "@/api/shop-admin";
 import { partItem } from "@/api/part";
 import { CURRENT_ENV } from '@/config'
@@ -457,7 +469,8 @@ export default {
   components: {
     TuiListCell,
     htzImageUpload,
-    ModalModule
+    ModalModule,
+    DatetimePicker
   },
   data() {
     return {
@@ -487,9 +500,9 @@ export default {
         hjPrice:'',
         hjAddPrice:2,
         addPrice:3,
-        discountPrice:0,
-        hjDiscountPrice:0,
-        skDiscountPrice:0,
+        discountPrice:0,   // 特价
+        hjDiscountPrice:0, // 会员特价
+        skDiscountPrice:0, // 零售特价
         reachNum:0,
         reachNumDiscount:0,
         cost:0,
@@ -498,6 +511,8 @@ export default {
         cover: "",
         images: [],
         limitBuy:0,
+        limitBuyClearTime:'',
+        limitBuyExceedType:1,
         stockWarning:5,
         status:2,
         itemId:0,
@@ -549,6 +564,9 @@ export default {
 		...mapGetters(["getLoginInfo","getDictionariesInfo"]),
     coverImgData() {
       return this.form.images || [];
+    },
+    showClearTime() {
+      return Number(this.form.limitBuy) > 0;
     }
 	},
   onLoad(option) {
@@ -1176,6 +1194,8 @@ export default {
         this.form.frontUse = 0
         this.form.virtualStock = 0
         this.form.limitBuy = 0
+        this.form.limitBuyClearTime = ''
+        this.form.limitBuyExceedType = 1
         this.cost = res.data && res.data.cost ? parseFloat(res.data.cost) : 0
       })
     },
@@ -1189,6 +1209,9 @@ export default {
         Object.keys(this.form).forEach((i) => {
             this.form[i] = res.data[i]
         });
+        if (![1, 2].includes(Number(this.form.limitBuyExceedType))) {
+          this.form.limitBuyExceedType = 1;
+        }
 
         const imageUrls = (res.data.images || '').split(',').filter(i => i);
         this.form.images = imageUrls;
@@ -1495,6 +1518,21 @@ export default {
     }
   }
 }
+.limit-buy-wrap {
+  border: 3upx solid #eee;
+  border-radius: 12upx;
+  margin: 0 22upx 20upx;
+  overflow: hidden;
+}
+.limit-buy-line {
+  margin-left: -20upx;
+  &:last-child {
+    border-bottom: none !important;
+  }
+}
+.limit-time-picker {
+  width: 470upx;
+}
 .use-img{
   font-size: 22rpx;
   color: #999999;
@@ -1506,11 +1544,6 @@ export default {
   color: #cccccc;
   padding: 12rpx 0;
 }
-.summary-wrap {
-  .goods-summary {
-    height: 400upx;
-  }
-}
 .app-footer {
   /* 使用固定定位确保位置稳定 */
   position: fixed;

+ 139 - 0
ghsApp/src/components/mx-datepicker/datetime-picker.vue

@@ -0,0 +1,139 @@
+<template>
+  <view class="uni-datetime-picker-wrap">
+    <picker mode="date" :value="dateValue" @change="onDateChange">
+      <view class="picker-item">
+        <text :class="dateText ? 'picker-value' : 'picker-placeholder'">
+          {{ dateText || placeholder }}
+        </text>
+      </view>
+    </picker>
+    <picker mode="time" :value="timeValue" @change="onTimeChange">
+      <view class="picker-item picker-item-time">
+        <text :class="timeText ? 'picker-value' : 'picker-placeholder'">
+          {{ timeText || '小时:分钟' }}
+        </text>
+      </view>
+    </picker>
+  </view>
+</template>
+
+<script>
+export default {
+  name: "UniDatetimePicker",
+  props: {
+    value: {
+      type: [String, Number],
+      default: ""
+    },
+    modelValue: {
+      type: [String, Number],
+      default: ""
+    },
+    type: {
+      type: String,
+      default: "datetime"
+    },
+    returnType: {
+      type: String,
+      default: "string"
+    },
+    placeholder: {
+      type: String,
+      default: "请选择日期"
+    }
+  },
+  data() {
+    return {
+      innerValue: ""
+    };
+  },
+  computed: {
+    currentValue() {
+      if (this.modelValue !== undefined && this.modelValue !== null && this.modelValue !== "") {
+        return String(this.modelValue);
+      }
+      if (this.value !== undefined && this.value !== null && this.value !== "") {
+        return String(this.value);
+      }
+      return this.innerValue;
+    },
+    dateText() {
+      if (!this.currentValue) return "";
+      return this.currentValue.split(" ")[0] || "";
+    },
+    timeText() {
+      if (!this.currentValue) return "";
+      const t = this.currentValue.split(" ")[1] || "";
+      if (!t) return "";
+      return t.length >= 5 ? t.slice(0, 5) : t;
+    },
+    dateValue() {
+      return this.dateText || this.formatDate(new Date());
+    },
+    timeValue() {
+      return this.timeText || "00:00";
+    }
+  },
+  watch: {
+    currentValue: {
+      immediate: true,
+      handler(val) {
+        this.innerValue = val || "";
+      }
+    }
+  },
+  methods: {
+    formatDate(dateObj) {
+      const y = dateObj.getFullYear();
+      const m = `${dateObj.getMonth() + 1}`.padStart(2, "0");
+      const d = `${dateObj.getDate()}`.padStart(2, "0");
+      return `${y}-${m}-${d}`;
+    },
+    emitValue(dateStr, timeStr) {
+      const next = `${dateStr} ${timeStr}:00`;
+      this.innerValue = next;
+      this.$emit("input", next);
+      this.$emit("update:modelValue", next);
+      this.$emit("change", next);
+    },
+    onDateChange(e) {
+      const dateStr = e.detail.value;
+      const timeStr = this.timeText || "00:00";
+      this.emitValue(dateStr, timeStr);
+    },
+    onTimeChange(e) {
+      const timeStr = e.detail.value;
+      const dateStr = this.dateText || this.formatDate(new Date());
+      this.emitValue(dateStr, timeStr);
+    }
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.uni-datetime-picker-wrap {
+  width: 470upx;
+  display: flex;
+  align-items: center;
+}
+.picker-item {
+  height: 62upx;
+  border: 1upx solid #d9d9d9;
+  border-radius: 8upx;
+  padding: 0 18upx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.picker-item-time {
+  margin-left: 12upx;
+}
+.picker-placeholder {
+  color: #b8b8b8;
+  font-size: 24upx;
+}
+.picker-value {
+  color: #333333;
+  font-size: 26upx;
+}
+</style>

+ 55 - 49
ghsApp/src/components/plugin/list-cell.vue

@@ -1,5 +1,9 @@
 <template>
-	<view class="tui-cell-class tui-list-cell" :class="{'tui-cell-arrow':arrow,'tui-cell-last':last,'tui-line-left':lineLeft,'tui-line-right':lineRight,'tui-radius':radius}" :hover-class="hover?'tui-cell-hover':''" :style="{background: bgcolor,fontSize: size+'rpx',color:color,padding:padding}" :hover-stay-time="150" @tap="handleClick">
+	<view class="tui-cell-class tui-list-cell"
+		:class="{ 'tui-cell-arrow': arrow, 'tui-cell-last': last, 'tui-line-left': lineLeft, 'tui-line-right': lineRight, 'tui-radius': radius }"
+		:hover-class="hover ? 'tui-cell-hover' : ''"
+		:style="{ background: bgcolor, fontSize: size + 'rpx', color: color, padding: padding }" :hover-stay-time="150"
+		@tap="handleClick">
 		<slot></slot>
 	</view>
 </template>
@@ -68,57 +72,59 @@ export default {
 </script>
 
 <style scoped>
-	.tui-list-cell {
-		position: relative;
-		width: 100%;
-		box-sizing: border-box;
-		overflow: hidden;
-		display: flex;
-		align-items: center;
-	}
-	.tui-radius {
-		border-radius: 12upx;
-		overflow: hidden;
-	}
+.tui-list-cell {
+	position: relative;
+	width: 100%;
+	box-sizing: border-box;
+	overflow: hidden;
+	display: flex;
+	align-items: center;
+}
 
-	.tui-cell-hover {
-		background: #f7f7f9 !important;
-	}
+.tui-radius {
+	border-radius: 12upx;
+	overflow: hidden;
+}
 
-	.tui-list-cell::after {
-		content: '';
-		position: absolute;
-		border-bottom: 2px solid #eee;
-		-webkit-transform: scaleY(0.5);
-		transform: scaleY(0.5);
-		bottom: 0;
-		right: 0;
-		left: 0;
-	}
-	.tui-line-left::after {
-		left: 30rpx !important;
-	}
+.tui-cell-hover {
+	background: #f7f7f9 !important;
+}
 
-	.tui-line-right::after {
-		right: 30rpx !important;
-	}
+.tui-list-cell::after {
+	content: '';
+	position: absolute;
+	border-bottom: 2px solid #eee;
+	-webkit-transform: scaleY(0.5);
+	transform: scaleY(0.5);
+	bottom: 0;
+	right: 0;
+	left: 0;
+}
 
-	.tui-cell-last::after {
-		border-bottom: 0 !important;
-	}
+.tui-line-left::after {
+	left: 30rpx !important;
+}
 
-	.tui-list-cell.tui-cell-arrow:before {
-		content: ' ';
-		height: 22upx;
-		width: 22upx;
-		border-width: 2px 2px 0 0;
-		border-color: #b2b2b2;
-		border-style: solid;
-		-webkit-transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
-		transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
-		position: absolute;
-		top: 50%;
-		margin-top: -12upx;
-		right: 30upx;
-	}
+.tui-line-right::after {
+	right: 30rpx !important;
+}
+
+.tui-cell-last::after {
+	border-bottom: 0 !important;
+}
+
+.tui-list-cell.tui-cell-arrow:before {
+	content: ' ';
+	height: 22upx;
+	width: 22upx;
+	border-width: 2px 2px 0 0;
+	border-color: #b2b2b2;
+	border-style: solid;
+	-webkit-transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
+	transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
+	position: absolute;
+	top: 50%;
+	margin-top: -12upx;
+	right: 30upx;
+}
 </style>

+ 43 - 2
hdApp/src/admin/billing/affirmGhs.vue

@@ -14,7 +14,7 @@
 				<view class="module-com">
 					<view class="commodity-view">
 						<view class="commodity-list">
-							<view class="commodity-item" v-for="(item, index) in selectList" :key="index">
+							<view class="commodity-item" :class="{'limit-exceed-item': isLimitExceededItem(item)}" v-for="(item, index) in selectList" :key="index">
 								<image class="item-icon" :src="item.cover" alt="" />
 								<view class="item-info">
 
@@ -40,6 +40,7 @@
 											</text>
 										</view>
 									</view>
+									<text v-if="isLimitExceededItem(item)" class="limit-exceed-tip">限购 {{ limitExceedLimitBuy }},超出 {{ limitExceedNum }}</text>
 									<text v-if="item.presell == 1" style="position:absolute;top:86upx;font-weight:bold;color:red;font-size:30upx;">预售花材下单不能退款</text>
 								</view>
 							</view>
@@ -435,6 +436,9 @@ export default {
 			needAddPackCost:false,
 			transCost:[],
 			lackList:[],
+			limitExceedProductId:'',
+			limitExceedLimitBuy:'',
+			limitExceedNum:'',
 			showDistance:0,
 			deliveryQuotes: [], // 跑腿平台报价列表
 			selectedDeliveryIndex: -1, // 选中的报价索引
@@ -1094,8 +1098,11 @@ export default {
 			self.$util.confirmModal({content:'确认提交?'},() => {
 				uni.showLoading({title: '加载中',mask:true})
 				createOrder(params).then(res => {
+					uni.hideLoading()
 					if(res.code == 1){
-						uni.hideLoading()
+						this.limitExceedProductId = ''
+						this.limitExceedLimitBuy = ''
+						this.limitExceedNum = ''
 						if(res.data.hasLackError && res.data.hasLackError == 1){
 							this.lackList = res.data.lackList ? res.data.lackList : []
 							this.$refs.selectFlowerNumRef.open('center')
@@ -1106,10 +1113,32 @@ export default {
 						setTimeout(() => {
 							self.removeMemory(self.ghsInfo.id)
 						}, 600)
+						return true
 					}
+					if(res.code == -1 && res.data && String(res.data.productId || '') !== ''){
+						this.limitExceedProductId = res.data.productId ? String(res.data.productId) : ''
+						this.limitExceedLimitBuy = res.data.limitBuy ? String(res.data.limitBuy) : '0'
+						this.limitExceedNum = res.data.exceed ? String(res.data.exceed) : '0'
+						this.$msg(res.msg || '累计已超出限购数')
+						return false
+					}
+					this.limitExceedProductId = ''
+					this.limitExceedLimitBuy = ''
+					this.limitExceedNum = ''
+					if(res.msg){
+						this.$msg(res.msg)
+					}
+				}).catch(() => {
+					uni.hideLoading()
 				})            
 			})
 		},
+		isLimitExceededItem(item){
+			if(!item || !this.limitExceedProductId){
+				return false
+			}
+			return String(item.id) === String(this.limitExceedProductId)
+		},
 		numberAdd(arg1, arg2) {
 			var r1, r2, m, n;
 			try {
@@ -1197,6 +1226,12 @@ export default {
 				.commodity-item {
 					display: flex;
 					margin-bottom: 20upx;
+					&.limit-exceed-item {
+						border: 2upx solid #ff4d4f;
+						border-radius: 12upx;
+						padding: 12upx;
+						box-sizing: border-box;
+					}
 					.item-icon {
 						flex-shrink: 0;
 						width: 140upx;
@@ -1209,6 +1244,12 @@ export default {
 						justify-content: center;
 						flex: 1;
 						margin-left: 20upx;
+						.limit-exceed-tip {
+							margin-top: 10upx;
+							color: #ff4d4f;
+							font-size: 24upx;
+							font-weight: bold;
+						}
 						.info-line {
 							margin-bottom: 20upx;
 							display: flex;

+ 47 - 15
hdApp/src/admin/item/detail.vue

@@ -77,6 +77,26 @@
           class="tui-input" name="reachNumDiscount" @focus="form.reachNumDiscount=''" placeholder="金额" type="digit" />元
         </tui-list-cell>
 
+        <view class="limit-buy-wrap">
+          <tui-list-cell class="line-cell limit-buy-line" :hover="false">
+            <view class="tui-title">每人限购</view>
+            <input v-model="form.limitBuy" style="width:300upx;" @focus="form.limitBuy=''" placeholder-class="phcolor" class="tui-input" name="limitBuy" placeholder="请填写,填0不限购" maxlength="50" type="number" />
+
+            <button v-if="productData.id > 0 && form.limitBuy>0" class="admin-button-com blue middle" @click.stop="clearBuyCache()" style="width:150upx;">清已购</button>
+            <button v-else class="admin-button-com default middle" style="width:150upx;" @click.stop="">清已购</button>
+          </tui-list-cell>
+          <tui-list-cell v-if="showClearTime" class="line-cell limit-buy-line" :hover="false">
+            <view class="tui-title">清空时间</view>
+            <uni-datetime-picker
+              v-model="form.limitBuyClearTime"
+              type="datetime"
+              return-type="string"
+              class="limit-time-picker"
+              placeholder="请选择时间,空则不自动清空"
+            />
+          </tui-list-cell>
+        </view>
+
         <tui-list-cell class="line-cell" :arrow="false" :hover="false">
         <view class="tui-title">成本</view>
         <input v-model="form.cost" style="width:300upx;" placeholder-class="phcolor" @focus="form.cost=''" class="tui-input" name="cost" placeholder="请输入" type="digit"/>
@@ -129,7 +149,7 @@
           </view>
         </tui-list-cell>
 
-<block v-if="option.ptItemId">
+      <block v-if="option.ptItemId">
         <tui-list-cell class="line-cell" :arrow="true">
           <view class="tui-title">大单位</view>
           <picker mode="selector" :value="form.bigUnitId" :range="unitData" range-key="name" @change="changeBigUnitFn" class="tui-input" >
@@ -159,8 +179,8 @@
           <input v-model="form.weight" placeholder-class="phcolor" style="width:200upx;"
           class="tui-input" name="weight" placeholder="公斤" maxlength="50" type="digit" />
         </tui-list-cell>
-</block>
-<block v-else>
+      </block>
+      <block v-else>
         <tui-list-cell class="line-cell" :arrow="false" :hover="false">
           <view class="tui-title">大单位</view>
           <input v-model="form.bigUnitId" name="bigUnitId" type="text" hidden />
@@ -195,15 +215,7 @@
           <button v-if="productData.id > 0 && productData.hasRightChange == 1" class="admin-button-com blue middle" @click.stop="changeWeight()" style="width:150upx;">修改</button>
           <button v-else class="admin-button-com default middle" style="width:150upx;" @click.stop="notAllowChange()">修改</button>
         </tui-list-cell>
-</block>
-
-        <tui-list-cell class="line-cell" :hover="false">
-          <view class="tui-title">每人限购</view>
-          <input v-model="form.limitBuy" style="width:300upx;" @focus="form.limitBuy=''" placeholder-class="phcolor" class="tui-input" name="limitBuy" placeholder="请填写,填0不限购" maxlength="50" type="number" />
-
-          <button v-if="productData.id > 0 && form.limitBuy>0" class="admin-button-com blue middle" @click.stop="clearBuyCache()" style="width:150upx;">清已购</button>
-          <button v-else class="admin-button-com default middle" style="width:150upx;" @click.stop="">清已购</button>
-        </tui-list-cell>
+      </block>
 
         <tui-list-cell class="line-cell" :hover="false">
           <view class="tui-title">库存预警</view>
@@ -522,6 +534,8 @@ export default {
         cover: "",
         images: [],
         limitBuy:0,
+        limitBuyClearTime:'',
+        limitBuyExceedType:1,
         stockWarning:5,
         status:2,
         itemId:0,
@@ -573,6 +587,9 @@ export default {
 		...mapGetters(["getLoginInfo","getDictionariesInfo","getMyShopInfo"]),
     coverImgData() {
       return this.form.images || [];
+    },
+    showClearTime() {
+      return Number(this.form.limitBuy) > 0;
     }
 	},
   onLoad(option) {
@@ -1180,6 +1197,8 @@ export default {
         this.form.frontUse = 0
         this.form.virtualStock = 0
         this.form.limitBuy = 0
+        this.form.limitBuyClearTime = ''
+        this.form.limitBuyExceedType = 1
         this.cost = res.data && res.data.cost ? parseFloat(res.data.cost) : 0
       })
     },
@@ -1193,6 +1212,9 @@ export default {
         Object.keys(this.form).forEach((i) => {
             this.form[i] = res.data[i]
         });
+        if (![1, 2].includes(Number(this.form.limitBuyExceedType))) {
+          this.form.limitBuyExceedType = 1;
+        }
 
         const imageUrls = (res.data.images || '').split(',').filter(i => i);
         this.form.images = imageUrls;
@@ -1482,11 +1504,21 @@ export default {
     }
   }
 }
-.summary-wrap {
-  .goods-summary {
-    height: 400upx;
+.limit-buy-wrap {
+  border: 3upx solid #eee;
+  border-radius: 12upx;
+  margin: 0 20upx 20upx;
+  overflow: hidden;
+}
+.limit-buy-line {
+  margin-left: -20upx;
+  &:last-child {
+    border-bottom: none !important;
   }
 }
+.limit-time-picker {
+  width: 470upx;
+}
 .app-footer {
   justify-content: space-evenly;
   z-index: 9999;