Sfoglia il codice sorgente

零售端-订单结算页面改版

ouyang 2 settimane fa
parent
commit
eba03508a7

+ 36 - 36
hdApp/src/admin/billing/affirmGhs.vue

@@ -215,12 +215,12 @@
 							<!-- 跑腿平台报价列表 -->
 							<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" 
+									<view
+										v-for="(item, index) in deliveryQuotes"
 										:key="index"
 										class="delivery-quote-item"
-										:class="{ 
-											'active': selectedDeliveryIndex === index, 
+										:class="{
+											'active': selectedDeliveryIndex === index,
 											'disabled': !item.isAble,
 											'fixed-width': deliveryQuotes.length <= 2
 										}"
@@ -505,12 +505,12 @@ export default {
 			// 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){
 				if(this.ghsInfo.hcMap && typeof this.ghsInfo.hcMap == 'string'){
@@ -522,13 +522,13 @@ export default {
 					// 获取花材数量和总价
 					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)
@@ -540,12 +540,12 @@ export default {
 						console.log('hcMap数据为空')
 						return false
 					}
-					
+
 					console.log('this.ghsInfo.hcMap: ',this.ghsInfo.hcMap)
 					console.log('hcMap数据格式出问题了')
 				}
 			}
-			
+
 			return false
 		},
 		/**
@@ -553,10 +553,10 @@ export default {
 		 */
 		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
@@ -637,12 +637,12 @@ export default {
 		// 展示包配送政策弹窗
 		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'){
@@ -657,11 +657,11 @@ export default {
 					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: '暂无详细配送政策',
@@ -669,7 +669,7 @@ export default {
 				})
 				return
 			}
-			
+
 			this.$refs.deliveryPolicyPopup.open()
 		},
 		closeDeliveryPolicy() {
@@ -753,7 +753,7 @@ export default {
 			this.deliveryQuotes = []
 			this.selectedDeliveryIndex = -1
 			this.selectedDeliveryData = null
-			
+
 			allDeliveryQuotes({
 				ghsId: this.option.id,
 				totalPrice: this.allPriceFun,
@@ -769,7 +769,7 @@ export default {
 						.map(item => {
 							// 价格从分转换为元
 							const price = item.price ? (item.price / 100).toFixed(1) : '0.0'
-							
+
 							// 提取平台名称(去掉括号内的内容)
 							let displayName = item.name
 							let bracketContent = ''
@@ -782,7 +782,7 @@ export default {
 							if(item.en_name == 'didi' && bracketContent != ''){
 								item.type = bracketContent
 							}
-							
+
 							return {
 								...item,
 								displayName: displayName,
@@ -791,7 +791,7 @@ export default {
 								bracketContent: bracketContent
 							}
 						})
-					
+
 					// 自动选中第一个可用的报价
 					const firstAvailableIndex = this.deliveryQuotes.findIndex(item => item.isAble)
 					if (firstAvailableIndex !== -1) {
@@ -1104,7 +1104,7 @@ export default {
 				version:10,
 				direct:direct
 			}
-			
+
 			// 如果选择了跑腿配送并且有选中的平台数据,则添加配送平台信息
 			if (this.form.sendType == 2 && this.selectedDeliveryData) {
 				params.deliveryPlatform = this.selectedDeliveryData.en_name // 平台名称
@@ -1181,9 +1181,9 @@ export default {
 			}
 			try {
 				r2 = arg2.toString().split(".")[1].length
-			} catch (e) { 
-				r2 = 0 
-			} 
+			} catch (e) {
+				r2 = 0
+			}
 			m = Math.pow(10, Math.max(r1, r2))
 			n = (r1 >= r2) ? r1 : r2;
 			return ((arg1 * m + arg2 * m) / m).toFixed(n);
@@ -1200,7 +1200,7 @@ export default {
 			} catch (e) {
 				re2 = 0;
 			}
-			m = Math.pow(10, Math.max(re1, re2)); 
+			m = Math.pow(10, Math.max(re1, re2));
 			n = (re1 >= re2) ? re1 : re2;
 			return ((arg1 * m - arg2 * m) / m).toFixed(n);
 		},
@@ -1559,13 +1559,13 @@ export default {
 	border-radius: 8upx;
 	box-sizing: border-box;
 	transition: all 0.3s;
-	
+
 	// 当只有1-2项时使用固定宽度
 	&.fixed-width {
 		flex: 0 0 220rpx;
 		width: 220rpx;
 	}
-	
+
 	.platform-name {
 		font-size: 26upx;
 		color: #333;
@@ -1582,14 +1582,14 @@ export default {
 		-webkit-box-orient: vertical;
 		word-break: break-all;
 	}
-	
+
 	.platform-price {
 		font-size: 30upx;
 		color: #333;
 		font-weight: bold;
 		margin-bottom: 4upx;
 	}
-	
+
 	.platform-type {
 		font-size: 20upx;
 		color: #868686;
@@ -1605,27 +1605,27 @@ export default {
 		-webkit-box-orient: vertical;
 		word-break: break-all;
 	}
-	
+
 	// 选中状态
 	&.active {
 		background: #09C567;
 		border-color: #09C567;
-		
+
 		.platform-name,
 		.platform-price {
 			color: #FFFFFF;
 		}
-		
+
 		.platform-type {
 			color: rgba(255, 255, 255, 0.85);
 		}
 	}
-	
+
 	// 不可用状态
 	&.disabled {
 		opacity: 0.5;
 		background: #F5F5F5;
-		
+
 		.platform-name,
 		.platform-price,
 		.platform-type {
@@ -1705,4 +1705,4 @@ export default {
 	font-size: 32upx;
 	border-radius: 40upx;
 }
-</style>
+</style>

+ 292 - 4
hdApp/src/admin/member/detail.vue

@@ -157,6 +157,61 @@
         <view class="tabs-name">充值</view>
       </view>
     </view>
+
+    <!-- 送货上门规则:单独设置时覆盖 xhPsMethod(style=0) 总配置 -->
+    <view class="module-com home-rule-wrap">
+      <view class="home-rule-inner">
+        <tui-list-cell class="line-cell" :hover="false">
+          <view class="tui-title">送货上门规则</view>
+          <view class="home-rule-actions">
+            <button class="admin-button-com middle" :class="[homeForm.homeRule == 0 ? 'blue' : 'default']" @click="changeHomeRuleBtn(0)">遵循总设置</button>
+            <button class="admin-button-com middle home-rule-btn-gap" :class="[homeForm.homeRule == 1 ? 'blue' : 'default']" @click="changeHomeRuleBtn(1)">单独设置</button>
+          </view>
+        </tui-list-cell>
+        <!-- 单独设置:可编辑客户级覆盖 -->
+        <block v-if="homeForm.homeRule == 1">
+          <tui-list-cell class="line-cell" :hover="false">
+            <view class="tui-title">送货上门</view>
+            <view class="home-rule-actions">
+              <button class="admin-button-com middle" :class="[homeForm.home == 1 ? 'blue' : 'default']" @click="changeHomeBtn(1)">启用</button>
+              <button class="admin-button-com middle home-rule-btn-gap" :class="[homeForm.home == 0 ? 'blue' : 'default']" @click="changeHomeBtn(0)">禁用</button>
+            </view>
+          </tui-list-cell>
+          <tui-list-cell class="line-cell" :hover="false" v-if="homeForm.home == 1">
+            <view class="tui-title">最低消费金额</view>
+            <view class="home-rule-input-row">
+              <input v-model="homeForm.homeAmount" @click="homeForm.homeAmount = ''" placeholder-class="phcolor" class="home-rule-input" confirm-type="go" placeholder="不限制填0" type="digit" />
+              <text class="home-rule-unit">元</text>
+            </view>
+            <button class="admin-button-com blue middle" @tap="changeHomeParams">确定</button>
+          </tui-list-cell>
+          <tui-list-cell class="line-cell" :hover="false" v-if="homeForm.home == 1">
+            <view class="tui-title">最低消费扎数</view>
+            <view class="home-rule-input-row">
+              <input v-model="homeForm.homeNum" @click="homeForm.homeNum = ''" placeholder-class="phcolor" class="home-rule-input" confirm-type="go" placeholder="不限制填0" type="number" />
+              <text class="home-rule-unit">扎</text>
+            </view>
+            <button class="admin-button-com blue middle" @tap="changeHomeParams">确定</button>
+          </tui-list-cell>
+          <tui-list-cell class="line-cell" :hover="false" v-if="homeForm.home == 1">
+            <view class="tui-title">不满最低要求</view>
+            <view class="home-rule-unmeet-group">
+              <button class="admin-button-com middle" :class="[homeForm.homeUnMeet == 0 ? 'blue' : 'default']" @click="homeUnMeetBtn(0)">收运费</button>
+              <button class="admin-button-com middle home-rule-unmeet-gap" :class="[homeForm.homeUnMeet == 2 ? 'blue' : 'default']" @click="homeUnMeetBtn(2)">收包装费</button>
+              <button class="admin-button-com middle home-rule-unmeet-gap" :class="[homeForm.homeUnMeet == 1 ? 'blue' : 'default']" @click="homeUnMeetBtn(1)">不能买</button>
+            </view>
+          </tui-list-cell>
+          <tui-list-cell class="line-cell" :hover="false" v-if="homeForm.home == 1 && homeForm.homeUnMeet != 1">
+            <view class="tui-title">{{ homeUnFeeLabel }}</view>
+            <view class="home-rule-input-row">
+              <input v-model="homeForm.homeUnFee" @click="homeForm.homeUnFee = ''" placeholder-class="phcolor" class="home-rule-input" confirm-type="go" placeholder="请填写" type="digit" />
+              <text class="home-rule-unit">元</text>
+            </view>
+            <button class="admin-button-com blue middle" @tap="changeHomeParams(true)">确定</button>
+          </tui-list-cell>
+        </block>
+      </view>
+    </view>
     
     <view class="module-com content_box user-open_bx">
       <view class="input-line-wrap">
@@ -510,7 +565,8 @@ import ModalModule from "@/components/plugin/modal";
 import { getLevel } from "@/utils/config";
 import TuiListCell from "@/components/plugin/list-cell";
 import { getUserDet, remarkAdd, remarkDel, upgrade, resetPassword } from "@/api/member";
-import { changeName,changeMemberLevel,modifyBirthday,updateBuyAmount,changeVip } from "@/api/custom"
+import { changeName,changeMemberLevel,modifyBirthday,updateBuyAmount,changeVip,toChangeHome,modifyHomeParams } from "@/api/custom"
+import { getPsMethodConfig } from '@/api/ps-method'
 import { getLevelInitData } from "@/api/member"
 import {toManRecharge} from "@/api/recharge"
 import {deductBalance} from "@/api/deduct"
@@ -570,11 +626,26 @@ export default {
       rechargeInputFocus: false,
       showBalanceDetail: false,
       memberLevelSet:0,
-      memberLevelData:[]
+      memberLevelData:[],
+      /** 送货上门规则表单,单独设置时覆盖 xhPsMethod(style=0) */
+      homeForm: {
+        home: 1,
+        homeRule: 0,
+        homeAmount: 0,
+        homeNum: 0,
+        homeUnMeet: 0,
+        homeUnFee: 0
+      },
+      /** 门店送货上门总设置(xhPsMethod style=0) */
+      psHomeConfig: null
     };
   },
   computed: {
-    ...mapGetters({ levelData: "getLevel" })
+    ...mapGetters({ levelData: "getLevel" }),
+    /** 不满最低要求时的费用标签,与 psMethod 页 unMeet 编码一致 */
+    homeUnFeeLabel() {
+      return Number(this.homeForm.homeUnMeet) === 2 ? '包装费' : '运费'
+    }
   },
   onLoad(){
     getLevelInitData().then(res=>{
@@ -768,9 +839,31 @@ export default {
       this.userTagModal = true;
     },
     initInfo() {
-      this.getCustomInfo()
+      this.loadPsHomeConfig().then(() => {
+        this.getCustomInfo()
+      })
       getLevel()
     },
+    /** 加载门店送货上门总设置 xhPsMethod style=0 */
+    loadPsHomeConfig() {
+      return getPsMethodConfig({ style: 0 }).then(res => {
+        if (res.code == 1 && res.data) {
+          this.psHomeConfig = res.data
+        }
+      }).catch(() => {})
+    },
+    /** 从 xhPsMethod 总设置填充客户单独规则表单 */
+    fillHomeFormFromPsConfig() {
+      if (!this.psHomeConfig) {
+        return
+      }
+      const cfg = this.psHomeConfig
+      this.homeForm.home = cfg.status != null ? Number(cfg.status) : 1
+      this.homeForm.homeAmount = cfg.minAmount != null ? cfg.minAmount : 0
+      this.homeForm.homeNum = cfg.minNum != null ? cfg.minNum : 0
+      this.homeForm.homeUnMeet = cfg.unMeet != null ? Number(cfg.unMeet) : 0
+      this.homeForm.homeUnFee = cfg.unMeetFee != null ? cfg.unMeetFee : 0
+    },
     getCustomInfo() {
       getUserDet({ userId: this.option.id }).then(res => {
         if (this.$util.isEmpty(res.data)) {
@@ -781,8 +874,136 @@ export default {
         this.debtAmount = res.data.debtAmount?parseFloat(res.data.debtAmount):0;
         this.buyAmount = res.data.buyAmount?parseFloat(res.data.buyAmount):0;
         this.balance = res.data.balance?parseFloat(res.data.balance):0;
+        this.syncHomeFormFromData(res.data);
       })
     },
+    /** 从客户详情同步送货上门规则字段 */
+    syncHomeFormFromData(customData) {
+      if (!customData || !customData.id) {
+        return;
+      }
+      const homeRule = customData.homeRule != null ? Number(customData.homeRule) : 0;
+      this.homeForm.homeRule = homeRule;
+
+      // 单独设置:先按 xhPsMethod 总设置预填,再用客户已保存值覆盖
+      if (homeRule === 1 && this.psHomeConfig) {
+        this.fillHomeFormFromPsConfig();
+      }
+
+      if (customData.home != null) {
+        this.homeForm.home = Number(customData.home);
+      }
+
+      if (homeRule === 1) {
+        const psUnMeet = this.psHomeConfig && this.psHomeConfig.unMeet != null
+          ? Number(this.psHomeConfig.unMeet)
+          : 0;
+        const hasSavedHomeParams = Number(customData.homeAmount || 0) > 0
+          || Number(customData.homeNum || 0) > 0
+          || Number(customData.homeUnFee || 0) > 0
+          || (customData.homeUnMeet != null && Number(customData.homeUnMeet) !== psUnMeet);
+
+        if (customData.homeUnMeet != null) {
+          this.homeForm.homeUnMeet = Number(customData.homeUnMeet);
+        }
+        if (hasSavedHomeParams) {
+          if (customData.homeAmount != null && customData.homeAmount !== '') {
+            this.homeForm.homeAmount = customData.homeAmount;
+          }
+          if (customData.homeNum != null && customData.homeNum !== '') {
+            this.homeForm.homeNum = customData.homeNum;
+          }
+          if (customData.homeUnFee != null && customData.homeUnFee !== '') {
+            this.homeForm.homeUnFee = customData.homeUnFee;
+          }
+        }
+      }
+    },
+    /**
+     * 保存送货上门相关参数
+     * @param {boolean} validateFee - 是否校验运费/包装费
+     */
+    changeHomeParams(validateFee = false) {
+      if (this.$util.isEmpty(this.homeForm.homeAmount)) {
+        this.$msg('请填写最低消费金额');
+        return false;
+      }
+      if (this.$util.isEmpty(this.homeForm.homeNum)) {
+        this.$msg('请填写最低消费扎数');
+        return false;
+      }
+      const homeUnMeet = Number(this.homeForm.homeUnMeet) || 0;
+      if (validateFee && homeUnMeet !== 1 && this.$util.isEmpty(this.homeForm.homeUnFee)) {
+        this.$msg(homeUnMeet === 2 ? '请填写包装费' : '请填写运费');
+        return false;
+      }
+      modifyHomeParams({
+        id: this.data.id,
+        homeRule: this.homeForm.homeRule,
+        homeAmount: this.homeForm.homeAmount,
+        homeNum: this.homeForm.homeNum,
+        homeUnMeet: homeUnMeet,
+        homeUnFee: homeUnMeet === 1 ? 0 : (this.homeForm.homeUnFee || 0)
+      }).then(res => {
+        if (res.code == 1) {
+          this.$msg(res.msg || '修改成功');
+        }
+      });
+    },
+    /** 切换不满最低要求时的处理方式(0收运费 2收包装费 1不能买) */
+    homeUnMeetBtn(value) {
+      if (Number(this.homeForm.homeUnMeet) === value) {
+        return true;
+      }
+      this.homeForm.homeUnMeet = value;
+      modifyHomeParams({
+        id: this.data.id,
+        homeRule: this.homeForm.homeRule,
+        homeAmount: this.homeForm.homeAmount,
+        homeNum: this.homeForm.homeNum,
+        homeUnMeet: value,
+        homeUnFee: value === 1 ? 0 : (this.homeForm.homeUnFee || 0)
+      }).then(res => {
+        if (res.code == 1) {
+          this.$msg(res.msg || '修改成功');
+        }
+      });
+    },
+    /** 切换遵循总设置 / 单独设置 */
+    changeHomeRuleBtn(value) {
+      if (Number(this.homeForm.homeRule) === value) {
+        return;
+      }
+      // 切到单独设置时,先用总设置预填,避免界面全是 0
+      if (Number(value) === 1) {
+        this.fillHomeFormFromPsConfig();
+      }
+      this.homeForm.homeRule = value;
+      modifyHomeParams({
+        id: this.data.id,
+        homeRule: value,
+        homeAmount: this.homeForm.homeAmount,
+        homeNum: this.homeForm.homeNum,
+        homeUnMeet: this.homeForm.homeUnMeet,
+        homeUnFee: Number(this.homeForm.homeUnMeet) === 1 ? 0 : (this.homeForm.homeUnFee || 0)
+      }).then(res => {
+        if (res.code == 1) {
+          this.$msg(res.msg || '修改成功');
+        }
+      });
+    },
+    /** 切换客户送货上门启用状态 */
+    changeHomeBtn(value) {
+      if (Number(this.homeForm.home) === value) {
+        return;
+      }
+      this.homeForm.home = value;
+      toChangeHome({ customId: this.data.id, home: value }).then(res => {
+        if (res.code == 1) {
+          this.$msg(res.msg || '修改成功');
+        }
+      });
+    },
     handleUpdateBuyAmount() {
       uni.showLoading()
       updateBuyAmount({ customId: this.option.id }).then(res => {
@@ -955,6 +1176,73 @@ export default {
   box-shadow: 0upx 6upx 16upx #ddd;
   border-radius: 10upx;
 }
+
+// 送货上门规则(客户级,覆盖 xhPsMethod 总设置)
+.home-rule-wrap {
+  padding: 0;
+  overflow: hidden;
+
+  .home-rule-inner {
+    border: 2upx solid #cccccc;
+    border-radius: 10upx;
+    overflow: hidden;
+  }
+
+  .line-cell {
+    margin-bottom: 0;
+  }
+
+  .tui-title {
+    font-size: 30upx;
+    color: #333333;
+    width: 200upx;
+    flex-shrink: 0;
+  }
+
+  .home-rule-actions {
+    margin-left: auto;
+    display: flex;
+    align-items: center;
+  }
+
+  .home-rule-btn-gap {
+    margin-left: 20upx;
+  }
+
+  .home-rule-input-row {
+    display: flex;
+    align-items: center;
+    flex: 1;
+    justify-content: flex-end;
+  }
+
+  .home-rule-input {
+    width: 245upx;
+    border: 1upx solid #dddddd;
+    margin-right: 10upx;
+    height: 70upx;
+    text-align: center;
+    font-size: 30upx;
+  }
+
+  .home-rule-unit {
+    margin-right: 30upx;
+    font-size: 28upx;
+    color: #666666;
+  }
+
+  .home-rule-unmeet-group {
+    margin-left: auto;
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+    justify-content: flex-end;
+  }
+
+  .home-rule-unmeet-gap {
+    margin-left: 4upx;
+  }
+}
 // 用户信息
 .user-info {
   padding: 30upx 30upx 40upx;

+ 10 - 0
hdApp/src/api/custom/index.js

@@ -55,4 +55,14 @@ export const updateBuyAmount = data => {
 
 export const changeVip = data => {
 	return https.post('/custom/change-vip', data)
+}
+
+/** 切换客户送货上门启用状态 */
+export const toChangeHome = data => {
+	return https.get('/custom/change-home', data)
+}
+
+/** 保存客户送货上门单独规则(覆盖 xhPsMethod 总设置) */
+export const modifyHomeParams = data => {
+	return https.get('/custom/modify-home-amount', data)
 }

+ 7 - 2
hdApp/src/components/sprite-icon/index.vue

@@ -40,11 +40,16 @@ export default {
       type: String,
       default: ""
     },
-    /** 显示宽度 rpx */
+    /** 显示宽度 upx;与 height 同时传时以 height 为准 */
     size: {
       type: [Number, String],
       default: 48
     },
+    /** 显示高度 upx;传入后按高度等比缩放,宽度自动计算 */
+    height: {
+      type: [Number, String],
+      default: ""
+    },
     /** 额外 class,配合页面 ::v-deep 写间距 */
     customClass: {
       type: [String, Array, Object],
@@ -62,7 +67,7 @@ export default {
       return getSpriteSheetUrl(this.resolvedSprite.sheetKey);
     },
     spriteLayout() {
-      return spriteImageStyle(this.name, this.size, this.sheet);
+      return spriteImageStyle(this.name, this.size, this.sheet, this.height);
     },
     wrapStyle() {
       return this.spriteLayout.wrap;

+ 39 - 13
hdApp/src/utils/mainIndexSprite.js

@@ -96,6 +96,34 @@ function rpx2px(rpx) {
   return rpx;
 }
 
+/**
+ * 计算图标显示宽高与缩放比(支持按宽度 size 或按高度 height 等比缩放)
+ * @param {{ w: number, h: number }} icon 雪碧图坐标中的原始宽高
+ * @param {{ size?: number|string, height?: number|string }} opts
+ * @returns {{ displayW: number, displayH: number, scale: number }}
+ */
+function resolveSpriteDisplaySize(icon, opts = {}) {
+  const heightNum = Number(opts.height);
+  const useHeight = opts.height !== "" && opts.height != null && !Number.isNaN(heightNum) && heightNum > 0;
+
+  let scale;
+  let displayW;
+  let displayH;
+
+  if (useHeight) {
+    displayH = Math.round(heightNum);
+    scale = displayH / icon.h;
+    displayW = Math.round(icon.w * scale);
+  } else {
+    const sizeNum = Number(opts.size);
+    displayW = !Number.isNaN(sizeNum) && sizeNum > 0 ? sizeNum : 48;
+    scale = displayW / icon.w;
+    displayH = Math.round(icon.h * scale);
+  }
+
+  return { displayW, displayH, scale };
+}
+
 /**
  * 解析图标所属雪碧图与坐标
  * @param {string} name 图标名
@@ -137,11 +165,12 @@ export function getSpriteSheetUrl(sheetKey = DEFAULT_SHEET_KEY) {
 /**
  * 生成雪碧图 image 裁切样式(小程序 absolute 定位)
  * @param {string} name
- * @param {number|string} size 显示宽度 rpx
+ * @param {number|string} size 显示宽度 upx(未传 height 时生效)
  * @param {string} sheetKey 可选雪碧图 key
+ * @param {number|string} height 显示高度 upx;传入后按高度等比缩放
  * @returns {{ wrap: string, inner: string, image: string }}
  */
-export function spriteImageStyle(name, size = 48, sheetKey = "") {
+export function spriteImageStyle(name, size = 48, sheetKey = "", height = "") {
   const resolved = resolveSprite(name, sheetKey);
   if (!resolved) {
     if (process.env.NODE_ENV !== "production") {
@@ -150,9 +179,7 @@ export function spriteImageStyle(name, size = 48, sheetKey = "") {
     return { wrap: "", inner: "", image: "" };
   }
   const { sheet, icon } = resolved;
-  const displayW = Number(size) || 48;
-  const scale = displayW / icon.w;
-  const displayH = Math.round(icon.h * scale);
+  const { displayW, displayH, scale } = resolveSpriteDisplaySize(icon, { size, height });
   const sheetW = sheet.width * scale;
   const sheetH = sheet.height * scale;
   const left = -rpx2px(icon.x * scale);
@@ -171,17 +198,16 @@ export function spriteImageStyle(name, size = 48, sheetKey = "") {
  * @param {string} name
  * @param {number|string} size
  * @param {string} sheetKey
+ * @param {number|string} height
  * @returns {string}
  */
-export function spriteStyle(name, size = 48, sheetKey = "") {
+export function spriteStyle(name, size = 48, sheetKey = "", height = "") {
   const resolved = resolveSprite(name, sheetKey);
   if (!resolved) {
     return "";
   }
   const { sheetKey: key, sheet, icon } = resolved;
-  const displayW = Number(size) || 48;
-  const scale = displayW / icon.w;
-  const displayH = Math.round(icon.h * scale);
+  const { displayW, displayH, scale } = resolveSpriteDisplaySize(icon, { size, height });
   const sheetW = sheet.width * scale;
   const sheetH = sheet.height * scale;
   const posX = rpx2px(icon.x * scale);
@@ -208,11 +234,11 @@ export function getMainIndexSpriteUrl() {
 }
 
 /** @deprecated 兼容旧 API */
-export function mainIndexSpriteImageStyle(name, size = 48) {
-  return spriteImageStyle(name, size, DEFAULT_SHEET_KEY);
+export function mainIndexSpriteImageStyle(name, size = 48, height = "") {
+  return spriteImageStyle(name, size, DEFAULT_SHEET_KEY, height);
 }
 
 /** @deprecated 兼容旧 API */
-export function mainIndexSpriteStyle(name, size = 48) {
-  return spriteStyle(name, size, DEFAULT_SHEET_KEY);
+export function mainIndexSpriteStyle(name, size = 48, height = "") {
+  return spriteStyle(name, size, DEFAULT_SHEET_KEY, height);
 }

+ 10 - 0
mallApp/src/api/ps-method/index.js

@@ -0,0 +1,10 @@
+/**
+ * 花店配送方式 API(xhPsMethod / xhPsExplain)
+ * 用途:商城混合结算页展示购买方式说明
+ */
+import https from '@/plugins/luch-request_0.0.7/request'
+
+/** 获取门店全部配送方式及说明项 */
+export const getAllPsMethod = data => {
+  return https.get('/ps-method/get-all-method', data)
+}

+ 55 - 16
mallApp/src/components/hb/hb-select.vue

@@ -1,7 +1,12 @@
 <template>
 	<view class="hb-select-container">
-		<!-- Trigger Row -->
-        <view class="cell-content" @click="openPopup" v-if="hasAvailableHb">
+		<!-- 触发区:hideTrigger 时由页面自定义行样式,仅保留弹层 -->
+        <view
+			class="cell-content"
+			:class="{ 'cell-content--expand': expandTrigger }"
+			@click.stop="openPopup"
+			v-if="hasAvailableHb && !hideTrigger"
+		>
             <view class="right-content">
                 <text v-if="selectedHb" class="selected-text">-¥{{ selectedHb.amount?parseFloat(selectedHb.amount):0 }}</text>
                 <view v-else class="available-tag">
@@ -18,9 +23,14 @@
 					<text class="close-btn" @click="closePopup">×</text>
 				</view>
 
-				<scroll-view scroll-y class="popup-scroll">
+				<scroll-view scroll-y class="popup-scroll" :enable-flex="true">
 					<view class="hb-list">
-						<view class="hb-card" v-for="item in availableHbList" :key="item.id" @click="selectHb(item)">
+						<view
+							class="hb-card"
+							v-for="item in availableHbList"
+							:key="item.id"
+							@click.stop="selectHb(item)"
+						>
 							<view class="card-left">
 								<view class="amount"><text class="symbol">¥</text>{{ item.amount?parseFloat(item.amount):0 }}</view>
 								<view class="type">{{ item.name }}</view>
@@ -33,14 +43,14 @@
 								<view class="date" v-else>{{ formatTime(item.endTime) }} 到期</view>
 							</view>
 							<view class="card-right">
-								<view class="radio-circle" :class="{ checked: currentSelectedId == item.id }">
-									<text v-if="currentSelectedId == item.id" class="iconfont icon-check">✓</text>
+								<view class="radio-circle" :class="{ checked: isHbItemSelected(item.id) }">
+									<text v-if="isHbItemSelected(item.id)" class="iconfont icon-check">✓</text>
 								</view>
 							</view>
 						</view>
 
-						<!-- Option to not use red packet -->
-						<view class="hb-card" @click="selectHb(null)">
+						<!-- 不使用红包 -->
+						<view class="hb-card" @click.stop="selectHb(null)">
 							<view class="card-left" style="border:none;">
 								<text style="font-size: 28upx; color: #333; font-weight: bold;">不使用红包</text>
 							</view>
@@ -55,7 +65,7 @@
 				</scroll-view>
 
 				<view class="popup-footer">
-					<button class="confirm-btn" @click="confirmSelection">确定</button>
+					<button class="confirm-btn" @click.stop="confirmSelection">确定</button>
 				</view>
 			</view>
 		</uni-popup>
@@ -82,6 +92,16 @@ export default {
 		value: { // v-model for selected Hb ID
 			type: [String, Number],
 			default: null
+		},
+		/** 结算页等场景:触发区撑满右侧,配合整行点击 */
+		expandTrigger: {
+			type: Boolean,
+			default: false
+		},
+		/** 隐藏默认触发按钮,由外部自定义行点击 openPopup */
+		hideTrigger: {
+			type: Boolean,
+			default: false
 		}
 	},
 	data() {
@@ -101,7 +121,6 @@ export default {
 			});
 		},
 		hasAvailableHb() {
-            console.log('availableHbList ----- ', this.availableHbList)
 			return this.availableHbList.length > 0;
 		},
 		selectedHb() {
@@ -118,20 +137,27 @@ export default {
 		}
 	},
 	methods: {
+		/** 红包 id 比较(兼容字符串/数字) */
+		isHbItemSelected(id) {
+			if (this.currentSelectedId === null || this.currentSelectedId === undefined || this.currentSelectedId === "") {
+				return false;
+			}
+			return String(this.currentSelectedId) === String(id);
+		},
 		openPopup() {
-			this.currentSelectedId = this.value; // Reset to current value when opening
-			this.$refs.popup.open('center');
+			this.currentSelectedId = this.value;
+			this.$refs.popup.open("bottom");
 		},
 		closePopup() {
 			this.$refs.popup.close();
 		},
 		selectHb(item) {
-			this.currentSelectedId = item ? item.id : null;
+			this.currentSelectedId = item && item.id !== undefined && item.id !== null ? item.id : null;
 		},
 		confirmSelection() {
-			this.$emit('input', this.currentSelectedId); // Update v-model
-            const selectedItem = this.hbData.find(item => item.id == this.currentSelectedId);
-			this.$emit('change', selectedItem || null);
+			this.$emit("input", this.currentSelectedId);
+			const selectedItem = this.hbData.find((item) => String(item.id) === String(this.currentSelectedId));
+			this.$emit("change", selectedItem || null);
 			this.closePopup();
 		},
 		formatTime(timestamp) {
@@ -154,11 +180,23 @@ export default {
 </script>
 
 <style lang="scss" scoped>
+.hb-select-container {
+	display: flex;
+	flex-direction: row;
+	align-items: center;
+}
+
 .cell-content {
 	display: flex;
 	justify-content: space-between;
 	align-items: center;
 	width: 400upx;
+
+	&--expand {
+		width: 100%;
+		min-height: 88upx;
+		justify-content: flex-end;
+	}
 }
 .tui-title {
     width: auto !important; /* Override tui-list-cell default if needed */
@@ -180,6 +218,7 @@ export default {
 	color: #ff2842;
 	font-size: 32upx;
 	font-weight: bold;
+	padding: 12upx 8upx;
 }
 
 /* Popup Styles */

+ 7 - 2
mallApp/src/components/sprite-icon/index.vue

@@ -40,11 +40,16 @@ export default {
       type: String,
       default: ""
     },
-    /** 显示宽度 rpx */
+    /** 显示宽度 upx;与 height 同时传时以 height 为准 */
     size: {
       type: [Number, String],
       default: 48
     },
+    /** 显示高度 upx;传入后按高度等比缩放,宽度自动计算 */
+    height: {
+      type: [Number, String],
+      default: ""
+    },
     /** 额外 class,配合页面 ::v-deep 写间距 */
     customClass: {
       type: [String, Array, Object],
@@ -62,7 +67,7 @@ export default {
       return getSpriteSheetUrl(this.resolvedSprite.sheetKey);
     },
     spriteLayout() {
-      return spriteImageStyle(this.name, this.size, this.sheet);
+      return spriteImageStyle(this.name, this.size, this.sheet, this.height);
     },
     wrapStyle() {
       return this.spriteLayout.wrap;

+ 1 - 1
mallApp/src/config.js

@@ -1,4 +1,4 @@
 export const ProjectName = 'mall'
 export const CURRENT_ENV = 'dev'
-export const APIHOST = 'https://api.shop.theflorist.cn'
+export const APIHOST = 'http://api.shop.theflorist.cn'
 export const WSSHOST = 'wss://chat.shop.huaml.com'

+ 2 - 2
mallApp/src/ext.json

@@ -4,9 +4,9 @@
   "directCommit": false,
   "ext": {
     "account": 0,
-    "apiHost": "https://api.shop.theflorist.cn",
+    "apiHost": "http://api.shop.theflorist.cn",
     "socketApiHost": "api.shop.theflorist.cn",
-    "imgHost": "https://img.theflorist.cn",
+    "imgHost": "http://img.theflorist.cn",
     "name":"中花卉"
   }
 }

+ 1 - 1
mallApp/src/pages.json

@@ -138,7 +138,7 @@
             "root": "pages/billing",
             "pages": [
                 { "path": "affirmGhs", "style": { "navigationBarTitleText": "订单结算", "enablePullDownRefresh": false } },
-                { "path": "affirmMix", "style": { "navigationBarTitleText": "订单结算", "enablePullDownRefresh": false } }
+                { "path": "affirmMix", "style": { "navigationBarTitleText": "立即购买", "enablePullDownRefresh": false } }
             ]
         },
         {

+ 13 - 0
mallApp/src/pages/billing/affirmGhs.vue

@@ -724,6 +724,19 @@ export default {
 				weight: 1, // 固定重量1kg
 				selectList: this.selectList,
 				remark: this.form.remark,
+				receiveUserName: this.form.receiveUserName,
+				receiveMobile: this.form.receiveMobile,
+				address: this.form.address || this.userInfo.address || '',
+				fullAddress: this.userInfo.fullAddress || this.form.address || '',
+				floor: this.form.floor || this.userInfo.floor || '',
+				dist: this.form.dist || '',
+				city: this.form.city || '',
+				lat: this.form.lat || this.userInfo.lat,
+				long: this.form.long || this.userInfo.long,
+				region: {
+					latitude: this.form.lat || this.userInfo.lat,
+					longitude: this.form.long || this.userInfo.long,
+				},
 			}).then(res => {
 				if (res.code === 1 && res.data && res.data.deliveryList) {
 					// 处理报价数据

File diff suppressed because it is too large
+ 2545 - 838
mallApp/src/pages/billing/affirmMix.vue


+ 5 - 12
mallApp/src/pages/home/cart.vue

@@ -1,6 +1,6 @@
 <!--
   店铺购物车页
-  用途:展示花材+花束购物车(Vuex cg 选型,property 区分),支持勾选、改数量、删除、去结算
+  用途:展示花材+花束购物车(Vuex cg 选型,property 区分),支持勾选、改数量、删除;去结算统一跳转 affirmMix
   路由:pages/home/cart?account=xxx&hdId=xxx
 -->
 <template>
@@ -656,12 +656,7 @@ export default {
         }
       })
     },
-    /** 结算页路由:含花束走合并结算页,纯花材保持 affirmGhs */
-    getCheckoutUrl(list) {
-      const hasBouquet = (list || []).some((item) => this.isBouquetItem(item))
-      return hasBouquet ? '/pages/billing/affirmMix' : '/pages/billing/affirmGhs'
-    },
-    /** 去结算:仅提交已勾选商品 */
+    /** 去结算:仅提交已勾选商品,统一进入混合结算页 affirmMix */
     goCheckout() {
       const list = this.checkedCheckoutList
       if (!list.length) {
@@ -674,7 +669,7 @@ export default {
         return
       }
       const account = this.shopAccount || 0
-      const checkoutUrl = this.getCheckoutUrl(list)
+      const checkoutUrl = '/pages/billing/affirmMix'
       const newList = list
         .filter((item) => !this.isBouquetItem(item) && Number(item.limitBuy) > 0)
         .map((item) => ({ id: item.id, bigCount: item.bigCount }))
@@ -685,8 +680,7 @@ export default {
         const realHdId = this.hdId || uni.getStorageSync('hdId') || 0
         this.$util.pageTo({
           url: checkoutUrl,
-          query: { account, hdId: realHdId },
-          type: 2
+          query: { account, hdId: realHdId }
         })
       }
       if (newList.length > 0) {
@@ -703,8 +697,7 @@ export default {
           const realHdId = this.hdId || uni.getStorageSync('hdId') || 0
           this.$util.pageTo({
             url: checkoutUrl,
-            query: { account, hdId: realHdId },
-            type: 2
+            query: { account, hdId: realHdId }
           })
         })
       } else {

+ 23 - 0
mallApp/src/pages/user/address/edit.vue

@@ -117,6 +117,8 @@ export default {
 	data() {
 		return {
 			id: '',
+			/** 结算页选择模式:保存后直接回传地址 */
+			isChooseMode: false,
 			form: {
 				name: '',
 				phone: '',
@@ -136,6 +138,7 @@ export default {
 		}
 	},
 	onLoad(options) {
+		this.isChooseMode = options && options.source === 'choose'
 		if (options.id) {
 			this.id = options.id
 			uni.setNavigationBarTitle({ title: '编辑地址' })
@@ -269,6 +272,26 @@ export default {
 			api(data).then(res => {
 				uni.hideLoading()
 				if (res.code === 1) {
+					if (this.isChooseMode) {
+						// 结算页选择模式:保存后直接回传,字段对齐 affirmMix.applyAddressFromItem
+						const saved = {
+							id: this.id || res.data && res.data.id,
+							name: this.form.name || '',
+							phone: this.form.phone || '',
+							province: this.form.province || '',
+							city: this.form.city || '',
+							dist: this.form.dist || '',
+							address: this.form.address || '',
+							floor: this.form.floor || '',
+							lat: this.form.lat || '',
+							long: this.form.long || '',
+							showAddress: this.form.showAddress || '',
+							fullAddress: this.form.fullAddress || ''
+						}
+						uni.setStorageSync('chooseAddress', saved)
+						uni.navigateBack()
+						return
+					}
 					uni.showToast({ title: '保存成功', icon: 'success' })
 					setTimeout(() => {
 						uni.navigateBack()

+ 51 - 8
mallApp/src/pages/user/address/list.vue

@@ -11,12 +11,15 @@
 			<text class="iconfont iconxiangyou" style="color: #999; font-size: 32upx;"></text>
 		</view>
 
+		<view class="choose-tip" v-if="isChooseMode">请选择收货地址</view>
+
 		<view class="address-list">
 			<view 
 				class="address-item" 
 				:class="{ 'is-default': item.default == 1 }"
 				v-for="(item, index) in list" 
 				:key="item.id"
+				@click="onItemClick(item)"
 			>
 				<view class="default-badge" v-if="item.default == 1">默认地址</view>
 				
@@ -38,7 +41,7 @@
 					<text>距离您 {{ item.distance }}</text>
 				</view>
 
-				<view class="action-bar">
+				<view class="action-bar" @click.stop>
 					<view class="left-action">
 						<view class="set-default" v-if="item.default != 1" @click="setDefault(item)">
 							<text class="iconfont iconweixuanzhong" style="color: #ccc; font-size: 36upx; margin-right: 10upx;"></text>
@@ -74,17 +77,23 @@
 <script>
 /**
  * 用户收货地址列表
- * 解决用户管理收货地址的问题
+ * 管理 xhUserAddress 地址簿;source=choose 时供结算页选择并回传
  */
 import { getAddressList, deleteAddress, setDefaultAddress } from '@/api/user-address'
 
 export default {
 	data() {
 		return {
-			list: []
+			list: [],
+			/** 是否为结算页选择地址模式 */
+			isChooseMode: false
 		}
 	},
-	onLoad() {
+	onLoad(option) {
+		this.isChooseMode = option && option.source === 'choose'
+		if (this.isChooseMode) {
+			uni.setNavigationBarTitle({ title: '选择收货地址' })
+		}
 	},
 	onShow() {
 		this.getList()
@@ -104,17 +113,44 @@ export default {
 				uni.hideLoading()
 			})
 		},
+		/** 结算页选择:写入缓存并返回 */
+		chooseAddressItem(item) {
+			const normalized = {
+				id: item.id,
+				name: item.name || '',
+				phone: item.phone || '',
+				province: item.province || '',
+				city: item.city || '',
+				dist: item.dist || '',
+				address: item.address || '',
+				floor: item.floor || '',
+				lat: item.lat || '',
+				long: item.long || '',
+				showAddress: item.showAddress || '',
+				fullAddress: item.fullAddress || ''
+			}
+			uni.setStorageSync('chooseAddress', normalized)
+			uni.navigateBack()
+		},
+		onItemClick(item) {
+			if (this.isChooseMode) {
+				this.chooseAddressItem(item)
+			}
+		},
 		// 添加地址
 		addAddress() {
+			const query = this.isChooseMode ? '?source=choose' : ''
 			uni.navigateTo({
-				url: '/pages/user/address/edit'
+				url: '/pages/user/address/edit' + query
 			})
 		},
 		// 编辑地址
 		editAddress(item) {
-			uni.navigateTo({
-				url: `/pages/user/address/edit?id=${item.id}`
-			})
+			let url = `/pages/user/address/edit?id=${item.id}`
+			if (this.isChooseMode) {
+				url += '&source=choose'
+			}
+			uni.navigateTo({ url })
 		},
 		// 删除地址
 		deleteItem(item) {
@@ -166,6 +202,13 @@ export default {
 	padding-bottom: 140upx;
 }
 
+.choose-tip {
+	font-size: 28upx;
+	color: #666;
+	margin-bottom: 16upx;
+	padding-left: 8upx;
+}
+
 .safe-banner {
 	display: flex;
 	align-items: center;

+ 43 - 18
mallApp/src/utils/mainIndexSprite.js

@@ -59,15 +59,15 @@ export const SPRITE_SHEETS = {
   },
   /** 进货/供货商专用雪碧图,坐标待设计稿测量后补全 */
   order: {
-    path: "/hhb/sprite_icon/icon-order.webp?time=26071614",
-    width: 500,
-    height: 500,
+    path: "/hhb/sprite_icon/icon-order.webp?time=26072009",
+    width: 600,
+    height: 600,
     icons: {
 		"ps-shop": { x: 257, y: 8 , w: 57, h: 50 },//商家配送
 		"ps-shop-active": { x: 190, y: 8 , w: 57, h: 50 },//商家配送-active
 		"ps-paotui": { x: 198, y: 63 , w: 59, h: 50 },//跑腿配送
 		"ps-paotui-active": { x: 129, y: 63 , w: 59, h: 50 },//跑腿配送-active
-		"ps-daodian": { x: 483, y: 8 , w: 48, h: 50 },//到店自取
+		"ps-daodian": { x: 383, y: 8 , w: 48, h: 50 },//到店自取
 		"ps-daodian-active": { x: 324, y: 8 , w: 49, h: 50 },//到店自取-active
 		"ps-kuaidi": { x: 72, y: 63 , w: 47, h: 50 },//快递
 		"ps-kuaidi-active": { x: 12, y: 63 , w: 46, h: 50 },//快递-active
@@ -76,8 +76,9 @@ export const SPRITE_SHEETS = {
 		"huoche": { x: 7, y: 8 , w: 46, h: 50 },//配送说明-小货车
 		"youhuiquan": { x: 267, y: 63 , w: 58, h: 50 },//优惠券
 		"beizhu": { x: 12, y: 8 , w: 50, h: 50 },//订单-备注
-		"shijian": { x: 70, y: 8 , w: 50, h: 50 },//配送时间
-		"shijianduan": { x: 129, y: 8 , w: 51, h: 50 },//配送时间段
+		"shijian": { x: 70, y: 8 , w: 52, h: 52 },//配送时间
+		"shijianduan": { x: 129, y: 8 , w: 52, h: 52 },//配送时间段
+		"dingwei": { x: 339, y: 63 , w: 42, h: 51 },//定位
 	}
   }
 };
@@ -129,6 +130,34 @@ function rpx2px(rpx) {
   return rpx;
 }
 
+/**
+ * 计算图标显示宽高与缩放比(支持按宽度 size 或按高度 height 等比缩放)
+ * @param {{ w: number, h: number }} icon 雪碧图坐标中的原始宽高
+ * @param {{ size?: number|string, height?: number|string }} opts
+ * @returns {{ displayW: number, displayH: number, scale: number }}
+ */
+function resolveSpriteDisplaySize(icon, opts = {}) {
+  const heightNum = Number(opts.height);
+  const useHeight = opts.height !== "" && opts.height != null && !Number.isNaN(heightNum) && heightNum > 0;
+
+  let scale;
+  let displayW;
+  let displayH;
+
+  if (useHeight) {
+    displayH = Math.round(heightNum);
+    scale = displayH / icon.h;
+    displayW = Math.round(icon.w * scale);
+  } else {
+    const sizeNum = Number(opts.size);
+    displayW = !Number.isNaN(sizeNum) && sizeNum > 0 ? sizeNum : 48;
+    scale = displayW / icon.w;
+    displayH = Math.round(icon.h * scale);
+  }
+
+  return { displayW, displayH, scale };
+}
+
 export function resolveSprite(name, sheetKey = "") {
   if (!name) {
     return null;
@@ -156,7 +185,7 @@ export function getSpriteSheetUrl(sheetKey = DEFAULT_SHEET_KEY) {
   return `${getImgHostBase()}${sheet.path}`;
 }
 
-export function spriteImageStyle(name, size = 48, sheetKey = "") {
+export function spriteImageStyle(name, size = 48, sheetKey = "", height = "") {
   const resolved = resolveSprite(name, sheetKey);
   if (!resolved) {
     if (process.env.NODE_ENV !== "production") {
@@ -165,9 +194,7 @@ export function spriteImageStyle(name, size = 48, sheetKey = "") {
     return { wrap: "", inner: "", image: "" };
   }
   const { sheet, icon } = resolved;
-  const displayW = Number(size) || 48;
-  const scale = displayW / icon.w;
-  const displayH = Math.round(icon.h * scale);
+  const { displayW, displayH, scale } = resolveSpriteDisplaySize(icon, { size, height });
   const sheetW = sheet.width * scale;
   const sheetH = sheet.height * scale;
   const left = -rpx2px(icon.x * scale);
@@ -181,15 +208,13 @@ export function spriteImageStyle(name, size = 48, sheetKey = "") {
   };
 }
 
-export function spriteStyle(name, size = 48, sheetKey = "") {
+export function spriteStyle(name, size = 48, sheetKey = "", height = "") {
   const resolved = resolveSprite(name, sheetKey);
   if (!resolved) {
     return "";
   }
   const { sheetKey: key, sheet, icon } = resolved;
-  const displayW = Number(size) || 48;
-  const scale = displayW / icon.w;
-  const displayH = Math.round(icon.h * scale);
+  const { displayW, displayH, scale } = resolveSpriteDisplaySize(icon, { size, height });
   const sheetW = sheet.width * scale;
   const sheetH = sheet.height * scale;
   const posX = rpx2px(icon.x * scale);
@@ -214,10 +239,10 @@ export function getMainIndexSpriteUrl() {
   return getSpriteSheetUrl(DEFAULT_SHEET_KEY);
 }
 
-export function mainIndexSpriteImageStyle(name, size = 48) {
-  return spriteImageStyle(name, size, DEFAULT_SHEET_KEY);
+export function mainIndexSpriteImageStyle(name, size = 48, height = "") {
+  return spriteImageStyle(name, size, DEFAULT_SHEET_KEY, height);
 }
 
-export function mainIndexSpriteStyle(name, size = 48) {
-  return spriteStyle(name, size, DEFAULT_SHEET_KEY);
+export function mainIndexSpriteStyle(name, size = 48, height = "") {
+  return spriteStyle(name, size, DEFAULT_SHEET_KEY, height);
 }

Some files were not shown because too many files changed in this diff