Преглед на файлове

Merge branch 'redesign‌-260706' of git.huaml.com:zhh/front-end into redesign‌-260706

shizhongqi преди 2 дни
родител
ревизия
ad70fdcfc2

+ 6 - 5
ghsApp/src/admin/home/login.vue

@@ -119,7 +119,7 @@
 						</text>
 					</view>
 					<button
-						class="login-btn login-btn--weixin"
+						class="login-btn login-btn--primary"
 						open-type="getPhoneNumber"
 						@getphonenumber="wxPhoneLogin"
 					>手机号一键登录</button>
@@ -197,7 +197,7 @@
 import { mapActions } from "vuex";
 import { getShopInfo} from "@/utils/auth";
 import {appLogin, sendLoginSms, smsLogin} from '@/api/common'
-import { getDictionaries,postWxCode } from '@/api/mini'
+import { getDictionaries,postWxCode,getMiniMobile } from '@/api/mini'
 import { phoneLogin,wxMobileLogin } from "@/api/auth";
 
 export default {
@@ -459,7 +459,8 @@ export default {
 			let that = this
 			let currentMiniOpenId = uni.getStorageSync('currentMiniOpenId')
 			if (e.detail.errMsg === "getPhoneNumber:ok") {
-				wxMobileLogin({ iv: e.detail.iv, encryptedData: e.detail.encryptedData,miniOpenId:currentMiniOpenId }).then(subRes => {
+				let code = e.detail.code
+				getMiniMobile({ code: code, miniOpenId: currentMiniOpenId }).then(subRes => {
 							uni.hideLoading()
 							if(subRes.data && subRes.data.hasNoOpenId && subRes.data.hasNoOpenId ==1){
 								that.$util.confirmModal({content:'网络异常,请重新操作'},() => {
@@ -812,8 +813,8 @@ export default {
 
 .login-btn--weixin {
   color: #fff;
-  background: #2ba245;
-  box-shadow: 0 10upx 24upx rgba(43, 162, 69, 0.2);
+  background: linear-gradient(90deg, #3385ff 0%, #33b0ff 100%);
+  box-shadow: 0 10upx 24upx rgba(51, 133, 255, 0.24);
 }
 
 .login-agreement {

+ 1 - 1
ghsApp/src/admin/home/workbench.vue

@@ -55,7 +55,7 @@
               <text class="guest-card-desc">前往花掌柜选购花材</text>
             </view>
           </view>
-          <button class="guest-card-btn guest-card-btn--outline" @click="buyItem()">去买花</button>
+          <button class="guest-card-btn guest-card-btn--primary" @click="buyItem()">去买花</button>
         </view>
         <!-- #endif -->
 

+ 7 - 0
ghsApp/src/api/mini/index.js

@@ -26,6 +26,13 @@ export const getWxPhone = data => {
 	return https.post('/admin/mini-mobile', data)
 }
 
+/** *
+ * 点击授权获取手机号 mini (新接口)
+ */
+export const getMiniMobile = data => {
+	return https.post('/auth/get-mini-mobile', data)
+}
+
 export const bindAutoLogin = data => {
 	return https.post('/admin/bind-auto-login', data)
 }

+ 2 - 2
ghsApp/src/config.js

@@ -1,5 +1,5 @@
 export const ProjectName = 'ghs'
-export const APIHOST = 'http://api.shop.hzghd.com'
-export const IMGHOST = 'http://img.hzghd.com'
+export const APIHOST = 'https://api.shop.hzghd.com'
+export const IMGHOST = 'https://img.hzghd.com'
 export const CURRENT_ENV = 'dev'
 export const APP_VERSION = '1.2.90'

+ 2 - 2
ghsApp/src/ext.json

@@ -4,9 +4,9 @@
   "directCommit": false,
   "ext": {
     "account": 12362,
-    "apiHost": "http://api.shop.hzghd.com",
+    "apiHost": "https://api.shop.hzghd.com",
     "socketApiHost": "api.shop.hzghd.com",
-    "imgHost": "http://img.hzghd.com",
+    "imgHost": "https://img.hzghd.com",
     "name":"花掌柜"
   }
 }

+ 38 - 1
ghsApp/src/pagesOrder/shMethod.vue

@@ -22,6 +22,41 @@
           <input type="text" v-model="form.name" maxlength="4" @focus="form.name = ''" class="tui-input" placeholder="请填写名称,最多4个字" />
         </tui-list-cell>
 
+        <!-- 算运费方式 (仅当选择跑腿 form.style === 2 时展示) -->
+        <tui-list-cell class="line-cell" :hover="false" v-if="form.style === 2">
+          <view class="tui-title">算运费方式</view>
+          <view class="btn-group">
+            <button
+              class="admin-button-com middle"
+              :class="[form.calcType == 0 ? 'blue' : 'default']"
+              @click="form.calcType = 0"
+            >
+              用跑腿
+            </button>
+            <button
+              class="admin-button-com middle"
+              :class="[form.calcType == 1 ? 'blue' : 'default']"
+              @click="form.calcType = 1"
+              style="margin-left: 20upx;"
+            >
+              用自定义
+            </button>
+          </view>
+        </tui-list-cell>
+
+        <!-- 跑腿提供方 (仅当选择跑腿 form.style === 2 时展示) -->
+        <tui-list-cell class="line-cell" :hover="false" v-if="form.style === 2">
+          <view class="tui-title">跑腿提供方</view>
+          <view class="btn-group">
+            <button
+              class="admin-button-com middle default"
+              @click="pageTo({ url: '/admin/delivery/deliveryManage' })"
+            >
+              管理
+            </button>
+          </view>
+        </tui-list-cell>
+
         <!-- 状态 -->
         <tui-list-cell class="line-cell" :hover="false">
           <view class="tui-title">状态</view>
@@ -133,7 +168,7 @@
             <view class="tui-title">起步价</view>
             <view class="input-row">
               <input type="digit" v-model="form.startKm" @focus="form.startKm = ''" class="tui-input-sm" placeholder="0" />
-              <text class="unit-text">km内</text>
+              <text class="unit-text">公里内</text>
               <input type="digit" v-model="form.startPrice" @focus="form.startPrice = ''" class="tui-input-sm" placeholder="0.00" />
               <text class="unit-text">元</text>
             </view>
@@ -274,6 +309,7 @@ export default {
         id: 0,
         style: 0,
         name: "",
+        calcType: 0,
         status: 1,
         sort: 0,
         minAmount: 0.00,
@@ -352,6 +388,7 @@ export default {
               id: data.id || 0,
               style: style,
               name: data.name || "",
+              calcType: data.calcType != null ? Number(data.calcType) : 0,
               status: data.status != null ? Number(data.status) : 1,
               sort: data.sort != null ? Number(data.sort) : 0,
               minAmount: data.minAmount != null ? parseFloat(data.minAmount) : 0.00,

+ 6 - 6
ghsApp/src/static/iconfont/iconfont.css

@@ -1,11 +1,11 @@
 @font-face {
   font-family: 'iconfont';  /* project id 1525256 */
-  src: url('http://api.shop.hzghd.com/iconfont/font_1525256_6bxwphhntqh.eot');
-  src: url('http://api.shop.hzghd.com/iconfont/font_1525256_6bxwphhntqh.eot?#iefix') format('embedded-opentype'),
-  url('http://api.shop.hzghd.com/iconfont/font_1525256_6bxwphhntqh.woff2') format('woff2'),
-  url('http://api.shop.hzghd.com/iconfont/font_1525256_6bxwphhntqh.woff') format('woff'),
-  url('http://api.shop.hzghd.com/iconfont/font_1525256_6bxwphhntqh.ttf') format('truetype'),
-  url('http://api.shop.hzghd.com/iconfont/font_1525256_6bxwphhntqh.svg#iconfont') format('svg');
+  src: url('https://api.shop.hzghd.com/iconfont/font_1525256_6bxwphhntqh.eot');
+  src: url('https://api.shop.hzghd.com/iconfont/font_1525256_6bxwphhntqh.eot?#iefix') format('embedded-opentype'),
+  url('https://api.shop.hzghd.com/iconfont/font_1525256_6bxwphhntqh.woff2') format('woff2'),
+  url('https://api.shop.hzghd.com/iconfont/font_1525256_6bxwphhntqh.woff') format('woff'),
+  url('https://api.shop.hzghd.com/iconfont/font_1525256_6bxwphhntqh.ttf') format('truetype'),
+  url('https://api.shop.hzghd.com/iconfont/font_1525256_6bxwphhntqh.svg#iconfont') format('svg');
 }
 
 .iconfont {

+ 162 - 341
hdApp/src/admin/billing/affirmSh.vue

@@ -129,7 +129,7 @@
 						</tui-list-cell>
 
 						<!-- 跑腿平台报价列表 -->
-						<tui-list-cell v-if="form.sendType == 2 && ghsInfo.openIntraCity == 1" class="line-cell" :hover="false">
+						<tui-list-cell v-if="form.sendType == 2 && currentShMethod && Number(currentShMethod.calcType) == 0 && ghsInfo.openIntraCity == 1" class="line-cell" :hover="false">
 							<view v-if="ghsInfo.openIntraCity == 1 && deliveryQuotes.length > 0" class="delivery-quotes-container">
 								<view class="delivery-quotes-grid">
 								<view
@@ -151,24 +151,24 @@
 							</view>
 							<view v-else style="text-align: center; padding: 20upx 0;">
 								<text v-if="validAddress">正在获取运费...</text>
-								<text v-else style="color:red;font-weight:bold;font-size:32upx;" @click="modifyAddress">收货地址缺失,请填写</text>
+								<text v-else style="color:red;font-weight:bold;font-size:32upx;" @click="modifyAddress">请完善收货地址</text>
 							</view>
 						</tui-list-cell>
 
 						<!-- 距离展示 -->
-						<tui-list-cell class="line-cell" :hover="false" v-if="displaySendCost && Number(showDistance)>0">
+						<tui-list-cell class="line-cell" :hover="false" v-if="form.sendType == 2 && Number(showDistance)>0">
 							<view class="tui-title">距离</view>
 							<text v-if="showDistance > 100" style="color: #3385FF">{{ (showDistance/1000).toFixed(1) }}公里</text>
 							<text v-else style="color: #3385FF">{{ showDistance }} 米</text>
-							<text v-if="showDeliveryPolicy" class="delivery-policy-link" @click="showDeliveryPolicyModal">免跑腿费条件</text>
 						</tui-list-cell>
 
 						<!-- 跑腿费 -->
-						<tui-list-cell class="line-cell" :hover="false" v-if="displaySendCost">
+						<tui-list-cell class="line-cell" :hover="false" v-if="form.sendType == 2">
 							<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">¥0【免跑腿费】</text>
+								<text :class="isFreePt ? 'delivery-price-free' : 'delivery-price-normal'">¥{{ form.sendCost }}</text>
+								<text v-if="isFreePt" class="free-delivery-tag">¥0</text>
+								<text class="delivery-policy-link" @click="showDeliveryPolicyModal">免运费条件</text>
 							</view>
 						</tui-list-cell>
 
@@ -195,8 +195,9 @@
 
 						<!-- 备注 -->
 						<tui-list-cell class="line-cell" :hover="false" :arrow="false">
-							<textarea style="height: 100upx" v-model="remark" placeholder="这里写备注"/>
+							<textarea style="height: 80upx" v-model="remark" placeholder="这里写备注"/>
 						</tui-list-cell>
+
 					</view>
 				</block>
 
@@ -225,7 +226,7 @@
 
 		<uni-popup ref="deliveryPolicyPopup" type="center" background-color="#fff">
 			<view class="policy-popup-content">
-				<view class="policy-title">免费配送条件</view>
+				<view class="policy-title">免费条件</view>
 				<scroll-view scroll-y="true" class="policy-scroll">
 					<view class="policy-list">
 						<block v-for="(item, index) in deliveryPolicyList" :key="index">
@@ -274,7 +275,7 @@ import appFormSend from "@/components/app-form-send";
 import appSendTime from "@/components/app-send-time";
 const formUtil = require("@/utils/formValidation.js");
 import AppDatePicker from "@/components/app-date-picker";
-import { getGhsDataApi,getWlList } from "@/api/ghs";
+import { getGhsDataApi,getWlList,calcCustomPtFee } from "@/api/ghs";
 import { createOrder,getShMethod } from "@/api/purchase";
 import { mapActions, mapGetters } from "vuex";
 import { shopHouponHas } from '@/api/coupon'
@@ -371,32 +372,11 @@ export default {
 			this.form.hbId = 0
 			this.hasCoupon()
 		}
-		if(this.isNewShMethod){
-			this.getCurrentShop(() => {
-				if (Number(this.form.sendType) === 2 && this.displaySendCost && this.validAddress) {
-					this.getDeliveryQuotes()
-				}
-			})
-		}else{
-			if(this.form.sendType == 2){
-				//计算运费
-				//this.calcFreight()
-
-				if(this.displaySendCost == true){
-					//各跑腿平台报价
-					this.getDeliveryQuotes()
-				}
-			}
-			//修改地址更新
-			this.getCurrentShop()
-		}
+		//修改地址重新返回页面时,重新获取当前门店信息
+		this.modifyAddressToggle()
 	},
 	computed: {
 		...mapGetters(["getMerchantInfo", "getLoginInfo","getDictionariesInfo"]),
-		/** 当前门店是否使用 getShMethod 配送业务面板 */
-		isNewShMethod() {
-			return this.ghsInfo && this.ghsInfo.useNewShMethod == 1
-		},
 		visibleMethodList() {
 			return (this.methodList || [])
 				.filter(item => Number(item.status) === 1)
@@ -409,6 +389,19 @@ export default {
 			}
 			return null
 		},
+		showDeliveryPolicy() {
+			const method = this.currentShMethod
+			if (!method) return false
+			let rules = method.reduceRules
+			if (typeof rules === 'string') {
+				try {
+					rules = JSON.parse(rules)
+				} catch (e) {
+					rules = []
+				}
+			}
+			return Array.isArray(rules) && rules.length > 0
+		},
 		showShMethodExtraFee() {
 			const method = this.currentShMethod
 			if (!method || !this.checkShMethodBelowMinimum(method)) {
@@ -459,7 +452,7 @@ export default {
 				.sort((a, b) => Number(a.sort) - Number(b.sort))
 		},
 		runnerFeeAmount() {
-			if (!this.displaySendCost || this.isFreeDelivery) {
+			if (this.isFreePt) {
 				return 0
 			}
 			return Number(this.form.sendCost) || 0
@@ -484,157 +477,51 @@ export default {
 			}
 			return false
 		},
-		/**
-		 * 显示跑腿费
-		 * @returns {boolean}
-		 */
-		displaySendCost(){
-			if(this.form.sendType == 2){
-				if([0, 2].includes(this.ghsInfo.openIntraCity)){
-					return false
-				}else{
-					return true
+		//判断是否免跑腿费
+		isFreePt(){
+			const method = this.currentShMethod
+			if (!method) return false
+
+			let rules = method.reduceRules
+			if (typeof rules === 'string') {
+				try {
+					rules = JSON.parse(rules)
+				} catch (e) {
+					rules = []
 				}
 			}
-			// 这个要先去掉,后面再考虑
-			// if(this.ghsInfo.pfLevel && this.ghsInfo.pfLevel == 1){
-			// 	return true
-			// }
-			return false
-		},
-		/**
-		 * 判断是否免跑腿费
-		 * @returns {boolean}
-		 */
-		isFreeDelivery(){
-			// 不显示跑腿费时,不需要判断
-			if(this.displaySendCost == false){
-				return false
-			}
-			//地址有问题时,不展示免费跑腿情况
-			if(this.validAddress == false){
+
+			if (!Array.isArray(rules) || rules.length === 0) {
 				return false
 			}
 
-			// 条件1: 比较距离与免费公里数
-			// showDistance单位是米,hcFreeKm单位是千米
+			const flowerCount = Number(this.allCountFun.bigLength) || 0
+			const flowerPrice = Number(this.allPriceFun) || 0
 			const distanceInMeters = Number(this.showDistance) || 0
-			const freeKmInMeters = (Number(this.ghsInfo.hcFreeKm) || 0) * 1000
-			
-			// 如果距离小于免费公里数,则免运费
-			if(distanceInMeters < freeKmInMeters){
-				return true
-			}
-			
-			// 条件2: 如果距离大于免费公里数,判断hcMap
-			if(distanceInMeters > freeKmInMeters){
-				if(this.ghsInfo.hcMap && typeof this.ghsInfo.hcMap == 'string'){
-					this.ghsInfo.hcMap = JSON.parse(this.ghsInfo.hcMap)
-				}
 
-				// 判断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){
-							console.log('满足免运费条件:',flowerCount,ruleNum,flowerPrice,rulePrice,distanceInMeters,ruleDistance)
-							return true
-						}
-					}
-				}else{
-					if(this.ghsInfo.hcMap && Array.isArray(this.ghsInfo.hcMap) && this.ghsInfo.hcMap.length == 0){
-						console.log('hcMap数据为空')
-						return false
-					}
-					
-					console.log('this.ghsInfo.hcMap: ',this.ghsInfo.hcMap)
-					console.log('hcMap数据格式出问题了')
+			for (const rule of rules) {
+				const meetNum = Number(rule.meetNum) || 0
+				const meetAmount = Number(rule.meetAmount) || 0
+				const freeKm = Number(rule.freeKm) || 0
+				const freeKmInMeters = freeKm * 1000
+
+				if (freeKmInMeters > 0 && flowerCount >= meetNum && flowerPrice >= meetAmount && distanceInMeters <= freeKmInMeters) {
+					return true
 				}
 			}
-			
+
 			return false
 		},
-		/**
-		 * 是否显示包配送政策
-		 */
-		showDeliveryPolicy() {
-			if (!this.ghsInfo) return false
-			
-			// 检查 hcFreeKm
-			const hasFreeKm = this.ghsInfo.hcFreeKm ?Number(this.ghsInfo.hcFreeKm):0
-			
-			// 检查 hcMap
-			let hasPolicy = false
-			let mapData = this.ghsInfo.hcMap
-			if(mapData && typeof mapData == 'string'){
-				try {
-					mapData = JSON.parse(mapData)
-				} catch(e) {
-					// 解析失败忽略
-				}
-			}
-			if(mapData && Array.isArray(mapData) && mapData.length > 0){
-				hasPolicy = true
-			}
-			if(hasFreeKm>0){
-				hasPolicy = true
-			}
-			return hasPolicy
-		},
 		/**
 		 * 计算总金额
 		 * @returns {number}
 		 */
 		modifyPrice(){
-			if (this.isNewShMethod) {
-				return this.panelTotalPrice
-			}
-			let allPrice = this.allPriceFun.toFixed(2)
-			allPrice = Number(allPrice)
-			let price = allPrice
-
-			// 判断是否需要加跑腿费
-			if(this.displaySendCost == true){
-				// 如果不是免跑腿费,则加上跑腿费
-				if(!this.isFreeDelivery){
-					price = price + this.form.sendCost
-				}
-			}
-			this.needAddPackCost = false
-			if(this.ghsInfo.pfLevel && this.ghsInfo.pfLevel == 1){
-				//不是同城配送的,不是到店自取的,并且不是第一次下单,才算打包费
-				if(this.form.transType != 4 && this.form.transType != 5 && this.ghsInfo.needAddPackFreight == 1){
-					//昆明发全国
-					this.needAddPackCost = true
-					price = price + this.form.packCost
-				}
-			}else{
-				//同城配送
-				if(this.form.sendType == 4){
-					//设置了订单金额低200需要付包装费,当前只付一次
-					if(Number(this.lackExpend) > 0 && allPrice < Number(this.lackExpend)){
-						price = price + this.form.packCost
-						this.needAddPackCost = true
-					}
-				}
-			}
-			price = Number(price)
-			price = price.toFixed(2)
-			price = parseFloat(price)
-			return price
+			return this.panelTotalPrice
 		}
 	},
 	methods: {
-		/** 初始化配送业务面板:拉取配送配置 */
+		//初始化配送业务面板:拉取配送配置
 		loadShMethods(ghsId) {
 			getShMethod({ ghsId: ghsId }).then(res => {
 				if (res.code == 1) {
@@ -669,18 +556,108 @@ export default {
 			this.selectedMethodIndex = index
 			const sendType = Number(list[index].style)
 			this.form.sendType = sendType
-			if (sendType === 2) {
-				if (this.displaySendCost && Number(this.ghsInfo.openIntraCity) === 1 && this.validAddress) {
+
+			//计算跑腿费,二种方式,一个通过跑腿接口,一个通过自定义计费
+			this.calcPtFee()
+
+			this.syncPackCostByMethod()
+		},
+		modifyAddressToggle(){
+			currentShop().then(res=>{
+				if(res.code == 1){
+					this.shopInfo = res.data
+					if(!this.$util.isEmpty(this.shopInfo.lat) && !this.$util.isEmpty(this.shopInfo.long) && !this.$util.isEmpty(this.shopInfo.address)){
+						this.validAddress = true
+						//计算跑腿费,二种方式,一个通过跑腿接口,一个通过自定义计费
+						this.calcPtFee()
+					}
+				}
+			})
+		},
+		//计算跑腿费,二种方式,一个通过跑腿接口,一个通过自定义计费
+		calcPtFee(){
+			if(this.form.sendType == 2 && this.validAddress && this.currentShMethod){
+				if(Number(this.currentShMethod.calcType) == 0){
 					this.getDeliveryQuotes()
+				}else{
+					this.getCustomPtFee()
 				}
-			} else {
+			}else{
 				this.deliveryQuotes = []
 				this.selectedDeliveryIndex = -1
 				this.selectedDeliveryData = null
 				this.form.sendCost = 0
 				this.showDistance = 0
 			}
-			this.syncPackCostByMethod()
+		},
+		/** 获取自定义计费跑腿费用与距离 */
+		getCustomPtFee(){
+			this.deliveryQuotes = []
+			this.selectedDeliveryIndex = -1
+			this.selectedDeliveryData = null
+			const ghsId = this.option.id || (this.ghsInfo && this.ghsInfo.id) || 0
+			calcCustomPtFee({ id: ghsId, sendType: 2 }).then(res => {
+				if (res.code == 1 && res.data) {
+					this.form.sendCost = parseFloat(res.data.sendCost) || 0
+					this.showDistance = Number(res.data.distance) || 0
+				} else {
+					this.form.sendCost = 0
+					this.showDistance = 0
+					if (res.msg) {
+						uni.showToast({ title: res.msg, icon: 'none' })
+					}
+				}
+			}).catch(() => {
+				this.form.sendCost = 0
+				this.showDistance = 0
+				uni.showToast({ title: '获取自定义运费失败', icon: 'none' })
+			})
+		},
+		// 展示包配送政策弹窗
+		showDeliveryPolicyModal() {
+			this.deliveryPolicyList = []
+			const method = this.currentShMethod
+			if (method) {
+				let rules = method.reduceRules
+				if (typeof rules === 'string') {
+					try {
+						rules = JSON.parse(rules)
+					} catch (e) {
+						rules = []
+					}
+				}
+				if (Array.isArray(rules) && rules.length > 0) {
+					rules.forEach(rule => {
+						const meetNum = Number(rule.meetNum) || 0
+						const meetAmount = Number(rule.meetAmount) || 0
+						const freeKm = Number(rule.freeKm) || 0
+						
+						let text = ''
+						if (meetNum > 0 && meetAmount > 0) {
+							text = `满${meetNum}扎和${meetAmount}元,${freeKm}公里内免跑腿费`
+						} else if (meetNum > 0) {
+							text = `满${meetNum}扎,${freeKm}公里内免跑腿费`
+						} else if (meetAmount > 0) {
+							text = `满${meetAmount}元,${freeKm}公里内免跑腿费`
+						} else if (freeKm > 0) {
+							text = `${freeKm}公里内免跑腿费`
+						}
+						if (text) {
+							this.deliveryPolicyList.push(text)
+						}
+					})
+				}
+			}
+			
+			if (this.deliveryPolicyList.length === 0) {
+				uni.showToast({
+					title: '暂无详细配送政策',
+					icon: 'none'
+				})
+				return
+			}
+			
+			this.$refs.deliveryPolicyPopup.open()
 		},
 		syncPackCostByMethod() {
 			const method = this.currentShMethod
@@ -725,44 +702,6 @@ export default {
 			this.$refs.wlPopupRef.close()
 		},
 		...mapActions(["initMerchantInfo"]),
-		// 展示包配送政策弹窗
-		showDeliveryPolicyModal() {
-			this.deliveryPolicyList = []
-			
-			// 1. hcFreeKm 规则
-			if (this.ghsInfo.hcFreeKm && Number(this.ghsInfo.hcFreeKm) > 0) {
-				this.deliveryPolicyList.push(`${Number(this.ghsInfo.hcFreeKm)}公里内免费配送`)
-			}
-			
-			// 2. hcMap 规则
-			let mapData = this.ghsInfo.hcMap
-			if(mapData && typeof mapData == 'string'){
-				try {
-					mapData = JSON.parse(mapData)
-				} catch(e) {
-					mapData = []
-				}
-			}
-			if(mapData && Array.isArray(mapData) && mapData.length > 0){
-				mapData.forEach(rule => {
-					const num = Number(rule.num) || 0
-					const price = Number(rule.price) || 0
-					const distance = Number(rule.distance) || 0
-					
-					this.deliveryPolicyList.push(`满${num}扎${price}元,${distance}公里内免费配送`)
-				})
-			}
-			
-			if (this.deliveryPolicyList.length === 0) {
-				uni.showToast({
-					title: '暂无详细配送政策',
-					icon: 'none'
-				})
-				return
-			}
-			
-			this.$refs.deliveryPolicyPopup.open()
-		},
 		closeDeliveryPolicy() {
 			this.$refs.deliveryPolicyPopup.close()
 		},
@@ -770,75 +709,6 @@ export default {
 			this.$refs.selectFlowerNumRef.close()
 			this.lackList = []
 		},
-		changeTransType(num){
-			let that = this
-			this.form.transType = num
-			this.form.sendCost = 0
-			//第二次下单不算打包费和运费
-			if(this.ghsInfo.needAddPackFreight == 0){
-				this.form.sendCost = 0
-			}else{
-				if(this.transCost && !this.$util.isEmpty(this.transCost)){
-					let weight = this.allCountFun.weight ? Number(this.allCountFun.weight) : 0
-					let totalNum = this.allCountFun.bigLength ? Number(this.allCountFun.bigLength) : 0
-					for (const ele of this.transCost) {
-						if(ele.sign == num){
-							if(num == 2){
-								//冷链物流
-								let llOption = ele.option ? ele.option : ''
-								if(!this.$util.isEmpty(llOption)){
-
-									let long = llOption.length
-									let bigInfo = llOption[long-1]
-									let bigNum = bigInfo.num
-									let bigAmount = bigInfo.amount
-									let bs = parseInt(totalNum/bigNum)
-									if(bs > 0){
-										this.form.sendCost = this.form.sendCost + (bs*bigAmount)
-										this.form.sendCost = parseFloat(this.form.sendCost.toFixed(2))
-										totalNum = totalNum - (bs*bigNum)
-										totalNum = parseFloat(totalNum.toFixed(2))
-									}
-									for (const ele of llOption){
-										if(Number(ele.num) >= Number(totalNum)){
-											this.form.sendCost = Number(this.form.sendCost)+Number(ele.amount)
-											break
-										}
-									}
-
-								}
-							}else{
-								//其它物流
-								let perKiloCost = ele.perKiloCost?Number(ele.perKiloCost):0
-								let sendCost = weight*perKiloCost
-								sendCost = parseFloat(sendCost.toFixed(2))
-								this.form.sendCost = sendCost
-							}
-							break
-						}
-					}
-				}
-			}
-		},
-		changeSendType(num){
-			this.form.sendType = num
-			if(num == 2){
-				//计算运费
-				//this.calcFreight() //废弃
-
-				if(this.displaySendCost && this.ghsInfo.openIntraCity == 1){
-					if(!this.$util.isEmpty(this.shopInfo.lat) && !this.$util.isEmpty(this.shopInfo.long) && !this.$util.isEmpty(this.shopInfo.address)){
-						this.getDeliveryQuotes()//各跑腿平台报价
-					}
-				}
-			} else {
-				// 切换到其他配送方式时清空报价数据
-				this.deliveryQuotes = []
-				this.selectedDeliveryIndex = -1
-				this.selectedDeliveryData = null
-				this.form.sendCost = 0
-			}
-		},
 		// 获取跑腿平台报价
 		getDeliveryQuotes() {
 			this.deliveryQuotes = []
@@ -991,8 +861,6 @@ export default {
 			let that = this
 			this.getDetailData()
 
-			// this.getCurrentShop() //重复执行了,注释掉
-
 			getWlList({id:this.option.id}).then(res=>{
 				if(res.code == 1){
 					that.wlList = res.data.list ? res.data.list : []
@@ -1000,19 +868,6 @@ export default {
 			})
 
 		},
-		getCurrentShop(callback){
-			currentShop().then(res=>{
-				if(res.code == 1){
-					this.shopInfo = res.data
-					if(!this.$util.isEmpty(this.shopInfo.lat) && !this.$util.isEmpty(this.shopInfo.long) && !this.$util.isEmpty(this.shopInfo.address)){
-						this.validAddress = true
-					}
-				}
-				if (typeof callback === "function") {
-					callback()
-				}
-			})
-		},
 		addEvents(item) {
 			if(item.variety == 0){
 				const ratio = Number(item.ratio);
@@ -1080,35 +935,6 @@ export default {
 
 				this.loadShMethods(id)
 
-				if(!that.isNewShMethod){
-					//杭州斗南鲜花批发部不需要显示免费配送
-					if(that.ghsInfo.shopId && Number(that.ghsInfo.shopId) == 4608){
-						that.form.sendType = 1
-					}
-					//万花田济南仓默认自取
-					if(that.ghsInfo.shopId && Number(that.ghsInfo.shopId) == 90985){
-						that.form.sendType = 1
-					}
-					//鼎盛花卉默认自取
-					if(that.ghsInfo.shopId && Number(that.ghsInfo.shopId) == 36919){
-						that.form.sendType = 1
-					}
-					//天天鲜花虎门店默认自取
-					if(that.ghsInfo.shopId && Number(that.ghsInfo.shopId) == 91053){
-						that.form.sendType = 1
-					}
-					if(res.data && res.data.shopId == 14636){
-						//花瀚鲜花供应链默认冷链
-						this.changeTransType(2)
-					}else if(res.data && res.data.shopId == 3){
-						//石头花艺
-						this.changeTransType(2)
-					}else if(res.data && res.data.shopId == 29136){
-						this.changeTransType(0)
-					}else{
-						this.changeTransType(4)
-					}
-				}
 				that.ghsInfoLoaded = true
 			})
 
@@ -1140,23 +966,18 @@ export default {
 			})
 
 			if(this.ghsInfo.pfLevel == 0){
-				if (this.isNewShMethod) {
-					/** 提交前校验,失败时提示并返回 false */
-					if (Number(this.form.sendType) === 3 && this.$util.isEmpty(this.form.wlName)) {
-						this.$msg("请填选物流")
-						return false
-					}
-					const method = this.currentShMethod
-					if (method && Number(method.unMeet) === 1 && this.checkShMethodBelowMinimum(method)) {
-						this.$msg("未达到最低消费,不能下单")
-						return false
-					}
-				} else if(this.form.sendType == 3){
-					if (this.$util.isEmpty(this.form.wlName)){
-						this.$msg('请填选物流')
-						return false
-					}
+				
+				/** 提交前校验,失败时提示并返回 false */
+				if (Number(this.form.sendType) === 3 && this.$util.isEmpty(this.form.wlName)) {
+					this.$msg("请填选物流")
+					return false
 				}
+				const method = this.currentShMethod
+				if (method && Number(method.unMeet) === 1 && this.checkShMethodBelowMinimum(method)) {
+					this.$msg("未达到最低消费,不能下单")
+					return false
+				}
+				
 			}
 
 			//多颜色
@@ -1325,7 +1146,7 @@ export default {
 	/* #endif */
 	.affirm-view {
 		flex: 1;
-		padding: 20upx;
+		padding: 20upx 20upx 100upx 20upx;
 		background-color: #f0f2f6;
 		.commodity-view {
 			display: flex;
@@ -1722,14 +1543,14 @@ export default {
 
 .free-delivery-tag {
 	color: #3385FF;
-	margin-left: 5upx;
+	margin-left: 20upx;
 }
 
 .delivery-policy-link {
 	color: rgb(201, 52, 52);
 	font-size: 30upx;
-	margin-left: 30upx;
-	font-weight:bold;
+	margin-left: 20upx;
+	font-weight: bold;
 	text-decoration: underline;
 }
 

+ 118 - 2
hdApp/src/admin/ghsProduct/components/sel-popup.vue

@@ -1,4 +1,9 @@
 <template>
+  <!--
+    用途:商品购买/加购弹窗中的加减数量与规格选择
+    谁用:花店采购端/客户
+    解决什么问题:提供实体按钮样式的数量加减与输入,提高点击体验
+  -->
   <div class="sel-popup">
     <bottom-popup class="popup-wrap" :show="show" @close="close()">
       <app-close @close="close()" />
@@ -15,7 +20,27 @@
           <div class="tui-scrolldiv-box">
             <div class="tui-number-box tui-bold tui-attr-title">
               <div class="tui-attr-title">数量</div>
-              <number-box :max="maxStock" :min="1" :value="buyNum" @change="change"></number-box>
+              <div class="custom-step-box">
+                <button 
+                  class="step-btn step-btn-minus" 
+                  :class="{ 'step-btn-disabled': buyNum <= 1 }"
+                  :disabled="buyNum <= 1" 
+                  @click="reduceNum"
+                >-</button>
+                <input 
+                  class="step-input" 
+                  type="number" 
+                  :value="buyNum" 
+                  @input="onNumInput" 
+                  @blur="onNumBlur" 
+                />
+                <button 
+                  class="step-btn step-btn-plus" 
+                  :class="{ 'step-btn-disabled': buyNum >= maxStock }"
+                  :disabled="buyNum >= maxStock" 
+                  @click="addNum"
+                >+</button>
+              </div>
             </div>
           </div>
         </scroll-view>
@@ -78,6 +103,34 @@ export default {
     change(e) {
       this.$emit("change", e);
     },
+    // 减少购买数量
+    reduceNum() {
+      if (this.buyNum <= 1) return;
+      const val = this.buyNum - 1;
+      this.$emit("change", { value: val });
+    },
+    // 增加购买数量
+    addNum() {
+      if (this.buyNum >= this.maxStock) return;
+      const val = this.buyNum + 1;
+      this.$emit("change", { value: val });
+    },
+    // 监听输入框实时变化
+    onNumInput(e) {
+      let val = parseInt(e.detail.value, 10);
+      if (isNaN(val)) return;
+      this.$emit("change", { value: val });
+    },
+    // 输入框失焦时纠正校验边界
+    onNumBlur(e) {
+      let val = parseInt(e.detail.value, 10);
+      if (isNaN(val) || val < 1) {
+        val = 1;
+      } else if (val > this.maxStock) {
+        val = this.maxStock;
+      }
+      this.$emit("change", { value: val });
+    },
     close() {
       this.$emit("close")
     },
@@ -121,6 +174,11 @@ export default {
     .button-com {
       width: 80%;
       font-size: 32upx;
+      padding: 32.5upx 0;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      line-height: 1;
     }
   }
 
@@ -166,6 +224,7 @@ export default {
   .tui-attr-title {
     padding: 10upx 0;
     color: #333;
+    font-size: 36upx;
   }
 
   .tui-attr-box {
@@ -212,8 +271,65 @@ export default {
     display: flex;
     align-items: center;
     justify-content: space-between;
-    padding: 20upx 0 30upx 0;
+    padding: 20upx 0 65upx 0;
     box-sizing: border-box;
+
+    .custom-step-box {
+      display: flex;
+      align-items: center;
+
+      .step-btn {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        width: 80upx;
+        height: 76upx;
+        margin: 0;
+        padding: 0;
+        border-radius: 16upx;
+        font-size: 44upx;
+        font-weight: bold;
+        line-height: 1;
+        box-sizing: border-box;
+
+        &::after {
+          border: none;
+        }
+      }
+
+      .step-btn-minus {
+        background-color: #f2f4f7;
+        color: #333333;
+        border: 1upx solid #e2e8f0;
+      }
+
+      .step-btn-plus {
+        background-color: #049e2c;
+        color: #ffffff;
+        box-shadow: 0 4upx 12upx rgba(4, 158, 44, 0.25);
+      }
+
+      .step-btn-disabled {
+        background-color: #f7f8fa !important;
+        color: #cccccc !important;
+        border-color: #eeeeee !important;
+        box-shadow: none !important;
+        opacity: 0.6;
+      }
+
+      .step-input {
+        width: 130upx;
+        height: 76upx;
+        margin: 0 16upx;
+        background-color: #f8fafc;
+        border: 1upx solid #e2e8f0;
+        border-radius: 16upx;
+        text-align: center;
+        font-size: 34upx;
+        font-weight: bold;
+        color: #333333;
+      }
+    }
   }
 }
 </style>

+ 90 - 1
hdApp/src/admin/ghsProduct/detail.vue

@@ -9,6 +9,7 @@
         <view class="tui-pro-title app-size-32">
           <text v-if="productInfo.presell == 1">【预售】</text>
           <text v-if="Number(productInfo.discountPrice) > 0">【推荐】</text>
+          <text v-if="productInfo.variety == 1" class="variety-tag">【多颜色】</text>
           {{ productInfo.name}}
         </view>
         <button
@@ -103,10 +104,48 @@ export default {
       previewContent: [],
       id:0,
       shopId:0,
-      ghsInfo:{}
+      ghsInfo:{},
+      xjData: {},
+      hasColorInfo: {}
     };
   },
   onLoad(option) {},
+  onShow() {
+    // 监听选颜色页面 (xj.vue) 确认后的返回事件与数据
+    if (this.xjData && this.xjData.hasUpdate == 1) {
+      this.customData = (this.hasColorInfo && this.hasColorInfo.id) ? this.hasColorInfo : this.productInfo;
+      if (this.xjData.cancel == 1) {
+        const customData = {
+          ...this.customData,
+          bigCount: 0,
+          smallCount: 0,
+          itemPrice: this.customData.price
+        };
+        this.addItemEvent(customData);
+      } else {
+        const num = Number(this.xjData.stock) || 0;
+        const price = this.xjData.price || this.customData.price;
+        const customData = {
+          ...this.customData,
+          bigCount: num,
+          smallCount: 0,
+          itemPrice: price,
+          bigPrice: price,
+          smallPrice: 0
+        };
+        this.addItemEvent(customData);
+        if (this.popupAction === 'buy') {
+          this.$util.pageTo({ url: this.getAffirmUrl(), type: 2 });
+        } else {
+          uni.showToast({
+            title: '已加入购物车',
+            duration: 1500
+          });
+        }
+      }
+    }
+    this.xjData = {};
+  },
   mounted() {},
   computed: {
     ...mapGetters({ shopUser: "getShopUser",loginInfo: "getLoginInfo" })
@@ -176,6 +215,31 @@ export default {
       }
       return true
     },
+    /**
+     * 跳转到多颜色花材选颜色页面 (xj.vue)
+     * @param {Object} info 花材商品信息
+     * @param {string} actionType 操作类型: 'cart' 加入购物车, 'buy' 立即购买
+     */
+    goToSpecialVariety(info, actionType = 'cart') {
+      this.popupAction = actionType;
+      this.hasColorInfo = info;
+      const stock = Number(info.stock) || 0;
+      if (stock <= 0) {
+        uni.showToast({ title: "没有库存", icon: "none" });
+        return;
+      }
+      const ghsId = this.option.ghsId || (this.ghsInfo && this.ghsInfo.id) || '';
+      const ptItemId = info.itemId || info.id || 0;
+      this.$util.pageTo({
+        url: "/pagesPurchase/xj",
+        query: {
+          stock: info.stock,
+          price: info.price,
+          ghsId: ghsId,
+          ptItemId: ptItemId
+        }
+      });
+    },
     openCartPopup() {
       if (!this.checkLogin()) {
         return
@@ -188,6 +252,10 @@ export default {
         this.$msg('暂无库存')
         return
       }
+      if (this.productInfo.variety == 1) {
+        this.goToSpecialVariety(this.productInfo, 'cart')
+        return
+      }
       this.popupAction = 'cart'
       this.buyNum = 1
       this.popupShow = true
@@ -204,6 +272,10 @@ export default {
         this.$msg('暂无库存')
         return
       }
+      if (this.productInfo.variety == 1) {
+        this.goToSpecialVariety(this.productInfo, 'buy')
+        return
+      }
       this.popupAction = 'buy'
       this.buyNum = 1
       this.popupShow = true
@@ -341,6 +413,23 @@ export default {
   .shop-intro {
     background: #fff;
     padding: 30upx 0 10upx 30upx;
+    .variety-tag {
+      color: #049e2c;
+      font-weight: bold;
+    }
+    .variety-action-row {
+      margin: 10upx 0 20upx;
+      .variety-button {
+        display: inline-block;
+        border: 2upx solid #049e2c;
+        border-radius: 24upx;
+        padding: 10upx 30upx;
+        font-size: 28upx;
+        color: #049e2c;
+        font-weight: bold;
+        text-align: center;
+      }
+    }
     .tui-pro-titbox {
       margin: 30upx 0 20upx;
       @include disFlex(center, space-between);

+ 4 - 3
hdApp/src/admin/home/login.vue

@@ -176,7 +176,7 @@
 import { mapActions } from "vuex";
 import { getShopInfo} from "@/utils/auth";
 import {appLogin, sendLoginSms, smsLogin} from '@/api/common'
-import { getDictionaries,postWxCode } from '@/api/mini'
+import { getDictionaries,postWxCode,getMiniMobile } from '@/api/mini'
 import { phoneLogin,wxMobileLogin } from "@/api/auth";
 import { ghsInfo } from "@/api/ghs/index";
 export default {
@@ -336,7 +336,8 @@ export default {
 		let that = this
 		let currentMiniOpenId = uni.getStorageSync('currentMiniOpenId')
 		if (e.detail.errMsg === "getPhoneNumber:ok") {
-			wxMobileLogin({ iv: e.detail.iv, encryptedData: e.detail.encryptedData,miniOpenId:currentMiniOpenId }).then(subRes => {
+			let code = e.detail.code
+			getMiniMobile({ code: code, miniOpenId: currentMiniOpenId }).then(subRes => {
 						uni.hideLoading()
 						if(subRes.data && subRes.data.hasNoOpenId && subRes.data.hasNoOpenId == 1){
 							that.$util.confirmModal({content:'网络异常,请刷新重试'},() => {
@@ -406,8 +407,8 @@ export default {
 									// H5 直接访问登录页,没有上一页,回首页
 									uni.reLaunch({ url: '/admin/home/workbench' })
 								}
+							}
 						}
-					}
 				});
 		} else {
 			this.$msg("登录失败");

+ 4 - 0
hdApp/src/api/ghs/index.js

@@ -1,5 +1,9 @@
 import https from '@/plugins/luch-request_0.0.7/request'
 
+export const calcCustomPtFee = data => {
+	return https.get('/ghs/calc-custom-pt-fee', data)
+}
+
 export const hasMoreGhs = data => {
 	return https.get('/ghs/remind-more-ghs', data)
 }

+ 7 - 0
hdApp/src/api/mini/index.js

@@ -26,6 +26,13 @@ export const getWxPhone = data => {
 	return https.post('/admin/mini-mobile', data)
 }
 
+/** *
+ * 点击授权获取手机号 mini (新接口)
+ */
+export const getMiniMobile = data => {
+	return https.post('/auth/get-mini-mobile', data)
+}
+
 export const bindAutoLogin = data => {
 	return https.post('/admin/bind-auto-login', data)
 }

+ 3 - 4
mallApp/src/manifest.json

@@ -43,8 +43,7 @@
             },
             /* SDK配置 */
             "sdkConfigs" : {
-                "speech" : {},
-                "push" : {}
+                "speech" : {}
             },
             "orientation" : [ "portrait-primary" ]
         },
@@ -96,7 +95,7 @@
             "base" : "/"
         },
         "async": {
-            "timeout": 20000
+            "timeout": 200000
         },
         "optimization": {
             "treeShaking": {
@@ -129,7 +128,7 @@
     },
     "uniStatistics" : {
         "version" : "2",
-        "enable" : true
+        "enable" : false
     },
     "app-harmony" : {
         "uniStatistics" : {

+ 6 - 6
mallApp/src/static/iconfont/iconfont.css

@@ -1,11 +1,11 @@
 @font-face {
   font-family: 'iconfont';  /* project id 1525256 */
-  src: url('http://api.shop.theflorist.cn/iconfont/font_1525256_6243f1wxe9f.eot');
-  src: url('http://api.shop.theflorist.cn/iconfont/font_1525256_6243f1wxe9f.eot?#iefix') format('embedded-opentype'),
-  url('http://api.shop.theflorist.cn/iconfont/font_1525256_6bxwphhntqh.woff2') format('woff2'),
-  url('http://api.shop.theflorist.cn/iconfont/font_1525256_6243f1wxe9f.woff') format('woff'),
-  url('http://api.shop.theflorist.cn/iconfont/font_1525256_6243f1wxe9f.ttf') format('truetype'),
-  url('http://api.shop.theflorist.cn/iconfont/font_1525256_6243f1wxe9f.svg#iconfont') format('svg');
+  src: url('https://api.shop.theflorist.cn/iconfont/font_1525256_6243f1wxe9f.eot');
+  src: url('https://api.shop.theflorist.cn/iconfont/font_1525256_6243f1wxe9f.eot?#iefix') format('embedded-opentype'),
+  url('https://api.shop.theflorist.cn/iconfont/font_1525256_6bxwphhntqh.woff2') format('woff2'),
+  url('https://api.shop.theflorist.cn/iconfont/font_1525256_6243f1wxe9f.woff') format('woff'),
+  url('https://api.shop.theflorist.cn/iconfont/font_1525256_6243f1wxe9f.ttf') format('truetype'),
+  url('https://api.shop.theflorist.cn/iconfont/font_1525256_6243f1wxe9f.svg#iconfont') format('svg');
 }
 
 .iconfont {