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

Merge branch 'zhongqi-intraCityExpress'

shish 11 месяцев назад
Родитель
Сommit
07335f2d07

+ 4 - 0
ghsApp/src/admin/home/me.vue

@@ -124,6 +124,10 @@
               <view class="tui-title">密码修改</view>
             </tui-list-cell>
 
+            <tui-list-cell @click="pageTo({ url: '/admin/shop/expressSet' })" class="line-cell" :hover="false" :arrow="true">
+              <view class="tui-title">跑腿设置</view>
+            </tui-list-cell>
+
             <tui-list-cell @click="pageTo({ url: '/admin/shop/print' })" class="line-cell" :hover="false" :arrow="true">
               <view class="tui-title">接单小票机</view>
             </tui-list-cell>

+ 7 - 3
ghsApp/src/admin/shop/add.vue

@@ -270,6 +270,7 @@ export default {
 				shopName: '',
 				province: '',
 				city: '',
+				dist: '',
 				address: '',
 				showAddress:'',
 				floor: '',
@@ -448,14 +449,17 @@ export default {
 			this.showRegion = true
 		},
 		changeAreaFn(e) {
-			this.form.address = e.name
-
 			let locationStr = e.location
 			let fruits = locationStr.split(",").map(fruit => fruit.trim())
-
 			this.region.lat = fruits[1]
 			this.region.long = fruits[0]
 			this.form.showAddress = e.address
+			this.form.address = e.name
+
+			// 提取地区信息,按遇到第一个"市"字后,把"市"后面的字符串作为地区
+			const districtStr = e.district || '';
+			const cityIndex = districtStr.indexOf('市');
+			this.form.dist = cityIndex !== -1 ? districtStr.substring(cityIndex + 1) : districtStr;
 		},
 		modifyShow(){
 			this.form.showAddress = this.form.city+this.form.address+this.form.floor

+ 1162 - 0
ghsApp/src/admin/shop/expressSet.vue

@@ -0,0 +1,1162 @@
+<template>
+  <view class="app-content">
+    <!-- 门店地址管理 -->
+    <view class="shop-address-section">
+      <view class="section-header">
+        <text class="section-title">门店地址</text>
+      </view>
+      
+      <view class="shop-info-card" v-if="shopAddress">
+        <view class="shop-status success">
+          <text class="status-icon">✓</text>
+          <text class="status-text">已创建门店地址</text>
+        </view>
+        <!-- <view class="shop-details">
+          <view class="detail-item">
+            <text class="detail-label">门店名称:</text>
+            <text class="detail-value">{{ shopAddress.shopName || '未设置' }}</text>
+          </view>
+          <view class="detail-item">
+            <text class="detail-label">门店地址:</text>
+            <text class="detail-value">{{ shopAddress.fullAddress || '未设置' }}</text>
+          </view>
+        </view> -->
+        <button class="update-btn" @click="updateShopAddressFn">
+          <text class="btn-text">更新门店地址</text>
+        </button>
+      </view>
+      
+      <view class="shop-info-card empty" v-else>
+        <view class="shop-status warning">
+          <text class="status-icon">!</text>
+          <text class="status-text">暂未创建门店地址</text>
+        </view>
+        <view class="shop-desc">
+          <text class="desc-text">请先创建门店地址,以便正常使用跑腿服务</text>
+        </view>
+        <button class="create-btn" @click="createShopAddress">
+          <text class="btn-text">创建门店</text>
+        </button>
+      </view>
+    </view>
+
+    <!-- 余额卡片 -->
+    <view class="balance-card">
+      <view class="balance-left">
+        <view class="balance-header">
+          <text class="balance-title">账户余额</text>
+        </view>
+        <view class="balance-amount">
+          <text class="amount-text">{{ balance.toFixed(2) }}</text>
+          <text class="balance-unit">元</text>
+        </view>
+        <view class="balance-desc">
+          <text class="desc-text">用于支付跑腿费用</text>
+        </view>
+      </view>
+      <view class="balance-right">
+        <view class="sub-balance sf">
+          <text class="sub-balance-label">达达</text>
+          <text class="sub-balance-amount">{{ dadaBalance.toFixed(2) }}元</text>
+        </view>
+        <view class="sub-balance dada">
+          <text class="sub-balance-label">顺丰同城</text>
+          <text class="sub-balance-amount">{{ sfBalance.toFixed(2) }}元</text>
+        </view>
+      </view>
+    </view>
+
+    <!-- 充值按钮 -->
+    <view class="recharge-section">
+      <button class="recharge-btn" @click="showRechargeModal">
+        <text class="btn-text">立即充值</text>
+      </button>
+    </view>
+
+    <!-- 充值记录 -->
+    <!-- <view class="record-section">
+      <view class="section-header">
+        <text class="section-title">充值记录</text>
+      </view>
+      <view class="record-list" v-if="rechargeRecords.length > 0">
+        <view class="record-item" v-for="(record, index) in rechargeRecords" :key="index">
+          <view class="record-info">
+            <text class="record-amount">+{{ record.amount }}元</text>
+            <text class="record-time">{{ record.time }}</text>
+          </view>
+          <text class="record-status" :class="record.status">{{ record.statusText }}</text>
+        </view>
+      </view>
+      <view class="empty-record" v-else>
+        <text class="empty-text">暂无充值记录</text>
+      </view>
+    </view> -->
+
+    <!-- 充值弹窗 -->
+    <view class="modal-overlay" v-if="showModal" @click="hideRechargeModal">
+      <view class="modal-content" @click.stop>
+        <view class="modal-header">
+          <text class="modal-title">账户充值</text>
+          <text class="modal-close" @click="hideRechargeModal">×</text>
+        </view>
+        
+        <view class="modal-body">
+          <view v-if="!showPayUrl">
+            <!-- 配送公司选择 -->
+            <view class="form-item">
+              <text class="form-label">选择跑腿</text>
+              <view class="express-company-options">
+                <view 
+                  class="express-option" 
+                  :class="{ active: expressCompany === 'DADA' }"
+                  @click="selectExpressCompany('DADA')"
+                >
+                  <text class="express-option-text">达达</text>
+                </view>
+                <view 
+                  class="express-option" 
+                  :class="{ active: expressCompany === 'SFTC' }"
+                  @click="selectExpressCompany('SFTC')"
+                >
+                  <text class="express-option-text">顺丰同城</text>
+                </view>
+              </view>
+            </view>
+            
+            <view class="form-item">
+              <text class="form-label">充值金额</text>
+              <view class="amount-input-wrapper">
+                <text class="currency-symbol">¥</text>
+                <input 
+                  class="amount-input" 
+                  type="digit" 
+                  v-model="rechargeAmount"
+                  placeholder="充值金额"
+                  @input="onAmountInput"
+                />
+              </view>
+              <view style="color:red;margin:10upx 0 10upx 0;font-size:24upx;font-weight:bold;">充值金额不能少于50元,用不完可以退</view>
+            </view>
+            
+            <!-- 快捷金额选择 -->
+            <view class="quick-amounts">
+              <text class="quick-title">快捷选择</text>
+              <view class="amount-options">
+                <view 
+                  class="amount-option" 
+                  v-for="amount in quickAmounts" 
+                  :key="amount"
+                  :class="{ active: rechargeAmount == amount }"
+                  @click="selectAmount(amount)"
+                >
+                  <text class="option-text">{{ amount }}元</text>
+                </view>
+              </view>
+            </view>
+          </view>
+          
+          <!-- 支付链接展示区域 -->
+          <view v-if="showPayUrl" class="pay-url-section">
+            <view class="pay-url-title">
+              <text>请复制以下链接在浏览器中打开完成支付</text>
+            </view>
+            <view class="pay-url-box">
+              <text class="pay-url-text" user-select>{{ payUrl }}</text>
+            </view>
+            <view class="copy-btn-wrapper">
+              <button class="copy-btn" @click="copyPayUrl">
+                <text class="copy-btn-text">复制链接</text>
+              </button>
+            </view>
+          </view>
+        </view>
+        
+        <view class="modal-footer">
+          <button class="cancel-btn" @click="hideRechargeModal">
+            <text class="cancel-text">{{ showPayUrl ? '关闭' : '取消' }}</text>
+          </button>
+          <button v-if="!showPayUrl" class="confirm-btn" @click="confirmRecharge" :disabled="!canRecharge">
+            <text class="confirm-text">确认充值</text>
+          </button>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+import TuiListCell from "@/components/plugin/list-cell";
+import { createStore, updateStore, getStore, getStoreBalance, rechargeStore } from "@/api/shop/shop-express.js";
+export default {
+  name: "expressSet",
+  components: {
+    TuiListCell,
+  },
+  data() {
+    return {
+      balance: 0.00, // 总账户余额
+      sfBalance: 0.00, // 顺丰余额
+      dadaBalance: 0.00, // 达达余额
+      showModal: false, // 是否显示充值弹窗
+      rechargeAmount: '', // 充值金额
+      expressCompany: 'DADA', // 跑腿公司,默认达达
+      quickAmounts: [50, 100, 200, 500], // 快捷金额选项
+      rechargeRecords: [], // 充值记录
+      shopAddress: null, // 门店地址信息
+      loading: false,
+      payUrl: '', // 支付链接
+      showPayUrl: false, // 是否显示支付链接
+      wxStoreId:''
+    };
+  },
+  computed: {
+    canRecharge() {
+      const amount = parseFloat(this.rechargeAmount);
+      return amount > 0 && amount <= 1000000; // 限制最大充值金额
+    }
+  },
+  onLoad() {
+    
+  },
+  onShow() {
+    uni.setNavigationBarTitle({
+      title: `跑腿设置`,
+    });
+  },
+  methods: {
+    // 复制支付链接
+    copyPayUrl() {
+      uni.setClipboardData({
+        data: this.payUrl,
+        success: () => {
+          uni.showToast({
+            title: '链接已复制',
+            icon: 'success'
+          });
+        }
+      });
+    },
+    init() {
+      this.initExpress()
+    },
+    async initExpress(){
+      try {
+        this.loading = true;
+        // 获取门店地址信息
+        this.getShopAddressInfo();
+        // 获取账户余额和充值记录
+        this.getBalance();
+        this.getRechargeRecords();
+      } catch (error) {
+        console.error('初始化失败:', error);
+        uni.showToast({
+          title: '加载失败',
+          icon: 'none'
+        });
+      } finally {
+        this.loading = false;
+      }
+    },
+    // 获取门店地址信息
+    async getShopAddressInfo() {
+      try {
+        const result = await getStore();
+
+        console.log(result.data);
+        if (result.data.id) {
+          this.shopAddress = result.data ? {
+            province: result.data.province,
+            city: result.data.city,
+            area: result.data.dist,
+            floor: result.data.floor,
+            address: result.data.address,
+            lat: result.data.lat,
+            lng: result.data.long,
+            wxStoreId: result.data.wx_store_id
+          } : null;
+        } else {
+          this.shopAddress = result.data ? {
+            province: result.data.address_info.province,
+            city: result.data.address_info.city,
+            area: result.data.address_info.area,
+            street: result.data.address_info.street,
+            house: result.data.address_info.house,
+            lat: result.data.address_info.lat,
+            lng: result.data.address_info.lng,
+            cityId: result.data.city_id,
+            orderPattern: result.data.order_pattern,
+            outStoreId: result.data.out_store_id,
+            serviceTransPrefer: result.data.service_trans_prefer,
+            wxStoreId: result.data.wx_store_id
+          } : null;
+          console.log(this.shopAddress);
+        }
+      } catch (error) {
+        // console.error('获取门店地址失败:', error);
+        // 如果接口不存在或失败,设置为null
+        this.shopAddress = null;
+      }
+    },
+
+    // 创建门店地址
+    async createShopAddress() {
+      try {
+        uni.showLoading({
+          title: '创建中...'
+        });
+
+        // 调用创建门店地址API
+        const result = await createStore({
+          // 这里可以传入默认的门店信息
+          shopName: '默认门店',
+          province: '',
+          city: '',
+          address: '',
+          lat: 0,
+          lng: 0
+        });
+
+        uni.hideLoading();
+
+        if (result.code === 1) {
+          uni.showToast({
+            title: '创建成功',
+            icon: 'success'
+          });
+          
+          // 刷新门店信息
+          await this.getShopAddressInfo();
+        } else {
+          if(result.msg && result.msg.includes('address_info.house is empty')){
+            this.$msg('门店的门牌号未填写')
+          } else {
+            console.log(result.message);
+            uni.showToast({
+              title: '创建失败',
+              icon: 'none'
+            });
+          }
+        }
+      } catch (error) {
+        uni.hideLoading();
+        console.error('创建门店地址失败:', error);
+        uni.showToast({
+          title: '创建失败,请重试',
+          icon: 'none'
+        });
+      }
+    },
+
+    // 更新门店地址
+    async updateShopAddressFn() {
+      try {
+        uni.showLoading({
+          title: '更新中...'
+        });
+
+        // 调用更新门店地址API
+        const result = await updateStore({
+          id: this.shopAddress.id,
+          province: this.shopAddress.province,
+          city: this.shopAddress.city,
+          address: this.shopAddress.address,
+          lat: this.shopAddress.lat,
+          lng: this.shopAddress.lng
+        });
+
+        uni.hideLoading();
+
+        if (result.code === 1) {
+          uni.showToast({
+            title: '更新成功',
+            icon: 'success'
+          });
+          
+          // 刷新门店信息
+          await this.getShopAddressInfo();
+        } else {
+          console.log(result);
+          if(result.msg && result.msg.includes('content.address_info.house is empty')){
+            this.$msg('门店的门牌号未填写')
+          } else {
+            console.log(result.msg);
+            uni.showToast({
+              title: '更新失败',
+              icon: 'none'
+            });
+          }
+        }
+      } catch (error) {
+        uni.hideLoading();
+        console.error('更新门店地址失败:', error);
+        if(error.msg && error.msg.includes('content.address_info.house is empty')){
+          this.$msg('门店的门牌号未填写')
+        } else {
+          console.log(error.msg);
+          this.$msg('更新失败')
+        }
+      }
+    },
+
+    // 获取账户余额
+    async getBalance() {
+      try {
+        const result = await getStoreBalance();
+        this.balance = result.data.all_balance || 0;
+        // 获取顺丰和达达的余额
+        this.sfBalance = result.data.sf_balance || 0;
+        this.dadaBalance = result.data.dada_balance || 0;
+      } catch (error) {
+        console.log(error);
+        // console.error('获取余额失败:', error);
+      }
+    },
+
+    // 获取充值记录
+    async getRechargeRecords() {
+      try {
+        // 这里调用实际的API获取充值记录
+        // const result = await getRechargeRecords();
+        // this.rechargeRecords = result.data || [];
+        
+        // 模拟数据
+        this.rechargeRecords = [
+          {
+            amount: 100,
+            time: '2024-01-15 14:30:25',
+            status: 'success',
+            statusText: '充值成功'
+          },
+          {
+            amount: 200,
+            time: '2024-01-10 09:15:30',
+            status: 'success',
+            statusText: '充值成功'
+          }
+        ];
+      } catch (error) {
+        console.error('获取充值记录失败:', error);
+      }
+    },
+
+    // 显示充值弹窗
+    showRechargeModal() {
+      this.showModal = true;
+      this.rechargeAmount = '';
+      this.expressCompany = 'DADA'; // 默认选择顺丰
+    },
+
+    // 隐藏充值弹窗
+    hideRechargeModal() {
+      this.showModal = false;
+      this.rechargeAmount = '';
+      this.payUrl = '';
+      this.showPayUrl = false;
+    },
+    
+    // 选择跑腿公司
+    selectExpressCompany(company) {
+      this.expressCompany = company;
+    },
+
+    // 金额输入处理
+    onAmountInput(e) {
+      let value = e.detail.value;
+      // 限制只能输入数字和小数点
+      value = value.replace(/[^\d.]/g, '');
+      // 限制小数点后两位
+      if (value.includes('.')) {
+        const parts = value.split('.');
+        if (parts[1].length > 2) {
+          value = parts[0] + '.' + parts[1].substring(0, 2);
+        }
+      }
+      this.rechargeAmount = value;
+    },
+
+    // 选择快捷金额
+    selectAmount(amount) {
+      this.rechargeAmount = amount.toString();
+    },
+
+    // 确认充值
+    async confirmRecharge() {
+      if (!this.canRecharge) {
+        uni.showToast({
+          title: '请输入有效金额',
+          icon: 'none'
+        });
+        return;
+      }
+
+      const amount = parseFloat(this.rechargeAmount);
+      
+      try {
+        uni.showLoading({
+          title: '充值中...'
+        });
+
+        // 调用实际的充值API,传入金额和跑腿公司
+        const result = await rechargeStore({ 
+          amount: amount,
+          expressId: this.expressCompany // 添加跑腿公司参数
+        });
+        
+        uni.hideLoading();
+        
+        if (result.code === 1 && result.data && result.data.payurl) {
+          // 保存支付链接并显示
+          this.payUrl = result.data.payurl;
+          this.showPayUrl = true;
+          
+          // 不关闭弹窗,而是显示支付链接
+        } else {
+          // 充值单生成成功但没有支付链接
+          uni.showToast({
+            title: '充值单已生成',
+            icon: 'success'
+          });
+          
+          this.hideRechargeModal();
+          
+          // 刷新余额和记录
+          await this.initExpress()
+        }
+        
+      } catch (error) {
+        uni.hideLoading();
+        console.error('充值失败:', error);
+        uni.showToast({
+          title: '充值失败,请重试',
+          icon: 'none'
+        });
+      }
+    }
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.app-content {
+  min-height: 100vh;
+  background-color: #f5f5f5;
+  padding: 20rpx;
+}
+
+// 门店地址管理样式
+.shop-address-section {
+  background-color: #ffffff;
+  border-radius: 20rpx;
+  padding: 30rpx;
+  margin-bottom: 30rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
+}
+
+.section-header {
+  margin-bottom: 30rpx;
+}
+
+.section-title {
+  color: #333333;
+  font-size: 32rpx;
+  font-weight: 600;
+}
+
+.shop-info-card {
+  &.empty {
+    text-align: center;
+    padding: 40rpx 0;
+  }
+}
+
+.shop-status {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 25rpx;
+  
+  &.success {
+    .status-icon {
+      color: #52c41a;
+      background-color: #f6ffed;
+      border: 2rpx solid #b7eb8f;
+    }
+  }
+  
+  &.warning {
+    .status-icon {
+      color: #faad14;
+      background-color: #fffbe6;
+      border: 2rpx solid #ffe58f;
+    }
+  }
+}
+
+.status-icon {
+  width: 40rpx;
+  height: 40rpx;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 24rpx;
+  font-weight: bold;
+  margin-right: 15rpx;
+}
+
+.status-text {
+  color: #333333;
+  font-size: 30rpx;
+  font-weight: 500;
+}
+
+.shop-desc {
+  margin-bottom: 30rpx;
+  
+  .desc-text {
+    color: #666666;
+    font-size: 26rpx;
+    line-height: 1.5;
+  }
+}
+
+.shop-details {
+  margin-bottom: 30rpx;
+}
+
+.detail-item {
+  display: flex;
+  margin-bottom: 15rpx;
+  
+  &:last-child {
+    margin-bottom: 0;
+  }
+}
+
+.detail-label {
+  color: #666666;
+  font-size: 26rpx;
+  min-width: 140rpx;
+}
+
+.detail-value {
+  color: #333333;
+  font-size: 26rpx;
+  flex: 1;
+}
+
+.create-btn, .update-btn {
+  width: 60%;
+  height: 80rpx;
+  border-radius: 40rpx;
+  border: none;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 28rpx;
+  font-weight: 500;
+  transition: all 0.3s ease;
+}
+
+.create-btn {
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.3);
+  
+  .btn-text {
+    color: #ffffff;
+  }
+  
+  &:active {
+    transform: translateY(2rpx);
+    box-shadow: 0 4rpx 12rpx rgba(102, 126, 234, 0.3);
+  }
+}
+
+.update-btn {
+  background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
+  box-shadow: 0 8rpx 24rpx rgba(82, 196, 26, 0.3);
+  
+  .btn-text {
+    color: #ffffff;
+  }
+  
+  &:active {
+    transform: translateY(2rpx);
+    box-shadow: 0 4rpx 12rpx rgba(82, 196, 26, 0.3);
+  }
+}
+
+// 余额卡片样式
+.balance-card {
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  border-radius: 20rpx;
+  padding: 40rpx 30rpx;
+  margin-bottom: 30rpx;
+  box-shadow: 0 8rpx 32rpx rgba(102, 126, 234, 0.3);
+  display: flex;
+  justify-content: space-between;
+}
+
+.balance-left {
+  flex: 1;
+}
+
+.balance-right {
+  width: 200rpx;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  border-left: 2rpx solid rgba(255, 255, 255, 0.2);
+  padding-left: 30rpx;
+  margin-left: 20rpx;
+}
+
+.balance-header {
+  display: flex;
+  align-items: center;
+  margin-bottom: 20rpx;
+}
+
+.balance-title {
+  color: rgba(255, 255, 255, 0.9);
+  font-size: 28rpx;
+  font-weight: 400;
+}
+
+.balance-amount {
+  margin-bottom: 15rpx;
+  display: flex;
+  align-items: baseline;
+}
+
+.amount-text {
+  color: #ffffff;
+  font-size: 60rpx;
+  font-weight: 600;
+  font-family: 'DIN Alternate', sans-serif;
+}
+
+.balance-unit {
+  color: rgba(255, 255, 255, 0.7);
+  font-size: 24rpx;
+  margin-left: 10rpx;
+}
+
+.balance-desc {
+  .desc-text {
+    color: rgba(255, 255, 255, 0.8);
+    font-size: 21rpx;
+  }
+}
+
+.sub-balance {
+  display: flex;
+  flex-direction: column;
+  padding: 10rpx 0;
+  
+  &.sf {
+    margin-bottom: 20rpx;
+    padding-bottom: 20rpx;
+    border-bottom: 2rpx solid rgba(255, 255, 255, 0.2);
+  }
+}
+
+.sub-balance-label {
+  color: rgba(255, 255, 255, 0.8);
+  font-size: 24rpx;
+  margin-bottom: 8rpx;
+}
+
+.sub-balance-amount {
+  color: #ffffff;
+  font-size: 32rpx;
+  font-weight: 600;
+  font-family: 'DIN Alternate', sans-serif;
+}
+
+// 充值按钮样式
+.recharge-section {
+  margin-bottom: 30rpx;
+}
+
+.recharge-btn {
+  width: 60%;
+  height: 88rpx;
+  background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
+  border-radius: 44rpx;
+  border: none;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-shadow: 0 8rpx 24rpx rgba(255, 107, 107, 0.3);
+  transition: all 0.3s ease;
+}
+
+.recharge-btn:active {
+  transform: translateY(2rpx);
+  box-shadow: 0 4rpx 12rpx rgba(255, 107, 107, 0.3);
+}
+
+.btn-text {
+  color: #ffffff;
+  font-size: 32rpx;
+  font-weight: 600;
+}
+
+// 记录区域样式
+.record-section {
+  background-color: #ffffff;
+  border-radius: 20rpx;
+  padding: 30rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
+}
+
+.record-list {
+  .record-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 25rpx 0;
+    border-bottom: 1rpx solid #f0f0f0;
+    
+    &:last-child {
+      border-bottom: none;
+    }
+  }
+  
+  .record-info {
+    display: flex;
+    flex-direction: column;
+  }
+  
+  .record-amount {
+    color: #333333;
+    font-size: 30rpx;
+    font-weight: 600;
+    margin-bottom: 8rpx;
+  }
+  
+  .record-time {
+    color: #999999;
+    font-size: 24rpx;
+  }
+  
+  .record-status {
+    font-size: 26rpx;
+    padding: 8rpx 16rpx;
+    border-radius: 20rpx;
+    
+    &.success {
+      color: #52c41a;
+      background-color: #f6ffed;
+    }
+    
+    &.pending {
+      color: #faad14;
+      background-color: #fffbe6;
+    }
+    
+    &.failed {
+      color: #ff4d4f;
+      background-color: #fff2f0;
+    }
+  }
+}
+
+.empty-record {
+  text-align: center;
+  padding: 60rpx 0;
+  
+  .empty-text {
+    color: #999999;
+    font-size: 28rpx;
+  }
+}
+
+// 支付链接样式
+.pay-url-section {
+  padding: 20rpx 0;
+}
+
+.pay-url-title {
+  margin-bottom: 20rpx;
+  text-align: center;
+  
+  text {
+    color: #333333;
+    font-size: 28rpx;
+  }
+}
+
+.pay-url-box {
+  background-color: #f5f5f5;
+  border-radius: 12rpx;
+  padding: 20rpx;
+  margin-bottom: 30rpx;
+  word-break: break-all;
+  border: 2rpx dashed #ddd;
+}
+
+.pay-url-text {
+  color: #0066cc;
+  font-size: 26rpx;
+  line-height: 1.5;
+}
+
+.copy-btn-wrapper {
+  display: flex;
+  justify-content: center;
+}
+
+.copy-btn {
+  width: 60%;
+  height: 80rpx;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  border-radius: 40rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-shadow: 0 8rpx 16rpx rgba(102, 126, 234, 0.3);
+  transition: all 0.3s ease;
+  
+  &:active {
+    transform: translateY(2rpx);
+    box-shadow: 0 4rpx 8rpx rgba(102, 126, 234, 0.3);
+  }
+}
+
+.copy-btn-text {
+  color: #ffffff;
+  font-size: 28rpx;
+  font-weight: 500;
+}
+
+// 弹窗样式
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 9999;
+}
+
+.modal-content {
+  width: 600rpx;
+  background-color: #ffffff;
+  border-radius: 20rpx;
+  overflow: hidden;
+  animation: modalSlideIn 0.3s ease;
+}
+
+@keyframes modalSlideIn {
+  from {
+    opacity: 0;
+    transform: scale(0.8) translateY(50rpx);
+  }
+  to {
+    opacity: 1;
+    transform: scale(1) translateY(0);
+  }
+}
+
+.modal-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 30rpx;
+  border-bottom: 1rpx solid #f0f0f0;
+}
+
+.modal-title {
+  color: #333333;
+  font-size: 32rpx;
+  font-weight: 600;
+}
+
+.modal-close {
+  color: #999999;
+  font-size: 40rpx;
+  line-height: 1;
+  padding: 10rpx;
+}
+
+.modal-body {
+  padding: 30rpx;
+}
+
+.form-item {
+  margin-bottom: 30rpx;
+}
+
+.form-label {
+  display: block;
+  color: #333333;
+  font-size: 28rpx;
+  font-weight: 500;
+  margin-bottom: 20rpx;
+}
+
+.amount-input-wrapper {
+  display: flex;
+  align-items: center;
+  border: 2rpx solid #e8e8e8;
+  border-radius: 12rpx;
+  padding: 0 20rpx;
+  background-color: #fafafa;
+  transition: all 0.3s ease;
+  
+  &:focus-within {
+    border-color: #667eea;
+    background-color: #ffffff;
+  }
+}
+
+.currency-symbol {
+  color: #333333;
+  font-size: 32rpx;
+  font-weight: 600;
+  margin-right: 15rpx;
+}
+
+.amount-input {
+  flex: 1;
+  height: 80rpx;
+  font-size: 32rpx;
+  color: #333333;
+  background: transparent;
+  border: none;
+}
+
+.quick-amounts {
+  margin-top: 30rpx;
+}
+
+.quick-title {
+  display: block;
+  color: #666666;
+  font-size: 26rpx;
+  margin-bottom: 20rpx;
+}
+
+.amount-options {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 20rpx;
+}
+
+.amount-option {
+  flex: 1;
+  min-width: 120rpx;
+  height: 70rpx;
+  border: 2rpx solid #e8e8e8;
+  border-radius: 12rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #ffffff;
+  transition: all 0.3s ease;
+  
+  &.active {
+    border-color: #667eea;
+    background-color: #667eea;
+    
+    .option-text {
+      color: #ffffff;
+    }
+  }
+  
+  &:active {
+    transform: scale(0.95);
+  }
+}
+
+.option-text {
+  color: #333333;
+  font-size: 26rpx;
+  font-weight: 500;
+}
+
+// 跑腿公司选择样式
+.express-company-options {
+  display: flex;
+  flex-direction: row;
+  gap: 30rpx;
+  margin-bottom: 20rpx;
+}
+
+.express-option {
+  height: 80rpx;
+  border: 2rpx solid #e8e8e8;
+  border-radius: 12rpx;
+  display: flex;
+  align-items: center;
+  padding: 0 20rpx;
+  background-color: #ffffff;
+  transition: all 0.3s ease;
+  
+  &.active {
+    border-color: #667eea;
+    background-color: #f0f4ff;
+    
+    .express-option-text {
+      color: #667eea;
+    }
+  }
+  
+  &:active {
+    transform: scale(0.98);
+  }
+}
+
+.express-option-text {
+  color: #333333;
+  font-size: 28rpx;
+  font-weight: 500;
+}
+
+.modal-footer {
+  display: flex;
+  border-top: 1rpx solid #f0f0f0;
+}
+
+.cancel-btn, .confirm-btn {
+  flex: 1;
+  height: 88rpx;
+  border: 1rpx solid #e8e8e8;
+  border-radius: 8rpx;
+  font-size: 30rpx;
+  font-weight: 500;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.cancel-btn {
+  background-color: #f5f5f5;
+  
+  .cancel-text {
+    color: #666666;
+  }
+}
+
+.confirm-btn {
+  background-color: #52c41a;
+  
+  .confirm-text {
+    color: #666666;
+  }
+  
+  &:disabled {
+    background-color: #f5f5f5 !important;
+    
+    .confirm-text {
+      color: #666666 !important;
+    }
+  }
+}
+</style>

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

@@ -0,0 +1,54 @@
+import https from '@/plugins/luch-request_0.0.7/request'
+
+// 创建门店地址
+export const createStore = data => {
+	return https.post('/intra-city/create-store', data)
+}
+
+// 更新门店地址
+export const updateStore = data => {
+	return https.post('/intra-city/update-store', data)
+}
+
+// 获取门店地址信息
+export const getStore = data => {
+	return https.post('/intra-city/store', data)
+}
+
+// 门店运费充值
+export const rechargeStore = data => {
+	return https.post('/intra-city/store-charge', data)
+}
+
+// 获取门店余额
+export const getStoreBalance = data => {
+	return https.post('/intra-city/store-balance', data)
+}
+
+/**
+ * 查询运费
+ */
+export const getStoreFee = data => {
+	return https.post('/intra-city/store-fee', data)
+}
+
+/**
+ * 创建快递订单
+ */
+export const createExpressOrder = data => {
+	return https.post('/intra-city/create-order', data)
+}
+
+/**
+ * 取消快递订单
+ */
+export const cancelExpressOrder = data => {
+	return https.post('/intra-city/cancel-order', data)
+}
+
+/**
+ * 查询快递订单
+ */
+export const getExpressOrder = data => {
+	return https.post('/intra-city/get-order', data)
+}

+ 2 - 1
ghsApp/src/pages.json

@@ -222,7 +222,8 @@
 				{"path": "selectShop","style": {"navigationBarTitleText": "选择门店"}},
 				{"path": "wl","style": {"navigationBarTitleText": "物流列表"}},
 				{"path": "myShop","style": {"navigationBarTitleText": "我的门店"}},
-				{"path": "renew","style": {"navigationBarTitleText": "续期"}}
+				{"path": "renew","style": {"navigationBarTitleText": "续期"}},
+				{"path": "expressSet","style": {"navigationBarTitleText": "跑腿设置"}}
 			]
 		},
 		{