2
0

11 Commits 8eeb85e912 ... 0896d33789

Autor SHA1 Mensagem Data
  jun 0896d33789 修改订单列表 2 semanas atrás
  jun cd856ed560 Merge branch 'qxy' into jun 2 semanas atrás
  jun 27a9406769 修改订单列表 2 semanas atrás
  钱新宇 5c0e3b7589 feat:首页更新 2 semanas atrás
  钱新宇 ebbb178757 feat:首页更新 2 semanas atrás
  钱新宇 506c7db0c1 Merge branch 'test' into branch_qxy_dev 2 semanas atrás
  钱新宇 a89cecf115 feat:首页更新 2 semanas atrás
  钱新宇 6301f6e02b Merge branch 'liuxiangxin' into branch_qxy_dev 2 semanas atrás
  钱新宇 be842a878c 合并分支 1 mês atrás
  liuxiangxin 027cb120af 【Add】小程序积分详情 2 meses atrás
  钱新宇 424a657a6a h5构建 1 mês atrás

+ 151 - 0
components/Banner/index.vue

@@ -0,0 +1,151 @@
+<template>
+  <ComponentsHeader v-bind="$props" />
+
+  <view class="banner" :style="{ padding: `0 ${gap}px` }">
+    <!-- 单图模式 -->
+    <view v-if="mode === 'single'" class="single-image">
+      <image :src="images[0]?.image || `http://iph.href.lu/400x200?text=1`" :style="{ borderRadius: `${radius}px` }" mode="aspectFill" @click="_handleClick(images[0].urlMap?.internal_url)" />
+    </view>
+
+    <!-- 轮播图模式 -->
+    <swiper
+      v-else-if="mode === 'swiper' || mode === 'swiper-no-dots'"
+      :autoplay="true"
+      :interval="swiperDuration"
+      :circular="true"
+      :indicator-dots="mode === 'swiper'"
+      class="swiper"
+      :style="{ borderRadius: `${radius}px` }"
+    >
+      <swiper-item v-for="(item, index) in images" :key="index">
+        <image @click="_handleClick(item.urlMap?.internal_url)" :src="item.image || `http://iph.href.lu/400x200?text=${index}`" :style="{ borderRadius: `${radius}px` }" mode="aspectFill" />
+      </swiper-item>
+    </swiper>
+
+    <!-- 网格模式 -->
+    <view v-else-if="mode === 'grid'" class="grid-container" :style="{ borderRadius: `${radius}px` }">
+      <view v-for="(item, index) in images.slice(0, 4)" :key="index" class="grid-item">
+        <image @click="_handleClick(item.urlMap?.internal_url)" :src="item.image || `http://iph.href.lu/400x200?text=${index}`" mode="widthFix" :style="{ borderRadius: `${radius}px` }" />
+      </view>
+    </view>
+
+    <!-- 双图模式 -->
+    <view v-else-if="mode === 'double'" class="double-container" :style="{ borderRadius: `${radius}px` }">
+      <view v-for="(item, index) in images.slice(0, 2)" :key="index" class="double-item">
+        <image @click="_handleClick(item.urlMap?.internal_url)" :src="item.image || `http://iph.href.lu/400x200?text=${index}`" :style="{ borderRadius: `${radius}px` }" mode="aspectFill" />
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import ComponentsHeader from '../ComponentsHeader';
+defineProps({
+  images: {
+    type: Array,
+    default: () => [],
+  },
+  mode: {
+    type: String,
+    default: 'single',
+    validator: (value) => ['single', 'swiper', 'swiper-no-dots', 'grid', 'double'].includes(value),
+  },
+  radius: {
+    type: Number,
+    default: 0,
+  },
+  swiperDuration: {
+    type: Number,
+    default: 3000,
+  },
+  gap: {
+    type: Number,
+    default: 0,
+  },
+  title: {
+    type: String,
+    default: '',
+  },
+  showTitle: {
+    type: Boolean,
+    default: false,
+  },
+});
+
+const _handleClick = (url) => {
+  if (url) {
+    uni.navigateTo({
+      url,
+      fail: (err) => {
+        uni.switchTab({
+          url,
+        });
+      },
+    });
+  }
+};
+</script>
+
+<style lang="less" scoped>
+.navigator {
+  width: 100%;
+  height: 100%;
+}
+.banner {
+  width: 100%;
+  overflow: hidden;
+  box-sizing: border-box;
+
+  .single-image {
+    width: 100%;
+    height: 150px;
+    overflow: hidden;
+
+    image {
+      width: 100%;
+      height: 100%;
+    }
+  }
+
+  .swiper {
+    width: 100%;
+    height: 150px;
+
+    image {
+      width: 100%;
+      height: 100%;
+    }
+  }
+
+  .grid-container {
+    display: grid;
+    grid-template-rows: repeat(2, 1fr);
+    grid-template-columns: repeat(2, 1fr);
+    gap: 4px;
+    width: 100%;
+
+    .grid-item {
+      image {
+        width: 100%;
+        height: 100%;
+      }
+    }
+  }
+
+  .double-container {
+    display: flex;
+    gap: 4px;
+    width: 100%;
+
+    .double-item {
+      flex: 1;
+      height: 150px;
+
+      image {
+        width: 100%;
+        height: 100%;
+      }
+    }
+  }
+}
+</style>

+ 38 - 0
components/ComponentsHeader/index.vue

@@ -0,0 +1,38 @@
+<template>
+  <view class="header" v-if="showTitle">
+    <view class="line" />
+    {{ title }}
+  </view>
+</template>
+
+<script setup>
+import { defineProps, onMounted } from 'vue';
+
+const props = defineProps({
+  title: {
+    type: String,
+    default: '',
+  },
+  showTitle: {
+    type: Boolean,
+    default: true,
+  },
+});
+</script>
+
+<style scoped lang="less">
+.header {
+  padding: 24rpx 0;
+  color: #333;
+  font-size: 16px;
+  display: flex;
+  align-items: center;
+  font-weight: bold;
+  .line {
+    width: 4px;
+    height: 20px;
+    background: linear-gradient(to bottom, #f89c33, #f86834);
+    margin-right: 16rpx;
+  }
+}
+</style>

+ 141 - 0
components/IconList/index.vue

@@ -0,0 +1,141 @@
+<template>
+  <view class="icon-list" :class="mode" :style="{ '--columns': getColumnCount() }">
+    <view v-for="(item, index) in displayIcons" :key="index" class="icon-item" @click="_handleClick(item.urlMap?.internal_url)">
+      <view class="icon-wrapper">
+        <image :src="item.image || `http://iph.href.lu/48x48?text=${index}`" :style="{ borderRadius: `${radius}px` }" mode="aspectFill" />
+      </view>
+      <view class="icon-text">{{ item.text }}</view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { computed } from 'vue';
+
+const props = defineProps({
+  icons: {
+    type: Array,
+    default: () => [1, 2, 3, 4],
+  },
+  mode: {
+    type: String,
+    default: 'row4',
+    validator: (value) => ['row4', 'row8', 'row5', 'row10'].includes(value),
+  },
+  radius: {
+    type: Number,
+    default: 0,
+  },
+});
+
+const getColumnCount = () => {
+  switch (props.mode) {
+    case 'row4':
+    case 'row8':
+      return 4;
+    case 'row5':
+    case 'row10':
+      return 5;
+    default:
+      return 4;
+  }
+};
+
+const getMaxItems = () => {
+  switch (props.mode) {
+    case 'row4':
+      return 4;
+    case 'row8':
+      return 8;
+    case 'row5':
+      return 5;
+    case 'row10':
+      return 10;
+    default:
+      return 4;
+  }
+};
+
+const _handleClick = (url) => {
+  if (url) {
+    uni.navigateTo({
+      url,
+      fail: (err) => {
+        uni.switchTab({
+          url,
+        });
+      },
+    });
+  }
+};
+
+const displayIcons = computed(() => {
+  return props.icons.slice(0, getMaxItems());
+});
+</script>
+
+<style lang="less" scoped>
+.navigator {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+}
+.icon-list {
+  display: grid;
+  grid-template-columns: repeat(var(--columns), 1fr);
+  gap: 16rpx;
+  width: 100%;
+  padding: 16px;
+  box-sizing: border-box;
+  background-color: #fff;
+  border-radius: 8px;
+
+  .icon-item {
+    display: flex;
+    flex-direction: column;
+    gap: 4px;
+    align-items: center;
+
+    .icon-wrapper {
+      width: 44px;
+      height: 44px;
+      overflow: hidden;
+
+      image {
+        width: 100%;
+        height: 100%;
+        object-fit: cover;
+      }
+    }
+
+    .icon-text {
+      width: 100%;
+      overflow: hidden;
+      color: #333;
+      font-size: 12px;
+      white-space: nowrap;
+      text-align: center;
+      text-overflow: ellipsis;
+    }
+  }
+}
+
+.row4 {
+  grid-template-rows: 1fr;
+}
+
+.row8 {
+  grid-template-rows: repeat(2, 1fr);
+}
+
+.row5 {
+  grid-template-rows: 1fr;
+}
+
+.row10 {
+  grid-template-rows: repeat(2, 1fr);
+}
+</style>

+ 157 - 0
components/Notice/index.vue

@@ -0,0 +1,157 @@
+<template>
+  <view class="notice-container" :style="{ padding: `0 ${gap}px` }">
+    <view class="notice-wrapper">
+      <view class="notice-icon">公告</view>
+      <view class="notice-content">
+        <swiper class="notice-swiper" vertical :circular="true" :autoplay="true" :interval="swiper * 1000" :duration="500" :display-multiple-items="1" @change="handleChange">
+          <swiper-item v-for="(notice, index) in noticeList" :key="index" @click="handleNoticeClick(notice)">
+            <view class="notice-item">{{ notice.text }}</view>
+          </swiper-item>
+        </swiper>
+        <view class="notice-more">更多 ></view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
+
+// 定义props
+const props = defineProps({
+  noticeList: {
+    type: Array,
+    default: () => [],
+    validator: (value) => {
+      return value.every((item) => typeof item.text === 'string' && typeof item.url === 'string');
+    },
+  },
+  gap: {
+    type: Number,
+    default: 0,
+  },
+  swiper: {
+    type: Number,
+    default: 3,
+  },
+});
+
+// 响应式状态
+const currentIndex = ref(0);
+let timer = null;
+
+// 计算循环列表
+const displayList = computed(() => {
+  return [props.noticeList[props.noticeList.length - 1], ...props.noticeList, props.noticeList[0]];
+});
+
+// 处理点击事件
+const handleNoticeClick = (notice) => {
+  if (notice.url) {
+    // window.location.href = notice.url;
+    uni.navigateTo({
+      url: notice.url,
+    });
+  }
+};
+
+// 启动轮播
+const startSwiper = () => {
+  if (props.noticeList.length <= 1) return;
+
+  // 设置初始位置
+  currentIndex.value = 1;
+
+  timer = setInterval(() => {
+    const nextIndex = currentIndex.value + 1;
+    if (nextIndex >= displayList.value.length - 1) {
+      currentIndex.value = nextIndex;
+      // 当到达最后一个元素时,等待过渡动画完成后重置到第一个元素
+      setTimeout(() => {
+        currentIndex.value = 1;
+      }, 500);
+    } else {
+      currentIndex.value = nextIndex;
+    }
+  }, props.swiper * 1000);
+};
+
+// 监听列表变化
+watch(
+  () => props.noticeList.length,
+  () => {
+    if (timer) {
+      clearInterval(timer);
+    }
+    startSwiper();
+  }
+);
+
+// 组件挂载时启动轮播
+onMounted(() => {
+  startSwiper();
+});
+
+// 组件卸载时清理定时器
+onUnmounted(() => {
+  if (timer) {
+    clearInterval(timer);
+  }
+});
+</script>
+
+<style lang="less" scoped>
+.notice-container {
+  margin: 4px 0;
+  position: relative;
+  .notice-wrapper {
+    display: flex;
+    align-items: center;
+    height: 40px;
+    background: #fff;
+    border-radius: 130rpx 130rpx 130rpx 130rpx;
+  }
+
+  .notice-icon {
+    width: 68rpx;
+    height: 32rpx;
+    color: #f89c33;
+    font-size: 14px;
+    border: 1px solid #f89c33;
+    border-radius: 8rpx;
+    text-align: center;
+    line-height: 32rpx;
+    margin: 0 10px;
+  }
+
+  .notice-content {
+    flex: 1;
+    height: 40px;
+    overflow: hidden;
+  }
+
+  .notice-slider {
+    height: 100%;
+  }
+
+  .notice-item {
+    height: 40px;
+    line-height: 40px;
+    color: #333;
+    font-size: 14px;
+    cursor: pointer;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    width: 80%;
+  }
+  .notice-more {
+    color: #999;
+    position: absolute;
+    right: 25px;
+    top: 50%;
+    transform: translateY(-50%);
+    font-size: 12px;
+  }
+}
+</style>

+ 7 - 1
manifest.json

@@ -78,5 +78,11 @@
     "uniStatistics" : {
         "enable" : false
     },
-    "vueVersion" : "3"
+    "vueVersion" : "3",
+    "h5" : {
+        "router" : {
+            "mode" : "history",
+            "base" : "/saas/web/"
+        }
+    }
 }

+ 14 - 2
pages.json

@@ -1,6 +1,5 @@
 {
   "pages": [
-    //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
     {
       "path": "pages/index/index",
       "style": {
@@ -8,6 +7,19 @@
         "enablePullDownRefresh": true
       }
     },
+    {
+      "path": "pages/product/list",
+      "style": {
+        "navigationBarTitleText": "产品列表",
+        "enablePullDownRefresh": true
+      }
+    },
+    {
+      "path": "pages/wait/index",
+      "style": {
+        "navigationBarTitleText": "活动页面"
+      }
+    },
     {
       "path": "pages/car/index",
       "style": {
@@ -108,7 +120,7 @@
         "navigationBarTitleText": "兑换记录"
       }
     },
-	{
+    {
       "path": "pages/score/orders_detail",
       "style": {
         "navigationBarTitleText": "兑换详情"

+ 46 - 47
pages/car/order.vue

@@ -86,7 +86,7 @@
         合计:
         <text class="price_total">¥{{ priceTotal }}</text>
       </view>
-      <button class="to_order" @click="createOrder()" data-eventsync="true">{{is_pay?'立即支付':'立即预约'}}</button>
+      <button class="to_order" @click="createOrder()" data-eventsync="true">{{ is_pay ? '立即支付' : '立即预约' }}</button>
     </view>
     <uni-popup ref="popup" type="bottom" class="popup" background-color="#FFFFFF" @touchmove.stop.prevent="() => {}">
       <view class="coupon_list">
@@ -171,14 +171,14 @@ export default {
       promoRebateList: [],
       // 请求参数
       requestParam: {
-        cart_ids: "",
+        cart_ids: '',
       },
       // 总价
-      priceTotal: "0.00",
-      discount: "0.00",
-      reduction: "0.00",
+      priceTotal: '0.00',
+      discount: '0.00',
+      reduction: '0.00',
       // 优惠券使用
-      couponUsed: "去使用 >",
+      couponUsed: '去使用 >',
       // 扣减金额
       rebatePrice: 0.0,
       // 已经选择的优惠券ID
@@ -188,12 +188,12 @@ export default {
       // 已选地址
       checkedAddr: {
         id: 0,
-        contact_name: "",
-        contact_phone: "",
-        contact_province: "",
-        contact_city: "",
-        contact_area: "",
-        contact_addr: "",
+        contact_name: '',
+        contact_phone: '',
+        contact_province: '',
+        contact_city: '',
+        contact_area: '',
+        contact_addr: '',
         is_default: 0,
       },
       is_pay: 0,
@@ -204,15 +204,15 @@ export default {
     this.requestParam.cart_ids = param.cart_ids;
     var that = this;
     // 监听地址变动
-    uni.$on("addr_list_change", function (data) {
+    uni.$on('addr_list_change', function (data) {
       // 地址列表
       that.addrList = data.list;
     });
   },
   onShow() {
     // 结果
-    this.$http.request("api/shop_cart/check_list", this.requestParam).then((re) => {
-      if (re.code == "success") {
+    this.$http.request('api/shop_cart/check_list', this.requestParam).then((re) => {
+      if (re.code == 'success') {
         // 赋值
         this.cartList = re.data;
         this.cartListByGroup = this.formatGroupedData(re.data);
@@ -220,8 +220,8 @@ export default {
         this.discount = re.discount;
         this.reduction = re.reduction;
         // 结果
-        this.$http.request("api/custom_coupon/get_checked", this.requestParam).then((re) => {
-          if (re.code == "success") {
+        this.$http.request('api/custom_coupon/get_checked', this.requestParam).then((re) => {
+          if (re.code == 'success') {
             // 赋值
             this.couponList = re.data;
             // 推荐使用的优惠券
@@ -327,7 +327,7 @@ export default {
     // 地址弹出层
     showAddrPopup() {
       // 显示下单弹出层
-      this.$refs.addrPopup.open("bottom");
+      this.$refs.addrPopup.open('bottom');
     },
     // 价格计算
     priceHandler() {
@@ -339,10 +339,10 @@ export default {
       for (let index in this.cartList) {
         priceTotal = this.$decimal.add(priceTotal, this.$decimal.mul(this.cartList[index].price, this.cartList[index].buy_num));
         if (this.cartList[index].is_pay == 0) {
-          reservation_status    = true;
+          reservation_status = true;
         }
         if (this.cartList[index].is_pay == 1) {
-          pay_status            = true;
+          pay_status = true;
         }
       }
       // 扣减数据
@@ -351,12 +351,12 @@ export default {
       priceTotal = this.$decimal.sub(priceTotal, this.discount);
       // 小数点保留
       this.priceTotal = priceTotal.toFixed(2);
-      if (pay_status && reservation_status){
-        this.is_pay     = 2;
-      }else if(pay_status){
-        this.is_pay     = 1;
-      }else if(reservation_status){
-        this.is_pay     = 0;
+      if (pay_status && reservation_status) {
+        this.is_pay = 2;
+      } else if (pay_status) {
+        this.is_pay = 1;
+      } else if (reservation_status) {
+        this.is_pay = 0;
       }
     },
     // 创建订单
@@ -380,23 +380,23 @@ export default {
       }
       if (productList.length <= 0) {
         uni.showToast({
-          title: "未选择可购买的产品",
-          icon: "none",
+          title: '未选择可购买的产品',
+          icon: 'none',
         });
         return;
       }
       // 地址未填
       if (!this.checkedAddr.id) {
         uni.showToast({
-          title: "请选择收货地址",
-          icon: "none",
+          title: '请选择收货地址',
+          icon: 'none',
         });
         return;
       }
       if (this.is_pay == 2) {
         uni.showToast({
-          title: "混合产品,无法下单",
-          icon: "none",
+          title: '混合产品,无法下单',
+          icon: 'none',
         });
         return;
       }
@@ -422,7 +422,7 @@ export default {
       // 请求接口
       this.$http
         .request(
-          "api/orders/create",
+          'api/orders/create',
           {
             product_list: productList,
             custom_coupon_id: this.customCoupon,
@@ -430,18 +430,18 @@ export default {
             addr_id: this.checkedAddr.id,
             is_pay: this.is_pay,
           },
-          "post"
+          'post'
         )
         .then((re) => {
           // 判断结果
-          if (re.code == "success") {
-            if (this.is_pay){
+          if (re.code == 'success') {
+            if (this.is_pay) {
               // 跳转到支付确认页面
               let orderInfo = re.data;
               orderInfo = JSON.stringify(orderInfo);
               let params = encodeURIComponent(orderInfo);
               uni.navigateTo({ url: `/pages/orders/confirm?params=${params}` });
-            }else {
+            } else {
               // 跳转到报单完成页面
               uni.navigateTo({
                 url: `/pages/orders/completion?params=${encodedArray}`,
@@ -450,10 +450,9 @@ export default {
             return;
           } else {
             uni.showModal({
-            title: re.msg,
-            showCancel: false,
-			  });
-            
+              title: re.msg,
+              showCancel: false,
+            });
           }
         });
     },
@@ -471,7 +470,7 @@ export default {
         if (index != i) this.couponList[i].checked = 0;
       }
       // 如果未选中,提示可用
-      if (!this.couponList[index].checked) this.couponUsed = "去使用 >";
+      if (!this.couponList[index].checked) this.couponUsed = '去使用 >';
       // 已经选择的优惠券ID
       this.customCoupon = this.couponList[index].checked ? this.couponList[index].id : 0;
       // 计算扣减
@@ -522,7 +521,7 @@ export default {
             // 计算扣减数据
             rebatePrice = this.$decimal.mul(this.couponList[i].rebate, 1);
             // 替换文字
-            this.couponUsed = "¥-" + rebatePrice.toFixed(2);
+            this.couponUsed = '¥-' + rebatePrice.toFixed(2);
           }
           // 折扣
           if (this.couponList[i].rebate_type == 2) {
@@ -531,12 +530,12 @@ export default {
             // -0.1 表示折扣
             rebatePrice = this.$decimal.sub(totalPrice, rebatePrice.mul(0.1));
             // 替换文字
-            this.couponUsed = "¥-" + rebatePrice.toFixed(2);
+            this.couponUsed = '¥-' + rebatePrice.toFixed(2);
           }
           //  赠品
           if (this.couponList[i].rebate_type == 3) {
             // 替换文字
-            this.couponUsed = "送" + (this.couponList[i].rebate_scope.length ? this.couponList[i].rebate_scope[0].product_name : "");
+            this.couponUsed = '送' + (this.couponList[i].rebate_scope.length ? this.couponList[i].rebate_scope[0].product_name : '');
           }
           // 小数点保留
           this.rebatePrice = rebatePrice.toFixed(2);
@@ -550,9 +549,9 @@ export default {
     },
     getAddrList() {
       // 判断数据
-      this.$http.request("api/custom_addr/get_list").then((callback) => {
+      this.$http.request('api/custom_addr/get_list').then((callback) => {
         // 获取成功
-        if (callback.code == "success") {
+        if (callback.code == 'success') {
           this.addrList = callback.data;
           // 如果有的话
           if (this.addrList.length) {

+ 188 - 83
pages/index/index.vue

@@ -1,35 +1,61 @@
 <template>
   <view>
+    <view class="page-title" />
     <!-- 轮播图 -->
+
     <view class="banner_box">
       <view class="banner_list" v-if="bannerList.length">
         <swiper class="banner_swiper" :autoplay="true">
-          <swiper-item v-for="(item, index) in bannerList" :key="index">
+          <swiper-item v-for="(item, index) in bannerList" :key="index" style="border-radius: 8px">
             <image :src="item.thumb" class="image" @click="navLottery(item.link_url)"></image>
           </swiper-item>
         </swiper>
       </view>
     </view>
+    <view class="icon-list">
+      <icon-list mode="row8" :icons="icons" :gap="0" />
+    </view>
+    <view class="notice-list">
+      <notice-list :noticeList="[{ text: '开邻智数新版本发布啦~' }, { text: '更多新功能敬请期待~' }]" gap="18" />
+    </view>
+    <view class="header-title">
+      <components-header title="专区导航" />
+    </view>
+    <view class="banner-list">
+      <banner-list :images="banners" mode="grid" :gap="16" />
+    </view>
+    <view class="header-title">
+      <components-header title="推荐商品" />
+    </view>
     <view class="product_box">
       <view class="to_bottom" v-if="!productList.length"> -----还没有产品啦-----</view>
       <!-- 产品列表 -->
       <view class="product_list">
         <!-- Vue3 项目部分小程序端事件延迟或调用失败 在执行事件的元素上添加 data-eventsync="true" 属性以解决此问题 -->
         <view @click="toDetail(item)" data-eventsync="true" class="product_item" v-for="(item, index) in productList" :key="index">
-          <image class="product_image" :src="item.thumb" mode=""></image>
-          <view class="product_name">
-            <text v-if="item.promo_title" class="regiment_title">{{ item.promo_title }}</text>
-            <text v-if="item.regiment_title" class="regiment_title">{{ item.regiment_title }}</text>
-            <text>{{ item.name }}</text></view
-          >
-          <view class="product_spec"
-            ><text>{{ item.spec }}</text></view
-          >
-          <view class="stock_price">
-            <view class="product_price" v-if="isShowPrice">
-              <text>¥{{ item.price }} </text>
+          <view class="product_item_content">
+            <view class="product_image_content">
+              <image class="product_image" :src="item.thumb" mode=""></image>
             </view>
-            <view class="product_stock">剩{{ item.stock }}个</view>
+            <view>
+              <view class="product_name">
+                <text v-if="item.promo_title" class="regiment_title">{{ item.promo_title }}</text>
+                <text v-if="item.regiment_title" class="regiment_title">{{ item.regiment_title }}</text>
+                <text>{{ item.name }}</text></view
+              >
+              <view class="product_spec"
+                ><text>{{ item.spec }}</text></view
+              ></view
+            >
+          </view>
+          <view class="product_item_bottom">
+            <view class="stock_price">
+              <view class="product_price" v-if="isShowPrice">
+                <text>¥{{ item.price }} </text>
+              </view>
+              <view class="product_stock">剩{{ item.stock }}个</view>
+            </view>
+            <view class="stock_button">立即抢购</view>
           </view>
         </view>
       </view>
@@ -47,7 +73,7 @@
     </view>
     <view class="to_bottom" v-if="isLast" style="display: flex; justify-content: center">
       -----
-      <view :style="!productList.length && toSelectedCity ? 'font-weight:bold;font-size:36rpx' : ''">{{ !productList.length && toSelectedCity ? "请点击左上角选择你的城市" : "到底啦" }}</view> -----
+      <view :style="!productList.length && toSelectedCity ? 'font-weight:bold;font-size:36rpx' : ''">{{ !productList.length && toSelectedCity ? '请点击左上角选择你的城市' : '到底啦' }}</view> -----
     </view>
     <uni-popup ref="addFollow" type="center" class="center_popup">
       <FollowPopup :closePopup="closePopup" />
@@ -56,9 +82,29 @@
 </template>
 
 <script>
-import FollowPopup from "@/components/FollowPopup/FollowPopup.vue";
+import FollowPopup from '@/components/FollowPopup/FollowPopup.vue';
+import IconList from '@/components/IconList';
+import NoticeList from '@/components/Notice';
+import BannerList from '@/components/Banner';
+import ComponentsHeader from '@/components/ComponentsHeader';
+const Icons = [
+  { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d3fed51fa2.ng', text: '全品', urlMap: { internal_url: '/pages/product/list' } },
+  { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d3ffdea775.ng', text: '医保价', urlMap: { internal_url: '/pages/wait/index?id=1&name=医保价' } },
+  { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d400fd5932.ng', text: '行业资讯', urlMap: { internal_url: '/pages/wait/index?id=2&name=行业资讯' } },
+  { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d401d6a885.ng', text: '直播', urlMap: { internal_url: '/pages/wait/index?id=3&name=直播' } },
+  { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d402ddaeb6.ng', text: '促销活动', urlMap: { internal_url: '/pages/wait/index?id=4&name=促销活动' } },
+  { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d404366cf8.ng', text: '拼团包邮', urlMap: { internal_url: '/pages/wait/index?id=5&name=拼团包邮' } },
+  { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d404c65d9f.ng', text: '积分商城', urlMap: { internal_url: '/pages/score/index' } },
+  { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d40561a23b.ng', text: '领卷中心', urlMap: { internal_url: '/pages/coupon/index' } },
+];
+const Banners = [
+  { image: 'https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/index/active.png', text: '区域活动', urlMap: { internal_url: '/pages/wait/index?id=8&name=区域活动' } },
+  { image: 'https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/index/b2b.png', text: 'B2B专供', urlMap: { internal_url: '/pages/wait/index?id=9&name=B2B专供' } },
+  { image: 'https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/index/exp.png', text: '近效期', urlMap: { internal_url: '/pages/wait/index?id=10&name=近效期' } },
+  { image: 'https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/index/heath.png', text: '大健康', urlMap: { internal_url: '/pages/wait/index?id=11&name=大健康' } },
+];
 export default {
-  components: { FollowPopup },
+  components: { FollowPopup, IconList, NoticeList, BannerList, ComponentsHeader },
   data() {
     return {
       // 轮播图
@@ -67,7 +113,7 @@ export default {
       productList: [],
       // 请求参数
       requestParam: {
-        name: "",
+        name: '',
         page: 1,
       },
       // 是否最后一页
@@ -77,11 +123,13 @@ export default {
       // 是否显示价格
       isShowPrice: false,
       // 城市名称
-      cityName: "选城市",
+      cityName: '选城市',
       // 选择城市
       toSelectedCity: false,
       // 是否是管理员
       isManager: false,
+      icons: Icons,
+      banners: Banners,
     };
   },
   onLoad() {
@@ -89,7 +137,7 @@ export default {
     //分享按钮
     uni.showShareMenu({
       withShareTicket: true,
-      menus: ["shareAppMessage", "shareTimeline"],
+      menus: ['shareAppMessage', 'shareTimeline'],
     });
     // #endif
   },
@@ -98,13 +146,13 @@ export default {
     let shareList = getApp().globalData.shareList;
     // 获取分享信息
     let shareObj = {
-      title: "999智控终端平台\n药优惠 得积分 兑豪礼",
-      path: "/pages/index/index",
-      imageUrl: "",
+      title: '999智控终端平台\n药优惠 得积分 兑豪礼',
+      path: '/pages/index/index',
+      imageUrl: '',
     };
     // 循环列表
     for (let i in shareList) {
-      if (shareList[i].pages == "pages/index/index") {
+      if (shareList[i].pages == 'pages/index/index') {
         shareObj.path = shareList[i].path ? shareList[i].path : shareObj.path;
         shareObj.title = shareList[i].title ? `999智控终端平台\n${shareList[i].title}` : shareObj.title;
         shareObj.imageUrl = shareList[i].image_url ? shareList[i].image_url : shareObj.imageUrl;
@@ -119,7 +167,7 @@ export default {
     // 城市名
     this.cityName = this.$checkAccess.getCity();
     // 选城市
-    (this.cityName = this.cityName ? this.cityName : "选城市"),
+    (this.cityName = this.cityName ? this.cityName : '选城市'),
       // 登录并且未选择城市,才可以选择城市
       (this.toSelectedCity = !this.$checkAccess.getCity() ? true : false);
     // 数据
@@ -127,12 +175,12 @@ export default {
     //未选城市先弹窗提醒选择城市
     if (!this.$checkAccess.getCity() && this.$checkAccess.checkLogin()) {
       uni.showModal({
-        title: "",
-        content: "请先选择城市",
+        title: '',
+        content: '请先选择城市',
         success: (res) => {
           if (res.confirm) {
             uni.navigateTo({
-              url: "/pages/user/info",
+              url: '/pages/user/info',
             });
           }
         },
@@ -142,28 +190,28 @@ export default {
     //如果已选城市且没有添加客服每天弹窗一次
     if (this.$checkAccess.getCity() && this.$checkAccess.getFollowQrcode()) {
       // 获取弹出时间
-      let followPopupTime = uni.getStorageSync("followPopupTime");
+      let followPopupTime = uni.getStorageSync('followPopupTime');
       // 现在的时候
       let nowTime = new Date().getTime();
       // 时间戳
       followPopupTime = followPopupTime ? followPopupTime : 0;
       // 弹出结果
       if (followPopupTime <= 0 || followPopupTime - nowTime > 86400000) {
-        this.$refs.addFollow.open("center");
-        uni.setStorageSync("followPopupTime", nowTime);
+        this.$refs.addFollow.open('center');
+        uni.setStorageSync('followPopupTime', nowTime);
       }
     }
     this.isManager = this.$checkAccess.isManager();
     // 没有数据的话,或者请求中,不允许刷新
     if (this.isReqing) return;
     // 获取列表
-    this.$http.request("/api/banner/get_list").then((re) => {
-      if (re.code === "success") {
+    this.$http.request('/api/banner/get_list').then((re) => {
+      if (re.code === 'success') {
         this.bannerList = re.data;
       }
     });
     // 请求参数
-    this.requestParam.name = "";
+    this.requestParam.name = '';
     // 请求参数
     this.requestParam.page = 1;
     // 是否是最后一页
@@ -171,17 +219,17 @@ export default {
     // 设置请求中
     this.isReqing = true;
     // 请求
-    this.$http.request("api/product/get_list", this.requestParam).then((re) => {
+    this.$http.request('api/product/get_list', this.requestParam).then((re) => {
       // 设置非请求中
       this.isReqing = false;
       // 成功结果
-      if (re.code == "success") {
-		// 如果是最后一页
+      if (re.code == 'success') {
+        // 如果是最后一页
         if (re.data.last_page <= this.requestParam.page) this.isLast = true;
-		// 赋值
+        // 赋值
         this.productList = re.data.data;
-		// 获取下一页
-		this.getMore(re);
+        // 获取下一页
+        this.getMore(re);
       }
     });
   },
@@ -195,17 +243,17 @@ export default {
     // 设置请求中
     this.isReqing = true;
     // 请求列表
-    this.$http.request("api/product/get_list", this.requestParam).then((re) => {
+    this.$http.request('api/product/get_list', this.requestParam).then((re) => {
       // 设置非请求中
       this.isReqing = false;
       // 成功结果
-      if (re.code == "success") {
-		// 如果是最后一页
+      if (re.code == 'success') {
+        // 如果是最后一页
         if (re.data.last_page <= this.requestParam.page) this.isLast = true;
-		// 赋值
+        // 赋值
         this.productList = re.data.data;
-		// 获取下一页
-		this.getMore(re);
+        // 获取下一页
+        this.getMore(re);
       }
     });
     uni.stopPullDownRefresh();
@@ -222,11 +270,11 @@ export default {
     // 设置请求中
     this.isReqing = true;
     // 请求列表
-    this.$http.request("api/product/get_list", this.requestParam).then((re) => {
+    this.$http.request('api/product/get_list', this.requestParam).then((re) => {
       // 设置非请求中
       this.isReqing = false;
       // 成功结果
-      if (re.code == "success") {
+      if (re.code == 'success') {
         // 最后一页
         if (re.data.last_page <= this.requestParam.page) this.isLast = true;
         // 追加数据
@@ -235,28 +283,28 @@ export default {
     });
   },
   methods: {
-	// 请求加载下一页
-	getMore(callback){
-		// 首页不足10个,并且下一页存在大于当前页
-		if( this.productList.length < 10 && callback.data.last_page > this.requestParam.page ){
-			// 最后一页不再请求
-			if (this.isLast) return;
-			// 增加一页
-			this.requestParam.page = this.requestParam.page + 1;
-			// 请求列表
-			this.$http.request("api/product/get_list", this.requestParam).then((re) => {
-			  // 成功结果
-			  if (re.code == "success") {
-			    // 最后一页
-			    if (re.data.last_page <= this.requestParam.page) this.isLast = true;
-			    // 追加数据
-			    this.productList.push(...re.data.data);
-				// 获取下一页
-				this.getMore(re);
-			  }
-			});
-		}
-	},
+    // 请求加载下一页
+    getMore(callback) {
+      // 首页不足10个,并且下一页存在大于当前页
+      if (this.productList.length < 10 && callback.data.last_page > this.requestParam.page) {
+        // 最后一页不再请求
+        if (this.isLast) return;
+        // 增加一页
+        this.requestParam.page = this.requestParam.page + 1;
+        // 请求列表
+        this.$http.request('api/product/get_list', this.requestParam).then((re) => {
+          // 成功结果
+          if (re.code == 'success') {
+            // 最后一页
+            if (re.data.last_page <= this.requestParam.page) this.isLast = true;
+            // 追加数据
+            this.productList.push(...re.data.data);
+            // 获取下一页
+            this.getMore(re);
+          }
+        });
+      }
+    },
     searchChange(e) {
       // 如果没有搜索词
       if (!this.requestParam.name) {
@@ -273,11 +321,11 @@ export default {
       // 设置请求中
       this.isReqing = true;
       // 请求列表
-      this.$http.request("api/product/get_list", this.requestParam).then((re) => {
+      this.$http.request('api/product/get_list', this.requestParam).then((re) => {
         // 设置非请求中
         this.isReqing = false;
         // 成功结果
-        if (re.code == "success") {
+        if (re.code == 'success') {
           this.productList = re.data.data;
           if (re.data.data.length && re.data.last_page >= this.requestParam.page) this.isLast = true;
         }
@@ -285,14 +333,14 @@ export default {
     },
     toDetail(item) {
       uni.navigateTo({
-        url: "/pages/product/index?product_id=" + item.id,
+        url: '/pages/product/index?product_id=' + item.id,
       });
     },
     navLottery(url) {
       // 没有路径,不跳转
       if (!url) return;
       // 判断是不是小程序链接
-      if (url.includes("http")) {
+      if (url.includes('http')) {
         // 转码
         let link_url = encodeURIComponent(url);
         // 跳转到webview
@@ -310,7 +358,7 @@ export default {
       this.$refs.addFollow.close();
       //存key以及时间
       uni.setStorage({
-        key: "followPopupTime",
+        key: 'followPopupTime',
         data: new Date().getTime(),
       });
     },
@@ -319,6 +367,16 @@ export default {
 </script>
 
 <style lang="less">
+.page-title {
+  //渐变加透明;
+  // background: linear-gradient(to bottom, rgba(245, 52, 29, 1) 0%, rgba(255, 255, 255, 0) 100%);
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 588rpx;
+  z-index: -1;
+}
 .search_fixed {
   top: var(--window-top);
   left: 0rpx;
@@ -397,9 +455,11 @@ export default {
       height: 382rpx;
       line-height: 382rpx;
       text-align: center;
+      border-radius: 8px;
       .image {
         width: 680rpx;
         height: 382rpx;
+        border-radius: 8px;
       }
     }
   }
@@ -407,25 +467,47 @@ export default {
 .product_box {
   display: block;
   overflow: hidden;
-  margin: 20rpx auto;
+  margin: -20rpx auto 20rpx;
   padding: 0rpx 35rpx;
   .product_list {
     display: block;
     overflow: hidden;
     margin: 0rpx auto;
     .product_item {
-      float: left;
-      width: 320rpx;
-      height: 520rpx;
+      // float: left;
+      width: 100%;
+      // height: 520rpx;
       display: block;
       overflow: hidden;
       margin: 20rpx 0rpx;
       margin-right: 40rpx;
       background-color: #ffffff;
       border-radius: 20rpx;
+      padding: 16rpx;
+      box-sizing: border-box;
+      .product_item_content {
+        display: flex;
+        gap: 10rpx;
+      }
+      .product_item_bottom {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+      }
+      .product_image_content {
+        width: 168rpx;
+        height: 168rpx;
+        background: #f5f5f5;
+        border-radius: 16rpx 16rpx 16rpx 16rpx;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        flex-shrink: 0;
+      }
       .product_image {
-        width: 320rpx;
-        height: 320rpx;
+        width: 143rpx;
+        height: 149rpx;
+        flex-shrink: 0;
       }
       .product_name {
         height: 80rpx;
@@ -456,8 +538,12 @@ export default {
         overflow: hidden;
         line-height: 30rpx;
         padding: 0rpx 10rpx;
+        display: flex;
+        gap: 10rpx;
+        align-items: baseline;
+        padding-left: 185rpx;
+        box-sizing: border-box;
         .product_price {
-          float: left;
           color: red;
           font-size: 30rpx;
           line-height: 60rpx;
@@ -470,15 +556,34 @@ export default {
           }
         }
         .product_stock {
-          float: right;
           font-size: 20rpx;
           line-height: 60rpx;
         }
       }
+      .stock_button {
+        width: 152rpx;
+        height: 60rpx;
+        background: #f89c33;
+        border-radius: 500rpx 500rpx 500rpx 500rpx;
+        color: #ffffff;
+        color: 26rpx;
+        text-align: center;
+        line-height: 60rpx;
+      }
     }
     .product_item:nth-child(even) {
       margin-right: 0rpx;
     }
   }
 }
+.icon-list {
+  margin-top: 24rpx;
+  padding: 0 35rpx;
+}
+.notice-list {
+  margin-top: 24rpx;
+}
+.header-title {
+  padding: 0 35rpx;
+}
 </style>

+ 28 - 1
pages/orders/index.vue

@@ -32,12 +32,20 @@
             <view class="pay_total">¥{{ item.pay_total }}</view>
           </view>
         </view>
+        <view class="order_btn" v-if="item.status == 0">
+          <button v-if="item.regiment_id > 0" class="order_cancel" @click="cancelOrderRegiment(index)">取消拼团</button>
+          <button v-else class="order_cancel" @click="cancelOrder(index)">取消订单</button>
+          <button class="order_share" @click="toPay(item)">去付款</button>
+        </view>
+        <view class="order_btn" v-if="item.status == 2">
+          <button class="order_share" @click="toReceipt(item)">我已收货</button>
+        </view>
 
         <view class="order_btn" v-if="item.status == 1">
           <button class="order_cancel" @click="cancelOrder(index)">取消订单</button>
           <button class="order_share" @click="toReceipt(item)">我已收货</button>
         </view>
-        <view class="order_btn" v-if="item.status == 10">
+        <view class="order_btn" v-if="item.status == 10 && item.is_pay == 0">
           <button class="order_cancel" @click="cancelOrderRegiment(index)">取消拼团</button>
         </view>
       </view>
@@ -183,6 +191,25 @@ export default {
         },
       });
     },
+    toPay(item) {
+      if (item) {
+        let orderInfo = {
+          snowflake_id: item.snowflake_id,
+          pay_total: item.pay_total,
+          order_id: item.id,
+        };
+        orderInfo = JSON.stringify(orderInfo);
+        let params = encodeURIComponent(orderInfo);
+        // 跳转到确认支付页面
+        uni.navigateTo({ url: `/pages/orders/confirm?params=${params}` });
+      } else {
+        uni.showToast({
+          title: '订单数据错误',
+          icon: 'none',
+        });
+        return;
+      }
+    },
     // 取消拼团
     cancelOrderRegiment(index) {
       uni.showModal({

+ 160 - 160
pages/product/index.vue

@@ -101,8 +101,8 @@
       <navigator url="/pages/car/index" open-type="switchTab" class="to_car">
         <image src="https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/icon/car.png" class="car_icon"></image>
       </navigator>
-      <button class="show_order" v-if="!productInfo.hide_orderbtn" data-eventsync="true" @click="showSpecPopup(1)">{{is_pay?'立即购买':'立即预约'}}</button>
-      <button :class="productInfo.hide_orderbtn?'show_car hide_orderbtn ':'show_car'"  data-eventsync="true" @click="showSpecPopup(2)">加入购物车</button>
+      <button class="show_order" v-if="!productInfo.hide_orderbtn" data-eventsync="true" @click="showSpecPopup(1)">{{ is_pay ? '立即购买' : '立即预约' }}</button>
+      <button :class="productInfo.hide_orderbtn ? 'show_car hide_orderbtn ' : 'show_car'" data-eventsync="true" @click="showSpecPopup(2)">加入购物车</button>
     </view>
     <view class="to_bottom"> --- 到底了 --- </view>
     <uni-popup ref="specPopup" :show="true" type="bottom" class="popup" background-color="#FFFFFF" @change="popupChange">
@@ -170,10 +170,10 @@
         </view>
         <view class="order_price" v-if="specBtnType == 1 || specBtnType == 3">合计: ¥{{ priceTotal }}</view>
         <view class="order_btn">
-          <button class="to_order" @click="createOrder()" v-if="specBtnType == 1" data-eventsync="true">{{is_pay?'购买':'预约'}}</button>
+          <button class="to_order" @click="createOrder()" v-if="specBtnType == 1" data-eventsync="true">{{ is_pay ? '购买' : '预约' }}</button>
           <button class="to_car" @click="createCart()" v-if="specBtnType == 2" data-eventsync="true">加入购物车</button>
-          <button class="to_order" @click="createOrder()" v-if="specBtnType == 3" data-eventsync="true">{{is_pay?'拼团购买':'拼团预约'}}</button>
-          <button class="to_order" @click="createOrder()" v-if="specBtnType == 4" data-eventsync="true">{{ productInfo.regiment_title }}{{is_pay?'购买':'预约'}}</button>
+          <button class="to_order" @click="createOrder()" v-if="specBtnType == 3" data-eventsync="true">{{ is_pay ? '拼团购买' : '拼团预约' }}</button>
+          <button class="to_order" @click="createOrder()" v-if="specBtnType == 4" data-eventsync="true">{{ productInfo.regiment_title }}{{ is_pay ? '购买' : '预约' }}</button>
         </view>
       </view>
     </uni-popup>
@@ -199,9 +199,9 @@
               <view class="coupon_name" v-if="item.rebate_type == 3">赠品券</view>
             </view>
             <view class="product_scope">
-              <text class="" v-if="item.type_id == 1">{{ item.is_scope ? "当前商品可用" : "当前商品不可用" }}</text>
+              <text class="" v-if="item.type_id == 1">{{ item.is_scope ? '当前商品可用' : '当前商品不可用' }}</text>
               <text class="" v-if="item.type_id == 2">全场可用</text>
-              <text class="" v-if="item.type_id == 3">{{ item.is_scope ? "当前商品可用" : "当前商品不可用" }}</text>
+              <text class="" v-if="item.type_id == 3">{{ item.is_scope ? '当前商品可用' : '当前商品不可用' }}</text>
               <view class="check_label">
                 <view class="isstd" v-if="!item.is_std">未达标</view>
                 <image
@@ -294,27 +294,27 @@ export default {
       show: false, // 使用Popup组件时,阻止禁止滚动穿透
       productInfo: {
         id: 0,
-        name: "",
-        price: "0.00",
-        market_price: "0.00",
-		hide_orderbtn:0,
-        spec: "",
+        name: '',
+        price: '0.00',
+        market_price: '0.00',
+        hide_orderbtn: 0,
+        spec: '',
         stock: 0,
-        thumb: "",
-        poster: "",
-        description: "",
-        regiment_title: "",
-        promo_title: "",
+        thumb: '',
+        poster: '',
+        description: '',
+        regiment_title: '',
+        promo_title: '',
         automatic_info: {
-          end_time: "",
+          end_time: '',
         },
         regiment_active: [],
         business_info: {
-          name: "",
-          logopic: "",
-          desc: "",
+          name: '',
+          logopic: '',
+          desc: '',
         },
-        regiment_price: "0.00",
+        regiment_price: '0.00',
         regiment_quota: 0,
         regiment_list: [],
         product_attr: [],
@@ -329,11 +329,11 @@ export default {
       // 数量
       quantity: 1,
       // 总价
-      priceTotal: "0.00",
+      priceTotal: '0.00',
       // 优惠券列表
       couponList: [],
       // 优惠券使用
-      couponUsed: "去使用 >",
+      couponUsed: '去使用 >',
       // 扣减金额
       rebatePrice: 0.0,
       // 已经选择的优惠券ID
@@ -345,25 +345,25 @@ export default {
       // 已选地址
       checkedAddr: {
         id: 0,
-        contact_name: "",
-        contact_shop: "",
-        contact_phone: "",
-        contact_province: "",
-        contact_city: "",
-        contact_area: "",
-        contact_addr: "",
+        contact_name: '',
+        contact_shop: '',
+        contact_phone: '',
+        contact_province: '',
+        contact_city: '',
+        contact_area: '',
+        contact_addr: '',
         is_default: 0,
         show_type: 0,
       },
       // 客服二维码
-      followQrcode: "",
+      followQrcode: '',
       // 二维码链接
-      follow_linkurl: "",
+      follow_linkurl: '',
       // 是否登录状态
       isShowPrice: false,
       // 选择的skuid
       sku_id: 0,
-      sku_thumb: "",
+      sku_thumb: '',
       regiment_id: 0,
       is_pay: 0,
     };
@@ -380,7 +380,7 @@ export default {
     }
     var that = this;
     // 监听地址变动
-    uni.$on("addr_list_change", function (data) {
+    uni.$on('addr_list_change', function (data) {
       // 地址列表
       that.addrList = data.list;
     });
@@ -388,22 +388,22 @@ export default {
     //分享按钮
     uni.showShareMenu({
       withShareTicket: true,
-      menus: ["shareAppMessage", "shareTimeline"],
+      menus: ['shareAppMessage', 'shareTimeline'],
     });
     // #endif
   },
   onShareAppMessage(obj) {
     return {
       title: `999智控终端平台\n${this.productInfo.name}`,
-      path: "/pages/product/index?product_id=" + this.productInfo.id,
+      path: '/pages/product/index?product_id=' + this.productInfo.id,
       promise: new Promise((resolve, reject) => {
-        this.$http.request("api/share_message/get_item", { item_id: this.productInfo.id, pages: "/pages/product/index" }).then((callback) => {
-          console.log(callback, "api/share_message/get_item");
+        this.$http.request('api/share_message/get_item', { item_id: this.productInfo.id, pages: '/pages/product/index' }).then((callback) => {
+          console.log(callback, 'api/share_message/get_item');
           let obj = {
-            title: callback.data?.title == "" ? `999智控终端平台\n${this.productInfo.name}` : callback.data.title,
-            path: "/pages/product/index?product_id=" + this.productInfo.id,
+            title: callback.data?.title == '' ? `999智控终端平台\n${this.productInfo.name}` : callback.data.title,
+            path: '/pages/product/index?product_id=' + this.productInfo.id,
           };
-          if (callback.data?.image_url !== "") {
+          if (callback.data?.image_url !== '') {
             obj.imageUrl = callback.data.image_url;
           }
           resolve(obj);
@@ -417,40 +417,40 @@ export default {
     // 如果有添加二维码的话,获取客户信息
     if (this.$checkAccess.getFollowQrcode()) {
       // 判断数据
-      this.$http.request("api/custom/get_info").then((callback) => {
-        if (callback.code == "success") {
-          if (!callback.data.userpic) callback.data.userpic = "https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/icon/doctor.png";
+      this.$http.request('api/custom/get_info').then((callback) => {
+        if (callback.code == 'success') {
+          if (!callback.data.userpic) callback.data.userpic = 'https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/icon/doctor.png';
           // 存储登录标识
-          uni.setStorageSync("userInfo", callback.data);
+          uni.setStorageSync('userInfo', callback.data);
         }
       });
     }
     // 如果存在产品ID的话
     if (this.requestParam.id > 0) {
       // 请求详情
-      this.$http.request("api/product/get_detail", this.requestParam).then((re) => {
+      this.$http.request('api/product/get_detail', this.requestParam).then((re) => {
         // 成功渲染数据
-        if (re.code == "success") {
+        if (re.code == 'success') {
           // 刷新数据
           this.productInfo = re.data;
-		  // 
+          //
           if (this.productInfo.automatic_info.id) {
             this.regiment_id = this.productInfo.automatic_info.id;
           }
-		  //设置默认sku
-		  this.sku_id = 0;
-		  this.is_pay = this.productInfo.is_pay;
-		  // 显示图片
-		  this.sku_thumb = this.productInfo.thumb;
-		  // 如果只有一个SKU,默认选择一个
-          if ( this.productInfo.product_attr.length == 1) {
-			// 设置对应的属性已经选中
-            if ( this.productInfo.product_attr[0].attr_list.length == 1 ) {
-				this.attrChange(0,0);
+          //设置默认sku
+          this.sku_id = 0;
+          this.is_pay = this.productInfo.is_pay;
+          // 显示图片
+          this.sku_thumb = this.productInfo.thumb;
+          // 如果只有一个SKU,默认选择一个
+          if (this.productInfo.product_attr.length == 1) {
+            // 设置对应的属性已经选中
+            if (this.productInfo.product_attr[0].attr_list.length == 1) {
+              this.attrChange(0, 0);
             }
           }
         } else {
-          if (re.code != "no_login") {
+          if (re.code != 'no_login') {
             uni.showModal({
               content: re.msg,
               showCancel: false,
@@ -485,7 +485,7 @@ export default {
     // 地址弹出层
     showAddrPopup() {
       // 显示下单弹出层
-      this.$refs.addrPopup.open("bottom");
+      this.$refs.addrPopup.open('bottom');
     },
     // 规格弹出层
     showSpecPopup(type, regiment_id = 0) {
@@ -499,7 +499,7 @@ export default {
       // 显示类型,1预约,2购物车,3拼团
       this.specBtnType = type;
       // 恢复优惠券使用按钮
-      this.couponUsed = "去使用 >";
+      this.couponUsed = '去使用 >';
       // 恢复扣减金额
       this.rebatePrice = 0.0;
       // 选择优惠券重置
@@ -507,28 +507,28 @@ export default {
       // 计算价格
       this.priceHandler();
       // 显示下单弹出层
-      this.$refs.specPopup.open("bottom");
-	  // 如果非团购的话,查询优惠券
-	  if( type == 3 || type == 4 ){
-		  // 选择优惠券重置
-		  this.couponList = [];
-		  // 已经选择的优惠券ID
-		  this.customCoupon = 0;
-		  // 计算扣减
-		  this.couponRebate();
-		  // 计算价格
-		  this.priceHandler();
-	  }else{
-		  // 结果
-		  this.$http.request("api/custom_coupon/get_checked", this.requestParam).then((re) => {
-		    if (re.code == "success") {
-		      // 赋值
-		      this.couponList = re.data;
-		      // 优惠券是否可用
-		      this.checkCoupon();
-		    }
-		  });
-	  }
+      this.$refs.specPopup.open('bottom');
+      // 如果非团购的话,查询优惠券
+      if (type == 3 || type == 4) {
+        // 选择优惠券重置
+        this.couponList = [];
+        // 已经选择的优惠券ID
+        this.customCoupon = 0;
+        // 计算扣减
+        this.couponRebate();
+        // 计算价格
+        this.priceHandler();
+      } else {
+        // 结果
+        this.$http.request('api/custom_coupon/get_checked', this.requestParam).then((re) => {
+          if (re.code == 'success') {
+            // 赋值
+            this.couponList = re.data;
+            // 优惠券是否可用
+            this.checkCoupon();
+          }
+        });
+      }
       // 地址列表
       this.getAddrList();
       //只有一组sku时是否下架
@@ -538,11 +538,11 @@ export default {
     },
     // 拼团列表弹出层
     openRegiment() {
-      this.$refs.regiment.open("bottom");
+      this.$refs.regiment.open('bottom');
     },
     // 优惠券弹出层
     openCoupon() {
-      this.$refs.couponPopup.open("bottom");
+      this.$refs.couponPopup.open('bottom');
     },
     // 数量调整
     changeQuantity(number) {
@@ -555,23 +555,23 @@ export default {
       if (this.quantity > this.productInfo.stock) {
         this.quantity = this.productInfo.stock;
         uni.showToast({
-          title: "库存不足",
-          icon: "none",
+          title: '库存不足',
+          icon: 'none',
         });
       }
       if ((this.specBtnType === 3 || this.specBtnType == 4) && this.quantity > this.productInfo.regiment_quota) {
         this.quantity = this.productInfo.regiment_quota;
         uni.showToast({
-          title: "拼团限购" + this.productInfo.regiment_quota + "份",
-          icon: "none",
+          title: '拼团限购' + this.productInfo.regiment_quota + '份',
+          icon: 'none',
         });
       }
       // 如果小于1.设置为1
       if (this.quantity < 1) {
         this.quantity = 1;
         uni.showToast({
-          title: "数量不可以小于0",
-          icon: "none",
+          title: '数量不可以小于0',
+          icon: 'none',
         });
       }
       // 计算价格
@@ -593,24 +593,24 @@ export default {
           skuname.push(this.productInfo.product_attr[i].spec_name);
         }
         uni.showToast({
-          title: "请选择" + skuname.join(" 与 "),
-          icon: "none",
+          title: '请选择' + skuname.join(' 与 '),
+          icon: 'none',
         });
         return;
       }
       // 下单数量小于0
       if (this.quantity < 1) {
         uni.showToast({
-          title: "至少购买1个",
-          icon: "none",
+          title: '至少购买1个',
+          icon: 'none',
         });
         return;
       }
       // 如果大于库存设置为库存
       if (this.productInfo.stock < 1) {
         uni.showToast({
-          title: "库存不足",
-          icon: "none",
+          title: '库存不足',
+          icon: 'none',
         });
         return;
       }
@@ -618,8 +618,8 @@ export default {
       if (this.productInfo.stock < this.quantity) {
         this.quantity = this.productInfo.stock;
         uni.showToast({
-          title: "库存不足",
-          icon: "none",
+          title: '库存不足',
+          icon: 'none',
         });
         return;
       }
@@ -627,23 +627,23 @@ export default {
         if (this.quantity > this.productInfo.regiment_quota) {
           this.quantity = this.productInfo.regiment_quota;
           uni.showToast({
-            title: "拼团限购" + this.productInfo.regiment_quota + "份",
-            icon: "none",
+            title: '拼团限购' + this.productInfo.regiment_quota + '份',
+            icon: 'none',
           });
           return;
         }
         const timestamp = Math.round(new Date().getTime() / 1000).toString();
         if (timestamp > this.productInfo.regiment_active.end_time) {
           uni.showToast({
-            title: "拼团活动已结束",
-            icon: "none",
+            title: '拼团活动已结束',
+            icon: 'none',
           });
           return;
         }
         if (this.specBtnType === 4 && timestamp > this.productInfo.automatic_info.end_time) {
           uni.showToast({
-            title: "该团已过期",
-            icon: "none",
+            title: '该团已过期',
+            icon: 'none',
           });
           return;
         }
@@ -680,7 +680,7 @@ export default {
         // 请求接口
         this.$http
           .request(
-            "api/orders/create_regiment",
+            'api/orders/create_regiment',
             {
               product_list: productList,
               // custom_coupon_id: this.customCoupon,
@@ -690,23 +690,23 @@ export default {
               regiment_active_id: this.productInfo.regiment_active_id,
               is_pay: this.is_pay,
             },
-            "post"
+            'post'
           )
           .then((re) => {
             // 判断结果
-            if (re.code == "success") {
+            if (re.code == 'success') {
               // 处理结果
               this.productInfo.stock = this.productInfo.stock - this.quantity;
               // 关闭弹窗
               this.$refs.specPopup.close();
-              if (this.is_pay){
+              if (this.is_pay) {
                 //订单详情
                 let orderInfo = re.data;
-                orderInfo = JSON.stringify(orderInfo)
+                orderInfo = JSON.stringify(orderInfo);
                 let params = encodeURIComponent(orderInfo);
                 // 跳转到确认支付页面
-                uni.navigateTo({url:`/pages/orders/confirm?params=${params}`});
-              }else {
+                uni.navigateTo({ url: `/pages/orders/confirm?params=${params}` });
+              } else {
                 // 跳转到报单完成页面
                 uni.navigateTo({
                   url: `/pages/orders/completion?params=${encodedArray}`,
@@ -723,30 +723,30 @@ export default {
         // 请求接口
         this.$http
           .request(
-            "api/orders/create",
+            'api/orders/create',
             {
               product_list: productList,
               custom_coupon_id: this.customCoupon,
               addr_id: this.checkedAddr.id,
               is_pay: this.is_pay,
             },
-            "post"
+            'post'
           )
           .then((re) => {
             // 判断结果
-            if (re.code == "success") {
+            if (re.code == 'success') {
               // 处理结果
               this.productInfo.stock = this.productInfo.stock - this.quantity;
               // 关闭弹窗
               this.$refs.specPopup.close();
-              if (this.is_pay){
+              if (this.is_pay) {
                 //订单详情
                 let orderInfo = re.data;
-                orderInfo = JSON.stringify(orderInfo)
+                orderInfo = JSON.stringify(orderInfo);
                 let params = encodeURIComponent(orderInfo);
                 // 跳转到确认支付页面
-                uni.navigateTo({url:`/pages/orders/confirm?params=${params}`});
-              }else {
+                uni.navigateTo({ url: `/pages/orders/confirm?params=${params}` });
+              } else {
                 // 跳转到报单完成页面
                 uni.navigateTo({
                   url: `/pages/orders/completion?params=${encodedArray}`,
@@ -775,23 +775,23 @@ export default {
           skuname.push(this.productInfo.product_attr[i].spec_name);
         }
         uni.showToast({
-          title: "请选择" + skuname.join(" 与 "),
-          icon: "none",
+          title: '请选择' + skuname.join(' 与 '),
+          icon: 'none',
         });
         return;
       }
       // 下单数量小于0
       if (this.quantity < 1) {
         uni.showToast({
-          title: "至少购买1个",
+          title: '至少购买1个',
         });
         return;
       }
       // 如果库存不足
       if (this.productInfo.stock < 1) {
         uni.showToast({
-          title: "库存不足",
-          icon: "none",
+          title: '库存不足',
+          icon: 'none',
         });
         return;
       }
@@ -799,8 +799,8 @@ export default {
       if (this.productInfo.stock < this.quantity) {
         this.quantity = this.productInfo.stock;
         uni.showToast({
-          title: "库存不足",
-          icon: "none",
+          title: '库存不足',
+          icon: 'none',
         });
         return;
       }
@@ -811,21 +811,21 @@ export default {
         skuid: this.sku_id,
       };
       // 请求接口
-      this.$http.request("api/shop_cart/add", data, "post").then((re) => {
+      this.$http.request('api/shop_cart/add', data, 'post').then((re) => {
         // 判断结果
-        if (re.code == "success") {
+        if (re.code == 'success') {
           // 跳转到订单列表
           uni.showToast({
-            icon: "success",
-            title: "加入购物车成功",
+            icon: 'success',
+            title: '加入购物车成功',
           });
           // 关闭结果
           this.$refs.specPopup.close();
         } else {
           // 跳转到订单列表
           uni.showToast({
-            icon: "error",
-            title: "加入购物车失败",
+            icon: 'error',
+            title: '加入购物车失败',
           });
         }
       });
@@ -921,7 +921,7 @@ export default {
         if (index != i) this.couponList[i].checked = 0;
       }
       // 如果未选中,提示可用
-      if (!this.couponList[index].checked) this.couponUsed = "去使用 >";
+      if (!this.couponList[index].checked) this.couponUsed = '去使用 >';
       // 已经选择的优惠券ID
       this.customCoupon = this.couponList[index].checked ? this.couponList[index].id : 0;
       // 计算扣减
@@ -994,7 +994,7 @@ export default {
             // 计算扣减数据
             rebatePrice = this.$decimal.mul(this.couponList[i].rebate, 1);
             // 替换文字
-            this.couponUsed = "¥-" + rebatePrice.toFixed(2);
+            this.couponUsed = '¥-' + rebatePrice.toFixed(2);
           }
           // 折扣
           if (this.couponList[i].rebate_type == 2) {
@@ -1003,12 +1003,12 @@ export default {
             // 减数
             rebatePrice = this.$decimal.sub(totalPrice, rebatePrice.mul(0.1));
             // 替换文字
-            this.couponUsed = "¥-" + rebatePrice.toFixed(2);
+            this.couponUsed = '¥-' + rebatePrice.toFixed(2);
           }
           //  赠品
           if (this.couponList[i].rebate_type == 3) {
             // 替换文字
-            this.couponUsed = "送" + (this.couponList[i].rebate_scope.length ? this.couponList[i].rebate_scope[0].product_name : "");
+            this.couponUsed = '送' + (this.couponList[i].rebate_scope.length ? this.couponList[i].rebate_scope[0].product_name : '');
           }
           // 小数点保留
           this.rebatePrice = rebatePrice.toFixed(2);
@@ -1026,9 +1026,9 @@ export default {
     },
     getAddrList() {
       // 判断数据
-      this.$http.request("api/custom_addr/get_list").then((callback) => {
+      this.$http.request('api/custom_addr/get_list').then((callback) => {
         // 获取成功
-        if (callback.code == "success") {
+        if (callback.code == 'success') {
           this.addrList = callback.data;
           // 如果有的话
           if (this.addrList.length) {
@@ -1052,7 +1052,7 @@ export default {
       // 返回结果
       this.follow_linkurl = this.$checkAccess.getFollowLinkUrl();
       // 有图才展示
-      if (this.followQrcode) this.$refs.addFollow.open("center");
+      if (this.followQrcode) this.$refs.addFollow.open('center');
     },
     closeAddFollow() {
       this.$refs.addFollow.close();
@@ -1086,7 +1086,7 @@ export default {
         }
       }
       // 转成字符串
-      var attrids = attr_ids.join(",");
+      var attrids = attr_ids.join(',');
       // 如果选项不足的话
       if (attr_ids.length != this.productInfo.product_attr.length) return;
       // 如果当前点击的属性对应的SKU状态为未下架(初始化为0)
@@ -1106,8 +1106,8 @@ export default {
           // 如果商品已经下架(status等于1),则恢复当前规格下所有属性原来的active状态
           if (currentSKUStatus === 1) {
             uni.showToast({
-              title: "该规格已下架",
-              icon: "none",
+              title: '该规格已下架',
+              icon: 'none',
             });
             for (let k in originalActiveStates) {
               this.productInfo.product_attr[spec_index].attr_list[k].active = originalActiveStates[k];
@@ -1117,8 +1117,8 @@ export default {
           // 如果商品没有库存
           if (this.productInfo.product_sku[i].stock <= 0) {
             uni.showToast({
-              title: "该规格库存不足",
-              icon: "none",
+              title: '该规格库存不足',
+              icon: 'none',
             });
             for (let k in originalActiveStates) {
               this.productInfo.product_attr[spec_index].attr_list[k].active = originalActiveStates[k];
@@ -1149,8 +1149,8 @@ export default {
         // 如果没有对应的SKU
         if (!haveSku) {
           uni.showToast({
-            title: "该规格已下架",
-            icon: "none",
+            title: '该规格已下架',
+            icon: 'none',
           });
           for (let k in originalActiveStates) {
             this.productInfo.product_attr[spec_index].attr_list[k].active = originalActiveStates[k];
@@ -1163,17 +1163,17 @@ export default {
       if (this.productInfo.product_sku.length) {
         if (this.productInfo.product_sku[0].status === 1) {
           uni.showToast({
-            title: "该规格已下架",
-            icon: "none",
+            title: '该规格已下架',
+            icon: 'none',
           });
           this.productInfo.stock = 0;
-          var attr_ids = this.productInfo.product_sku[0].attr_ids.split(",");
+          var attr_ids = this.productInfo.product_sku[0].attr_ids.split(',');
           // 循环规格列表
           for (let i in this.productInfo.product_attr) {
             // 再循环属性
             for (let j in this.productInfo.product_attr[i].attr_list) {
               // 如果不等于id
-              if (attr_ids.includes(this.productInfo.product_attr[i].attr_list[j].id + "")) {
+              if (attr_ids.includes(this.productInfo.product_attr[i].attr_list[j].id + '')) {
                 // 取消选中
                 this.productInfo.product_attr[i].attr_list[j].active = 0;
               }
@@ -1186,17 +1186,17 @@ export default {
     // 去往webview
     followLinkurl() {
       // 获取登录标识
-      let userInfo = uni.getStorageSync("userInfo");
+      let userInfo = uni.getStorageSync('userInfo');
       // 如果不存在的话
-      if (!userInfo) return "";
+      if (!userInfo) return '';
       // 未添加好友
-      if (!userInfo.follow_linkurl) return "";
+      if (!userInfo.follow_linkurl) return '';
       // 获取Url
       let url = userInfo.follow_linkurl;
       // 没有路径,不跳转
       if (!url) return;
       // 判断是不是小程序链接
-      if (url.includes("http")) {
+      if (url.includes('http')) {
         // 转码
         let link_url = encodeURIComponent(url);
         // 跳转到webview
@@ -1428,11 +1428,11 @@ export default {
     border-top-left-radius: 20rpx;
     border-bottom-left-radius: 20rpx;
   }
-  
-  .show_car.hide_orderbtn{
-	  width: 580rpx;
-	  border-radius: 20rpx;
-	  margin-right: 35rpx;
+
+  .show_car.hide_orderbtn {
+    width: 580rpx;
+    border-radius: 20rpx;
+    margin-right: 35rpx;
   }
 
   .to_car {

+ 474 - 0
pages/product/list.vue

@@ -0,0 +1,474 @@
+<template>
+  <view style="padding-top: 120rpx">
+    <!-- 轮播图 -->
+    <view class="search_fixed">
+      <view class="search_box">
+        <input class="search_input" type="text" v-model="requestParam.name" @input="searchChange" placeholder="请输入产品名称搜索" />
+        <button class="search_btn" @click.stop="searchOpen()" data-eventsync="true">搜索</button>
+      </view>
+    </view>
+    <view class="product_box">
+      <view class="to_bottom" v-if="!productList.length"> -----还没有产品啦-----</view>
+      <!-- 产品列表 -->
+      <view class="product_list">
+        <!-- Vue3 项目部分小程序端事件延迟或调用失败 在执行事件的元素上添加 data-eventsync="true" 属性以解决此问题 -->
+        <view @click="toDetail(item)" data-eventsync="true" class="product_item" v-for="(item, index) in productList" :key="index">
+          <view class="product_item_content">
+            <view class="product_image_content">
+              <image class="product_image" :src="item.thumb" mode=""></image>
+            </view>
+            <view>
+              <view class="product_name">
+                <text v-if="item.promo_title" class="regiment_title">{{ item.promo_title }}</text>
+                <text v-if="item.regiment_title" class="regiment_title">{{ item.regiment_title }}</text>
+                <text>{{ item.name }}</text></view
+              >
+              <view class="product_spec"
+                ><text>{{ item.spec }}</text></view
+              ></view
+            >
+          </view>
+          <view class="product_item_bottom">
+            <view class="stock_price">
+              <view class="product_price" v-if="isShowPrice">
+                <text>¥{{ item.price }} </text>
+              </view>
+              <view class="product_stock">剩{{ item.stock }}个</view>
+            </view>
+            <view class="stock_button">立即抢购</view>
+          </view>
+        </view>
+      </view>
+    </view>
+    <view class="to_bottom" v-if="isLast" style="display: flex; justify-content: center">
+      -----
+      <view :style="!productList.length && toSelectedCity ? 'font-weight:bold;font-size:36rpx' : ''">{{ !productList.length && toSelectedCity ? '请点击左上角选择你的城市' : '到底啦' }}</view> -----
+    </view>
+    <uni-popup ref="addFollow" type="center" class="center_popup">
+      <FollowPopup :closePopup="closePopup" />
+    </uni-popup>
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      // 轮播图
+      bannerList: [],
+      // 产品列表
+      productList: [],
+      // 请求参数
+      requestParam: {
+        name: '',
+        page: 1,
+      },
+      // 是否最后一页
+      isLast: false,
+      // 是否请求中
+      isReqing: false,
+      // 是否显示价格
+      isShowPrice: false,
+      // 城市名称
+      cityName: '选城市',
+      // 选择城市
+      toSelectedCity: false,
+      // 是否是管理员
+      isManager: false,
+    };
+  },
+  onLoad() {
+    // #ifdef MP-WEIXIN
+    //分享按钮
+    uni.showShareMenu({
+      withShareTicket: true,
+      menus: ['shareAppMessage', 'shareTimeline'],
+    });
+    // #endif
+  },
+  onShareAppMessage(obj) {
+    // 获取分享信息
+    let shareList = getApp().globalData.shareList;
+    // 获取分享信息
+    let shareObj = {
+      title: '999智控终端平台\n药优惠 得积分 兑豪礼',
+      path: '/pages/index/index',
+      imageUrl: '',
+    };
+    // 循环列表
+    for (let i in shareList) {
+      if (shareList[i].pages == 'pages/index/index') {
+        shareObj.path = shareList[i].path ? shareList[i].path : shareObj.path;
+        shareObj.title = shareList[i].title ? `999智控终端平台\n${shareList[i].title}` : shareObj.title;
+        shareObj.imageUrl = shareList[i].image_url ? shareList[i].image_url : shareObj.imageUrl;
+      }
+    }
+    // 返回分享信息
+    return shareObj;
+  },
+  onShow() {
+    // 是否显示价格
+    this.isShowPrice = this.$checkAccess.checkShowPrice();
+    // 城市名
+    this.cityName = this.$checkAccess.getCity();
+    // 选城市
+    (this.cityName = this.cityName ? this.cityName : '选城市'),
+      // 登录并且未选择城市,才可以选择城市
+      (this.toSelectedCity = !this.$checkAccess.getCity() ? true : false);
+    // 数据
+
+    //未选城市先弹窗提醒选择城市
+    if (!this.$checkAccess.getCity() && this.$checkAccess.checkLogin()) {
+      uni.showModal({
+        title: '',
+        content: '请先选择城市',
+        success: (res) => {
+          if (res.confirm) {
+            uni.navigateTo({
+              url: '/pages/user/info',
+            });
+          }
+        },
+      });
+    }
+
+    //如果已选城市且没有添加客服每天弹窗一次
+    if (this.$checkAccess.getCity() && this.$checkAccess.getFollowQrcode()) {
+      // 获取弹出时间
+      let followPopupTime = uni.getStorageSync('followPopupTime');
+      // 现在的时候
+      let nowTime = new Date().getTime();
+      // 时间戳
+      followPopupTime = followPopupTime ? followPopupTime : 0;
+      // 弹出结果
+      if (followPopupTime <= 0 || followPopupTime - nowTime > 86400000) {
+        this.$refs.addFollow.open('center');
+        uni.setStorageSync('followPopupTime', nowTime);
+      }
+    }
+    this.isManager = this.$checkAccess.isManager();
+    // 没有数据的话,或者请求中,不允许刷新
+    if (this.isReqing) return;
+    // 获取列表
+    this.$http.request('/api/banner/get_list').then((re) => {
+      if (re.code === 'success') {
+        this.bannerList = re.data;
+      }
+    });
+    // 请求参数
+    this.requestParam.name = '';
+    // 请求参数
+    this.requestParam.page = 1;
+    // 是否是最后一页
+    this.isLast = false;
+    // 设置请求中
+    this.isReqing = true;
+    // 请求
+    this.$http.request('api/product/get_list', this.requestParam).then((re) => {
+      // 设置非请求中
+      this.isReqing = false;
+      // 成功结果
+      if (re.code == 'success') {
+        // 如果是最后一页
+        if (re.data.last_page <= this.requestParam.page) this.isLast = true;
+        // 赋值
+        this.productList = re.data.data;
+        // 获取下一页
+        this.getMore(re);
+      }
+    });
+  },
+  onPullDownRefresh() {
+    // 如果请求中,不允许请求,
+    if (this.isReqing) return false;
+    // 初始化页码为1
+    this.requestParam.page = 1;
+    // 是否是最后一页
+    this.isLast = false;
+    // 设置请求中
+    this.isReqing = true;
+    // 请求列表
+    this.$http.request('api/product/get_list', this.requestParam).then((re) => {
+      // 设置非请求中
+      this.isReqing = false;
+      // 成功结果
+      if (re.code == 'success') {
+        // 如果是最后一页
+        if (re.data.last_page <= this.requestParam.page) this.isLast = true;
+        // 赋值
+        this.productList = re.data.data;
+        // 获取下一页
+        this.getMore(re);
+      }
+    });
+    uni.stopPullDownRefresh();
+  },
+  onReachBottom() {
+    // 如果页码是0,避免第一页重复
+    if (this.requestParam.page < 1) return;
+    // 最后一页不再请求
+    if (this.isLast) return;
+    // 请求中,不再请求
+    if (this.isReqing) return;
+    // 增加一页
+    this.requestParam.page = this.requestParam.page + 1;
+    // 设置请求中
+    this.isReqing = true;
+    // 请求列表
+    this.$http.request('api/product/get_list', this.requestParam).then((re) => {
+      // 设置非请求中
+      this.isReqing = false;
+      // 成功结果
+      if (re.code == 'success') {
+        // 最后一页
+        if (re.data.last_page <= this.requestParam.page) this.isLast = true;
+        // 追加数据
+        this.productList.push(...re.data.data);
+      }
+    });
+  },
+  methods: {
+    // 请求加载下一页
+    getMore(callback) {
+      // 首页不足10个,并且下一页存在大于当前页
+      if (this.productList.length < 10 && callback.data.last_page > this.requestParam.page) {
+        // 最后一页不再请求
+        if (this.isLast) return;
+        // 增加一页
+        this.requestParam.page = this.requestParam.page + 1;
+        // 请求列表
+        this.$http.request('api/product/get_list', this.requestParam).then((re) => {
+          // 成功结果
+          if (re.code == 'success') {
+            // 最后一页
+            if (re.data.last_page <= this.requestParam.page) this.isLast = true;
+            // 追加数据
+            this.productList.push(...re.data.data);
+            // 获取下一页
+            this.getMore(re);
+          }
+        });
+      }
+    },
+    searchChange(e) {
+      // 如果没有搜索词
+      if (!this.requestParam.name) {
+        this.searchOpen();
+      }
+    },
+    searchOpen() {
+      // 请求中,不再请求
+      if (this.isReqing) return;
+      // 是否是最后一页
+      this.isLast = false;
+      // 初始化页码为1
+      this.requestParam.page = 1;
+      // 设置请求中
+      this.isReqing = true;
+      // 请求列表
+      this.$http.request('api/product/get_list', this.requestParam).then((re) => {
+        // 设置非请求中
+        this.isReqing = false;
+        // 成功结果
+        if (re.code == 'success') {
+          this.productList = re.data.data;
+          if (re.data.data.length && re.data.last_page >= this.requestParam.page) this.isLast = true;
+        }
+      });
+    },
+    toDetail(item) {
+      uni.navigateTo({
+        url: '/pages/product/index?product_id=' + item.id,
+      });
+    },
+    navLottery(url) {
+      // 没有路径,不跳转
+      if (!url) return;
+      // 判断是不是小程序链接
+      if (url.includes('http')) {
+        // 转码
+        let link_url = encodeURIComponent(url);
+        // 跳转到webview
+        uni.redirectTo({
+          url: `/pages/webview/index?link_url=${link_url}`,
+        });
+      } else {
+        // 跳转到webview
+        uni.navigateTo({
+          url: url,
+        });
+      }
+    },
+    closePopup() {
+      this.$refs.addFollow.close();
+      //存key以及时间
+      uni.setStorage({
+        key: 'followPopupTime',
+        data: new Date().getTime(),
+      });
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.search_fixed {
+  top: var(--window-top);
+  left: 0rpx;
+  width: 750rpx;
+  display: block;
+  position: fixed;
+  margin: 0rpx auto;
+  padding: 20rpx 20rpx;
+  background-color: #ffffff;
+  box-sizing: border-box;
+  .search_box {
+    width: 750rpx;
+    height: 60rpx;
+    display: block;
+    position: relative;
+
+    .search_input {
+      z-index: 0;
+      float: left;
+      width: 600rpx;
+      height: 56rpx;
+      display: block;
+      font-size: 24rpx;
+      padding-left: 20rpx;
+      position: relative;
+      border-top-left-radius: 40rpx;
+      border-bottom-left-radius: 40rpx;
+      border: 2rpx solid #dddddd;
+    }
+    .search_btn {
+      top: 0rpx;
+      z-index: 9;
+      right: 40rpx;
+      color: #ffffff;
+      position: absolute;
+      display: block;
+      width: 120rpx;
+      height: 60rpx;
+      font-size: 24rpx;
+      margin: 0rpx 0rpx;
+      padding: 0rpx 0rpx;
+      line-height: 60rpx;
+      border-radius: 40rpx;
+      background-color: #e03519;
+    }
+  }
+}
+.product_box {
+  display: block;
+  overflow: hidden;
+  margin: -20rpx auto 20rpx;
+  padding: 0rpx 35rpx;
+  .product_list {
+    display: block;
+    overflow: hidden;
+    margin: 0rpx auto;
+    .product_item {
+      // float: left;
+      width: 100%;
+      // height: 520rpx;
+      display: block;
+      overflow: hidden;
+      margin: 20rpx 0rpx;
+      margin-right: 40rpx;
+      background-color: #ffffff;
+      border-radius: 20rpx;
+      padding: 16rpx;
+      box-sizing: border-box;
+      .product_item_content {
+        display: flex;
+        gap: 10rpx;
+      }
+      .product_item_bottom {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+      }
+      .product_image_content {
+        width: 168rpx;
+        height: 168rpx;
+        background: #f5f5f5;
+        border-radius: 16rpx 16rpx 16rpx 16rpx;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        flex-shrink: 0;
+      }
+      .product_image {
+        width: 143rpx;
+        height: 149rpx;
+        flex-shrink: 0;
+      }
+      .product_name {
+        height: 80rpx;
+        font-size: 30rpx;
+        line-height: 40rpx;
+        overflow: hidden;
+        margin: 10rpx 0rpx;
+        padding: 0rpx 10rpx;
+        text-overflow: ellipsis;
+        .regiment_title {
+          background-color: red;
+          color: #f9f9f9;
+        }
+      }
+      .product_spec {
+        height: 30rpx;
+        color: #999999;
+        font-size: 24rpx;
+        line-height: 30rpx;
+        padding: 0rpx 10rpx;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+      }
+      .stock_price {
+        color: #dddddd;
+        font-size: 20rpx;
+        overflow: hidden;
+        line-height: 30rpx;
+        padding: 0rpx 10rpx;
+        display: flex;
+        gap: 10rpx;
+        align-items: baseline;
+        padding-left: 185rpx;
+        box-sizing: border-box;
+        .product_price {
+          color: red;
+          font-size: 30rpx;
+          line-height: 60rpx;
+          .product_market {
+            font-size: 24rpx;
+            color: #999999;
+            line-height: 30rpx;
+            vertical-align: top;
+            text-decoration: line-through;
+          }
+        }
+        .product_stock {
+          font-size: 20rpx;
+          line-height: 60rpx;
+        }
+      }
+      .stock_button {
+        width: 152rpx;
+        height: 60rpx;
+        background: #f89c33;
+        border-radius: 500rpx 500rpx 500rpx 500rpx;
+        color: #ffffff;
+        color: 26rpx;
+        text-align: center;
+        line-height: 60rpx;
+      }
+    }
+    .product_item:nth-child(even) {
+      margin-right: 0rpx;
+    }
+  }
+}
+</style>

+ 21 - 21
pages/score/orders_detail.vue

@@ -48,16 +48,16 @@
         <view>下单时间&nbsp;</view>
         <view>{{ order_datail?.insert_time }}</view>
       </view>
-	  <view class="price_content_item" v-if="order_datail?.track_number">
-	    <view>物流编号&nbsp;</view>
-	    <view style="display: flex; align-items: center">
-	      <view>{{order_datail?.track_number}}</view>
-	      <view class="copy_btn" @click="_copyorderCode(order_datail?.track_number)">&nbsp;复制</view>
-	    </view>
-	  </view>
+      <view class="price_content_item" v-if="order_datail?.track_number">
+        <view>物流编号&nbsp;</view>
+        <view style="display: flex; align-items: center">
+          <view>{{ order_datail?.track_number }}</view>
+          <view class="copy_btn" @click="_copyorderCode(order_datail?.track_number)">&nbsp;复制</view>
+        </view>
+      </view>
       <view class="price_content_item">
         <view>备&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;注&nbsp;&nbsp;</view>
-        <view class="remark" style="text-align: right;">{{ order_datail?.remark }}</view>
+        <view class="remark" style="text-align: right">{{ order_datail?.remark }}</view>
       </view>
     </view>
   </view>
@@ -76,16 +76,16 @@ export default {
   methods: {
     _getOrderDetail(orderId) {
       this.$http
-        .request("api/score_orders/get_detail", { id: orderId })
+        .request('api/score_orders/get_detail', { id: orderId })
         .then((response) => {
-          if (response.code == "success") {
+          if (response.code == 'success') {
             this.order_datail = response.data; // 打印订单详情
           }
         })
         .catch((error) => {
           uni.showToast({
-            title: "获取订单详情失败",
-            icon: "error",
+            title: '获取订单详情失败',
+            icon: 'error',
             duration: 2000,
           });
         });
@@ -93,7 +93,7 @@ export default {
     _navToProduct(id) {
       if (id) {
         uni.navigateTo({
-          url: "/pages/score/product?id=" + id,
+          url: '/pages/score/product?id=' + id,
         });
       }
     },
@@ -106,24 +106,24 @@ export default {
           //复制成功的回调函数
           uni.showToast({
             //提示
-            title: "复制成功",
+            title: '复制成功',
           });
         },
       });
       // #endif
 
       // #ifdef H5
-      let textarea = document.createElement("textarea");
+      let textarea = document.createElement('textarea');
       textarea.value = info;
-      textarea.readOnly = "readOnly";
+      textarea.readOnly = 'readOnly';
       document.body.appendChild(textarea);
       textarea.select(); // 选中文本内容
       textarea.setSelectionRange(0, info.length);
       uni.showToast({
         //提示
-        title: "复制成功",
+        title: '复制成功',
       });
-      result = document.execCommand("copy");
+      result = document.execCommand('copy');
       textarea.remove();
       // #endif
     },
@@ -296,9 +296,9 @@ export default {
     .price {
       color: red;
     }
-	.remark{
-		word-break: break-all;
-	}
+    .remark {
+      word-break: break-all;
+    }
   }
   .copy_btn {
     border-radius: 20rpx;

+ 46 - 0
pages/wait/index.vue

@@ -0,0 +1,46 @@
+<template>
+  <view class="page">
+    <image :src="imgUrl" mode="widthFix" />
+    <view v-if="!imagePage">即将开放,敬请期待</view>
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      imagePage: false,
+      imgUrl: '',
+    };
+  },
+  onLoad(param) {
+    this.imgUrl = `https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/index/banner_${param.id}.png`;
+    this.imagePage = ['3', '11'].includes(param.id);
+    uni.setNavigationBarTitle({
+      title: param.name,
+    });
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.page {
+  width: 100vw;
+  height: 100vh;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  > image {
+    height: 300rpx;
+    width: 100%;
+  }
+  > view {
+    flex: 1;
+    font-size: 30rpx;
+    color: #999;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+}
+</style>