Przeglądaj źródła

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

shizhongqi 13 godzin temu
rodzic
commit
bf58ed8638

+ 108 - 66
hdApp/src/admin/goods/add.vue

@@ -1,7 +1,7 @@
 <!--
   花店后台新增商品
   谁用:hdApp 管理端创建花束
-  解决问题:单规格写主记录;开启多规格时隐藏卡片外主图/封面,改在规格卡片内编辑(规格1回写主记录),其余规格提交 specList 由后端拆子行;多规格用可横滑 tab 切换卡片编辑
+  解决问题:单规格写主记录;开启多规格时隐藏卡片外主图/封面,改在规格卡片内编辑(规格1回写主记录),其余规格提交 specList 由后端拆子行;多规格用可横滑 pill tab 切换;表单区视觉层次与开关/规格卡片统一美化
 -->
 <template>
   <view class="app-content">
@@ -16,13 +16,13 @@
 
         <view class="spec-switch-card">
           <view class="spec-switch-left">
-            <view class="spec-switch-icon"></view>
-            <view>
+            <view class="spec-switch-icon"></view>
+            <view class="spec-switch-copy">
               <view class="spec-switch-title">多规格</view>
             </view>
           </view>
           <view class="spec-switch-right">
-            <text>{{ form.specEnabled == 1 ? '已启用' : '未启用' }}</text>
+            <text class="spec-switch-status">{{ form.specEnabled == 1 ? '已启用' : '未启用' }}</text>
             <switch class="spec-switch-ctrl" :checked="form.specEnabled == 1" @change="toggleSpecs" color="#09C567" />
           </view>
         </view>
@@ -147,10 +147,6 @@
           </view>
         </tui-list-cell>
 
-        <tui-list-cell class="line-cell category-wrap" :hover="false">
-          <view class="tui-title">使用场景</view><view class="tui-input"><block v-for="item in useCaseData" :key="item.id"><button class="admin-button-com" :class="[form.useCaseIdList.includes(item.id) ? '' : 'default']" @click="toggleUseCase(item)">{{ item.useCaseName }}</button></block></view>
-        </tui-list-cell>
-
         <tui-list-cell class="line-cell category-wrap" :hover="false">
           <view class="tui-title required">分类</view>
           <view class="tui-input">
@@ -161,6 +157,10 @@
           </view>
         </tui-list-cell>
 
+        <tui-list-cell class="line-cell category-wrap" :hover="false">
+          <view class="tui-title">使用场景</view><view class="tui-input"><block v-for="item in useCaseData" :key="item.id"><button class="admin-button-com" :class="[form.useCaseIdList.includes(item.id) ? '' : 'default']" @click="toggleUseCase(item)">{{ item.useCaseName }}</button></block></view>
+        </tui-list-cell>
+
         <tui-list-cell v-if="form.specEnabled != 1" class="line-cell" :hover="false">
           <view class="tui-title">价格类型</view>
           <view class="btn-group">
@@ -199,11 +199,11 @@
 
        <tui-list-cell v-if="form.specEnabled != 1" class="line-cell" :hover="false">
           <view class="tui-title">已售数量</view>
-          <input v-model="form.sold" placeholder-class="phcolor" class="tui-input" name="sold" placeholder="客户端展示:已售数量+实售数量" maxlength="10" type="number" />
+          <input v-model="form.sold" placeholder-class="phcolor" class="tui-input" name="sold" placeholder="客户看到:已售数量+实售数量" maxlength="10" type="number" />
         </tui-list-cell>
 
         <tui-list-cell class="line-cell" :hover="false">
-          <view class="tui-title">节日涨价管理</view>
+          <view class="tui-title">节日涨价</view>
           <view class="btn-group">
             <button class="admin-button-com middle" :class="[form.autoRise === '1' ? '' : 'default']" @click="autoRiseChange('1')">参与涨价</button>
             <button class="admin-button-com middle" :class="[form.autoRise === '0' ? '' : 'default']" @click="autoRiseChange('0')">不要涨价</button>
@@ -294,6 +294,8 @@ export default {
   onLoad() {
     const token = uni.getStorageSync('token')
     this.headers.token = token
+    // 新增默认填入随机已售,商城展示不显得冷清
+    this.form.sold = this.randomSold()
   },
   computed: {
     // 根据上传的图片数量动态生成封面选项
@@ -428,6 +430,13 @@ export default {
       useCaseList().then(res => { if (res.code == 1) this.useCaseData = res.data || [] })
     },
     toggleUseCase(item) { const i=this.form.useCaseIdList.indexOf(item.id); i<0?this.form.useCaseIdList.push(item.id):this.form.useCaseIdList.splice(i,1) },
+    /**
+     * 生成 150~360 的随机已售数量(含两端)
+     * @returns {number}
+     */
+    randomSold() {
+      return Math.floor(Math.random() * (360 - 150 + 1)) + 150
+    },
     createSpecData(data = {}) {
       const shopImg = Array.isArray(data.shortImgList) ? data.shortImgList : (Array.isArray(data.shopImg) ? data.shopImg : []);
       const currentImgData = Array.isArray(data.currentImgData) ? data.currentImgData : (Array.isArray(data.smallImgList) ? data.smallImgList : []);
@@ -931,6 +940,13 @@ export default {
   .module-det {
     padding: 0 30upx;
   }
+  &.goods-wrap {
+    margin: 0 24upx 20upx;
+    padding-bottom: 16upx;
+    border-radius: 16upx;
+    border: 1px solid #f0f0f0;
+    overflow: hidden;
+  }
 }
 .category-wrap {
   align-items: flex-start;
@@ -939,18 +955,20 @@ export default {
     @include disFlex(center, flex-start);
     flex-wrap: wrap;
     .admin-button-com {
-      margin-right: 30rpx;
-      margin-bottom: 20upx;
+      margin-right: 16rpx;
+      margin-bottom: 16upx;
       position: relative;
       z-index: 9999;
+      border-radius: 12upx;
     }
   }
 }
 .use-img{
   font-size: 22rpx;
   color: #999999;
-  padding-left: 4rpx 8rpx;
+  padding: 4rpx 0 8rpx;
   line-height: 1.5;
+  width: 100%;
 }
 .no-img-tip {
   font-size: 26rpx;
@@ -961,83 +979,96 @@ export default {
 .btn-group {
   display: flex;
   justify-content: flex-start;
+  flex-wrap: wrap;
   .admin-button-com {
-    margin-right: 35rpx;
-    
+    margin-right: 20rpx;
+    margin-bottom: 8upx;
+    border-radius: 12upx;
     &:last-child {
       margin-right: 0;
     }
   }
 }
 .spec-switch-card {
-  margin: 0 20upx 20upx;
-  padding: 10upx 30upx;
-  border: 1px solid #e5f5ec;
-  border-radius: 12upx;
-  background: linear-gradient(90deg, #f3fff8 0%, #ffffff 100%);
+  margin: 16upx 24upx 24upx;
+  padding: 10upx 28upx;
+  border: 1px solid #dff5e8;
+  border-radius: 20upx;
+  background: linear-gradient(135deg, #f2fff8 0%, #ffffff 55%);
   display: flex;
   align-items: center;
   justify-content: space-between;
   box-sizing: border-box;
+  box-shadow: 0 6upx 20upx rgba(9, 197, 103, 0.06);
 }
 .spec-switch-left {
   display: flex;
   align-items: center;
   min-width: 0;
+  flex: 1;
 }
 .spec-switch-icon {
   width: 40upx;
   height: 40upx;
-  margin-right: 22upx;
-  border-radius: 50%;
+  margin-right: 18upx;
+  border-radius: 16upx;
   background: #09C567;
   color: #ffffff;
-  font-size: 28upx;
+  font-size: 22upx;
   display: flex;
   align-items: center;
   justify-content: center;
+  flex-shrink: 0;
+}
+.spec-switch-copy {
+  min-width: 0;
+  flex: 1;
 }
 .spec-switch-title {
-  font-size: 32upx;
-  color: #222222;
+  font-size: 30upx;
+  color: #1f1f1f;
   font-weight: 700;
-  line-height: 44upx;
+  line-height: 40upx;
 }
 .spec-switch-desc {
-  margin-top: 6upx;
-  font-size: 24upx;
-  color: #999999;
+  margin-top: 4upx;
+  font-size: 22upx;
+  color: #8c8c8c;
+  line-height: 32upx;
 }
 .spec-switch-right {
   display: flex;
   align-items: center;
   flex-shrink: 0;
-  color: #999999;
-  font-size: 24upx;
-  text {
-    margin-right: 12upx;
+  margin-left: 16upx;
+  .spec-switch-status {
+    margin-right: 8upx;
+    color: #8c8c8c;
+    font-size: 22upx;
   }
-  /* uni-app switch 无尺寸属性,用缩放缩小 */
   .spec-switch-ctrl {
     transform: scale(0.75);
     transform-origin: center right;
   }
 }
 .spec-wrap {
-  padding: 0 20upx 20upx;
+  padding: 0 24upx 24upx;
 }
 .spec-card {
   margin-bottom: 20upx;
   background: #ffffff;
-  border: 4px solid #e8e8e8;
-  border-radius: 16upx;
+  border: 1px solid #eef0f2;
+  border-radius: 20upx;
   overflow: hidden;
+  box-shadow: 0 4upx 18upx rgba(0, 0, 0, 0.04);
 }
 .spec-card-head {
   display: flex;
   align-items: center;
   justify-content: space-between;
-  padding: 20upx 24upx 12upx;
+  padding: 24upx 24upx 16upx;
+  background: #fafbfc;
+  border-bottom: 1px solid #f0f0f0;
 }
 .spec-card-head-left {
   display: flex;
@@ -1047,33 +1078,32 @@ export default {
 }
 .spec-card-title {
   font-size: 30upx;
-  color: #222222;
+  color: #1f1f1f;
   font-weight: 700;
   flex-shrink: 0;
 }
 .spec-remove {
   margin: 0 0 0 16upx;
-  padding: 0 20upx;
+  padding: 0 22upx;
   height: 52upx;
   line-height: 52upx;
-  border: 1px solid #eeeeee;
-  border-radius: 8upx;
+  border: 1px solid #eadede;
+  border-radius: 26upx;
   background: #ffffff;
   color: #999999;
   font-size: 24upx;
   flex-shrink: 0;
 }
 .spec-add-btn {
-  margin: 0 0 0 16upx;
-  padding: 0 20upx;
+  margin: 0 0 0 20upx;
+  padding: 0 22upx;
   height: 52upx;
   line-height: 52upx;
-  border-radius: 8upx;
+  border-radius: 26upx;
   background: #09C567;
   color: #ffffff;
   font-size: 24upx;
   flex-shrink: 0;
-  margin-left: 40upx;
 }
 .spec-add-btn::after,
 .spec-remove::after {
@@ -1081,25 +1111,25 @@ export default {
 }
 .spec-tab-scroll {
   width: 100%;
-  height: 80upx;
+  height: 88upx;
   white-space: nowrap;
-  border-bottom: 1px solid #f0f0f0;
+  background: #f7f8fa;
 }
 .spec-tab-list {
   display: inline-flex;
   flex-direction: row;
   align-items: center;
-  height: 80upx;
-  padding: 0 12upx;
+  height: 88upx;
+  padding: 0 16upx;
 }
 .spec-tab-item {
   display: inline-flex;
   align-items: center;
   justify-content: center;
-  height: 80upx;
-  padding: 0 28upx;
-  margin-right: 8upx;
-  font-size: 28upx;
+  height: 56upx;
+  padding: 0 24upx;
+  margin-right: 12upx;
+  font-size: 26upx;
   color: #666666;
   flex-shrink: 0;
   max-width: 240upx;
@@ -1107,11 +1137,15 @@ export default {
   white-space: nowrap;
   text-overflow: ellipsis;
   box-sizing: border-box;
+  border-radius: 28upx;
+  background: #ffffff;
+  border: 1px solid #ececec;
 }
 .spec-tab-item.active {
   color: #09C567;
   font-weight: 700;
-  border-bottom: 4upx solid #09C567;
+  background: rgba(9, 197, 103, 0.12);
+  border-color: rgba(9, 197, 103, 0.35);
 }
 .spec-tab-text {
   overflow: hidden;
@@ -1122,22 +1156,25 @@ export default {
   margin-top: 0;
 }
 .spec-image-wrap {
-  padding: 10upx 0 20upx;
-  border-bottom: 1px solid #eeeeee;
+  margin: 8upx 16upx 16upx;
+  padding: 8upx 0 16upx;
+  border-radius: 16upx;
+  background: #fafbfc;
+  border: 1px solid #f0f0f0;
   .module-tit {
-    padding: 20upx 30upx;
+    padding: 16upx 24upx 8upx;
   }
   .module-det {
-    padding: 0 30upx;
+    padding: 0 24upx;
   }
 }
 .spec-cover-row {
   display: flex;
   align-items: flex-start;
-  padding: 20upx 30upx 0;
+  padding: 16upx 24upx 0;
 }
 .spec-cover-title {
-  width: 200upx;
+  width: 120upx;
   flex-shrink: 0;
   font-size: 28upx;
   color: #333333;
@@ -1148,8 +1185,9 @@ export default {
   display: flex;
   flex-wrap: wrap;
   .admin-button-com {
-    margin-right: 30upx;
-    margin-bottom: 16upx;
+    margin-right: 16upx;
+    margin-bottom: 12upx;
+    border-radius: 12upx;
   }
 }
 
@@ -1167,10 +1205,14 @@ export default {
 .app-footer {
   justify-content: space-evenly;
   z-index: 9999;
+  padding-top: 16upx;
+  padding-bottom: calc(16upx + env(safe-area-inset-bottom));
+  box-shadow: 0 -6upx 20upx rgba(0, 0, 0, 0.04);
   .admin-button-com {
-    width: 46%;
-    padding-top:30upx;
-    padding-bottom:30upx;
+    width: 44%;
+    padding-top: 26upx;
+    padding-bottom: 26upx;
+    border-radius: 44upx;
     
     &:disabled {
       opacity: 0.6;

+ 106 - 71
hdApp/src/admin/goods/detail.vue

@@ -1,7 +1,7 @@
 <!--
   花店后台编辑商品
   谁用:hdApp 管理端修改花束
-  解决问题:详情 specList 首项即主记录自身;开启多规格时隐藏卡片外主图/封面,改在规格卡片内编辑(规格1回写主记录);提交时把首规格名称回写主表单 specName;多规格用可横滑 tab 切换卡片编辑
+  解决问题:详情 specList 首项即主记录自身;开启多规格时隐藏卡片外主图/封面,改在规格卡片内编辑(规格1回写主记录);提交时把首规格名称回写主表单 specName;多规格用可横滑 pill tab;表单区视觉层次与开关/规格卡片统一美化
 -->
 <template>
   <view class="app-content">
@@ -17,13 +17,13 @@
 
         <view class="spec-switch-card">
           <view class="spec-switch-left">
-            <view class="spec-switch-icon"></view>
-            <view>
+            <view class="spec-switch-icon"></view>
+            <view class="spec-switch-copy">
               <view class="spec-switch-title">多规格</view>
             </view>
           </view>
           <view class="spec-switch-right">
-            <text>{{ form.specEnabled == 1 ? '已启用' : '未启用' }}</text>
+            <text class="spec-switch-status">{{ form.specEnabled == 1 ? '已启用' : '未启用' }}</text>
             <switch class="spec-switch-ctrl" :checked="form.specEnabled == 1" @change="toggleSpecs" color="#09C567" />
           </view>
         </view>
@@ -161,15 +161,6 @@
           </view>
         </tui-list-cell>
 
-        <tui-list-cell class="line-cell category-wrap" :hover="false">
-          <view class="tui-title">使用场景</view>
-          <view class="tui-input">
-            <block v-for="item in useCaseData" :key="item.id"><button class="admin-button-com"
-                :class="[(form.useCaseIdList.includes(item.id + '') || form.useCaseIdList.includes(item.id * 1)) ? '' : 'default']"
-                @click="toggleUseCase(item)">{{ item.useCaseName }}</button></block>
-          </view>
-        </tui-list-cell>
-
         <tui-list-cell class="line-cell category-wrap" :hover="false">
           <view class="tui-title required">分类</view>
           <view class="tui-input">
@@ -181,6 +172,15 @@
           </view>
         </tui-list-cell>
 
+        <tui-list-cell class="line-cell category-wrap" :hover="false">
+          <view class="tui-title">使用场景</view>
+          <view class="tui-input">
+            <block v-for="item in useCaseData" :key="item.id"><button class="admin-button-com"
+                :class="[(form.useCaseIdList.includes(item.id + '') || form.useCaseIdList.includes(item.id * 1)) ? '' : 'default']"
+                @click="toggleUseCase(item)">{{ item.useCaseName }}</button></block>
+          </view>
+        </tui-list-cell>
+
         <tui-list-cell v-if="form.specEnabled != 1" class="line-cell" :hover="false">
           <view class="tui-title">价格类型</view>
           <view class="btn-group">
@@ -236,11 +236,11 @@
         <tui-list-cell v-if="form.specEnabled != 1" class="line-cell" :hover="false">
           <view class="tui-title">已售数量</view>
           <input v-model="form.sold" placeholder-class="phcolor" @focus="soldFocusHandler" @blur="soldBlurHandler"
-            class="tui-input" name="sold" placeholder="客户端展示:已售数量+实售数量" maxlength="10" type="number" />
+            class="tui-input" name="sold" placeholder="客户看到:已售数量+实售数量" maxlength="10" type="number" />
         </tui-list-cell>
 
         <tui-list-cell class="line-cell" :hover="false">
-          <view class="tui-title">节日涨价管理</view>
+          <view class="tui-title">节日涨价</view>
           <view class="btn-group">
             <button class="admin-button-com middle" :class="[form.autoRise === '1' ? '' : 'default']"
               @click="autoRiseChange('1')">参与涨价</button>
@@ -1127,6 +1127,14 @@ export default {
   .module-det {
     padding: 0 30upx;
   }
+
+  &.goods-wrap {
+    margin: 0 24upx 20upx;
+    padding-bottom: 16upx;
+    border-radius: 16upx;
+    border: 1px solid #f0f0f0;
+    overflow: hidden;
+  }
 }
 
 .category-wrap {
@@ -1138,10 +1146,11 @@ export default {
     flex-wrap: wrap;
 
     .admin-button-com {
-      margin-right: 30rpx;
-      margin-bottom: 20upx;
+      margin-right: 16rpx;
+      margin-bottom: 16upx;
       position: relative;
       z-index: 9999;
+      border-radius: 12upx;
     }
   }
 }
@@ -1149,8 +1158,9 @@ export default {
 .use-img {
   font-size: 22rpx;
   color: #999999;
-  padding-left: 4rpx 8rpx;
+  padding: 4rpx 0 8rpx;
   line-height: 1.5;
+  width: 100%;
 }
 
 .no-img-tip {
@@ -1163,9 +1173,12 @@ export default {
 .btn-group {
   display: flex;
   justify-content: flex-start;
+  flex-wrap: wrap;
 
   .admin-button-com {
-    margin-right: 35rpx;
+    margin-right: 20rpx;
+    margin-bottom: 8upx;
+    border-radius: 12upx;
 
     &:last-child {
       margin-right: 0;
@@ -1174,61 +1187,70 @@ export default {
 }
 
 .spec-switch-card {
-  margin: 0 20upx 20upx;
-  padding: 10upx 30upx;
-  border: 1px solid #e5f5ec;
-  border-radius: 12upx;
-  background: linear-gradient(90deg, #f3fff8 0%, #ffffff 100%);
+  margin: 16upx 24upx 24upx;
+  padding: 10upx 28upx;
+  border: 1px solid #dff5e8;
+  border-radius: 20upx;
+  background: linear-gradient(135deg, #f2fff8 0%, #ffffff 55%);
   display: flex;
   align-items: center;
   justify-content: space-between;
   box-sizing: border-box;
+  box-shadow: 0 6upx 20upx rgba(9, 197, 103, 0.06);
 }
 
 .spec-switch-left {
   display: flex;
   align-items: center;
   min-width: 0;
+  flex: 1;
 }
 
 .spec-switch-icon {
   width: 40upx;
   height: 40upx;
-  margin-right: 22upx;
-  border-radius: 50%;
+  margin-right: 18upx;
+  border-radius: 16upx;
   background: #09C567;
   color: #ffffff;
-  font-size: 28upx;
+  font-size: 22upx;
   display: flex;
   align-items: center;
   justify-content: center;
+  flex-shrink: 0;
+}
+
+.spec-switch-copy {
+  min-width: 0;
+  flex: 1;
 }
 
 .spec-switch-title {
-  font-size: 32upx;
-  color: #222222;
+  font-size: 30upx;
+  color: #1f1f1f;
   font-weight: 700;
-  line-height: 44upx;
+  line-height: 40upx;
 }
 
 .spec-switch-desc {
-  margin-top: 6upx;
-  font-size: 24upx;
-  color: #999999;
+  margin-top: 4upx;
+  font-size: 22upx;
+  color: #8c8c8c;
+  line-height: 32upx;
 }
 
 .spec-switch-right {
   display: flex;
   align-items: center;
   flex-shrink: 0;
-  color: #999999;
-  font-size: 24upx;
+  margin-left: 16upx;
 
-  text {
-    margin-right: 12upx;
+  .spec-switch-status {
+    margin-right: 8upx;
+    color: #8c8c8c;
+    font-size: 22upx;
   }
 
-  /* uni-app switch 无尺寸属性,用缩放缩小 */
   .spec-switch-ctrl {
     transform: scale(0.75);
     transform-origin: center right;
@@ -1236,22 +1258,25 @@ export default {
 }
 
 .spec-wrap {
-  padding: 0 20upx 20upx;
+  padding: 0 24upx 24upx;
 }
 
 .spec-card {
   margin-bottom: 20upx;
   background: #ffffff;
-  border: 3px solid #e8e8e8;
-  border-radius: 16upx;
+  border: 1px solid #eef0f2;
+  border-radius: 20upx;
   overflow: hidden;
+  box-shadow: 0 4upx 18upx rgba(0, 0, 0, 0.04);
 }
 
 .spec-card-head {
   display: flex;
   align-items: center;
   justify-content: space-between;
-  padding: 20upx 24upx 12upx;
+  padding: 24upx 24upx 16upx;
+  background: #fafbfc;
+  border-bottom: 1px solid #f0f0f0;
 }
 
 .spec-card-head-left {
@@ -1263,18 +1288,18 @@ export default {
 
 .spec-card-title {
   font-size: 30upx;
-  color: #222222;
+  color: #1f1f1f;
   font-weight: 700;
   flex-shrink: 0;
 }
 
 .spec-remove {
   margin: 0 0 0 16upx;
-  padding: 0 20upx;
+  padding: 0 22upx;
   height: 52upx;
   line-height: 52upx;
-  border: 1px solid #eeeeee;
-  border-radius: 8upx;
+  border: 1px solid #eadede;
+  border-radius: 26upx;
   background: #ffffff;
   color: #999999;
   font-size: 24upx;
@@ -1282,16 +1307,15 @@ export default {
 }
 
 .spec-add-btn {
-  margin: 0 0 0 16upx;
-  padding: 0 20upx;
+  margin: 0 0 0 20upx;
+  padding: 0 22upx;
   height: 52upx;
   line-height: 52upx;
-  border-radius: 8upx;
+  border-radius: 26upx;
   background: #09C567;
   color: #ffffff;
   font-size: 24upx;
   flex-shrink: 0;
-  margin-left: 40upx;
 }
 
 .spec-add-btn::after,
@@ -1301,27 +1325,27 @@ export default {
 
 .spec-tab-scroll {
   width: 100%;
-  height: 80upx;
+  height: 88upx;
   white-space: nowrap;
-  border-bottom: 1px solid #f0f0f0;
+  background: #f7f8fa;
 }
 
 .spec-tab-list {
   display: inline-flex;
   flex-direction: row;
   align-items: center;
-  height: 80upx;
-  padding: 0 12upx;
+  height: 88upx;
+  padding: 0 16upx;
 }
 
 .spec-tab-item {
   display: inline-flex;
   align-items: center;
   justify-content: center;
-  height: 80upx;
-  padding: 0 28upx;
-  margin-right: 8upx;
-  font-size: 28upx;
+  height: 56upx;
+  padding: 0 24upx;
+  margin-right: 12upx;
+  font-size: 26upx;
   color: #666666;
   flex-shrink: 0;
   max-width: 240upx;
@@ -1329,12 +1353,16 @@ export default {
   white-space: nowrap;
   text-overflow: ellipsis;
   box-sizing: border-box;
+  border-radius: 28upx;
+  background: #ffffff;
+  border: 1px solid #ececec;
 }
 
 .spec-tab-item.active {
   color: #09C567;
   font-weight: 700;
-  border-bottom: 4upx solid #09C567;
+  background: rgba(9, 197, 103, 0.12);
+  border-color: rgba(9, 197, 103, 0.35);
 }
 
 .spec-tab-text {
@@ -1348,26 +1376,29 @@ export default {
 }
 
 .spec-image-wrap {
-  padding: 10upx 0 20upx;
-  border-bottom: 1px solid #eeeeee;
+  margin: 8upx 16upx 16upx;
+  padding: 8upx 0 16upx;
+  border-radius: 16upx;
+  background: #fafbfc;
+  border: 1px solid #f0f0f0;
 
   .module-tit {
-    padding: 20upx 30upx;
+    padding: 16upx 24upx 8upx;
   }
 
   .module-det {
-    padding: 0 30upx;
+    padding: 0 24upx;
   }
 }
 
 .spec-cover-row {
   display: flex;
   align-items: flex-start;
-  padding: 20upx 30upx 0;
+  padding: 16upx 24upx 0;
 }
 
 .spec-cover-title {
-  width: 200upx;
+  width: 120upx;
   flex-shrink: 0;
   font-size: 28upx;
   color: #333333;
@@ -1380,12 +1411,12 @@ export default {
   flex-wrap: wrap;
 
   .admin-button-com {
-    margin-right: 30upx;
-    margin-bottom: 16upx;
+    margin-right: 16upx;
+    margin-bottom: 12upx;
+    border-radius: 12upx;
   }
 }
 
-
 /* 确保所有选中的按钮都使用相同的颜色 */
 .admin-button-com:not(.default) {
   background-color: #09C567 !important;
@@ -1402,11 +1433,15 @@ export default {
 .app-footer {
   justify-content: space-evenly;
   z-index: 9999;
+  padding-top: 16upx;
+  padding-bottom: calc(16upx + env(safe-area-inset-bottom));
+  box-shadow: 0 -6upx 20upx rgba(0, 0, 0, 0.04);
 
   .admin-button-com {
-    width: 46%;
-    padding-top: 30upx;
-    padding-bottom: 30upx;
+    width: 44%;
+    padding-top: 26upx;
+    padding-bottom: 26upx;
+    border-radius: 44upx;
 
     &:disabled {
       opacity: 0.6;

+ 122 - 1
hdApp/src/admin/home/psMethod.vue

@@ -156,6 +156,48 @@
             <view class="tui-title">{{ form.unMeet == 2 ? '包装费' : '运费' }}</view>
             <input type="digit" v-model="form.unMeetFee" @focus="form.unMeetFee = ''" class="tui-input" placeholder="请填写金额" />
           </tui-list-cell>
+          <!-- 附加费重收:自然日锁一天 或 按小时间隔冷却后再收 -->
+          <tui-list-cell class="line-cell" :hover="false" v-if="form.unMeet != 1">
+            <view class="tui-title">附加费重收</view>
+            <view class="btn-group">
+              <button
+                class="admin-button-com middle"
+                :class="[form.unMeetLockType == 0 ? 'blue' : 'default']"
+                @click="form.unMeetLockType = 0"
+              >
+                按自然日
+              </button>
+              <button
+                class="admin-button-com middle"
+                :class="[form.unMeetLockType == 1 ? 'blue' : 'default']"
+                @click="form.unMeetLockType = 1"
+                style="margin-left: 10upx;"
+              >
+                按时间间隔
+              </button>
+            </view>
+          </tui-list-cell>
+          <tui-list-cell class="line-cell" :hover="false" v-if="form.unMeet != 1 && form.unMeetLockType == 1">
+            <view class="tui-title">间隔时长</view>
+            <view class="input-row">
+              <input
+                type="digit"
+                v-model="form.unMeetLockHours"
+                @focus="form.unMeetLockHours = ''"
+                class="tui-input-sm"
+                placeholder="0.5"
+              />
+              <text class="unit-text">小时后再收</text>
+            </view>
+          </tui-list-cell>
+          <view
+            class="section-tip"
+            v-if="form.unMeet != 1"
+            style="padding: 0 30upx 20upx;"
+          >
+            <text v-if="form.unMeetLockType == 0">按自然日:同一客户当天收过该附加费后,当日不再收取。</text>
+            <text v-else>按时间间隔:收过附加费后,需间隔填写的小时数才会再次收取(支持小数,如 0.5)</text>
+          </view>
         </block>
 
         <!-- 跑腿 特有字段(花束运费、满减、自定义计费等) -->
@@ -349,6 +391,7 @@
  * 花店配送方式设置
  * 路由:admin/home/psMethod
  * 跑腿保存:无论用跑腿还是用自定义,都必须完整填写自定义计费;启用还需绑定跑腿或自定义完整
+ * 送货/快递:支持附加费重收规则(按自然日 或 按小时间隔冷却)
  */
 import TuiListCell from '@/components/plugin/list-cell'
 import { getPsMethodConfig, savePsMethodConfig, getPsMethodSorts } from '@/api/ps-method'
@@ -381,6 +424,11 @@ export default {
         minNum: 0,
         unMeet: 0,
         unMeetFee: 0.00,
+        /** 附加费重收:0 按自然日;1 按冷却秒(页面用小时录入) */
+        unMeetLockType: 0,
+        unMeetLockSeconds: 1800,
+        /** 仅编辑展示:小时,支持小数如 0.5 */
+        unMeetLockHours: 0.5,
         calcType: 0,
         hsFreeKm: 0.00,
         hsPerKmPrice: 0.00,
@@ -555,6 +603,11 @@ export default {
               minNum: data.minNum != null ? Number(data.minNum) : 0,
               unMeet: data.unMeet != null ? Number(data.unMeet) : 0,
               unMeetFee: data.unMeetFee != null ? parseFloat(data.unMeetFee) : 0.00,
+              unMeetLockType: data.unMeetLockType != null ? Number(data.unMeetLockType) : 0,
+              unMeetLockSeconds: data.unMeetLockSeconds != null ? Number(data.unMeetLockSeconds) : 1800,
+              unMeetLockHours: this.secondsToLockHours(
+                data.unMeetLockSeconds != null ? Number(data.unMeetLockSeconds) : 1800
+              ),
               calcType: data.calcType != null ? Number(data.calcType) : 0,
               hsFreeKm: data.hsFreeKm != null ? parseFloat(data.hsFreeKm) : 0.00,
               hsPerKmPrice: data.hsPerKmPrice != null ? parseFloat(data.hsPerKmPrice) : 0.00,
@@ -699,6 +752,64 @@ export default {
       this.$util.pageTo({ url: "/admin/shop/wl" });
     },
 
+    /**
+     * 冷却秒数 → 配置页小时(保留小数,去掉多余 0)
+     * @param {number} seconds
+     * @returns {number}
+     */
+    secondsToLockHours(seconds) {
+      const s = Number(seconds);
+      if (!(s > 0)) {
+        return 0.5;
+      }
+      return parseFloat((s / 3600).toFixed(4));
+    },
+
+    /**
+     * 配置页小时 → 冷却秒(四舍五入)
+     * @param {number|string} hours
+     * @returns {number}
+     */
+    hoursToLockSeconds(hours) {
+      const h = Number(hours);
+      if (!(h > 0)) {
+        return 0;
+      }
+      return Math.round(h * 3600);
+    },
+
+    /**
+     * 送货/快递附加费重收规则校验;通过则把小时写入 form.unMeetLockSeconds
+     * @returns {string} 错误文案,空表示通过
+     */
+    validateUnMeetLockBeforeSave() {
+      const style = Number(this.form.style);
+      if (style !== 0 && style !== 4) {
+        return "";
+      }
+      if (Number(this.form.unMeet) === 1) {
+        this.form.unMeetLockType = 0;
+        return "";
+      }
+      const lockType = Number(this.form.unMeetLockType) === 1 ? 1 : 0;
+      this.form.unMeetLockType = lockType;
+      if (lockType !== 1) {
+        // 自然日模式仍保留秒数字段默认值,便于切回间隔时有底
+        if (!(Number(this.form.unMeetLockSeconds) > 0)) {
+          this.form.unMeetLockSeconds = 1800;
+          this.form.unMeetLockHours = 0.5;
+        }
+        return "";
+      }
+      const seconds = this.hoursToLockSeconds(this.form.unMeetLockHours);
+      if (!(seconds > 0)) {
+        return "请填写大于 0 的间隔小时(支持小数,如 0.5)";
+      }
+      this.form.unMeetLockSeconds = seconds;
+      this.form.unMeetLockHours = this.secondsToLockHours(seconds);
+      return "";
+    },
+
     /**
      * 保存当前配置
      */
@@ -720,6 +831,12 @@ export default {
         }
       }
 
+      const lockErr = this.validateUnMeetLockBeforeSave();
+      if (lockErr) {
+        this.$msg(lockErr);
+        return;
+      }
+
       const runnerErr = this.validateRunnerBeforeSave()
       if (runnerErr) {
         this.$msg(runnerErr)
@@ -728,7 +845,11 @@ export default {
 
       savePsMethodConfig(this.form).then(res => {
           if (res.code == 1) {
-            this.$msg("保存成功");
+            if (Number(this.form.unMeetLockType) === 1 && (Number(this.form.style) === 0 || Number(this.form.style) === 4)) {
+              this.$msg(`保存成功,间隔 ${this.form.unMeetLockHours} 小时后再收`);
+            } else {
+              this.$msg("保存成功");
+            }
             // 重新加载配置刷新数据
             this.loadConfig(this.form.style);
             // 重新加载排序和别名信息

+ 8 - 2
hdPad/src/pages/home/components/console.vue

@@ -386,7 +386,10 @@ export default {
 		cancelSelectPrice(){
 			this.$refs.gatheringRef.close()
 		},
-		//直接收款
+		/**
+		 * 计算器直接收款:用户输入(及手选折)即最终应收。
+		 * 提交后不再套会员折扣/门店满减;传 skip* 避免 createHdOrder/addOrder 二次扣减。
+		 */
 		zjGathering(params){
 			uni.showLoading()
 			const payload = {
@@ -402,7 +405,10 @@ export default {
 				sendType: 1,
 				getGoods: 1,
 				hasPay: params.hasPay != null ? params.hasPay : 0,
-				payWay: Number(params.hasPay) === 1 ? (params.payWay != null ? params.payWay : 0) : 0
+				payWay: Number(params.hasPay) === 1 ? (params.payWay != null ? params.payWay : 0) : 0,
+				// 金额已是最终订单金额,禁止服务端再套会员折扣/门店满减(对齐 hdApp calculator)
+				skipMemberDiscount: 1,
+				skipShopMeetCut: 1
 			}
 			createOrder(payload).then(res=>{
 				uni.hideLoading()

+ 1 - 0
hdPad/src/pages/home/components/selectPrice.vue

@@ -1234,6 +1234,7 @@ export default {
                 source: 'submit',
                 orderOnly: !hasCalc,
             })
+            // 提交价即最终应收(含计算器手选折);父级 createOrder 须 skip 会员折扣/门店满减
             this.$emit('zjGathering', {
                 price: p,
                 name: this.name,