Browse Source

Merge remote-tracking branch 'origin/dev_v3_zb' into dev_v3_lqw

# Conflicts:
#	pages.json
#	pages/merchantCenter/index.vue
#	pages/users/vault/withdraw.vue
ext.liuqiwen3 1 day ago
parent
commit
7c31cacdba

+ 4 - 1
App.vue

@@ -1,6 +1,9 @@
 <script setup>
 <script setup>
 import { ref, computed, watch, nextTick } from "vue";
 import { ref, computed, watch, nextTick } from "vue";
 import { onLoad, onShow, onLaunch } from "@dcloudio/uni-app";
 import { onLoad, onShow, onLaunch } from "@dcloudio/uni-app";
+import { useAppStore } from "@/stores/app";
+
+const appStore = useAppStore();
 // onLoad 接受 A 页面传递的参数
 // onLoad 接受 A 页面传递的参数
 onLoad((option) => {
 onLoad((option) => {
 });
 });
@@ -11,7 +14,7 @@ onShow(() => {
 
 
 onLaunch(async () => {
 onLaunch(async () => {
   // console.log("app 页面 onLaunch");
   // console.log("app 页面 onLaunch");
-
+	await appStore.GET_WX_CONFIG();
 });
 });
 </script>
 </script>
 
 

+ 1 - 1
api/merchant.js

@@ -52,7 +52,7 @@ export function fetchMerchantRecordAPI(params) {
  * @param
  * @param
  */
  */
 export function fetchMerchantRestockListAPI(params) {
 export function fetchMerchantRestockListAPI(params) {
-  return request.get(`merchant/restock/list?metalType=${params.metalType}&limit=${params.limit}&page=${params.page}&type=${params.type}`);
+	return request.get(`merchant/restock/list?metalType=${params.metalType}&limit=${params.limit}&page=${params.page}`);
 }
 }
 
 
 /**
 /**

+ 22 - 0
api/payment.js

@@ -0,0 +1,22 @@
+import request from "@/utils/request.js";
+
+/**
+ * 创建支付订单
+ * @param {Object} data - 支付订单参数
+ * @param {string} data.goodsId - 商品ID
+ * @param {number} data.amount - 支付金额
+ * @param {string} data.payType - 支付方式(wxpay/alipay)
+ */
+export function createPaymentOrder(params) {
+  return request.post("wxpay/v2/jsapi/pay", params);
+}
+
+/**
+ * 查询订单支付状态
+ * @param {string} orderNo - 订单编号
+ */
+export function queryPaymentStatus(orderNo) {
+  return request.get("wxpay/v2/order/query", {
+    orderNo,
+  });
+}

+ 15 - 0
api/svip.js

@@ -16,3 +16,18 @@ export function svipBuy(data) {
 
 
   return request.post("svip/buy", data);
   return request.post("svip/buy", data);
 }
 }
+
+
+/**
+ * 获取等级成长列表
+ *
+ */
+export function levelGrowthList() {
+  return request.get("user/level/benefits");
+}
+
+
+// 保存用户开通SVIP记录
+export function svipsaveAPI(data) {
+  return request.post("svip/save", data);
+}

+ 209 - 0
components/payment/WechatPayment.vue

@@ -0,0 +1,209 @@
+<template>
+  <!-- 支付加载提示 -->
+  <view v-if="showPayLoading" class="pay-loading-mask">
+    <view class="pay-loading-box">
+      <view class="loading-spinner"></view>
+      <text class="loading-text">处理支付中...</text>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, getCurrentInstance } from "vue";
+import { createPaymentOrder, queryPaymentStatus } from "@/api/payment";
+import { generateCustomId } from "@/utils/util.js";
+
+// 组件实例
+const instance = getCurrentInstance();
+
+// 状态管理
+const orderNo = ref("");
+const orderId = ref("");
+const showPayLoading = ref(false);
+const paymentInProgress = ref(false);
+
+// 回调函数存储
+const callbacks = ref({
+  onUniPayCreate: null,
+  onUniPaySuccess: null,
+  onUniPayCancel: null,
+  onUniPayFail: null,
+});
+
+/**
+ * 发起微信支付
+ * @param {Object} options - 支付参数
+ * @param {number} options.amount - 支付金额(分)
+ * @param {string} options.description - 商品描述
+ * @param {string} options.openId - 用户openId
+ * @param {string} options.orderPrefix - 订单号前缀
+ * @param {Function} options.onUniPayCreate - 订单创建成功回调
+ * @param {Function} options.onUniPaySuccess - 支付成功回调
+ * @param {Function} options.onUniPayCancel - 取消支付回调
+ * @param {Function} options.onUniPayFail - 支付失败回调
+ */
+const createUniPay = async (options) => {
+  // 防止重复发起支付
+  if (paymentInProgress.value) return;
+
+  try {
+    paymentInProgress.value = true;
+    showPayLoading.value = true;
+
+    // 保存回调函数
+    Object.keys(callbacks.value).forEach((key) => {
+      callbacks.value[key] =
+        options[key] && typeof options[key] === "function"
+          ? options[key]
+          : () => {};
+    });
+
+    // 生成订单号(使用公共组件)
+    orderNo.value = generateCustomId(options.orderPrefix || "WX");
+
+    // 调用后端创建支付订单
+    const { data: payRes } = await createPaymentOrder({
+      amount: options.amount,
+      description: options.description,
+      openId: options.openId,
+      orderNo: orderNo.value,
+    });
+
+    // 订单创建成功,触发回调
+    callbacks.value.onUniPayCreate({
+      out_trade_no: orderNo.value,
+      ...payRes,
+    });
+
+    // 调起微信支付
+    await uni.requestPayment({
+      provider: "wxpay",
+      timeStamp: payRes.timeStamp.toString(),
+      nonceStr: payRes.nonceStr,
+      package: payRes.package,
+      signType: payRes.signType,
+      paySign: payRes.paySign,
+      success: () => {
+        confirmPaymentStatus();
+      },
+      fail: (err) => {
+        showPayLoading.value = false;
+        paymentInProgress.value = false;
+        if (err.errMsg && err.errMsg.includes("cancel")) {
+          callbacks.value.onUniPayCancel(err);
+        } else {
+          callbacks.value.onUniPayFail(err);
+        }
+      },
+    });
+  } catch (err) {
+    showPayLoading.value = false;
+    paymentInProgress.value = false;
+    console.error("支付流程异常:", err);
+    callbacks.value.onUniPayFail(err);
+  }
+};
+
+/**
+ * 确认支付状态(轮询查询)
+ */
+const confirmPaymentStatus = async () => {
+  try {
+    let checkCount = 0;
+    const maxCheckCount = 10; // 最多查询10次
+    const checkInterval = 1000; // 每次查询间隔1秒
+
+    const checkStatus = async () => {
+      // 超过最大查询次数,视为超时
+      if (checkCount >= maxCheckCount) {
+        showPayLoading.value = false;
+        paymentInProgress.value = false;
+        callbacks.value.onUniPayFail(
+          new Error("支付结果查询超时,请稍后查看订单状态")
+        );
+        return;
+      }
+
+      checkCount++;
+
+      try {
+        // 查询支付状态
+        const res = await queryPaymentStatus(orderNo.value);
+        // 根据后端返回的支付状态进行处理
+        if (res.code === 200) {
+          showPayLoading.value = false;
+          paymentInProgress.value = false;
+          callbacks.value.onUniPaySuccess({
+            ...res.data,
+            out_trade_no: orderNo.value,
+          });
+        }
+      } catch (err) {
+        // 查询接口出错,重试
+        console.error(`第${checkCount}次查询支付状态失败:`, err);
+        setTimeout(checkStatus, checkInterval);
+      }
+    };
+
+    // 开始第一次查询
+    checkStatus();
+  } catch (err) {
+    showPayLoading.value = false;
+    paymentInProgress.value = false;
+    console.error("确认支付状态异常:", err);
+    callbacks.value.onUniPayFail(err);
+  }
+};
+
+// 对外暴露方法
+defineExpose({
+  createUniPay,
+});
+</script>
+
+<style scoped>
+/* 支付加载提示样式 */
+.pay-loading-mask {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 9999;
+}
+
+.pay-loading-box {
+  background-color: white;
+  padding: 30rpx 40rpx;
+  border-radius: 16rpx;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.loading-spinner {
+  width: 50rpx;
+  height: 50rpx;
+  border: 4rpx solid #eee;
+  border-top-color: #07c160;
+  border-radius: 50%;
+  animation: spin 1s linear infinite;
+  margin-bottom: 20rpx;
+}
+
+.loading-text {
+  color: #333;
+  font-size: 28rpx;
+}
+
+/* 旋转动画 */
+@keyframes spin {
+  to {
+    transform: rotate(360deg);
+  }
+}
+</style>

+ 2 - 2
config/app.js

@@ -1,6 +1,6 @@
-// let domain = "https://www.shuibeibyg.com/front-api"; // 正式环境IP
+let domain = "https://www.shuibeibyg.com/front-api"; // 正式环境IP
 // let domain = "https://test.shuibeibyg.com/front-api"; // 测试环境IP
 // let domain = "https://test.shuibeibyg.com/front-api"; // 测试环境IP
-let domain = 'http://192.168.100.199:8081' // 晋守桦IP
+// let domain = 'http://192.168.100.199:8081' // 晋守桦IP
 // let domain = 'http://192.168.100.246:8081' // 韩朝龙IP
 // let domain = 'http://192.168.100.246:8081' // 韩朝龙IP
 let share = "https://www.shuibeibyg.com";
 let share = "https://www.shuibeibyg.com";
 
 

+ 22 - 2
pages.json

@@ -144,6 +144,26 @@
 				"navigationBarBackgroundColor": "#ffe079",
 				"navigationBarBackgroundColor": "#ffe079",
 				"navigationStyle": "custom"
 				"navigationStyle": "custom"
 			}
 			}
+		},
+		{
+			"path": "pages/VIP/VIP",
+			"style": {
+				"navigationBarTitleText": "VIP权益"
+			}
+		},
+		{
+			"path": "pages/webview/index",
+			"style": {
+				"navigationBarTitleText": "H5服务",
+				"navigationBarBackgroundColor": "#ffe079",
+				"navigationBarTextStyle": "black"
+			}
+		},
+		{
+			"path": "pages/SVIP/SVIP",
+			"style": {
+				"navigationBarTitleText": "SVIP权益"
+			}
 		}
 		}
 	],
 	],
 	"subPackages": [
 	"subPackages": [
@@ -197,7 +217,7 @@
 					}
 					}
 				},
 				},
 				{
 				{
-					"path": "bank_card_manage/index",
+					"path": "card_page/index",
 					"style": {
 					"style": {
 						"navigationBarTitleText": "卡包管理",
 						"navigationBarTitleText": "卡包管理",
 						"navigationBarBackgroundColor": "#ffe079",
 						"navigationBarBackgroundColor": "#ffe079",
@@ -212,7 +232,7 @@
 					}
 					}
 				},
 				},
 				{
 				{
-					"path": "bank_card_manage/create",
+					"path": "card_page/create",
 					"style": {
 					"style": {
 						"navigationBarTitleText": "卡包编辑",
 						"navigationBarTitleText": "卡包编辑",
 						"navigationBarBackgroundColor": "#ffe079",
 						"navigationBarBackgroundColor": "#ffe079",

+ 379 - 0
pages/SVIP/SVIP.vue

@@ -0,0 +1,379 @@
+<template>
+  <view class="level-container">
+    <!-- 顶部会员信息区域 -->
+    <view class="vip-info">
+      <view class="flex-between vip-box">
+        <view class="flex_2">
+          <view class="flex-between">
+            <view class="vip-text">
+              <view class="vip-title">SVIP会员</view>
+              <view class="vip-desc"
+                >会员等级 {{ appStore?.$userInfo?.level || 0 }}</view
+              >
+            </view>
+            <view class="point-info">
+              <text class="point-text">{{
+                appStore?.$userInfo?.integral || 0
+              }}</text>
+              <text class="point-desc">会员贝币</text>
+            </view>
+          </view>
+          <view>
+            <view class="growth-info">
+              <text>成长值 {{ appStore?.$userInfo?.experience || 0 }}</text>
+              <text class="growth-progress">
+                {{ appStore?.$userInfo?.experience || 0 }}/{{
+                  appStore?.$userInfo?.experienceCount || 0
+                }}
+              </text>
+            </view>
+            <up-line-progress
+              :percentage="percentExperience"
+              activeColor="#d6c3a3"
+              inactiveColor="#808080"
+              height="6"
+              :showText="false"
+            ></up-line-progress>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- SVIP尊享权益 -->
+    <view class="vip-benefit">
+      <view class="task-title">SVIP尊享权益</view>
+      <view class="task-item" v-for="(task, index) in taskList" :key="index">
+        <image class="task-icon" :src="task.icon"></image>
+        <view class="task-desc flex-center-between flex_1">
+          <text class="task-name">{{ task.name }}</text>
+          <text class="task-reward flex_1">{{ task.reward }}</text>
+        </view>
+      </view>
+    </view>
+
+    <!-- SVIP购买按钮(仅非SVIP用户显示) -->
+    <view class="svip-price" v-if="!isSvip">
+      <view class="flex-center" @click="handlePayOpen">
+        <view class="svip-price-btn">
+          <text class="svip-price-name">年费会员¥</text>
+          <text class="svip-price-num">{{ totalPrice }}</text>
+        </view>
+      </view>
+    </view>
+
+    <WechatPayment ref="wechatPaymentRef" />
+  </view>
+</template>
+
+<script setup>
+import { ref, computed } from "vue";
+import { useAppStore } from "@/stores/app";
+import { svipPrice, svipsaveAPI } from "@/api/svip";
+import { getUserInfo } from "@/api/user";
+// 引入封装的微信支付组件(替换原paymentCommon)
+import WechatPayment from "@/components/payment/WechatPayment.vue";
+// 引入后端接口(按需补充:如“创建会员订单”“标记SVIP身份”的接口)
+// import { createVipOrder, markUserSvip } from "@/api/vip";
+import { onLoad } from "@dcloudio/uni-app";
+
+// 状态管理
+const appStore = useAppStore();
+const wechatPaymentRef = ref(null); // 微信支付组件引用
+const totalPrice = ref(0); // 会员价格(单位:元,从接口获取)
+const orderId = ref(""); // 后端生成的会员订单ID(用于后续标记SVIP)
+
+// 计算是否为SVIP用户
+const isSvip = computed(() => {
+  return appStore.isLogin && !!appStore?.$userInfo?.svip;
+});
+// 获取用户信息
+async function fetchUserInfo() {
+  const { data } = await getUserInfo();
+  appStore.UPDATE_USERINFO(data);
+}
+// 会员权益列表
+const taskList = ref([
+  {
+    name: "每日福利",
+    reward: "200成长值",
+    icon: "https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/svip/%E8%B7%AF%E5%BE%84733%403x.png",
+  },
+  {
+    name: "回收特权",
+    reward: "回收价+0.3/克",
+    icon: "https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/svip/huishoutequan.png",
+  },
+  {
+    name: "整点秒杀",
+    reward: "抄底补贴,限时抢购",
+    icon: "https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/svip/zhengdianmiaosha.png",
+  },
+  {
+    name: "超级工具",
+    reward: "自动回收,金价预警使用权限",
+    icon: "https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/svip/chaojigongju.png",
+  },
+  {
+    name: "邮费减半",
+    reward: "邮费全部五折",
+    icon: "https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/svip/youfeijianban.png",
+  },
+  {
+    name: "专属服务群",
+    reward: "专属福利,优先传达",
+    icon: "https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/svip/zhuanshufuli.png",
+  },
+]);
+
+// 成长值进度百分比
+const percentExperience = computed(() => {
+  if (!appStore.isLogin) return 0;
+  const current = appStore.$userInfo.experience || 0;
+  const target = appStore.$userInfo.experienceCount || 1; // 避免除以0
+  const percent = Math.floor((current / target) * 100);
+  return percent > 100 ? 100 : percent;
+});
+
+// 页面加载时获取会员价格
+onLoad(() => {
+  getSvipPrice();
+});
+
+/**
+ * 获取SVIP会员价格(单位:元)
+ */
+const getSvipPrice = async () => {
+  try {
+    const res = await svipPrice();
+    totalPrice.value = Number(res.data) || 99; // 默认99元,防止接口返回异常
+  } catch (err) {
+    totalPrice.value = 99; // 兜底价格
+  }
+};
+
+/**
+ * 点击“开通会员”触发:发起微信支付
+ */
+const handlePayOpen = async () => {
+  // 1. 前置校验:是否登录、是否已为SVIP
+  if (!appStore.isLogin) {
+    uni.showToast({ title: "未登录", icon: "none" });
+    console.log("未登录");
+    return;
+  }
+  if (isSvip.value) {
+    uni.showToast({ title: "已经是svip会员", icon: "none" });
+    console.log("已经是svip会员");
+    return;
+  }
+  console.log("没有openId:", appStore?.$userInfo);
+
+  // 2. 校验用户openId(微信支付必需)
+  const userOpenId = appStore?.$userInfo?.openId; // 假设用户信息中存储了openId
+  if (!userOpenId) {
+    uni.showToast({ title: "用户openId获取失败", icon: "none" });
+    console.log("没有openId:");
+    return;
+  }
+
+  // 3. 调用微信支付组件的支付方法
+  wechatPaymentRef.value.createUniPay({
+    // 支付金额:元转分(微信支付要求单位为“分”)
+    amount: Math.round(totalPrice.value * 100),
+    description: `SVIP年费会员(¥${totalPrice.value})`, // 商品描述(显示在微信支付账单中)
+    openId: userOpenId, // 微信支付必需:用户的微信openId
+    orderPrefix: "SVIP", // 订单号前缀(与公共组件generateCustomId匹配)
+
+    /**
+     * 回调1:支付订单创建成功(用户尚未支付)
+     * 作用:记录后端生成的会员订单ID,用于后续支付成功后标记SVIP
+     */
+    onUniPayCreate: async (payRes) => {
+      console.log("会员支付订单创建成功:", payRes);
+      try {
+      } catch (err) {
+        console.error("创建会员订单异常:", err);
+      }
+    },
+
+    /**
+     * 回调2:支付成功(核心逻辑)
+     * 作用:通知后端标记用户为SVIP,刷新用户状态
+     */
+    onUniPaySuccess: async (payStatusRes) => {
+      console.log("SVIP会员支付成功:", payStatusRes);
+      try {
+        const res = await svipsaveAPI({
+          orderId: payStatusRes.out_trade_no,
+          price: totalPrice.value,
+          payType: "weixin",
+        });
+
+        appStore.USERINFO();
+      } catch (err) {
+        console.error("标记SVIP身份异常:", err);
+      }
+    },
+
+    /**
+     * 回调3:用户取消支付
+     */
+    onUniPayCancel: () => {
+      console.log("用户取消SVIP支付");
+    },
+
+    /**
+     * 回调4:支付失败(如网络异常、余额不足等)
+     */
+    onUniPayFail: (err) => {
+      const errMsg = err.message || "支付失败,请重新尝试";
+
+      console.error("SVIP会员支付失败:", err);
+    },
+  });
+};
+</script>
+
+<style scoped lang="scss">
+.level-container {
+  color: black;
+  position: relative;
+  top: -130rpx;
+}
+
+/* 顶部会员信息 */
+.vip-info {
+  color: #dfd7bc;
+  margin-bottom: -25rpx;
+  overflow: hidden;
+  background-image: url("https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/svip/svip-bg.jpg");
+  background-size: 100%;
+  background-repeat: no-repeat;
+  height: 450rpx;
+
+  .vip-box {
+    margin: 200rpx 90rpx 100rpx 265rpx;
+  }
+}
+.vip-avatar {
+  width: 151rpx;
+  height: 161rpx;
+  margin-right: 70rpx;
+  margin-top: 50rpx;
+}
+.vip-title {
+  font-size: 36rpx;
+  font-weight: bold;
+  margin-bottom: 8rpx;
+}
+.vip-desc {
+  font-size: 24rpx;
+  margin-bottom: 12rpx;
+}
+.growth-info {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-top: 20rpx;
+  margin-bottom: 5rpx;
+  font-size: 20rpx;
+}
+.point-info {
+  text-align: right;
+}
+.point-text {
+  font-size: 40rpx;
+  font-weight: bold;
+  display: block;
+}
+.point-desc {
+  font-size: 20rpx;
+  opacity: 0.8;
+}
+
+/* VIP尊享权益 */
+.vip-benefit {
+  padding: 30rpx;
+}
+.task-title {
+  font-size: 32rpx;
+  font-weight: bold;
+  margin: 32rpx 0 16rpx 0;
+}
+.task-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 20rpx 30rpx;
+  border: 1px solid #f2f2f2;
+  border-radius: 8rpx;
+  margin-bottom: 16rpx;
+  background-color: #f4f3f1;
+  .task-icon {
+    width: 70rpx;
+    height: 70rpx;
+    margin-right: 30rpx;
+  }
+}
+.task-desc {
+  .task-name {
+    font-size: 28rpx;
+    font-weight: bold;
+    margin-right: 30rpx;
+    width: 160rpx;
+    text-align: center;
+  }
+  .task-reward {
+    font-size: 24rpx;
+    color: #5d5c5a;
+  }
+}
+
+/* SVIP购买按钮 */
+.svip-price {
+  .svip-price-title {
+    font-size: 32rpx;
+    font-weight: bold;
+    text-align: center;
+  }
+  .flex-center {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+  .svip-price-btn {
+    margin-top: 20rpx;
+    display: inline-block;
+    border: 1px solid #fdfdf9;
+    border-radius: 20rpx;
+    padding: 40rpx 100rpx;
+    background-color: #fee1a9;
+    color: #080604;
+    font-size: 24rpx;
+    cursor: pointer;
+    .svip-price-num {
+      font-size: 40rpx;
+      font-weight: bold;
+      margin-left: 10rpx;
+    }
+  }
+}
+
+/* 工具类(如果项目中没有全局flex工具类,需保留) */
+.flex-between {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.flex-center-between {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.flex_1 {
+  flex: 1;
+}
+.flex_2 {
+  flex: 2;
+}
+</style>

+ 551 - 0
pages/VIP/VIP.vue

@@ -0,0 +1,551 @@
+<template>
+  <view class="level-container">
+    <!-- 顶部会员信息区域 -->
+    <view class="vip-info">
+      <view class="flex-between vip-box">
+        <view class="flex_2">
+          <view class="flex-between">
+            <view class="vip-text">
+              <view class="vip-title">VIP会员</view>
+              <view class="vip-desc"
+                >会员等级 {{ appStore?.$userInfo?.level || 0 }}</view
+              >
+            </view>
+            <view class="point-info">
+              <text class="point-text">{{
+                appStore?.$userInfo?.integral || 0
+              }}</text>
+              <text class="point-desc">会员贝币</text>
+            </view>
+          </view>
+          <view>
+            <view class="growth-info">
+              <text>成长值 {{ appStore?.$userInfo?.experience || 0 }}</text>
+              <text class="growth-progress">
+                {{ appStore?.$userInfo?.experience || 0 }}/{{
+                  appStore?.$userInfo?.experienceCount || 0
+                }}
+              </text>
+            </view>
+            <up-line-progress
+              :percentage="percentExperience"
+              activeColor="#d6c3a3"
+              inactiveColor="#808080"
+              height="6"
+              :showText="false"
+            ></up-line-progress>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <view class="vip-benefit">
+      <!-- VIP尊享权益区域 -->
+      <view class="vip-benefit-title">VIP尊享权益</view>
+      <view class="benefit-content">
+        <view class="benefit-list">
+          <view
+            class="benefit-item"
+            v-for="(item, index) in benefitList"
+            :key="index"
+          >
+            <image :src="item.icon" class="benefit-icon"></image>
+            <text class="benefit-text">{{ item.text }}</text>
+          </view>
+        </view>
+        <view class="benefit-desc">
+          <view>当前已解锁权益:</view>
+          <view>
+            买金-<text>{{ appStore.$userInfo?.buy || 0 }}</text
+            >元/克
+          </view>
+          <view>
+            回收+<text
+              ><text>{{ appStore.$userInfo?.sold || 0 }}</text></text
+            >元/克
+          </view>
+          <view>
+            购物折扣:<text>{{ appStore.$userInfo?.discount || "无" }}</text
+            >折
+          </view>
+        </view>
+      </view>
+
+      <!-- 做任务赚成长值/贝币区域 -->
+      <view class="task-title">做任务赚成长值/贝币</view>
+      <view class="task-item" v-for="(task, index) in taskList" :key="index">
+        <view class="task-desc">
+          <text class="task-name">{{ task.name }}</text>
+          <text class="task-reward">{{ task.reward }}</text>
+        </view>
+		<view class="submit-btn">
+			<up-button
+			  v-if="!appStore.$wxConfig?.auditModeEnabled"
+			  @click="toPages(task)"
+			  type="warning"
+			  :text="task.btnText"
+			  size="mini"
+			  shape="circle"
+			></up-button>
+		</view>
+        
+      </view>
+    </view>
+
+    <!-- vip成长系统 -->
+    <view class="vip-level-box">
+      <view class="vip-level-title">会员成长系统</view>
+      <view class="title-box">
+        <view class="title-item">等级</view>
+        <view class="title-item">图标</view>
+        <view class="title-item">成长值</view>
+        <view class="title-item">权益</view>
+      </view>
+
+      <scroll-view class="title-content" :scroll-y="true">
+        <view
+          class="content-list"
+          v-for="(item, index) in leveList"
+          :key="index"
+        >
+          <view class="content-item">{{ index + 1 }}</view>
+          <view class="content-item">
+            <image mode="heightFix" :src="item.icon"></image>
+          </view>
+          <view class="content-item">{{ item.experience }}</view>
+          <view class="content-item quanyi" style="width: 27%">
+            <text
+              >买金- <text class="gw"> {{ item.buy }}元/克</text>
+            </text>
+            <text>
+              卖金+<text class="gw"> {{ item.sold }}元/克</text>
+            </text>
+            <text
+              >购物 :<text class="gw zk">{{ item.discount }} 折</text></text
+            >
+          </view>
+        </view>
+        <veiw class="content-desc">
+          以上显示{{ leveList.length }}级,继续努力,更多等级权益等你探索~
+        </veiw>
+      </scroll-view>
+    </view>
+
+    <!-- 邀请新人弹窗 -->
+    <up-popup
+      :show="showInvite"
+      closeOnClickOverlay
+      mode="center"
+      @close="showInvite = !showInvite"
+    >
+      <view class="upopup-box">
+        <image
+          style="width: 100%"
+          src="https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/Invite/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20250807170542.jpg"
+          mode="widthFix"
+          showMenuByLongpress
+        ></image>
+        <button open-type="share" class="upopup-button">点击邀约</button>
+      </view>
+    </up-popup>
+  </view>
+</template>
+
+<script setup>
+import { ref, computed, onMounted } from "vue";
+import { useAppStore } from "@/stores/app";
+import { onLoad, onShareAppMessage } from "@dcloudio/uni-app";
+import { levelGrowthList } from "@/api/svip";
+
+const appStore = useAppStore();
+let leveList = ref([]);
+const showInvite = ref(false);
+
+onMounted(() => {
+  console.log("mounted1", appStore.$userInfo);
+
+  getLevelGrowthList();
+});
+
+// 权益列表数据
+const benefitList = ref([
+  {
+    icon: "https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/vip/storeGold.png",
+    text: "存金",
+  },
+  {
+    icon: "https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/vip/swapModel.png",
+    text: "换款",
+  },
+  {
+    icon: "https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/vip/Recycling.png",
+    text: "回收",
+  },
+  {
+    icon: "https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/vip/exchange.png",
+    text: "兑换",
+  },
+]);
+
+// 任务列表数据
+const taskList = ref([
+  {
+    name: "完善基本资料",
+    reward: "获得200成长值,200贝币",
+    btnText: "立即前往",
+    url: "/pages/personal_info/personal_info",
+  },
+  // {
+  //   name: "每日签到",
+  //   reward: "获得20成长值,20贝币",
+  //   btnText: "立即前往",
+  //   url: "/pages/bb_mall/index",
+  // },
+  {
+    name: "卖料",
+    reward: "每回收黄金1g,获得20成长值,20贝币",
+    btnText: "立即前往",
+    url: "/pages/users/vault/storeMetal/index",
+  },
+  {
+    name: "买料",
+    reward: "每买料黄金1g,获得20成长值,20贝币",
+    btnText: "立即前往",
+    url: "/pages/users/vault/rechargeGold",
+  },
+  // {
+  //   name: "攒金",
+  //   reward: "每攒1克,获得20成长值,20贝币",
+  //   btnText: "立即前往",
+  //   url: "/pages/users/utils/wool/index",
+  // },
+  {
+    name: "消费",
+    reward: "每消费1元工费,获得1成长值,1贝币",
+    btnText: "立即前往",
+    url: "/pages/users/vault/rechargeGold",
+  },
+  {
+    name: "邀请新人",
+    reward:
+      "邀请一位新人注册,可获得100成长值,100贝币;新人升级会员,可获得200成长值,200贝币。",
+    btnText: "立即邀请",
+    url: "invite",
+  },
+  {
+    name: "升级SVIP",
+    reward: "升级SVIP解锁更多功能,加速成长值成长",
+    btnText: "立即前往",
+    url: "/pages/SVIP/SVIP",
+  },
+]);
+
+// 跳转任务页面
+function toPages(task) {
+  // 买料、卖料、消费需要通过webview跳转
+  if (
+    [
+      "/pages/users/vault/rechargeGold",
+      "/pages/users/vault/storeMetal/index",
+      "/pages/users/vault/storeMetal/order",
+    ].includes(task.url)
+  ) {
+    const webviewPageUrl = `/pages/webview/index?path=${task.url}`;
+    uni.navigateTo({
+      url: webviewPageUrl,
+      fail: (err) => {
+        console.error("跳转到webview页面失败:", err);
+        uni.showToast({
+          title: "跳转失败,请重试",
+          icon: "none",
+          duration: 1500,
+        });
+      },
+    });
+    return; // 阻止继续执行后续跳转逻辑
+  }
+
+  // 其他任务的跳转逻辑
+  if (["/pages/index/index"].includes(task.url)) {
+    uni.switchTab({ url: task.url });
+  } else if (task.url === "invite") {
+    showInvite.value = true;
+  } else {
+    uni.navigateTo({ url: task.url });
+  }
+}
+
+// 计算成长值百分比
+const percentExperience = computed(() => {
+  if (appStore.isLogin) {
+    const percent = Math.floor(
+      (appStore?.$userInfo?.experience / appStore?.$userInfo?.experienceCount) *
+        100
+    );
+    return percent > 100 ? 100 : percent;
+  }
+  return 0;
+});
+
+const getLevelGrowthList = async () => {
+  const res = await levelGrowthList();
+  leveList.value = res.data;
+};
+
+// 分享功能
+onShareAppMessage(() => {
+  return {
+    title: "邀请您加入水贝搬运工",
+    path: `/pages/users/login/index?invite_code=${appStore.$userInfo.inviteCode}`,
+    imageUrl:
+      "https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/Invite/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20250807170542.jpg",
+  };
+});
+</script>
+
+<style scoped lang="scss">
+// 邀请新人弹窗
+.upopup-box {
+  width: 600rpx;
+  border-radius: 30rpx;
+  overflow: hidden;
+  position: relative;
+  background-color: none;
+
+  .upopup-button {
+    position: absolute;
+    bottom: 80rpx;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 200rpx;
+    height: 60rpx;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    background-color: #cc9933;
+    color: #ffffff;
+    font-size: 30rpx;
+    border-radius: 40rpx;
+    box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.2);
+  }
+}
+
+.level-container {
+  // background-color: #fff;
+  .up-nav-slot-title {
+    color: #fff;
+  }
+  color: black;
+  position: relative;
+  top: -130rpx;
+}
+
+/* 顶部会员信息 */
+.vip-info {
+  color: #dfd7bc;
+  background: url("https://sb-admin.oss-cn-shenzhen.aliyuncs.com/shuibei-mini/svip/vip-bg.jpg")
+    no-repeat center top;
+  background-size: 100%;
+  height: 450rpx;
+  overflow: hidden;
+
+  .vip-box {
+    margin: 200rpx 90rpx 100rpx 265rpx;
+  }
+}
+.vip-avatar {
+  width: 151rpx;
+  height: 161rpx;
+  margin-right: 70rpx;
+  margin-top: 50rpx;
+}
+.vip-title {
+  font-size: 36rpx;
+  font-weight: bold;
+  margin-bottom: 8rpx;
+}
+.vip-desc {
+  font-size: 24rpx;
+  margin-bottom: 12rpx;
+}
+.growth-info {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-top: 20rpx;
+  margin-bottom: 5rpx;
+  font-size: 20rpx;
+}
+.point-info {
+  text-align: right;
+}
+.point-text {
+  font-size: 40rpx;
+  font-weight: bold;
+  display: block;
+}
+.point-desc {
+  font-size: 20rpx;
+  opacity: 0.8;
+}
+
+/* VIP尊享权益标题 */
+.vip-benefit {
+  padding: 30rpx;
+  .vip-benefit-title {
+    font-size: 32rpx;
+    font-weight: bold;
+    margin: 32rpx 0 16rpx 0;
+  }
+  .benefit-content {
+    background-color: #323141;
+    padding: 40rpx 30rpx;
+    padding-bottom: 10rpx;
+    border-radius: 20rpx;
+    /* 权益列表 */
+    .benefit-list {
+      display: flex;
+      justify-content: space-between;
+      padding-bottom: 20rpx;
+      border-bottom: 1px dashed #797887;
+    }
+    .benefit-desc {
+      display: flex;
+      justify-content: space-between;
+      align-items: flex-end;
+      font-size: 18rpx;
+      color: #bdc3c7;
+      padding: 10rpx 0;
+      box-sizing: border-box;
+
+      text {
+        color: #d1bb9c;
+        font-size: 18rpx;
+      }
+    }
+    .benefit-item {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+    }
+    .benefit-icon {
+      width: 100rpx;
+      height: 100rpx;
+      margin-bottom: 8rpx;
+    }
+    .benefit-text {
+      font-size: 20rpx;
+      color: #fff;
+    }
+  }
+}
+
+/* 任务标题 */
+.task-title {
+  font-size: 32rpx;
+  font-weight: bold;
+  margin: 32rpx 0 16rpx 0;
+}
+
+/* 任务项 */
+.task-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 20rpx 30rpx;
+  border: 1px solid #f2f2f2;
+  border-radius: 8rpx;
+  margin-bottom: 16rpx;
+  background-color: #f4f3f1;
+  .submit-btn {
+    width: 120rpx;
+  }
+}
+.task-desc {
+  display: flex;
+  flex-direction: column;
+  flex: 1;
+}
+.task-name {
+  font-size: 28rpx;
+  font-weight: bold;
+  margin-bottom: 4rpx;
+}
+.task-reward {
+  font-size: 24rpx;
+  color: #999;
+}
+
+.vip-level-box {
+  .vip-level-title {
+    font-size: 32rpx;
+    font-weight: bold;
+    text-align: center;
+    margin-bottom: 30rpx;
+  }
+  .title-box {
+    height: 60rpx;
+    background: #302f3f;
+    display: flex;
+    align-items: center;
+    .title-item {
+      flex: 1;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      color: #fff;
+    }
+  }
+  .title-content {
+    width: 100%;
+
+    min-height: 500rpx;
+
+    .content-list {
+      display: flex;
+    }
+
+    .content-item {
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      font-size: 22rpx;
+      height: 120rpx;
+      border-bottom: 1px dashed #eee;
+      // width: 24%;
+      image {
+        height: 25rpx;
+        // height: 100%;
+      }
+    }
+    .quanyi {
+      align-items: flex-start;
+      // margin-right: 30rpx;
+    }
+    .gw {
+      margin-left: 5rpx;
+      &.zk {
+        letter-spacing: 6rpx;
+        margin-left: 9rpx;
+      }
+    }
+  }
+  .vip-level-img {
+    width: 100%;
+  }
+}
+.content-desc {
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-top: 20rpx;
+  font-size: 22rpx;
+}
+
+uni-page-body{
+	background-color: #fff !important;
+}
+</style>

+ 4 - 4
pages/merchantCenter/index.vue

@@ -137,10 +137,10 @@ const commonFunctions = ref([
   { src: '/static/images/setting/fabu.png', name: '发布商品',pageUrl:'/pages/merchantCenter/postInformation',show:true },
   { src: '/static/images/setting/fabu.png', name: '发布商品',pageUrl:'/pages/merchantCenter/postInformation',show:true },
   { src: '/static/images/setting/shangpin.png', name: '商品管理',pageUrl:'/pages/merchantCenter/productManagement',show:true },
   { src: '/static/images/setting/shangpin.png', name: '商品管理',pageUrl:'/pages/merchantCenter/productManagement',show:true },
   { src: '/static/images/setting/kucun.png', name: '库存管理',pageUrl:'/pages/users/user_asset/asset_info/asset_info' ,show:true},
   { src: '/static/images/setting/kucun.png', name: '库存管理',pageUrl:'/pages/users/user_asset/asset_info/asset_info' ,show:true},
-  { src: '/static/images/setting/jinqian.png', name: '我的收益',pageUrl: '' ,show:true},
-  { src: '/static/images/setting/kabao.png', name: '卡包管理' ,pageUrl: '/pages/users/bank_card_manage/index' ,show:true},
-  { src: '/static/images/setting/mendian.png', name: '门店推广',pageUrl: '/pages/users/my_merchant/index' ,show:true },
-  { src: '/static/images/setting/dianpu.png', name: '我的商城' ,pageUrl: '/pages/users/bank_card_manage/index' ,show:true},
+  { src: '/static/images/setting/jinqian.png', name: '我的收益',pageUrl: '/pages/users/my_merchant/index' ,show:appStore.merchantId?true:false},
+  { src: '/static/images/setting/kabao.png', name: '卡包管理' ,show:true},
+  { src: '/static/images/setting/mendian.png', name: '门店推广',show:true },
+  { src: '/static/images/setting/dianpu.png', name: '我的商城' ,show:true},
 ])
 ])
 const params = ref({
 const params = ref({
   page: 1,
   page: 1,

+ 86 - 14
pages/user/index.vue

@@ -47,7 +47,7 @@
             <image class="vipIcon" src="@/static/images/setting/vipIcon.png" mode="widthFix"></image>
             <image class="vipIcon" src="@/static/images/setting/vipIcon.png" mode="widthFix"></image>
             <text>开通<text class="bigText">会员</text>享受更多<text class="bigText">权益</text></text>
             <text>开通<text class="bigText">会员</text>享受更多<text class="bigText">权益</text></text>
           </view>
           </view>
-          <button class="open-vip">去开通<image class="bofang" src="@/static/images/setting/bofang.png" mode="widthFix"></image></button>
+          <button class="open-vip" @click="goVIP">去开通<image class="bofang" src="@/static/images/setting/bofang.png" mode="widthFix"></image></button>
         </view>
         </view>
       </view>
       </view>
     </view>
     </view>
@@ -74,17 +74,17 @@
         </view>
         </view>
       </view>
       </view>
 
 
-      <view class="wallet-actions">
-        <view class="wallet-btn withdraw" @click="recharge">充值</view>
-        <view class="wallet-btn recharge" @click="withdraw">提现</view>
+      <view class="wallet-actions" v-if="tradeList&&tradeList.length>0">
+        <view class="wallet-btn withdraw" @click="goDetail(tradeList[0].jumpUrl)">{{tradeList[0].iconName}}</view>
+        <view class="wallet-btn recharge" @click="goDetail(tradeList[1].jumpUrl)">{{tradeList[1].iconName}}</view>
       </view>
       </view>
 
 
-      <view class="functions">
-        <view class="function-item" v-for="item in mainFunctions" :key="item.name" @click="handleFunctionClick(item.pageUrl)">
+      <view class="functions" v-if="useList&&useList.length>0">
+        <view class="function-item" v-for="item in useList" :key="item.iconName" @click="goDetail(item.jumpUrl)">
           <view class="function-icon">
           <view class="function-icon">
             <image class="img" :src="item.src" mode="widthFix"></image>
             <image class="img" :src="item.src" mode="widthFix"></image>
           </view>
           </view>
-          <text class="function-name">{{ item.name }}</text>
+          <text class="function-name">{{ item.iconName }}</text>
         </view>
         </view>
       </view>
       </view>
     </view>
     </view>
@@ -152,7 +152,7 @@
 </template>
 </template>
 
 
 <script setup>
 <script setup>
-import { ref, reactive } from 'vue'
+import { ref, reactive, watch } from 'vue'
 import { onLoad, onShow, onReachBottom } from "@dcloudio/uni-app";
 import { onLoad, onShow, onReachBottom } from "@dcloudio/uni-app";
 import UniIcons from "../../uni_modules/uni-icons/components/uni-icons/uni-icons.vue";
 import UniIcons from "../../uni_modules/uni-icons/components/uni-icons/uni-icons.vue";
 import { HTTP_REQUEST_URL_IMG } from "@/config/app";
 import { HTTP_REQUEST_URL_IMG } from "@/config/app";
@@ -179,10 +179,10 @@ const wallet = ref({
 
 
 // 主要功能列表
 // 主要功能列表
 const mainFunctions = ref([
 const mainFunctions = ref([
-  { src: '/static/images/setting/mailiao.png', name: '买料',pageUrl:'/pages/users/vault/buy?type=buygold' },
-  { src: '/static/images/setting/mailiao2.png', name: '卖料',pageUrl:'/pages/users/vault/storeMetal/index?type=soldgold' },
-  { src: '/static/images/setting/cunliao.png', name: '存料',pageUrl:'/pages/users/vault/storeMetal/goldBullionStock?type=savegold' },
-  { src: '/static/images/setting/tiliao.png', name: '提料',pageUrl:'/pages/users/vault/storeMetal/metalExchange?type=materialdeduction' }
+  { src: '/static/images/setting/mailiao.png', name: '买料',pageUrl:'/pages/users/vault/rechargeGold' },
+  { src: '/static/images/setting/mailiao2.png', name: '卖料',pageUrl:'/pages/users/vault/storeMetal/index' },
+  { src: '/static/images/setting/cunliao.png', name: '存料',pageUrl:'/pages/users/vault/storeMetal/goldBullionStock' },
+  { src: '/static/images/setting/tiliao.png', name: '提料',pageUrl:'/pages/users/vault/storeMetal/metalExchange' }
 ])
 ])
 
 
 // 最近访问的商家
 // 最近访问的商家
@@ -221,6 +221,35 @@ onShow(() => {
   getHistoryList()
   getHistoryList()
 })
 })
 
 
+const wxConfig = ref({});
+const tradeList = ref([]);
+const useList = ref([])
+watch(
+  () => appStore.wxConfig,
+  (newVal) => {
+    const configDate = newVal || appStore.$wxConfig;
+    wxConfig.value = configDate;
+	const list = JSON.parse(configDate.essentialFunctions);
+    tradeList.value = [list[0],list[1]];
+	useList.value = [{
+		...list[2],
+		src: '/static/images/setting/mailiao.png'
+	},{
+		...list[3],
+		src: '/static/images/setting/mailiao2.png'
+	},{
+		...list[4],
+		src: '/static/images/setting/cunliao.png',
+		iconName: '存料'
+	},{
+		...list[5],
+		src: '/static/images/setting/tiliao.png'
+	}]
+	console.log(tradeList.value)
+  },
+  { deep: true, immediate: true }
+);
+
 // 编辑资料
 // 编辑资料
 const editProfile = () => {
 const editProfile = () => {
   uni.showToast({
   uni.showToast({
@@ -237,6 +266,11 @@ const openVip = () => {
   })
   })
 }
 }
 
 
+// 查看会员权益
+const goVIP = ()=>{
+	uni.navigateTo({ url:"/pages/VIP/VIP" });
+}
+
 // 查看交易明细
 // 查看交易明细
 const viewTransactionDetail = () => {
 const viewTransactionDetail = () => {
   if(!isLogin){
   if(!isLogin){
@@ -251,7 +285,7 @@ const recharge = () => {
   if(!isLogin){
   if(!isLogin){
     toLogin();
     toLogin();
   }else{
   }else{
-    uni.navigateTo({ url:"/pages/users/vault/recharge" });
+    uni.navigateTo({ url:`/pages/webview/index?path=${'/pages/users/vault/rechargeRmb'}` });
   }
   }
 }
 }
 
 
@@ -260,14 +294,52 @@ const withdraw = () => {
   if(!isLogin){
   if(!isLogin){
     toLogin();
     toLogin();
   }else{
   }else{
-    uni.navigateTo({ url:"/pages/users/vault/withdraw" });
+    uni.navigateTo({ url:`/pages/webview/index?path=${'/pages/users/vault/withdraw'}` });
   }
   }
 }
 }
 
 
+const goDetail = (url) => {
+	console.log(url)
+	const webviewPageUrl = `/pages/webview/index?path=${url}`;
+	uni.navigateTo({
+	  url: webviewPageUrl,
+	  fail: (err) => {
+	    console.error("跳转到webview页面失败:", err);
+	    uni.showToast({
+	      title: "跳转失败,请重试",
+	      icon: "none",
+	      duration: 1500,
+	    });
+	  },
+	});
+}
+
 // 功能点击
 // 功能点击
 const handleFunctionClick = (url) => {
 const handleFunctionClick = (url) => {
   console.log(url)
   console.log(url)
   if (!url) return;
   if (!url) return;
+  // 买料、卖料、消费需要通过webview跳转
+  if (
+    [
+      "/pages/users/vault/rechargeGold",
+      "/pages/users/vault/storeMetal/index",
+      "/pages/users/vault/storeMetal/order",
+    ].includes(url)
+  ) {
+    const webviewPageUrl = `/pages/webview/index?path=${url}`;
+    uni.navigateTo({
+      url: webviewPageUrl,
+      fail: (err) => {
+        console.error("跳转到webview页面失败:", err);
+        uni.showToast({
+          title: "跳转失败,请重试",
+          icon: "none",
+          duration: 1500,
+        });
+      },
+    });
+    return; // 阻止继续执行后续跳转逻辑
+  }
   uni.navigateTo({ url });
   uni.navigateTo({ url });
 }
 }
 
 

pages/users/bank_card_manage/create.vue → pages/users/card_page/create.vue


+ 3 - 2
pages/users/bank_card_manage/index.vue

@@ -128,7 +128,7 @@ const selectCard = async (card) => {
 const editCard = (card) => {
 const editCard = (card) => {
   const queryStr = `id=${card.id}&bankName=${card.bankName}&accountNumber=${card.accountNumber}&accountType=${card.accountType}&name=${card.accountName}&isDefault=${card.isDefault}`;
   const queryStr = `id=${card.id}&bankName=${card.bankName}&accountNumber=${card.accountNumber}&accountType=${card.accountType}&name=${card.accountName}&isDefault=${card.isDefault}`;
   uni.navigateTo({
   uni.navigateTo({
-    url: `/pages/users/bank_card_manage/create?${queryStr}`,
+    url: `/pages/users/card_page/create?${queryStr}`,
   });
   });
   isEditing.value = true;
   isEditing.value = true;
   currentEditIndex.value = bankCards.value.findIndex((c) => c.id === card.id);
   currentEditIndex.value = bankCards.value.findIndex((c) => c.id === card.id);
@@ -160,7 +160,8 @@ async function confirmDeleteCard() {
 }
 }
 
 
 const addNewCard = () => {
 const addNewCard = () => {
-  uni.navigateTo({ url: "/pages/users/bank_card_manage/create" });
+	console.log('create')
+  uni.navigateTo({ url: "/pages/users/card_page/create" });
   isEditing.value = false;
   isEditing.value = false;
   cardForm.bankName = "";
   cardForm.bankName = "";
   cardForm.cardNumber = "";
   cardForm.cardNumber = "";

+ 1 - 1
pages/users/user_asset/asset_info/asset_info.vue

@@ -349,7 +349,7 @@
 	.asset_container {
 	.asset_container {
 		// padding-top: 92rpx;
 		// padding-top: 92rpx;
 		background-color: #F9F7F0;
 		background-color: #F9F7F0;
-		height: 100%;
+		height: 100vh;
 		display: flex;
 		display: flex;
 		flex-direction: column;
 		flex-direction: column;
 		justify-content: flex-start;
 		justify-content: flex-start;

+ 68 - 19
pages/users/user_asset/record_list/record_list.vue

@@ -134,7 +134,7 @@
 				</view>
 				</view>
 			</view>
 			</view>
 		</view>
 		</view>
-		<view class="list_filter" v-show="menuType==1">
+		<view class="list_filter" v-if="menuType==1">
 			<view class="filter_title">
 			<view class="filter_title">
 
 
 			</view>
 			</view>
@@ -168,6 +168,12 @@
 					</view>
 					</view>
 				</view>
 				</view>
 			</view>
 			</view>
+			<view class="noMore" v-if="recordList.length>0&&!recordParams.hasMore">
+				到底了
+			</view>
+			<view class="empty" v-if="!recordList||recordList.length==0">
+				暂无数据
+			</view>
 
 
 		</scroll-view>
 		</scroll-view>
 		<scroll-view class="asset_list" scroll-y="true" v-show="menuType==2" :lower-threshold='100'
 		<scroll-view class="asset_list" scroll-y="true" v-show="menuType==2" :lower-threshold='100'
@@ -184,6 +190,9 @@
 								{{item.auditStatus==2?'审核拒绝':item.auditStatus==0?'审核中':'审核通过'}}
 								{{item.auditStatus==2?'审核拒绝':item.auditStatus==0?'审核中':'审核通过'}}
 							</view>
 							</view>
 						</view>
 						</view>
+						<view class="record_time reject_reason" v-if="item.auditStatus==2">
+							拒绝原因:{{item.rejectReason}}
+						</view>
 						<view class="record_time">
 						<view class="record_time">
 							{{item.createTime}}
 							{{item.createTime}}
 						</view>
 						</view>
@@ -193,6 +202,12 @@
 					</view>
 					</view>
 				</view>
 				</view>
 			</view>
 			</view>
+			<view class="noMore" v-if="approveList.length>0&&!approveParams.hasMore">
+				到底了
+			</view>
+			<view class="empty empty-1" v-if="!approveList||approveList.length==0">
+				暂无数据
+			</view>
 
 
 		</scroll-view>
 		</scroll-view>
 	</view>
 	</view>
@@ -279,12 +294,15 @@
 
 
 	const approveList = ref([])
 	const approveList = ref([])
 	
 	
+	
 	function scrollRecord(e){
 	function scrollRecord(e){
-		console.log(e.detail.scrollTop,recordScrollTop)
+		// console.log(e.detail.scrollTop,recordScrollTop.value)
+		// oldScroll1 = e.detail.scrollTop
 	}
 	}
 	
 	
 	function scrollApprove(e){
 	function scrollApprove(e){
-		console.log(e.detail.scrollTop,approveScrollTop)
+		// console.log(e.detail.scrollTop,approveScrollTop.value)
+		// oldScroll2 = e.detail.scrollTop
 	}
 	}
 
 
 
 
@@ -303,7 +321,7 @@
 				uni.showToast({
 				uni.showToast({
 					title: '刷新成功',
 					title: '刷新成功',
 					icon: 'none',
 					icon: 'none',
-					duration: 1000
+					duration: 800
 				})
 				})
 			}
 			}
 
 
@@ -347,11 +365,12 @@
 	function nextPageRecord() {
 	function nextPageRecord() {
 		console.log("到底了")
 		console.log("到底了")
 		if (!recordParams.value.hasMore) {
 		if (!recordParams.value.hasMore) {
-			return uni.showToast({
-				title: "没有更多了",
-				icon: "none",
-				duration: 1000
-			})
+			// uni.showToast({
+			// 	title: "没有更多了",
+			// 	icon: "none",
+			// 	duration: 1000
+			// })
+			return 
 		}
 		}
 		recordParams.value.page += 1;
 		recordParams.value.page += 1;
 		fetchRecordList()
 		fetchRecordList()
@@ -361,11 +380,12 @@
 	function nextPageApprove() {
 	function nextPageApprove() {
 		// console.log("到底了")
 		// console.log("到底了")
 		if (!approveParams.value.hasMore) {
 		if (!approveParams.value.hasMore) {
-			return uni.showToast({
-				title: "没有更多了",
-				icon: "none",
-				duration: 1000
-			})
+			// uni.showToast({
+			// 	title: "没有更多了",
+			// 	icon: "none",
+			// 	duration: 1000
+			// })
+			return 
 		}
 		}
 		approveParams.value.page += 1;
 		approveParams.value.page += 1;
 		fetchApproveList()
 		fetchApproveList()
@@ -395,7 +415,10 @@
 			uni.hideLoading()
 			uni.hideLoading()
 			if (recordParams.value.page == 1) {
 			if (recordParams.value.page == 1) {
 				recordList.value = res?.data?.list || [];
 				recordList.value = res?.data?.list || [];
-				recordScrollTop.value = 0
+				recordScrollTop.value = 1
+				setTimeout(()=>{
+					recordScrollTop.value = 0
+				},100)
 			} else {
 			} else {
 				recordList.value = recordList.value.concat(res?.data?.list || []);
 				recordList.value = recordList.value.concat(res?.data?.list || []);
 			}
 			}
@@ -422,7 +445,10 @@
 			uni.hideLoading()
 			uni.hideLoading()
 			if (approveParams.value.page == 1) {
 			if (approveParams.value.page == 1) {
 				approveList.value = res?.data?.list || [];
 				approveList.value = res?.data?.list || [];
-				approveScrollTop.value = 0
+				approveScrollTop.value = 1
+				setTimeout(()=>{
+					approveScrollTop.value = 0
+				},100)
 			} else {
 			} else {
 				approveList.value = approveList.value.concat(res?.data?.list || []);
 				approveList.value = approveList.value.concat(res?.data?.list || []);
 			}
 			}
@@ -526,7 +552,7 @@
 	.asset_container {
 	.asset_container {
 		// padding-top: 92rpx;
 		// padding-top: 92rpx;
 		background-color: #F9F7F0;
 		background-color: #F9F7F0;
-		height: 100%;
+		height: 100vh;
 		display: flex;
 		display: flex;
 		flex-direction: column;
 		flex-direction: column;
 		justify-content: flex-start;
 		justify-content: flex-start;
@@ -559,7 +585,7 @@
 				color: #F8C008;
 				color: #F8C008;
 
 
 				.filter_icon {
 				.filter_icon {
-					// width: 32rpx;
+					width: 32rpx;
 					height: 32rpx;
 					height: 32rpx;
 					margin-right: 8rpx;
 					margin-right: 8rpx;
 				}
 				}
@@ -708,12 +734,13 @@
 		margin-bottom: 16rpx;
 		margin-bottom: 16rpx;
 
 
 		.record_left {
 		.record_left {
+			margin-right: 20rpx;
 
 
 			.record_title {
 			.record_title {
 				display: flex;
 				display: flex;
 				justify-content: flex-start;
 				justify-content: flex-start;
 				align-items: center;
 				align-items: center;
-				margin-bottom: 20rpx;
+				margin-bottom: 10rpx;
 
 
 				.record_name {
 				.record_name {
 					font-size: 28rpx;
 					font-size: 28rpx;
@@ -748,6 +775,12 @@
 			.record_time {
 			.record_time {
 				font-size: 24rpx;
 				font-size: 24rpx;
 				color: #333;
 				color: #333;
+				margin-top: 10rpx;
+			}
+			.reject_reason{
+				font-size: 28rpx;
+				line-height: 34rpx;
+				margin-bottom: 10rpx;
 			}
 			}
 		}
 		}
 
 
@@ -804,4 +837,20 @@
 			}
 			}
 		}
 		}
 	}
 	}
+	.empty{
+		width: 100%;
+		text-align: center;
+		padding: 200rpx 0;
+		color:#dedede;
+		&.empty-1{
+			padding-top: 268rpx;
+		}
+	}
+	.noMore{
+		width: 100%;
+		color:#dedede;
+		text-align: center;
+		line-height: 40rpx;
+		padding-bottom: 20rpx;
+	}
 </style>
 </style>

+ 2 - 2
pages/users/user_asset/stock_in/stock_in.vue

@@ -203,8 +203,8 @@
 					title: "补货申请条件成功,正在审核中"
 					title: "补货申请条件成功,正在审核中"
 				})
 				})
 				setTimeout(() => {
 				setTimeout(() => {
-					// uni.navigateBack()
-					submitting = false;
+					uni.navigateBack()
+					// submitting = false;
 				}, 500)
 				}, 500)
 
 
 			}).catch(() => {
 			}).catch(() => {

+ 0 - 0
pages/users/vault/withdraw.vue


+ 232 - 0
pages/webview/index.vue

@@ -0,0 +1,232 @@
+<template>
+  <view class="webview-wrapper">
+    <!-- 加载状态提示 -->
+    <view class="loading-mask" v-if="isLoading">
+      <uni-loading-icon type="circle" size="24" color="#333"></uni-loading-icon>
+      <text class="loading-txt">加载中...</text>
+    </view>
+
+    <web-view
+      :src="h5Url"
+      id="any-id"
+      @load="onWebViewLoad"
+      @error="onWebViewError"
+      @message="onWebViewMessage"
+    ></web-view>
+  </view>
+</template>
+
+<script setup>
+import { ref, onUnmounted } from "vue";
+import { onLoad } from "@dcloudio/uni-app";
+import { H5_BASE_URL, TOKENNAME, WHITELIST } from "@/config/app";
+import { useAppStore } from "@/stores/app";
+import { toLogin, checkLogin } from "@/libs/login";
+
+const h5Url = ref("");
+const appStore = useAppStore();
+const isLoading = ref(true);
+const errorMsg = ref("");
+
+onUnmounted(() => {
+  isLoading.value = false;
+});
+
+onLoad((query) => {
+  try {
+    const { path = "/", ...otherParams } = query;
+    let normalizedPath = normalizeH5Path(path);
+    const token = appStore.tokenComputed;
+
+    if (!token && !WHITELIST.includes(normalizedPath)) {
+      uni.showToast({
+        title: "登录已失效,请重新登录",
+        icon: "none",
+        duration: 1500,
+      });
+      setTimeout(() => {
+        toLogin();
+      }, 1500);
+      return;
+    }
+
+    if (!normalizedPath) {
+      uni.showToast({
+        title: "页面路径无效,默认跳转首页",
+        icon: "none",
+        duration: 1500,
+      });
+      normalizedPath = "/";
+    }
+
+    // 参数处理
+    const params = {
+      ...parseComplexParams(otherParams),
+      [TOKENNAME]: token,
+    };
+
+    const queryString = buildQueryString(params);
+
+    h5Url.value = `${H5_BASE_URL}/#${normalizedPath}${
+      queryString ? `?${queryString}` : ""
+    }`;
+    console.log("WebView 加载地址:", h5Url.value);
+  } catch (err) {
+    console.error("WebView 初始化失败:", err);
+    uni.showToast({ title: "页面加载异常", icon: "none", duration: 1500 });
+    setTimeout(() => uni.navigateBack(), 1500);
+  }
+});
+
+// 标准化H5路径
+const normalizeH5Path = (path) => {
+  if (typeof path !== "string") {
+    console.warn("H5路径格式错误:非字符串类型");
+    return null;
+  }
+
+  // URL解码
+  let decodedPath;
+  try {
+    decodedPath = decodeURIComponent(path);
+  } catch (err) {
+    console.error("H5路径解码失败(非法编码格式):", err, "原始路径:", path);
+    return null;
+  }
+
+  const purePath = decodedPath.split(/[?#]/)[0];
+
+  const pathReg = /^\/[a-zA-Z0-9\/:\.\-_\u4e00-\u9fa5]*$/;
+  const isValid = pathReg.test(purePath);
+
+  if (!isValid) {
+    console.warn("H5路径格式非法(含不允许字符):", purePath);
+    return null;
+  }
+
+  // 第五步:最终处理(去除末尾多余的/,避免重复路径如/path// → /path)
+  const normalizedPath = purePath.replace(/\/+$/, "") || "/";
+
+  return normalizedPath;
+};
+/**
+ * 解析复杂参数
+ * @param {object} params - 原始参数
+ * @returns {object} 处理后的参数
+ */
+const parseComplexParams = (params) => {
+  const result = {};
+  Object.entries(params).forEach(([key, value]) => {
+    if (value === undefined || value === null) return;
+
+    if (Array.isArray(value)) {
+      value.forEach((item) => {
+        const encodedItem = encodeURIComponent(item);
+        if (result[key]) {
+          result[key] = `${result[key]},${encodedItem}`;
+        } else {
+          result[key] = encodedItem;
+        }
+      });
+    } else if (typeof value === "object") {
+      result[key] = encodeURIComponent(JSON.stringify(value));
+    }
+    // 基础类型直接保留
+    else {
+      result[key] = value;
+    }
+  });
+  return result;
+};
+
+/**
+ * 构建编码后的查询参数串
+ * @param {object} params - 处理后的参数
+ * @returns {string} 编码后的查询串
+ */
+const buildQueryString = (params) => {
+  return Object.entries(params)
+    .filter(
+      ([_, value]) => value !== undefined && value !== null && value !== ""
+    )
+    .map(
+      ([key, value]) =>
+        `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
+    )
+    .join("&");
+};
+
+/**
+ * web-view 加载成功
+ */
+const onWebViewLoad = () => {
+  isLoading.value = false; // 隐藏加载中
+};
+
+/**
+ * web-view 加载失败
+ * @param {object} err - 错误信息
+ */
+const onWebViewError = (err) => {
+  isLoading.value = false;
+  errorMsg.value = `页面加载失败:${err.detail.errMsg}`;
+  uni.showToast({ title: errorMsg.value, icon: "none", duration: 2000 });
+  console.error("WebView 加载错误:", err);
+  setTimeout(() => uni.navigateBack(), 1500);
+};
+
+/**
+ * 接收 H5 发送的消息
+ * @param {object} e - 消息事件
+ */
+const onWebViewMessage = (e) => {
+  const h5Msg = e.detail.data[0]; // H5 发送的消息格式为 { data: [消息体] }
+  console.log("接收 H5 消息:", h5Msg);
+
+  // 示例:H5 触发「返回小程序」
+  if (h5Msg.type === "navigateBack") {
+    uni.navigateBack({ delta: h5Msg.delta || 1 });
+  }
+
+  if (h5Msg.type === "refreshToken") {
+    appStore.refreshToken().then((newToken) => {
+      const webview = uni.createSelectorQuery().select("#any-id");
+      webview
+        .context((res) => {
+          res.context.postMessage({
+            data: { type: "newToken", token: newToken },
+          });
+        })
+        .exec();
+    });
+  }
+};
+</script>
+
+<style scoped>
+.webview-wrapper {
+  width: 100vw;
+  height: 100vh;
+  position: relative;
+}
+
+.loading-mask {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(255, 255, 255, 0.8);
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  z-index: 999;
+}
+
+.loading-txt {
+  margin-top: 16rpx;
+  font-size: 28rpx;
+  color: #666;
+}
+</style>