diff --git a/ghy-admin/src/main/resources/templates/goods/category/serviceTree.html b/ghy-admin/src/main/resources/templates/goods/category/serviceTree.html
new file mode 100644
index 00000000..434924a0
--- /dev/null
+++ b/ghy-admin/src/main/resources/templates/goods/category/serviceTree.html
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ghy-common/src/main/java/com/ghy/common/utils/LocationUtils.java b/ghy-common/src/main/java/com/ghy/common/utils/LocationUtils.java
new file mode 100644
index 00000000..dd16c1e9
--- /dev/null
+++ b/ghy-common/src/main/java/com/ghy/common/utils/LocationUtils.java
@@ -0,0 +1,166 @@
+package com.ghy.common.utils;
+
+/**
+ * 地理位置计算工具类
+ * 提供经纬度之间的距离计算功能
+ *
+ * @author clunt
+ */
+public class LocationUtils {
+
+ /** 地球半径(千米) */
+ private static final double EARTH_RADIUS_KM = 6371.0;
+
+ /** 地球半径(米) */
+ private static final double EARTH_RADIUS_M = 6371000.0;
+
+ /**
+ * 使用Haversine公式计算两点间的距离(米)
+ *
+ * @param lat1 第一个点的纬度
+ * @param lng1 第一个点的经度
+ * @param lat2 第二个点的纬度
+ * @param lng2 第二个点的经度
+ * @return 距离(米)
+ */
+ public static double getDistanceInMeters(double lat1, double lng1, double lat2, double lng2) {
+ return getDistanceInKilometers(lat1, lng1, lat2, lng2) * 1000;
+ }
+
+ /**
+ * 使用Haversine公式计算两点间的距离(千米)
+ *
+ * @param lat1 第一个点的纬度
+ * @param lng1 第一个点的经度
+ * @param lat2 第二个点的纬度
+ * @param lng2 第二个点的经度
+ * @return 距离(千米)
+ */
+ public static double getDistanceInKilometers(double lat1, double lng1, double lat2, double lng2) {
+ // 将角度转换为弧度
+ double lat1Rad = Math.toRadians(lat1);
+ double lng1Rad = Math.toRadians(lng1);
+ double lat2Rad = Math.toRadians(lat2);
+ double lng2Rad = Math.toRadians(lng2);
+
+ // 计算经纬度差值
+ double deltaLat = lat2Rad - lat1Rad;
+ double deltaLng = lng2Rad - lng1Rad;
+
+ // Haversine公式
+ double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
+ Math.cos(lat1Rad) * Math.cos(lat2Rad) *
+ Math.sin(deltaLng / 2) * Math.sin(deltaLng / 2);
+
+ double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+
+ return EARTH_RADIUS_KM * c;
+ }
+
+ /**
+ * 判断某个点是否在指定范围内
+ *
+ * @param centerLat 中心点纬度
+ * @param centerLng 中心点经度
+ * @param targetLat 目标点纬度
+ * @param targetLng 目标点经度
+ * @param radiusKm 半径(千米)
+ * @return 是否在范围内
+ */
+ public static boolean isWithinRadius(double centerLat, double centerLng,
+ double targetLat, double targetLng,
+ double radiusKm) {
+ double distance = getDistanceInKilometers(centerLat, centerLng, targetLat, targetLng);
+ return distance <= radiusKm;
+ }
+
+ /**
+ * 格式化距离显示
+ *
+ * @param distanceInMeters 距离(米)
+ * @return 格式化后的距离字符串
+ */
+ public static String formatDistance(double distanceInMeters) {
+ if (distanceInMeters < 1000) {
+ return String.format("%.0f米", distanceInMeters);
+ } else {
+ double km = distanceInMeters / 1000;
+ if (km < 10) {
+ return String.format("%.1f公里", km);
+ } else {
+ return String.format("%.0f公里", km);
+ }
+ }
+ }
+
+ /**
+ * 计算两个坐标点的方位角(以正北为0度,顺时针)
+ *
+ * @param lat1 起点纬度
+ * @param lng1 起点经度
+ * @param lat2 终点纬度
+ * @param lng2 终点经度
+ * @return 方位角(度数,0-360)
+ */
+ public static double getBearing(double lat1, double lng1, double lat2, double lng2) {
+ double lat1Rad = Math.toRadians(lat1);
+ double lat2Rad = Math.toRadians(lat2);
+ double deltaLngRad = Math.toRadians(lng2 - lng1);
+
+ double y = Math.sin(deltaLngRad) * Math.cos(lat2Rad);
+ double x = Math.cos(lat1Rad) * Math.sin(lat2Rad) -
+ Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(deltaLngRad);
+
+ double bearingRad = Math.atan2(y, x);
+ double bearingDeg = Math.toDegrees(bearingRad);
+
+ // 转换为0-360度
+ return (bearingDeg + 360) % 360;
+ }
+
+ /**
+ * 将方位角转换为方向描述
+ *
+ * @param bearing 方位角(度数)
+ * @return 方向描述
+ */
+ public static String getDirectionDescription(double bearing) {
+ String[] directions = {"北", "东北", "东", "东南", "南", "西南", "西", "西北"};
+ int index = (int) Math.round(bearing / 45) % 8;
+ return directions[index];
+ }
+
+ /**
+ * 验证经纬度的有效性
+ *
+ * @param latitude 纬度
+ * @param longitude 经度
+ * @return 是否有效
+ */
+ public static boolean isValidCoordinate(Double latitude, Double longitude) {
+ if (latitude == null || longitude == null) {
+ return false;
+ }
+ return latitude >= -90 && latitude <= 90 && longitude >= -180 && longitude <= 180;
+ }
+
+ /**
+ * 计算中心点坐标(多个点的几何中心)
+ *
+ * @param coordinates 坐标点数组,每个元素为[纬度, 经度]
+ * @return 中心点坐标 [纬度, 经度]
+ */
+ public static double[] getCenterPoint(double[][] coordinates) {
+ if (coordinates == null || coordinates.length == 0) {
+ return null;
+ }
+
+ double sumLat = 0, sumLng = 0;
+ for (double[] coord : coordinates) {
+ sumLat += coord[0];
+ sumLng += coord[1];
+ }
+
+ return new double[]{sumLat / coordinates.length, sumLng / coordinates.length};
+ }
+}
\ No newline at end of file