Просмотр исходного кода

1. 蜂鸟跑腿设置添加门店绑定与解绑
2. 花掌柜端--花店买花选择跑腿情况下,会根据花材的免费规则判断是否免跑腿费

shizhongqi 8 месяцев назад
Родитель
Сommit
cbc311cd05

+ 7 - 1
ghsApp/src/admin/delivery/components/PlatformItem.vue

@@ -60,7 +60,13 @@ export default {
 			this.$emit('recharge', this.platform);
 		},
 		handleShop() {
-			this.$emit('shop', this.platform);
+			console.log(this.platform.id);
+			// this.$emit('shop', this.platform);
+			if(this.platform.id == 'fengniao') {
+				uni.navigateTo({
+					url: `/admin/delivery/shopDetail?platformId=${this.platform.id}`
+				});
+			}
 		},
 		handleCancelAuth() {
 			this.$emit('cancel-auth', this.platform);

+ 384 - 0
ghsApp/src/admin/delivery/shopDetail.vue

@@ -0,0 +1,384 @@
+<template>
+  <view class="shop-detail-page">
+    <view class="shop-list">
+      <view v-for="shop in shopList" :key="shop.id" class="shop-card">
+        <view class="card-body">
+          <!-- 门店基本信息 -->
+          <view class="shop-info">
+            <view class="info-row">
+              <text class="label">门店ID:</text>
+              <text class="value">{{ shop.id }}</text>
+            </view>
+            <view class="info-row">
+              <text class="label">门店名称:</text>
+              <text class="value shop-name">{{ shop.name }}</text>
+            </view>
+            <view class="info-row">
+              <text class="label">门店地址:</text>
+              <text class="value address">{{ shop.address }}</text>
+            </view>
+            <view class="info-row">
+              <text class="label">认证状态:</text>
+              <text class="value status" :class="shop.statusClass">
+                {{ shop.statusText }}
+              </text>
+            </view>
+          </view>
+
+          <!-- 操作按钮 -->
+          <view v-if="shop.bindStatus == false">
+            <view class="card-actions">
+              <button class="action-btn select-btn" @click="handleBindShop(shop)">绑定此店</button>
+            </view>
+          </view>
+          <view v-else>
+            <view class="card-actions">
+              <button class="action-btn">已绑定此店</button>
+              <button class="action-btn select-btn" @click="cancelBindShop(shop)">取消绑定</button>
+            </view>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- 空状态 -->
+    <view v-if="!shopList.length && !loading" class="empty-state">
+      <text class="empty-text">暂无门店信息</text>
+    </view>
+
+    <!-- 加载状态 -->
+    <view v-if="loading" class="loading-state">
+      <text>加载中...</text>
+    </view>
+  </view>
+</template>
+
+<script>
+import { storeList, bindStore, unBindStore } from '@/api/express/shop.js';
+export default {
+  name: 'ShopDetail',
+  data() {
+    return {
+      platformId: '', // 平台ID
+      shopList: [],
+      loading: false
+    };
+  },
+  onLoad(options) {
+    // 获取平台ID
+    if (options.platformId) {
+      this.platformId = options.platformId;
+      console.log(this.platformId);
+    }
+    this.fetchShopList();
+  },
+  methods: {
+    init() {},
+
+    /**
+     * 获取状态文字
+     */
+     getStatusText(status) {
+      const statusMap = {
+        10: '上架审核中',
+        20: '正常',
+        30: '上架审核失败',
+        40: '已冻结',
+        50: '已下架'
+      };
+      return statusMap[status] || '未知状态';
+    },
+
+    /**
+     * 获取状态样式类
+     */
+    getStatusClass(status) {
+      const classMap = {
+        10: 'status-auditing',
+        20: 'status-normal',
+        30: 'status-failed',
+        40: 'status-frozen',
+        50: 'status-offline'
+      };
+      return classMap[status] || '';
+    },
+
+    /**
+     * 获取门店列表
+     */
+    async fetchShopList() {
+      this.loading = true;
+      try {
+        // 调用API获取门店列表
+        storeList({ platform: this.platformId }).then((res) => {
+          console.log(res);
+          if (res.data && res.data.length > 0) {
+            this.shopList = res.data.map(item => {
+              // 预处理状态显示,避免在模板中直接调用方法导致渲染问题
+              return {
+                ...item,
+                statusText: this.getStatusText(item.status),
+                statusClass: this.getStatusClass(item.status)
+              };
+            });
+          } else {
+            this.shopList = [];
+          }
+          this.loading = false;
+        });
+
+        // --- 模拟数据 ---
+        /*setTimeout(() => {
+          this.shopList = [
+            {
+              id: 'shop001',
+              name: '门店一',
+              address: '北京市朝阳区某某街道123号',
+              
+            },
+            {
+              id: 'shop002',
+              name: '门店二',
+              address: '上海市浦东新区某某路456号',
+              is_verified: true
+            },      
+            {
+              id: 'shop003',
+              name: '门店三',
+              address: '广州市天河区某某大道789号',
+              is_verified: false
+            }
+          ];
+          this.loading = false;
+        }, 500);*/
+        // --- 模拟数据结束 ---
+      } catch (error) {
+        console.error('获取门店列表失败', error);
+        uni.showToast({
+          title: '获取门店列表失败',
+          icon: 'none'
+        });
+        this.loading = false;
+      }
+    },
+
+    /**
+     * 选择门店
+     * @param {Object} shop - 门店信息对象
+     */
+    handleBindShop(shop) {
+      console.log('选择门店:', shop);
+
+      // 显示确认弹窗
+      uni.showModal({
+        title: '确认选择',
+        content: `确定要选择【${shop.name}】作为本账号的门店吗?`,
+        success: (res) => {
+          if (res.confirm) {
+            this.bindShop(shop);
+          }
+        }
+      });
+    },
+
+    /**
+     * 执行绑定门店操作
+     * @param {Object} shop - 门店信息对象
+     */
+    async bindShop(shop) {
+      uni.showLoading({ title: '处理中...' });
+      try {
+        // 调用API选择门店
+        bindStore({
+            platform: this.platformId,
+            shopId: shop.id
+        }).then(res => {
+          uni.hideLoading();
+          uni.showToast({
+            title: '绑定成功',
+            icon: 'success'
+          });
+          shop.bindStatus = true;
+        });
+      } catch (error) {
+        uni.hideLoading();
+        console.error('绑定门店失败', error);
+        uni.showToast({
+          title: '绑定失败,请重试',
+          icon: 'none'
+        });
+      }
+    },
+    /**
+     * 取消绑定门店
+     * @param {Object} shop - 门店信息对象
+     */
+    async cancelBindShop(shop) {
+      uni.showLoading({ title: '处理中...' });
+      try {
+        // 调用API取消绑定门店
+        unBindStore({
+            platform: this.platformId,
+            shopId: shop.id
+        }).then(res => {
+          uni.hideLoading();
+          uni.showToast({
+            title: '取消绑定成功',
+            icon: 'success'
+          });
+          // 变更当前的卡片状态
+          shop.bindStatus = false;
+        });
+      } catch (error) {
+        uni.hideLoading();
+        console.error('取消绑定门店失败', error);
+        uni.showToast({
+          title: '取消绑定失败,请重试',
+          icon: 'none'
+        });
+      }
+    }
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.shop-detail-page {
+  background-color: #f5f5f5;
+  min-height: 100vh;
+  padding: 24rpx;
+}
+
+.shop-list {
+  display: flex;
+  flex-direction: column;
+  gap: 24rpx;
+}
+
+.shop-card {
+  background-color: #ffffff;
+  border-radius: 16rpx;
+  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
+  overflow: hidden;
+}
+
+.card-body {
+  padding: 32rpx;
+}
+
+.shop-info {
+  display: flex;
+  flex-direction: column;
+  gap: 20rpx;
+  margin-bottom: 32rpx;
+}
+
+.info-row {
+  display: flex;
+  align-items: flex-start;
+  font-size: 28rpx;
+  line-height: 1.6;
+}
+
+.label {
+  color: #999;
+  min-width: 140rpx;
+  flex-shrink: 0;
+}
+
+.value {
+  color: #333;
+  flex: 1;
+  word-break: break-all;
+}
+
+.shop-name {
+  font-weight: bold;
+  font-size: 30rpx;
+  color: #000;
+}
+
+.address {
+  color: #666;
+}
+
+.status {
+  font-size: 26rpx;
+  padding: 4rpx 16rpx;
+  border-radius: 6rpx;
+  display: inline-block;
+  max-width: 165rpx;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  text-align: center;
+}
+
+.status-auditing {
+  background-color: #fff7e6;
+  color: #fa8c16;
+  border: 1rpx solid #ffd591;
+}
+
+.status-normal {
+  background-color: #f6ffed;
+  color: #52c41a;
+  border: 1rpx solid #b7eb8f;
+}
+
+.status-failed {
+  background-color: #fff1f0;
+  color: #f5222d;
+  border: 1rpx solid #ffa39e;
+}
+
+.status-frozen {
+  background-color: #fff2e8;
+  color: #d4380d;
+  border: 1rpx solid #ffbb96;
+}
+
+.status-offline {
+  background-color: #f5f5f5;
+  color: #999;
+  border: 1rpx solid #d9d9d9;
+}
+
+
+.card-actions {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.action-btn {
+  font-size: 28rpx;
+  height: 64rpx;
+  line-height: 64rpx;
+  padding: 0 32rpx;
+  border-radius: 32rpx;
+  border: none;
+  white-space: nowrap;
+}
+
+.select-btn {
+  background-color: #1890ff;
+  color: #fff;
+}
+
+.empty-state {
+  padding-top: 200rpx;
+  text-align: center;
+}
+
+.empty-text {
+  font-size: 28rpx;
+  color: #999;
+}
+
+.loading-state {
+  padding-top: 200rpx;
+  text-align: center;
+  font-size: 28rpx;
+  color: #999;
+}
+</style>

+ 14 - 0
ghsApp/src/api/express/shop.js

@@ -0,0 +1,14 @@
+import https from '@/plugins/luch-request_0.0.7/request'
+
+export const bindStore = data => {
+    return https.post('/delivery-shop/bind-store', data)
+}
+
+export const unBindStore = data => {
+    return https.post('/delivery-shop/unbind-store', data)
+}
+
+export const storeList = data => {
+    return https.get('/delivery-shop/store-list', data)
+}
+

+ 2 - 1
ghsApp/src/pages.json

@@ -233,7 +233,8 @@
 			"root": "admin/delivery",
 			"pages": [
 				{"path": "allDelivery","style": {"navigationBarTitleText": "配送平台报价"}},
-				{"path": "deliveryManage","style": {"navigationBarTitleText": "跑腿管理"}}
+				{"path": "deliveryManage","style": {"navigationBarTitleText": "跑腿管理"}},
+				{"path": "shopDetail","style": {"navigationBarTitleText": "门店详情"}}
 			]
 		},
 		{

+ 108 - 44
hdApp/src/admin/billing/affirmGhs.vue

@@ -175,9 +175,10 @@
 			<text style="color: #3385FF;width:100%;">到店自取,没有配送费</text>
 		</view>
 		<view v-if="form.sendType == 2">
-			<text style="color: #3385FF;width:100%;">各平台跑腿费</text>
+			<text v-if="ghsInfo.openIntraCity == 0" style="color: #3385FF;width:100%;">运费自理或到付(请联系客服)</text>
+			<text v-if="ghsInfo.openIntraCity == 1" style="color: #3385FF;width:100%;">各平台跑腿费</text>
 			<!-- 跑腿平台报价列表 -->
-			<view v-if="deliveryQuotes.length > 0" class="delivery-quotes-container">
+			<view v-if="ghsInfo.openIntraCity == 1 && deliveryQuotes.length > 0" class="delivery-quotes-container">
 				<view class="delivery-quotes-grid">
 					<view 
 						v-for="(item, index) in deliveryQuotes" 
@@ -192,7 +193,7 @@
 					</view>
 				</view>
 			</view>
-			<view v-else-if="deliveryQuotesLoading" style="text-align: center; padding: 20upx 0; color: #999;">
+			<view v-else-if="ghsInfo.openIntraCity == 1 && deliveryQuotesLoading" style="text-align: center; padding: 20upx 0; color: #999;">
 				正在获取报价...
 			</view>
 		</view>
@@ -228,7 +229,13 @@
 		</tui-list-cell>
 	</block>
 </block>
-
+			<tui-list-cell class="line-cell" :hover="false" v-if="displaySendCost == true">
+				<view class="tui-title">跑腿费</view>
+				<view>
+					<text :class="isFreeDelivery ? 'delivery-price-free' : 'delivery-price-normal'">¥ {{ form.sendCost }}</text>
+					<text v-if="isFreeDelivery" class="free-delivery-tag">【免跑腿费】</text>
+				</view>
+			</tui-list-cell>
 					<tui-list-cell class="line-cell" :hover="false" :arrow="true" v-if="displayAddress == true" @click="modifyAddress">
 						<view class="tui-title">收花地址</view>
 						<view v-if="!$util.isEmpty(shopInfo.address)">
@@ -242,12 +249,7 @@
 
 					<tui-list-cell class="line-cell" :hover="false" v-if="displaySendCost == true && Number(showDistance)>0">
 					<view class="tui-title">距离</view>
-					<text style="color: #3385FF">{{ showDistance }}公里</text>
-					</tui-list-cell>
-
-					<tui-list-cell class="line-cell" :hover="false" v-if="displaySendCost == true">
-					<view class="tui-title">跑腿费</view>
-					<text style="color: #3385FF">¥{{ form.sendCost }}</text>
+					<text style="color: #3385FF">{{ showDistance }}米</text>
 					</tui-list-cell>
 
 					<tui-list-cell class="line-cell" :hover="false" v-if="needAddPackCost == true">
@@ -257,7 +259,7 @@
 
 					<tui-list-cell class="line-cell" :hover="false" :arrow="false" >
 						<view class="tui-title">总金额</view>
-						<text style="color: #3385FF">¥{{ modifyPrice }}</text>
+						<text style="color: #3385FF">¥ {{ modifyPrice }}</text>
 					</tui-list-cell>
 
 					<tui-list-cell class="line-cell" :hover="false" :arrow="true">
@@ -412,8 +414,10 @@ export default {
 			//计算运费
 			//this.calcFreight()
 
-			//各跑腿平台报价
-			this.getDeliveryQuotes()
+			if(this.displaySendCost() == true){
+				//各跑腿平台报价
+				this.getDeliveryQuotes()
+			}
 		}
 		//修改地址更新
 		this.getCurrentShop()
@@ -429,6 +433,10 @@ export default {
 			}
 			return false
 		},
+		/**
+		 * 显示跑腿费
+		 * @returns {boolean}
+		 */
 		displaySendCost(){
 			if(this.form.sendType == 2){
 				if(this.ghsInfo.openIntraCity==0){
@@ -442,13 +450,65 @@ export default {
 			}
 			return false
 		},
+		/**
+		 * 判断是否免跑腿费
+		 * @returns {boolean}
+		 */
+		isFreeDelivery(){
+			// 不显示跑腿费时,不需要判断
+			if(this.displaySendCost == false){
+				return false
+			}
+			
+			// 条件1: 比较距离与免费公里数
+			// showDistance单位是米,hcFreeKm单位是千米
+			const distanceInMeters = Number(this.showDistance) || 0
+			const freeKmInMeters = (Number(this.ghsInfo.hcFreeKm) || 0) * 1000
+			
+			// 如果距离小于免费公里数,则免运费
+			if(distanceInMeters < freeKmInMeters){
+				return true
+			}
+			
+			// 条件2: 如果距离大于免费公里数,判断hcMap
+			if(distanceInMeters > freeKmInMeters){
+				// 判断hcMap是否为空
+				if(this.ghsInfo.hcMap && Array.isArray(this.ghsInfo.hcMap) && this.ghsInfo.hcMap.length > 0){
+					// 获取花材数量和总价
+					const flowerCount = this.allCountFun.bigLength || 0
+					const flowerPrice = this.allPriceFun || 0
+					
+					// 遍历hcMap,检查是否满足免运费条件
+					for(const rule of this.ghsInfo.hcMap){
+						const ruleNum = Number(rule.num) || 0
+						const rulePrice = Number(rule.price) || 0
+						const ruleDistance = (Number(rule.distance) || 0) * 1000 // 转换为米
+						
+						// 如果花材数量大于num,花材总价大于price,距离小于distance,则免运费
+						if(flowerCount >= ruleNum && flowerPrice >= rulePrice && distanceInMeters <= ruleDistance){
+							return true
+						}
+					}
+				}
+			}
+			
+			return false
+		},
+		/**
+		 * 计算总金额
+		 * @returns {number}
+		 */
 		modifyPrice(){
 			let allPrice = this.allPrice.toFixed(2)
 			allPrice = Number(allPrice)
 			let price = allPrice
 
+			// 判断是否需要加跑腿费
 			if(this.displaySendCost == true){
-				price = price + this.form.sendCost
+				// 如果不是免跑腿费,则加上跑腿费
+				if(!this.isFreeDelivery){
+					price = price + this.form.sendCost
+				}
 			}
 			this.needAddPackCost = false
 			if(this.ghsInfo.pfLevel && this.ghsInfo.pfLevel == 1){
@@ -568,28 +628,25 @@ export default {
 				this.deliveryQuotesLoading = false
 				if (res.code === 1 && res.data && res.data.deliveryList) {
 					// 处理报价数据
-					this.deliveryQuotes = res.data.deliveryList.map(item => {
-						// 如果 isAble 为 false,则此项不显示
-						if (item.isAble == false) {
-							console.log('item.isAble == false', item)
-							return false;
-						}
-						// 价格从分转换为元
-						const price = item.price ? (item.price / 100).toFixed(1) : '0.0'
-						
-						// 提取平台名称(去掉括号内的内容)
-						let displayName = item.name
-						if (displayName && displayName.includes('(')) {
-							displayName = displayName.split('(')[0].trim()
-						}
-						
-						return {
-							...item,
-							displayName: displayName,
-							priceText: price,
-							priceNumber: parseFloat(price)
-						}
-					})
+					this.deliveryQuotes = res.data.deliveryList
+						.filter(item => item.isAble !== false)
+						.map(item => {
+							// 价格从分转换为元
+							const price = item.price ? (item.price / 100).toFixed(1) : '0.0'
+							
+							// 提取平台名称(去掉括号内的内容)
+							let displayName = item.name
+							if (displayName && displayName.includes('(')) {
+								displayName = displayName.split('(')[0].trim()
+							}
+							
+							return {
+								...item,
+								displayName: displayName,
+								priceText: price,
+								priceNumber: parseFloat(price)
+							}
+						})
 					
 					// 自动选中第一个可用的报价
 					const firstAvailableIndex = this.deliveryQuotes.findIndex(item => item.isAble)
@@ -613,14 +670,6 @@ export default {
 		},
 		// 选择跑腿平台
 		selectDelivery(item, index) {
-			if (!item.isAble) {
-				uni.showToast({
-					title: '该平台暂不可用',
-					icon: 'none'
-				})
-				return
-			}
-			
 			this.selectedDeliveryIndex = index
 			this.selectedDeliveryData = item
 			this.form.sendCost = item.priceNumber
@@ -1339,4 +1388,19 @@ export default {
 		}
 	}
 }
+
+/* 跑腿费价格样式 */
+.delivery-price-normal {
+	color: #3385FF;
+}
+
+.delivery-price-free {
+	color: #999;
+	text-decoration: line-through;
+}
+
+.free-delivery-tag {
+	color: #3385FF;
+	margin-left: 10upx;
+}
 </style>