ext.liuqiwen3 1 day ago
parent
commit
886ad60dbf

+ 7 - 0
api/merchant.js

@@ -124,4 +124,11 @@ export function productInfo(id) {
  */
 export function productDelete(id) {
   return request.get(`product/delete/${id}`);
+}
+/**
+ * 新增商品
+ * @param
+ */
+export function batchStatus(data) {
+  return request.post(`batch/status`,data);
 }

+ 5 - 3
pages.json

@@ -53,7 +53,9 @@
 		{
 			"path": "pages/goods_cate/goods_cate",
 			"style": {
-				"navigationBarTitleText": "商品分类"
+				"navigationBarTitleText": "商品分类",
+				"navigationBarBackgroundColor": "#fff",
+				"navigationBarTextStyle": "black"
 			}
 		},
 		{
@@ -142,8 +144,8 @@
 				{
 					"path": "share/index",
 					"style": {
-						"navigationBarTitleText": "分享海报",
-						"navigationBarBackgroundColor": "#e93323",
+						"navigationBarTitleText": "成为门店会员",
+						"navigationBarBackgroundColor": "#ffffff",
 						"navigationBarTextStyle": "black"
 					}
 				},

+ 223 - 0
pages/goods/goods_search/index.vue

@@ -0,0 +1,223 @@
+<template>
+  <view>
+    <view class='searchGood'>
+      <view class='search acea-row row-between-wrapper'>
+        <view class='input acea-row row-between-wrapper'>
+          <text class='iconfont icon-sousuo'></text>
+          <input type='text' confirm-type="search" :value='searchValue' :focus="focus" placeholder='点击搜索商品' placeholder-class='placeholder'
+            @input="setValue" @confirm="searchBut" />
+        </view>
+        <view class='bnt' @tap='searchBut'>搜索</view>
+      </view>
+      <view class='title'>热门搜索</view>
+      <view class='list acea-row'>
+        <block v-for="(item, index) in hotSearchList" :key="index">
+          <view class='item' @tap='setHotSearchValue(item.title)'>{{ item.title }}</view>
+        </block>
+      </view>
+      <view class='line'></view>
+      <goodList :bastList="bastList" v-if="bastList.length > 0"></goodList>
+      <view class='loadingicon acea-row row-center-wrapper' v-if="bastList.length > 0">
+        <text class='loading iconfont icon-jiazai' :hidden='loading == false'></text>{{ loadTitle }}
+      </view>
+    </view>
+    <view class='noCommodity'>
+      <view class='pictrue' v-if="bastList.length == 0 && isbastList">
+        <image :src="HTTP_REQUEST_URL_IMG+'noSearch.png'"></image>
+      </view>
+      <recommend :hostProduct='hostProduct' v-if="bastList.length == 0"></recommend>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import { onShow, onReachBottom,onLoad } from '@dcloudio/uni-app'
+import { getSearchKeyword, getProductslist, getProductHot } from '@/api/store.js'
+import goodList from '@/components/goodList'
+import recommend from '@/components/recommend'
+import { HTTP_REQUEST_URL_IMG } from "@/config/app";
+
+// 响应式数据
+const hostProduct = ref([])
+const searchValue = ref('')
+const focus = ref(true)
+const bastList = ref([])
+const hotSearchList = ref([])
+const limit = ref(8)
+const page = ref(1)
+const loading = ref(false)
+const loadend = ref(false)
+const loadTitle = ref('加载更多')
+const hotPage = ref(1)
+const isScroll = ref(true)
+const isbastList = ref(false)
+const query = ref({})
+
+// 获取热搜
+function getRoutineHotSearch() {
+  getSearchKeyword().then(res => {
+    hotSearchList.value = res.data
+  })
+}
+
+// 获取商品列表
+function getProductList() {
+  if (loadend.value || loading.value) return
+  loading.value = true
+  loadTitle.value = ''
+  getProductslist({
+    ...query.value,
+    keyword: searchValue.value,
+    page: page.value,
+    limit: limit.value
+  }).then(res => {
+    const list = res.data.list
+    const isLoadend = list.length < limit.value
+    // 合并数组
+    bastList.value = (bastList.value || []).concat(list)
+    loading.value = false
+    loadend.value = isLoadend
+    loadTitle.value = isLoadend ? "😕人家是有底线的~~" : "加载更多"
+    page.value += 1
+    isbastList.value = true
+  }).catch(() => {
+    loading.value = false
+    loadTitle.value = '加载更多'
+  })
+}
+
+// 获取热门商品
+function getHostProduct() {
+  if (!isScroll.value) return
+  getProductHot(hotPage.value, limit.value).then(res => {
+    isScroll.value = res.data.list.length >= limit.value
+    hostProduct.value = hostProduct.value.concat(res.data.list)
+    hotPage.value += 1
+  })
+}
+
+// 设置热搜值
+function setHotSearchValue(val) {
+  searchValue.value = val
+  page.value = 1
+  loadend.value = false
+  bastList.value = []
+  getProductList()
+}
+
+// 输入框赋值
+function setValue(event) {
+  searchValue.value = event.detail.value;
+}
+
+// 搜索按钮
+function searchBut() {
+  focus.value = false
+  if (searchValue.value.length > 0) {
+    page.value = 1
+    loadend.value = false
+    bastList.value = []
+    uni.showLoading({ title: '正在搜索中' })
+    getProductList()
+    uni.hideLoading()
+  } else {
+    // 这里假设 $util.Tips 已全局挂载
+    uni.$u.toast('请输入要搜索的商品')
+  }
+}
+
+// 生命周期
+onShow(() => {
+  getRoutineHotSearch()
+  getHostProduct()
+})
+onLoad((options)=>{
+  query.value = options || {};
+  if(options){
+    getProductList()
+  }
+})
+
+onReachBottom(() => {
+  if (bastList.value.length > 0) {
+    getProductList()
+  } else {
+    getHostProduct()
+  }
+})
+</script>
+
+<style lang="scss">
+page {
+  margin-top: var(--status-bar-height);
+  background-color: #fff !important;
+}
+
+.searchGood .search {
+  padding-left: 30rpx;
+  background-color: #fff !important;
+}
+
+.searchGood .search {
+  padding-top: 20rpx;
+}
+
+.searchGood .search .input {
+  width: 598rpx;
+  background-color: #f7f7f7;
+  border-radius: 33rpx;
+  padding: 0 35rpx;
+  box-sizing: border-box;
+  height: 66rpx;
+}
+
+.searchGood .search .input input {
+  width: 472rpx;
+  font-size: 26rpx;
+}
+
+.searchGood .search .input .placeholder {
+  color: #bbb;
+}
+
+.searchGood .search .input .iconfont {
+  color: #000;
+  font-size: 35rpx;
+}
+
+.searchGood .search .bnt {
+  width: 120rpx;
+  text-align: center;
+  height: 66rpx;
+  line-height: 66rpx;
+  font-size: 30rpx;
+  color: #282828;
+}
+
+.searchGood .title {
+  font-size: 28rpx;
+  color: #999;
+  margin: 50rpx 30rpx 25rpx 30rpx;
+}
+
+.searchGood .list {
+  padding-left: 10rpx;
+}
+
+.searchGood .list .item {
+  font-size: 26rpx;
+  color: #454545;
+  padding: 0 21rpx;
+  height: 60rpx;
+  border-radius: 30rpx;
+  line-height: 60rpx;
+  border: 1rpx solid #aaa;
+  margin: 0 0 20rpx 20rpx;
+}
+
+.searchGood .line {
+  border-bottom: 1rpx solid #eee;
+  margin: 20rpx 30rpx 0 30rpx;
+}
+</style>

+ 292 - 168
pages/goods_cate/goods_cate.vue

@@ -1,175 +1,299 @@
 <template>
-	<view class='productSort'>
-<!--		<view class='header acea-row row-center-wrapper'>-->
-<!--			<view class='acea-row row-between-wrapper input'>-->
-<!--				<text class='iconfont icon-sousuo'></text>-->
-<!--				<input type='text' placeholder='点击搜索商品信息' @confirm="searchSubmitValue" confirm-type='search' name="search"-->
-<!--				 placeholder-class='placeholder'></input>-->
-<!--			</view>-->
-<!--		</view>-->
-<!--		<view class='aside' :style="{bottom: tabbarH + 'px',height: height + 'rpx'}">-->
-<!--			<scroll-view scroll-y="true" scroll-with-animation='true' style="height: 100%;">-->
-<!--				<view class='item acea-row row-center-wrapper' :class='index==navActive?"on":""' v-for="(item,index) in productList"-->
-<!--			 :key="index" @click='tap(index,"b"+index)'><text>{{item.name}}</text></view>-->
-<!--			 </scroll-view>-->
-<!--			-->
-<!--		</view>-->
-<!--		<view class='conter'>-->
-<!--			<scroll-view scroll-y="true" :scroll-into-view="toView" :style='"height:"+height+"rpx;margin-top: 96rpx;"' @scroll="scroll"-->
-<!--			 scroll-with-animation='true'>-->
-<!--				<block v-for="(item,index) in productList" :key="index">-->
-<!--					-->
-<!--					<view class='listw' :id="'b'+index">-->
-<!--						<view class='title acea-row row-center-wrapper'>-->
-<!--							<view class='line'></view>-->
-<!--							<view class='name'>{{item.name}}</view>-->
-<!--							<view class='line'></view>-->
-<!--						</view>-->
-<!--						<view class='list acea-row'>-->
-<!--							<block v-for="(itemn,indexn) in item.child" :key="indexn">-->
-<!--								<navigator hover-class='none' :url='"/pages/goods_list/index?cid="+itemn.id+"&title="+itemn.name' class='item acea-row row-column row-middle'>-->
-<!--							        &lt;!&ndash; <view class='picture' :style="{'background-color':itemn.extra?'none':'#f7f7f7'}">-->
-<!--										<image :src='itemn.extra'></image>-->
-<!--									</view> &ndash;&gt;-->
-<!--									<view class='name line1'>{{itemn.name}}</view>-->
-<!--								</navigator>-->
-<!--							</block>-->
-<!--						</view>-->
-<!--					</view>-->
-<!--				</block>-->
-<!--				<view :style='"height:"+(height-300)+"rpx;"' v-if="number<15"></view>-->
-<!--			</scroll-view>-->
-<!--		</view>-->
-	</view>
+  <view class='productSort'>
+    <view class='header acea-row row-center-wrapper'>
+      <view class='acea-row row-between-wrapper input'>
+        <text class='iconfont icon-sousuo'></text>
+        <input type='text' placeholder='点击搜索商品信息' @confirm="searchSubmitValue" confirm-type='search' name="search"
+               placeholder-class='placeholder'></input>
+      </view>
+    </view>
+    <view class='aside' :style="{bottom: tabbarH + 'px',height: height + 'rpx'}">
+      <scroll-view scroll-y="true" scroll-with-animation='true' style="height: 100%;">
+        <view class='item acea-row row-center-wrapper'
+              :class='index==navActive?"on":""'
+              v-for="(item,index) in productList"
+              :key="index"
+              @click='tap(index,"b"+index)'>
+          <text>{{item.name}}</text>
+        </view>
+      </scroll-view>
+    </view>
+    <view class='conter'>
+      <scroll-view scroll-y="true"
+                   :scroll-into-view="toView"
+                   :style='"height:"+height+"rpx;margin-top: 96rpx;"'
+                   @scroll="scroll"
+                   scroll-with-animation='true'>
+        <view v-for="(item,index) in productList" :key="index">
+          <view class='listw' :id="'b'+index">
+            <view class='title acea-row row-center-wrapper'>
+              <view class='line'></view>
+              <view class='name'>{{item.name}}</view>
+              <view class='line'></view>
+            </view>
+            <view class='list acea-row'>
+              <view v-for="(itemn,indexn) in item.child" :key="indexn">
+                <navigator hover-class='none'
+                           :url='"/pages/goods/goods_search/index?cid="+itemn.id+"&title="+itemn.name'
+                           class='item acea-row row-column row-middle'>
+                  <view class='name line1'>{{itemn.name}}</view>
+                </navigator>
+              </view>
+            </view>
+          </view>
+        </view>
+        <view :style='"height:"+(height-300)+"rpx;"' v-if="number<15"></view>
+      </scroll-view>
+    </view>
+  </view>
 </template>
 
-<script>
+<script setup>
+import { ref, onMounted, nextTick } from 'vue';
+import { onLoad, onShow } from '@dcloudio/uni-app';
+import { productCategory } from '@/api/merchant.js';
 
+// 响应式数据
+const productList = ref([]);
+const navActive = ref(0);
+const number = ref("");
+const height = ref(0);
+const hightArr = ref([]);
+const toView = ref("");
+const tabbarH = ref(0);
+
+// 获取分类列表
+const getAllCategory = async () => {
+  try {
+    let obj = {
+      type: 1,
+      status: -1
+    }
+    const { data }= await productCategory(obj);
+    const newArr = []
+    data.forEach((value, index) => {
+      newArr[index] = value
+      if (value.child) newArr[index].child = value.child.filter(item => item.status === true)
+    })
+    productList.value = newArr.filter(item => item.code !== 'bb_mall')
+
+    // 使用 nextTick 确保 DOM 已更新
+    nextTick(() => {
+      setTimeout(() => {
+        infoScroll();
+      }, 500);
+    });
+  } catch (error) {
+    console.error('获取分类列表失败:', error);
+    uni.showToast({ title: '加载分类失败' });
+  }
+};
+
+// 计算滚动相关数据
+const infoScroll = () => {
+  let len = productList.value.length;
+  let child = productList.value[len - 1] && productList.value[len - 1].child
+      ? productList.value[len - 1].child
+      : [];
+  number.value = child ? child.length : 0;
+
+  // 设置商品列表高度
+  uni.getSystemInfo({
+    success: (res) => {
+      height.value = (res.windowHeight) * (750 / res.windowWidth) - 98;
+    },
+  });
+
+  let heightTemp = 0;
+  let hightArrTemp = [];
+
+  for (let i = 0; i < len; i++) {
+    // 获取元素所在位置
+    let query = uni.createSelectorQuery();
+    let idView = "#b" + i;
+    query.select(idView).boundingClientRect();
+    query.exec((res) => {
+      if (res && res[0]) {
+        let top = res[0].top;
+        hightArrTemp.push(top);
+        hightArr.value = hightArrTemp;
+      }
+    });
+  }
+};
+
+// 点击左侧导航
+const tap = (index, id) => {
+  toView.value = id;
+  navActive.value = index;
+};
+
+// 右侧滚动事件
+const scroll = (e) => {
+  let scrollTop = e.detail.scrollTop;
+  let scrollArr = hightArr.value;
+
+  if (!scrollArr || scrollArr.length === 0) return;
+
+  for (let i = 0; i < scrollArr.length; i++) {
+    if (scrollTop >= 0 && scrollTop < scrollArr[1] - scrollArr[0]) {
+      navActive.value = 0;
+    } else if (scrollTop >= scrollArr[i] - scrollArr[0] && scrollTop < scrollArr[i + 1] - scrollArr[0]) {
+      navActive.value = i;
+    } else if (scrollTop >= scrollArr[scrollArr.length - 1] - scrollArr[0]) {
+      navActive.value = scrollArr.length - 1;
+    }
+  }
+};
+
+// 搜索提交
+const searchSubmitValue = (e) => {
+  const searchValue = e.detail.value?.trim();
+
+  if (!searchValue) {
+    return uni.showToast({ title: '请填写要搜索的产品信息' });
+  }
+
+  if (searchValue.length > 0) {
+    uni.navigateTo({
+      url: '/pages/goods/goods_search/index?keyword=' + searchValue
+    });
+  }
+};
+
+// 页面加载
+onLoad(() => {
+  getAllCategory();
+});
+
+// 页面显示
+onShow(() => {
+  // 可以在这里添加页面显示时的逻辑
+});
 </script>
 
 <style scoped lang="scss">
-	.productSort .header {
-		width: 100%;
-		height: 96rpx;
-		background-color: #fff;
-		position: fixed;
-		left: 0;
-		right: 0;
-		top: 0;
-		z-index: 9;
-		border-bottom: 1rpx solid #f5f5f5;
-	}
-
-	.productSort .header .input {
-		width: 700rpx;
-		height: 60rpx;
-		background-color: #f5f5f5;
-		border-radius: 50rpx;
-		box-sizing: border-box;
-		padding: 0 25rpx;
-	}
-
-	.productSort .header .input .iconfont {
-		font-size: 26rpx;
-		color: #555;
-	}
-
-	.productSort .header .input .placeholder {
-		color: #999;
-	}
-
-	.productSort .header .input input {
-		font-size: 26rpx;
-		height: 100%;
-		width: 597rpx;
-	}
-
-	.productSort .aside {
-		position: fixed;
-		width: 180rpx;
-		left: 0;
-		top:0;
-		background-color: #f7f7f7;
-		overflow-y: scroll;
-		overflow-x: hidden;
-
-		height: auto;
-		margin-top: 96rpx;
-	}
-
-	.productSort .aside .item {
-		height: 100rpx;
-		width: 100%;
-		font-size: 26rpx;
-		color: #424242;
-	}
-
-	.productSort .aside .item.on {
-		background-color: #fff;
-		border-left: 4rpx solid #fc4141;
-		width: 100%;
-		text-align: center;
-		color: #fc4141;
-		font-weight: bold;
-	}
-
-	.productSort .conter {
-		margin: 96rpx 0 0 180rpx;
-		padding: 0 14rpx;
-		background-color: #fff;
-	}
-
-	.productSort .conter .listw {
-		padding-top: 20rpx;
-	}
-
-	.productSort .conter .listw .title {
-		height: 90rpx;
-	}
-
-	.productSort .conter .listw .title .line {
-		width: 100rpx;
-		height: 2rpx;
-		background-color: #f0f0f0;
-	}
-
-	.productSort .conter .listw .title .name {
-		font-size: 28rpx;
-		color: #333;
-		margin: 0 30rpx;
-		font-weight: bold;
-	}
-
-	.productSort .conter .list {
-		flex-wrap: wrap;
-	}
-
-	.productSort .conter .list .item {
-		width: 177rpx;
-		margin-top: 26rpx;
-	}
-
-	.productSort .conter .list .item .picture {
-		width: 120rpx;
-		height: 120rpx;
-		border-radius: 50%;
-	}
-
-	.productSort .conter .list .item .picture image {
-		width: 100%;
-		height: 100%;
-		border-radius: 50%;
-		div{
-			background-color: #f7f7f7;
-		}
-	}
-
-	.productSort .conter .list .item .name {
-		font-size: 24rpx;
-		color: #333;
-		height: 56rpx;
-		line-height: 56rpx;
-		width: 120rpx;
-		text-align: center;
-	}
-</style>
+.productSort .header {
+  width: 100%;
+  height: 96rpx;
+  background-color: #fff;
+  position: fixed;
+  left: 0;
+  right: 0;
+  top: 0;
+  z-index: 9;
+  border-bottom: 1rpx solid #f5f5f5;
+}
+
+.productSort .header .input {
+  width: 700rpx;
+  height: 88rpx;
+  background-color: #f5f5f5;
+  border-radius: 16rpx;
+  box-sizing: border-box;
+  padding: 0 25rpx;
+}
+
+.productSort .header .input .iconfont {
+  font-size: 26rpx;
+  color: #555;
+}
+
+.productSort .header .input .placeholder {
+  color: #999;
+}
+
+.productSort .header .input input {
+  font-size: 26rpx;
+  height: 100%;
+  width: 597rpx;
+}
+
+.productSort .aside {
+  position: absolute;
+  width: 180rpx;
+  left: 0;
+  top:0;
+  background-color: #f7f7f7;
+  overflow-y: scroll;
+  overflow-x: hidden;
+  height: auto;
+  margin-top: 96rpx;
+}
+
+.productSort .aside .item {
+  height: 100rpx;
+  width: 100%;
+  font-size: 26rpx;
+  color: #424242;
+}
+
+.productSort .aside .item.on {
+  background-color: #fff;
+  border-left: 4rpx solid #F8C008;
+  width: 100%;
+  text-align: center;
+  color: #F8C008;
+  font-weight: bold;
+}
+
+.productSort .conter {
+  margin: 96rpx 0 0 180rpx;
+  padding: 0 14rpx;
+  background-color: #fff;
+}
+
+.productSort .conter .listw {
+  padding-top: 20rpx;
+}
+
+.productSort .conter .listw .title {
+  height: 90rpx;
+}
+
+.productSort .conter .listw .title .line {
+  width: 100rpx;
+  height: 2rpx;
+  background-color: #f0f0f0;
+}
+
+.productSort .conter .listw .title .name {
+  font-size: 28rpx;
+  color: #333;
+  margin: 0 30rpx;
+  font-weight: bold;
+}
+
+.productSort .conter .list {
+  flex-wrap: wrap;
+}
+
+.productSort .conter .list .item {
+  width: 177rpx;
+  margin-top: 26rpx;
+}
+
+.productSort .conter .list .item .picture {
+  width: 120rpx;
+  height: 120rpx;
+  border-radius: 50%;
+}
+
+.productSort .conter .list .item .picture image {
+  width: 100%;
+  height: 100%;
+  border-radius: 50%;
+  div{
+    background-color: #f7f7f7;
+  }
+}
+
+.productSort .conter .list .item .name {
+  font-size: 24rpx;
+  color: #333;
+  height: 56rpx;
+  line-height: 56rpx;
+  width: 120rpx;
+  text-align: center;
+}
+</style>

+ 1 - 1
pages/index/index.vue

@@ -25,7 +25,7 @@
 <!--              <image src="@/static/logo1.png" mode=""></image>-->
 <!--            </view>-->
             <navigator
-                url="/pages/goods_search/index"
+                url="/pages/goods/goods_search/index"
                 class="input"
                 hover-class="none"
             ><text class="iconfont icon-sousuo"></text> 搜索商品</navigator

+ 5 - 5
pages/merchantCenter/index.vue

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

+ 255 - 0
pages/merchantCenters/components/merchant_cate.vue

@@ -0,0 +1,255 @@
+<template>
+  <view class='productSort'>
+    <view class='aside' :style="{bottom: tabbarH + 'px',height: height + 'rpx'}">
+      <scroll-view scroll-y="true" scroll-with-animation='true' style="height: 100%;">
+        <view class='item acea-row row-center-wrapper'
+              :class='index==navActive?"on":""'
+              v-for="(item,index) in productList"
+              :key="index"
+              @click='tap(index,"b"+index)'>
+          <text>{{item.name}}</text>
+        </view>
+      </scroll-view>
+    </view>
+    <view class='conter'>
+      <scroll-view scroll-y="true"
+                   :scroll-into-view="toView"
+                   :style='"height:"+height+"rpx;"'
+                   @scroll="scroll"
+                   scroll-with-animation='true'>
+        <view v-for="(item,index) in productList" :key="index">
+          <view class='listw' :id="'b'+index">
+            <view class='title acea-row row-center-wrapper'>
+              <view class='line'></view>
+              <view class='name'>{{item.name}}</view>
+              <view class='line'></view>
+            </view>
+            <view class='list acea-row'>
+              <view v-for="(itemn,indexn) in item.child" :key="indexn">
+                <navigator hover-class='none'
+                           :url='"/pages/goods/goods_search/index?cid="+itemn.id+"&title="+itemn.name+"&merchantId="+props.merchantId'
+                           class='item acea-row row-column row-middle'>
+                  <view class='name line1'>{{itemn.name}}</view>
+                </navigator>
+              </view>
+            </view>
+          </view>
+        </view>
+        <view :style='"height:"+(height-300)+"rpx;"' v-if="number<15"></view>
+      </scroll-view>
+    </view>
+  </view>
+</template>
+<script setup>
+import { ref, onMounted, nextTick,watch} from 'vue';
+import { onLoad, onShow } from '@dcloudio/uni-app';
+import { productCategory } from '@/api/merchant.js';
+
+const props = defineProps({
+  merchantId: {
+    type: [String, Number],
+    required: true
+  }
+});
+// 响应式数据
+const productList = ref([]);
+const navActive = ref(0);
+const number = ref("");
+const height = ref(0);
+const hightArr = ref([]);
+const toView = ref("");
+const tabbarH = ref(0);
+
+
+// 获取分类列表
+const getAllCategory = async () => {
+  console.log('============')
+  console.log(props.merchantId)
+  try {
+    let obj = {
+      type: 1,
+      status: -1
+    }
+    const { data }= await productCategory(obj);
+    const newArr = []
+    data.forEach((value, index) => {
+      newArr[index] = value
+      if (value.child) newArr[index].child = value.child.filter(item => item.status === true)
+    })
+    productList.value = newArr.filter(item => item.code !== 'bb_mall')
+
+    // 使用 nextTick 确保 DOM 已更新
+    nextTick(() => {
+      setTimeout(() => {
+        infoScroll();
+      }, 500);
+    });
+  } catch (error) {
+    console.error('获取分类列表失败:', error);
+    uni.showToast({ title: '加载分类失败' });
+  }
+};
+
+// 计算滚动相关数据
+const infoScroll = () => {
+  let len = productList.value.length;
+  let child = productList.value[len - 1] && productList.value[len - 1].child
+      ? productList.value[len - 1].child
+      : [];
+  number.value = child ? child.length : 0;
+
+  // 设置商品列表高度
+  uni.getSystemInfo({
+    success: (res) => {
+      height.value = (res.windowHeight) * (750 / res.windowWidth) - 98;
+    },
+  });
+
+  let heightTemp = 0;
+  let hightArrTemp = [];
+
+  for (let i = 0; i < len; i++) {
+    // 获取元素所在位置
+    let query = uni.createSelectorQuery();
+    let idView = "#b" + i;
+    query.select(idView).boundingClientRect();
+    query.exec((res) => {
+      if (res && res[0]) {
+        let top = res[0].top;
+        hightArrTemp.push(top);
+        hightArr.value = hightArrTemp;
+      }
+    });
+  }
+};
+
+// 点击左侧导航
+const tap = (index, id) => {
+  toView.value = id;
+  navActive.value = index;
+};
+
+// 右侧滚动事件
+const scroll = (e) => {
+  let scrollTop = e.detail.scrollTop;
+  let scrollArr = hightArr.value;
+
+  if (!scrollArr || scrollArr.length === 0) return;
+
+  for (let i = 0; i < scrollArr.length; i++) {
+    if (scrollTop >= 0 && scrollTop < scrollArr[1] - scrollArr[0]) {
+      navActive.value = 0;
+    } else if (scrollTop >= scrollArr[i] - scrollArr[0] && scrollTop < scrollArr[i + 1] - scrollArr[0]) {
+      navActive.value = i;
+    } else if (scrollTop >= scrollArr[scrollArr.length - 1] - scrollArr[0]) {
+      navActive.value = scrollArr.length - 1;
+    }
+  }
+};
+// 监听 merchantId 变化
+watch(() => props.merchantId, (newVal) => {
+  console.log('merchantId 变化了:', newVal);
+  if (newVal) {
+    getAllCategory();
+  }
+}, { immediate: true }); // 立即执行一次
+
+// 页面加载
+onLoad(() => {
+
+});
+
+// 页面显示
+onShow(() => {
+  getAllCategory();
+});
+</script>
+
+<style scoped lang="scss">
+.productSort .aside {
+  position: absolute;
+  width: 180rpx;
+  left: 0;
+  top:0;
+  background-color: #f7f7f7;
+  overflow-y: scroll;
+  overflow-x: hidden;
+  height: auto;
+}
+
+.productSort .aside .item {
+  height: 100rpx;
+  width: 100%;
+  font-size: 26rpx;
+  color: #424242;
+}
+
+.productSort .aside .item.on {
+  background-color: #fff;
+  border-left: 4rpx solid #F8C008;
+  width: 100%;
+  text-align: center;
+  color: #F8C008;
+  font-weight: bold;
+}
+
+.productSort .conter {
+  margin: 0rpx 0 0 180rpx;
+  padding: 0 14rpx;
+  background-color: #fff;
+}
+
+.productSort .conter .listw {
+  padding-top: 20rpx;
+}
+
+.productSort .conter .listw .title {
+  height: 90rpx;
+}
+
+.productSort .conter .listw .title .line {
+  width: 100rpx;
+  height: 2rpx;
+  background-color: #f0f0f0;
+}
+
+.productSort .conter .listw .title .name {
+  font-size: 28rpx;
+  color: #333;
+  margin: 0 30rpx;
+  font-weight: bold;
+}
+
+.productSort .conter .list {
+  flex-wrap: wrap;
+}
+
+.productSort .conter .list .item {
+  width: 177rpx;
+  margin-top: 26rpx;
+}
+
+.productSort .conter .list .item .picture {
+  width: 120rpx;
+  height: 120rpx;
+  border-radius: 50%;
+}
+
+.productSort .conter .list .item .picture image {
+  width: 100%;
+  height: 100%;
+  border-radius: 50%;
+  div{
+    background-color: #f7f7f7;
+  }
+}
+
+.productSort .conter .list .item .name {
+  font-size: 24rpx;
+  color: #333;
+  height: 56rpx;
+  line-height: 56rpx;
+  width: 120rpx;
+  text-align: center;
+}
+</style>

+ 46 - 7
pages/merchantCenters/merchant.vue

@@ -13,7 +13,7 @@
         </view>
       </view>
       <view class="desc">{{merchantInfo.merchantDescribe}}</view>
-      <view class="tel">
+      <view class="tel" @click="makePhoneCall">
         <image class="phone mr20" src="@/static/images/phone2.png" mode="widthFix"></image>
         <text>联系电话:{{merchantInfo.merchantPhone}}</text>
         <image class="phone fr" src="@/static/images/phoneyellow.png" mode="widthFix"></image>
@@ -37,7 +37,7 @@
               transform: 'scale(1)'
         }"></up-tabs>
       <!--    商品列表-->
-    <view class="index-product-wrapper">
+    <view class="index-product-wrapper" v-if="tabActive == '0'">
       <view
           class="list-box animated"
           :class="goodsList.length > 0 ? 'fadeIn on' : ''"
@@ -90,15 +90,17 @@
         <text>我是有底线的</text>
       </view>
     </view>
+    <view class="index-product-wrapper" v-if="tabActive == '1'">
+      <merchantCate :merchant-id="query.merchantId || merchantInfo.id" />
+    </view>
   </view>
 </template>
 <script setup>
 import {computed, ref} from 'vue';
 import { onLoad, onShow, onReachBottom } from "@dcloudio/uni-app";
 import { getSbmerchantInfo } from "@/api/merchant.js";
-import {
-  getGroomList as getGroomListApi,
-} from "@/api/store.js";
+import merchantCate from "./components/merchant_cate.vue"
+import { getGroomList as getGroomListApi, } from "@/api/store.js";
 // 获取实时金价
 import useRealGoldPrice from "@/hooks/useRealGoldPrice";
 // 实时价格处理
@@ -111,9 +113,10 @@ const {
 const query = ref({});
 const merchantInfo = ref({});
 const tabList = ref([
-  {name:'推荐商品'},
-  {name:'商品分类'}
+  {name:'推荐商品',code:'0'},
+  {name:'商品分类',code:'1'}
 ])
+const tabActive = ref('0');
 const goodsList = ref([]);
 const goodType = ref(1);
 // Pagination
@@ -166,6 +169,7 @@ const getSbmerchantInfoFn = () => {
 }
 const tabChange = (item) => {
   console.log('item',item)
+  tabActive.value = item.code;
 }
 // Product Lists
 const getGroomList = async () => {
@@ -184,6 +188,40 @@ const getGroomList = async () => {
     loading.value = false;
   }
 };
+// 在methods部分添加:
+const makePhoneCall = () => {
+  if (!merchantInfo.value.merchantPhone) {
+    uni.showToast({
+      title: '暂无联系电话',
+      icon: 'none'
+    });
+    return;
+  }
+
+  // 显示确认弹窗
+  uni.showModal({
+    title: '拨打电话',
+    content: `是否拨打 ${merchantInfo.value.merchantPhone}?`,
+    success: (res) => {
+      if (res.confirm) {
+        // 调用拨打电话API
+        uni.makePhoneCall({
+          phoneNumber: merchantInfo.value.merchantPhone,
+          success: () => {
+            console.log('拨打电话成功');
+          },
+          fail: (err) => {
+            console.log('拨打电话失败:', err);
+            uni.showToast({
+              title: '拨打电话失败',
+              icon: 'none'
+            });
+          }
+        });
+      }
+    }
+  });
+};
 </script>
 <style scoped lang="scss">
 .container{
@@ -246,6 +284,7 @@ const getGroomList = async () => {
   min-height: 700rpx;
   margin-top: 30rpx;
   //background: #fff;
+  position: relative;
 
   &.on {
     min-height: 1500rpx;

+ 411 - 139
pages/merchantCenters/productManagement.vue

@@ -40,43 +40,61 @@
               transform: 'scale(1)'
         }"></up-tabs>
 
+      <!-- 管理按钮 -->
+      <view v-if="goodsList.length" class='nav acea-row row-between-wrapper'>
+        <view>共 <text class='num font-color'>{{ goodsList.length }}</text>件商品</view>
+        <view class='administrate acea-row row-center-wrapper' @click='manage'>
+          {{ footerswitch ? '管理' : '取消' }}
+        </view>
+      </view>
     </view>
 
-
     <!-- 商品列表 -->
     <view class="product-list">
-      <view class="product-card" v-for="(item, index) in goodsList" :key="index">
-        <view class="product-header">
-          <image class="product-image" :src="item.image" mode="aspectFit" />
-          <view class="product-info">
-            <view class="nameweight">
-              <text class="product-name">{{ item.storeName }}</text>
-              <text class="product-weight">{{ item.weight }}g</text>
-            </view>
-            <view class="nameweight">
-              <view class="price-info">
-                <text class="label">工费</text>
-                <view class="value"><text class="unit">¥</text>{{ item.totalLaborCost }}<text class="unit">/g</text></view>
+      <up-checkbox-group shape="circle" @change="checkboxChange" class="centent" activeColor="#F8C008">
+        <view class="product-card" v-for="(item, index) in goodsList" :key="index">
+          <view class="product-header">
+            <!-- 多选框 -->
+            <up-checkbox
+                :name="item.id.toString()"
+                :checked="item.checked"
+                v-if="!footerswitch"
+                style="margin-right: 10rpx;"
+                activeColor="#F8C008"
+            />
+
+            <image class="product-image" :src="item.image" mode="aspectFit" />
+            <view class="product-info">
+              <view class="nameweight">
+                <text class="product-name">{{ item.storeName }}</text>
+                <text class="product-weight">{{ item.weight }}g</text>
               </view>
-              <view class="price-info">
-                <text class="label">附加费</text>
-                <view class="value"><text class="unit">¥</text>{{ item.additionalAmount }}</view>
+              <view class="nameweight">
+                <view class="price-info">
+                  <text class="label">工费</text>
+                  <view class="value"><text class="unit">¥</text>{{ item.totalLaborCost }}<text class="unit">/g</text></view>
+                </view>
+                <view class="price-info">
+                  <text class="label">附加费</text>
+                  <view class="value"><text class="unit">¥</text>{{ item.additionalAmount }}</view>
+                </view>
+              </view>
+              <view class="product-stats">
+                <text class="stat">销量:{{ Number(item.sales || 0) + Number(item.ficti || 0) }}</text>
+                <text class="stat">库存:{{ item.stock }}</text>
               </view>
-            </view>
-            <view class="product-stats">
-              <text class="stat">销量:{{ Number(item.sales || 0) + Number(item.ficti || 0) }}</text>
-              <text class="stat">库存:{{ item.stock }}</text>
             </view>
           </view>
-        </view>
 
-        <view class="action-buttons">
-          <button class="btn btn-delete" @click="deleteFn(item,index)">删除</button>
-          <button class="btn btn-offline" v-show="params.isShow==1" @click="OffShellFn(item,index)">下架</button>
-          <button class="btn btn-offline" v-show="params.isShow==0" @click="PutOnShellFn(item,index)">上架</button>
-          <button class="btn btn-edit" v-show="params.isShow==0" @click="toEditProduct(item)">编辑</button>
+          <view class="action-buttons">
+            <button class="btn btn-delete" @click="deleteFn(item,index)">删除</button>
+            <button class="btn btn-offline" v-show="params.isShow==1" @click="OffShellFn(item,index)">下架</button>
+            <button class="btn btn-offline" v-show="params.isShow==0" @click="PutOnShellFn(item,index)">上架</button>
+            <button class="btn btn-edit" v-show="params.isShow==0" @click="toEditProduct(item)">编辑</button>
+          </view>
         </view>
-      </view>
+      </up-checkbox-group>
+
       <view class="loadingicon acea-row row-center-wrapper" v-if="goodScroll">
         <text
             class="loading iconfont icon-jiazai"
@@ -92,17 +110,37 @@
         <text>我是有底线的</text>
       </view>
     </view>
+
+    <!-- 底部操作栏 -->
+    <view v-if="!footerswitch" class='footer acea-row row-between-wrapper'>
+      <view>
+        <up-checkbox-group shape="circle" @change="checkboxAllChange">
+          <up-checkbox value="all" :checked="!!isAllSelect" activeColor="#F8C008"  />
+          <text class='checkAll'>全选</text>
+        </up-checkbox-group>
+      </view>
+      <view class='button acea-row row-middle'>
+        <button v-if="params.isShow==1" class='bnt' @click="batchOffShell">批量下架</button>
+        <button v-if="params.isShow==0" class='bnt' @click="batchPutOnShell">批量上架</button>
+<!--        <button class='bnt cart-color delete-btn' @click="batchDelete">批量删除</button>-->
+      </view>
+    </view>
   </view>
 </template>
 
 <script setup>
-import {computed, ref} from 'vue'
+import {computed, ref,watch} from 'vue'
 import { onLoad, onShow, onReachBottom } from "@dcloudio/uni-app";
-import { productsList,productPutOnShell,productOffShell,productDelete } from "@/api/merchant.js";
+import { productsList, productPutOnShell, productOffShell, productDelete, batchStatus } from "@/api/merchant.js";
 import { useAppStore } from "@/stores/app";
 
 const appStore = useAppStore();
 
+// 管理相关状态
+const footerswitch = ref(true); // true: 显示正常模式, false: 显示管理模式
+const isAllSelect = ref(false); // 是否全选
+const selectValue = ref([]); // 选中的商品ID数组
+
 const tabList = ref([
   {name:'销售中',code:1},
   {name:'已下架',code:0}
@@ -126,12 +164,160 @@ const isNoDataState = computed(() => {
   return goodsList.value.length === 0 && !loading.value;
 });
 
-
 onShow(() => {
   merchantInfo.value = appStore.userInfo.merchant;
   getGroomList()
 })
 
+// 切换管理状态
+const manage = () => {
+  footerswitch.value = !footerswitch.value;
+  // 退出管理状态时,清空选择
+  if (footerswitch.value) {
+    resetSelection();
+  }
+}
+
+// 重置选择状态
+const resetSelection = () => {
+  goodsList.value.forEach(item => {
+    item.checked = false;
+  });
+  isAllSelect.value = false;
+  selectValue.value = [];
+}
+
+// 多选框变化
+const checkboxChange = (values) => {
+
+  goodsList.value.forEach(item => {
+    item.checked = values.includes(item.id.toString());
+  });
+
+  selectValue.value = values;
+  isAllSelect.value = goodsList.value.length === values.length;
+};
+
+// 全选变化
+const checkboxAllChange = (event) => {
+  if (event.length > 0) {
+    setAllSelectValue(1);
+  } else {
+    setAllSelectValue(0);
+  }
+};
+
+// 设置全选状态
+const setAllSelectValue = (status) => {
+  const selectValues = [];
+
+  goodsList.value.forEach(item => {
+    if (status) {
+      item.checked = true;
+      selectValues.push(item.id);
+      isAllSelect.value = true;
+    } else {
+      item.checked = false;
+      isAllSelect.value = false;
+    }
+  });
+  selectValue.value = selectValues;
+  console.log(selectValue.value)
+};
+
+// 检查是否有选中商品
+const checkHasSelected = () => {
+  if (!selectValue.value || selectValue.value.length === 0) {
+    uni.showToast({ title: '请先选择商品', icon: 'none' });
+    return false;
+  }
+  return true;
+}
+
+// 批量下架
+const batchOffShell = async () => {
+  if (!checkHasSelected()) return;
+
+  uni.showModal({
+    title: '提示',
+    content: `确定要下架选中的${selectValue.value.length}件商品吗?`,
+    success: async (res) => {
+      if (res.confirm) {
+        try {
+          const { code, message } = await batchStatus({ ids: selectValue.value, status:0 });
+          if (code === 200) {
+            uni.showToast({ title: '批量下架成功', icon: 'success' });
+            // 从列表中移除下架的商品
+            goodsList.value = goodsList.value.filter(item => !selectValue.value.includes(item.id.toString()));
+            resetSelection();
+            footerswitch.value = true; // 退出管理模式
+          } else {
+            uni.showToast({ title: message || '操作失败', icon: 'none' });
+          }
+        } catch (err) {
+          uni.showToast({ title: err.message || '操作失败', icon: 'none' });
+        }
+      }
+    }
+  });
+}
+
+// 批量上架
+const batchPutOnShell = async () => {
+  if (!checkHasSelected()) return;
+
+  uni.showModal({
+    title: '提示',
+    content: `确定要上架选中的${selectValue.value.length}件商品吗?`,
+    success: async (res) => {
+      if (res.confirm) {
+        try {
+          const { code, message } = await batchStatus({ ids: selectValue.value,status:1 });
+          if (code === 200) {
+            uni.showToast({ title: '批量上架成功', icon: 'success' });
+            // 从列表中移除上架的商品
+            goodsList.value = goodsList.value.filter(item => !selectValue.value.includes(item.id.toString()));
+            resetSelection();
+            footerswitch.value = true; // 退出管理模式
+          } else {
+            uni.showToast({ title: message || '操作失败', icon: 'none' });
+          }
+        } catch (err) {
+          uni.showToast({ title: err.message || '操作失败', icon: 'none' });
+        }
+      }
+    }
+  });
+}
+
+// 批量删除
+const batchDelete = async () => {
+  if (!checkHasSelected()) return;
+
+  uni.showModal({
+    title: '警告',
+    content: `确定要删除选中的${selectValue.value.length}件商品吗?此操作不可恢复!`,
+    success: async (res) => {
+      if (res.confirm) {
+        try {
+          const { code, message } = await batchDeleteApi({ ids: selectValue.value.join(',') });
+          if (code === 200) {
+            uni.showToast({ title: '批量删除成功', icon: 'success' });
+            // 从列表中移除删除的商品
+            goodsList.value = goodsList.value.filter(item => !selectValue.value.includes(item.id.toString()));
+            resetSelection();
+            footerswitch.value = true; // 退出管理模式
+          } else {
+            uni.showToast({ title: message || '操作失败', icon: 'none' });
+          }
+        } catch (err) {
+          uni.showToast({ title: err.message || '操作失败', icon: 'none' });
+        }
+      }
+    }
+  });
+}
+
 const tabChange = (item) => {
   console.log('item',item)
   goodsList.value = [];
@@ -140,21 +326,29 @@ const tabChange = (item) => {
   params.value.isShow = item.code;
   params.value.page = 1;
   getGroomList();
+  // 切换标签时退出管理模式
+  footerswitch.value = true;
+  resetSelection();
 }
+
 const onSearch = () => {
   goodsList.value = [];
   loading.value = false;
   goodScroll.value = true;
   params.value.page = 1;
   getGroomList();
+  // 搜索时退出管理模式
+  footerswitch.value = true;
+  resetSelection();
 }
+
 // 清除搜索内容
 const onClear = () => {
   console.log('清除搜索内容');
-  searchVal.value = ''; // 手动清空关键词
-  // 如果需要清除后立即刷新列表,可以调用搜索
+  searchVal.value = '';
   onSearch();
 }
+
 const getGroomList = async () => {
   if (!goodScroll.value) return;
   try {
@@ -162,7 +356,14 @@ const getGroomList = async () => {
     params.value.merchantId = merchantInfo.value.id;
     params.value.keyword = searchVal.value;
     const { data } = await productsList(params.value);
-    goodsList.value = [...goodsList.value, ...data.list] || [];
+
+    // 初始化选择状态
+    const newList = data.list || [];
+    newList.forEach(item => {
+      item.checked = false;
+    });
+
+    goodsList.value = [...goodsList.value, ...newList];
     goodScroll.value = data.list.length >= params.value.limit;
     params.value.page++;
   } catch (err) {
@@ -171,6 +372,7 @@ const getGroomList = async () => {
     loading.value = false;
   }
 };
+
 async function OffShellFn(obj,index) {
   const {code} = await productOffShell(obj.id);
   if(code == 200){
@@ -178,87 +380,134 @@ async function OffShellFn(obj,index) {
     goodsList.value.splice(index,1);
   }
 }
+
 async function PutOnShellFn(obj,index) {
   const {code} = await productPutOnShell(obj.id);
   if(code == 200){
     uni.showToast({ title: "操作成功", icon: "none" });
     goodsList.value.splice(index,1);
   }
-
 }
+
 function toEditProduct (obj){
   uni.navigateTo({
     url:`/pages/merchantCenters/releaseProduct?id=${obj.id}`
   })
 }
+
 async function deleteFn(obj,index){
-  const {code} = await productDelete(obj.id);
-  if(code == 200){
-    uni.showToast({ title: "操作成功", icon: "none" });
-    goodsList.value.splice(index,1);
-  }
+  uni.showModal({
+    title: '警告',
+    content: '确定要删除此商品吗?此操作不可恢复!',
+    success: async (res) => {
+      if (res.confirm) {
+        const {code} = await productDelete(obj.id);
+        if(code == 200){
+          uni.showToast({ title: "操作成功", icon: "none" });
+          goodsList.value.splice(index,1);
+        }
+      }
+    }
+  });
 }
+
 onReachBottom(() => {
   getGroomList();
 });
 </script>
 
-<style lang="scss" scoped>
+<style scoped>
+/* 管理栏样式 */
+.nav {
+  width: 100%;
+  height: 90rpx;
+  background-color: #fff;
+  padding: 0 30rpx;
+  box-sizing: border-box;
+  font-size: 28rpx;
+  color: #282828;
+  border-top: 1px solid #f0f0f0;
+  border-bottom: 1px solid #f0f0f0;
+  margin-top: 20rpx;
+}
 
-/* 搜索栏样式 */
-.search-bar {
-  background: #fff;
-  padding: 30rpx 30rpx 0;
+.nav .administrate {
+  width: 120rpx;
+  height: 50rpx;
+  border-radius: 8rpx;
+  border: 1px solid #F8C008;
+  color: #F8C008;
+  font-size: 24rpx;
 }
 
-.search-input {
+.num {
+  color: #F8C008;
+  font-weight: bold;
+  margin: 0 4rpx;
+}
+
+/* 底部操作栏样式 */
+.footer {
+  z-index: 9;
   width: 100%;
-  height: 60rpx;
+  height: 96rpx;
+  background-color: #fff;
+  position: fixed;
+  padding: 0 30rpx;
+  box-sizing: border-box;
+  border-top: 1rpx solid #eee;
+  border-bottom: 1px solid #EEEEEE;
+  bottom: 0rpx;
+}
+
+.footer .checkAll {
   font-size: 28rpx;
+  color: #282828;
+  margin-left: 16rpx;
 }
 
-/* 标签页样式 */
-.tabs {
+.footer .button {
   display: flex;
-  background: white;
-  border-radius: 10rpx;
-  margin-bottom: 20rpx;
+  gap: 20rpx;
 }
 
-.tab {
-  flex: 1;
-  text-align: center;
-  padding: 20rpx;
+.footer .button .bnt {
   font-size: 28rpx;
-  color: #666;
+  color: #333333;
+  border-radius: 8rpx;
+  background-color: #F8C008;
+  width: 180rpx;
+  height: 60rpx;
+  line-height: 60rpx;
+  text-align: center;
+  border: none;
 }
 
-.tab.active {
-  color: #333;
-  font-weight: bold;
-  border-bottom: 4rpx solid #333;
-}
-.product-list{
-  padding: 30rpx;
-  box-sizing: border-box;
+.footer .button .delete-btn {
+  background-color: #e64340;
 }
-/* 商品卡片样式 */
+
+/* 商品卡片调整 */
 .product-card {
-  background: #fff;
+  width: 100%;
+  position: relative;
+  background-color: #fff;
   border-radius: 16rpx;
   padding: 30rpx;
-  margin-bottom: 20rpx;
+  margin: 20rpx 30rpx;
+  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
 }
 
 .product-header {
   display: flex;
+  align-items: flex-start;
   margin-bottom: 20rpx;
 }
 
 .product-image {
-  width: 120rpx;
-  height: 120rpx;
-  border-radius: 10rpx;
+  width: 180rpx;
+  height: 180rpx;
+  border-radius: 12rpx;
   margin-right: 20rpx;
 }
 
@@ -266,133 +515,120 @@ onReachBottom(() => {
   flex: 1;
 }
 
-.nameweight{
+.nameweight {
   display: flex;
   justify-content: space-between;
   align-items: center;
   margin-bottom: 20rpx;
 }
+
 .product-name {
   font-size: 28rpx;
+  font-weight: bold;
   color: #333;
-  display: block;
+  flex: 1;
+  margin-right: 20rpx;
 }
+
 .product-weight {
-    background-color: rgba(197, 128, 3, 0.10);
-    color: #C58003;
-    font-size: 24rpx;
-    padding: 8rpx 16rpx;
-    border-radius: 8rpx;
-    float: right;
+  font-size: 24rpx;
+  color: #999;
+  background: #f5f5f5;
+  padding: 4rpx 12rpx;
+  border-radius: 8rpx;
 }
 
 .price-info {
   display: flex;
-  justify-content: space-between;
-  margin-bottom: 8rpx;
+  align-items: center;
+  margin-bottom: 10rpx;
 }
 
-.label {
+.price-info .label {
   font-size: 24rpx;
-  color: #666666;
+  color: #666;
+  margin-right: 10rpx;
+  min-width: 60rpx;
 }
 
-.value {
-  color: #FD5F3C;
-  font-size: 32rpx;
-  .unit{
-    font-size: 24rpx;
-  }
+.price-info .value {
+  font-size: 28rpx;
+  color: #e64340;
+  font-weight: bold;
+}
+
+.price-info .unit {
+  font-size: 20rpx;
 }
 
-/* 销售数据样式 */
 .product-stats {
   display: flex;
-  margin-bottom: 20rpx;
-  gap: 10rpx;
+  gap: 30rpx;
+  margin-top: 10rpx;
 }
 
-.stat {
+.product-stats .stat {
   font-size: 24rpx;
-  color: #666;
-  padding: 10rpx;
-  background-color: #F5F7FA;
-  border-radius: 8rpx;
+  color: #999;
 }
 
-/* 操作按钮样式 */
 .action-buttons {
   display: flex;
-  justify-content: space-between;
-  gap: 30rpx;
+  justify-content: flex-start;
+  align-items: center;
+  gap: 20rpx;
+  padding-top: 20rpx;
+  border-top: 1rpx solid #f0f0f0;
 }
 
 .btn {
+  font-size: 28rpx;
+  border-radius: 8rpx;
+  background: transparent;
   flex: 1;
   height: 60rpx;
   line-height: 60rpx;
-  border-radius: 8rpx;
-  font-size: 28rpx;
-  border: none;
 }
 
 .btn-delete {
-  background: #FEEAEA;
   color: #F52929;
+  background-color: #FEEAEA;
 }
+
 .btn-offline {
-  background: #F5F7FA;
-  color: #333;
+  color: #333333;
+  background-color: #F5F7FA;
 }
 
 .btn-edit {
-  background: #F8C008;
-  color: #333;
+  color: #333333;
+  background-color: #F8C008;
 }
-.no-data {
-  margin: 150rpx auto 0;
-  text-align: center;
 
-  img {
-    width: 65%;
-    height: auto;
-  }
+/* 搜索栏样式 */
+.search-bar {
+  background-color: #fff;
+  position: sticky;
+  top: 0;
+  z-index: 100;
+  padding: 20rpx 30rpx 0;
 }
-.mores-txt {
-  width: 100%;
-  align-items: center;
-  justify-content: center;
-  height: 70rpx;
-  color: #999;
-  font-size: 24rpx;
 
-  .iconfont {
-    margin-top: 2rpx;
-    font-size: 20rpx;
-  }
-}
 .search-bar-con {
-  display: flex;
-  align-items: center;
-  background-color: #fff;
-  border-bottom: 1rpx solid #eee;
+  padding-bottom: 20rpx;
 }
 
 .search-input-wrapper {
-  flex: 1;
-  position: relative;
   display: flex;
   align-items: center;
-  background-color: #F9F7F0;
-  border-radius: 16rpx;
-  height: 72rpx;
-  line-height: 72rpx;
+  background-color: #f5f5f5;
+  border-radius: 50rpx;
   padding: 0 20rpx;
-  box-sizing: border-box;
+  height: 70rpx;
 }
 
 .search-icon {
-  margin-right: 20rpx;
+  margin-right: 10rpx;
 }
 
 .search-input {
@@ -408,8 +644,44 @@ onReachBottom(() => {
 }
 
 .clear-btn {
-  padding: 10rpx;
+  width: 40rpx;
+  height: 40rpx;
+  border-radius: 50%;
+  background: #e0e0e0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
   margin-left: 10rpx;
 }
 
+/* 加载状态 */
+.loadingicon {
+  text-align: center;
+  color: #999;
+  font-size: 24rpx;
+  padding: 30rpx 0;
+}
+
+/* 无数据状态 */
+.no-data {
+  display: flex;
+  justify-content: center;
+  padding: 100rpx 0;
+}
+
+.no-data image {
+  width: 300rpx;
+  height: 300rpx;
+}
+
+.mores-txt {
+  text-align: center;
+  color: #999;
+  font-size: 24rpx;
+  padding: 30rpx 0 60rpx;
+  border-top: 1rpx solid #f0f0f0;
+  margin-top: 20rpx;
+  align-items: center;
+  justify-content: center;
+}
 </style>

+ 93 - 72
pages/users/my_merchant/index.vue

@@ -1,25 +1,24 @@
 <template>
   <view class="container">
     <!-- 商家信息卡片 -->
-    <view class="merchant-card">
-      <view class="merchant-info">
-        <image class="merchant-logo" :src="merchantInfo.merchantLogo" mode="aspectFill"></image>
-        <view class="merchant-detail">
-          <view class="merchant-name">{{merchantInfo.merchantName}}</view>
-
+    <view class="store-card">
+      <view class="info-top">
+        <view class="left">
+          <image class="storeImg" :src="merchantInfo.merchantLogo" mode="aspectFit"></image>
         </view>
-        <view class="share-btn" @click="to_share">
-          <image :src="HTTP_REQUEST_URL_IMG+'share.png'" mode="aspectFit"></image>
-          <text>分享店铺</text>
+        <view class="center">
+          <view class="name">{{merchantInfo.merchantName}}</view>
+        </view>
+        <view class="right" @click="to_share">
+          <image class="share" src="@/static/images/share.png" mode="widthFix"></image>
+          <view>分享</view>
         </view>
       </view>
-      <view class="merchant-phone">
-        <image src="@/static/images/phone.png" mode="aspectFit"></image>
-        <text>{{ merchantInfo.merchantPhone }}</text>
-      </view>
-      <!-- 商家描述 -->
-      <view class="merchant-desc">
-        <text>{{ merchantInfo.merchantDescribe }}</text>
+      <view class="desc">{{merchantInfo.merchantDescribe}}</view>
+      <view class="tel" @click="makePhoneCall">
+        <image class="phone mr20" src="@/static/images/phone2.png" mode="widthFix"></image>
+        <text>联系电话:{{merchantInfo.merchantPhone}}</text>
+        <image class="phone fr" src="@/static/images/phoneyellow.png" mode="widthFix"></image>
       </view>
     </view>
 
@@ -34,7 +33,7 @@
       </view>
 
       <!-- 客服按钮 -->
-      <button class="service-btn" @click="onContactService">在线客服</button>
+<!--      <button class="service-btn" @click="onContactService">在线客服</button>-->
     </view>
   </view>
 </template>
@@ -92,6 +91,41 @@ const to_share = () => {
     toLogin();
   }
 }
+
+// 在methods部分添加:
+const makePhoneCall = () => {
+  if (!merchantInfo.value.merchantPhone) {
+    uni.showToast({
+      title: '暂无联系电话',
+      icon: 'none'
+    });
+    return;
+  }
+
+  // 显示确认弹窗
+  uni.showModal({
+    title: '拨打电话',
+    content: `是否拨打 ${merchantInfo.value.merchantPhone}?`,
+    success: (res) => {
+      if (res.confirm) {
+        // 调用拨打电话API
+        uni.makePhoneCall({
+          phoneNumber: merchantInfo.value.merchantPhone,
+          success: () => {
+            console.log('拨打电话成功');
+          },
+          fail: (err) => {
+            console.log('拨打电话失败:', err);
+            uni.showToast({
+              title: '拨打电话失败',
+              icon: 'none'
+            });
+          }
+        });
+      }
+    }
+  });
+};
 </script>
 
 <style scoped lang="scss">
@@ -134,78 +168,62 @@ const to_share = () => {
 }
 
 /* 商家卡片 */
-.merchant-card {
+.store-card{
+  background: #ffffff;
+  border-radius: 16rpx;
   padding: 20rpx;
-  background-color: #fff;
-  border-radius: 24rpx;
-  position: relative;
+  margin-bottom: 10rpx;
 
-  .merchant-info {
+  .info-top{
     display: flex;
+    justify-content: space-around;
     align-items: center;
-    margin-bottom: 20rpx;
-
-    .merchant-logo {
-      width: 160rpx;
-      height: 160rpx;
-      border-radius: 8rpx;
-      margin-right: 30rpx;
+    background-color: #F9F7F0;
+    border-radius: 16rpx;
+    .left{
+      width: 140rpx;
+      .storeImg{
+        width: 100rpx;
+        height: 100rpx;
+      }
     }
-
-    .merchant-detail {
-      flex: 1;
-
-      .merchant-name {
-        font-size: 28rpx;
-        font-weight: bold;
-        color: #333;
-        margin-bottom: 20rpx;
+    .center{
+      width: 50%;
+      .name{
+        font-size: 32rpx;
+        color: #333;line-height: 60rpx;
       }
 
-
     }
-
-    .share-btn {
-      position: absolute;
-      top: 30rpx;
-      right: 30rpx;
+    .right{
+      width: 10%;
+      font-size: 20rpx;
+      color: #333;
       display: flex;
-      align-items: center;
-      color: #666;
-      font-size: 28rpx;
-
-      image {
-        width: 36rpx;
-        height: 36rpx;
-        margin-right: 10rpx;
+      flex-direction:column;
+      justify-content: center;
+      align-items: flex-end;
+      .share{
+        width: 40rpx;
       }
     }
   }
-  .merchant-phone {
-    display: flex;
-    align-items: center;
+  .desc{
+    font-size: 24rpx;
     color: #666;
-    font-size: 28rpx;
-    margin-bottom: 20rpx;
-
-    image {
-      width: 36rpx;
-      height: 36rpx;
-      margin-right: 10rpx;
-    }
+    line-height: 40rpx;
+    padding: 20rpx 0;
   }
-  .merchant-desc {
-    width: 100%;
-    padding: 30rpx;
+  .tel{
     font-size: 28rpx;
-    color: #333;
-    background-color: #f9f9f9;
-    border-radius: 20rpx;
-    border: 2rpx solid #eee;
-    margin-bottom: 20rpx;
+    color:#333;
+    line-height: 40rpx;
+    .phone{
+      width: 34rpx;
+      vertical-align: middle;
+    }
   }
 }
-
 /* 联系商家部分 */
 .contact-section {
   margin-top: 30rpx;
@@ -255,4 +273,7 @@ const to_share = () => {
     }
   }
 }
+.fr{
+  float: right;
+}
 </style>

+ 10 - 9
pages/users/user_goods_collection/index.vue

@@ -12,7 +12,7 @@
       <view class="list">
         <up-checkbox-group shape="circle" @change="checkboxChange" class="centent" activeColor="#ffe079">
           <view v-for="(item,index) in collectProductList" :key="index" class='item acea-row row-middle' style="width: 100%;">
-            <up-checkbox :value="item.id.toString()" :checked="item.checked" v-if="!footerswitch"
+            <up-checkbox :name="item.id.toString()" :checked="item.checked" v-if="!footerswitch"
                       style="margin-right: 10rpx;" activeColor="#ffe079" />
             <navigator :url='"/pages/goods/goods_details/index?id="+item.productId' hover-class='none'
                        class="acea-row">
@@ -33,13 +33,13 @@
       <view v-if="!footerswitch" class='footer acea-row row-between-wrapper'>
         <view>
           <up-checkbox-group shape="circle" @change="checkboxAllChange">
-            <up-checkbox value="all" :checked="!!isAllSelect" />
+            <up-checkbox value="all" :checked="!!isAllSelect" activeColor="#ffe079"  />
             <text class='checkAll'>全选</text>
           </up-checkbox-group>
         </view>
         <view class='button acea-row row-middle'>
           <form @submit="delCollectionAll" report-submit='true'>
-            <button class='bnt cart-color' formType="submit">取消收藏</button>
+            <button class='bnt' formType="submit">取消收藏</button>
           </form>
         </view>
       </view>
@@ -148,7 +148,7 @@ const checkboxChange = (event) => {
 
 // 全选变化
 const checkboxAllChange = (event) => {
-  if (event.detail.value.length > 0) {
+  if (event.length > 0) {
     setAllSelectValue(1);
   } else {
     setAllSelectValue(0);
@@ -442,13 +442,14 @@ onReachBottom(() => {
 
   .button .bnt {
     font-size: 28rpx;
-    color: #999;
-    border-radius: 30rpx;
-    border: 1px solid #999;
-    width: 160rpx;
+    color: #333333;
+    border-radius: 8rpx;
+    background-color: #F8C008;
+    width: 180rpx;
     height: 60rpx;
-    text-align: center;
     line-height: 60rpx;
+    text-align: center;
+    border: none;
   }
 }
 </style>

BIN
static/images/share.png