wzh преди 4 месеца
родител
ревизия
4c237ebbea

+ 138 - 8
api/hexiao.js

@@ -1,4 +1,5 @@
 import request from '@/utils/requestAdmin'
+import {uploadImageToServer} from "../utils/requestAdmin";
 
 
 //返送验证码
@@ -32,18 +33,60 @@ export function getAdminUserInfo(){
     })
 }
 
-export function getQrcodeNum(code){
+export function getQrcodeNum(code,type){
     return request({
         url: `/ywy/getQrcodeNum`,
         method: 'post',
         params: {
-            qrCode:code
+            qrCode:code,
+            operationType:type
         }
     })
 }
 
 
+export function doCommitToJxs(id){
+    return request({
+        url: `/ywy/writeOffSubmit`,
+        method: 'post',
+        params: {
+            orderId:id
+        }
+    })
+}
 
+export function parseLocation(latitute,longitute){
+    return request({
+        url: `/miniapp/getLocation`,
+        method: 'post',
+        data: {
+            latitute: latitute,
+            longitute: longitute
+        }
+    })
+}
+
+export function xundianRecord(pageIndex,pageSize,storeName){
+    return request({
+        url: `/ywy/queryXunJi`,
+        method: 'post',
+        params: {
+            pageIndex:pageIndex,
+            pageSize:pageSize,
+            storeName:storeName
+        }
+    })
+}
+
+export function doCommitToChang(id){
+    return request({
+        url: `/jxs/writeOffSubmit`,
+        method: 'post',
+        params: {
+            orderId:id
+        }
+    })
+}
 export function active(data){
     return request({
         url: `/ywy/active`,
@@ -52,6 +95,14 @@ export function active(data){
     })
 }
 
+export function writeOff(data){
+    return request({
+        url: `/ywy/writeOff`,
+        method: 'post',
+        data: data
+    })
+}
+
 
 export function getRetailDetail(id){
     return request({
@@ -87,7 +138,7 @@ export function getStoreList(pageIndex,pageSize,storeName){
     })
 }
 
-export function addStore(store_name,contact_name,contact_phone,address){
+export function addStore(store_name,contact_name,contact_phone,address,store_photo){
     return request({
         url: `/store/save`,
         method: 'post',
@@ -95,12 +146,13 @@ export function addStore(store_name,contact_name,contact_phone,address){
             store_name:store_name,
             contact_name:contact_name,
             contact_phone:contact_phone,
-            address:address
+            address:address,
+            store_photo:store_photo
         }
 
     })
 }
-export function updateStore(id,store_name,contact_name,contact_phone,address){
+export function updateStore(id,store_name,contact_name,contact_phone,address,  store_photo){
     return request({
         url: `/store/update`,
         method: 'post',
@@ -109,7 +161,8 @@ export function updateStore(id,store_name,contact_name,contact_phone,address){
             store_name:store_name,
             contact_name:contact_name,
             contact_phone:contact_phone,
-            address:address
+            address:address,
+            store_photo:store_photo
         }
 
     })
@@ -120,18 +173,76 @@ export function updateStore(id,store_name,contact_name,contact_phone,address){
  * @param pageSize
  * @returns {*}
  */
-export function queryActiveRecord(pageIndex,pageSize){
+export function queryActiveRecord(pageIndex,pageSize,storeName,startTime,endTime){
     return request({
         url: `/ywy/queryActiveRecord`,
         method: 'post',
         params: {
             pageIndex:pageIndex,
-            pageSize:pageSize
+            pageSize:pageSize,
+            storeName,
+            startTime,
+            endTime
         }
     })
 }
 
+/**
+ * 查询上货记录
+ * @param pageIndex
+ * @param pageSize
+ * @returns {*}
+ */
+export function queryAddRecord(data){
+    return request({
+        url: `/ywy/writeOffRecord`,
+        method: 'post',
+        data: data
+    });
+}
+
+/**
+ * 核销记录的明细
+ * @param id
+ * @returns {*}
+ */
+export function queryAddRecordDetail(id){
+    return request({
+        url: `/ywy/queryWriteOffDetail`,
+        method: 'post',
+        params: {
+            orderNo:id
+        }
+    })
+}
+
+/**
+ * 经销商核销记录
+ * @param id
+ * @returns {*}
+ */
+export function queryJxsAddRecord(data){
+    return request({
+        url: `/jxs/writeOffRecord`,
+        method: 'post',
+        data: data
+    });
+}
 
+/**
+ * 经销商核销记录
+ * @param id
+ * @returns {*}
+ */
+export function queryJxsAddRecordDetail(id){
+    return request({
+        url: `/jxs/queryWriteOffDetail`,
+        method: 'post',
+        params: {
+            orderNo:id
+        }
+    })
+}
 
 
 export function ywyList(keyword){
@@ -186,6 +297,25 @@ export function getYwyByIdDetail(id){
     })
 }
 
+export  async function uploadImage(files){
+    const arr = []
+    for(let i=0;i<files.length;i++){
+        let url = files[i].path;
+        let res =  await uploadImageToServer(url);
+        arr.push(res);
+    }
+    return arr;
+}
+
+
+export function addPatrolRecord(data){
+    return request({
+        url: `/ywy/addXunStore`,
+        method: 'post',
+        data: data
+    })
+}
+
 /**
  * 经销商销售总数查询
  * @param startDate

+ 9 - 1
manifest.json

@@ -55,7 +55,15 @@
             "urlCheck" : false,
             "minified" : true
         },
-        "usingComponents" : true
+        "usingComponents" : true,
+        "permission" : {
+            "scope.userLocation" : {
+                "desc" : "需要巡店的获取实时位置"
+            }
+        },
+		"requiredPrivateInfos": [
+		        "getLocation"
+		    ]
     },
     "mp-alipay" : {
         "usingComponents" : true

+ 58 - 1
pages.json

@@ -251,6 +251,22 @@
 				"enablePullDownRefresh" : false
 			}
 		},
+	{
+		"path" : "pages/cjx/hexiao/jxs/hexiao_record",
+		"style" :
+		{
+			"navigationBarTitleText" : "核销记录",
+			"enablePullDownRefresh" : false
+		}
+	},
+	{
+		"path" : "pages/cjx/hexiao/jxs/hexiao_detail",
+		"style" :
+		{
+			"navigationBarTitleText" : "核销详情",
+			"enablePullDownRefresh" : false
+		}
+	},
 		{
 			"path" : "pages/cjx/hexiao/jxs/add_ywy",
 			"style" :
@@ -265,15 +281,56 @@
 			{
 				"navigationBarTitleText" : "",
 				"navigationStyle": "custom"
+
 			}
 		},
 		{
 			"path" : "pages/cjx/xiaoshou/index",
-			"style" : 
+			"style" :
 			{
 				"navigationBarTitleText" : "",
 				"navigationStyle": "custom"
 			}
+		},
+		{
+			"path" : "pages/cjx/shop/shop",
+			"style" :
+			{
+				"navigationBarTitleText" : "商城",
+				"enablePullDownRefresh" : false
+			}
+		},
+		{
+			"path" : "pages/cjx/hexiao/ywy/add_patrol",
+			"style" :
+			{
+				"navigationBarTitleText" : "巡店记录",
+				"enablePullDownRefresh" : false
+			}
+		},
+		{
+			"path" : "pages/cjx/hexiao/ywy/patrol_record",
+			"style" :
+			{
+				"navigationBarTitleText" : "巡店记录",
+				"enablePullDownRefresh" : false
+			}
+		},
+		{
+			"path" : "pages/cjx/hexiao/ywy/hexiao_record",
+			"style" :
+			{
+				"navigationBarTitleText" : "",
+				"enablePullDownRefresh" : false
+			}
+		},
+		{
+			"path" : "pages/cjx/hexiao/ywy/hexiao_detail",
+			"style" : 
+			{
+				"navigationBarTitleText" : "核销详情",
+				"enablePullDownRefresh" : false
+			}
 		}
 
 	],

+ 209 - 0
pages/cjx/hexiao/jxs/hexiao_detail.vue

@@ -0,0 +1,209 @@
+<template>
+  <view class="page-container">
+    <view class="info-card">
+      <view class="info-row">
+        <text class="info-label">核销门店</text>
+        <text class="info-value">{{ recordInfo.storeName }}</text>
+      </view>
+      <view class="info-row">
+        <text class="info-label">核销时间</text>
+        <text class="info-value">{{ recordInfo.verificationTime }}</text>
+      </view>
+    </view>
+
+    <view class="summary-card">
+      <view
+          class="summary-tab"
+          v-for="item in summaryData"
+          :key="item.key"
+      >
+        <text class="tab-category">{{ item.category }}</text>
+        <text class="tab-count">{{ item.count }}{{ item.unit }}</text>
+      </view>
+    </view>
+
+    <scroll-view class="details-list" scroll-y="true" @scrolltolower="loadMore">
+      <view v-if="detailsList.length === 0 && loadStatus !== 'loading'" class="empty-tip">
+        暂无明细记录
+      </view>
+      <view v-for="(item, index) in detailsList" :key="index" class="detail-item-card">
+        <text class="item-name">{{ item.name }}</text>
+        <text class="item-code">扫码编号:{{ item.code }}</text>
+      </view>
+      <uni-load-more :status="loadStatus"></uni-load-more>
+    </scroll-view>
+  </view>
+</template>
+
+<script>
+import {queryAddRecordDetail} from "@/api/hexiao";
+
+export default {
+  data() {
+    return {
+      id:"",
+      // 总览信息
+      recordInfo: {
+        storeName: '湖南长沙超吉炫旗舰店',
+        verificationTime: '2025-08-11 09:30:00',
+      },
+      // 分类汇总数据
+      summaryData: [
+        { category: '10元槟榔', count: 20, unit: '袋', key: 'product_10' },
+        { category: '20元槟榔', count: 20, unit: '袋', key: 'product_20' },
+        { category: '30元槟榔', count: 20, unit: '袋', key: 'product_30' },
+        { category: '能量饮料', count: 20, unit: '罐', key: 'product_drink' },
+      ],
+      // 所有明细的列表
+      detailsList: [],
+      // 分页加载相关
+      pagination: { page: 1, limit: 15 },
+      loadStatus: 'more', // 'more', 'loading', 'noMore'
+      isLoading: false,
+    };
+  },
+  onLoad(opt) {
+    // 页面加载时,获取第一页数据
+    // options.id 可以用来从上个页面传递记录ID
+    this.id = opt.id
+    this.getDetail(true);
+  },
+  onPullDownRefresh() {
+    this.fetchDetails(true);
+  },
+  methods: {
+    getDetail(){
+      queryAddRecordDetail(this.id).then(res=>{
+        debugger;
+      })
+    },
+    // 模拟从API获取明细数据
+    async fetchDetails(isRefresh = false) {
+      if (this.isLoading || (this.loadStatus === 'noMore' && !isRefresh)) {
+        return;
+      }
+      if (isRefresh) {
+        this.pagination.page = 1;
+        this.detailsList = [];
+        this.loadStatus = 'more';
+      }
+      this.isLoading = true;
+      this.loadStatus = 'loading';
+
+      console.log(`请求第 ${this.pagination.page} 页明细...`);
+      await new Promise(resolve => setTimeout(resolve, 1000));
+
+      const mockData = Array.from({ length: this.pagination.limit }, (_, i) => {
+        const id = (this.pagination.page - 1) * this.pagination.limit + i + 1;
+        return {
+          name: `超吉炫10元精制槟榔 - ${id}`,
+          code: `BH2025010020${String(id).padStart(3, '0')}`
+        };
+      });
+      const noMoreData = this.pagination.page >= 5; // 模拟加载4页后没有更多
+
+      uni.stopPullDownRefresh();
+      if (mockData.length > 0 && !noMoreData) {
+        this.detailsList = [...this.detailsList, ...mockData];
+        this.pagination.page++;
+        this.loadStatus = 'more';
+      } else {
+        this.loadStatus = 'noMore';
+      }
+      this.isLoading = false;
+    },
+    // 滚动到底部加载更多
+    loadMore() {
+      this.fetchDetails();
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.page-container {
+  display: flex;
+  flex-direction: column;
+  height: 100vh;
+  background-color: #f5f6fa;
+}
+
+.info-card {
+  background-color: #ffffff;
+  border-radius: 16rpx;
+  margin: 20rpx;
+  padding: 20rpx 30rpx;
+  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
+}
+
+.info-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  font-size: 28rpx;
+  padding: 15rpx 0;
+  .info-label { color: #666; }
+  .info-value { color: #333; }
+}
+
+.summary-card {
+  display: flex;
+  justify-content: space-around;
+  background: linear-gradient(to right, #6ca1ff, #3c82f8);
+  border-radius: 16rpx;
+  margin: 0 20rpx 20rpx;
+  padding: 20rpx 10rpx;
+  color: #ffffff;
+}
+
+.summary-tab {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 10rpx;
+
+  .tab-category {
+    font-size: 26rpx;
+    opacity: 0.9;
+  }
+  .tab-count {
+    font-size: 28rpx;
+    font-weight: bold;
+    margin-top: 10rpx;
+  }
+}
+
+.details-list {
+  flex: 1;
+  height: 100%;
+  padding: 0 20rpx;
+}
+
+.empty-tip {
+  text-align: center;
+  color: #999;
+  padding-top: 100rpx;
+}
+
+.detail-item-card {
+  background-color: #ffffff;
+  border-radius: 16rpx;
+  padding: 30rpx;
+  margin-bottom: 20rpx;
+  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
+
+  .item-name {
+    display: block;
+    font-size: 30rpx;
+    font-weight: bold;
+    color: #333;
+  }
+
+  .item-code {
+    display: block;
+    font-size: 26rpx;
+    color: #999;
+    margin-top: 15rpx;
+  }
+}
+</style>

+ 392 - 0
pages/cjx/hexiao/jxs/hexiao_record.vue

@@ -0,0 +1,392 @@
+<template>
+  <view class="page-container">
+    <view class="sticky-header">
+      <view class="search-wrapper">
+        <view class="query">
+          <u-row customStyle="margin-bottom: 10px" gutter="20">
+            <u-col span="9">
+              <u--input
+                  @focus="timeShow = true"
+                  v-model="startTimeXd"
+                  placeholder="开始日期 ~ 结束日期"
+                  prefixIcon="calendar"
+                  prefixIconStyle="font-size: 22px;color: #909399"
+                  @clear="handleSearch"
+              ></u--input>
+            </u-col>
+            <u-col span="3">
+              <view class="query-btn" @click="clearSearch">
+                <view class="query-btn-text">清空</view>
+              </view>
+            </u-col>
+          </u-row>
+        </view>
+      </view>
+      <view class="tabs-wrapper">
+        <view
+            v-for="tab in tabs"
+            :key="tab.key"
+            class="tab-item"
+            :class="{ 'active': currentTab === tab.id }"
+            @click="changeTab(tab.id)"
+        >
+          {{ tab.name }}
+        </view>
+      </view>
+    </view>
+
+    <scroll-view class="list-container" scroll-y="true" @scrolltolower="loadMore">
+      <view v-if="recordList.length === 0 && loadStatus !== 'loading'" class="empty-list">
+        <text>暂无相关记录</text>
+      </view>
+
+      <view v-for="record in recordList" :key="record.orderNo" class="record-card">
+        <view class="card-header">
+          <uni-icons type="paperclip" size="20" color="#3c82f8"></uni-icons>
+          <text class="record-id" @click="detail(record.id)" style="text-decoration: underline">{{ record.orderNo }}</text>
+          <view class="status-badge pending" v-if="record.status === 0">
+            {{ getStatusText(record.status) }}
+          </view>
+          <view class="status-badge verifying"  v-if="record.status === 1">
+            {{ getStatusText(record.status) }}
+          </view>
+          <view class="status-badge verified"  v-if="record.status === 2">
+            {{ getStatusText(record.status) }}
+          </view>
+        </view>
+
+        <view class="card-body">
+          <view class="detail-row">
+            <text class="detail-label">待核销商品总数</text>
+            <text class="detail-value">{{ record.writeOffNum }}</text>
+          </view>
+          <view class="detail-row product-item" v-for="(item, index) in record.writeOffRecordDetailVos" :key="index">
+            <text class="detail-label">{{ item.categoryName }}</text>
+            <text class="detail-value">{{ item.num }}</text>
+          </view>
+
+          <view class="detail-row" v-if="record.applicationTime">
+            <text class="detail-label">申请时间</text>
+            <text class="detail-value">{{ record.applicationTime }}</text>
+          </view>
+
+          <view class="detail-row" v-if="record.verificationTime">
+            <text class="detail-label">核销时间</text>
+            <text class="detail-value">{{ record.verificationTime }}</text>
+          </view>
+        </view>
+
+        <view class="card-footer" v-if="record.status === 1">
+          <button class="verify-btn" @click="verify(record.id,record.orderNo)">一键核销</button>
+        </view>
+      </view>
+
+      <uni-load-more :status="loadStatus"></uni-load-more>
+    </scroll-view>
+    <u-calendar @close="timeShow = false" :show="timeShow" :mode="mode" @confirm="confirm"></u-calendar>
+
+  </view>
+</template>
+
+<script>
+import {queryJxsAddRecord,doCommitToJxs} from "@/api/hexiao";
+import {doCommitToChang} from "../../../../api/hexiao";
+
+export default {
+  data() {
+    return {
+      startTime: '',
+      endTime: '',
+      timeShow: false,
+      startTimeXd:"",
+      mode: 'range',
+      searchQuery: '',
+      tabs: [
+        { name: '全部', key: 'all' ,id:-1 },
+        { name: '待核销', key: 'pending',id: 1 },
+        { name: '核销中', key: 'verifying', id: 2},
+        { name: '已核销', key: 'verified' , id :3},
+      ],
+      currentTab: -1,
+      recordList: [],
+      pagination: { page: 1, limit: 10 },
+      loadStatus: 'more', // 'more', 'loading', 'noMore'
+      isLoading: false,
+    };
+  },
+  onLoad() {
+    this.fetchRecords(true);
+  },
+  onPullDownRefresh() {
+    this.fetchRecords(true);
+  },
+  methods: {
+    confirm(e) {
+      this.startTime = e[0];
+      this.endTime = e[e.length-1];
+      this.startTimeXd = e[0]+' ~ '+e[e.length-1];
+      if(!this.show){
+        this.handleSearch()
+      }
+      this.timeShow = false;
+
+    },
+    getStatusClass(status){
+      const statusMap = {
+        1: 'pending',
+        2: 'verifying',
+        3: 'verified'
+      };
+      return statusMap[status] || '';
+    },
+    getStatusText(status) {
+      const statusMap = {
+        1: '待核销',
+        2: '核销中',
+        3: '已核销'
+      };
+      return statusMap[status] || '未知';
+    },
+    changeTab(tabKey) {
+      if (this.currentTab === tabKey) return;
+      this.currentTab = tabKey;
+      this.fetchRecords(true); // 切换tab时重新加载数据
+    },
+    async fetchRecords(isRefresh = false) {
+      if (this.isLoading || (this.loadStatus === 'noMore' && !isRefresh)) {
+        return;
+      }
+      if (isRefresh) {
+        this.pagination.page = 1;
+        this.recordList = [];
+        this.loadStatus = 'more';
+      }
+      this.isLoading = true;
+      this.loadStatus = 'loading';
+
+
+      let data = {};
+      if(this.currentTab !== -1){
+        data.status = this.currentTab;
+      }
+      data.startTime = this.startTime;
+      data.endTime = this.endTime;
+      data.pageIndex = this.pagination.page
+      data.pageSize = this.pagination.limit
+      queryJxsAddRecord(data).then(res=>{
+        let finalData = res.data.records;
+        if(!finalData){
+          finalData = [];
+        }
+        if (finalData.length > 0) {
+          this.recordList = [...this.recordList, ...finalData];
+          this.pagination.page++;
+          this.loadStatus = 'more';
+        } else {
+          this.loadStatus = 'noMore';
+        }
+        this.isLoading = false;
+        uni.stopPullDownRefresh();
+      });
+
+
+
+    },
+    detail(id){
+      uni.navigateTo({ url: `/pages/cjx/hexiao/jxs/hexiao_detail?id=`+id });
+    },
+    loadMore() {
+      this.fetchRecords();
+    },
+    clearSearch(){
+      this.startTime = "";
+      this.endTime = "";
+      this.startTimeXd = "";
+      this.handleSearch()
+    },
+    handleSearch() {
+      this.fetchRecords(true);
+    },
+    verify(id,orderNo) {
+      uni.showModal({
+        title: '提示',
+        content: `确认核销订单 ${orderNo} 吗?`,
+        success: (res) => {
+          if (res.confirm) {
+            doCommitToChang(id).then(res=>{
+              if(res.code === 0){
+                this.fetchRecords(true);
+                uni.showToast({ title: '核销成功' });
+              }else{
+                uni.showToast({ title: '核销失败' });
+              }
+
+            });
+          }
+        }
+      });
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.page-container {
+  display: flex;
+  flex-direction: column;
+  height: 100vh;
+  background-color: #f5f6fa;
+}
+
+.sticky-header {
+  position: sticky;
+  top: 0;
+  z-index: 100;
+  background-color: #f5f6fa;
+}
+.search-wrapper {
+  padding: 20rpx;
+  background-color: #ffffff;
+}
+.search-bar {
+  display: flex;
+  align-items: center;
+  background-color: #f5f6fa;
+  border-radius: 50rpx;
+  padding: 0 25rpx;
+  height: 70rpx;
+}
+.search-input { flex: 1; font-size: 28rpx; margin-left: 15rpx; }
+.placeholder { color: #b0b0b0; }
+
+.tabs-wrapper {
+  display: flex;
+  background-color: #ffffff;
+  border-bottom: 1rpx solid #f0f0f0;
+  .tab-item {
+    flex: 1;
+    text-align: center;
+    padding: 25rpx 0;
+    font-size: 28rpx;
+    color: #666;
+    position: relative;
+    &.active {
+      color: #3c82f8;
+      font-weight: 500;
+      &::after {
+        content: '';
+        position: absolute;
+        bottom: 0;
+        left: 50%;
+        transform: translateX(-50%);
+        width: 60rpx;
+        height: 6rpx;
+        background-color: #3c82f8;
+        border-radius: 3rpx;
+      }
+    }
+  }
+}
+
+.list-container {
+  flex: 1;
+  height: 100%;
+}
+.empty-list { text-align: center; color: #999; padding-top: 150rpx; }
+
+.record-card {
+  background-color: #ffffff;
+  border-radius: 16rpx;
+  margin: 20rpx;
+  padding: 30rpx;
+  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
+  position: relative;
+}
+
+.card-header {
+  display: flex;
+  align-items: center;
+  padding-bottom: 20rpx;
+  border-bottom: 1rpx solid #f5f5f5;
+  .record-id {
+    font-size: 30rpx;
+    font-weight: bold;
+    color: #333;
+    margin-left: 15rpx;
+  }
+}
+
+.status-badge {
+  position: absolute;
+  top: 0;
+  right: 0;
+  padding: 8rpx 20rpx;
+  font-size: 24rpx;
+  color: #fff;
+  border-top-right-radius: 16rpx;
+  border-bottom-left-radius: 16rpx;
+
+  &.pending { background-color: #3c82f8; }
+  &.verifying { background-color: #ff9900; }
+  &.verified { background-color: #909399; }
+}
+
+.card-body {
+  padding-top: 10rpx;
+}
+.detail-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 12rpx 0;
+  font-size: 28rpx;
+  .detail-label { color: #666; }
+  .detail-value { color: #333; }
+  &.product-item {
+    .detail-label { color: #333; }
+    .detail-value { color: #999; }
+  }
+}
+
+.card-footer {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 20rpx;
+}
+.verify-btn {
+  background-color: #3c82f8;
+  color: #fff;
+  font-size: 26rpx;
+  padding: 0 30rpx;
+  height: 60rpx;
+  line-height: 60rpx;
+  border-radius: 30rpx;
+  margin: 0;
+  &::after { border: none; }
+}
+
+.query-btn {
+  background-color: #409eff;
+  color: #fff;
+  padding: 20rpx;
+  border-radius: 10rpx;
+  height: 34rpx;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.query-btn-icon {
+  height: 32rpx;
+  width: 32rpx;
+  background-image:
+      url("https://hyscancode.oss-cn-hangzhou.aliyuncs.com/xiaochengxu/cjx/queryIoc.png");
+  background-size: cover;
+  background-position: center;
+  background-repeat: no-repeat;
+}
+.query-btn-text {
+  font-weight: 400;
+  font-size: 30rpx;
+  color: #F5F5F5;
+}
+</style>

+ 4 - 0
pages/cjx/hexiao/jxs/index.vue

@@ -134,6 +134,10 @@ export default {
         uni.navigateTo({ url: `/pages/cjx/hexiao/jxs/ywy_list` });
         return;
       }
+      if("patrolRecords" === page){
+        uni.navigateTo({ url: `/pages/cjx/hexiao/jxs/hexiao_record` });
+        return;
+      }
       if("stockRecords" === page){
         uni.navigateTo({ url: `/pages/cjx/hexiao/ywy/add_goods_record` });
       }else{

+ 4 - 1
pages/cjx/hexiao/jxs/ywy_list.vue

@@ -154,7 +154,10 @@ export default {
         success: () => uni.showToast({ title: '已复制' })
       });
     },
-    goToStores(id) { console.log('查看门店列表 ID:', id); this.build()},
+    goToStores(id) {
+
+
+    },
     viewSalesData(id) { console.log('查看销售数据 ID:', id); this.build() },
     editSalesperson(id) {
       uni.navigateTo({ url: '/pages/cjx/hexiao/jxs/add_ywy?id='+id });

+ 0 - 1
pages/cjx/hexiao/login.vue

@@ -81,7 +81,6 @@ export default {
   },
   onLoad(){
     let token = getAdminToken()
-    debugger;
     if(token){
       this.doLoginSuccess();
     }

+ 147 - 17
pages/cjx/hexiao/ywy/add_goods_record.vue

@@ -1,18 +1,29 @@
 <template>
   <view class="page-container">
-<!--    <view class="search-wrapper">-->
-<!--      <view class="search-bar">-->
-<!--        <uni-icons type="search" size="20" color="#999"></uni-icons>-->
-<!--        <input-->
-<!--            class="search-input"-->
-<!--            v-model="searchQuery"-->
-<!--            placeholder="输入门店名称/上货日期搜索"-->
-<!--            placeholder-class="placeholder"-->
-<!--            confirm-type="search"-->
-<!--            @confirm="handleSearch"-->
-<!--        />-->
-<!--      </view>-->
-<!--    </view>-->
+    <view class="search-wrapper">
+    <view class="query">
+      <u-row customStyle="margin-bottom: 10px" gutter="20">
+        <u-col span="9">
+          <u--input
+              @focus="timeShow = true"
+              v-model="startTimeXd"
+              placeholder="开始日期 ~ 结束日期"
+              prefixIcon="calendar"
+              prefixIconStyle="font-size: 22px;color: #909399"
+              @input="handleSearch"
+              @change="change"
+          ></u--input>
+        </u-col>
+        <u-col span="3">
+          <view class="query-btn" @click="show = !show">
+            <view class="query-btn-icon">
+            </view>
+            <view class="query-btn-text">筛选</view>
+          </view>
+        </u-col>
+      </u-row>
+    </view>
+  </view>
 
     <scroll-view class="list-container" scroll-y="true" @scrolltolower="loadMore">
       <view v-if="recordList.length === 0 && loadStatus !== 'loading'" class="empty-list">
@@ -33,6 +44,11 @@
               <text class="detail-value">{{ record.totalNum }}</text>
             </view>
 
+            <view class="detail-row" v-for="item in record.queryActiveRecordDetailVos">
+              <text class="detail-label">{{ item.productName }}</text>
+              <text class="detail-value">{{ item.num }}</text>
+            </view>
+
             <view class="detail-row product-item" v-for="(product, index) in record.products" :key="index">
               <text class="detail-label product-name">{{ product.name }}</text>
               <text class="detail-value">{{ product.quantity }}{{ product.unit }}</text>
@@ -56,16 +72,61 @@
 
       <uni-load-more :status="loadStatus"></uni-load-more>
     </scroll-view>
+    <u-popup :show="show" mode="bottom"  @close="show = false" >
+      <view class="popup-content">
+        <view class="popup-text">筛选</view>
+        <u-row customStyle="margin-bottom: 10px">
+          <u-col span="3">
+            <view class="explain">选择日期</view>
+          </u-col>
+          <u-col span="9">
+            <u--input
+                v-model="startTimeXd"
+                placeholder="开始日期 ~ 结束日期"
+                prefixIcon="calendar"
+                prefixIconStyle="font-size: 22px;color: #909399"
+                @focus="timeShow = true"
+            ></u--input>
+          </u-col>
+        </u-row>
+        <u-row customStyle="margin-bottom: 10px">
+          <u-col span="3">
+            <view class="explain">门店名称</view>
+          </u-col>
+          <u-col span="9">
+            <u--input v-model="searchQuery"
+                placeholder="请输入内容"
+                border="surround"
+            ></u--input>
+          </u-col>
+        </u-row>
+        <view class="popup-btn">
+          <u-button @click="handleSearch"  class="popup-btn-one">搜索</u-button>
+          <u-button @click="resetForm" class="popup-btn-one" type="primary">重置</u-button>
+        </view>
+      </view>
+
+    </u-popup>
+    <u-calendar @close="timeShow = false" :show="timeShow" :mode="mode" @confirm="confirm"></u-calendar>
   </view>
 </template>
 
 <script>
-import {queryActiveRecord} from "../../../../api/hexiao";
+import {queryActiveRecord} from "@/api/hexiao";
 
 export default {
   data() {
     return {
+      startTime: '',
+      endTime: '',
+      timeShow: false,
+      startTimeXd:"",
+      mode: 'range',
+      show:false,
+
+
       searchQuery: '',
+
       recordList: [],
       pagination: {
         page: 1,
@@ -84,6 +145,16 @@ export default {
     this.fetchRecords(true);
   },
   methods: {
+    confirm(e) {
+      this.startTime = e[0];
+      this.endTime = e[e.length-1];
+      this.startTimeXd = e[0]+' ~ '+e[e.length-1];
+      if(!this.show){
+        this.handleSearch()
+      }
+      this.timeShow = false;
+
+    },
     // 核心:获取记录列表数据
     async fetchRecords(isRefresh = false) {
       if (this.isLoading || (this.loadStatus === 'noMore' && !isRefresh)) {
@@ -102,8 +173,11 @@ export default {
       // 在这里替换成您真实的 uni.request API 调用
       console.log(`正在请求第 ${this.pagination.page} 页数据...`);
 
-      queryActiveRecord(this.pagination.page,this.pagination.limit).then(res=>{
+      queryActiveRecord(this.pagination.page,this.pagination.limit,this.searchQuery,this.startTime,this.endTime).then(res=>{
         let mockData = res.data.records;
+        if(mockData == null){
+          mockData = [];
+        }
         if (mockData.length > 0) {
           this.recordList = [...this.recordList, ...mockData];
           this.pagination.page++;
@@ -129,10 +203,19 @@ export default {
     },
 
     // 搜索
+    change(){
+      debugger;
+    },
     handleSearch() {
+      this.show = false;
       // 在实际项目中,搜索应该调用API,这里为简单起见只做前端筛选
-      // this.fetchRecords(true);
-      uni.showToast({ title: '触发搜索', icon: 'none' });
+      this.fetchRecords(true);
+    },
+    resetForm(){
+        this.searchQuery = "";
+        this.startTime = "";
+        this.endTime = "";
+        this.startTimeXd = "";
     }
   }
 }
@@ -246,4 +329,51 @@ export default {
     font-weight: 500;
   }
 }
+.query-btn {
+  background-color: #409eff;
+  color: #fff;
+  padding: 20rpx;
+  border-radius: 10rpx;
+  height: 34rpx;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.query-btn-icon {
+  height: 32rpx;
+  width: 32rpx;
+  background-image:
+      url("https://hyscancode.oss-cn-hangzhou.aliyuncs.com/xiaochengxu/cjx/queryIoc.png");
+  background-size: cover;
+  background-position: center;
+  background-repeat: no-repeat;
+}
+.query-btn-text {
+  font-weight: 400;
+  font-size: 30rpx;
+  color: #F5F5F5;
+}
+.popup-content{
+  height: 25vh;
+  padding: 10px;
+}
+.popup-text{
+  font-family: PingFang SC;
+  font-weight: bold;
+  font-size: 36rpx;
+  color: #1C1E1D;
+  text-align: center;
+  margin-bottom: 10px;
+}
+.popup-btn{
+  display: flex;
+  justify-content: space-around;
+}
+.popup-btn-one{
+  width: 275rpx;
+  height: 70rpx;
+  background: linear-gradient(0deg, #6FA4FE, #488CFF);
+  box-shadow: 0rpx 9rpx 16rpx 0rpx rgba(153,153,153,0.35);
+  border-radius: 35rpx;
+}
 </style>

+ 32 - 6
pages/cjx/hexiao/ywy/add_retail.vue

@@ -44,6 +44,20 @@
         />
       </view>
 
+      <view class="form-item">
+        <text class="form-label">店铺照片</text>
+        <uni-file-picker
+            class="file-picker"
+            ref="files"
+            :del-icon="edit"
+            file-mediatype="image"
+            mode="grid"
+            :limit="1"
+            title="最多选择1张图片"
+            v-model="formData.photos"
+        />
+      </view>
+
     </view>
 
     <view class="footer-save-button" v-if="edit">
@@ -54,7 +68,7 @@
 </template>
 
 <script>
-import {addStore, getRetailDetail, updateStore} from "../../../../api/hexiao";
+import {addStore, getRetailDetail, updateStore, uploadImage} from "@/api/hexiao";
 
 export default {
   data() {
@@ -62,6 +76,7 @@ export default {
       edit:false,
       // 表单数据
       formData: {
+        photos: [],
         storeId: 0,
         storeName: '',
         ownerName: '',
@@ -81,14 +96,26 @@ export default {
             storeName: data.store_name,
             ownerName: data.contact_name,
             contact: data.contact_phone,
-            address: data.address
+            address: data.address,
+            photos: [{
+              "url":data.store_photo,
+            }]
           }
         })
       }
   },
   methods: {
     // 提交表单
-    submitForm() {
+    async submitForm() {
+      if(this.$refs.files.files.length === 0){
+        uni.showToast({ title: '请上传门店照片', icon: 'none' });
+        return;
+      }
+      const imageUrlarr = await uploadImage(this.$refs.files.files);
+      if(imageUrlarr.length === 0){
+        uni.showToast({ title: '门店照片上传失败,请重试', icon: 'none' });
+        return;
+      }
       // --- 手动进行数据校验 ---
       if (!this.formData.storeName) {
         uni.showToast({ title: '请输入店铺名称', icon: 'none' });
@@ -113,11 +140,10 @@ export default {
       }
 
       console.log('校验通过,准备提交的数据:', this.formData);
-
       // 执行提交逻辑
       uni.showLoading({ title: '正在保存...' });
       if(this.formData.storeId>0){
-        updateStore(this.formData.storeId,this.formData.storeName,this.formData.ownerName,this.formData.contact,this.formData.address)
+        updateStore(this.formData.storeId,this.formData.storeName,this.formData.ownerName,this.formData.contact,this.formData.address,imageUrlarr[0])
             .then(res=>{
               uni.hideLoading();
               if(res.code == 0){
@@ -136,7 +162,7 @@ export default {
 
             })
       }else{
-        addStore(this.formData.storeName,this.formData.ownerName,this.formData.contact,this.formData.address)
+        addStore(this.formData.storeName,this.formData.ownerName,this.formData.contact,this.formData.address,imageUrlarr[0])
             .then(res=>{
               uni.hideLoading();
               if(res.code == 0){

+ 13 - 7
pages/cjx/hexiao/ywy/index.vue

@@ -65,9 +65,9 @@
       </view>
     </view>
     <select-store-drawer
-        :show="showDrawer"
+        :show="showDrawer>0"
         :selected-id="selectedStore ? selectedStore.id : null"
-        @close="showDrawer = false"
+        @close="showDrawer = 0"
         @select="onStoreSelect"
     ></select-store-drawer>
     <CustomTabbar :current="0"/>
@@ -89,7 +89,7 @@ export default {
   data() {
     return {
       selectedStore: 0,
-      showDrawer:false,
+      showDrawer:0,
       imgurl:"https://hyscancode.oss-cn-hangzhou.aliyuncs.com/xiaochengxu",
       userInfo: {
         name: '',
@@ -118,7 +118,7 @@ export default {
     onStoreSelect(store) {
       console.log('在首页接收到选中的门店:', store);
       this.selectedStore = store;
-      uni.navigateTo({ url: '/pages/cjx/hexiao/ywy/scan_code?storeId='+store.id });
+      uni.navigateTo({ url: '/pages/cjx/hexiao/ywy/scan_code?type='+this.showDrawer+'&storeId='+store.id });
     },
     // 格式化数字,添加千位分隔符
     formatNumber(num) {
@@ -128,9 +128,9 @@ export default {
     scanCode(type) {
       // uni.navigateTo({ url: `/pages/cjx/hexiao/scan_code` });
       if("stock" === type){
-        this.showDrawer = true;
+        this.showDrawer = 1;
       }else{
-        this.build();
+        this.showDrawer = 2;
       }
     },
     build(){
@@ -146,7 +146,13 @@ export default {
 
       if("stockRecords" === page){
         uni.navigateTo({ url: `/pages/cjx/hexiao/ywy/add_goods_record` });
-      }else{
+      }
+      else if("verifyRecords" === page){
+        uni.navigateTo({ url: `/pages/cjx/hexiao/ywy/hexiao_record` });
+      }else if("patrolRecords" === page){
+        uni.navigateTo({ url: `/pages/cjx/hexiao/ywy/patrol_record` });
+      }
+      else{
         this.build();
       }
     }

+ 5 - 2
pages/cjx/hexiao/ywy/retail.vue

@@ -94,7 +94,8 @@ export default {
   onShow(){
     this.fetchStoreList(true);
   },
-  onLoad() {
+  onLoad(opt) {
+
    this.fetchStoreList(true);
   },
   methods: {
@@ -137,7 +138,9 @@ export default {
       console.log('查看详情 ID:', id);
       },
     editStore(id) {    uni.navigateTo({ url: '/pages/cjx/hexiao/ywy/add_retail?edit=1&id='+id });},
-    patrolStore(id) { console.log('巡店 ID:', id); },
+    patrolStore(id) {
+      uni.navigateTo({ url: '/pages/cjx/hexiao/ywy/add_patrol?edit=1&id='+id });
+    },
     deleteStore(id) {
       let self = this;
       uni.showModal({

+ 41 - 15
pages/cjx/hexiao/ywy/scan_code.vue

@@ -31,8 +31,7 @@
 </template>
 
 <script>
-import {getQrcodeNum } from '@/api/hexiao.js';
-import {active} from "../../../../api/hexiao";
+import {getQrcodeNum,active ,writeOff} from '@/api/hexiao.js';
 
 export default {
   data() {
@@ -42,7 +41,9 @@ export default {
       storeId:0,
       numberList: [],
       // 用于播放提示音
-      audioContext: null
+      audioContext: null,
+      // 1上货 2是核销
+      type:0
     };
   },
   onReady() {
@@ -53,6 +54,17 @@ export default {
   },
   onLoad(opt) {
     this.storeId = opt.storeId
+    this.type = opt.type
+    let title = "";
+    if(this.type == 1){
+      title = "上货列表"
+    }else{
+      title = "核销列表"
+    }
+    uni.setNavigationBarTitle({
+      title: title
+    });
+    this.getCodeNumber('ac6a603e708d24c9')
     // 获取二维码列表
     // this.codeList = this.$store.state.qrCodeList;
   },
@@ -72,7 +84,7 @@ export default {
         return;
       }
       uni.showLoading();
-      getQrcodeNum(code).then(res=>{
+      getQrcodeNum(code,this.type).then(res=>{
         uni.hideLoading();
         if(res.code === 0){
           let data = res.data;
@@ -164,17 +176,31 @@ export default {
       let obj = {};
       obj.storeId = 1;
       obj.qrcodeIds = this.codeList;
-      active(obj).then(res=>{
-        uni.hideLoading();
-        if(res.code == 0){
-          uni.showToast({ title: '操作成功', icon: 'none' });
-          this.numberList = []
-          this.codeList = [];
-          uni.navigateBack();
-        }else{
-          uni.showToast({ title: res.msg, icon: 'none' });
-        }
-      })
+      if(this.type == 1){
+        active(obj).then(res=>{
+          uni.hideLoading();
+          if(res.code == 0){
+            uni.showToast({ title: '操作成功', icon: 'none' });
+            this.numberList = []
+            this.codeList = [];
+            uni.navigateBack();
+          }else{
+            uni.showToast({ title: res.msg, icon: 'none' });
+          }
+        })
+      }else if(this.type == 2){
+        writeOff(obj).then(res=>{
+          uni.hideLoading();
+          if(res.code == 0){
+            uni.showToast({ title: '操作成功', icon: 'none' });
+            this.numberList = []
+            this.codeList = [];
+            uni.navigateBack();
+          }else{
+            uni.showToast({ title: res.msg, icon: 'none' });
+          }
+        })
+      }
     }
   }
 }

+ 46 - 0
utils/requestAdmin.js

@@ -101,5 +101,51 @@ const request = config => {
     })
   })
 }
+export function uploadImageToServer(tempFilePath){
+  return new Promise((resolve, reject) => {
+    // 获取已选择的图片临时路径
+    // const tempFilePath = this.formData.photos[0].url;
+    config.header = config.header || {}
+    if (getAdminToken()) {
+      config.header['sessionId'] = getAdminToken()
+    }else{
+
+    }
+    // 使用 uni.uploadFile 上传
+    uni.uploadFile({
+      // 【重要】这里是您后端接收上传文件的接口地址
+      url: config.baseUrl +'/ywy/uploadStoreImage',
+
+      filePath: tempFilePath,
+      name: 'file', // 和后端约定的文件名参数,'file' 是常用名
+
+      // 如果您的接口需要token等header信息
+      header: config.header,
+
+      success: (res) => {
+        console.log('上传接口返回结果:', res);
+
+        // 通常后端会返回一个JSON字符串,需要解析
+        const resData = JSON.parse(res.data);
+
+        // 根据您和后端约定的返回格式进行判断
+        // 假设成功时 { "code": 0, "data": { "url": "https://oss..." } }
+        if (resData.code === 0) {
+          // 上传成功,resolve返回最终的图片URL
+          resolve(resData.data);
+        } else {
+          // 上传失败,reject返回错误信息
+          reject(new Error(resData.msg || '上传失败'));
+        }
+      },
+      fail: (err) => {
+        reject(err);
+      }
+    });
+  });
+}
 
 export default request
+
+
+