ITPub博客

首页 > 移动开发 > 微信开发 > 家政预约小程序源码开发全攻略:LBS定位+智能匹配算法+多端协同部署方案

家政预约小程序源码开发全攻略:LBS定位+智能匹配算法+多端协同部署方案

原创 微信开发 作者:xihuanni 时间:2026-01-09 10:29:24 0 删除 编辑

  随着家政服务行业数字化转型加速,基于微信小程序的预约平台成为提升服务效率、优化用户体验的重要工具。本文将详细介绍如何从零搭建一个功能完整的家政预约小程序,涵盖LBS定位、智能匹配算法、多端协同部署等核心技术实现。

  技术架构设计

  前端技术栈:

  •源码及演示:j.yunzes.top/er

  •uni-app+Vue3:实现一套代码多端运行(微信小程序、H5、APP)

  •TypeScript:提供类型安全和现代化开发体验

  •uView UI组件库:丰富的UI组件支持

  •腾讯地图SDK:LBS定位与导航功能

  后端技术栈:

  •Spring Boot 2.7:RESTful API服务框架

  •MySQL:关系型数据存储

  •Redis:缓存与消息队列

  •Elasticsearch:搜索与推荐服务

  智能算法:

  •协同过滤推荐算法

  •实时路径规划算法

  •供需预测模型

   项目环境搭建

  1.初始化项目

  使用uni-app CLI创建项目:

# 全局安装uni-app CLI
npm install -g @dcloudio/uni-app
# 创建Vue3+TypeScript项目
uni-app create my-housekeeping-app --template vue3-ts
# 进入项目目录
cd my-housekeeping-app
# 安装依赖
npm install
# 安装uView UI
npm install uview-ui

  2.项目配置

  在src/manifest.json中配置小程序基本信息:

{
  "name": "家政预约",
  "appid": "your-appid",
  "description": "家政服务预约平台",
  "versionName": "1.0.0",
  "versionCode": "100",
  "mp-weixin": {
    "appid": "your-weixin-appid",
    "setting": {
      "urlCheck": false,
      "es6": true,
      "enhance": true
    }
  }
}

   核心功能模块实现

  1.LBS定位与地址管理

  实现用户位置获取与地址选择功能:

// utils/location.ts
export class LocationService {
  // 获取用户当前位置
  static async getCurrentLocation(): Promise<{ latitude: number; longitude: number }> {
    return new Promise((resolve, reject) => {
      uni.getLocation({
        type: 'gcj02',
        success: (res) => {
          resolve({
            latitude: res.latitude,
            longitude: res.longitude
          })
        },
        fail: (error) => {
          reject(error)
        }
      })
    })
  }
  // 选择地址
  static async chooseLocation(): Promise<{ address: string; latitude: number; longitude: number }> {
    return new Promise((resolve, reject) => {
      uni.chooseLocation({
        success: (res) => {
          resolve({
            address: res.address,
            latitude: res.latitude,
            longitude: res.longitude
          })
        },
        fail: (error) => {
          reject(error)
        }
      })
    })
  }
  // 计算两点间距离(公里)
  static calculateDistance(lat1: number, lng1: number, lat2: number, lng2: number): number {
    const radLat1 = (lat1 * Math.PI) / 180
    const radLat2 = (lat2 * Math.PI) / 180
    const a = radLat1 - radLat2
    const b = (lng1 * Math.PI) / 180 - (lng2 * Math.PI) / 180
    let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)))
    s = s * 6378.137
    s = Math.round(s * 10000) / 10000
    return s
  }
}

  2.服务展示与预约模块

  实现服务分类展示与预约功能:

<template>
  <view>
    <!-- 服务分类 -->
    <view>
      <view 
        v-for="category in categories" 
        :key="category.id"
       
        :class="{ active: activeCategory === category.id }"
        @click="changeCategory(category.id)"
      >
        <image :src="category.icon" />
        <text>{{ category.name }}</text>
      </view>
    </view>
    <!-- 服务列表 -->
    <view>
      <view 
        v-for="service in filteredServices" 
        :key="service.id"
       
        @click="goToServiceDetail(service)"
      >
        <image :src="service.image" />
        <view>
          <text>{{ service.name }}</text>
          <text>{{ service.description }}</text>
          <view>
            <text>¥{{ service.price }}</text>
            <text>/{{ service.unit }}</text>
          </view>
        </view>
      </view>
    </view>
  </view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { getServiceCategories, getServices } from '@/api/service'
interface ServiceCategory {
  id: number
  name: string
  icon: string
}
interface ServiceItem {
  id: number
  name: string
  description: string
  price: number
  unit: string
  image: string
  categoryId: number
}
const categories = ref<ServiceCategory[]>([])
const services = ref<ServiceItem[]>([])
const activeCategory = ref<number>(0)
onMounted(async () => {
  await loadData()
})
const loadData = async () => {
  try {
    const [categoryRes, serviceRes] = await Promise.all([
      getServiceCategories(),
      getServices()
    ])
    categories.value = categoryRes.data
    services.value = serviceRes.data
    if (categories.value.length > 0) {
      activeCategory.value = categories.value[0].id
    }
  } catch (error) {
    console.error('加载数据失败:', error)
  }
}
const filteredServices = computed(() => {
  if (activeCategory.value === 0) {
    return services.value
  }
  return services.value.filter(item => item.categoryId === activeCategory.value)
})
const changeCategory = (categoryId: number) => {
  activeCategory.value = categoryId
}
const goToServiceDetail = (service: ServiceItem) => {
  uni.navigateTo({
    url: `/pages/service/detail?id=${service.id}`
  })
}
</script>

  3.智能匹配算法实现

  实现基于多维度数据的服务人员匹配算法:

// utils/matching.ts
export interface StaffProfile {
  id: number
  name: string
  skills: string[]
  rating: number
  serviceCount: number
  acceptanceRate: number
  currentLocation: { latitude: number; longitude: number }
  isOnline: boolean
  workingStatus: string
  price: number
}
export interface UserRequirement {
  serviceType: string
  serviceTime: string
  location: { latitude: number; longitude: number }
  budget?: number
  specialRequirements?: string[]
}
export class MatchingAlgorithm {
  // 综合匹配算法
  static matchStaff(
    staffList: StaffProfile[],
    requirement: UserRequirement,
    maxDistance: number = 10 // 最大距离(公里)
  ): StaffProfile[] {
    return staffList
      .filter(staff => this.filterByDistance(staff, requirement.location, maxDistance))
      .filter(staff => this.filterBySkills(staff, requirement.serviceType))
      .filter(staff => this.filterByAvailability(staff))
      .sort((a, b) => this.calculateScore(b, requirement) - this.calculateScore(a, requirement))
      .slice(0, 5) // 返回前5个推荐
  }
  // 距离过滤
  private static filterByDistance(
    staff: StaffProfile,
    userLocation: { latitude: number; longitude: number },
    maxDistance: number
  ): boolean {
    const distance = LocationService.calculateDistance(
      staff.currentLocation.latitude,
      staff.currentLocation.longitude,
      userLocation.latitude,
      userLocation.longitude
    )
    return distance <= maxDistance
  }
  // 技能匹配
  private static filterBySkills(staff: StaffProfile, serviceType: string): boolean {
    return staff.skills.includes(serviceType)
  }
  // 可用性检查
  private static filterByAvailability(staff: StaffProfile): boolean {
    return staff.isOnline && staff.workingStatus === 'available'
  }
  // 综合评分计算
  private static calculateScore(staff: StaffProfile, requirement: UserRequirement): number {
    let score = 0
    // 评分权重(40%)
    score += staff.rating * 0.4
    // 服务次数权重(20%)
    score += Math.min(staff.serviceCount / 100, 1) * 0.2
    // 接单率权重(20%)
    score += (staff.acceptanceRate / 100) * 0.2
    // 距离权重(20%)
    const distance = LocationService.calculateDistance(
      staff.currentLocation.latitude,
      staff.currentLocation.longitude,
      requirement.location.latitude,
      requirement.location.longitude
    )
    score += (1 - Math.min(distance / 10, 1)) * 0.2
    // 预算匹配(如果指定预算)
    if (requirement.budget && staff.price <= requirement.budget) {
      score += 0.1
    }
    return score
  }
}

  4.订管理模块

  实现订单创建、支付、状态跟踪功能:

// stores/order.ts
import { defineStore } from 'pinia'
import { createOrder, getOrderList, getOrderDetail, payOrder } from '@/api/order'
export interface OrderItem {
  id: number
  orderNo: string
  totalAmount: number
  status: number // 0:待支付, 1:已支付, 2:服务中, 3:已完成, 4:已取消
  createTime: string
  serviceName: string
  staffName: string
  serviceTime: string
  address: string
}
export const useOrderStore = defineStore('order', {
  state: () => ({
    orderList: [] as OrderItem[],
    currentOrder: null as OrderItem | null
  }),
  
  actions: {
    // 创建订单
    async createOrder(params: {
      serviceId: number
      staffId: number
      serviceTime: string
      address: string
      remark?: string
    }) {
      const res = await createOrder(params)
      this.currentOrder = res.data
      return res.data
    },
    
    // 获取订单列表
    async getOrderList() {
      const res = await getOrderList()
      this.orderList = res.data
      return res.data
    },
    
    // 获取订单详情
    async getOrderDetail(orderId: number) {
      const res = await getOrderDetail(orderId)
      this.currentOrder = res.data
      return res.data
    },
    
    // 支付订单
    async payOrder(orderId: number) {
      const res = await payOrder(orderId)
      if (res.code === 200) {
        // 更新订单状态
        const order = this.orderList.find(item => item.id === orderId)
        if (order) {
          order.status = 1
        }
        if (this.currentOrder && this.currentOrder.id === orderId) {
          this.currentOrder.status = 1
        }
      }
      return res
    },
    
    // 更新订单状态
    updateOrderStatus(orderId: number, status: number) {
      const order = this.orderList.find(item => item.id === orderId)
      if (order) {
        order.status = status
      }
      if (this.currentOrder && this.currentOrder.id === orderId) {
        this.currentOrder.status = status
      }
    }
  }
})

   多端协同部署方案

  1.后端微服务架构

  采用Spring Cloud微服务架构实现多端协同:

// 订单服务接口
@RestController
@RequestMapping("/api/order")
public class OrderController {
    
    @Autowired
    private OrderService orderService;
    
    @PostMapping("/create")
    public R<OrderVO> createOrder(@RequestBody OrderCreateDTO dto) {
        OrderVO order = orderService.createOrder(dto);
        return R.success(order);
    }
    
    @GetMapping("/list")
    public R<List<OrderVO>> getOrderList(@RequestParam Integer pageNum, 
                                       @RequestParam Integer pageSize) {
        List<OrderVO> orders = orderService.getOrderList(pageNum, pageSize);
        return R.success(orders);
    }
    
    @PostMapping("/pay/{orderId}")
    public R<Void> payOrder(@PathVariable Long orderId) {
        orderService.payOrder(orderId);
        return R.success();
    }
}
// 统一返回结果类
@Data
public class R<T> {
    private int code;
    private String message;
    private T data;
    
    public static <T> R<T> success(T data) {
        R<T> result = new R<>();
        result.code = 200;
        result.message = "成功";
        result.data = data;
        return result;
    }
    
    public static <T> R<T> error(String message) {
        R<T> result = new R<>();
        result.code = 500;
        result.message = message;
        return result;
    }
}

  2.数据库设计

  核心表结构设计:

-- 用户表
CREATE TABLE `users` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `openid` varchar(100) NOT NULL COMMENT '微信openid',
  `nickname` varchar(100) DEFAULT NULL COMMENT '昵称',
  `avatar` varchar(500) DEFAULT NULL COMMENT '头像',
  `phone` varchar(20) DEFAULT NULL COMMENT '手机号',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_openid` (`openid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 服务人员表
CREATE TABLE `staffs` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL COMMENT '关联用户ID',
  `real_name` varchar(50) NOT NULL COMMENT '真实姓名',
  `id_card` varchar(20) DEFAULT NULL COMMENT '身份证号',
  `skills` json DEFAULT NULL COMMENT '技能列表',
  `rating` decimal(3,2) DEFAULT '5.00' COMMENT '评分',
  `service_count` int(11) DEFAULT '0' COMMENT '服务次数',
  `acceptance_rate` decimal(5,2) DEFAULT '100.00' COMMENT '接单率',
  `current_latitude` decimal(10,6) DEFAULT NULL COMMENT '当前位置纬度',
  `current_longitude` decimal(10,6) DEFAULT NULL COMMENT '当前位置经度',
  `is_online` tinyint(1) DEFAULT '0' COMMENT '是否在线',
  `working_status` varchar(20) DEFAULT 'offline' COMMENT '工作状态',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 订单表
CREATE TABLE `orders` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `order_no` varchar(50) NOT NULL COMMENT '订单号',
  `user_id` bigint(20) NOT NULL COMMENT '用户ID',
  `staff_id` bigint(20) DEFAULT NULL COMMENT '服务人员ID',
  `service_id` bigint(20) NOT NULL COMMENT '服务ID',
  `total_amount` decimal(10,2) NOT NULL COMMENT '订单金额',
  `status` tinyint(4) DEFAULT '0' COMMENT '订单状态',
  `service_time` datetime NOT NULL COMMENT '服务时间',
  `address` varchar(500) NOT NULL COMMENT '服务地址',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_order_no` (`order_no`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_staff_id` (`staff_id`),
  KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

  3.多端适配配置

  使用uni-app的条件编译实现多端适配:

// 条件编译示例
export default {
  data() {
    return {
      // #ifdef H5
      platform: 'web',
      // #endif
      // #ifdef MP-WEIXIN
      platform: 'wx',
      // #endif
      // #ifdef APP-PLUS
      platform: 'app',
      // #endif
    }
  },
  
  methods: {
    // 多端支付接口
    async payOrder(orderId) {
      // #ifdef MP-WEIXIN
      return this.wxPay(orderId)
      // #endif
      // #ifdef H5
      return this.h5Pay(orderId)
      // #endif
      // #ifdef APP-PLUS
      return this.appPay(orderId)
      // #endif
    },
    
    // 微信支付
    wxPay(orderId) {
      return new Promise((resolve, reject) => {
        uni.requestPayment({
          provider: 'wxpay',
          timeStamp: '',
          nonceStr: '',
          package: '',
          signType: 'MD5',
          paySign: '',
          success: resolve,
          fail: reject
        })
      })
    }
  }
}

   性能优化与最佳实践

      1.图片懒加载与缓存

<template>
  <view>
    <image 
      :src="imageUrl" 
      mode="aspectFill" 
      lazy-load
      :show-menu-by-longpress="true"
      @load="onImageLoad"
      @error="onImageError"
    />
  </view>
</template>
<script setup>
import { ref } from 'vue'
const props = defineProps<{
  imageUrl: string
}>()
const loaded = ref(false)
const onImageLoad = () => {
  loaded.value = true
}
const onImageError = () => {
  // 加载失败时使用默认图片
  console.error('图片加载失败:', props.imageUrl)
}
</script>

  2.请求拦截与错误处理

// utils/request.ts
import { useAuthStore } from '@/stores/auth'
const request = (options: UniApp.RequestOptions) => {
  const authStore = useAuthStore()
  
  return new Promise((resolve, reject) => {
    uni.request({
      ...options,
      header: {
        'Authorization': `Bearer ${authStore.token}`,
        ...options.header
      },
      success: (res) => {
        if (res.statusCode === 200) {
          resolve(res.data)
        } else if (res.statusCode === 401) {
          // token过期,跳转到登录页
          authStore.logout()
          uni.navigateTo({ url: '/pages/login/index' })
          reject(new Error('登录已过期'))
        } else {
          reject(new Error(res.data?.message || '请求失败'))
        }
      },
      fail: (error) => {
        reject(error)
      }
    })
  })
}

  3.数据缓存策略

// utils/request.ts
import { useAuthStore } from '@/stores/auth'
const request = (options: UniApp.RequestOptions) => {
  const authStore = useAuthStore()
  
  return new Promise((resolve, reject) => {
    uni.request({
      ...options,
      header: {
        'Authorization': `Bearer ${authStore.token}`,
        ...options.header
      },
      success: (res) => {
        if (res.statusCode === 200) {
          resolve(res.data)
        } else if (res.statusCode === 401) {
          // token过期,跳转到登录页
          authStore.logout()
          uni.navigateTo({ url: '/pages/login/index' })
          reject(new Error('登录已过期'))
        } else {
          reject(new Error(res.data?.message || '请求失败'))
        }
      },
      fail: (error) => {
        reject(error)
      }
    })
  })
}

   项目部署与上线

  小程序发布流程

  1.开发环境配置:在微信公众平台配置服务器域名

  2.代码上传:使用微信开发者工具上传代码

  3.提交审核:提交小程序审核

  4.发布上线:审核通过后发布上线

  后端服务部署

  使用Docker容器化部署:

FROM openjdk:11-jre-slim
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

  自动化部署脚本

#!/bin/bash
# 构建前端
echo "Building frontend..."
cd frontend
npm run build:mp-weixin
cd ..
# 构建后端
echo "Building backend..."
cd backend
mvn clean package -DskipTests
cd ..
# 构建Docker镜像
echo "Building Docker image..."
docker build -t housekeeping-app:latest .
# 部署到服务器
echo "Deploying to server..."
docker-compose up -d
echo "Deployment completed!"

   总结

  本文详细介绍了家政预约小程序的完整开发流程,从技术选型到功能实现,再到多端协同部署。通过LBS定位技术实现精准服务匹配,结合智能算法提升用户体验,采用微服务架构确保系统可扩展性。在实际开发中,还需要关注数据安全、性能优化、用户体验等方面,持续迭代完善系统功能。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70049253/viewspace-3107531/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: 没有了~
下一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2026-01-09

  • 博文量
    1
  • 访问量
    1159