chengjunhui 6 gün önce
ebeveyn
işleme
2541204472

+ 3 - 32
App.vue

@@ -160,38 +160,9 @@
     /* #endif */
   }
 
-
-
-  // @font-face {
-  //   font-family: "ld";
-  //   src: url("@/static/font/iconfont1.woff2") format("woff2"),
-  //     url("@/static/font/iconfont1.woff") format("woff"),
-  //     url("@/static/font/iconfont1.ttf") format("truetype");
-  // }
-
-  // @font-face {
-  //   font-family: "iconfont2";
-  //   src: url("@/static/font/iconfont2.woff2") format("woff2"),
-  //     url("@/static/font/iconfont2.woff") format("woff"),
-  //     url("@/static/font/iconfont2.ttf") format("truetype");
-  // }
-
-  // @font-face {
-  //   font-family: "iconfont3";
-  //   src: url("@/static/font/iconfont3.woff2") format("woff2"),
-  //     url("@/static/font/iconfont3.woff") format("woff"),
-  //     url("@/static/font/iconfont3.ttf") format("truetype");
-  // }
-
-  // .iconfont2 {
-  //   font-family: "iconfont2";
-  // }
-
-  // .iconfont3 {
-  //   font-family: "iconfont3";
-  // }
-
-
+  view{
+    box-sizing: border-box;
+  }
 
   .u-btn-two {
     width: 100%;

+ 6 - 0
api/shop.js

@@ -1,5 +1,11 @@
 // 查询商家列表
 export const getBusinessList = (params) => uni.$uv.http.get(`/ticket/business/list`, { params });
+// 分页查询商家列表
+export const getBusinessPage = (params) => uni.$uv.http.get(`/ticket/business/page`, { params });
+
+// 分页查询商家分类列表
+export const getBusinessCategoryList = (params) => uni.$uv.http.get(`/ticket/business/category/list`, { params });
+
 // 获取商家详细信息
 export const getBusinessInfo = (data) => uni.$uv.http.post(`/ticket/business/info`, data);
 // 根据id获取商家详细信息

+ 192 - 0
components/RegionSelection/RegionSelection.vue

@@ -0,0 +1,192 @@
+<template>
+  <!-- 地区选择 -->
+  <uv-picker
+    ref="pickerRef"
+    :columns="columns"
+    keyName="name"
+    @confirm="areaConfirm"
+    @change="areaChange"
+  >
+  </uv-picker>
+</template>
+
+<script setup name="RegionSelection">
+import { computed, onMounted, ref, watch } from "vue";
+import { cnareaTreeLbs } from "@/api/index";
+const emit = defineEmits(["confirm"]);
+const props = defineProps({
+  // 地区选择器层级, 默认3级
+  // 1级 省
+  // 2级 市
+  // 3级 区县
+  hierarchy: {
+    type: Number,
+    default: () => 3,
+  },
+});
+const pickerRef = ref(null);
+const columnIndexs = ref([0, 0, 0]);
+const provinceList = ref([]);
+
+const municipalityNames = ["北京", "天津", "上海", "重庆"];
+const isMunicipality = (name) => municipalityNames.includes(String(name || ""));
+
+const getCnareaTreeLbs = () => {
+  cnareaTreeLbs().then((res) => {
+    if (res.code == 200) {
+      provinceList.value = res.data?.children || [];
+      initColumns();
+    }
+  });
+};
+
+const safeHierarchy = computed(() => {
+  const n = Number(props.hierarchy);
+  if (!Number.isFinite(n)) return 3;
+  return Math.min(3, Math.max(1, n));
+});
+
+const selectedProvince = computed(() => {
+  const provinces = provinceList.value || [];
+  const pIndex = columnIndexs.value[0] || 0;
+  return provinces[pIndex] || null;
+});
+
+const selectedCityList = computed(() => {
+  return selectedProvince.value?.children || [];
+});
+
+const selectedMunicipalityCity = computed(() => {
+  if (!selectedProvince.value) return null;
+  if (!isMunicipality(selectedProvince.value.name)) return null;
+  const cities = selectedCityList.value || [];
+  if (cities.length !== 1) return null;
+  return cities[0] || null;
+});
+
+const secondColumnList = computed(() => {
+  if (!selectedProvince.value) return [];
+  if (safeHierarchy.value === 1) return [];
+  if (safeHierarchy.value === 2 && selectedMunicipalityCity.value) {
+    return selectedMunicipalityCity.value.children || [];
+  }
+  return selectedCityList.value || [];
+});
+
+const thirdColumnList = computed(() => {
+  if (safeHierarchy.value !== 3) return [];
+  const p = selectedProvince.value;
+  if (!p) return [];
+  const cities = selectedCityList.value || [];
+  const cIndex = columnIndexs.value[1] || 0;
+  return cities[cIndex]?.children || [];
+});
+
+const initColumns = () => {
+  const pIndex = 0;
+  const cIndex = 0;
+  columnIndexs.value = [pIndex, cIndex, 0];
+  if (pickerRef.value?.setIndexs) {
+    pickerRef.value.setIndexs(
+      columnIndexs.value.slice(0, safeHierarchy.value),
+      true
+    );
+  }
+};
+
+const columns = computed(() => {
+  const provinces = provinceList.value || [];
+  if (safeHierarchy.value === 1) return [provinces];
+  if (safeHierarchy.value === 2) return [provinces, secondColumnList.value];
+  return [provinces, selectedCityList.value || [], thirdColumnList.value];
+});
+
+// 地区选择器改变事件
+const areaChange = (e) => {
+  const { columnIndex, index, indexs } = e || {};
+  if (safeHierarchy.value === 1) return;
+
+  if (columnIndex === 0) {
+    const next = [index || 0, 0, 0];
+    columnIndexs.value = next;
+    pickerRef.value?.setIndexs?.(next.slice(0, safeHierarchy.value), true);
+    return;
+  }
+
+  if (columnIndex === 1) {
+    if (safeHierarchy.value === 2) {
+      const next = [
+        (indexs && indexs[0]) || columnIndexs.value[0] || 0,
+        index || 0,
+        0,
+      ];
+      columnIndexs.value = next;
+      pickerRef.value?.setIndexs?.(next.slice(0, safeHierarchy.value), true);
+      return;
+    }
+    const next = [
+      (indexs && indexs[0]) || columnIndexs.value[0] || 0,
+      index || 0,
+      0,
+    ];
+    columnIndexs.value = next;
+    pickerRef.value?.setIndexs?.(next.slice(0, safeHierarchy.value), true);
+  }
+};
+// 地区选择器确认事件
+const areaConfirm = (e) => {
+  let obj = {
+    provinceName: undefined,
+    provinceCode: undefined,
+    cityName: undefined,
+    cityCode: undefined,
+    areaName: undefined,
+    areaCode: undefined,
+  };
+  const values = e?.value || [];
+  if (values.length > 0) {
+    obj.provinceName = values[0]?.name;
+    obj.provinceCode = values[0]?.id;
+    if (safeHierarchy.value === 2) {
+      if (isMunicipality(values[0]?.name) && selectedMunicipalityCity.value) {
+        obj.cityName = selectedMunicipalityCity.value.name;
+        obj.cityCode = selectedMunicipalityCity.value.id;
+        obj.areaName = values[1]?.name;
+        obj.areaCode = values[1]?.id;
+      } else {
+        obj.cityName = values[1]?.name;
+        obj.cityCode = values[1]?.id;
+      }
+    } else if (safeHierarchy.value >= 3) {
+      obj.cityName = values[1]?.name;
+      obj.cityCode = values[1]?.id;
+      obj.areaName = values[2]?.name;
+      obj.areaCode = values[2]?.id;
+    }
+  }
+  emit("confirm", obj);
+};
+
+const open = () => {
+  initColumns();
+  pickerRef.value?.open?.();
+};
+
+onMounted(() => {
+  getCnareaTreeLbs();
+});
+
+watch(
+  () => props.hierarchy,
+  () => {
+    initColumns();
+  }
+);
+
+defineExpose({
+  open,
+});
+</script>
+
+<style>
+</style>

+ 2 - 2
config/global.config.js

@@ -2,8 +2,8 @@ const CONFIG = {
     staticUrl: 'https://shop.xiaocaituan.com/image', // 所有图片服务器地址 https://shop.xiaocaituan.com/image
     // staticUrl: '/static/image', // 所有图片服务器地址 https://shop.xiaocaituan.com/image
 
-    baseUrl: 'http://192.168.0.152:8300/api', // 后台接、口请求地址
-    // baseUrl: 'http://192.168.0.70:8301/api', // 后台接、口请求地址
+    // baseUrl: 'http://192.168.0.152:8300/api', // 后台接、口请求地址
+    baseUrl: 'http://192.168.0.68:8300/api', // 后台接、口请求地址
 		
     // baseUrl: 'https://shop.xiaocaituan.com/hd-api/api', // 正式接口请求地址
     telRegex: /^1[3-9]\d{9}$/, //手机正则

+ 17 - 8
pages.json

@@ -94,17 +94,18 @@
 			}
 		},
 		{
-			"path": "pages/setup/edit",
+			"path": "pages/tabtar/city",
 			"style": {
-				"navigationBarTitleText": "修改资料",
-				"navigationStyle": "custom"
+				"navigationBarTitleText": "本地生活",
+				"navigationStyle": "custom",
+				"enablePullDownRefresh": true
 			}
 		},
 		{
-			"path": "pages/tabtar/city",
+			"path": "pages/nearbyShop/list",
 			"style": {
-				"navigationBarTitleText": "本地生活",
-				"navigationStyle": "custom"
+				"navigationBarTitleText": "同城商家",
+				"enablePullDownRefresh": true
 			}
 		}
 	],
@@ -306,12 +307,19 @@
 					"style": {
 						"navigationBarTitleText": "物流信息"
 					}
-				},
+				}
 			]
 		},
 		{
 			"root": "pages/set",
 			"pages": [
+				{
+					"path": "edit",
+					"style": {
+						"navigationBarTitleText": "修改资料",
+						"navigationStyle": "custom"
+					}
+				},
 				{
 					"path": "index",
 					"style": {
@@ -444,7 +452,8 @@
 		"navigationBarTextStyle": "black",
 		"navigationBarTitleText": "商城",
 		"navigationBarBackgroundColor": "#ffffff",
-		"backgroundColor": "#ffffff"
+		"backgroundColor": "#F8F8F8",
+		"backgroundColorBottom": "#F4F5F6"
 	},
 	"tabBar": {
 		"color": "#999999",

+ 197 - 0
pages/nearbyShop/components/ShopItem.vue

@@ -0,0 +1,197 @@
+<template>
+  <view class="item" @click.stop="goDetails(v)">
+    <view class="shop-img">
+      <image class="u-skeleton-fillet" :src="v.image" mode="aspectFill"></image>
+    </view>
+    <view class="right">
+      <view class="title u-skeleton-fillet">{{
+        v.businessName || "加载中"
+      }}</view>
+      <view class="score-box u-skeleton-fillet">
+        <view class="score">
+          <rate :value="Math.round(v.average || 0)"></rate>
+        </view>
+        <text class="score-text"
+          >{{ v.average ? Number(v.average).toFixed(2) : "" }}分</text
+        >
+        <text class="ju"
+          >距离:{{ Math.round((v.distance / 1000) * 100) / 100 }}KM</text
+        >
+      </view>
+      <view class="address-box u-skeleton-fillet">
+        <view class="left">
+          <uv-icon name="map" color="#999999" size="34rpx"></uv-icon>
+          <view class="district">{{ v.address || "商户暂无地理位置" }}</view>
+        </view>
+        <view class="goShopping">
+          <text class="iconfont">&#xe642;</text>
+          <text class="text">去逛逛</text>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref } from "vue";
+
+const props = defineProps({
+  v: {
+    type: Object,
+    default: () => {},
+  },
+});
+
+// const emit = defineEmits(["click"]);
+
+const goDetails = (v) => {
+  uni.navigateTo({
+    url: "/pages/shop/index?businessId=" + v.businessId,
+  });
+  // emit("click", v);
+};
+</script>
+
+<style scoped lang="scss">
+.item {
+  display: flex;
+  align-items: center;
+  padding: 25rpx 0;
+  // border-bottom: 1rpx solid #e6e6e6;
+
+  .shop-img {
+    width: 162rpx;
+    height: 158rpx;
+    margin-right: 40rpx;
+    border-radius: 10rpx;
+    overflow: hidden;
+    flex-shrink: 0;
+
+    image {
+      width: 100%;
+      height: 100%;
+    }
+  }
+
+  .right {
+    flex: 1;
+    width: 0;
+
+    .score-box,
+    .address-box,
+    .location2-box {
+      display: flex;
+      align-items: center;
+      font-size: 24rpx;
+      font-family: PingFang SC, PingFang SC-Regular;
+      font-weight: 400;
+    }
+
+    .location1,
+    .location2 {
+      width: 20rpx;
+      height: 27rpx;
+      flex-shrink: 0;
+      margin-right: 9rpx;
+    }
+
+    .light-start,
+    .startt {
+      width: 30rpx;
+      height: 30rpx;
+      margin-right: 12rpx;
+    }
+
+    .title {
+      margin-bottom: 18rpx;
+      font-size: 28rpx;
+      font-family: PingFang SC, PingFang SC-Regular;
+      color: #1a1a1a;
+    }
+
+    .score-box {
+      display: flex;
+      align-items: normal;
+      margin-bottom: 10rpx;
+      font-family: PingFang SC, PingFang SC-Semibold;
+      color: #333333;
+
+      .score {
+        flex-shrink: 0;
+      }
+
+      .score-text {
+        font-size: 24rpx;
+        font-family: PingFang SC, PingFang SC-Medium;
+        font-weight: 500;
+        text-align: left;
+        color: #333333;
+        flex-shrink: 0;
+      }
+
+      .ju {
+        margin-left: 23rpx;
+        font-size: 24rpx;
+        color: #808080;
+        text-align: left;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+    }
+
+    .address-box {
+      // margin-bottom: 10rpx;
+      font-family: PingFang SC;
+      color: #666666;
+      justify-content: space-between;
+
+      .left {
+        flex: 1;
+        width: 0;
+        display: flex;
+        align-items: center;
+        font-size: 24rpx;
+        font-family: PingFang SC, PingFang SC-Regular;
+        font-weight: 400;
+        text-align: left;
+        color: #333333;
+      }
+
+      .goShopping {
+        display: flex;
+        align-items: center;
+        font-size: 40rpx;
+        color: #fa6138;
+        flex-shrink: 0;
+
+        .text {
+          font-size: 24rpx;
+          font-family: PingFang SC, PingFang SC-Medium;
+          font-weight: 500;
+          text-align: left;
+          color: #666666;
+        }
+      }
+
+      .district {
+        color: #1a1a1a;
+        margin-right: 40rpx;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+    }
+
+    .location2-box {
+      color: #333333;
+
+      view {
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+    }
+  }
+}
+</style>

+ 332 - 0
pages/nearbyShop/list.vue

@@ -0,0 +1,332 @@
+<template>
+  <view>
+    <view class="top-box">
+      <view class="top-nav">
+        <view class="city-text" @click="regionSelectionRef.open()">
+          <uv-icon name="map" color="#999999" size="34rpx"></uv-icon>
+          <view>{{ cityName }}</view>
+        </view>
+        <view class="searchBox">
+          <image
+            src="/static/image/order/icon_search.png"
+            mode="widthFix"
+          ></image>
+          <input
+            v-model="param.keyword"
+            type="text"
+            @confirm="search"
+            placeholder-style="color:#B3B3B3"
+            placeholder="请输入关键字"
+            @input="search"
+          />
+        </view>
+      </view>
+      <view class="tabsBox">
+        <view class="type-box">
+          <view class="item" @click="show = true">
+            <view>{{
+              selectIndex === null ? "全部分类" : selector[selectIndex].name
+            }}</view>
+            <uv-icon name="arrow-down" color="#4d4d4d" size="26rpx"></uv-icon>
+          </view>
+          <view
+            class="item"
+            v-for="(v, i) in typeList"
+            :key="i"
+            :class="{ activeCls: tabCurrent == i }"
+            @click="tabsChange2(i)"
+          >
+            <view>{{ v.name }}</view>
+          </view>
+        </view>
+      </view>
+    </view>
+    <view :style="{ height: placeholderH + 'px' }"></view>
+    <view class="shopListBox" v-if="RowsList.length > 0">
+      <!-- 附近门店 -->
+      <ShopItem
+        v-for="(v, index) in RowsList"
+        :key="v.businessId"
+        :v="v"
+      />
+    </view>
+    <view>
+      <loadMore v-if="RowsList.length > 0" :status="LoadStatus"></loadMore>
+      <noData v-if="RowsList.length <= 0" :config="{ top: 2 }"></noData>
+    </view>
+
+    <!-- 地区选择 -->
+    <RegionSelection
+      ref="regionSelectionRef"
+      :hierarchy="2"
+      @confirm="addressConfirm"
+    />
+    <uv-picker
+      mode="selector"
+      v-model="show"
+      :range="selector"
+      range-key="name"
+      :default-selector="[sIndex]"
+      @confirm="confirmSelect"
+    ></uv-picker>
+  </view>
+</template>
+
+<script setup>
+import { computed, getCurrentInstance, nextTick, reactive, ref } from "vue";
+import { onLoad, onPullDownRefresh, onShow } from "@dcloudio/uni-app";
+import { getBusinessPage, getBusinessCategoryList } from "@/api/shop.js";
+import { usePageData } from "@/hooks/usePageData.ts";
+
+import ShopItem from "./components/ShopItem.vue";
+const regionSelectionRef = ref(null);
+const { RowsList, LoadStatus, initData } = usePageData(getBusinessPage);
+
+const instance = getCurrentInstance();
+
+const statusBarHeight = ref(uni.getSystemInfoSync().statusBarHeight || 0);
+const sticky = computed(() => statusBarHeight.value + 44);
+const placeholderH = ref(0);
+
+const cityName = ref("武汉市");
+const sIndex = ref(0);
+const param = reactive({});
+
+const tabCurrent = ref(0);
+const typeList = ref([
+  { name: "距离优先", order: "distance" },
+  { name: "评分优先", order: "average" },
+]);
+const show = ref(false);
+const selector = ref([]);
+const selectIndex = ref(null);
+
+const getRect = (selectorStr) =>
+  new Promise((resolve) => {
+    const query = uni.createSelectorQuery();
+    const ctx = instance?.proxy || undefined;
+    if (ctx) query.in(ctx);
+    query
+      .select(selectorStr)
+      .boundingClientRect((res) => resolve(res || {}))
+      .exec();
+  });
+
+const tabsChange2 = (index) => {
+  tabCurrent.value = index;
+  param.order = typeList.value[index]?.order || "distance";
+  console.log(param);
+  //   initData(param);
+};
+
+const confirmSelect = (e) => {
+  const idx = e?.[0] ?? 0;
+  selectIndex.value = idx;
+  sIndex.value = idx;
+  initData(param);
+};
+
+// 地区选择确认
+const addressConfirm = (e) => {
+  const picked = e.areaName || e.cityName || e.provinceName;
+  cityName.value = picked || cityName.value;
+  Object.assign(param, { ...e });
+  initData(param);
+};
+
+const getTppe = async (id) => {
+  await getBusinessCategoryList().then((res) => {
+    if (res && res.code == 200) {
+      selector.value = [{ name: "全部分类", id: "" }, ...(res.data || [])];
+      if (id) {
+        selector.value.forEach((v, i) => {
+          if (String(v.id) === String(id)) selectIndex.value = i;
+        });
+      }
+    }
+  });
+};
+
+// 获取当前位置
+const getLoca = async () => {
+  await uni.getLocation({
+    type: "gcj02",
+    geocode: true,
+    success: (res) => {
+      param.longitude = res.longitude;
+      param.latitude = res.latitude;
+    },
+    fail: () => {},
+  });
+};
+
+const searchTimer = ref(null);
+const search = () => {
+  if (searchTimer.value) clearTimeout(searchTimer.value);
+  searchTimer.value = setTimeout(() => {
+    initData(param);
+  }, 1000);
+};
+
+const initPage = async (options = {}) => {
+  if (options?.id) {
+    param.businessCategoryId = options.id;
+  }
+  if (options?.cityName) {
+    cityName.value = options.cityName;
+  }
+  if (options?.cityCode) {
+    param.cityCode = options.cityCode;
+  }
+  try {
+    await getTppe(param.businessCategoryId);
+    await getLoca();
+  } catch (error) {
+    console.log(error);
+  }
+  initData(param);
+};
+
+onLoad((options) => {
+  initPage(options || {});
+});
+
+onShow(async () => {
+  await nextTick();
+  const rect = await getRect(".top-box");
+  placeholderH.value = rect?.height || 0;
+});
+
+onPullDownRefresh(() => {
+  //   Promise.allSettled([getLoca(), initData(param)]).finally(() => {
+  //     uni.stopPullDownRefresh();
+  //   });
+});
+</script>
+
+<style lang="scss" scoped>
+.top-box {
+  width: 750rpx;
+  position: fixed;
+  background-color: #fff;
+  z-index: 3;
+}
+
+.top-nav {
+  height: 120rpx;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 0 30rpx;
+  background-color: #fff;
+}
+
+.city-text {
+  margin-right: 20rpx;
+  font-size: 30rpx;
+  font-family: PingFang SC, PingFang SC-Regular;
+  font-weight: 400;
+  text-align: center;
+  color: #666666;
+  display: flex;
+  align-items: center;
+
+  view {
+    max-width: 100rpx;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+  }
+
+  image {
+    width: 26rpx;
+    height: 36rpx;
+    margin-right: 10rpx;
+    vertical-align: middle;
+  }
+}
+
+.searchBox {
+  //   width: 560rpx;
+  flex: 1;
+  display: flex;
+  padding: 10rpx 27rpx;
+  border: 1rpx solid #cccccc;
+  border-radius: 10rpx;
+  display: flex;
+  align-items: center;
+
+  image {
+    width: 35rpx;
+    height: 35rpx;
+    margin-right: 15rpx;
+    flex-shrink: 0;
+  }
+
+  input {
+    text-align: left;
+  }
+}
+
+.tabsBox {
+  width: 100%;
+  background-color: #fff;
+
+  .tabsBox_tabs {
+    padding: 0 10rpx;
+
+    ::v-deep .u-tab-item {
+      font-weight: 700;
+    }
+  }
+}
+
+.type-box {
+  display: flex;
+  align-items: center;
+  padding: 0 40rpx 20rpx;
+  justify-content: space-between;
+
+  .item {
+    display: flex;
+    font-size: 28rpx;
+    font-family: PingFang SC, PingFang SC-Regular;
+    font-weight: 400;
+    color: #4d4d4d;
+    align-items: center;
+    color: #4d4d4d;
+
+    &:first-child {
+      min-width: 142rpx;
+    }
+
+    image {
+      width: 14rpx;
+      height: 10rpx;
+      margin-left: 10rpx;
+      vertical-align: middle;
+    }
+  }
+
+  .activeCls {
+    color: #fa6138;
+  }
+
+  .item2 {
+    margin-left: 100rpx;
+    padding-top: 20rpx;
+  }
+}
+
+.content-box {
+  padding: 0 30rpx;
+}
+
+.shopListBox {
+  padding: 0 30rpx;
+
+  .shopListBox_item {
+    margin-top: 30rpx;
+  }
+}
+</style>

pages/setup/edit.vue → pages/set/edit.vue


+ 1 - 1
pages/set/index.vue

@@ -166,7 +166,7 @@ const handleOperation = (item) => {
       break;
     case "userDetails":
       uni.navigateTo({
-        url: "/pages/setup/edit",
+        url: "/pages/set/edit",
       });
       break;
     default:

+ 2 - 2
pages/shop/components/SeckillGood.vue

@@ -97,7 +97,7 @@ const onFinish = () => {
 };
 
 // 一维数组转二维数组
-const oneArrToTwoArr = (data) => {
+const oneArrToTwoArr = (data = []) => {
   let newData = [];
   let zyf = 4; //一维数组转二维数组长度(此处是二维数组每一个长度控制)
   for (let i = 0; i < Math.ceil(data.length / zyf); i++) {
@@ -122,7 +122,7 @@ const seckillActivityProductFlash = () => {
   }).then((res) => {
     // console.log(res);
     if (res.code == 200) {
-      currSeckill.value = oneArrToTwoArr(res.data.list || []);
+      currSeckill.value = res.data.list ? oneArrToTwoArr(res.data.list || []) : [];
       currTime.value = res.data.startHour;
       // finishTime.value = res.data.finishTime;
       if (res.data.finishTime) {

+ 87 - 398
pages/tabtar/city.vue

@@ -1,63 +1,55 @@
 <template>
   <view class="container">
-    <!-- <navbar id="navbar" :config="config" backColor="#888888"></navbar> -->
-    <uv-navbar
-      title="本地生活"
-      leftIconSize="0"
-      :border="false"
-      bgColor="#fbcd17"
-      titleStyle="font-weight: 700;color: #1A1A1A;"
-    ></uv-navbar>
     <uv-sticky>
+      <uv-navbar
+        title="本地生活"
+        leftIconSize="0"
+        :border="false"
+        bgColor="#fbcd17"
+        titleStyle="font-weight: 700;color: #1A1A1A;"
+        placeholder
+      ></uv-navbar>
       <view class="search-top">
-        <view class="city-text" @click="addressShow = true">
-          <!-- <image mode="widthFix" src="/static/shop/location-icon.png"></image> -->
-          <uv-icon name="map" color="#000000" size="34"></uv-icon>
+        <view class="city-text" @click="regionSelectionRef.open()">
+          <uv-icon name="map" color="#000000" size="28rpx"></uv-icon>
           <view>{{ cityName }}</view>
-          <uv-icon name="arrow-right" color="#000000" size="30"></uv-icon>
+          <uv-icon name="arrow-right" color="#000000" size="30rpx"></uv-icon>
         </view>
         <view class="searchBox">
           <uv-search
-            v-model="param.shop_name"
+            v-model="param.keyword"
             shape="round"
             :clearabled="false"
             :showAction="false"
-            height="80"
+            height="80rpx"
             bg-color="#f7f7f7"
             border-color="#D9D9D9"
-            placeholder-color="#CCCCCC"
-            search-icon="/static/shop/search-icon.png"
-            :customStyle="searchCustomStyle"
-            :boxStyle="searchBoxStyle"
-            :inputStyle="searchInputStyle"
-            @search="onSearch"
-            @custom="onSearch"
+            laceholder-color="#CCCCCC"
+            search-icon="/static/image/order/icon_search.png"
+            @search="$uv.throttle(search, 1000)"
+            @custom="$uv.throttle(search, 1000)"
           >
             <template #suffix>
-              <view class="search-action" @tap.stop="onSearch">搜索</view>
+              <view class="search-action">搜索</view>
             </template>
           </uv-search>
         </view>
       </view>
     </uv-sticky>
-    <!-- <view style="height: 110rpx;"></view> -->
+    <!-- <view style="height: 86rpx"></view> -->
     <view class="u-skeleton">
       <view class="banner" v-if="bannerList.length > 0 || skeletonShow">
         <!-- <image src="/static/shop/banner.png" mode="aspectFill"></image> -->
         <uv-swiper
           class="u-skeleton-fillet"
           :list="bannerList"
-          name="cover"
-          height="360"
-          :mode="bannerList.length > 1 ? 'round' : 'none'"
-          bg-color="transparent"
-          @click="bannerClick"
+          keyName="image"
+          height="360rpx"
+          :indicatorMode="bannerList.length > 1 ? 'round' : 'none'"
+          bgColor="transparent"
         ></uv-swiper>
       </view>
-      <view
-        class="menu"
-        v-if="iconList.length > 0 || skeletonShow"
-      >
+      <view class="menu" v-if="iconList.length > 0 || skeletonShow">
         <swiper
           class="swiper u-skeleton-fillet"
           :indicator-dots="true"
@@ -81,117 +73,52 @@
         </swiper>
       </view>
       <view class="con-box">
-        <!-- <uv-section class="u-skeleton-fillet" title="附近门店" font-size="36" :bold="true" color="#333333" :show-line="false"
-          sub-title="查看更多" sub-color="#333333" @click="goShop()">
-        </uv-section> -->
         <view class="store-bg">
           <image class="store-bg-image" src="/static/store.png" mode="">
           </image>
           <view class="store-bg-btn" @click="goShop()">
             <text class="text">查看更多</text>
-            <uv-icon name="arrow-right" color="#fbbd1c" size="24"></uv-icon>
+            <uv-icon name="arrow-right" color="#fbbd1c" size="24rpx"></uv-icon>
           </view>
         </view>
         <view class="items">
-          <view
-            class="item"
-            v-for="(v, index) in listData"
-            :key="v.shop_id"
-            @click="goDetails(v)"
-          >
-            <view class="shop-img">
-              <image
-                class="u-skeleton-fillet"
-                :src="v.logo"
-                mode="aspectFill"
-              ></image>
-            </view>
-            <view class="right">
-              <view class="title u-skeleton-fillet">{{
-                v.shop_name || "加载中"
-              }}</view>
-              <view class="score-box u-skeleton-fillet">
-                <view class="score">
-                  <rate :value="Math.round(v.average || 0)"></rate>
-                </view>
-                <text class="score-text"
-                  >{{ v.average ? v.average.toFixed(2) : "" }}分</text
-                >
-                <text class="ju"
-                  >距离:{{
-                    Math.round((v.distance / 1000) * 100) / 100
-                  }}KM</text
-                >
-              </view>
-              <view class="address-box u-skeleton-fillet">
-                <view class="left">
-                  <!-- <image class="location1" :src="$getImgPath('/static/shop/location-icon.png')" mode="widthFix">
-                  </image> -->
-                  <uv-icon name="map" color="#999999" size="34"></uv-icon>
-                  <view class="district">{{
-                    v.map_punctuation || "商户暂无地理位置"
-                  }}</view>
-                </view>
-                <view class="goShopping">
-                  <text class="iconfont3">&#xe787;</text>
-                  <text class="text">去逛逛</text>
-                </view>
-              </view>
-              <!-- <view class="location2-box">
-              <image class="location2" src="/static/convenienceService/location2.png" mode="widthFix">
-              </image>
-              <view>{{v.map_punctuation}}&gt;</view>
-            </view> -->
-            </view>
-          </view>
+          <ShopItem v-for="(v, index) in RowsList" :key="v.businessId" :v="v" />
         </view>
       </view>
       <view>
-        <noData v-if="listData.length <= 0" :config="{ top: 2 }"></noData>
+        <loadMore v-if="RowsList.length > 0" :status="LoadStatus"></loadMore>
+        <noData v-if="RowsList.length <= 0" :config="{ top: 2 }"></noData>
       </view>
-      <!-- <uv-loadmore :status="loadStatus" /> -->
       <uv-skeleton
         :loading="skeletonShow"
         :animation="true"
         bgColor="#FFF"
       ></uv-skeleton>
     </view>
-    <!-- 选择地区 -->
-    <uv-select
-      v-model="addressShow"
-      mode="mutil-column-auto"
-      :list="cityTree"
+
+    <!-- 地区选择 -->
+    <RegionSelection
+      ref="regionSelectionRef"
+      :hierarchy="2"
       @confirm="addressConfirm"
-    >
-    </uv-select>
-    <!-- <entrepreneurship-zone-tabbar :current="2"></entrepreneurship-zone-tabbar> -->
+    />
   </view>
 </template>
 
 <script setup>
 import { computed, reactive, ref } from "vue";
 import { onLoad, onPullDownRefresh } from "@dcloudio/uni-app";
-import throttle from "@/uni_modules/uv-ui-tools/libs/function/throttle.js";
-import rate from "@/components/rate/rate.vue";
-import noData from "@/components/noData/noData.vue";
-
-const $http = uni.$http || {
-  get: (url, params) => uni.$uv.http.get(url, { params }),
-  post: (url, data) => uni.$uv.http.post(url, data),
-};
-const $mUtil = uni.$mUtil;
+import { getAdList_Api, getQuickLinkList_Api } from "@/api/index.js";
+import { getBusinessPage } from "@/api/shop.js";
+import { usePageData } from "@/hooks/usePageData.ts";
+import ShopItem from "../nearbyShop/components/ShopItem.vue";
 
-const listData = ref([]);
+const { RowsList, LoadStatus, initData } = usePageData(getBusinessPage);
+const regionSelectionRef = ref(null);
 const cityName = ref("洪山区");
-const addressShow = ref(false);
 const param = reactive({
-  shop_name: "",
-  lon: "",
-  lat: "",
-  area_code: "",
-  address: "",
+  keyword: "",
 });
-const cityTree = ref([]);
 const iconList = ref([]);
 const bannerList = ref([]);
 const current = ref(0);
@@ -202,12 +129,6 @@ const menuHeight = computed(() => {
   return items.length > 5 ? "350rpx" : "150rpx";
 });
 
-const chunk = (arr, size) => {
-  const res = [];
-  for (let i = 0; i < arr.length; i += size) res.push(arr.slice(i, i + size));
-  return res;
-};
-
 const goShop = (item = {}) => {
   uni.navigateTo({
     url:
@@ -215,45 +136,33 @@ const goShop = (item = {}) => {
       (item.id || "") +
       "&cityName=" +
       cityName.value +
-      "&address=" +
-      (param.address || "") +
-      "&area_code=" +
-      (param.area_code || ""),
+      "&cityCode=" +
+      (param.cityCode || ""),
   });
 };
-
+// 获取banner广告
 const getBanner = () => {
-  return $http.get("/ad/ad/getByCode/localMerchant-banner").then((res) => {
+  getAdList_Api("local_life_banner").then((res) => {
     if (res && res.code == 200) {
-      bannerList.value = res.list || [];
+      bannerList.value = res.data || [];
     } else {
       bannerList.value = [];
     }
   });
 };
 
-const bannerClick = (index) => {
-  const item = bannerList.value[index];
-  if (!item) return;
-  $mUtil?.imgLink?.(item);
-};
-
-const getCitys = () => {
-  return $http.get("/cnarea/tree-lbs").then((res) => {
-    if (res && res.code == 200) {
-      const list = res.tree?.children || [];
-      list.forEach((v) => {
-        if (!v.children || v.children.length <= 0) v.children = [{}];
-      });
-      cityTree.value = list;
-    }
-  });
+// 分组
+const chunk = (arr, size) => {
+  const res = [];
+  for (let i = 0; i < arr.length; i += size) res.push(arr.slice(i, i + size));
+  return res;
 };
 
+// 获取分类列表
 const getTypeList = () => {
-  return $http.get("/union/business/classify/list").then((res) => {
+  getQuickLinkList_Api("local_life").then((res) => {
     if (res && res.code == 200) {
-      const list = res.list || [];
+      const list = res.data || [];
       iconList.value = chunk(list, 10);
       current.value = 0;
     } else {
@@ -262,6 +171,7 @@ const getTypeList = () => {
   });
 };
 
+// 获取当前位置
 const getLocation = () =>
   new Promise((resolve, reject) => {
     uni.getLocation({
@@ -272,82 +182,38 @@ const getLocation = () =>
     });
   });
 
-const getList = () => {
-  uni.showLoading({ title: "努力加载中...", mask: true });
-  return $http
-    .get("/service/goods/nearby", { ...param })
-    .then((res) => {
-      if (res && res.code == 200) {
-        listData.value = res.list || [];
-      } else {
-        listData.value = [];
-      }
-    })
-    .finally(() => {
-      uni.hideLoading();
-    });
-};
-
-const getLoca = async () => {
-  try {
-    const res = await getLocation();
-    param.lon = res.longitude;
-    param.lat = res.latitude;
-  } catch (e) {
-    param.lon = "";
-    param.lat = "";
-  }
-  await getList();
-};
-
 const swiperChange = (e) => {
   if (!e) return;
   current.value = e.detail.current;
 };
-
-const addressConfirm = (e) => {
-  const picked = [...(e || [])].reverse().find((i) => i && i.value) || e?.[0];
-  cityName.value = picked?.label || cityName.value;
-  param.area_code = picked?.value || "";
-  param.address = "";
-  getList();
+// 地区选择确认
+const addressConfirm = (e = {}) => {
+  // console.log(e);
+  const picked = e.areaName || e.cityName || e.provinceName;
+  cityName.value = picked || cityName.value;
+  Object.assign(param, { ...e });
+  initData(param);
 };
 
-const goDetails = (v) => {
-  uni.navigateTo({
-    url: "/pages/convenienceService/shopDetails?shopId=" + v.shop_id,
+onLoad(() => {
+  getBanner();
+  getTypeList();
+  getLocation().then((res) => {
+    console.log("当前位置", res);
+    param.longitude = res.longitude;
+    param.latitude = res.latitude;
+    initData({
+      latitude: res.latitude,
+      longitude: res.longitude,
+    });
   });
-};
-
-const search = () => getList();
-const onSearch = throttle(search, 1000);
-
-const searchCustomStyle = {
-  position: "relative",
-};
-const searchBoxStyle = {
-  paddingLeft: "27rpx",
-  borderRadius: "36rpx",
-};
-const searchInputStyle = {
-  marginLeft: "22rpx",
-  paddingRight: "20rpx",
-};
-
-const initPage = async () => {
-  skeletonShow.value = true;
-  await Promise.allSettled([getCitys(), getTypeList(), getBanner(), getLoca()]);
   skeletonShow.value = false;
-};
-
-onLoad(() => {
-  initPage();
+  // initData();
 });
 
 onPullDownRefresh(() => {
-  Promise.allSettled([getTypeList(), getBanner(), getLoca()]).finally(() => {
-    uni.stopPullDownRefresh();
-  });
+  getBanner();
+  getTypeList();
 });
 </script>
 
@@ -360,14 +226,15 @@ onPullDownRefresh(() => {
     // display: flex;
     // justify-content: space-between;
     // align-items: center;
-    padding: 0 30rpx 26rpx 30rpx;
+    padding: 10rpx 30rpx 26rpx 30rpx;
     background-color: #fbcd17;
     // z-index: 3;
+    box-sizing: border-box;
   }
 
   .city-text {
     margin-right: 12rpx;
-    font-size: 30rpx;
+    font-size: 28rpx;
     font-family: PingFang SC, PingFang SC-Regular;
     font-weight: 400;
     text-align: center;
@@ -394,8 +261,9 @@ onPullDownRefresh(() => {
   .searchBox {
     position: relative;
     flex: 1;
+    box-sizing: border-box;
     // width: 580rpx;
-    height: 80rpx;
+    // height: 80rpx;
 
     image {
       width: 35rpx;
@@ -414,56 +282,17 @@ onPullDownRefresh(() => {
       display: flex;
       align-items: center;
       justify-content: center;
-      margin-right: 5rpx;
-    }
-  }
-}
-
-.navbar {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 90rpx;
-  text-align: center;
-  line-height: 90rpx;
-  z-index: 9;
-  background-color: #fff;
-
-  .title {
-    font-size: 36rpx;
-    font-family: PingFang SC, PingFang SC-Regular;
-    font-weight: 400;
-    text-align: center;
-    color: #1a1a1a;
-  }
-
-  .left {
-    position: absolute;
-    top: 50%;
-    left: 30rpx;
-    display: flex;
-    align-items: center;
-    font-size: 30rpx;
-    font-family: PingFang SC, PingFang SC-Regular;
-    font-weight: 400;
-    text-align: center;
-    color: #1a1a1a;
-    transform: translateY(-50%);
-
-    .city-icon {
-      width: 19rpx;
-      height: 12rpx;
-      margin-left: 5rpx;
+      margin-right: 0rpx;
     }
   }
 }
 
 .banner {
   width: 100%;
-  height: 350rpx;
+  height: 360rpx;
   // padding: 0rpx 30rpx 0;
   margin-bottom: 20rpx;
+  box-sizing: border-box;
 
   image {
     width: 100%;
@@ -471,7 +300,8 @@ onPullDownRefresh(() => {
   }
 
   ::v-deep uni-swiper {
-    height: 350rpx !important;
+    height: 360rpx !important;
+    box-sizing: border-box;
   }
 }
 
@@ -552,7 +382,7 @@ onPullDownRefresh(() => {
     justify-content: space-between;
     padding: 30rpx;
     box-sizing: border-box;
-    background: url("/static/store_bg.png") no-repeat;
+    // background: url("/static/store_bg.png") no-repeat;
     background-size: 100% 117rpx;
 
     .store-bg-image {
@@ -583,147 +413,6 @@ onPullDownRefresh(() => {
 
   .items {
     padding: 0 30rpx;
-    .item {
-      display: flex;
-      align-items: center;
-      padding: 25rpx 0;
-      // border-bottom: 1rpx solid #e6e6e6;
-
-      .shop-img {
-        width: 162rpx;
-        height: 158rpx;
-        margin-right: 40rpx;
-        border-radius: 10rpx;
-        overflow: hidden;
-        flex-shrink: 0;
-
-        image {
-          width: 100%;
-          height: 100%;
-        }
-      }
-
-      .right {
-        flex: 1;
-        width: 0;
-
-        .score-box,
-        .address-box,
-        .location2-box {
-          display: flex;
-          align-items: center;
-          font-size: 24rpx;
-          font-family: PingFang SC, PingFang SC-Regular;
-          font-weight: 400;
-        }
-
-        .location1,
-        .location2 {
-          width: 20rpx;
-          height: 27rpx;
-          flex-shrink: 0;
-          margin-right: 9rpx;
-        }
-
-        .light-start,
-        .startt {
-          width: 30rpx;
-          height: 30rpx;
-          margin-right: 12rpx;
-        }
-
-        .title {
-          margin-bottom: 18rpx;
-          font-size: 28rpx;
-          font-family: PingFang SC, PingFang SC-Regular;
-          color: #1a1a1a;
-        }
-
-        .score-box {
-          display: flex;
-          align-items: normal;
-          margin-bottom: 10rpx;
-          font-family: PingFang SC, PingFang SC-Semibold;
-          color: #333333;
-
-          .score {
-            flex-shrink: 0;
-          }
-
-          .score-text {
-            font-size: 24rpx;
-            font-family: PingFang SC, PingFang SC-Medium;
-            font-weight: 500;
-            text-align: left;
-            color: #333333;
-            flex-shrink: 0;
-          }
-
-          .ju {
-            margin-left: 23rpx;
-            font-size: 24rpx;
-            color: #808080;
-            text-align: left;
-            overflow: hidden;
-            text-overflow: ellipsis;
-            white-space: nowrap;
-          }
-        }
-
-        .address-box {
-          // margin-bottom: 10rpx;
-          font-family: PingFang SC;
-          color: #666666;
-          justify-content: space-between;
-
-          .left {
-            flex: 1;
-            width: 0;
-            display: flex;
-            align-items: center;
-            font-size: 24rpx;
-            font-family: PingFang SC, PingFang SC-Regular;
-            font-weight: 400;
-            text-align: left;
-            color: #333333;
-          }
-
-          .goShopping {
-            display: flex;
-            align-items: center;
-            font-size: 40rpx;
-            color: #fa6138;
-            flex-shrink: 0;
-
-            .text {
-              font-size: 24rpx;
-              font-family: PingFang SC, PingFang SC-Medium;
-              font-weight: 500;
-              text-align: left;
-              color: #666666;
-            }
-          }
-
-          .district {
-            color: #1a1a1a;
-            margin-right: 40rpx;
-            overflow: hidden;
-            text-overflow: ellipsis;
-            white-space: nowrap;
-          }
-        }
-
-        .location2-box {
-          color: #333333;
-
-          view {
-            overflow: hidden;
-            text-overflow: ellipsis;
-            white-space: nowrap;
-          }
-        }
-      }
-    }
   }
 }
 </style>

+ 179 - 0
pages/tabtar/components/CartGuessYouLike.vue

@@ -0,0 +1,179 @@
+<template>
+  <!-- 猜你喜欢 -->
+  <view
+    class="guess"
+    :style="{
+      padding: RowsList && RowsList.length
+        ? '0 30rpx 150rpx 30rpx'
+        : '100rpx 30rpx 0 30rpx',
+    }"
+  >
+    <view class="guess-top">
+      <image class="guess-icon" src="/static/image/common/heart.png" mode=""></image>
+      <view class="guess-left">你可能还喜欢</view>
+    </view>
+    <view class="guess-item" v-if="RowsList && RowsList.length > 0">
+      <view
+        class="item"
+        @click="goProductDetails('/pages/product/goods/goods?id=' + item.id)"
+        v-for="(item, index) in RowsList"
+        :key="index"
+      >
+        <image
+          v-if="item && item.cover"
+          :src="item.cover"
+          mode="aspectFill"
+        ></image>
+        <view style="padding-bottom: 40rpx">
+          <view class="name" style="flex: 1">{{ item.title }}</view>
+          <view class="number">
+            <view class="number-red">
+              <rich-text
+                :nodes="$mUtil.priceBigSmall(item.min_sale_price)"
+              ></rich-text>
+            </view>
+            <view class="number-grey">¥{{ item.max_market_price }}</view>
+          </view>
+        </view>
+      </view>
+    </view>
+    <noData v-else :config="{ top: 1, content: '暂无商品~' }"></noData>
+    <loadMore v-if="RowsList.length > 0" :status="status"></loadMore>
+  </view>
+</template>
+
+<script setup>
+import { ref, onMounted } from "vue";
+import { usePageData } from "@/hooks/usePageData.ts";
+const { RowsList, LoadStatus, initData } = usePageData();
+
+onMounted(() => {
+  initData();
+});
+
+defineExpose({
+  initData,
+});
+</script>
+
+<style scoped lang="scss">
+.guess {
+  // padding: 100rpx 30rpx 0 30rpx;
+
+  .guess-item {
+    display: flex;
+    // justify-content: space-around;
+    flex-wrap: wrap;
+
+    .item {
+      margin-bottom: 36rpx;
+      background-color: #ffffff;
+      overflow: hidden;
+      display: flex;
+      flex-direction: column;
+      border-radius: 20rpx 20rpx 0 0;
+      box-shadow: 0 0 40rpx rgba(0, 0, 0, 0.1);
+
+      image {
+        width: 336rpx;
+        height: 336rpx;
+        border-radius: 18rpx;
+      }
+
+      .name {
+        margin: 6rpx 20rpx;
+        width: 296rpx;
+        height: 70rpx;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        display: -webkit-box;
+        -webkit-line-clamp: 2;
+        -webkit-box-orient: vertical;
+        word-wrap: break-word;
+        word-break: break-all;
+        white-space: normal !important;
+      }
+
+      .tag-box {
+        margin: 10rpx 20rpx 0 20rpx;
+
+        .tag1 {
+          width: 69rpx;
+          height: 30rpx;
+        }
+
+        .tag2 {
+          width: 116rpx;
+          height: 30rpx;
+          margin-left: 10rpx;
+        }
+      }
+
+      .number {
+        display: flex;
+        align-items: flex-end;
+        // padding-bottom: 40rpx;
+        margin: 0 20rpx 0 20rpx;
+
+        .number-red {
+          color: #ff6600;
+          font-size: 36rpx;
+          font-weight: 700;
+
+          text {
+            font-size: 36rpx;
+            font-weight: Bold;
+          }
+        }
+
+        .number-grey {
+          color: #999999;
+          font-size: 22rpx;
+          font-weight: 400;
+          text-decoration: line-through;
+          margin-left: 16rpx;
+          padding-bottom: 4rpx;
+        }
+      }
+    }
+
+    .item:nth-child(2n) {
+      margin-left: 18rpx;
+    }
+  }
+
+  .guess-top {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-bottom: 24rpx;
+
+    .guess-icon {
+      width: 35rpx;
+      height: 35rpx;
+      margin-right: 10rpx;
+    }
+
+    .guess-left {
+      font-size: 30rpx;
+      color: #1a1a1a;
+      font-weight: Bold;
+      line-height: 30rpx;
+    }
+
+    .guess-line {
+      width: 1rpx;
+      height: 32rpx;
+      background-color: #707070;
+      margin: 0 16rpx;
+    }
+
+    .guess-right {
+      font-size: 24rpx;
+      color: #666666;
+      font-weight: Regular;
+      line-height: 24rpx;
+    }
+  }
+}
+</style>

+ 41 - 42
pages/tabtar/goodsType.vue

@@ -1,17 +1,27 @@
 <template>
-  <view>
-    <uv-navbar title="分类" placeholder leftIcon=""></uv-navbar>
-    <view class="searchBox" @click="goSearch()">
-      <view>
-        <text class="iconfont">&#xe7a6;</text>
-        <text class="searchBox_inp">请输入搜索关键字</text>
-        <text class="searchBox_btn">搜索</text>
+  <view class="goodsType">
+    <uv-navbar
+      title="商品分类"
+      placeholder
+      leftIcon=""
+      bgColor="rgba(0,0,0,0)"
+    ></uv-navbar>
+    <view
+      class="topsearch u-p30 u-flex-center-sb"
+      style="paddingtop: 20rpx"
+      @click="goSearch()"
+    >
+      <view class="u-flex1 u-flex-center leftbox">
+        <text class="iconfont u-font30 u-666 u-ml30">&#xe618;</text>
+        <text class="u-font22 u-CCC u-ml20">请输入搜索关键字</text>
+        <text class="search-btn">搜索</text>
       </view>
+      <!-- <text class="u-font28 u-1A1A1A u-ml30">搜索</text> -->
     </view>
-    <view
+    <!-- <view
       class=""
       style="height: 13rpx; background-color: rgba(230, 230, 230, 0.4)"
-    ></view>
+    ></view> -->
     <view class="goodsBox">
       <scroll-view scroll-y="true" class="goodsBox_lScroll">
         <view class="goodsBox_l">
@@ -175,44 +185,33 @@ const goSearch = () => {
 </script>
 
 <style lang='scss' scoped>
-.searchBox {
-  display: flex;
-  align-items: center;
-  padding: 30rpx;
-  > view {
-    width: 100%;
-    height: 70rpx;
-    line-height: 70rpx;
-    background-color: rgba(230, 230, 230, 0.4);
+.goodsType {
+  background: linear-gradient(180deg, #fffaec, #ffffff 36%);
+}
+.leftbox {
+  height: 80rpx;
+  line-height: 80rpx;
+  // background-color: rgba($color: #E6E6E6, $alpha: .4);
+  background: #ffffff;
+  border-radius: 35rpx;
+  padding: 5rpx;
+  box-sizing: border-box;
+  .search-btn {
+    margin-left: auto;
+    width: 124rpx;
+    // background: linear-gradient(98deg, #fa6339 5%, #fdae6a 94%);
+    background: #fbd415;
     border-radius: 35rpx;
-    padding-left: 30rpx;
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    .iconfont {
-      color: #666;
-      font-size: 30rpx;
-    }
-    .searchBox_inp {
-      color: #ccc;
-      font-size: 22rpx;
-      margin-left: 20rpx;
-    }
-    .searchBox_btn {
-      margin-left: auto;
-      width: 124rpx;
-      background: linear-gradient(98deg, #fa6339 5%, #fdae6a 94%);
-      border-radius: 35rpx;
-      text-align: center;
-      line-height: 70rpx;
-      color: #fff;
-    }
+    text-align: center;
+    line-height: 70rpx;
+    color: #1a1a1a;
   }
 }
 .goodsBox {
-  background-color: rgba(230, 230, 230, 0.4);
+  // background-color: rgba(230, 230, 230, 0.4);
   display: flex;
   .goodsBox_lScroll {
+    background-color: #f4f4f4;
     height: calc(100vh - 150rpx - v-bind(tabTop) * 1rpx);
   }
   .goodsBox_l {
@@ -249,7 +248,7 @@ const goSearch = () => {
     }
   }
   .goodsBox_r {
-    background: #fff;
+    // background: #fff;
     width: 570rpx;
     padding: 0 30rpx;
     .goodsBox_r_t {

+ 7 - 10
pages/tabtar/personalCenter.vue

@@ -10,14 +10,11 @@
         :border="false"
         titleStyle="font-weight: 700;color: #1a1a1a;"
       >
-        <!-- <template #right>
-          
-        </template> -->
       </uv-navbar>
 
       <view
         class="pc-user u-flex-center-sb"
-        @tap.stop="goJump('/pages/setup/edit', true)"
+        @tap.stop="goJump('/pages/set/edit', true)"
       >
         <view class="pc-user-left u-flex-center">
           <image
@@ -62,7 +59,7 @@
           >
             <uv-icon name="setting" color="#1a1a1a" size="40rpx"></uv-icon>
           </view>
-          <uv-icon name="arrow-right" color="#1a1a1a" size="28rpx"></uv-icon>
+          <uv-icon name="arrow-right" color="#1a1a1a" size="40rpx"></uv-icon>
         </view>
       </view>
 
@@ -399,13 +396,13 @@ onPullDownRefresh(() => {
 .pc-nav-right {
   display: flex;
   align-items: center;
-  gap: 22rpx;
+  // gap: 22rpx;
 }
 
 .pc-nav-icon {
   position: relative;
-  width: 56rpx;
-  height: 56rpx;
+  // width: 56rpx;
+  // height: 56rpx;
   display: flex;
   align-items: center;
   justify-content: center;
@@ -430,8 +427,8 @@ onPullDownRefresh(() => {
 }
 
 .pc-user {
-  margin-top: 24rpx;
-  padding: 10rpx 0;
+  // margin-top: 24rpx;
+  // padding: 10rpx 0;
 }
 
 .pc-user-left {

+ 106 - 41
pages/tabtar/shoppingCart.vue

@@ -1,24 +1,35 @@
 <template>
   <view class="container">
     <!-- 有数据 -->
-		<uv-sticky v-if="shopList.length > 0">
-			<view class="topStatus u-flex-center-sb u-plr30">
-			  <text class="u-1A1A1A u-font30">共{{ totalNum }}件商品</text>
-			  <text class="u-1A1A1A u-font30" @click="editorBtn">{{
-			    editorStatus ? "完成" : "编辑"
-			  }}</text>
-			</view>
-		</uv-sticky>
+    <uv-sticky v-if="shopList.length > 0">
+      <view class="topStatus u-flex-center-sb u-plr30">
+        <text class="u-1A1A1A u-font30">共{{ totalNum }}件商品</text>
+        <text class="u-1A1A1A u-font30" @click="editorBtn">{{
+          editorStatus ? "完成" : "编辑"
+        }}</text>
+      </view>
+    </uv-sticky>
     <view v-if="shopList.length > 0">
       <view class="carbox">
-        <view class="shopList u-mt20" v-for="(item, index) in shopList" :key="item.businessId">
+        <view
+          class="shopList u-mt20"
+          v-for="(item, index) in shopList"
+          :key="item.businessId"
+        >
           <view class="u-flex-center-sb">
             <view class="u-flex-center">
               <view class="check u-mr10" @click="shopChecked(index)">
-                <uv-icon name="checkmark-circle-fill" color="#eb5153" size="36rpx" v-if="item.flag"></uv-icon>
+                <uv-icon
+                  name="checkmark-circle-fill"
+                  color="#eb5153"
+                  size="36rpx"
+                  v-if="item.flag"
+                ></uv-icon>
                 <view class="radios" v-else></view>
               </view>
-              <text class="iconfont u-bold u-ml10" style="color: #eb5153">&#xe71b;</text>
+              <text class="iconfont u-bold u-ml10" style="color: #eb5153"
+                >&#xe71b;</text
+              >
               <text class="u-1A1A1A u-font30 u-ml15 u-text1 name-width">{{
                 item.businessName
               }}</text>
@@ -26,13 +37,29 @@
             </view>
           </view>
 
-          <view class="goodsItem u-border-one-one u-flex-center" v-for="children in item.userShoppingCartList" :key="children.id">
-            <view class="check u-mr10" @click.stop="goodsChecked(index, children.id)">
-              <uv-icon name="checkmark-circle-fill" color="#eb5153" size="36rpx" v-if="children.flag"></uv-icon>
+          <view
+            class="goodsItem u-border-one-one u-flex-center"
+            v-for="children in item.userShoppingCartList"
+            :key="children.id"
+          >
+            <view
+              class="check u-mr10"
+              @click.stop="goodsChecked(index, children.id)"
+            >
+              <uv-icon
+                name="checkmark-circle-fill"
+                color="#eb5153"
+                size="36rpx"
+                v-if="children.flag"
+              ></uv-icon>
               <view class="radios" v-else></view>
             </view>
             <view class="u-goods200 u-ml15 positionRetave">
-              <image :src="`${children.productCover}?x-oss-process=style/w_150`" class="u-goods200" mode="scaleToFill">
+              <image
+                :src="`${children.productCover}?x-oss-process=style/w_150`"
+                class="u-goods200"
+                mode="scaleToFill"
+              >
               </image>
             </view>
             <view class="u-flex1 right-box rightText u-ml30">
@@ -40,17 +67,29 @@
                 <text>{{ children.productTitle }}</text>
               </view>
               <view class="u-flex-column-start">
-                <text class="u-font22 u-999" v-if="children.skuSetName">规格: {{ children.skuSetName }}</text>
+                <text class="u-font22 u-999" v-if="children.skuSetName"
+                  >规格: {{ children.skuSetName }}</text
+                >
                 <view class="u-flex-center-sb botPrice">
                   <view class="u-FF0000 u-font32 u-flex1">
-                    <rich-text :nodes="$mUtil.priceBigSmall(children.salePrice)"></rich-text>
+                    <rich-text
+                      :nodes="$mUtil.priceBigSmall(children.salePrice)"
+                    ></rich-text>
                   </view>
                   <view class="rightAddRes u-flex-center">
-                    <text class="btnTag" @click.stop="resNum(children, children.id)">-</text>
+                    <text
+                      class="btnTag"
+                      @click.stop="resNum(children, children.id)"
+                      >-</text
+                    >
                     <text class="u-flex1 centertext u-font28 u-999">{{
                       children.num
                     }}</text>
-                    <text class="btnTag" @click.stop="addNum(children, children.id)">+</text>
+                    <text
+                      class="btnTag"
+                      @click.stop="addNum(children, children.id)"
+                      >+</text
+                    >
                   </view>
                 </view>
               </view>
@@ -65,7 +104,12 @@
         <view class="leftAll u-flex-center" @click="allChecked">
           <view class="check u-mr10">
             <!-- <text class="iconfont iconbox u-font32 u-FF0000" v-if="checkAggrement">&#xe646;</text> -->
-            <uv-icon name="checkmark-circle-fill" color="#eb5153" size="36rpx" v-if="checkAggrement"></uv-icon>
+            <uv-icon
+              name="checkmark-circle-fill"
+              color="#eb5153"
+              size="36rpx"
+              v-if="checkAggrement"
+            ></uv-icon>
             <view class="radios" v-else></view>
           </view>
           <text class="u-ml5 u-font24 u-999">{{
@@ -73,29 +117,45 @@
           }}</text>
         </view>
         <view class="rightP u-flex-center">
-          <view class="u-flex-center u-mr10" v-if="!editorStatus" >
+          <view class="u-flex-center u-mr10" v-if="!editorStatus">
             <text class="u-font30 u-333 u-bold">合计:</text>
             <view class="u-FF0000 u-bold">
               <rich-text :nodes="$mUtil.priceBigSmall(totalPrice)"></rich-text>
             </view>
           </view>
-          <view class="u-btn-two btnWidth u-ml30" v-if="!editorStatus" @click="surePay">去结算({{ checkNum }})</view>
-          <view class="u-btn-two btnWidth u-ml30" v-else @click="delCart">删除</view>
+          <view
+            class="u-btn-two btnWidth u-ml30"
+            v-if="!editorStatus"
+            @click="surePay"
+            >去结算({{ checkNum }})</view
+          >
+          <view class="u-btn-two btnWidth u-ml30" v-else @click="delCart"
+            >删除</view
+          >
         </view>
       </view>
     </view>
 
     <!-- 没有数据 -->
-    <view class="nogoods u-mt30 u-flex-column-center" v-if="shopList.length == 0">
-      <image :src="$handleImageUrl('/common/noGoods.png')" mode="" class="noImg"></image>
-      <text class="u-font26 u-999">您的购物车空空如也~</text>
+    <view
+      class="nogoods u-mt30 u-flex-column-center"
+      v-if="shopList.length == 0"
+    >
+      <image
+        src="/static/image/common/noGoods.png"
+        mode=""
+        class="noImg"
+      ></image>
+      <text class="u-font26 u-999">您的购物车空空如也~快快去逛逛吧!~</text>
       <view class="btnview" @click="gotoshop">
         <button class="u-DCCDA4 shop-btn u-font30">
           {{ isLogin ? "去逛逛" : "去登录" }}
         </button>
       </view>
     </view>
-
+    
+    <!-- 猜你喜欢商品 -->
+    <CartGuessYouLike />
     <!--页面加载动画-->
     <ldLoading isFullScreen :active="loading"></ldLoading>
   </view>
@@ -108,8 +168,8 @@ import {
   userShoppingCartList_Api,
   userShoppingCartAdd_Api,
   userShoppingCartDel_Api,
-  oneClickClear_Api,
 } from "@/api/shop";
+import CartGuessYouLike from "./components/CartGuessYouLike.vue";
 import utils from "@/util/index.js";
 
 const totalPrice = ref(0);
@@ -121,7 +181,6 @@ const shopList = ref([]);
 const arrLenid = ref([]);
 const editorStatus = ref(false);
 const isLogin = ref(false);
-const tabTop = ref(0);
 const ispay = ref(true);
 
 const gotoshop = () => {
@@ -210,7 +269,7 @@ const resNum = (item, id) => {
       }
     });
   });
-  if(show) return;
+  if (show) return;
   setGoodsNum(item, "subtract");
 };
 
@@ -350,15 +409,19 @@ const cartList = () => {
       if (res && res.code == 200) {
         if (res.data.length > 0) {
           let nums = 0;
-          let shopLists = [...shopList.value]
+          let shopLists = [...shopList.value];
           let list = [];
           res.data.forEach((k) => {
             k.flag = false;
             nums += k.userShoppingCartList.length;
-            let objs = shopLists.find((item) => item.businessId == k.businessId) || {};
+            let objs =
+              shopLists.find((item) => item.businessId == k.businessId) || {};
 
             k.userShoppingCartList.forEach((j) => {
-              let obj = objs.userShoppingCartList ? objs.userShoppingCartList.find((item) => item.id == j.id) || {} : {};
+              let obj = objs.userShoppingCartList
+                ? objs.userShoppingCartList.find((item) => item.id == j.id) ||
+                  {}
+                : {};
               if (obj.flag) {
                 j.flag = true;
               } else {
@@ -386,16 +449,16 @@ const psotJson = () => {
   let parendArr = [];
   // let childArr = [[], [], [], [], [], [], [], [], []];
   let dataJson = {};
-  let businessId = '';
+  let businessId = "";
   let num = 0;
   shopList.value.map((res, i) => {
     res.userShoppingCartList.map((keys, j) => {
       if (keys.flag) {
-        if (businessId == '') {
+        if (businessId == "") {
           businessId = res.businessId;
         } else {
           if (businessId != res.businessId) {
-            num++
+            num++;
           }
         }
         parendArr.push({
@@ -409,7 +472,7 @@ const psotJson = () => {
   });
   if (num) {
     uni.$uv.toast("不支持多店铺商品一起下单");
-    return
+    return;
   }
   dataJson = {
     shippingMethod: 0, //0物流,10自提
@@ -455,10 +518,11 @@ page {
 .shop-btn {
   width: 300rpx;
   height: 86rpx;
-  background: #eb5153;
+  background: #f5f5f5;
+  border: 1px solid #fbbd1c;
   border-radius: 43rpx;
   font-size: 30rpx;
-  color: #fff;
+  color: #fbbd1c;
   text-align: center;
   line-height: 86rpx;
   margin-top: 30rpx;
@@ -569,8 +633,9 @@ page {
 }
 
 .noImg {
-  width: 490rpx;
-  height: 556rpx;
+  margin-top: 10vh;
+  width: 229rpx;
+  height: 243rpx;
 }
 
 .btnview {

+ 6 - 50
pages/user/address/addEditAddress.vue

@@ -82,15 +82,9 @@
         <button class="u-btn-two" form-type="submit">保存</button>
       </view>
     </form>
+
     <!-- 地区选择 -->
-    <uv-picker
-      ref="pickerRef"
-      :columns="newProvinceDataList"
-      keyName="label"
-      @confirm="areaConfirm"
-      @change="areaChange"
-    >
-    </uv-picker>
+    <RegionSelection ref="pickerRef" @confirm="areaConfirm"/>
   </view>
 </template>
 
@@ -102,11 +96,8 @@ import {
   useraddressEdit_Api,
   useraddressInfo_Api,
 } from "@/api/userInfo.js";
-import { cnareaTreeLbs } from "@/api/index";
 import $mConfig from "@/config/global.config";
 const pickerRef = ref(null);
-const oldpProvinceDataList = ref([]);
-const newProvinceDataList = ref([]);
 const dataform = ref({
   receiverName: "", //收货人姓名
   receiverPhone: "", //联系电话
@@ -120,45 +111,11 @@ const dataform = ref({
   defaultStatus: false, //是否是默认
 });
 
-const getAreaList2 = () => {
-  cnareaTreeLbs().then((res) => {
-    if (res.code == 200) {
-      let provincesList = res.data.children;
-      // console.log(provincesList);
-      newProvinceDataList.value = [
-        provincesList,
-        provincesList[0].children,
-        provincesList[0].children[0].children,
-      ];
-      oldpProvinceDataList.value = provincesList;
-    }
-  });
-};
-
-const areaChange = (e) => {
-  const { columnIndex, index, indexs } = e;
-  // 改变了省
-  if (columnIndex === 0) {
-    newProvinceDataList.value[1] =
-      oldpProvinceDataList.value[index].children || [];
-    newProvinceDataList.value[2] =
-      oldpProvinceDataList.value[index].children[0]?.children || [];
-    pickerRef.value.setIndexs([index, 0, 0], true);
-  } else if (columnIndex === 1) {
-    newProvinceDataList.value[2] =
-      newProvinceDataList.value[1][index].children || [];
-    pickerRef.value.setIndexs(indexs, true);
-  }
-};
-
+// 地区选择器确认事件
 const areaConfirm = (e) => {
-  if (e.value.length > 0) {
-    dataform.value.provinceName = e.value[0].label;
-    dataform.value.provinceCode = e.value[0].value;
-    dataform.value.cityName = e.value[1].label;
-    dataform.value.cityCode = e.value[1].value;
-    dataform.value.areaName = e.value[2].label;
-    dataform.value.areaCode = e.value[2].value;
+  dataform.value = {
+    ...dataform.value,
+    ...e,
   }
 };
 
@@ -229,7 +186,6 @@ onLoad((options) => {
       }
     });
   }
-  getAreaList2();
 });
 </script>
 

BIN
static/image/common/heart.png


BIN
static/image/common/noGoods.png


BIN
static/image/home/banner1.png


BIN
static/image/home/bg1.png


BIN
static/image/home/icon_left.png


BIN
static/image/home/icon_right.png