From 347909bae241fff128b628ea6d12992d7e5b4b10 Mon Sep 17 00:00:00 2001
From: xin <1099200748@qq.com>
Date: Fri, 30 May 2025 18:35:43 +0800
Subject: [PATCH] 响应信息主体

---
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryMerchantCreateRequest.java   |   20 
 oying-system/src/main/java/com/oying/modules/system/mapper/MerchantsMapper.java                            |   22 
 oying-system/src/main/resources/mapper/pc/store/StoreQualificationMapper.xml                               |   36 
 oying-system/src/main/java/com/oying/AppRun.java                                                           |    1 
 oying-system/src/main/java/com/oying/modules/pc/category/service/PlatformCategoryService.java              |   59 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryCreateRequest.java           |   18 
 oying-system/src/main/java/com/oying/modules/pc/store/service/StoreQueryService.java                       |   10 
 oying-system/src/main/java/com/oying/modules/pc/search/domain/dto/StoreSearchDto.java                      |   17 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryMerchantUpdateRequest.java   |   16 
 oying-system/src/main/java/com/oying/modules/pc/common/core/constrant/Constants.java                       |   50 
 oying-system/src/main/java/com/oying/modules/pc/product/view/ProductMerchantSimpleView.java                |   22 
 oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreView.java                          |   28 
 oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreMapper.java                              |   34 
 oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreQueryServiceImpl.java              |   33 
 oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreMerchantController.java                    |  263 ++
 oying-system/src/main/java/com/oying/modules/system/service/impl/MerchantsServiceImpl.java                 |   86 
 oying-system/src/main/resources/config/application-dev.yml                                                 |   58 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreFieldUpdateRequest.java              |   92 
 oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductQueryCriteria.java               |   34 
 oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryCreateRequest.java     |   33 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQualificationQueryCriteria.java      |   24 
 oying-system/src/main/java/com/oying/modules/pc/search/view/StoreSearchView.java                           |   27 
 oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryController.java                    |   64 
 oying-system/src/main/java/com/oying/modules/pc/category/rest/PlatformCategoryAdminController.java         |   83 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreCategory.java                            |   70 
 oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCustomerController.java                    |   36 
 oying-generator/src/main/java/com/oying/rest/GenConfigController.java                                      |    9 
 oying-system/src/main/java/com/oying/modules/pc/category/converter/PlatformCategoryDtoAssembler.java       |   10 
 oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductMerchantCreateRequest.java       |   52 
 oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductCategoryMapper.java                  |   22 
 oying-system/src/main/java/com/oying/modules/system/rest/VerifyController.java                             |    7 
 oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreController.java                            |   68 
 oying-generator/src/main/java/com/oying/rest/GeneratorController.java                                      |   42 
 oying-system/src/main/java/com/oying/modules/pc/category/service/impl/PlatformCategoryServiceImpl.java     |   90 
 oying-system/src/main/java/com/oying/modules/pc/search/domain/dto/NearbyStoreQueryCriteria.java            |   38 
 oying-system/src/main/java/com/oying/modules/pc/store/service/StoreMerchantOwnershipService.java           |   12 
 oying-system/src/main/java/com/oying/modules/pc/store/view/StoreSimpleView.java                            |   16 
 oying-common/src/main/java/com/oying/utils/HttpRequest.java                                                |  101 
 oying-system/src/main/java/com/oying/modules/system/rest/DeptController.java                               |   36 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreQualification.java                       |   75 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryQueryCriteria.java           |   26 
 oying-system/src/main/java/com/oying/modules/pc/common/id/StoreQualificationIdGenerator.java               |   15 
 oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreCategoryMapper.java                      |   22 
 oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreQualificationServiceImpl.java      |   79 
 oying-system/src/main/resources/mapper/pc/store/StoreMapper.xml                                            |  108 
 oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductController.java                        |   73 
 oying-system/src/main/java/com/oying/modules/system/rest/JobController.java                                |   26 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCustomerDetailDto.java               |   26 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/enums/StoreStatusEnum.java                    |   21 
 oying-system/src/main/java/com/oying/modules/system/domain/dto/MerchantsQueryCriteria.java                 |   36 
 pom.xml                                                                                                    |   14 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQueryCriteria.java                   |   31 
 oying-system/src/main/java/com/oying/modules/security/config/WeiXinProperties.java                         |   31 
 oying-system/src/main/java/com/oying/modules/pc/store/service/StoreCreationCoordinator.java                |   31 
 oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductMapper.java                          |   22 
 oying-system/src/main/java/com/oying/modules/pc/store/view/StoreMerchantView.java                          |   48 
 oying-system/src/main/java/com/oying/modules/system/rest/MenuController.java                               |   42 
 oying-system/src/main/java/com/oying/modules/pc/search/service/StoreSearchService.java                     |   10 
 oying-system/src/main/java/com/oying/modules/pc/product/view/ProductSimpleView.java                        |   21 
 oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreCategoryView.java                  |   25 
 oying-system/src/main/java/com/oying/modules/pc/category/converter/PlatformCategoryViewAssembler.java      |   25 
 oying-common/src/main/java/com/oying/utils/RedisUtils.java                                                 |   10 
 oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryQueryCriteria.java     |   22 
 oying-system/src/main/java/com/oying/modules/pc/common/id/StoreIdGenerator.java                            |   15 
 oying-system/src/main/java/com/oying/modules/pc/category/view/PlatformCategoryCustomerView.java            |   16 
 oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreViewAssembler.java                    |    7 
 oying-system/src/main/java/com/oying/modules/system/domain/Merchants.java                                  |   68 
 oying-system/src/main/java/com/oying/modules/pc/product/domain/Product.java                                |  120 +
 oying-system/src/main/java/com/oying/modules/system/rest/MonitorController.java                            |    3 
 oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreServiceImpl.java                   |  159 +
 oying-system/src/main/java/com/oying/modules/pc/category/domain/PlatformCategory.java                      |   72 
 oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductMerchantUpdateRequest.java       |   45 
 oying-system/src/main/java/com/oying/modules/pc/product/view/ProductOverviewView.java                      |    4 
 oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationCustomerController.java       |   54 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/Store.java                                    |  135 +
 oying-system/src/main/java/com/oying/modules/pc/category/view/PlatformCategoryView.java                    |   33 
 oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductServiceImpl.java               |  106 
 oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreDtoAssembler.java                     |    7 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreLocationUpdateRequest.java           |   17 
 oying-system/src/main/java/com/oying/modules/system/rest/DictController.java                               |   30 
 oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreQualificationMapper.java                 |   24 
 oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductImageCreateRequest.java          |    9 
 oying-system/src/main/java/com/oying/modules/pc/store/service/StoreQualificationService.java               |   57 
 oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductMerchantController.java                |  140 +
 oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryCustomerController.java            |   71 
 oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryMerchantController.java            |  135 +
 oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantCreateServiceImpl.java |   59 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCreateRequest.java                   |   90 
 oying-system/src/main/java/com/oying/modules/pc/search/rest/StoreSearchController.java                     |   58 
 oying-system/src/main/java/com/oying/modules/pc/store/service/StoreCreateService.java                      |    7 
 oying-generator/src/main/resources/template/admin/Entity.ftl                                               |    6 
 oying-system/src/main/java/com/oying/modules/security/config/SwiftPassProperties.java                      |   40 
 oying-system/src/main/java/com/oying/modules/pc/category/mapper/PlatformCategoryMapper.java                |   22 
 oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreMerchantOwnershipServiceImpl.java  |   59 
 oying-common/src/main/java/com/oying/utils/ConstantsKey.java                                               |    5 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreBusinessHoursRequest.java            |   18 
 oying-tools/src/main/java/com/oying/rest/LocalStorageController.java                                       |   28 
 oying-system/src/main/resources/mapper/pc/product/ProductMapper.xml                                        |   60 
 oying-system/src/main/java/com/oying/modules/pc/product/view/ProductCustomerView.java                      |   25 
 oying-system/src/main/java/com/oying/modules/pc/store/view/StoreQualificationMerchantView.java             |   24 
 oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductCategoryQueryCriteria.java       |   18 
 oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationController.java               |   67 
 oying-system/src/main/resources/mapper/pc/store/StoreCategoryMapper.xml                                    |   40 
 oying-system/src/main/java/com/oying/modules/pc/product/service/ProductMerchantService.java                |   16 
 oying-system/src/main/resources/mapper/pc/category/PlatformCategoryMapper.xml                              |   34 
 oying-system/src/main/resources/mapper/system/MerchantsMapper.xml                                          |   48 
 oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreQualificationView.java             |   21 
 oying-common/src/main/java/com/oying/utils/R.java                                                          |  102 
 oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryUpdateDto.java         |   21 
 oying-system/src/main/java/com/oying/modules/pc/common/id/StoreIdentifierGenerator.java                    |   11 
 oying-system/src/main/java/com/oying/modules/pc/store/service/StoreCategoryService.java                    |   52 
 oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationMerchantController.java       |  100 
 oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductCustomerController.java                |   82 
 oying-system/src/main/java/com/oying/modules/pc/product/view/ProductMerchantDetailsView.java               |   25 
 oying-system/src/main/java/com/oying/modules/pc/utils/WrapperUtils.java                                    |   18 
 .gitignore                                                                                                 |   34 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQualificationUpdateRequest.java      |   27 
 oying-system/src/main/java/com/oying/modules/pc/store/service/StoreService.java                            |   56 
 oying-system/src/main/java/com/oying/modules/pc/product/service/ProductService.java                        |   60 
 oying-system/src/main/java/com/oying/modules/security/rest/OnlineController.java                           |    8 
 oying-system/src/main/resources/mapper/pc/search/SearchMapper.xml                                          |   56 
 oying-system/src/main/java/com/oying/modules/pc/search/service/impl/StoreSearchServiceImpl.java            |   25 
 oying-system/src/main/java/com/oying/modules/security/rest/VerificationController.java                     |   45 
 oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductLabelCreateRequest.java          |   16 
 .idea/vcs.xml                                                                                              |    2 
 oying-system/src/main/java/com/oying/modules/system/rest/DictDetailController.java                         |   30 
 oying-system/src/main/java/com/oying/modules/system/rest/MerchantsController.java                          |   74 
 oying-system/src/main/java/com/oying/modules/pc/product/view/ProductImageCustomerView.java                 |   12 
 oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreCategoryServiceImpl.java           |   96 
 oying-system/src/main/java/com/oying/modules/pc/common/exception/LevelExceededException.java               |   13 
 oying-system/src/main/java/com/oying/modules/pc/product/view/ProductLabelCustomerView.java                 |   13 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCustomerQueryCriteria.java           |   16 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQualificationCreateRequest.java      |   26 
 oying-system/src/main/java/com/oying/modules/system/rest/RoleController.java                               |   43 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryUpdateRequest.java           |   20 
 oying-system/src/main/java/com/oying/modules/quartz/rest/QuartzJobController.java                          |   37 
 oying-system/src/main/java/com/oying/modules/system/service/MerchantsService.java                          |   59 
 oying-system/src/main/java/com/oying/modules/pc/product/service/ProductCategoryService.java                |   60 
 oying-system/src/main/java/com/oying/modules/system/rest/UserController.java                               |   67 
 oying-system/src/main/java/com/oying/modules/pc/product/view/ProductCustomerDetailsView.java               |   24 
 oying-system/src/main/resources/config/application-prod.yml                                                |   53 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreStatus.java                              |    5 
 oying-system/src/main/resources/config/application.yml                                                     |    8 
 oying-system/src/main/java/com/oying/modules/security/service/WeiXinService.java                           |  112 +
 oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreLocation.java                            |   57 
 oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreCreateServiceImpl.java             |   51 
 oying-system/src/main/java/com/oying/modules/pc/product/domain/ProductCategory.java                        |   52 
 oying-tools/src/main/java/com/oying/rest/EmailController.java                                              |   14 
 oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductCustomerQueryCriteria.java       |   21 
 oying-logging/src/main/java/com/oying/rest/SysLogController.java                                           |   27 
 oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductCategoryServiceImpl.java       |   79 
 oying-system/src/main/java/com/oying/modules/pc/store/view/StoreCategoryMerchantView.java                  |   23 
 oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryUpdateRequest.java     |   24 
 oying-system/src/main/java/com/oying/modules/pc/category/rest/PlatformCategoryCustomerController.java      |   43 
 oying-system/src/main/java/com/oying/modules/security/rest/AuthController.java                             |   20 
 155 files changed, 6,340 insertions(+), 229 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d723c67
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,34 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+*.pid
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 94a25f7..5ace414 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -3,4 +3,4 @@
   <component name="VcsDirectoryMappings">
     <mapping directory="$PROJECT_DIR$" vcs="Git" />
   </component>
-</project>
\ No newline at end of file
+</project>
diff --git a/oying-common/src/main/java/com/oying/utils/ConstantsKey.java b/oying-common/src/main/java/com/oying/utils/ConstantsKey.java
new file mode 100644
index 0000000..b40936b
--- /dev/null
+++ b/oying-common/src/main/java/com/oying/utils/ConstantsKey.java
@@ -0,0 +1,5 @@
+package com.oying.utils;
+
+public interface ConstantsKey {
+
+}
diff --git a/oying-common/src/main/java/com/oying/utils/HttpRequest.java b/oying-common/src/main/java/com/oying/utils/HttpRequest.java
new file mode 100644
index 0000000..d3293c4
--- /dev/null
+++ b/oying-common/src/main/java/com/oying/utils/HttpRequest.java
@@ -0,0 +1,101 @@
+package com.oying.utils;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.oying.exception.BadRequestException;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.ssl.SSLContexts;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.web.client.RestTemplate;
+
+import javax.net.ssl.SSLContext;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Map;
+
+/**
+ * 功能描述:
+ *
+ * @author LIX
+ * @date 创建时间 :2022/6/15 下午4:19
+ */
+public class HttpRequest {
+
+
+    /**
+     * 读取请求数据流
+     *
+     * @param request 请求数据
+     * @return String
+     */
+    public static String getRequestBody(HttpServletRequest request) {
+        StringBuilder sb = new StringBuilder();
+        try (ServletInputStream inputStream = request.getInputStream();
+             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                sb.append(line);
+            }
+        } catch (IOException e) {
+            throw new BadRequestException("读取数据流异常");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 忽略ssl证书验证
+     *
+     * @return HttpComponentsClientHttpRequestFactory
+     */
+    public static HttpComponentsClientHttpRequestFactory getFactory() {
+        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
+        try {
+            TrustStrategy acceptingTrustStrategy = (chain, authType) -> true;
+            SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
+            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
+            HttpClientBuilder clientBuilder = HttpClients.custom();
+            CloseableHttpClient httpClient = clientBuilder.setSSLSocketFactory(socketFactory).build();
+            requestFactory.setHttpClient(httpClient);
+        } catch (Exception e) {
+            throw new BadRequestException("忽略ssl证书验证失败!!!");
+        }
+        return requestFactory;
+    }
+
+    private static HttpHeaders getHeaders() {
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        return headers;
+    }
+
+    /**
+     * http返回String
+     */
+    public static String exchangeString(HttpMethod httpMethod, String url, Map<String, Object> map) {
+        HttpHeaders headers = getHeaders();
+        HttpEntity<Object> httpEntity = new HttpEntity<>(map, headers);
+        RestTemplate restTemplate = new RestTemplate();
+        return restTemplate.exchange(url, httpMethod, httpEntity, String.class).getBody();
+    }
+
+    /**
+     * http返回JSONObject
+     */
+    public static JSONObject exchangeJsonObject(HttpMethod httpMethod, String url, Map<String, Object> map) {
+        HttpHeaders headers = getHeaders();
+        HttpEntity<Object> httpEntity = new HttpEntity<>(map, headers);
+        RestTemplate restTemplate = new RestTemplate();
+        return restTemplate.exchange(url, httpMethod, httpEntity, JSONObject.class).getBody();
+    }
+}
diff --git a/oying-common/src/main/java/com/oying/utils/R.java b/oying-common/src/main/java/com/oying/utils/R.java
new file mode 100644
index 0000000..70040f4
--- /dev/null
+++ b/oying-common/src/main/java/com/oying/utils/R.java
@@ -0,0 +1,102 @@
+package com.oying.utils;
+
+import java.io.Serializable;
+
+/**
+ * 响应信息主体
+ *
+ * @author lzp
+ * @date 2025-04-22
+ */
+public class R<T> implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 成功
+     */
+    public static final int SUCCESS = 0;
+
+    /**
+     * 失败
+     */
+    public static final int FAIL = 1;
+
+    private int status;
+
+    private String message;
+
+    private T data;
+
+    public static <T> R<T> success() {
+        return restResult(null, SUCCESS, "null");
+    }
+
+    public static <T> R<T> success(T data) {
+        return restResult(data, SUCCESS, null);
+    }
+
+    public static <T> R<T> success(T data, String msg) {
+        return restResult(data, SUCCESS, msg);
+    }
+
+    public static <T> R<T> fail() {
+        return restResult(null, FAIL, null);
+    }
+
+    public static <T> R<T> fail(String msg) {
+        return restResult(null, FAIL, msg);
+    }
+
+    public static <T> R<T> fail(T data) {
+        return restResult(data, FAIL, null);
+    }
+
+    public static <T> R<T> fail(T data, String msg) {
+        return restResult(data, FAIL, msg);
+    }
+
+    public static <T> R<T> fail(int code, String msg) {
+        return restResult(null, code, msg);
+    }
+
+    private static <T> R<T> restResult(T data, int code, String msg) {
+        R<T> apiResult = new R<>();
+        apiResult.setStatus(code);
+        apiResult.setData(data);
+        apiResult.setMessage(msg);
+        return apiResult;
+    }
+
+    public int getStatus() {
+        return status;
+    }
+
+    public void setStatus(int status) {
+        this.status = status;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    public static <T> Boolean isError(R<T> ret) {
+        return !isSuccess(ret);
+    }
+
+    public static <T> Boolean isSuccess(R<T> ret) {
+        return R.SUCCESS == ret.getStatus();
+    }
+}
diff --git a/oying-common/src/main/java/com/oying/utils/RedisUtils.java b/oying-common/src/main/java/com/oying/utils/RedisUtils.java
index ccd9126..d50d82c 100644
--- a/oying-common/src/main/java/com/oying/utils/RedisUtils.java
+++ b/oying-common/src/main/java/com/oying/utils/RedisUtils.java
@@ -31,6 +31,16 @@
     }
 
     /**
+     * 判断key是否过期
+     *
+     * @param key
+     * @return
+     */
+    public boolean isExpire(Object key) {
+        return getExpire(key) > 1 ? false : true;
+    }
+
+    /**
      * 指定缓存失效时间
      *
      * @param key  键
diff --git a/oying-generator/src/main/java/com/oying/rest/GenConfigController.java b/oying-generator/src/main/java/com/oying/rest/GenConfigController.java
index 65a788e..f4ff590 100644
--- a/oying-generator/src/main/java/com/oying/rest/GenConfigController.java
+++ b/oying-generator/src/main/java/com/oying/rest/GenConfigController.java
@@ -2,6 +2,7 @@
 
 import com.oying.domain.GenConfig;
 import com.oying.service.GenConfigService;
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -24,13 +25,13 @@
 
     @ApiOperation("查询")
     @GetMapping(value = "/{tableName}")
-    public ResponseEntity<GenConfig> queryGenConfig(@PathVariable String tableName){
-        return new ResponseEntity<>(genConfigService.find(tableName), HttpStatus.OK);
+    public ResponseEntity<Object> queryGenConfig(@PathVariable String tableName) {
+        return new ResponseEntity<>(R.success(genConfigService.find(tableName)), HttpStatus.OK);
     }
 
     @PutMapping
     @ApiOperation("修改")
-    public ResponseEntity<GenConfig> updateGenConfig(@Validated @RequestBody GenConfig genConfig){
-        return new ResponseEntity<>(genConfigService.update(genConfig.getTableName(), genConfig),HttpStatus.OK);
+    public ResponseEntity<Object> updateGenConfig(@Validated @RequestBody GenConfig genConfig) {
+        return new ResponseEntity<>(R.success(genConfigService.update(genConfig.getTableName(), genConfig)), HttpStatus.OK);
     }
 }
diff --git a/oying-generator/src/main/java/com/oying/rest/GeneratorController.java b/oying-generator/src/main/java/com/oying/rest/GeneratorController.java
index 6435ace..a693983 100644
--- a/oying-generator/src/main/java/com/oying/rest/GeneratorController.java
+++ b/oying-generator/src/main/java/com/oying/rest/GeneratorController.java
@@ -5,6 +5,7 @@
 import com.oying.domain.dto.TableInfo;
 import com.oying.service.GenConfigService;
 import com.oying.service.GeneratorService;
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -15,6 +16,7 @@
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
+
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.util.List;
@@ -37,50 +39,54 @@
 
     @ApiOperation("查询数据库数据")
     @GetMapping(value = "/tables")
-    public ResponseEntity<PageResult<TableInfo>> queryTables(@RequestParam(defaultValue = "") String name, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size){
-        return new ResponseEntity<>(generatorService.getTables(name, new Page<>(page, size)), HttpStatus.OK);
+    public ResponseEntity<Object> queryTables(@RequestParam(defaultValue = "") String name, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size) {
+        return new ResponseEntity<>(R.success(generatorService.getTables(name, new Page<>(page, size))), HttpStatus.OK);
     }
 
     @ApiOperation("查询字段数据")
     @GetMapping(value = "/columns")
-    public ResponseEntity<PageResult<ColumnInfo>> queryColumns(@RequestParam String tableName){
+    public ResponseEntity<Object> queryColumns(@RequestParam String tableName) {
         List<ColumnInfo> columnInfos = generatorService.getColumns(tableName);
-        return new ResponseEntity<>(PageUtil.toPage(columnInfos), HttpStatus.OK);
+        return new ResponseEntity<>(R.success(PageUtil.toPage(columnInfos)), HttpStatus.OK);
     }
 
     @ApiOperation("保存字段数据")
     @PutMapping
-    public ResponseEntity<HttpStatus> saveColumn(@RequestBody List<ColumnInfo> columnInfos){
+    public ResponseEntity<Object> saveColumn(@RequestBody List<ColumnInfo> columnInfos) {
         generatorService.save(columnInfos);
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 
     @ApiOperation("同步字段数据")
     @PostMapping(value = "sync")
-    public ResponseEntity<HttpStatus> syncColumn(@RequestBody List<String> tables){
+    public ResponseEntity<Object> syncColumn(@RequestBody List<String> tables) {
         for (String table : tables) {
             generatorService.sync(generatorService.getColumns(table), generatorService.query(table));
         }
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 
     @ApiOperation("生成代码")
     @PostMapping(value = "/{tableName}/{type}")
-    public ResponseEntity<Object> generatorCode(@PathVariable String tableName, @PathVariable Integer type, HttpServletRequest request, HttpServletResponse response){
-        if(!generatorEnabled && type == 0){
+    public ResponseEntity<Object> generatorCode(@PathVariable String tableName, @PathVariable Integer type, HttpServletRequest request, HttpServletResponse response) {
+        if (!generatorEnabled && type == 0) {
             throw new BadRequestException("此环境不允许生成代码,请选择预览或者下载查看!");
         }
-        switch (type){
+        switch (type) {
             // 生成代码
-            case 0: generatorService.generator(genConfigService.find(tableName), generatorService.getColumns(tableName));
-                    break;
+            case 0:
+                generatorService.generator(genConfigService.find(tableName), generatorService.getColumns(tableName));
+                break;
             // 预览
-            case 1: return generatorService.preview(genConfigService.find(tableName), generatorService.getColumns(tableName));
+            case 1:
+                return generatorService.preview(genConfigService.find(tableName), generatorService.getColumns(tableName));
             // 打包
-            case 2: generatorService.download(genConfigService.find(tableName), generatorService.getColumns(tableName), request, response);
-                    break;
-            default: throw new BadRequestException("没有这个选项");
+            case 2:
+                generatorService.download(genConfigService.find(tableName), generatorService.getColumns(tableName), request, response);
+                break;
+            default:
+                throw new BadRequestException("没有这个选项");
         }
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 }
diff --git a/oying-generator/src/main/resources/template/admin/Entity.ftl b/oying-generator/src/main/resources/template/admin/Entity.ftl
index d2e9ac4..5673769 100644
--- a/oying-generator/src/main/resources/template/admin/Entity.ftl
+++ b/oying-generator/src/main/resources/template/admin/Entity.ftl
@@ -1,6 +1,7 @@
 package ${package}.domain;
 
-import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
 import cn.hutool.core.bean.BeanUtil;
 import io.swagger.annotations.ApiModelProperty;
 import cn.hutool.core.bean.copier.CopyOptions;
@@ -41,7 +42,8 @@
 * @author ${author}
 * @date ${date}
 **/
-@Data
+@Getter
+@Setter
 @TableName("${tableName}")
 public class ${className} implements Serializable {
 <#if columns??>
diff --git a/oying-logging/src/main/java/com/oying/rest/SysLogController.java b/oying-logging/src/main/java/com/oying/rest/SysLogController.java
index 968c67a..fe3754a 100644
--- a/oying-logging/src/main/java/com/oying/rest/SysLogController.java
+++ b/oying-logging/src/main/java/com/oying/rest/SysLogController.java
@@ -5,6 +5,7 @@
 import com.oying.domain.SysLog;
 import com.oying.domain.dto.SysLogQueryCriteria;
 import com.oying.service.SysLogService;
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -14,6 +15,7 @@
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
+
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 
@@ -50,51 +52,52 @@
     @GetMapping
     @ApiOperation("日志查询")
     @PreAuthorize("@el.check()")
-    public ResponseEntity<PageResult<SysLog>> queryLog(SysLogQueryCriteria criteria){
+    public ResponseEntity<Object> queryLog(SysLogQueryCriteria criteria) {
         criteria.setLogType("INFO");
         Page<SysLog> page = new Page<>(criteria.getPage(), criteria.getSize());
-        return new ResponseEntity<>(sysLogService.queryAll(criteria,page), HttpStatus.OK);
+        return new ResponseEntity<>(R.success(sysLogService.queryAll(criteria, page)), HttpStatus.OK);
     }
 
     @GetMapping(value = "/user")
     @ApiOperation("用户日志查询")
-    public ResponseEntity<PageResult<SysLog>> queryUserLog(SysLogQueryCriteria criteria){
+    public ResponseEntity<Object> queryUserLog(SysLogQueryCriteria criteria) {
         criteria.setLogType("INFO");
         criteria.setUsername(SecurityUtils.getCurrentUsername());
         Page<SysLog> page = new Page<>(criteria.getPage(), criteria.getSize());
-        return new ResponseEntity<>(sysLogService.queryAllByUser(criteria,page), HttpStatus.OK);
+        return new ResponseEntity<>(R.success(sysLogService.queryAllByUser(criteria, page)), HttpStatus.OK);
     }
 
     @GetMapping(value = "/error")
     @ApiOperation("错误日志查询")
     @PreAuthorize("@el.check()")
-    public ResponseEntity<PageResult<SysLog>> queryErrorLog(SysLogQueryCriteria criteria){
+    public ResponseEntity<Object> queryErrorLog(SysLogQueryCriteria criteria) {
         criteria.setLogType("ERROR");
         Page<SysLog> page = new Page<>(criteria.getPage(), criteria.getSize());
-        return new ResponseEntity<>(sysLogService.queryAll(criteria,page), HttpStatus.OK);
+        return new ResponseEntity<>(R.success(sysLogService.queryAll(criteria, page)), HttpStatus.OK);
     }
 
     @GetMapping(value = "/error/{id}")
     @ApiOperation("日志异常详情查询")
     @PreAuthorize("@el.check()")
-    public ResponseEntity<Object> queryErrorLogDetail(@PathVariable Long id){
-        return new ResponseEntity<>(sysLogService.findByErrDetail(id), HttpStatus.OK);
+    public ResponseEntity<Object> queryErrorLogDetail(@PathVariable Long id) {
+        return new ResponseEntity<>(R.success(sysLogService.findByErrDetail(id)), HttpStatus.OK);
     }
+
     @DeleteMapping(value = "/del/error")
     @Log("删除所有ERROR日志")
     @ApiOperation("删除所有ERROR日志")
     @PreAuthorize("@el.check()")
-    public ResponseEntity<Object> delAllErrorLog(){
+    public ResponseEntity<Object> delAllErrorLog() {
         sysLogService.delAllByError();
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 
     @DeleteMapping(value = "/del/info")
     @Log("删除所有INFO日志")
     @ApiOperation("删除所有INFO日志")
     @PreAuthorize("@el.check()")
-    public ResponseEntity<Object> delAllInfoLog(){
+    public ResponseEntity<Object> delAllInfoLog() {
         sysLogService.delAllByInfo();
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 }
diff --git a/oying-system/src/main/java/com/oying/AppRun.java b/oying-system/src/main/java/com/oying/AppRun.java
index d040eaf..1616dd6 100644
--- a/oying-system/src/main/java/com/oying/AppRun.java
+++ b/oying-system/src/main/java/com/oying/AppRun.java
@@ -5,7 +5,6 @@
 import lombok.extern.slf4j.Slf4j;
 import com.oying.annotation.rest.AnonymousGetMapping;
 import com.oying.utils.SpringBeanHolder;
-import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.context.ApplicationPidFileWriter;
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/converter/PlatformCategoryDtoAssembler.java b/oying-system/src/main/java/com/oying/modules/pc/category/converter/PlatformCategoryDtoAssembler.java
new file mode 100644
index 0000000..1c84e51
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/converter/PlatformCategoryDtoAssembler.java
@@ -0,0 +1,10 @@
+package com.oying.modules.pc.category.converter;
+
+import com.oying.modules.pc.category.domain.PlatformCategory;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryCreateRequest;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryUpdateRequest;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PlatformCategoryDtoAssembler {
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/converter/PlatformCategoryViewAssembler.java b/oying-system/src/main/java/com/oying/modules/pc/category/converter/PlatformCategoryViewAssembler.java
new file mode 100644
index 0000000..8b70f78
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/converter/PlatformCategoryViewAssembler.java
@@ -0,0 +1,25 @@
+package com.oying.modules.pc.category.converter;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.oying.modules.pc.category.domain.PlatformCategory;
+import com.oying.modules.pc.category.view.PlatformCategoryCustomerView;
+import com.oying.modules.pc.category.view.PlatformCategoryView;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PlatformCategoryViewAssembler {
+
+    public PlatformCategoryView toPlatformCategoryResponse(PlatformCategory category) {
+        PlatformCategoryView categoryView = new PlatformCategoryView();
+        BeanUtil.copyProperties(category, categoryView);
+        categoryView.setIconUrl("");
+        return categoryView;
+    }
+
+    public PlatformCategoryCustomerView toCustomerPlatformCategoryResponse(PlatformCategory category) {
+        PlatformCategoryCustomerView categoryView = new PlatformCategoryCustomerView();
+        BeanUtil.copyProperties(category, categoryView);
+        categoryView.setIconUrl("");
+        return categoryView;
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/domain/PlatformCategory.java b/oying-system/src/main/java/com/oying/modules/pc/category/domain/PlatformCategory.java
new file mode 100644
index 0000000..258cc2b
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/domain/PlatformCategory.java
@@ -0,0 +1,72 @@
+package com.oying.modules.pc.category.domain;
+
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import java.sql.Timestamp;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+/**
+* @description /
+* @author lzp
+* @date 2025-04-28
+**/
+@Data
+@TableName("pc_platform_category")
+public class PlatformCategory implements Serializable {
+
+    @TableId(value = "category_id", type = IdType.AUTO)
+    @ApiModelProperty(value = "类目ID")
+    private Long categoryId;
+
+    @NotNull
+    @ApiModelProperty(value = "父类目ID")
+    private Long parentId;
+
+    @NotBlank
+    @ApiModelProperty(value = "类目名称")
+    private String name;
+
+    @NotNull
+    @ApiModelProperty(value = "类目层级:1-级类目 ")
+    private Integer level;
+
+    @NotNull
+    @ApiModelProperty(value = "排序权重")
+    private Integer sortWeight;
+
+    @ApiModelProperty(value = "类目图标ID")
+    private Long iconId;
+
+    @NotNull
+    @ApiModelProperty(value = "状态")
+    private Integer status;
+
+    @NotNull
+    @ApiModelProperty(value = "是否启用(0-否 1-是)")
+    private Integer active;
+
+    @ApiModelProperty(value = "创建人")
+    private Long createBy;
+
+    @NotNull
+    @ApiModelProperty(value = "创建时间")
+    private Timestamp createTime;
+
+    @ApiModelProperty(value = "修改人")
+    private Long updateBy;
+
+    @NotNull
+    @ApiModelProperty(value = "更新时间")
+    private Timestamp updateTime;
+
+    public void copy(PlatformCategory source){
+        BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryCreateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryCreateRequest.java
new file mode 100644
index 0000000..e22e4e3
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryCreateRequest.java
@@ -0,0 +1,33 @@
+package com.oying.modules.pc.category.domain.dto;
+
+import cn.hutool.json.JSONUtil;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class PlatformCategoryCreateRequest {
+
+    @NotBlank
+    @ApiModelProperty(value = "类目名称", example = "超市")
+    private String name;
+
+    @ApiModelProperty(value = "排序权重", example = "1")
+    private Integer sortWeight;
+
+    @ApiModelProperty(value = "是否启用", example = "1")
+    private int active;
+
+    @ApiModelProperty(value = "上传类目图标文件ID", example = "4682827376555999")
+    private Long iconUploadFileId;
+
+    public static void main(String[] args) {
+        PlatformCategoryCreateRequest platformCategory = new PlatformCategoryCreateRequest();
+        platformCategory.setName("美食");
+        platformCategory.setSortWeight(1);
+        platformCategory.setIconUploadFileId(1L);
+        platformCategory.setActive(1);
+        System.out.println(JSONUtil.toJsonStr(platformCategory));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryQueryCriteria.java b/oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryQueryCriteria.java
new file mode 100644
index 0000000..3ed3ef2
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryQueryCriteria.java
@@ -0,0 +1,22 @@
+package com.oying.modules.pc.category.domain.dto;
+
+import lombok.Data;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+* @author lzp
+* @date 2025-04-30
+**/
+@Data
+public class PlatformCategoryQueryCriteria{
+
+    @ApiModelProperty(value = "是否启用", example = "1")
+    private Integer active = 1;
+
+    @ApiModelProperty(value = "页码", example = "1")
+    private Integer page = 1;
+
+    @ApiModelProperty(value = "每页数据量", example = "10")
+    private Integer size = 10;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryUpdateDto.java b/oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryUpdateDto.java
new file mode 100644
index 0000000..a8ca29d
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryUpdateDto.java
@@ -0,0 +1,21 @@
+package com.oying.modules.pc.category.domain.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class PlatformCategoryUpdateDto {
+
+    private Long categoryId;
+
+    private String name;
+
+    private Integer sortWeight;
+
+    private Long iconUploadFileId;
+
+    private int active;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryUpdateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryUpdateRequest.java
new file mode 100644
index 0000000..be896e5
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/domain/dto/PlatformCategoryUpdateRequest.java
@@ -0,0 +1,24 @@
+package com.oying.modules.pc.category.domain.dto;
+
+import com.oying.modules.pc.category.domain.PlatformCategory;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class PlatformCategoryUpdateRequest {
+
+    @ApiModelProperty(value = "类目名称", example = "超市")
+    private String name;
+
+    @ApiModelProperty(value = "排序权重", example = "1")
+    private Integer sortWeight;
+
+    @ApiModelProperty(value = "上传类目图标文件ID", example = "2682827376555999239484")
+    private Long iconUploadFileId;
+
+    @ApiModelProperty(value = "是否启用", example = "1")
+    private int active;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/mapper/PlatformCategoryMapper.java b/oying-system/src/main/java/com/oying/modules/pc/category/mapper/PlatformCategoryMapper.java
new file mode 100644
index 0000000..16f289d
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/mapper/PlatformCategoryMapper.java
@@ -0,0 +1,22 @@
+package com.oying.modules.pc.category.mapper;
+
+import com.oying.modules.pc.category.domain.PlatformCategory;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryQueryCriteria;
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Mapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+* @author lzp
+* @date 2025-04-30
+**/
+@Mapper
+public interface PlatformCategoryMapper extends BaseMapper<PlatformCategory> {
+
+    IPage<PlatformCategory> findAll(@Param("criteria") PlatformCategoryQueryCriteria criteria, Page<Object> page);
+
+    List<PlatformCategory> findAll(@Param("criteria") PlatformCategoryQueryCriteria criteria);
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/rest/PlatformCategoryAdminController.java b/oying-system/src/main/java/com/oying/modules/pc/category/rest/PlatformCategoryAdminController.java
new file mode 100644
index 0000000..fd2668e
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/rest/PlatformCategoryAdminController.java
@@ -0,0 +1,83 @@
+package com.oying.modules.pc.category.rest;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.oying.annotation.Log;
+import com.oying.modules.pc.category.converter.PlatformCategoryViewAssembler;
+import com.oying.modules.pc.category.domain.PlatformCategory;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryCreateRequest;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryQueryCriteria;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryUpdateDto;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryUpdateRequest;
+import com.oying.modules.pc.category.service.PlatformCategoryService;
+import com.oying.modules.pc.category.view.PlatformCategoryView;
+import com.oying.utils.R;
+import com.oying.utils.PageResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author lzp
+ * @date 2025-04-28
+ **/
+@RestController
+@RequiredArgsConstructor
+@Api(tags = "平台类目")
+@RequestMapping("/api/pc/admin/platformCategory")
+public class PlatformCategoryAdminController {
+
+    private final PlatformCategoryService categoryService;
+    private final PlatformCategoryViewAssembler assembler;
+
+    @GetMapping
+    @ApiOperation("查询平台类目(支持分页)")
+    @PreAuthorize("@el.check('admin:platformCategory:list')")
+    public ResponseEntity<?> queryPlatformCategory(PlatformCategoryQueryCriteria criteria) {
+        Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
+        PageResult<PlatformCategory> pageResult = categoryService.queryAll(criteria, page);
+        List<PlatformCategoryView> responseList = Optional.ofNullable(pageResult.getContent()).orElse(new ArrayList<>()).stream().map(assembler::toPlatformCategoryResponse).collect(Collectors.toList());
+        PageResult<PlatformCategoryView> responsePageResult = new PageResult<>(responseList, pageResult.getTotalElements());
+        return ResponseEntity.ok(R.success(responsePageResult));
+    }
+
+    @PostMapping
+    @ApiOperation("新增平台类目")
+    //@PreAuthorize("@el.check('admin:platformCategory:create')")
+    public ResponseEntity<?> create(@Validated @RequestBody PlatformCategoryCreateRequest request) {
+        categoryService.create(request);
+        return ResponseEntity.status(HttpStatus.CREATED).build();
+    }
+
+    @PutMapping("/{categoryId}")
+    @ApiOperation("修改平台类目")
+    //@PreAuthorize("@el.check('admin:platformCategory:updateById')")
+    public ResponseEntity<?> updateById(@PathVariable Long categoryId,
+                       @Validated @RequestBody PlatformCategoryUpdateRequest request) {
+        PlatformCategoryUpdateDto updateDto = new PlatformCategoryUpdateDto();
+        BeanUtils.copyProperties(request, updateDto);
+        updateDto.setCategoryId(categoryId);
+        categoryService.update(updateDto);
+        return ResponseEntity.noContent().build();
+    }
+
+    @DeleteMapping
+    @Log("删除平台类目")
+    @ApiOperation("删除平台类目")
+    //@PreAuthorize("@el.check('admin:platformCategory:batchDel')")
+    public ResponseEntity<?> batchDelete(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
+        categoryService.deleteAll(ids);
+        return ResponseEntity.noContent().build();
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/rest/PlatformCategoryCustomerController.java b/oying-system/src/main/java/com/oying/modules/pc/category/rest/PlatformCategoryCustomerController.java
new file mode 100644
index 0000000..fff0767
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/rest/PlatformCategoryCustomerController.java
@@ -0,0 +1,43 @@
+package com.oying.modules.pc.category.rest;
+
+import com.oying.modules.pc.category.converter.PlatformCategoryViewAssembler;
+import com.oying.modules.pc.category.domain.PlatformCategory;
+import com.oying.modules.pc.category.view.PlatformCategoryCustomerView;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryQueryCriteria;
+import com.oying.modules.pc.category.service.PlatformCategoryService;
+import com.oying.utils.R;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author lzp
+ * @date 2025-04-28
+ **/
+@RestController
+@RequiredArgsConstructor
+@Api(tags = "平台类目(客户端)")
+@RequestMapping("/api/pc/customer/platformCategory")
+public class PlatformCategoryCustomerController {
+
+    private final PlatformCategoryService categoryService;
+    private final PlatformCategoryViewAssembler assembler;
+
+    @GetMapping("/list")
+    @ApiOperation("查询平台类目")
+    //@PreAuthorize("@el.check('customer:platformCategory:list')")
+    public ResponseEntity<?> queryPlatformCategory() {
+        PlatformCategoryQueryCriteria criteria = new PlatformCategoryQueryCriteria();
+        criteria.setActive(1);
+        List<PlatformCategory> platformCategoryList = categoryService.queryAll(criteria);
+        List<PlatformCategoryCustomerView> responseList = platformCategoryList.stream().map(assembler::toCustomerPlatformCategoryResponse).collect(Collectors.toList());
+        return ResponseEntity.ok(R.success(responseList));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/service/PlatformCategoryService.java b/oying-system/src/main/java/com/oying/modules/pc/category/service/PlatformCategoryService.java
new file mode 100644
index 0000000..490df6b
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/service/PlatformCategoryService.java
@@ -0,0 +1,59 @@
+package com.oying.modules.pc.category.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.oying.modules.pc.category.domain.PlatformCategory;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryCreateRequest;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryQueryCriteria;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryUpdateDto;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryUpdateRequest;
+import com.oying.utils.PageResult;
+
+import java.util.List;
+
+/**
+ * 平台类目服务接口
+ *
+ * @author lzp
+ * @date 2025-04-30
+ **/
+public interface PlatformCategoryService extends IService<PlatformCategory> {
+
+    /**
+     * 查询数据分页
+     *
+     * @param criteria 条件
+     * @param page     分页参数
+     * @return PageResult
+     */
+    PageResult<PlatformCategory> queryAll(PlatformCategoryQueryCriteria criteria, Page<Object> page);
+
+    /**
+     * 查询所有数据不分页
+     *
+     * @param criteria 条件参数
+     * @return List<PlatformCategoryDto>
+     */
+    List<PlatformCategory> queryAll(PlatformCategoryQueryCriteria criteria);
+
+    /**
+     * 创建
+     *
+     * @param resources /
+     */
+    void create(PlatformCategoryCreateRequest resources);
+
+    /**
+     * 编辑
+     *
+     * @param resources /
+     */
+    void update(PlatformCategoryUpdateDto resources);
+
+    /**
+     * 多选删除
+     *
+     * @param ids /
+     */
+    void deleteAll(List<Long> ids);
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/service/impl/PlatformCategoryServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/category/service/impl/PlatformCategoryServiceImpl.java
new file mode 100644
index 0000000..5b220a6
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/service/impl/PlatformCategoryServiceImpl.java
@@ -0,0 +1,90 @@
+package com.oying.modules.pc.category.service.impl;
+
+import cn.hutool.core.util.ObjUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.oying.exception.EntityExistException;
+import com.oying.modules.pc.category.converter.PlatformCategoryDtoAssembler;
+import com.oying.modules.pc.category.domain.PlatformCategory;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryCreateRequest;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryQueryCriteria;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryUpdateDto;
+import com.oying.modules.pc.category.domain.dto.PlatformCategoryUpdateRequest;
+import com.oying.modules.pc.category.mapper.PlatformCategoryMapper;
+import com.oying.modules.pc.category.service.PlatformCategoryService;
+import com.oying.utils.PageResult;
+import com.oying.utils.PageUtil;
+import com.oying.utils.SecurityUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 平台类目服务实现
+ *
+ * @author lzp
+ * @date 2025-04-30
+ **/
+@Service
+@RequiredArgsConstructor
+public class PlatformCategoryServiceImpl extends ServiceImpl<PlatformCategoryMapper, PlatformCategory> implements PlatformCategoryService {
+
+    private final PlatformCategoryMapper platformCategoryMapper;
+
+    @Override
+    public PageResult<PlatformCategory> queryAll(PlatformCategoryQueryCriteria criteria, Page<Object> page) {
+        return PageUtil.toPage(platformCategoryMapper.findAll(criteria, page));
+    }
+
+    @Override
+    public List<PlatformCategory> queryAll(PlatformCategoryQueryCriteria criteria) {
+        return platformCategoryMapper.findAll(criteria);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void create(PlatformCategoryCreateRequest request) {
+
+        PlatformCategory platformCategoryCreate = new PlatformCategory();
+        platformCategoryCreate.setName(request.getName());
+        platformCategoryCreate.setSortWeight(request.getSortWeight());
+        platformCategoryCreate.setIconId(request.getIconUploadFileId());
+        platformCategoryCreate.setActive(request.getActive());
+        platformCategoryCreate.setCreateBy(SecurityUtils.getCurrentUserId());
+
+        // 使用处理图标文件
+        platformCategoryMapper.insert(platformCategoryCreate);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void update(PlatformCategoryUpdateDto updateDto) {
+
+        Long categoryId = updateDto.getCategoryId();
+        PlatformCategory existingPlatformCategory = this.getById(categoryId);
+        if (ObjUtil.isEmpty(existingPlatformCategory)) {
+            throw new EntityExistException(PlatformCategory.class, "categoryId", Optional.ofNullable(categoryId).map(Object::toString).orElse("null"));
+        }
+
+        PlatformCategory platformCategoryUpdate = new PlatformCategory();
+        platformCategoryUpdate.setCategoryId(updateDto.getCategoryId());
+        platformCategoryUpdate.setName(updateDto.getName());
+        platformCategoryUpdate.setSortWeight(updateDto.getSortWeight());
+        platformCategoryUpdate.setIconId(updateDto.getIconUploadFileId());
+        platformCategoryUpdate.setActive(updateDto.getActive());
+        existingPlatformCategory.copy(platformCategoryUpdate);
+        existingPlatformCategory.setUpdateBy(SecurityUtils.getCurrentUserId());
+        platformCategoryMapper.updateById(existingPlatformCategory);
+
+        // 使用处理图标文件
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteAll(List<Long> ids) {
+        platformCategoryMapper.deleteBatchIds(ids);
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/view/PlatformCategoryCustomerView.java b/oying-system/src/main/java/com/oying/modules/pc/category/view/PlatformCategoryCustomerView.java
new file mode 100644
index 0000000..de6fcda
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/view/PlatformCategoryCustomerView.java
@@ -0,0 +1,16 @@
+package com.oying.modules.pc.category.view;
+
+import lombok.Data;
+
+@Data
+public class PlatformCategoryCustomerView {
+
+    private Long categoryId;
+
+    private String name;
+
+    private Integer sortWeight;
+
+    private String iconUrl;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/category/view/PlatformCategoryView.java b/oying-system/src/main/java/com/oying/modules/pc/category/view/PlatformCategoryView.java
new file mode 100644
index 0000000..3fa48a8
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/category/view/PlatformCategoryView.java
@@ -0,0 +1,33 @@
+package com.oying.modules.pc.category.view;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.sql.Timestamp;
+
+@Data
+public class PlatformCategoryView implements Serializable {
+
+    private Long categoryId;
+
+    private String name;
+
+    private Integer sort;
+
+    private String icon;
+
+    private String iconUrl;
+
+    private Integer status;
+
+    private Integer visible;
+
+    private Long createBy;
+
+    private Timestamp createTime;
+
+    private Long updateBy;
+
+    private Timestamp updateTime;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/common/core/constrant/Constants.java b/oying-system/src/main/java/com/oying/modules/pc/common/core/constrant/Constants.java
new file mode 100644
index 0000000..796bccf
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/common/core/constrant/Constants.java
@@ -0,0 +1,50 @@
+package com.oying.modules.pc.common.core.constrant;
+
+/**
+ * 通用常量信息
+ *
+ * @author lzp
+ * @date 2025-04-22
+ */
+public class Constants {
+
+    /**
+     * UTF-8 字符集
+     */
+    public static final String UTF8 = "UTF-8";
+
+    /**
+     * GBK 字符集
+     */
+    public static final String GBK = "GBK";
+
+    /**
+     * www主域
+     */
+    public static final String WWW = "www.";
+
+    /**
+     * RMI 远程方法调用
+     */
+    public static final String LOOKUP_RMI = "rmi:";
+
+    /**
+     * LDAP 远程方法调用
+     */
+    public static final String LOOKUP_LDAP = "ldap:";
+
+    /**
+     * LDAPS 远程方法调用
+     */
+    public static final String LOOKUP_LDAPS = "ldaps:";
+
+    /**
+     * http请求
+     */
+    public static final String HTTP = "http://";
+
+    /**
+     * https请求
+     */
+    public static final String HTTPS = "https://";
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/common/exception/LevelExceededException.java b/oying-system/src/main/java/com/oying/modules/pc/common/exception/LevelExceededException.java
new file mode 100644
index 0000000..eff343d
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/common/exception/LevelExceededException.java
@@ -0,0 +1,13 @@
+package com.oying.modules.pc.common.exception;
+
+public class LevelExceededException extends RuntimeException {
+
+    public LevelExceededException(Integer level, Integer maxLevel) {
+        super(generateMessage(level, maxLevel));
+    }
+
+    private static String generateMessage(Integer level, Integer maxLevel) {
+        return String.format("层级 %d 超过了允许的最大层级 (%d)", level, maxLevel);
+    }
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/common/id/StoreIdGenerator.java b/oying-system/src/main/java/com/oying/modules/pc/common/id/StoreIdGenerator.java
new file mode 100644
index 0000000..1abed33
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/common/id/StoreIdGenerator.java
@@ -0,0 +1,15 @@
+package com.oying.modules.pc.common.id;
+
+import cn.hutool.core.lang.Snowflake;
+import cn.hutool.core.util.IdUtil;
+import org.springframework.stereotype.Component;
+
+@Component
+public class StoreIdGenerator {
+
+    private static final Snowflake snowflake = IdUtil.getSnowflake(1,1);
+
+    public static long getId() {
+        return snowflake.nextId();
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/common/id/StoreIdentifierGenerator.java b/oying-system/src/main/java/com/oying/modules/pc/common/id/StoreIdentifierGenerator.java
new file mode 100644
index 0000000..1e26454
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/common/id/StoreIdentifierGenerator.java
@@ -0,0 +1,11 @@
+package com.oying.modules.pc.common.id;
+
+import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
+
+public class StoreIdentifierGenerator implements IdentifierGenerator {
+
+    @Override
+    public Number nextId(Object entity) {
+        return null;
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/common/id/StoreQualificationIdGenerator.java b/oying-system/src/main/java/com/oying/modules/pc/common/id/StoreQualificationIdGenerator.java
new file mode 100644
index 0000000..38b167c
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/common/id/StoreQualificationIdGenerator.java
@@ -0,0 +1,15 @@
+package com.oying.modules.pc.common.id;
+
+import cn.hutool.core.lang.Snowflake;
+import cn.hutool.core.util.IdUtil;
+import org.springframework.stereotype.Component;
+
+@Component
+public class StoreQualificationIdGenerator {
+
+    private static final Snowflake snowflake = IdUtil.getSnowflake(1,1);
+
+    public static long getId() {
+        return snowflake.nextId();
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/domain/Product.java b/oying-system/src/main/java/com/oying/modules/pc/product/domain/Product.java
new file mode 100644
index 0000000..9a7c28f
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/domain/Product.java
@@ -0,0 +1,120 @@
+package com.oying.modules.pc.product.domain;
+
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import java.sql.Timestamp;
+import java.math.BigDecimal;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+/**
+* @description /
+* @author lzp
+* @date 2025-04-30
+**/
+@Data
+@TableName("pc_product")
+public class Product implements Serializable {
+
+    @TableId(value = "product_id")
+    @ApiModelProperty(value = "ID")
+    private Long productId;
+
+    @NotBlank
+    @ApiModelProperty(value = "店铺ID")
+    private Long storeId;
+
+    @NotBlank
+    @ApiModelProperty(value = "条形码")
+    private String barcode;
+
+    @NotBlank
+    @ApiModelProperty(value = "商品名称")
+    private String name;
+
+    @NotBlank
+    @ApiModelProperty(value = "商品标题")
+    private String title;
+
+    @NotNull
+    @ApiModelProperty(value = "一级分类ID")
+    private Long categoryId;
+
+    @NotNull
+    @ApiModelProperty(value = "二级分类ID")
+    private Long secondCategoryId;
+
+    @NotNull
+    @ApiModelProperty(value = "状态:1000-草稿 1001上架 1002下架")
+    private Integer status;
+
+    @NotBlank
+    @ApiModelProperty(value = "主图片")
+    private String mainImage;
+
+    @ApiModelProperty(value = "详情图片")
+    private String detailImage;
+
+    @ApiModelProperty(value = "商品描述")
+    private String description;
+
+    @NotNull
+    @ApiModelProperty(value = "销售价格")
+    private BigDecimal price;
+
+    @NotNull
+    @ApiModelProperty(value = "库存数量")
+    private Integer stockQuantity;
+
+    @NotNull
+    @ApiModelProperty(value = "起售数量")
+    private Integer minPurchaseQuantity;
+
+    @ApiModelProperty(value = "预警库存")
+    private Integer warnStock;
+
+    @ApiModelProperty(value = "重量(单位:g)")
+    private Integer weight;
+
+    @ApiModelProperty(value = "宽度(单位:厘米)")
+    private Integer width;
+
+    @ApiModelProperty(value = "长度(单位:厘米)")
+    private Integer length;
+
+    @ApiModelProperty(value = "高度(单位:厘米)")
+    private Integer height;
+
+    @NotNull
+    @ApiModelProperty(value = "是否删除")
+    private Integer deletedFlag;
+
+    @NotNull
+    @ApiModelProperty(value = "创建人")
+    private Long createBy;
+
+    @NotNull
+    @ApiModelProperty(value = "创建时间")
+    private Timestamp createTime;
+
+    @NotNull
+    @ApiModelProperty(value = "修改人")
+    private Long updateBy;
+
+    @NotNull
+    @ApiModelProperty(value = "修改时间")
+    private Timestamp updateTime;
+
+    @NotNull
+    @ApiModelProperty(value = "版本号")
+    private Long version;
+
+    public void copy(Product source){
+        BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/domain/ProductCategory.java b/oying-system/src/main/java/com/oying/modules/pc/product/domain/ProductCategory.java
new file mode 100644
index 0000000..b677fdc
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/domain/ProductCategory.java
@@ -0,0 +1,52 @@
+package com.oying.modules.pc.product.domain;
+
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import java.sql.Timestamp;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+/**
+* @description /
+* @author lzp
+* @date 2025-05-13
+**/
+@Data
+@TableName("pc_product_category")
+public class ProductCategory implements Serializable {
+
+    @TableId(value = "id", type = IdType.AUTO)
+    @ApiModelProperty(value = "商品类目唯一标识")
+    private Long id;
+
+    @NotNull
+    @ApiModelProperty(value = "商品ID")
+    private Long productId;
+
+    @ApiModelProperty(value = "所属一级店铺类目ID")
+    private Long storeCategoryId;
+
+    @ApiModelProperty(value = "所属二级店铺类目ID")
+    private Long storeCategorySecondId;
+
+    @ApiModelProperty(value = "创建者")
+    private Long createBy;
+
+    @ApiModelProperty(value = "创建时间")
+    private Timestamp createTime;
+
+    @ApiModelProperty(value = "修改者")
+    private Long updateBy;
+
+    @ApiModelProperty(value = "修改时间")
+    private Timestamp updateTime;
+
+    public void copy(ProductCategory source){
+        BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductCategoryQueryCriteria.java b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductCategoryQueryCriteria.java
new file mode 100644
index 0000000..46eede8
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductCategoryQueryCriteria.java
@@ -0,0 +1,18 @@
+package com.oying.modules.pc.product.domain.dto;
+
+import lombok.Data;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+* @author lzp
+* @date 2025-05-13
+**/
+@Data
+public class ProductCategoryQueryCriteria{
+
+    @ApiModelProperty(value = "页码", example = "1")
+    private Integer page = 1;
+
+    @ApiModelProperty(value = "每页数据量", example = "10")
+    private Integer size = 10;
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductCustomerQueryCriteria.java b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductCustomerQueryCriteria.java
new file mode 100644
index 0000000..412ee55
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductCustomerQueryCriteria.java
@@ -0,0 +1,21 @@
+package com.oying.modules.pc.product.domain.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author lzp
+ * @date 2025-04-30
+ **/
+@Data
+public class ProductCustomerQueryCriteria {
+
+    private Long categoryId;
+
+    @ApiModelProperty(value = "页码", example = "1")
+    private Integer page = 1;
+
+    @ApiModelProperty(value = "每页数据量", example = "10")
+    private Integer size = 10;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductImageCreateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductImageCreateRequest.java
new file mode 100644
index 0000000..0fb9117
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductImageCreateRequest.java
@@ -0,0 +1,9 @@
+package com.oying.modules.pc.product.domain.dto;
+
+public class ProductImageCreateRequest {
+
+    private Long uploadId;
+
+    private Integer type;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductLabelCreateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductLabelCreateRequest.java
new file mode 100644
index 0000000..bcf7d49
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductLabelCreateRequest.java
@@ -0,0 +1,16 @@
+package com.oying.modules.pc.product.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class ProductLabelCreateRequest {
+
+    private String category;
+
+    private String labelName;
+
+    private String labelValue;
+
+    private String unit;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductMerchantCreateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductMerchantCreateRequest.java
new file mode 100644
index 0000000..85c8761
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductMerchantCreateRequest.java
@@ -0,0 +1,52 @@
+package com.oying.modules.pc.product.domain.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class ProductMerchantCreateRequest {
+
+    @NotBlank
+    private String barcode;
+
+    @NotBlank
+    private String name;
+
+    @NotBlank
+    private String title;
+
+    @NotNull
+    private Long categoryId;
+
+    private Long secondCategoryId;
+
+    @NotNull
+    private BigDecimal price;
+
+    @NotNull
+    private Integer stockQuantity;
+
+    private Integer minPurchaseQuantity;
+
+    private Integer warnStock;
+
+    @NotNull
+    private Integer weight;
+
+    private Integer length;
+
+    private Integer width;
+
+    private Integer height;
+
+    private Integer allowReturns;
+
+    private List<ProductImageCreateRequest> imageList;
+
+    private List<ProductLabelCreateRequest> labelList;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductMerchantUpdateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductMerchantUpdateRequest.java
new file mode 100644
index 0000000..734cb8f
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductMerchantUpdateRequest.java
@@ -0,0 +1,45 @@
+package com.oying.modules.pc.product.domain.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class ProductMerchantUpdateRequest {
+
+    private String barcode;
+
+    private String name;
+
+    private String title;
+
+    private Long categoryId;
+
+    private Long secondCategoryId;
+
+    private BigDecimal price;
+
+    private Integer stockQuantity;
+
+    private Integer minPurchaseQuantity;
+
+    private Integer warnStock;
+
+    private Integer weight;
+
+    private Integer length;
+
+    private Integer width;
+
+    private Integer height;
+
+    private Integer allowReturns;
+
+    private List<ProductImageCreateRequest> imageList;
+
+    private List<ProductLabelCreateRequest> specList;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductQueryCriteria.java b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductQueryCriteria.java
new file mode 100644
index 0000000..b89cf98
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductQueryCriteria.java
@@ -0,0 +1,34 @@
+package com.oying.modules.pc.product.domain.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author lzp
+ * @date 2025-04-30
+ **/
+@Data
+public class ProductQueryCriteria {
+
+    @ApiModelProperty(value = "搜索字段", example = "柚子")
+    private String blurry;
+
+    private Long productId;
+
+    private Long storeId;
+
+    private Integer status;
+
+    private Long categoryId;
+
+    private Long secondCategoryId;
+
+    private Integer active;
+
+    @ApiModelProperty(value = "页码", example = "1")
+    private Integer page = 1;
+
+    @ApiModelProperty(value = "每页数据量", example = "10")
+    private Integer size = 10;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductCategoryMapper.java b/oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductCategoryMapper.java
new file mode 100644
index 0000000..8fe2ade
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductCategoryMapper.java
@@ -0,0 +1,22 @@
+package com.oying.modules.pc.product.mapper;
+
+import com.oying.modules.pc.product.domain.ProductCategory;
+import com.oying.modules.pc.product.domain.dto.ProductCategoryQueryCriteria;
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Mapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+* @author lzp
+* @date 2025-05-13
+**/
+@Mapper
+public interface ProductCategoryMapper extends BaseMapper<ProductCategory> {
+
+    IPage<ProductCategory> findAll(@Param("criteria") ProductCategoryQueryCriteria criteria, Page<Object> page);
+
+    List<ProductCategory> findAll(@Param("criteria") ProductCategoryQueryCriteria criteria);
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductMapper.java b/oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductMapper.java
new file mode 100644
index 0000000..861cd02
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductMapper.java
@@ -0,0 +1,22 @@
+package com.oying.modules.pc.product.mapper;
+
+import com.oying.modules.pc.product.domain.Product;
+import com.oying.modules.pc.product.domain.dto.ProductQueryCriteria;
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Mapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+* @author lzp
+* @date 2025-04-30
+**/
+@Mapper
+public interface ProductMapper extends BaseMapper<Product> {
+
+    IPage<Product> findAll(@Param("criteria") ProductQueryCriteria criteria, Page<Object> page);
+
+    List<Product> findAll(@Param("criteria") ProductQueryCriteria criteria);
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductController.java b/oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductController.java
new file mode 100644
index 0000000..6d47589
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductController.java
@@ -0,0 +1,73 @@
+package com.oying.modules.pc.product.rest;
+
+import com.oying.annotation.Log;
+import com.oying.utils.R;
+import com.oying.modules.pc.product.domain.Product;
+import com.oying.modules.pc.product.service.ProductService;
+import com.oying.modules.pc.product.domain.dto.ProductQueryCriteria;
+import lombok.RequiredArgsConstructor;
+import java.util.List;
+
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import io.swagger.annotations.*;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.oying.utils.PageResult;
+
+/**
+* @author lzp
+* @date 2025-04-30
+**/
+@RestController
+@RequiredArgsConstructor
+@Api(tags = "商品")
+@RequestMapping("/api/product")
+public class ProductController {
+
+    private final ProductService productService;
+
+    @ApiOperation("导出数据")
+    @GetMapping(value = "/download")
+    @PreAuthorize("@el.check('product:list')")
+    public void exportProduct(HttpServletResponse response, ProductQueryCriteria criteria) throws IOException {
+        productService.download(productService.queryAll(criteria), response);
+    }
+
+    @GetMapping
+    @ApiOperation("查询商品")
+    @PreAuthorize("@el.check('product:list')")
+    public R<PageResult<Product>> queryProduct(ProductQueryCriteria criteria){
+        Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
+        return R.success(productService.queryAll(criteria,page));
+    }
+
+    @PostMapping
+    @Log("新增商品")
+    @ApiOperation("新增商品")
+    @PreAuthorize("@el.check('product:add')")
+    public R<?> createProduct(@Validated @RequestBody Product resources){
+        productService.create(resources);
+        return R.success();
+    }
+
+    @PutMapping
+    @Log("修改商品")
+    @ApiOperation("修改商品")
+    @PreAuthorize("@el.check('product:edit')")
+    public R<?> updateProduct(@Validated @RequestBody Product resources){
+        productService.update(resources);
+        return R.success();
+    }
+
+    @DeleteMapping
+    @Log("删除商品")
+    @ApiOperation("删除商品")
+    @PreAuthorize("@el.check('product:del')")
+    public R<?> deleteProduct(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
+        productService.deleteAll(ids);
+        return R.success();
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductCustomerController.java b/oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductCustomerController.java
new file mode 100644
index 0000000..c778cf8
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductCustomerController.java
@@ -0,0 +1,82 @@
+package com.oying.modules.pc.product.rest;
+
+import cn.hutool.core.collection.ListUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.oying.utils.R;
+import com.oying.modules.pc.product.domain.Product;
+import com.oying.modules.pc.product.domain.dto.ProductQueryCriteria;
+import com.oying.modules.pc.product.service.ProductService;
+import com.oying.modules.pc.product.view.ProductCustomerView;
+import com.oying.utils.PageResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/*
+*
+ * @author lzp
+ * @date 2025-04-30
+ *
+*/
+@RestController
+@RequiredArgsConstructor
+@Api(tags = "商品(客户端)")
+@RequestMapping("/api/pc/customer/store/{storeId}/product")
+public class ProductCustomerController {
+
+    private final ProductService productService;
+
+    @GetMapping(value = "/page")
+    @ApiOperation("根据商品名称模糊匹配店铺内的商品")
+    /*@PreAuthorize("@el.check('merchant:product:page')")*/
+    public ResponseEntity<?> query(@PathVariable Long storeId,
+                                   @RequestParam(value = "categoryId", required = false) Long categoryId,
+                                   @RequestParam(value = "secondCategoryId", required = false) Long secondCategoryId,
+                                   @RequestParam(value = "blurry", required = false) String blurry) {
+
+        ProductQueryCriteria criteria = new ProductQueryCriteria();
+        criteria.setStoreId(storeId);
+        criteria.setCategoryId(categoryId);
+        criteria.setSecondCategoryId(secondCategoryId);
+        criteria.setBlurry(blurry);
+        Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
+        PageResult<Product> productPageResult = productService.queryAll(criteria, page);
+
+        List<Product> productList = Optional.ofNullable(productPageResult.getContent()).orElse(ListUtil.empty());
+
+        PageResult<ProductCustomerView> viewPageResult = new PageResult<>(
+                productList.stream().map(i -> {
+                    ProductCustomerView view = new ProductCustomerView();
+                    BeanUtils.copyProperties(i, view);
+                    view.setScore(5.0D);
+                    view.setSold(0);
+                    return view;
+                }).collect(Collectors.toList()),
+                productPageResult.getTotalElements());
+        return ResponseEntity.ok(R.success(viewPageResult));
+    }
+
+    @GetMapping(value = "/{productId}/details")
+    @ApiOperation("查询商品")
+    /*@PreAuthorize("@el.check('merchant:product:byProductId')")*/
+    public ResponseEntity<?> getDetails(@PathVariable Long productId) {
+        Product product = productService.getById(productId);
+        ProductCustomerView customerView = new ProductCustomerView();
+        customerView.setProductId(product.getProductId());
+        customerView.setTitle(product.getTitle());
+        customerView.setPrice(product.getPrice());
+        customerView.setScore(5.0D);
+        customerView.setSold(0);
+        customerView.setLabelList(ListUtil.empty());
+        customerView.setMainImageList(ListUtil.empty());
+        return ResponseEntity.ok(R.success(customerView));
+    }
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductMerchantController.java b/oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductMerchantController.java
new file mode 100644
index 0000000..cf88760
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductMerchantController.java
@@ -0,0 +1,140 @@
+package com.oying.modules.pc.product.rest;
+
+import cn.hutool.core.collection.ListUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.oying.annotation.Log;
+import com.oying.utils.R;
+import com.oying.modules.pc.product.domain.Product;
+import com.oying.modules.pc.product.domain.dto.ProductMerchantCreateRequest;
+import com.oying.modules.pc.product.domain.dto.ProductMerchantUpdateRequest;
+import com.oying.modules.pc.product.domain.dto.ProductQueryCriteria;
+import com.oying.modules.pc.product.service.ProductMerchantService;
+import com.oying.modules.pc.product.service.ProductService;
+import com.oying.modules.pc.product.view.ProductMerchantDetailsView;
+import com.oying.modules.pc.product.view.ProductMerchantSimpleView;
+import com.oying.utils.PageResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author lzp
+ * @date 2025-04-30
+ **/
+@RestController
+@RequiredArgsConstructor
+@Api(tags = "商品(商户端)")
+@RequestMapping("/api/pc/merchant/store/{storeId}/product")
+public class ProductMerchantController {
+
+    private final ProductService productService;
+    private final ProductMerchantService productMerchantService;
+
+    @GetMapping(value = "/page")
+    @ApiOperation("获取指定商户店铺的商品列表(支持分页)")
+    /*@PreAuthorize("@el.check('merchant:product:page') " +
+            "and @storeMerchantOwnershipService.check(#storeId)")*/
+    public ResponseEntity<?> query(@PathVariable Long storeId,
+                                   ProductQueryCriteria criteria) {
+
+        criteria.setStoreId(storeId);
+        Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
+        PageResult<Product> productPageResult = productService.queryAll(criteria, page);
+        List<Product> productList = Optional.ofNullable(productPageResult.getContent()).orElse(ListUtil.empty());
+        PageResult<ProductMerchantSimpleView> viewPageResult = new PageResult<>(
+                productList.stream().map(i -> {
+                    ProductMerchantSimpleView view = new ProductMerchantSimpleView();
+                    BeanUtils.copyProperties(i, view);
+                    return view;
+                }).collect(Collectors.toList()),
+                productPageResult.getTotalElements());
+        return ResponseEntity.ok(R.success(viewPageResult));
+    }
+
+    @GetMapping(value = "/{productId}")
+    @ApiOperation("查询商品")
+    /*@PreAuthorize("@el.check('merchant:product:byProductId') " +
+            "and @storeMerchantOwnershipService.check(#storeId)")*/
+    public ResponseEntity<?> getById(@PathVariable Long productId) {
+        return ResponseEntity.ok(R.success(productService.getById(productId)));
+    }
+
+    @GetMapping(value = "/{productId}/details")
+    @ApiOperation("查询商品详情")
+    /*@PreAuthorize("@el.check('merchant:product:byProductId') " +
+            "and @storeMerchantOwnershipService.check(#storeId)")*/
+    public ResponseEntity<?> getDetailsById(@PathVariable Long productId) {
+        Product product = productService.getById(productId);
+        ProductMerchantDetailsView view = null;
+        if (product != null) {
+            view = new ProductMerchantDetailsView();
+            BeanUtils.copyProperties(product, view);
+            view.setMainImageList(ListUtil.empty());
+            view.setLabelList(ListUtil.empty());
+        }
+        return ResponseEntity.ok(R.success(view));
+    }
+
+    @PostMapping
+    @Log("新增商品")
+    @ApiOperation("新增商品")
+    //@PreAuthorize("@el.check('merchant:product:add') " +
+    //        "and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> createProduct(@PathVariable Long storeId,
+                                           @Validated @RequestBody ProductMerchantCreateRequest request) {
+
+        productMerchantService.create(storeId, request);
+        return ResponseEntity.noContent().build();
+    }
+
+    @PutMapping(value = "/{productId}")
+    @Log("修改商品")
+    @ApiOperation("修改商品")
+    /*@PreAuthorize("@el.check('merchant:product:edit') " +
+            "and @storeMerchantOwnershipService.check(#storeId)")*/
+    public ResponseEntity<?> updateProduct(@PathVariable Long productId,
+                                           @Validated @RequestBody ProductMerchantUpdateRequest request) {
+
+        productMerchantService.update(productId, request);
+        return ResponseEntity.noContent().build();
+    }
+
+    @DeleteMapping
+    @Log("批量删除商品")
+    @ApiOperation("批量删除商品")
+    //@PreAuthorize("@el.check('merchant:product:batchDel') " +
+    //        "and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> deleteProduct(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
+        productMerchantService.batchDelete(ids);
+        return ResponseEntity.noContent().build();
+    }
+
+    @PutMapping(value = "/{productId}/on")
+    @Log("上架商品")
+    @ApiOperation("上架商品")
+    /*@PreAuthorize("@el.check('merchant:product:on') " +
+            "and @storeMerchantOwnershipService.check(#storeId)")*/
+    public ResponseEntity<?> putOnShelf(@PathVariable("productId") Long productId) {
+        productMerchantService.putOnShelf(productId);
+        return ResponseEntity.noContent().build();
+    }
+
+    @PutMapping(value = "/{productId}/off")
+    @Log("下架商品")
+    @ApiOperation("下架商品")
+    /*@PreAuthorize("@el.check('merchant:product:off') " +
+            "and @storeMerchantOwnershipService.check(#storeId)")*/
+    public ResponseEntity<?> takeOffShelf(@PathVariable("productId") Long productId) {
+        productMerchantService.takeOffShelf(productId);
+        return ResponseEntity.noContent().build();
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductCategoryService.java b/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductCategoryService.java
new file mode 100644
index 0000000..8e3aa61
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductCategoryService.java
@@ -0,0 +1,60 @@
+package com.oying.modules.pc.product.service;
+
+import com.oying.modules.pc.product.domain.ProductCategory;
+import com.oying.modules.pc.product.domain.dto.ProductCategoryQueryCriteria;
+import java.util.Map;
+import java.util.List;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.oying.utils.PageResult;
+
+/**
+* @description 服务接口
+* @author lzp
+* @date 2025-05-13
+**/
+public interface ProductCategoryService extends IService<ProductCategory> {
+
+    /**
+    * 查询数据分页
+    * @param criteria 条件
+    * @param page 分页参数
+    * @return PageResult
+    */
+    PageResult<ProductCategory> queryAll(ProductCategoryQueryCriteria criteria, Page<Object> page);
+
+    /**
+    * 查询所有数据不分页
+    * @param criteria 条件参数
+    * @return List<ProductCategoryDto>
+    */
+    List<ProductCategory> queryAll(ProductCategoryQueryCriteria criteria);
+
+    /**
+    * 创建
+    * @param resources /
+    */
+    void create(ProductCategory resources);
+
+    /**
+    * 编辑
+    * @param resources /
+    */
+    void update(ProductCategory resources);
+
+    /**
+    * 多选删除
+    * @param ids /
+    */
+    void deleteAll(List<Long> ids);
+
+    /**
+    * 导出数据
+    * @param all 待导出的数据
+    * @param response /
+    * @throws IOException /
+    */
+    void download(List<ProductCategory> all, HttpServletResponse response) throws IOException;
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductMerchantService.java b/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductMerchantService.java
new file mode 100644
index 0000000..dba1948
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductMerchantService.java
@@ -0,0 +1,16 @@
+package com.oying.modules.pc.product.service;
+
+import com.oying.modules.pc.product.domain.dto.ProductMerchantCreateRequest;
+import com.oying.modules.pc.product.domain.dto.ProductMerchantUpdateRequest;
+
+import java.util.List;
+
+public interface ProductMerchantService {
+
+    void create(Long storeId, ProductMerchantCreateRequest request);
+    void update(Long storeId, ProductMerchantUpdateRequest request);
+    void batchDelete(List<Long> ids);
+    void putOnShelf(Long productId);
+    void takeOffShelf(Long productId);
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductService.java b/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductService.java
new file mode 100644
index 0000000..a610f1d
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductService.java
@@ -0,0 +1,60 @@
+package com.oying.modules.pc.product.service;
+
+import com.oying.modules.pc.product.domain.Product;
+import com.oying.modules.pc.product.domain.dto.ProductQueryCriteria;
+
+import java.util.List;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.oying.utils.PageResult;
+
+/**
+* @description 服务接口
+* @author lzp
+* @date 2025-04-30
+**/
+public interface ProductService extends IService<Product> {
+
+    /**
+    * 查询数据分页
+    * @param criteria 条件
+    * @param page 分页参数
+    * @return PageResult
+    */
+    PageResult<Product> queryAll(ProductQueryCriteria criteria, Page<Object> page);
+
+    /**
+    * 查询所有数据不分页
+    * @param criteria 条件参数
+    * @return List<ProductDto>
+    */
+    List<Product> queryAll(ProductQueryCriteria criteria);
+
+    /**
+    * 创建
+    * @param resources /
+    */
+    void create(Product resources);
+
+    /**
+    * 编辑
+    * @param resources /
+    */
+    void update(Product resources);
+
+    /**
+    * 多选删除
+    * @param ids /
+    */
+    void deleteAll(List<Long> ids);
+
+    /**
+    * 导出数据
+    * @param all 待导出的数据
+    * @param response /
+    * @throws IOException /
+    */
+    void download(List<Product> all, HttpServletResponse response) throws IOException;
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductCategoryServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductCategoryServiceImpl.java
new file mode 100644
index 0000000..844836f
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductCategoryServiceImpl.java
@@ -0,0 +1,79 @@
+package com.oying.modules.pc.product.service.impl;
+
+import com.oying.modules.pc.product.domain.ProductCategory;
+import com.oying.utils.FileUtil;
+import lombok.RequiredArgsConstructor;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.oying.modules.pc.product.service.ProductCategoryService;
+import com.oying.modules.pc.product.domain.dto.ProductCategoryQueryCriteria;
+import com.oying.modules.pc.product.mapper.ProductCategoryMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.oying.utils.PageUtil;
+import java.util.List;
+import java.util.Map;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import com.oying.utils.PageResult;
+
+/**
+* @description 服务实现
+* @author lzp
+* @date 2025-05-13
+**/
+@Service
+@RequiredArgsConstructor
+public class ProductCategoryServiceImpl extends ServiceImpl<ProductCategoryMapper, ProductCategory> implements ProductCategoryService {
+
+    private final ProductCategoryMapper productCategoryMapper;
+
+    @Override
+    public PageResult<ProductCategory> queryAll(ProductCategoryQueryCriteria criteria, Page<Object> page){
+        return PageUtil.toPage(productCategoryMapper.findAll(criteria, page));
+    }
+
+    @Override
+    public List<ProductCategory> queryAll(ProductCategoryQueryCriteria criteria){
+        return productCategoryMapper.findAll(criteria);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void create(ProductCategory resources) {
+        productCategoryMapper.insert(resources);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void update(ProductCategory resources) {
+        ProductCategory productCategory = getById(resources.getId());
+        productCategory.copy(resources);
+        productCategoryMapper.updateById(productCategory);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteAll(List<Long> ids) {
+        productCategoryMapper.deleteBatchIds(ids);
+    }
+
+    @Override
+    public void download(List<ProductCategory> all, HttpServletResponse response) throws IOException {
+        List<Map<String, Object>> list = new ArrayList<>();
+        for (ProductCategory productCategory : all) {
+            Map<String, Object> map = new LinkedHashMap<>();
+            map.put("商品ID", productCategory.getProductId());
+            map.put("所属一级店铺类目ID", productCategory.getStoreCategoryId());
+            map.put("所属二级店铺类目ID", productCategory.getStoreCategorySecondId());
+            map.put("创建者", productCategory.getCreateBy());
+            map.put("创建时间", productCategory.getCreateTime());
+            map.put("修改者", productCategory.getUpdateBy());
+            map.put("修改时间", productCategory.getUpdateTime());
+            list.add(map);
+        }
+        FileUtil.downloadExcel(list, response);
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantCreateServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantCreateServiceImpl.java
new file mode 100644
index 0000000..c675445
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantCreateServiceImpl.java
@@ -0,0 +1,59 @@
+package com.oying.modules.pc.product.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.oying.modules.pc.product.domain.Product;
+import com.oying.modules.pc.product.domain.dto.ProductMerchantCreateRequest;
+import com.oying.modules.pc.product.domain.dto.ProductMerchantUpdateRequest;
+import com.oying.modules.pc.product.service.ProductMerchantService;
+import com.oying.modules.pc.product.service.ProductService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Service
+@RequiredArgsConstructor
+public class ProductMerchantCreateServiceImpl implements ProductMerchantService {
+
+    private final ProductService productService;
+
+    @Override
+    public void create(Long storeId, ProductMerchantCreateRequest request) {
+        Product product = new Product();
+        BeanUtils.copyProperties(request, product);
+        product.setStoreId(storeId);
+        productService.create(product);
+    }
+
+    @Override
+    public void update(Long productId, ProductMerchantUpdateRequest request) {
+        Product product = new Product();
+        BeanUtils.copyProperties(request, product);
+        product.setProductId(productId);
+        productService.update(product);
+    }
+
+    @Transactional
+    @Override
+    public void batchDelete(List<Long> ids) {
+        productService.deleteAll(ids);
+    }
+
+    @Override
+    public void putOnShelf(Long productId) {
+        LambdaUpdateWrapper<Product> wrapper = new LambdaUpdateWrapper<Product>()
+                .eq(Product::getProductId, productId)
+                .set(Product::getStatus, 1001);
+        productService.update(wrapper);
+    }
+
+    @Override
+    public void takeOffShelf(Long productId) {
+        LambdaUpdateWrapper<Product> wrapper = new LambdaUpdateWrapper<Product>()
+                .eq(Product::getProductId, productId)
+                .set(Product::getStatus, 1002);
+        productService.update(wrapper);
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductServiceImpl.java
new file mode 100644
index 0000000..5a91767
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductServiceImpl.java
@@ -0,0 +1,106 @@
+package com.oying.modules.pc.product.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.oying.modules.pc.product.domain.Product;
+import com.oying.modules.pc.product.domain.dto.ProductQueryCriteria;
+import com.oying.modules.pc.product.mapper.ProductMapper;
+import com.oying.modules.pc.product.service.ProductService;
+import com.oying.utils.FileUtil;
+import com.oying.utils.PageResult;
+import com.oying.utils.PageUtil;
+import com.oying.utils.SecurityUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author lzp
+ * @description 服务实现
+ * @date 2025-04-30
+ **/
+@Service
+@RequiredArgsConstructor
+public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
+
+    private final ProductMapper productMapper;
+
+    @Override
+    public PageResult<Product> queryAll(ProductQueryCriteria criteria, Page<Object> page) {
+        return PageUtil.toPage(productMapper.findAll(criteria, page));
+    }
+
+    @Override
+    public List<Product> queryAll(ProductQueryCriteria criteria) {
+        return productMapper.findAll(criteria);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void create(Product resources) {
+        resources.setCreateBy(SecurityUtils.getCurrentUserId());
+        productMapper.insert(resources);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void update(Product resources) {
+        Product product = getById(resources.getProductId());
+        product.copy(resources);
+        product.setUpdateBy(SecurityUtils.getCurrentUserId());
+        productMapper.updateById(product);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteAll(List<Long> ids) {
+        for (Long id : ids) {
+            LambdaUpdateWrapper<Product> wrapper = new LambdaUpdateWrapper<Product>()
+                    .eq(Product::getProductId, id)
+                    .set(Product::getDeletedFlag, 1);
+            // set状态
+            this.update(wrapper);
+        }
+    }
+
+    @Override
+    public void download(List<Product> all, HttpServletResponse response) throws IOException {
+        List<Map<String, Object>> list = new ArrayList<>();
+        for (Product product : all) {
+            Map<String, Object> map = new LinkedHashMap<>();
+            map.put("商品编号", product.getStoreId());
+            map.put("条形码", product.getBarcode());
+            map.put("商品名称", product.getName());
+            map.put("商品标题", product.getTitle());
+            map.put("分类ID", product.getCategoryId());
+            map.put("状态:1000-草稿 1001上架 1002下架", product.getStatus());
+            map.put("主图片", product.getMainImage());
+            map.put("详情图片", product.getDetailImage());
+            map.put("商品描述", product.getDescription());
+            map.put("销售价格", product.getPrice());
+            map.put("库存数量", product.getStockQuantity());
+            map.put("起售数量", product.getMinPurchaseQuantity());
+            map.put("预警库存", product.getWarnStock());
+            map.put("重量(单位:g)", product.getWeight());
+            map.put("宽度(单位:厘米)", product.getWidth());
+            map.put("长度(单位:厘米)", product.getLength());
+            map.put("高度(单位:厘米)", product.getHeight());
+            map.put("是否删除", product.getDeletedFlag());
+            map.put("创建人", product.getCreateBy());
+            map.put("创建时间", product.getCreateTime());
+            map.put("修改人", product.getUpdateBy());
+            map.put("修改时间", product.getUpdateTime());
+            map.put("版本号", product.getVersion());
+            list.add(map);
+        }
+        FileUtil.downloadExcel(list, response);
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductCustomerDetailsView.java b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductCustomerDetailsView.java
new file mode 100644
index 0000000..29204b7
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductCustomerDetailsView.java
@@ -0,0 +1,24 @@
+package com.oying.modules.pc.product.view;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 简单商品vo
+ * @author lzp
+ * @date 2025-04-25
+ */
+@Data
+public class ProductCustomerDetailsView {
+
+    private Long id;
+    private String title;
+    private BigDecimal price;
+    private Integer sold;
+
+    private List<ProductImageCustomerView> mainImageList;
+    private List<ProductLabelCustomerView> labelList;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductCustomerView.java b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductCustomerView.java
new file mode 100644
index 0000000..bf2ca91
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductCustomerView.java
@@ -0,0 +1,25 @@
+package com.oying.modules.pc.product.view;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 简单商品vo
+ * @author lzp
+ * @date 2025-04-25
+ */
+@Data
+public class ProductCustomerView {
+
+    private Long productId;
+    private String title;
+    private BigDecimal price;
+    private Double score;           // 评分
+    private Integer sold;    // 月销量
+
+    private List<ProductImageCustomerView> mainImageList;
+    private List<ProductLabelCustomerView> labelList;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductImageCustomerView.java b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductImageCustomerView.java
new file mode 100644
index 0000000..208cd49
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductImageCustomerView.java
@@ -0,0 +1,12 @@
+package com.oying.modules.pc.product.view;
+
+import lombok.Data;
+
+@Data
+public class ProductImageCustomerView {
+
+    private String url;
+    private Integer primaryFlag;
+    private Integer sortWeight;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductLabelCustomerView.java b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductLabelCustomerView.java
new file mode 100644
index 0000000..868e975
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductLabelCustomerView.java
@@ -0,0 +1,13 @@
+package com.oying.modules.pc.product.view;
+
+import lombok.Data;
+
+@Data
+public class ProductLabelCustomerView {
+
+    private Integer categoryId;
+    private String categoryName;
+    private String labelName;
+    private String labelValue;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductMerchantDetailsView.java b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductMerchantDetailsView.java
new file mode 100644
index 0000000..383115b
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductMerchantDetailsView.java
@@ -0,0 +1,25 @@
+package com.oying.modules.pc.product.view;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 简单商品vo
+ * @author lzp
+ * @date 2025-04-25
+ */
+@Data
+public class ProductMerchantDetailsView {
+
+    private Long productId;
+    private String name;
+    private BigDecimal price;
+    private Integer sold;
+    private Integer status;
+
+    private List<ProductImageCustomerView> mainImageList;
+    private List<ProductLabelCustomerView> labelList;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductMerchantSimpleView.java b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductMerchantSimpleView.java
new file mode 100644
index 0000000..b558519
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductMerchantSimpleView.java
@@ -0,0 +1,22 @@
+package com.oying.modules.pc.product.view;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 简单商品vo
+ * @author lzp
+ * @date 2025-04-25
+ */
+@Data
+public class ProductMerchantSimpleView {
+
+    private Long productId;
+    private String name;
+    private BigDecimal price;
+    private Integer stockQuantity;
+    private Integer sold;
+    private Integer status;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductOverviewView.java b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductOverviewView.java
new file mode 100644
index 0000000..01918a8
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductOverviewView.java
@@ -0,0 +1,4 @@
+package com.oying.modules.pc.product.view;
+
+public class ProductOverviewView {
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductSimpleView.java b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductSimpleView.java
new file mode 100644
index 0000000..c7df610
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/view/ProductSimpleView.java
@@ -0,0 +1,21 @@
+package com.oying.modules.pc.product.view;
+
+import java.math.BigDecimal;
+
+/**
+ * 简单商品vo
+ * @author lzp
+ * @date 2025-04-25
+ */
+public class ProductSimpleView {
+
+    private Long productId;
+    private String productTitle;
+    private String mainImage;
+    private BigDecimal price;
+    private BigDecimal originalPrice;  // 原价(用于显示划线价)
+    //private Double rating;           // 评分
+    //private Integer monthlySales;    // 月销量
+
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/search/domain/dto/NearbyStoreQueryCriteria.java b/oying-system/src/main/java/com/oying/modules/pc/search/domain/dto/NearbyStoreQueryCriteria.java
new file mode 100644
index 0000000..723d856
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/search/domain/dto/NearbyStoreQueryCriteria.java
@@ -0,0 +1,38 @@
+package com.oying.modules.pc.search.domain.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class NearbyStoreQueryCriteria {
+
+    @NotNull
+    private Double longitude; // 中心点经度
+
+    @NotNull
+    private Double latitude;  // 中心点纬度
+
+    @Min(100)
+    @Max(5000)
+    private Integer radius = 1000; // 搜索半径(米)
+
+    private Boolean onlyOpenNow = true; // 是否只查当前营业的
+
+    @Min(1)
+    @Max(50)
+    private Integer limit = 20; // 返回数量限制
+
+    // 分页参数
+    private Integer page = 1;
+
+    private Integer size = 10;
+
+    private String blurry;
+
+    private Long status;
+
+    private Long platformCategoryId;
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/search/domain/dto/StoreSearchDto.java b/oying-system/src/main/java/com/oying/modules/pc/search/domain/dto/StoreSearchDto.java
new file mode 100644
index 0000000..66f15c0
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/search/domain/dto/StoreSearchDto.java
@@ -0,0 +1,17 @@
+package com.oying.modules.pc.search.domain.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+public class StoreSearchDto {
+
+    // 店铺基础信息
+    private Long storeId;
+    private String storeName;
+    private String logoImage;
+    private Integer deliveryTime;
+    private Integer distance;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/search/rest/StoreSearchController.java b/oying-system/src/main/java/com/oying/modules/pc/search/rest/StoreSearchController.java
new file mode 100644
index 0000000..557a76e
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/search/rest/StoreSearchController.java
@@ -0,0 +1,58 @@
+package com.oying.modules.pc.search.rest;
+
+import cn.hutool.core.collection.CollUtil;
+import com.oying.utils.R;
+import com.oying.modules.pc.search.domain.dto.NearbyStoreQueryCriteria;
+import com.oying.modules.pc.search.domain.dto.StoreSearchDto;
+import com.oying.modules.pc.search.view.StoreSearchView;
+import com.oying.modules.pc.search.service.StoreSearchService;
+import com.oying.utils.PageResult;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Collections;
+import java.util.stream.Collectors;
+
+/**
+ * 店铺
+ *
+ * @author lzp
+ * @date 2025-04-22
+ */
+@RestController
+@RequestMapping("/api/pc/search")
+@RequiredArgsConstructor
+public class StoreSearchController {
+
+    private final StoreSearchService storeSearchService;
+
+    /**
+     * 查询最近的店铺
+     */
+    @GetMapping("/near")
+    public R<PageResult<StoreSearchView>> list(NearbyStoreQueryCriteria criteria) {
+        return R.success(toStoreSearchVo(storeSearchService.findNearStores(criteria)));
+    }
+
+    private PageResult<StoreSearchView> toStoreSearchVo(PageResult<StoreSearchDto> resources) {
+        PageResult<StoreSearchView> t = new PageResult<>();
+        t.setTotalElements(resources.getTotalElements());
+        if (CollUtil.isNotEmpty(resources.getContent())) {
+            t.setContent(resources.getContent().stream().map(storeSearchDto -> {
+                StoreSearchView searchView = new StoreSearchView();
+                searchView.setStoreId(storeSearchDto.getStoreId());
+                searchView.setStoreName(storeSearchDto.getStoreName());
+                searchView.setStoreLogoUrl(""); // 获取obs
+                searchView.setDistance(storeSearchDto.getDistance());
+                searchView.setRecommendedProducts(Collections.emptyList());
+                return searchView;
+            }).collect(Collectors.toList()));
+        }
+        if (CollUtil.isEmpty(t.getContent())) {
+            t.setContent(Collections.emptyList());
+        }
+        return t;
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/search/service/StoreSearchService.java b/oying-system/src/main/java/com/oying/modules/pc/search/service/StoreSearchService.java
new file mode 100644
index 0000000..63d91d6
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/search/service/StoreSearchService.java
@@ -0,0 +1,10 @@
+package com.oying.modules.pc.search.service;
+
+import com.oying.modules.pc.search.domain.dto.NearbyStoreQueryCriteria;
+import com.oying.modules.pc.search.domain.dto.StoreSearchDto;
+import com.oying.utils.PageResult;
+
+public interface StoreSearchService {
+
+    PageResult<StoreSearchDto> findNearStores(NearbyStoreQueryCriteria criteria);
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/search/service/impl/StoreSearchServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/search/service/impl/StoreSearchServiceImpl.java
new file mode 100644
index 0000000..3c37c6a
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/search/service/impl/StoreSearchServiceImpl.java
@@ -0,0 +1,25 @@
+package com.oying.modules.pc.search.service.impl;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.oying.modules.pc.search.domain.dto.NearbyStoreQueryCriteria;
+import com.oying.modules.pc.search.domain.dto.StoreSearchDto;
+import com.oying.modules.pc.store.mapper.StoreMapper;
+import com.oying.modules.pc.search.service.StoreSearchService;
+import com.oying.utils.PageResult;
+import com.oying.utils.PageUtil;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class StoreSearchServiceImpl implements StoreSearchService {
+
+    private final StoreMapper storeMapper;
+
+    @Override
+    public PageResult<StoreSearchDto> findNearStores(NearbyStoreQueryCriteria criteria) {
+        Page<StoreSearchDto> page = new Page<>(criteria.getPage(), criteria.getSize());
+        return PageUtil.toPage(storeMapper.queryNearStores(criteria, page));
+    }
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/search/view/StoreSearchView.java b/oying-system/src/main/java/com/oying/modules/pc/search/view/StoreSearchView.java
new file mode 100644
index 0000000..fabd856
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/search/view/StoreSearchView.java
@@ -0,0 +1,27 @@
+package com.oying.modules.pc.search.view;
+
+import com.oying.modules.pc.product.view.ProductSimpleView;
+import com.oying.modules.pc.search.domain.dto.StoreSearchDto;
+import lombok.Data;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 搜索结果VO - 包含店铺和推荐商品
+ * @author lzp
+ * @date 2025-04-25
+ */
+@Data
+public class StoreSearchView {
+
+    // 店铺基础信息
+    private Long storeId;
+    private String storeName;
+    private String storeLogoUrl;
+    private Integer deliveryTime;
+    private Integer distance;
+
+    // 商品列表(通常3-5个推荐商品)
+    private List<ProductSimpleView> recommendedProducts;
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreDtoAssembler.java b/oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreDtoAssembler.java
new file mode 100644
index 0000000..fed4923
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreDtoAssembler.java
@@ -0,0 +1,7 @@
+package com.oying.modules.pc.store.converter;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class StoreDtoAssembler {
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreViewAssembler.java b/oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreViewAssembler.java
new file mode 100644
index 0000000..d92d697
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreViewAssembler.java
@@ -0,0 +1,7 @@
+package com.oying.modules.pc.store.converter;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class StoreViewAssembler {
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/Store.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/Store.java
new file mode 100644
index 0000000..4542f86
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/Store.java
@@ -0,0 +1,135 @@
+package com.oying.modules.pc.store.domain;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.bean.copier.CopyOptions;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.data.geo.Point;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalTime;
+import java.time.ZonedDateTime;
+
+/**
+ * @author lzp
+ * @date 2025-04-21
+ **/
+@Data
+@TableName("pc_store")
+public class Store implements Serializable {
+
+    @TableId(value = "store_id", type = IdType.AUTO)
+    @ApiModelProperty(value = "唯一标识")
+    private Long storeId;
+
+    @NotNull
+    @ApiModelProperty(value = "商户ID")
+    private Long merchantId;
+
+    @NotNull
+    @ApiModelProperty(value = "平台类目")
+    private Long platformCategoryId;
+
+    @NotNull
+    @ApiModelProperty(value = "店铺类型:1-自营 2-加盟 3-第三方")
+    private Integer storeType;
+
+    @ApiModelProperty(value = "店铺编码")
+    private String storeCode;
+
+    @NotBlank
+    @ApiModelProperty(value = "店铺名称")
+    private String storeName;
+
+    @ApiModelProperty(value = "经营范围")
+    private String businessScope;
+
+    @NotNull
+    @ApiModelProperty(value = "状态:1000-草稿  1002-正常  1003-暂停营业 1004-关闭")
+    private Integer status;
+
+    @NotBlank
+    @ApiModelProperty(value = "店铺logo图片")
+    private Long logoImageId;
+
+    @NotBlank
+    @ApiModelProperty(value = "店铺封面图")
+    private Long coverImageId;
+
+    @ApiModelProperty(value = "店铺描述")
+    private String description;
+
+    @ApiModelProperty(value = "店铺标签,逗号分隔")
+    private String tags;
+
+    @ApiModelProperty(value = "配送费用")
+    private BigDecimal deliveryFee;
+
+    @ApiModelProperty(value = "起送金额")
+    private BigDecimal deliveryMinimum;
+
+    @ApiModelProperty(value = "联系电话")
+    private String contactPhone;
+
+    @ApiModelProperty(value = "营业开始时间")
+    private LocalTime openTime;
+
+    @ApiModelProperty(value = "营业结束时间")
+    private LocalTime closeTime;
+
+    @ApiModelProperty(value = "省级代码")
+    private String provinceCode;
+
+    @ApiModelProperty(value = "市级代码")
+    private String cityCode;
+
+    @ApiModelProperty(value = "区/县级代码")
+    private String districtCode;
+
+    @ApiModelProperty(value = "详细地址")
+    private String address;
+
+    @ApiModelProperty(value = "经度")
+    private Double longitude;
+
+    @ApiModelProperty(value = "纬度")
+    private Double latitude;
+
+    @ApiModelProperty(value = "GeoHash编码")
+    private String geoHash;
+
+    @ApiModelProperty(value = "空间坐标")
+    private Point geoPoint;
+
+    @ApiModelProperty(value = "坐标系:WGS84/GCJ02/BD09/CGCS2000")
+    private String coordinateSystem;
+
+    @ApiModelProperty(value = "营业半径(米)")
+    private Integer radius;
+
+    @NotNull
+    @ApiModelProperty(value = "创建人")
+    private Long createBy;
+
+    @NotNull
+    @ApiModelProperty(value = "创建日期")
+    private ZonedDateTime createTime;
+
+    @NotNull
+    @ApiModelProperty(value = "修改人")
+    private Long updateBy;
+
+    @NotNull
+    @ApiModelProperty(value = "修改时间")
+    private ZonedDateTime updateTime;
+
+    public void copy(Store source) {
+        BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreCategory.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreCategory.java
new file mode 100644
index 0000000..9c68dbb
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreCategory.java
@@ -0,0 +1,70 @@
+package com.oying.modules.pc.store.domain;
+
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import java.sql.Timestamp;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+/**
+* @description /
+* @author lzp
+* @date 2025-04-27
+**/
+@Data
+@TableName("pc_store_category")
+public class StoreCategory implements Serializable {
+
+    @TableId(value = "category_id")
+    @ApiModelProperty(value = "ID")
+    private Long categoryId;
+
+    @NotNull
+    @ApiModelProperty(value = "店铺ID")
+    private Long storeId;
+
+    @NotNull
+    @ApiModelProperty(value = "父ID")
+    private Long parentId;
+
+    @NotBlank
+    @ApiModelProperty(value = "类目名称")
+    private String name;
+
+    @NotNull
+    @ApiModelProperty(value = "类目层级:1-级类目 2-级类目")
+    private Integer level;
+
+    @ApiModelProperty(value = "排序权重")
+    private Integer sortWeight;
+
+    @ApiModelProperty(value = "类目图标")
+    private String iconId;
+
+    @ApiModelProperty(value = "状态(暂不使用)")
+    private Integer status;
+
+    @ApiModelProperty(value = "是否启用(0-否 1-是)")
+    private Integer active;
+
+    @ApiModelProperty(value = "创建人")
+    private Long createBy;
+
+    @ApiModelProperty(value = "创建时间")
+    private Timestamp createTime;
+
+    @ApiModelProperty(value = "更新人")
+    private Long updateBy;
+
+    @ApiModelProperty(value = "更新时间")
+    private Timestamp updateTime;
+
+    public void copy(StoreCategory source){
+        BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreLocation.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreLocation.java
new file mode 100644
index 0000000..6cd40d9
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreLocation.java
@@ -0,0 +1,57 @@
+package com.oying.modules.pc.store.domain;
+
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+
+import java.math.BigDecimal;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.springframework.data.geo.Point;
+
+/**
+* @description /
+* @author lzp
+* @date 2025-04-23
+**/
+@Data
+@TableName("store_location")
+public class StoreLocation implements Serializable {
+
+    @TableId(value = "address_id", type = IdType.AUTO)
+    @ApiModelProperty(value = "地址ID")
+    private Long locationId;
+
+    @NotNull
+    @ApiModelProperty(value = "关联的店铺ID")
+    private Long storeId;
+
+    @ApiModelProperty(value = "省份")
+    private String province;
+
+    @ApiModelProperty(value = "城市")
+    private String city;
+
+    @ApiModelProperty(value = "区县")
+    private String district;
+
+    @ApiModelProperty(value = "详细地址")
+    private String address;
+
+    @ApiModelProperty(value = "经度")
+    private BigDecimal longitude;
+
+    @ApiModelProperty(value = "纬度")
+    private BigDecimal latitude;
+
+    @ApiModelProperty(value = "空间坐标")
+    private Point getPoint;
+
+    public void copy(StoreLocation source){
+        BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreQualification.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreQualification.java
new file mode 100644
index 0000000..069b7c8
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreQualification.java
@@ -0,0 +1,75 @@
+package com.oying.modules.pc.store.domain;
+
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.time.LocalTime;
+import java.time.ZonedDateTime;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+/**
+* @description /
+* @author lzp
+* @date 2025-04-22
+**/
+@Data
+@TableName("pc_store_qualification")
+public class StoreQualification implements Serializable {
+
+    @TableId(value = "qualification_id", type = IdType.AUTO)
+    @ApiModelProperty(value = "资质ID")
+    private Long qualificationId;
+
+    @NotNull
+    @ApiModelProperty(value = "关联的店铺ID")
+    private Long storeId;
+
+    @NotNull
+    @ApiModelProperty(value = "资质类型")
+    private Integer qualificationType;
+
+    @ApiModelProperty(value = "资质编号")
+    private String qualificationNumber;
+
+    @ApiModelProperty(value = "资质名称")
+    private String qualificationName;
+
+    @ApiModelProperty(value = "资质图片")
+    private String qualificationImageId;
+
+    @ApiModelProperty(value = "有效期开始日期")
+    private LocalTime startDate;
+
+    @ApiModelProperty(value = "有效期结束日期")
+    private LocalTime endDate;
+
+    @ApiModelProperty(value = "状态:1000-草稿 1001-有效 1002-无效")
+    private Integer status;
+
+    @NotNull
+    @ApiModelProperty(value = "创建人")
+    private Long createBy;
+
+    @NotNull
+    @ApiModelProperty(value = "创建日期")
+    private ZonedDateTime createTime;
+
+    @NotNull
+    @ApiModelProperty(value = "修改人")
+    private Long updateBy;
+
+    @NotNull
+    @ApiModelProperty(value = "修改时间")
+    private ZonedDateTime updateTime;
+
+    public void copy(StoreQualification source){
+        BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreStatus.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreStatus.java
new file mode 100644
index 0000000..719247d
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreStatus.java
@@ -0,0 +1,5 @@
+package com.oying.modules.pc.store.domain;
+
+public class StoreStatus {
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreBusinessHoursRequest.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreBusinessHoursRequest.java
new file mode 100644
index 0000000..a89348e
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreBusinessHoursRequest.java
@@ -0,0 +1,18 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalTime;
+
+@Data
+public class StoreBusinessHoursRequest {
+
+    @NotNull
+    private LocalTime openTime;
+
+    @NotNull
+    private LocalTime closeTime;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryCreateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryCreateRequest.java
new file mode 100644
index 0000000..cedeb47
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryCreateRequest.java
@@ -0,0 +1,18 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class StoreCategoryCreateRequest {
+
+    private Long storeId;
+
+    private Long parentId;
+
+    private String name;
+
+    private Integer sortWeight;
+
+    private Integer active;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryMerchantCreateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryMerchantCreateRequest.java
new file mode 100644
index 0000000..46b5256
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryMerchantCreateRequest.java
@@ -0,0 +1,20 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class StoreCategoryMerchantCreateRequest {
+
+    private Long parentId;
+
+    @NotBlank
+    private String name;
+
+    private Integer sortWeight;
+
+    private Integer active;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryMerchantUpdateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryMerchantUpdateRequest.java
new file mode 100644
index 0000000..48a15fb
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryMerchantUpdateRequest.java
@@ -0,0 +1,16 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class StoreCategoryMerchantUpdateRequest {
+
+    private Long parentId;
+
+    private String name;
+
+    private Integer sortWeight;
+
+    private Integer active;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryQueryCriteria.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryQueryCriteria.java
new file mode 100644
index 0000000..bc8ae0a
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryQueryCriteria.java
@@ -0,0 +1,26 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author lzp
+ * @date 2025-04-27
+ **/
+@Data
+public class StoreCategoryQueryCriteria {
+
+    private Long storeId;
+
+    private Integer level;
+
+    private Boolean recursive;
+
+    private Integer active;
+
+    @ApiModelProperty(value = "页码", example = "1")
+    private Integer page = 1;
+
+    @ApiModelProperty(value = "每页数据量", example = "10")
+    private Integer size = 10;
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryUpdateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryUpdateRequest.java
new file mode 100644
index 0000000..fc238f6
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCategoryUpdateRequest.java
@@ -0,0 +1,20 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class StoreCategoryUpdateRequest {
+
+    private Long storeId;
+
+    private Long parentId;
+
+    private Long categoryId;
+
+    private String name;
+
+    private Integer sortWeight;
+
+    private Integer active;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCreateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCreateRequest.java
new file mode 100644
index 0000000..f23b372
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCreateRequest.java
@@ -0,0 +1,90 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.json.JSONUtil;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+public class StoreCreateRequest {
+
+    @NotBlank
+    @ApiModelProperty(value = "店铺全称", example = "重庆永辉超市新纪元店")
+    private String storeName;
+
+    /*@NotBlank
+    @ApiModelProperty(value = "店铺简称", example = "永辉超市(新纪元店)")
+    private String storeShortName;*/
+
+    @NotBlank
+    @ApiModelProperty(value = "店铺LOGO文件ID", example = "14567785444763247876234")
+    private Long logoUploadFileId;
+
+    /*@NotBlank
+    @ApiModelProperty(value = "店铺门户图片ID", example = "276409837458893793939")
+    private Long coverUploadFileId;*/
+
+    @NotBlank
+    @ApiModelProperty(value = "平台类目ID", example = "29784639387324848347230")
+    private Long platformCategoryId;
+    //private String businessCategory;
+
+    @NotBlank
+    @ApiModelProperty(value = "简介", example = "")
+    private String description;
+
+    @NotBlank
+    @ApiModelProperty(value = "店铺联系电话", example = "13800000001")
+    private String contactPhone;
+
+    @NotBlank
+    @ApiModelProperty(value = "店铺地址", example = "276409837458893793939")
+    private String address;
+
+    @NotBlank
+    @ApiModelProperty(value = "店铺坐标经度", example = "121.505978")
+    private Double longitude;
+
+    @NotBlank
+    @ApiModelProperty(value = "店铺坐标纬度", example = "31.144515")
+    private Double latitude;
+
+    @ApiModelProperty(value = "店铺资质", example = "")
+    private List<StoreQualificationCreateRequest> qualificationList;
+
+    public boolean hasQualificationList() {
+        return CollUtil.isNotEmpty(this.qualificationList);
+    }
+
+    public static void main(String[] args) {
+        StoreCreateRequest request = new StoreCreateRequest();
+        request.setStoreName("上海三林小学");
+        request.setLogoUploadFileId(1L);
+        request.setDescription("");
+        // request.setCoverUploadFileId(1L);
+        request.setPlatformCategoryId(1L);
+        request.setContactPhone("13599873421");
+        request.setAddress("上海");
+        request.setLongitude(121.505978D);
+        request.setLatitude(31.144515D);
+
+        List<StoreQualificationCreateRequest> qualificationList = new ArrayList<>();
+        StoreQualificationCreateRequest sq1 = new StoreQualificationCreateRequest();
+        sq1.setType(10001);
+        // sq1.setName("营业执照");
+        sq1.setImageUploadFileId("");
+        qualificationList.add(sq1);
+        StoreQualificationCreateRequest sq2 = new StoreQualificationCreateRequest();
+        sq2.setType(10002);
+        // sq2.setName("许可证");
+        sq2.setImageUploadFileId("");
+        qualificationList.add(sq2);
+        request.setQualificationList(qualificationList);
+        System.out.println(JSONUtil.toJsonStr(request));
+    }
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCustomerDetailDto.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCustomerDetailDto.java
new file mode 100644
index 0000000..765a099
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCustomerDetailDto.java
@@ -0,0 +1,26 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class StoreCustomerDetailDto {
+
+    private String name;
+
+    private String logoUrl;
+
+    private String description;
+
+    private String address;
+
+    private String businessHours;
+
+    private String contactPhone;
+
+    private Integer score;
+
+    private Integer deliveryDuration;
+
+    private Integer monthlySales;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCustomerQueryCriteria.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCustomerQueryCriteria.java
new file mode 100644
index 0000000..ad461f2
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCustomerQueryCriteria.java
@@ -0,0 +1,16 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class StoreCustomerQueryCriteria {
+
+    private Long StoreId;
+
+    private Double longitude; // 中心点经度
+
+    private Double latitude;  // 中心点纬度
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreFieldUpdateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreFieldUpdateRequest.java
new file mode 100644
index 0000000..a273357
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreFieldUpdateRequest.java
@@ -0,0 +1,92 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.time.LocalTime;
+
+@Data
+public class StoreFieldUpdateRequest {
+
+    @NotNull
+    private Long storeId;
+
+    public interface UpdateStorePlatformCategoryGroup{}
+
+    @NotNull(groups = UpdateStorePlatformCategoryGroup.class)
+    private Long platformCategoryId;
+
+    public interface UpdateStoreNameGroup{}
+
+    @NotBlank(groups = UpdateStoreNameGroup.class)
+    private String storeName;
+
+    public interface UpdateStoreTitleGroup{}
+
+    @NotBlank(groups = UpdateStoreTitleGroup.class)
+    private String storeTitle;
+
+    public interface UpdateStoreBusinessStatusGroup {}
+
+    @NotNull(groups = UpdateStoreBusinessStatusGroup.class)
+    private Integer businessStatus;
+
+    public interface UpdateStoreLogoImageGroup{}
+
+    @NotBlank(groups = UpdateStoreLogoImageGroup.class)
+    private String logoImageUploadId;
+
+    public interface UpdateStoreCoverImageGroup{}
+
+    @NotBlank(groups = UpdateStoreCoverImageGroup.class)
+    private String coverImageUploadId;
+
+    public interface UpdateStoreDescriptionGroup{}
+
+    @NotBlank(groups = UpdateStoreDescriptionGroup.class)
+    private String description;
+
+    public interface UpdateStoreDeliveryFeeGroup{}
+
+    @NotBlank(groups = UpdateStoreDeliveryFeeGroup.class)
+    private BigDecimal deliveryFee;
+
+    public interface UpdateStoreDeliveryMinimumGroup{}
+
+    @NotBlank(groups = UpdateStoreDeliveryMinimumGroup.class)
+    private BigDecimal deliveryMinimum;
+
+    public interface UpdateStoreContactPhoneGroup{}
+
+    @NotBlank(groups = UpdateStoreContactPhoneGroup.class)
+    private String contactPhone;
+
+    public interface UpdateStoreBusinessHoursGroup{}
+
+    @NotBlank(groups = UpdateStoreBusinessHoursGroup.class)
+    private LocalTime openTime;
+
+    @NotBlank(groups = UpdateStoreBusinessHoursGroup.class)
+    private LocalTime closeTime;
+
+    public interface UpdateStoreAddressGroup{}
+
+    @NotBlank(groups = UpdateStoreAddressGroup.class)
+    private String address;
+
+    public interface UpdateStoreLocationGroup{}
+
+    @NotBlank(groups = UpdateStoreLocationGroup.class)
+    private Double longitude;
+
+    @NotBlank(groups = UpdateStoreLocationGroup.class)
+    private Double latitude;
+
+    public interface UpdateStoreRadiusGroup{}
+
+    @NotBlank(groups = UpdateStoreRadiusGroup.class)
+    private Integer radius;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreLocationUpdateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreLocationUpdateRequest.java
new file mode 100644
index 0000000..f6555b3
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreLocationUpdateRequest.java
@@ -0,0 +1,17 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class StoreLocationUpdateRequest {
+
+    @NotNull
+    private Double longitude;
+
+    @NotNull
+    private Double latitude;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQualificationCreateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQualificationCreateRequest.java
new file mode 100644
index 0000000..5826de4
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQualificationCreateRequest.java
@@ -0,0 +1,26 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import com.oying.modules.pc.store.domain.StoreQualification;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+
+@Data
+public class StoreQualificationCreateRequest {
+
+    @NotNull
+    @ApiModelProperty(value = "资质类型", example = "1001")
+    private Integer type;
+
+    /*@NotBlank
+    @ApiModelProperty(value = "资质名称", example = "营业执照")
+    private String name;*/
+
+    @NotBlank
+    @ApiModelProperty(value = "资质图片ID", example = "30975645483838730008921")
+    private String imageUploadFileId;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQualificationQueryCriteria.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQualificationQueryCriteria.java
new file mode 100644
index 0000000..3d0e43b
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQualificationQueryCriteria.java
@@ -0,0 +1,24 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import lombok.Data;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+* @author lzp
+* @date 2025-04-23
+**/
+@Data
+public class StoreQualificationQueryCriteria{
+
+    @ApiModelProperty(value = "店铺资质ID", example = "1")
+    private Long id;
+
+    @ApiModelProperty(value = "店铺ID", example = "1")
+    private Long storeId;
+
+    @ApiModelProperty(value = "页码", example = "1")
+    private Integer page = 1;
+
+    @ApiModelProperty(value = "每页数据量", example = "10")
+    private Integer size = 10;
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQualificationUpdateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQualificationUpdateRequest.java
new file mode 100644
index 0000000..23f8369
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQualificationUpdateRequest.java
@@ -0,0 +1,27 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+
+@Data
+public class StoreQualificationUpdateRequest {
+
+    @NotBlank
+    @ApiModelProperty(value = "资质ID", example = "317640956839788210948")
+    private Long id;
+
+    @NotBlank(groups = {UpdateGroup.class})
+    @ApiModelProperty(value = "资质类型", example = "1001")
+    private Integer type;
+
+    @NotBlank(groups = {UpdateGroup.class})
+    @ApiModelProperty(value = "资质图片ID", example = "30975645483838730008921")
+    private String imageUploadFileId;
+
+    public interface UpdateGroup {
+    }
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQueryCriteria.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQueryCriteria.java
new file mode 100644
index 0000000..2d86a34
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreQueryCriteria.java
@@ -0,0 +1,31 @@
+package com.oying.modules.pc.store.domain.dto;
+
+import lombok.Data;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * @author lzp
+ * @date 2025-04-22
+ **/
+@Data
+public class StoreQueryCriteria implements Serializable {
+
+    @ApiModelProperty(value = "商户ID", example = "1")
+    private Long merchantId;
+
+    private String storeName;
+
+    private Integer status;
+
+    @ApiModelProperty(value = "页码", example = "1")
+    private Integer page = 1;
+
+    @ApiModelProperty(value = "每页数据量", example = "10")
+    private Integer size = 10;
+
+    @ApiModelProperty(value = "偏移量", hidden = true)
+    private long offset;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/enums/StoreStatusEnum.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/enums/StoreStatusEnum.java
new file mode 100644
index 0000000..3471252
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/enums/StoreStatusEnum.java
@@ -0,0 +1,21 @@
+package com.oying.modules.pc.store.domain.enums;
+
+public enum StoreStatusEnum {
+
+    creating(1000, "筹备中"),
+    reviewing(2000, "审核中"),
+    business_open(3000, ""),
+    business_paused(3001, ""),
+    business_banned(3002, ""),
+    business_suspended(3003, ""),
+    closed(1001, ""),
+    deleted(1002, "");
+
+    private final int value;
+    private final String reasonPhrase;
+
+    private StoreStatusEnum(int value, String reasonPhrase) {
+        this.value = value;
+        this.reasonPhrase = reasonPhrase;
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreCategoryMapper.java b/oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreCategoryMapper.java
new file mode 100644
index 0000000..dd684f7
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreCategoryMapper.java
@@ -0,0 +1,22 @@
+package com.oying.modules.pc.store.mapper;
+
+import com.oying.modules.pc.store.domain.StoreCategory;
+import com.oying.modules.pc.store.domain.dto.StoreCategoryQueryCriteria;
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Mapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+* @author lzp
+* @date 2025-04-24
+**/
+@Mapper
+public interface StoreCategoryMapper extends BaseMapper<StoreCategory> {
+
+    IPage<StoreCategory> findAll(@Param("criteria") StoreCategoryQueryCriteria criteria, Page<Object> page);
+
+    List<StoreCategory> findAll(@Param("criteria") StoreCategoryQueryCriteria criteria);
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreMapper.java b/oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreMapper.java
new file mode 100644
index 0000000..15753c0
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreMapper.java
@@ -0,0 +1,34 @@
+package com.oying.modules.pc.store.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.oying.modules.pc.store.domain.Store;
+import com.oying.modules.pc.search.domain.dto.NearbyStoreQueryCriteria;
+import com.oying.modules.pc.store.domain.dto.StoreQueryCriteria;
+import com.oying.modules.pc.search.domain.dto.StoreSearchDto;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 店铺Mapper接口
+ *
+ * @author lzp
+ * @date 2025-04-22
+ */
+@Mapper
+public interface StoreMapper extends BaseMapper<Store> {
+
+    List<Store> selectStoreList(@Param("criteria") StoreQueryCriteria criteria, Page<Store> page);
+
+    List<Store> selectStoreList(@Param("criteria") StoreQueryCriteria criteria);
+
+    Store selectStoreByMerchantId(@Param("merchantId") Long merchantId);
+
+    IPage<StoreSearchDto> queryNearStores(@Param("criteria") NearbyStoreQueryCriteria criteria, Page<StoreSearchDto> page);
+
+    IPage<StoreSearchDto> queryNearStoreWithProduct(@Param("criteria") NearbyStoreQueryCriteria criteria, Page<StoreSearchDto> page);
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreQualificationMapper.java b/oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreQualificationMapper.java
new file mode 100644
index 0000000..51b20df
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreQualificationMapper.java
@@ -0,0 +1,24 @@
+package com.oying.modules.pc.store.mapper;
+
+import java.util.List;
+
+import com.oying.modules.pc.store.domain.StoreQualification;
+import com.oying.modules.pc.store.domain.dto.StoreQualificationQueryCriteria;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Mapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+* @author lzp
+* @date 2025-04-23
+**/
+@Mapper
+public interface StoreQualificationMapper extends BaseMapper<StoreQualification> {
+
+    IPage<StoreQualification> findAll(@Param("criteria") StoreQualificationQueryCriteria criteria, Page<Object> page);
+
+    List<StoreQualification> findAll(@Param("criteria") StoreQualificationQueryCriteria criteria);
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryController.java b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryController.java
new file mode 100644
index 0000000..65462c7
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryController.java
@@ -0,0 +1,64 @@
+package com.oying.modules.pc.store.rest;
+
+import com.oying.annotation.Log;
+import com.oying.utils.R;
+import com.oying.modules.pc.store.domain.StoreCategory;
+import com.oying.modules.pc.store.service.StoreCategoryService;
+import com.oying.modules.pc.store.domain.dto.StoreCategoryQueryCriteria;
+import lombok.RequiredArgsConstructor;
+import java.util.List;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import io.swagger.annotations.*;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+* @author lzp
+* @date 2025-04-24
+**/
+@Api(tags = "商品中心:店铺类目")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/pc/storeCategory")
+public class StoreCategoryController {
+
+    private final StoreCategoryService storeCategoryService;
+
+    @GetMapping
+    @ApiOperation("查询api/store/category")
+    public ResponseEntity<?> queryStoreCategory(StoreCategoryQueryCriteria criteria){
+        Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
+        return ResponseEntity.ok(R.success(storeCategoryService.queryAll(criteria, page)));
+    }
+
+    @PostMapping
+    @Log("新增api/store")
+    @ApiOperation("新增api/store")
+    @PreAuthorize("@el.check('storeCategory:add')")
+    public ResponseEntity<?> createStoreCategory(@Validated @RequestBody StoreCategory resources){
+        storeCategoryService.create(resources);
+        return ResponseEntity.status(HttpStatus.CREATED).build();
+    }
+
+    @PutMapping
+    @Log("修改api/store")
+    @ApiOperation("修改api/store")
+    @PreAuthorize("@el.check('storeCategory:edit')")
+    public ResponseEntity<?> updateStoreCategory(@Validated @RequestBody StoreCategory resources){
+        storeCategoryService.update(resources);
+        return ResponseEntity.noContent().build();
+    }
+
+    @DeleteMapping
+    @Log("删除api/store")
+    @ApiOperation("删除api/store")
+    @PreAuthorize("@el.check('storeCategory:del')")
+    public ResponseEntity<?> deleteStoreCategory(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
+        storeCategoryService.deleteAll(ids);
+        return ResponseEntity.noContent().build();
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryCustomerController.java b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryCustomerController.java
new file mode 100644
index 0000000..deb8507
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryCustomerController.java
@@ -0,0 +1,71 @@
+package com.oying.modules.pc.store.rest;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.lang.tree.TreeNodeConfig;
+import cn.hutool.core.lang.tree.TreeUtil;
+import cn.hutool.core.util.BooleanUtil;
+import com.oying.utils.R;
+import com.oying.modules.pc.store.domain.StoreCategory;
+import com.oying.modules.pc.store.domain.dto.StoreCategoryQueryCriteria;
+import com.oying.modules.pc.store.service.StoreCategoryService;
+import com.oying.modules.pc.store.view.CustomerStoreCategoryView;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author lzp
+ * @date 2025-04-24
+ **/
+@Api(tags = "店铺类目(客户端)")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/pc/customer/store/{storeId}/category")
+public class StoreCategoryCustomerController {
+
+    private final StoreCategoryService storeCategoryService;
+
+    @GetMapping(value = "/list")
+    @ApiOperation("查询店铺类目")
+    public ResponseEntity<?> getList(@PathVariable("storeId") Long storeId,
+                                     @RequestParam(value = "recursive", required = false) Boolean recursive) {
+
+        StoreCategoryQueryCriteria criteria = new StoreCategoryQueryCriteria();
+        criteria.setStoreId(storeId);
+        criteria.setActive(1);
+        List<StoreCategory> categoryList = storeCategoryService.queryAll(criteria);
+
+        List<CustomerStoreCategoryView> categoryViewList = Optional.ofNullable(categoryList).orElse(ListUtil.empty()).stream().map(i -> {
+            CustomerStoreCategoryView view = new CustomerStoreCategoryView();
+            view.setCategoryId(i.getCategoryId());
+            view.setParentId(i.getParentId());
+            view.setName(i.getName());
+            view.setSortWeight(i.getSortWeight());
+            return view;
+        }).collect(Collectors.toList());
+
+        if (BooleanUtil.isFalse(recursive)) {
+            return ResponseEntity.ok(R.success(categoryViewList));
+        }
+
+        TreeNodeConfig config = new TreeNodeConfig();
+        config.setIdKey("categoryId");
+        config.setWeightKey("sortWeight");
+        //config.setDeep(3);
+
+        List<Tree<Long>> tree = TreeUtil.build(categoryViewList, 0L, config, (c, treeNode) -> {
+            treeNode.setId(c.getCategoryId());
+            treeNode.setParentId(c.getParentId());
+            treeNode.setName(c.getName());
+            treeNode.setWeight(c.getSortWeight());
+        });
+        return ResponseEntity.ok(R.success(tree));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryMerchantController.java b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryMerchantController.java
new file mode 100644
index 0000000..f576684
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryMerchantController.java
@@ -0,0 +1,135 @@
+package com.oying.modules.pc.store.rest;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.lang.tree.TreeNodeConfig;
+import cn.hutool.core.lang.tree.TreeUtil;
+import cn.hutool.core.util.BooleanUtil;
+import com.oying.annotation.Log;
+import com.oying.utils.R;
+import com.oying.modules.pc.store.domain.StoreCategory;
+import com.oying.modules.pc.store.domain.dto.*;
+import com.oying.modules.pc.store.service.StoreCategoryService;
+import com.oying.modules.pc.store.view.StoreCategoryMerchantView;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author lzp
+ * @date 2025-04-24
+ **/
+@Api(tags = "店铺类目(商户端)")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/pc/merchant/store/{storeId}/category")
+public class StoreCategoryMerchantController {
+
+    private final StoreCategoryService storeCategoryService;
+
+    @GetMapping(value = "/list")
+    @ApiOperation("查询店铺类目")
+    //@PreAuthorize("@el.check('merchant:storeCategory:list')" +
+    //        " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> getList(@PathVariable Long storeId,
+                                     @RequestParam(value = "recursive", required = false) Boolean recursive) {
+
+        StoreCategoryQueryCriteria criteria = new StoreCategoryQueryCriteria();
+        criteria.setStoreId(storeId);
+        List<StoreCategory> storeCategoryList = storeCategoryService.queryAll(criteria);
+        List<StoreCategoryMerchantView> viewList = Optional.ofNullable(storeCategoryList).orElse(ListUtil.empty()).stream().map(i -> {
+            StoreCategoryMerchantView view = new StoreCategoryMerchantView();
+            BeanUtils.copyProperties(i, view);
+            return view;
+        }).collect(Collectors.toList());
+
+        if (BooleanUtil.isFalse(recursive)) {
+            return ResponseEntity.ok(R.success(viewList));
+        }
+
+        TreeNodeConfig config = new TreeNodeConfig();
+        config.setIdKey("categoryId");
+        config.setWeightKey("sortWeight");
+        //config.setDeep(3);
+
+        List<Tree<Long>> tree = TreeUtil.build(viewList, 0L, config, (c, treeNode) -> {
+            treeNode.setId(c.getCategoryId());
+            treeNode.setParentId(c.getParentId());
+            treeNode.setName(c.getName());
+            treeNode.setWeight(c.getSortWeight());
+        });
+
+        return ResponseEntity.ok(R.success(tree));
+    }
+
+    @GetMapping(value = "/{categoryId}")
+    @ApiOperation("查询店铺类目")
+    //@PreAuthorize("@el.check('merchant:storeCategory:list')" +
+    //        " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> getById(@PathVariable Long categoryId,
+                                     @RequestParam(value = "recursive", required = false) Boolean recursive) {
+
+        StoreCategory storeCategory = storeCategoryService.getById(categoryId);
+        StoreCategoryMerchantView view = new StoreCategoryMerchantView();
+        BeanUtils.copyProperties(storeCategory, view);
+
+        /*LambdaQueryWrapper<StoreCategory> wrapper = new LambdaQueryWrapper<StoreCategory>()
+                .eq(StoreCategory::getParentId, categoryId);
+        List<StoreCategory> subStoreCategoryList = storeCategoryService.list(wrapper);*/
+
+        return ResponseEntity.ok(R.success(view));
+    }
+
+    @PostMapping
+    @Log("新增店铺类目")
+    @ApiOperation("新增店铺类目")
+    //@PreAuthorize("@el.check('storeCategory:add')" +
+    //        " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> createStoreCategory(@PathVariable Long storeId,
+                                                 @Validated @RequestBody StoreCategoryMerchantCreateRequest request) {
+
+        StoreCategory resources = new StoreCategory();
+        BeanUtils.copyProperties(request, resources);
+        resources.setStoreId(storeId);
+        storeCategoryService.create(resources);
+        return ResponseEntity.status(HttpStatus.CREATED).build();
+    }
+
+    @PutMapping(value = "/{categoryId}")
+    @Log("修改店铺类目")
+    @ApiOperation("修改店铺类目")
+    //@PreAuthorize("@el.check('storeCategory:edit')" +
+    //        " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> updateStoreCategory(@PathVariable Long storeId,
+                                                 @PathVariable Long categoryId,
+                                                 @Validated @RequestBody StoreCategoryMerchantUpdateRequest request) {
+
+        StoreCategory resources = new StoreCategory();
+        BeanUtils.copyProperties(request, resources);
+        resources.setCategoryId(categoryId);
+        resources.setStoreId(storeId);
+        storeCategoryService.update(resources);
+        return ResponseEntity.noContent().build();
+    }
+
+    @DeleteMapping
+    @Log("删除店铺类目")
+    @ApiOperation("删除店铺类目")
+    @PreAuthorize("@el.check('storeCategory:del')" +
+            " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> deleteStoreCategory(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
+        storeCategoryService.deleteAll(ids);
+        return ResponseEntity.noContent().build();
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreController.java b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreController.java
new file mode 100644
index 0000000..a53cf9c
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreController.java
@@ -0,0 +1,68 @@
+package com.oying.modules.pc.store.rest;
+
+import com.oying.utils.R;
+import com.oying.modules.pc.common.id.StoreIdGenerator;
+import com.oying.modules.pc.store.domain.Store;
+import com.oying.modules.pc.store.domain.dto.*;
+import com.oying.modules.pc.store.service.StoreService;
+import com.oying.utils.SecurityUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.ZonedDateTime;
+
+/**
+ * 店铺
+ *
+ * @author lzp
+ * @date 2025-04-22
+ */
+@RestController
+@RequestMapping("/api/pc/store")
+@RequiredArgsConstructor
+public class StoreController {
+
+    private final StoreService storeService;
+
+    @GetMapping(value = "/page")
+    public R<?> getStoresByPage(@RequestBody StoreQueryCriteria criteria) {
+        return R.success(storeService.queryByPage(criteria));
+    }
+
+    @GetMapping(value = "/list")
+    public R<?> getStores(@RequestBody StoreQueryCriteria criteria) {
+        return R.success(storeService.queryAll(criteria));
+    }
+
+    @GetMapping(value = "/{storeId}")
+    public R<?> getStoreById(@PathVariable("storeId") Long storeId) {
+        return R.success(storeService.getById(storeId));
+    }
+
+    @GetMapping(value = "/{storeId}/details")
+    public R<?> getStoreDetailsById(@PathVariable("storeId") Long storeId) {
+        return R.success(storeService.getById(storeId));
+    }
+
+    @PostMapping(value = "/createEmpty")
+    public R<?> createEmpty(@RequestBody StoreCreateRequest request) {
+        Store store = new Store();
+        store.setStoreId(StoreIdGenerator.getId());
+        store.setMerchantId(SecurityUtils.getCurrentUserId());
+        store.setCreateBy(SecurityUtils.getCurrentUserId());
+        store.setCreateTime(ZonedDateTime.now());
+        storeService.save(store);
+        return R.success();
+    }
+
+    /**
+     * 修改店铺信息
+     */
+    @PostMapping(value = "/{storeId}")
+    public R<?> update(@PathVariable("storeId") Long storeId, @RequestBody Store store) {
+        store.setStoreId(storeId);
+        storeService.updateById(store);
+        return R.success();
+    }
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCustomerController.java b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCustomerController.java
new file mode 100644
index 0000000..0dfd954
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCustomerController.java
@@ -0,0 +1,36 @@
+package com.oying.modules.pc.store.rest;
+
+import com.oying.utils.R;
+import com.oying.modules.pc.store.domain.dto.StoreCustomerDetailDto;
+import com.oying.modules.pc.store.domain.dto.StoreCustomerQueryCriteria;
+import com.oying.modules.pc.store.service.StoreQueryService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 店铺
+ *
+ * @author lzp
+ * @date 2025-04-22
+ */
+@Api(tags = "店铺(客户端)")
+@RestController
+@RequestMapping("/api/pc/customer/store")
+@RequiredArgsConstructor
+public class StoreCustomerController {
+
+    private final StoreQueryService storeQueryService;
+
+    @GetMapping(value = "/{storeId}")
+    @ApiOperation("查询店铺")
+    public ResponseEntity<?> getCustomerStoreById(@PathVariable("storeId") Long storeId) {
+        StoreCustomerQueryCriteria criteria = new StoreCustomerQueryCriteria();
+        criteria.setStoreId(storeId);
+        StoreCustomerDetailDto detailDto = storeQueryService.getCustomerStoreDetail(criteria);
+        return ResponseEntity.ok(R.success(detailDto));
+    }
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreMerchantController.java b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreMerchantController.java
new file mode 100644
index 0000000..6e5d928
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreMerchantController.java
@@ -0,0 +1,263 @@
+package com.oying.modules.pc.store.rest;
+
+import cn.hutool.core.collection.ListUtil;
+import com.oying.utils.R;
+import com.oying.modules.pc.store.domain.Store;
+import com.oying.modules.pc.store.domain.dto.StoreCreateRequest;
+import com.oying.modules.pc.store.domain.dto.StoreFieldUpdateRequest;
+import com.oying.modules.pc.store.domain.dto.StoreQueryCriteria;
+import com.oying.modules.pc.store.service.StoreCreateService;
+import com.oying.modules.pc.store.service.StoreService;
+import com.oying.modules.pc.store.view.StoreMerchantView;
+import com.oying.modules.pc.store.view.StoreSimpleView;
+import com.oying.utils.SecurityUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * 店铺
+ *
+ * @author lzp
+ * @date 2025-04-22
+ */
+@Api(tags = "店铺(商户端)")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/pc/merchant/store")
+public class StoreMerchantController {
+
+    private final StoreService storeService;
+    private final StoreCreateService storeCreateService;
+
+    @GetMapping(value = "/list")
+    @ApiOperation("查询所有店铺")
+    //@PreAuthorize("@el.check('merchant:store:list')")
+    public ResponseEntity<?> getList() {
+        StoreQueryCriteria criteria = new StoreQueryCriteria();
+        criteria.setMerchantId(SecurityUtils.getCurrentUserId());
+        //criteria.setStatus();
+        List<Store> storeList = Optional.ofNullable(storeService.queryAll(criteria)).orElse(ListUtil.empty());
+        List<StoreSimpleView> storeViewList = storeList.stream().map(s -> {
+            StoreSimpleView view = new StoreSimpleView();
+            view.setId(s.getStoreId());
+            view.setName(s.getStoreName());
+            view.setLogoUrl("");
+            view.setStatus(s.getStatus());
+            return view;
+        }).collect(Collectors.toList());
+        return ResponseEntity.ok(R.success(storeViewList));
+    }
+
+    @GetMapping(value = "/{storeId}")
+    @ApiOperation("查询店铺")
+    //@PreAuthorize("@el.check('merchant:store:getById')" +
+    //             " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> getById(@PathVariable Long storeId) {
+        Store store = storeService.getById(storeId);
+        StoreMerchantView view = new StoreMerchantView();
+        BeanUtils.copyProperties(store, view);
+        view.setLogoUrl("");
+        return ResponseEntity.ok(R.success(view));
+    }
+
+    @PostMapping
+    @ApiOperation("创建店铺")
+    //@PreAuthorize("@el.check('merchant:store:create')")
+    public ResponseEntity<?> create(@RequestBody StoreCreateRequest request) {
+        storeCreateService.create(request);
+        return ResponseEntity.status(HttpStatus.CREATED).build();
+    }
+
+    /**
+     * 修改店铺信息
+     */
+    @PostMapping(value = "/{storeId}")
+    @ApiOperation("修改店铺")
+    //@PreAuthorize("@el.check('merchant:store:update')" +
+    //        " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> update(@PathVariable("storeId") Long storeId,
+                       @RequestBody Store store) {
+        store.setStoreId(storeId);
+        storeService.updateById(store);
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * 修改店铺LOGO
+     */
+    @PatchMapping(value = "/{storeId}/logo")
+    @ApiOperation("修改店铺LOGO")
+    //@PreAuthorize("@el.check('merchant:store:list')" +
+    //        " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> updateLogo(@PathVariable("storeId") Long storeId,
+                           @Validated(value = StoreFieldUpdateRequest.UpdateStoreLogoImageGroup.class)
+                           @RequestBody StoreFieldUpdateRequest request) {
+        storeService.updateLogo(storeId, request.getLogoImageUploadId());
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * 修改店铺名称
+     */
+    @PatchMapping(value = "/{storeId}/name")
+    @ApiOperation("修改店铺名称")
+    //@PreAuthorize("@el.check('merchant:store:name')" +
+    //        " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> updateName(@PathVariable("storeId") Long storeId,
+                           @Validated(value = StoreFieldUpdateRequest.UpdateStoreNameGroup.class)
+                           @RequestBody StoreFieldUpdateRequest request) {
+        storeService.updateName(storeId, request.getStoreName());
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * 修改店铺简介
+     */
+    @PatchMapping(value = "/{storeId}/description")
+    @ApiOperation("修改店铺简介")
+    //@PreAuthorize("@el.check('merchant:store:description')" +
+    //        " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> updateDescription(@PathVariable("storeId") Long storeId,
+                                  @Validated(value = StoreFieldUpdateRequest.UpdateStoreDescriptionGroup.class)
+                                  @RequestBody StoreFieldUpdateRequest request) {
+        storeService.updateDescription(storeId, request.getDescription());
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * 修改店铺联系电话
+     */
+    @PatchMapping(value = "/{storeId}/contactPhone")
+    @ApiOperation("修改店铺联系电话")
+    @PreAuthorize("@el.check('merchant:store:list')" +
+            " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> updateContactPhone(@PathVariable("storeId") Long storeId,
+                                   @Validated(value = StoreFieldUpdateRequest.UpdateStoreContactPhoneGroup.class)
+                                   @RequestBody StoreFieldUpdateRequest request) {
+        storeService.updateContactPhone(storeId, request.getContactPhone());
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * 修改店铺地址
+     */
+    @PatchMapping(value = "/{storeId}/address")
+    @ApiOperation("修改店铺地址")
+    @PreAuthorize("@el.check('merchant:store:address')" +
+            " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> updateAddress(@PathVariable("storeId") Long storeId,
+                              @Validated(value = StoreFieldUpdateRequest.UpdateStoreAddressGroup.class)
+                              @RequestBody StoreFieldUpdateRequest request) {
+        storeService.updateAddress(storeId, request.getAddress());
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * 修改店铺坐标
+     */
+    @PatchMapping(value = "/{storeId}/location")
+    @ApiOperation("修改店铺坐标")
+    @PreAuthorize("@el.check('merchant:store:location')" +
+            " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> updateLocation(@PathVariable("storeId") Long storeId,
+                               @Validated(value = StoreFieldUpdateRequest.UpdateStoreLocationGroup.class)
+                               @RequestBody StoreFieldUpdateRequest request) {
+        storeService.updateLocation(storeId, request.getLongitude(), request.getLatitude());
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * 修改店铺配送范围
+     */
+    @PatchMapping(value = "/{storeId}/radius")
+    @ApiOperation("修改店铺配送范围")
+    @PreAuthorize("@el.check('merchant:store:radius')" +
+            " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> updateRadius(@PathVariable("storeId") Long storeId,
+                             @Validated(value = StoreFieldUpdateRequest.UpdateStoreRadiusGroup.class)
+                             @RequestBody StoreFieldUpdateRequest request) {
+        storeService.updateRadius(storeId, request.getRadius());
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * 修改店铺绑定的经营类目
+     */
+    @PatchMapping(value = "/{storeId}/platformCategory")
+    @ApiOperation("修改店铺绑定的经营类目")
+    @PreAuthorize("@el.check('merchant:store:platformCategory')" +
+            " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> updatePlatformCategory(@PathVariable("storeId") Long storeId,
+                                       @Validated(value = StoreFieldUpdateRequest.UpdateStorePlatformCategoryGroup.class)
+                                       @RequestBody StoreFieldUpdateRequest request) {
+        storeService.updatePlatformCategory(storeId, request.getPlatformCategoryId());
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * 修改店铺营业时间
+     */
+    @PatchMapping(value = "/{storeId}/businessHours")
+    @ApiOperation("修改店铺营业时间")
+    @PreAuthorize("@el.check('merchant:store:businessHours')" +
+            " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> updateBusinessHours(@PathVariable("storeId") Long storeId,
+                                    @Validated(value = StoreFieldUpdateRequest.UpdateStoreBusinessHoursGroup.class)
+                                    @RequestBody StoreFieldUpdateRequest request) {
+        storeService.updateBusinessHours(storeId, request.getOpenTime(), request.getCloseTime());
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * 修改起送金额
+     */
+    @PatchMapping(value = "/{storeId}/deliveryMinimum")
+    @ApiOperation("修改起送金额")
+    @PreAuthorize("@el.check('merchant:store:deliveryMinimum')" +
+            " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> updateDeliveryMinimum(@PathVariable("storeId") Long storeId,
+                                      @Validated(value = StoreFieldUpdateRequest.UpdateStoreDeliveryMinimumGroup.class)
+                                      @RequestBody StoreFieldUpdateRequest request) {
+        storeService.updateDeliveryMinimum(storeId, request.getDeliveryMinimum());
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * 修改配送费用
+     */
+    @PatchMapping(value = "/{storeId}/deliveryFee")
+    @ApiOperation("修改配送费用")
+    @PreAuthorize("@el.check('merchant:store:deliveryFee')" +
+            " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> updateDeliveryFee(@PathVariable("storeId") Long storeId,
+                                  @Validated(value = StoreFieldUpdateRequest.UpdateStoreDeliveryFeeGroup.class)
+                                  @RequestBody StoreFieldUpdateRequest request) {
+        storeService.updateDeliveryFee(storeId, request.getDeliveryFee());
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * 修改状态
+     */
+    @PatchMapping(value = "/{storeId}/businessStatus")
+    @ApiOperation("修改状态")
+    @PreAuthorize("@el.check('merchant:store:businessStatus')" +
+            " and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> businessStatus(@PathVariable("storeId") Long storeId,
+                               @Validated(value = StoreFieldUpdateRequest.UpdateStoreBusinessStatusGroup.class)
+                               @RequestBody StoreFieldUpdateRequest request) {
+        storeService.updateStatus(storeId, request.getBusinessStatus());
+        return ResponseEntity.noContent().build();
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationController.java b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationController.java
new file mode 100644
index 0000000..3ae4ed7
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationController.java
@@ -0,0 +1,67 @@
+package com.oying.modules.pc.store.rest;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.oying.annotation.Log;
+import com.oying.modules.pc.store.domain.StoreQualification;
+import com.oying.modules.pc.store.domain.dto.StoreQualificationQueryCriteria;
+import com.oying.modules.pc.store.service.StoreQualificationService;
+import com.oying.utils.PageResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author lzp
+ * @date 2025-04-23
+ **/
+@RestController
+@RequiredArgsConstructor
+@Api(tags = "店铺资质")
+@RequestMapping("/api/storeQualification")
+public class StoreQualificationController {
+
+    private final StoreQualificationService storeQualificationService;
+
+    @GetMapping
+    @ApiOperation("查询店铺资质")
+    @PreAuthorize("@el.check('storeQualification:list')")
+    public ResponseEntity<PageResult<StoreQualification>> queryStoreQualification(StoreQualificationQueryCriteria criteria) {
+        Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
+        return new ResponseEntity<>(storeQualificationService.queryAll(criteria, page), HttpStatus.OK);
+    }
+
+    @PostMapping
+    @Log("新增店铺资质")
+    @ApiOperation("新增店铺资质")
+    @PreAuthorize("@el.check('storeQualification:add')")
+    public ResponseEntity<Object> createStoreQualification(@Validated @RequestBody StoreQualification resources) {
+        storeQualificationService.create(resources);
+        return new ResponseEntity<>(HttpStatus.CREATED);
+    }
+
+    @PutMapping
+    @Log("修改店铺资质")
+    @ApiOperation("修改店铺资质")
+    @PreAuthorize("@el.check('storeQualification:edit')")
+    public ResponseEntity<Object> updateStoreQualification(@Validated @RequestBody StoreQualification resources) {
+        storeQualificationService.update(resources);
+        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+    }
+
+    @DeleteMapping
+    @Log("删除店铺资质")
+    @ApiOperation("删除店铺资质")
+    @PreAuthorize("@el.check('storeQualification:del')")
+    public ResponseEntity<Object> deleteStoreQualification(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
+        storeQualificationService.deleteAll(ids);
+        return new ResponseEntity<>(HttpStatus.OK);
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationCustomerController.java b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationCustomerController.java
new file mode 100644
index 0000000..7d24181
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationCustomerController.java
@@ -0,0 +1,54 @@
+package com.oying.modules.pc.store.rest;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.util.ObjUtil;
+import com.oying.utils.R;
+import com.oying.modules.pc.store.domain.StoreQualification;
+import com.oying.modules.pc.store.domain.dto.StoreQualificationQueryCriteria;
+import com.oying.modules.pc.store.service.StoreQualificationService;
+import com.oying.modules.pc.store.view.CustomerStoreQualificationView;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author lzp
+ * @date 2025-04-23
+ *
+*/
+@RestController
+@RequiredArgsConstructor
+@Api(tags = "店铺资质(客户端)")
+@RequestMapping("/api/pc/customer/store/{storeId}/qualification")
+public class StoreQualificationCustomerController {
+
+    private final StoreQualificationService storeQualificationService;
+
+    @GetMapping("/list")
+    @ApiOperation("查询店铺资质")
+    //@PreAuthorize("@el.check('customer:storeQualification:list')")
+    public ResponseEntity<?> getList(@PathVariable Long storeId) {
+        if (ObjUtil.isEmpty(storeId)) {
+            return ResponseEntity.ok(R.success(ListUtil.empty()));
+        }
+        StoreQualificationQueryCriteria criteria = new StoreQualificationQueryCriteria();
+        criteria.setStoreId(storeId);
+        List<StoreQualification> qualificationList = storeQualificationService.queryAll(criteria);
+        List<CustomerStoreQualificationView> viewList = Optional.ofNullable(qualificationList).orElse(ListUtil.empty()).stream().map(i -> {
+            CustomerStoreQualificationView view = new CustomerStoreQualificationView();
+            BeanUtils.copyProperties(i, view);
+            view.setType(i.getQualificationType());
+            view.setName(i.getQualificationName());
+            view.setImageUrl("");
+            return view;
+        }).collect(Collectors.toList());
+        return ResponseEntity.ok(R.success(viewList));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationMerchantController.java b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationMerchantController.java
new file mode 100644
index 0000000..6bae2fa
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationMerchantController.java
@@ -0,0 +1,100 @@
+package com.oying.modules.pc.store.rest;
+
+import cn.hutool.core.collection.ListUtil;
+import com.oying.annotation.Log;
+import com.oying.utils.R;
+import com.oying.modules.pc.store.domain.StoreQualification;
+import com.oying.modules.pc.store.domain.dto.StoreQualificationCreateRequest;
+import com.oying.modules.pc.store.domain.dto.StoreQualificationQueryCriteria;
+import com.oying.modules.pc.store.domain.dto.StoreQualificationUpdateRequest;
+import com.oying.modules.pc.store.service.StoreQualificationService;
+import com.oying.modules.pc.store.view.StoreQualificationMerchantView;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author lzp
+ * @date 2025-04-23
+ **/
+@RestController
+@RequiredArgsConstructor
+@Api(tags = "店铺资质(商户端)")
+@RequestMapping("/api/pc/merchant/store/{storeId}/qualification")
+public class StoreQualificationMerchantController {
+
+    private final StoreQualificationService storeQualificationService;
+
+    @GetMapping("/list")
+    @ApiOperation("查询店铺资质")
+    //@PreAuthorize("@el.check('merchant:storeQualification:list') " +
+    //        "and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> getList(@PathVariable Long storeId) {
+        StoreQualificationQueryCriteria criteria = new StoreQualificationQueryCriteria();
+        criteria.setStoreId(storeId);
+        List<StoreQualification> storeQualificationList = storeQualificationService.queryAll(criteria);
+        List<StoreQualificationMerchantView> viewList = Optional.ofNullable(storeQualificationList).orElse(ListUtil.empty()).stream().map(i -> {
+            StoreQualificationMerchantView view = new StoreQualificationMerchantView();
+            view.setId(i.getQualificationId());
+            view.setType(i.getQualificationType());
+            view.setName(i.getQualificationName());
+            view.setImageUrl("");
+            return view;
+        }).collect(Collectors.toList());
+
+        return ResponseEntity.ok(R.success(viewList));
+    }
+
+    @PostMapping
+    @Log("新增店铺资质")
+    @ApiOperation("新增店铺资质")
+    //@PreAuthorize("@el.check('merchant:storeQualification:add') " +
+    //        "and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> create(@PathVariable Long storeId,
+                                         @Validated @RequestBody StoreQualificationCreateRequest request) {
+
+        StoreQualification resources = new StoreQualification();
+        resources.setStoreId(storeId);
+        resources.setQualificationType(request.getType());
+        resources.setQualificationImageId(request.getImageUploadFileId());
+        storeQualificationService.create(resources);
+        return ResponseEntity.status(HttpStatus.CREATED).build();
+    }
+
+    @PutMapping("/{qualificationId}")
+    @Log("修改店铺资质")
+    @ApiOperation("修改店铺资质")
+    //@PreAuthorize("@el.check('merchant:storeQualification:edit') " +
+    //        "and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> update(@PathVariable Long storeId,
+                                         @PathVariable Long qualificationId,
+                                         @Validated @RequestBody StoreQualificationUpdateRequest request) {
+
+        StoreQualification resources = new StoreQualification();
+        resources.setQualificationId(qualificationId);
+        resources.setStoreId(storeId);
+        resources.setQualificationType(request.getType());
+        resources.setQualificationImageId(request.getImageUploadFileId());
+        storeQualificationService.update(resources);
+        return ResponseEntity.noContent().build();
+    }
+
+    @DeleteMapping
+    @Log("删除店铺资质")
+    @ApiOperation("删除店铺资质")
+    //@PreAuthorize("@el.check('merchant:storeQualification:batchDel') " +
+    //        "and @storeMerchantOwnershipService.check(#storeId)")
+    public ResponseEntity<?> batchDel(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
+        storeQualificationService.deleteAll(ids);
+        return ResponseEntity.noContent().build();
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreCategoryService.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreCategoryService.java
new file mode 100644
index 0000000..74f3947
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreCategoryService.java
@@ -0,0 +1,52 @@
+package com.oying.modules.pc.store.service;
+
+import com.oying.modules.pc.store.domain.StoreCategory;
+import com.oying.modules.pc.store.domain.dto.StoreCategoryQueryCriteria;
+
+import java.util.List;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.oying.utils.PageResult;
+
+/**
+* @description 服务接口
+* @author lzp
+* @date 2025-04-24
+**/
+public interface StoreCategoryService extends IService<StoreCategory> {
+
+    /**
+    * 查询数据分页
+    * @param criteria 条件
+    * @param page 分页参数
+    * @return PageResult
+    */
+    PageResult<StoreCategory> queryAll(StoreCategoryQueryCriteria criteria, Page<Object> page);
+
+    /**
+    * 查询所有数据不分页
+    * @param criteria 条件参数
+    * @return List<StoreCategoryDto>
+    */
+    List<StoreCategory> queryAll(StoreCategoryQueryCriteria criteria);
+
+    /**
+    * 创建
+    * @param resources /
+    */
+    void create(StoreCategory resources);
+
+    /**
+    * 编辑
+    * @param resources /
+    */
+    void update(StoreCategory resources);
+
+    /**
+    * 多选删除
+    * @param ids /
+    */
+    void deleteAll(List<Long> ids);
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreCreateService.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreCreateService.java
new file mode 100644
index 0000000..7644c48
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreCreateService.java
@@ -0,0 +1,7 @@
+package com.oying.modules.pc.store.service;
+
+import com.oying.modules.pc.store.domain.dto.StoreCreateRequest;
+
+public interface StoreCreateService {
+    void create(StoreCreateRequest request);
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreCreationCoordinator.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreCreationCoordinator.java
new file mode 100644
index 0000000..df486f6
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreCreationCoordinator.java
@@ -0,0 +1,31 @@
+package com.oying.modules.pc.store.service;
+
+import com.oying.modules.pc.store.domain.dto.StoreCreateRequest;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class StoreCreationCoordinator {
+
+    private final StoreService storeService;
+    private final StoreQualificationService qualificationService;
+
+    // 核心方法:支持可选 qualification
+    /*@Transactional
+    public StoreFullDTO createFullStore(StoreCreateRequest request) {
+        // 1. 必选操作:store + location + staff
+        Store store = storeService.create(request.getStore());
+        StoreLocation location = locationService.create(store.getId(), request.getLocation());
+        StoreStaff staff = staffService.create(store.getId(), request.getStaff());
+
+        // 2. 可选操作:qualification(根据请求决定)
+        StoreQualification qualification = null;
+        if (request.hasQualification()) {
+            qualification = qualificationService.create(store.getId(), request.getQualification());
+        }
+
+        // 3. 返回聚合结果
+        return new StoreFullDTO(store, location, staff, qualification);
+    }*/
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreMerchantOwnershipService.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreMerchantOwnershipService.java
new file mode 100644
index 0000000..0b1abf6
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreMerchantOwnershipService.java
@@ -0,0 +1,12 @@
+package com.oying.modules.pc.store.service;
+
+import com.oying.modules.pc.store.domain.Store;
+
+public interface StoreMerchantOwnershipService {
+
+    boolean isStoreOwnedByMerchant(Long storeId, Long merchantId);
+    Store verifyAndGetStore(Long storeId, Long merchantId);
+    void verifyStoreOwnership(Long storeId, Long merchantId);
+    Boolean check(Long storeId);
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreQualificationService.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreQualificationService.java
new file mode 100644
index 0000000..fca62cf
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreQualificationService.java
@@ -0,0 +1,57 @@
+package com.oying.modules.pc.store.service;
+
+import java.util.List;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.oying.modules.pc.store.domain.StoreQualification;
+import com.oying.modules.pc.store.domain.dto.StoreQualificationQueryCriteria;
+import com.oying.utils.PageResult;
+
+/**
+* @description 服务接口
+* @author lzp
+* @date 2025-04-27
+**/
+public interface StoreQualificationService extends IService<StoreQualification> {
+
+    /**
+    * 查询数据分页
+    * @param criteria 条件
+    * @param page 分页参数
+    * @return PageResult
+    */
+    PageResult<StoreQualification> queryAll(StoreQualificationQueryCriteria criteria, Page<Object> page);
+
+    /**
+    * 查询所有数据不分页
+    * @param criteria 条件参数
+    * @return List<StoreQualificationDto>
+    */
+    List<StoreQualification> queryAll(StoreQualificationQueryCriteria criteria);
+
+    /**
+    * 创建
+    * @param resources /
+    */
+    void create(StoreQualification resources);
+
+    /**
+     * 批量创建
+     * @param resources /
+     */
+    void batchCreate(List<StoreQualification> resources);
+
+    /**
+    * 编辑
+    * @param resources /
+    */
+    void update(StoreQualification resources);
+
+    /**
+    * 多选删除
+    * @param ids /
+    */
+    void deleteAll(List<Long> ids);
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreQueryService.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreQueryService.java
new file mode 100644
index 0000000..e0c3aa0
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreQueryService.java
@@ -0,0 +1,10 @@
+package com.oying.modules.pc.store.service;
+
+import com.oying.modules.pc.store.domain.dto.StoreCustomerDetailDto;
+import com.oying.modules.pc.store.domain.dto.StoreCustomerQueryCriteria;
+
+public interface StoreQueryService {
+
+    StoreCustomerDetailDto getCustomerStoreDetail(StoreCustomerQueryCriteria criteria);
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreService.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreService.java
new file mode 100644
index 0000000..8bdcc52
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/StoreService.java
@@ -0,0 +1,56 @@
+package com.oying.modules.pc.store.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.oying.modules.pc.store.domain.Store;
+import com.oying.modules.pc.store.domain.StoreCategory;
+import com.oying.modules.pc.store.domain.dto.StoreBusinessHoursRequest;
+import com.oying.modules.pc.store.domain.dto.StoreLocationUpdateRequest;
+import com.oying.modules.pc.store.domain.dto.StoreQueryCriteria;
+import com.oying.utils.PageResult;
+
+import java.math.BigDecimal;
+import java.time.LocalTime;
+import java.util.List;
+
+/**
+ * 店铺基础信息Service接口
+ *
+ * @author lzp
+ * @date 2025-04-22
+ */
+public interface StoreService extends IService<Store> {
+
+    PageResult<Store> queryByPage(StoreQueryCriteria criteria);
+
+    List<Store> queryAll(StoreQueryCriteria criteria);
+
+    Store getMerchantStore(Long merchantId);
+
+    boolean create(Store store);
+
+    boolean updateLogo(Long storeId, String logo);
+
+    boolean updateName(Long storeId, String storeName);
+
+    boolean updateDescription(Long storeId, String description);
+
+    boolean updateContactPhone(Long storeId, String contactPhone);
+
+    boolean updateAddress(Long storeId, String address);
+
+    boolean updateLocation(Long storeId, Double longitude, Double latitude);
+
+    boolean updateRadius(Long storeId, Integer radius);
+
+    boolean updatePlatformCategory(Long storeId, Long platformCategory);
+
+    boolean updateBusinessHours(Long storeId, LocalTime openTime, LocalTime endTime);
+
+    boolean updateDeliveryMinimum(Long storeId, BigDecimal deliveryMinimum);
+
+    boolean updateDeliveryFee(Long storeId, BigDecimal deliveryFee);
+
+    boolean updateStatus(Long storeId, Integer status);
+
+    boolean existsByIdAndMerchantId(Long storeId, Long merchantId);
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreCategoryServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreCategoryServiceImpl.java
new file mode 100644
index 0000000..a994009
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreCategoryServiceImpl.java
@@ -0,0 +1,96 @@
+package com.oying.modules.pc.store.service.impl;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.oying.exception.EntityNotFoundException;
+import com.oying.modules.pc.common.exception.LevelExceededException;
+import com.oying.modules.pc.store.domain.StoreCategory;
+import com.oying.modules.pc.store.domain.dto.StoreCategoryQueryCriteria;
+import com.oying.modules.pc.store.mapper.StoreCategoryMapper;
+import com.oying.modules.pc.store.service.StoreCategoryService;
+import com.oying.utils.FileUtil;
+import com.oying.utils.PageResult;
+import com.oying.utils.PageUtil;
+import com.oying.utils.SecurityUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * @author lzp
+ * @date 2025-04-24
+ **/
+@Service
+@RequiredArgsConstructor
+public class StoreCategoryServiceImpl extends ServiceImpl<StoreCategoryMapper, StoreCategory> implements StoreCategoryService {
+
+    private static final int MAX_LEVEL = 2;
+
+    private final StoreCategoryMapper storeCategoryMapper;
+
+    @Override
+    public PageResult<StoreCategory> queryAll(StoreCategoryQueryCriteria criteria, Page<Object> page) {
+        return PageUtil.toPage(storeCategoryMapper.findAll(criteria, page));
+    }
+
+    @Override
+    public List<StoreCategory> queryAll(StoreCategoryQueryCriteria criteria) {
+        return storeCategoryMapper.findAll(criteria);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void create(StoreCategory resources) {
+        // 重名
+        this.calculateAndSetLevel(resources);
+        resources.setCreateBy(SecurityUtils.getCurrentUserId());
+        storeCategoryMapper.insert(resources);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void update(StoreCategory resources) {
+        StoreCategory storeCategory = getById(resources.getCategoryId());
+        storeCategory.copy(resources);
+        resources.setUpdateBy(SecurityUtils.getCurrentUserId());
+        storeCategoryMapper.updateById(storeCategory);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteAll(List<Long> ids) {
+        storeCategoryMapper.deleteBatchIds(ids);
+    }
+
+    /**
+     * 计算并设置类目的层级
+     */
+    private void calculateAndSetLevel(StoreCategory category) {
+
+        if (category == null) {
+            throw new IllegalArgumentException("对象不能为null");
+        }
+
+        Long parentCategoryId = category.getParentId();
+        if (parentCategoryId == null) {
+            category.setParentId(0L);
+            category.setLevel(1);
+            return;
+        }
+
+        StoreCategory parentCategory = Optional.ofNullable(getById(parentCategoryId))
+                .orElseThrow(() -> new EntityNotFoundException(StoreCategory.class, "parentId", parentCategoryId.toString()));
+
+        int currentLevel = parentCategory.getLevel() + 1;
+
+        if (currentLevel > MAX_LEVEL) {
+            throw new LevelExceededException(category.getLevel(), MAX_LEVEL);
+        }
+
+        category.setLevel(currentLevel);
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreCreateServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreCreateServiceImpl.java
new file mode 100644
index 0000000..467ebbb
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreCreateServiceImpl.java
@@ -0,0 +1,51 @@
+package com.oying.modules.pc.store.service.impl;
+
+import com.oying.modules.pc.store.domain.Store;
+import com.oying.modules.pc.store.domain.StoreQualification;
+import com.oying.modules.pc.store.domain.dto.StoreCreateRequest;
+import com.oying.modules.pc.store.service.StoreCreateService;
+import com.oying.modules.pc.store.service.StoreQualificationService;
+import com.oying.modules.pc.store.service.StoreService;
+import com.oying.utils.SecurityUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class StoreCreateServiceImpl implements StoreCreateService {
+
+    private final StoreService storeService;
+    private final StoreQualificationService storeQualificationService;
+
+    @Transactional(rollbackFor = Exception.class)
+    public void create(StoreCreateRequest request) {
+        Store store = new Store();
+        BeanUtils.copyProperties(request, store);
+        store.setMerchantId(SecurityUtils.getCurrentUserId());
+        store.setLogoImageId(request.getLogoUploadFileId());
+        // store.setCoverImage(request.getCoverUploadFileId());
+        storeService.create(store);
+        if (request.hasQualificationList()) {
+            List<StoreQualification> storeQualificationList = request.getQualificationList()
+                    .stream()
+                    .map(i -> {
+                        StoreQualification qualification = new StoreQualification();
+                        qualification.setStoreId(store.getStoreId());
+                        qualification.setQualificationType(i.getType());
+                        qualification.setQualificationName("");
+                        qualification.setQualificationImageId(i.getImageUploadFileId());
+                        return qualification;
+                    })
+                    .collect(Collectors.toList());
+            storeQualificationList.forEach(i -> i.setStoreId(store.getStoreId()));
+            storeQualificationService.batchCreate(storeQualificationList);
+        }
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreMerchantOwnershipServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreMerchantOwnershipServiceImpl.java
new file mode 100644
index 0000000..3825e60
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreMerchantOwnershipServiceImpl.java
@@ -0,0 +1,59 @@
+package com.oying.modules.pc.store.service.impl;
+
+import com.oying.modules.pc.store.domain.Store;
+import com.oying.modules.pc.store.service.StoreMerchantOwnershipService;
+import com.oying.modules.pc.store.service.StoreService;
+import com.oying.utils.SecurityUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+@Service("smo")
+@RequiredArgsConstructor
+public class StoreMerchantOwnershipServiceImpl implements StoreMerchantOwnershipService {
+
+    private final StoreService storeService;
+
+    /**
+     *  验证店铺是否属于商户
+     */
+    @Override
+    public boolean isStoreOwnedByMerchant(Long storeId, Long merchantId) {
+        /*if (storeId == null || merchantId == null) {
+            return false;
+        }
+        Store store = storeService.getById(storeId);
+        return Optional.ofNullable(store).map(i -> merchantId.equals(i.getMerchantId())).orElse(false);*/
+        return true;
+    }
+
+    /**
+     * 验证并获取店铺对象
+     */
+    @Override
+    public Store verifyAndGetStore(Long storeId, Long merchantId) {
+        Store store = storeService.getById(storeId);
+        return Optional.ofNullable(store).orElseThrow(() -> new AccessDeniedException("无权访问此店铺"));
+    }
+
+    /**
+     *  简单验证(不返回对象)
+     */
+    @Override
+    public void verifyStoreOwnership(Long storeId, Long merchantId) {
+        if (!isStoreOwnedByMerchant(storeId, merchantId)) {
+            throw new AccessDeniedException("无权操作此店铺");
+        }
+    }
+
+    /**
+     * PreAuthorize验证
+     */
+    @Override
+    public Boolean check(Long storeId) {
+        Long merchantId = SecurityUtils.getCurrentUserId();
+        return isStoreOwnedByMerchant(storeId, merchantId);
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreQualificationServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreQualificationServiceImpl.java
new file mode 100644
index 0000000..6c380c6
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreQualificationServiceImpl.java
@@ -0,0 +1,79 @@
+package com.oying.modules.pc.store.service.impl;
+
+import cn.hutool.core.util.ObjUtil;
+import com.oying.exception.EntityExistException;
+import com.oying.modules.pc.common.id.StoreQualificationIdGenerator;
+import com.oying.modules.pc.store.domain.StoreQualification;
+import com.oying.modules.pc.store.domain.dto.StoreQualificationQueryCriteria;
+import com.oying.modules.pc.store.mapper.StoreQualificationMapper;
+import com.oying.modules.pc.store.service.StoreQualificationService;
+import com.oying.utils.*;
+import lombok.RequiredArgsConstructor;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.ZonedDateTime;
+import java.util.*;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+* @description 服务实现
+* @author lzp
+* @date 2025-04-27
+**/
+@Service
+@RequiredArgsConstructor
+public class StoreQualificationServiceImpl extends ServiceImpl<StoreQualificationMapper, StoreQualification> implements StoreQualificationService {
+
+    private final StoreQualificationMapper storeQualificationMapper;
+
+    @Override
+    public PageResult<StoreQualification> queryAll(StoreQualificationQueryCriteria criteria, Page<Object> page){
+        return PageUtil.toPage(storeQualificationMapper.findAll(criteria, page));
+    }
+
+    @Override
+    public List<StoreQualification> queryAll(StoreQualificationQueryCriteria criteria){
+        return storeQualificationMapper.findAll(criteria);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void create(StoreQualification resources) {
+        // resources.setQualificationId(StoreQualificationIdGenerator.getId());
+        resources.setCreateBy(SecurityUtils.getCurrentUserId());
+        resources.setCreateTime(ZonedDateTime.now());
+        storeQualificationMapper.insert(resources);
+    }
+
+    @Override
+    public void batchCreate(List<StoreQualification> resources) {
+        resources.forEach(i-> {
+            i.setCreateBy(SecurityUtils.getCurrentUserId());
+            i.setCreateTime(ZonedDateTime.now());
+        });
+        this.saveBatch(resources);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void update(StoreQualification resources) {
+        // resources.setUpdateBy();
+        Long qualificationId = resources.getQualificationId();
+        StoreQualification existingStoreQualification = this.getById(qualificationId);
+        if (ObjUtil.isEmpty(existingStoreQualification)) {
+            throw new EntityExistException(StoreQualification.class, "id", Optional.ofNullable(qualificationId).map(Object::toString).orElse("null"));
+        }
+        existingStoreQualification.copy(resources);
+        storeQualificationMapper.updateById(existingStoreQualification);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteAll(List<Long> ids) {
+        storeQualificationMapper.deleteBatchIds(ids);
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreQueryServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreQueryServiceImpl.java
new file mode 100644
index 0000000..0514d5c
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreQueryServiceImpl.java
@@ -0,0 +1,33 @@
+package com.oying.modules.pc.store.service.impl;
+
+import com.oying.modules.pc.store.domain.Store;
+import com.oying.modules.pc.store.domain.dto.StoreCustomerDetailDto;
+import com.oying.modules.pc.store.domain.dto.StoreCustomerQueryCriteria;
+import com.oying.modules.pc.store.service.StoreQueryService;
+import com.oying.modules.pc.store.service.StoreService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class StoreQueryServiceImpl implements StoreQueryService {
+
+    private final StoreService storeService;
+
+    @Override
+    public StoreCustomerDetailDto getCustomerStoreDetail(StoreCustomerQueryCriteria criteria) {
+        Store store = storeService.getById(criteria.getStoreId());
+        StoreCustomerDetailDto storeDto = new StoreCustomerDetailDto();
+        BeanUtils.copyProperties(store, storeDto);
+        storeDto.setName(store.getStoreName());
+        storeDto.setLogoUrl("");
+        storeDto.setBusinessHours("");
+        storeDto.setDeliveryDuration(0);
+        storeDto.setMonthlySales(0);
+        storeDto.setScore(0);
+        return storeDto;
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreServiceImpl.java
new file mode 100644
index 0000000..445170a
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreServiceImpl.java
@@ -0,0 +1,159 @@
+package com.oying.modules.pc.store.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.oying.modules.pc.store.domain.Store;
+import com.oying.modules.pc.store.domain.dto.StoreQueryCriteria;
+import com.oying.modules.pc.store.mapper.StoreMapper;
+import com.oying.modules.pc.store.service.StoreService;
+import com.oying.utils.PageResult;
+import com.oying.utils.PageUtil;
+import com.oying.utils.SecurityUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.time.LocalTime;
+import java.time.ZonedDateTime;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 店铺Service业务层处理
+ *
+ * @author lzp
+ * @date 2025-04-22
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements StoreService {
+
+    private final StoreMapper storeMapper;
+
+    @Override
+    public PageResult<Store> queryByPage(StoreQueryCriteria criteria) {
+        Page<Store> page = new Page<>(criteria.getPage(), criteria.getSize());
+        return PageUtil.toPage(storeMapper.selectStoreList(criteria, page));
+    }
+
+    @Override
+    public List<Store> queryAll(StoreQueryCriteria criteria) {
+        return storeMapper.selectStoreList(criteria);
+    }
+
+    @Override
+    public Store getMerchantStore(Long merchantId) {
+        return storeMapper.selectStoreByMerchantId(merchantId);
+    }
+
+    @Override
+    public boolean create(Store store) {
+        // store.setStoreId(StoreIdGenerator.getId());
+        store.setCreateBy(SecurityUtils.getCurrentUserId());
+        store.setCreateTime(ZonedDateTime.now());
+        return save(store);
+    }
+
+    @Override
+    public boolean updateLogo(Long storeId, String logo) {
+        LambdaUpdateWrapper<Store> wrapper = this.createLambdaUpdateWrapper(storeId).set(Store::getLogoImageId, logo);
+        return update(wrapper);
+    }
+
+    @Override
+    public boolean updateName(Long storeId, String storeName) {
+        LambdaUpdateWrapper<Store> wrapper = this.createLambdaUpdateWrapper(storeId)
+                .set(Store::getStoreName, storeName);
+        return update(wrapper);
+    }
+
+    @Override
+    public boolean updateDescription(Long storeId, String description) {
+        LambdaUpdateWrapper<Store> wrapper = this.createLambdaUpdateWrapper(storeId)
+                .set(Store::getDescription, description);
+        return update(wrapper);
+    }
+
+    @Override
+    public boolean updateContactPhone(Long storeId, String contactPhone) {
+        LambdaUpdateWrapper<Store> wrapper = this.createLambdaUpdateWrapper(storeId)
+                .set(Store::getContactPhone, contactPhone);
+        return update(wrapper);
+    }
+
+    @Override
+    public boolean updateAddress(Long storeId, String address) {
+        LambdaUpdateWrapper<Store> wrapper = this.createLambdaUpdateWrapper(storeId)
+                .set(Store::getAddress, address);
+        return update(wrapper);
+    }
+
+    @Override
+    public boolean updateLocation(Long storeId, Double longitude, Double latitude) {
+        LambdaUpdateWrapper<Store> wrapper = this.createLambdaUpdateWrapper(storeId)
+                .set(Store::getLongitude, longitude)
+                .set(Store::getLatitude, latitude);
+        return update(wrapper);
+    }
+
+    @Override
+    public boolean updateRadius(Long storeId, Integer radius) {
+        LambdaUpdateWrapper<Store> wrapper = this.createLambdaUpdateWrapper(storeId)
+                .set(Store::getRadius, radius);
+        return update(wrapper);
+    }
+
+    @Override
+    public boolean updatePlatformCategory(Long storeId, Long platformCategory) {
+        LambdaUpdateWrapper<Store> wrapper = this.createLambdaUpdateWrapper(storeId)
+                .set(Store::getPlatformCategoryId, platformCategory);
+        return update(wrapper);
+    }
+
+    @Override
+    public boolean updateBusinessHours(Long storeId, LocalTime openTime, LocalTime endTime) {
+        LambdaUpdateWrapper<Store> wrapper = this.createLambdaUpdateWrapper(storeId)
+                .set(Store::getOpenTime, openTime)
+                .set(Store::getCloseTime, endTime);
+        return update(wrapper);
+    }
+
+    @Override
+    public boolean updateDeliveryMinimum(Long storeId, BigDecimal deliveryMinimum) {
+        LambdaUpdateWrapper<Store> wrapper = this.createLambdaUpdateWrapper(storeId)
+                .set(Store::getDeliveryMinimum, deliveryMinimum);
+        return update(wrapper);
+    }
+
+    @Override
+    public boolean updateDeliveryFee(Long storeId, BigDecimal deliveryFee) {
+        LambdaUpdateWrapper<Store> wrapper = this.createLambdaUpdateWrapper(storeId)
+                .set(Store::getDeliveryFee, deliveryFee);
+        return update(wrapper);
+    }
+
+    @Override
+    public boolean updateStatus(Long storeId, Integer status) {
+        LambdaUpdateWrapper<Store> wrapper = this.createLambdaUpdateWrapper(storeId)
+                .set(Store::getStatus, status);
+        return update(wrapper);
+    }
+
+    @Override
+    public boolean existsByIdAndMerchantId(Long storeId, Long merchantId) {
+        if (storeId == null || merchantId == null) {
+            return false;
+        }
+        Store store = getById(storeId);
+        return Optional.ofNullable(store).map(i -> merchantId.equals(i.getMerchantId())).orElse(false);
+    }
+
+    private LambdaUpdateWrapper<Store> createLambdaUpdateWrapper(Long storeId) {
+        return new LambdaUpdateWrapper<Store>()
+                .eq(Store::getStoreId, storeId)
+                .set(Store::getUpdateBy, SecurityUtils.getCurrentUserId());
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreCategoryView.java b/oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreCategoryView.java
new file mode 100644
index 0000000..e1fd477
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreCategoryView.java
@@ -0,0 +1,25 @@
+package com.oying.modules.pc.store.view;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class CustomerStoreCategoryView {
+
+    @ApiModelProperty(value = "类目ID")
+    private Long categoryId;
+
+    @ApiModelProperty(value = "父ID")
+    private Long parentId;
+
+    @ApiModelProperty(value = "类目名称")
+    private String name;
+
+    @ApiModelProperty(value = "排序权重")
+    private Integer sortWeight;
+
+    private List<StoreCategoryMerchantView> children;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreQualificationView.java b/oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreQualificationView.java
new file mode 100644
index 0000000..92f9328
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreQualificationView.java
@@ -0,0 +1,21 @@
+package com.oying.modules.pc.store.view;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class CustomerStoreQualificationView {
+
+    @NotNull
+    @ApiModelProperty(value = "资质类型")
+    private Integer type;
+
+    @ApiModelProperty(value = "资质名称")
+    private String name;
+
+    @ApiModelProperty(value = "资质图片")
+    private String imageUrl;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreView.java b/oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreView.java
new file mode 100644
index 0000000..b68087a
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreView.java
@@ -0,0 +1,28 @@
+package com.oying.modules.pc.store.view;
+
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+
+@Data
+public class CustomerStoreView {
+
+    private String name;
+
+    private String logoUrl;
+
+    private String description;
+
+    private String address;
+
+    private String businessHours;
+
+    private String contactPhone;
+
+    private Integer score;
+
+    private Integer deliveryDuration;
+
+    private Integer monthlySales;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/view/StoreCategoryMerchantView.java b/oying-system/src/main/java/com/oying/modules/pc/store/view/StoreCategoryMerchantView.java
new file mode 100644
index 0000000..05d0450
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/view/StoreCategoryMerchantView.java
@@ -0,0 +1,23 @@
+package com.oying.modules.pc.store.view;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class StoreCategoryMerchantView {
+
+    private Long categoryId;
+
+    private Long storeId;
+
+    private Long parentId;
+
+    private String name;
+
+    private Integer sortWeight;
+
+    private Integer active;
+
+    private List<StoreCategoryMerchantView> children;
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/view/StoreMerchantView.java b/oying-system/src/main/java/com/oying/modules/pc/store/view/StoreMerchantView.java
new file mode 100644
index 0000000..d5c970f
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/view/StoreMerchantView.java
@@ -0,0 +1,48 @@
+package com.oying.modules.pc.store.view;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalTime;
+
+@Data
+public class StoreMerchantView {
+
+    @ApiModelProperty(value = "ID")
+    private Long storeId;
+
+    @ApiModelProperty(value = "平台类目")
+    private Long platformCategoryId;
+
+    @ApiModelProperty(value = "店铺名称")
+    private String storeName;
+
+    private String logoUrl;
+
+    @ApiModelProperty(value = "店铺描述")
+    private String description;
+
+    @ApiModelProperty(value = "联系电话")
+    private String contactPhone;
+
+    @ApiModelProperty(value = "营业开始时间")
+    private LocalTime openTime;
+
+    @ApiModelProperty(value = "营业结束时间")
+    private LocalTime closeTime;
+
+    @ApiModelProperty(value = "详细地址")
+    private String address;
+
+    @ApiModelProperty(value = "经度")
+    private Double longitude;
+
+    @ApiModelProperty(value = "纬度")
+    private Double latitude;
+
+    @ApiModelProperty(value = "营业半径(米)")
+    private Integer radius;
+
+    private Integer status;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/view/StoreQualificationMerchantView.java b/oying-system/src/main/java/com/oying/modules/pc/store/view/StoreQualificationMerchantView.java
new file mode 100644
index 0000000..0c45390
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/view/StoreQualificationMerchantView.java
@@ -0,0 +1,24 @@
+package com.oying.modules.pc.store.view;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class StoreQualificationMerchantView {
+
+    @NotNull
+    @ApiModelProperty(value = "资质ID")
+    private Long id;
+
+    @ApiModelProperty(value = "资质类型")
+    private Integer type;
+
+    @ApiModelProperty(value = "资质名称")
+    private String name;
+
+    @ApiModelProperty(value = "资质图片")
+    private String imageUrl;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/view/StoreSimpleView.java b/oying-system/src/main/java/com/oying/modules/pc/store/view/StoreSimpleView.java
new file mode 100644
index 0000000..1a93719
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/view/StoreSimpleView.java
@@ -0,0 +1,16 @@
+package com.oying.modules.pc.store.view;
+
+import lombok.Data;
+
+@Data
+public class StoreSimpleView {
+
+    private Long id;
+
+    private String name;
+
+    private String logoUrl;
+
+    private Integer status;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/utils/WrapperUtils.java b/oying-system/src/main/java/com/oying/modules/pc/utils/WrapperUtils.java
new file mode 100644
index 0000000..304b570
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/utils/WrapperUtils.java
@@ -0,0 +1,18 @@
+package com.oying.modules.pc.utils;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.oying.base.BaseEntity;
+
+public class WrapperUtils {
+
+    public static <T> UpdateWrapper<T> baseUpdateWrapper(Long id, Long updateBy) {
+        return new UpdateWrapper<T>()
+                .eq("id", id)
+                .set("update_by", updateBy);
+    }
+
+    public static <T extends BaseEntity> LambdaUpdateWrapper<T> getBaseLambdaUpdateWrapper(Long id, Long updateBy) {
+        return new LambdaUpdateWrapper<T>();
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/quartz/rest/QuartzJobController.java b/oying-system/src/main/java/com/oying/modules/quartz/rest/QuartzJobController.java
index 9636273..a3ed98a 100644
--- a/oying-system/src/main/java/com/oying/modules/quartz/rest/QuartzJobController.java
+++ b/oying-system/src/main/java/com/oying/modules/quartz/rest/QuartzJobController.java
@@ -3,6 +3,7 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.oying.modules.quartz.domain.QuartzJob;
 import com.oying.modules.quartz.domain.QuartzLog;
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -18,6 +19,7 @@
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.Set;
@@ -39,9 +41,9 @@
     @ApiOperation("查询定时任务")
     @GetMapping
     @PreAuthorize("@el.check('timing:list')")
-    public ResponseEntity<PageResult<QuartzJob>> queryQuartzJob(QuartzJobQueryCriteria criteria){
+    public ResponseEntity<Object> queryQuartzJob(QuartzJobQueryCriteria criteria) {
         Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
-        return new ResponseEntity<>(quartzJobService.queryAll(criteria,page), HttpStatus.OK);
+        return new ResponseEntity<>(R.success(quartzJobService.queryAll(criteria, page)), HttpStatus.OK);
     }
 
     @ApiOperation("导出任务数据")
@@ -61,71 +63,72 @@
     @ApiOperation("查询任务执行日志")
     @GetMapping(value = "/logs")
     @PreAuthorize("@el.check('timing:list')")
-    public ResponseEntity<PageResult<QuartzLog>> queryQuartzJobLog(QuartzJobQueryCriteria criteria){
+    public ResponseEntity<Object> queryQuartzJobLog(QuartzJobQueryCriteria criteria) {
         Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
-        return new ResponseEntity<>(quartzJobService.queryAllLog(criteria,page), HttpStatus.OK);
+        return new ResponseEntity<>(R.success(quartzJobService.queryAllLog(criteria, page)), HttpStatus.OK);
     }
 
     @Log("新增定时任务")
     @ApiOperation("新增定时任务")
     @PostMapping
     @PreAuthorize("@el.check('timing:add')")
-    public ResponseEntity<Object> createQuartzJob(@Validated @RequestBody QuartzJob resources){
+    public ResponseEntity<Object> createQuartzJob(@Validated @RequestBody QuartzJob resources) {
         if (resources.getId() != null) {
-            throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
+            throw new BadRequestException("A new " + ENTITY_NAME + " cannot already have an ID");
         }
         // 验证Bean是不是合法的,合法的定时任务 Bean 需要用 @Service 定义
         checkBean(resources.getBeanName());
         quartzJobService.create(resources);
-        return new ResponseEntity<>(HttpStatus.CREATED);
+        return new ResponseEntity<>(R.success(), HttpStatus.CREATED);
     }
 
     @Log("修改定时任务")
     @ApiOperation("修改定时任务")
     @PutMapping
     @PreAuthorize("@el.check('timing:edit')")
-    public ResponseEntity<Object> updateQuartzJob(@Validated(QuartzJob.Update.class) @RequestBody QuartzJob resources){
+    public ResponseEntity<Object> updateQuartzJob(@Validated(QuartzJob.Update.class) @RequestBody QuartzJob resources) {
         // 验证Bean是不是合法的,合法的定时任务 Bean 需要用 @Service 定义
         checkBean(resources.getBeanName());
         quartzJobService.update(resources);
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(), HttpStatus.NO_CONTENT);
     }
 
     @Log("更改定时任务状态")
     @ApiOperation("更改定时任务状态")
     @PutMapping(value = "/{id}")
     @PreAuthorize("@el.check('timing:edit')")
-    public ResponseEntity<Object> updateQuartzJobStatus(@PathVariable Long id){
+    public ResponseEntity<Object> updateQuartzJobStatus(@PathVariable Long id) {
         quartzJobService.updateIsPause(quartzJobService.getById(id));
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(), HttpStatus.NO_CONTENT);
     }
 
     @Log("执行定时任务")
     @ApiOperation("执行定时任务")
     @PutMapping(value = "/exec/{id}")
     @PreAuthorize("@el.check('timing:edit')")
-    public ResponseEntity<Object> executionQuartzJob(@PathVariable Long id){
+    public ResponseEntity<Object> executionQuartzJob(@PathVariable Long id) {
         quartzJobService.execution(quartzJobService.getById(id));
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(), HttpStatus.NO_CONTENT);
     }
 
     @Log("删除定时任务")
     @ApiOperation("删除定时任务")
     @DeleteMapping
     @PreAuthorize("@el.check('timing:del')")
-    public ResponseEntity<Object> deleteQuartzJob(@RequestBody Set<Long> ids){
+    public ResponseEntity<Object> deleteQuartzJob(@RequestBody Set<Long> ids) {
         quartzJobService.delete(ids);
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(),HttpStatus.OK);
     }
 
     /**
      * 验证Bean是不是合法的,合法的定时任务 Bean 需要用 @Service 定义
+     *
      * @param beanName Bean名称
      */
-    private void checkBean(String beanName){
+    private void checkBean(String beanName) {
         // 避免调用攻击者可以从SpringContextHolder获得控制jdbcTemplate类
         // 并使用getDeclaredMethod调用jdbcTemplate的queryForMap函数,执行任意sql命令。
-        if(!SpringBeanHolder.getAllServiceBeanName().contains(beanName)){
+        if (!SpringBeanHolder.getAllServiceBeanName().contains(beanName)) {
             throw new BadRequestException("非法的 Bean,请重新输入!");
         }
     }
diff --git a/oying-system/src/main/java/com/oying/modules/security/config/SwiftPassProperties.java b/oying-system/src/main/java/com/oying/modules/security/config/SwiftPassProperties.java
new file mode 100644
index 0000000..7724412
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/security/config/SwiftPassProperties.java
@@ -0,0 +1,40 @@
+package com.oying.modules.security.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author xin
+ * @description
+ * @date 2025/1/22 下午4:49
+ */
+@Getter
+@Setter
+@Configuration
+@ConfigurationProperties(prefix = "swift-pass")
+public class SwiftPassProperties {
+    // 交易密钥1
+    private String key;
+    // 平台私钥
+    private String mchPrivateKey;
+    // 平台公钥
+    private String platPublicKey;
+    // 门店编号1
+    private String mchId;
+    // 签名方式
+    private String signType;
+    // 原生JS
+    private String isRaw;
+    // 是否小程序支付
+    private String isMinipg;
+    // AppID
+    private String appId;
+    // 请求url
+    private String reqUrl;
+    // 支付通知地址
+    private String notifyUrl;
+    // 退款通知地址
+    private String refundUrl;
+}
diff --git a/oying-system/src/main/java/com/oying/modules/security/config/WeiXinProperties.java b/oying-system/src/main/java/com/oying/modules/security/config/WeiXinProperties.java
new file mode 100644
index 0000000..bcaca43
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/security/config/WeiXinProperties.java
@@ -0,0 +1,31 @@
+package com.oying.modules.security.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "wx")
+public class WeiXinProperties {
+    // APPID
+    private String appId;
+    // APP密钥
+    private String appSecret;
+    // 跳转小程序类型
+    private String miniProgramState;
+    /*access_token的KEY*/
+    private String tokenKey;
+    /*access_token的失效时间间隔,微信是2小时,此处隔7200秒就重新获取*/
+    private Long tokenTime;
+    /*POST 获取稳定版接口调用凭据 获取小程序全局唯一后台接口调用凭据,token有效期为7200s,开发者需要进行妥善保存。*/
+    private String getStableAccessToken;
+    /*GET 小程序登录 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程*/
+    private String code2Session;
+    /*POST 获取手机号 该接口用于将code换取用户手机号。 说明,每个code只能使用一次,code的有效期为5min。*/
+    private String getPhoneNumber;
+    /*POST 该接口用于发送订阅消息。*/
+    private String sendMessage;
+    /* 是否生成环境*/
+    private boolean enabled;
+}
diff --git a/oying-system/src/main/java/com/oying/modules/security/rest/AuthController.java b/oying-system/src/main/java/com/oying/modules/security/rest/AuthController.java
index d6443ee..da9d9b8 100644
--- a/oying-system/src/main/java/com/oying/modules/security/rest/AuthController.java
+++ b/oying-system/src/main/java/com/oying/modules/security/rest/AuthController.java
@@ -10,6 +10,7 @@
 import com.oying.modules.security.service.UserDetailsServiceImpl;
 import com.oying.modules.security.service.dto.AuthUserDto;
 import com.oying.modules.security.service.dto.JwtUserDto;
+import com.oying.utils.*;
 import com.wf.captcha.base.Captcha;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -21,10 +22,6 @@
 import com.oying.annotation.rest.AnonymousPostMapping;
 import com.oying.config.properties.RsaProperties;
 import com.oying.exception.BadRequestException;
-import com.oying.utils.RsaUtils;
-import com.oying.utils.RedisUtils;
-import com.oying.utils.SecurityUtils;
-import com.oying.utils.StringUtils;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -34,6 +31,7 @@
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+
 import javax.servlet.http.HttpServletRequest;
 import java.util.HashMap;
 import java.util.Map;
@@ -98,11 +96,11 @@
         // 保存在线信息
         onlineUserService.save(jwtUser, token, request);
         // 返回登录信息
-        return ResponseEntity.ok(authInfo);
+        return ResponseEntity.ok(R.success(authInfo));
     }
 
     @ApiOperation("临时授权")
-    @AnonymousPostMapping(value = "/token")
+    @AnonymousGetMapping(value = "/token")
     public ResponseEntity<Object> loginTest(@RequestParam String username, HttpServletRequest request) {
         // 生成令牌与第三方系统获取令牌方式
         JwtUserDto jwtUser = userDetailsService.loadUserByUsername(username);
@@ -118,14 +116,14 @@
         // 保存在线信息
         onlineUserService.save(jwtUser, token, request);
         // 返回登录信息
-        return ResponseEntity.ok(authInfo);
+        return ResponseEntity.ok(R.success(authInfo));
     }
 
     @ApiOperation("获取用户信息")
     @GetMapping(value = "/info")
-    public ResponseEntity<UserDetails> getUserInfo() {
+    public ResponseEntity<Object> getUserInfo() {
         JwtUserDto jwtUser = (JwtUserDto) SecurityUtils.getCurrentUser();
-        return ResponseEntity.ok(jwtUser);
+        return ResponseEntity.ok(R.success(jwtUser));
     }
 
     @ApiOperation("获取验证码")
@@ -146,7 +144,7 @@
             put("img", captcha.toBase64());
             put("uuid", uuid);
         }};
-        return ResponseEntity.ok(imgResult);
+        return ResponseEntity.ok(R.success(imgResult));
     }
 
     @ApiOperation("退出登录")
@@ -154,6 +152,6 @@
     public ResponseEntity<Object> logout(HttpServletRequest request) {
         String token = tokenProvider.getToken(request);
         onlineUserService.logout(token);
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 }
diff --git a/oying-system/src/main/java/com/oying/modules/security/rest/OnlineController.java b/oying-system/src/main/java/com/oying/modules/security/rest/OnlineController.java
index c3b988c..174ffdf 100644
--- a/oying-system/src/main/java/com/oying/modules/security/rest/OnlineController.java
+++ b/oying-system/src/main/java/com/oying/modules/security/rest/OnlineController.java
@@ -2,6 +2,7 @@
 
 import com.oying.modules.security.service.OnlineUserService;
 import com.oying.modules.security.service.dto.OnlineUserDto;
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -12,6 +13,7 @@
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
+
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.Set;
@@ -30,8 +32,8 @@
     @ApiOperation("查询在线用户")
     @GetMapping
     @PreAuthorize("@el.check()")
-    public ResponseEntity<PageResult<OnlineUserDto>> queryOnlineUser(String username, Pageable pageable){
-        return new ResponseEntity<>(onlineUserService.getAll(username, pageable),HttpStatus.OK);
+    public ResponseEntity<Object> queryOnlineUser(String username, Pageable pageable) {
+        return new ResponseEntity<>(R.success(onlineUserService.getAll(username, pageable)), HttpStatus.OK);
     }
 
     @ApiOperation("导出数据")
@@ -50,6 +52,6 @@
             token = EncryptUtils.desDecrypt(token);
             onlineUserService.logout(token);
         }
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 }
diff --git a/oying-system/src/main/java/com/oying/modules/security/rest/VerificationController.java b/oying-system/src/main/java/com/oying/modules/security/rest/VerificationController.java
new file mode 100644
index 0000000..20fdd29
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/security/rest/VerificationController.java
@@ -0,0 +1,45 @@
+package com.oying.modules.security.rest;
+
+import cn.hutool.core.util.IdUtil;
+import com.oying.annotation.rest.AnonymousGetMapping;
+import com.oying.utils.R;
+import com.oying.utils.RedisUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author xin
+ * @description
+ * @date 2025/5/29 00:54
+ */
+@Slf4j
+@RestController
+@RequestMapping("/auth/verification")
+@RequiredArgsConstructor
+@Api(tags = "系统:短信验证码")
+public class VerificationController {
+
+    private final RedisUtils redisUtils;
+    @Value("${sms.key}")
+    private String key;
+    @Value("${sms.time}")
+    private Long time;
+
+    @AnonymousGetMapping
+    @ApiOperation("短信验证码")
+    public ResponseEntity<Object> toPayAsPc(@RequestParam String phone) {
+        String uuid = key + IdUtil.simpleUUID();
+        System.out.println(phone);
+        //创建验证码
+        String verification = (int) ((Math.random() * 9 + 1) * 100000) + "";
+        redisUtils.set(uuid, verification, time);
+        return ResponseEntity.ok(R.success(uuid));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/security/service/WeiXinService.java b/oying-system/src/main/java/com/oying/modules/security/service/WeiXinService.java
new file mode 100644
index 0000000..2826e98
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/security/service/WeiXinService.java
@@ -0,0 +1,112 @@
+package com.oying.modules.security.service;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.oying.modules.security.config.WeiXinProperties;
+import com.oying.utils.HttpRequest;
+import com.oying.utils.RedisUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+@Service
+@Slf4j
+public class WeiXinService {
+
+    @Resource
+    private WeiXinProperties weiXinProperties;
+    @Resource
+    private RedisUtils redisUtils;
+    @Value("${wx.enabled}")
+    private Boolean wxEnabled;
+
+    /**
+     * POST 获取稳定版接口调用凭据 获取小程序全局唯一后台接口调用凭据,token有效期为7200s,开发者需要进行妥善保存。
+     *
+     * @return accessToken
+     */
+    public String getStableAccessToken() {
+        String accessToken;
+        if (redisUtils.isExpire(weiXinProperties.getTokenKey())) {
+            // 获取接口调用凭据
+            String url = weiXinProperties.getGetStableAccessToken();
+            Map<String, Object> map = new LinkedHashMap<>();
+            map.put("grant_type", "client_credential");
+            map.put("appid", weiXinProperties.getAppId());
+            map.put("secret", weiXinProperties.getAppSecret());
+            map.put("force_refresh", false);
+            JSONObject jsonObject = HttpRequest.exchangeJsonObject(HttpMethod.POST, url, map);
+            accessToken = jsonObject.getString("access_token");
+            redisUtils.set(weiXinProperties.getTokenKey(), accessToken, weiXinProperties.getTokenTime());
+        } else {
+            // 查询接口调用凭据
+            accessToken = (String) redisUtils.get(weiXinProperties.getTokenKey());
+        }
+        return accessToken;
+    }
+
+    /**
+     * GET 小程序登录 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程
+     *
+     * @param js_code 登录时获取的 code,可通过wx.login获取
+     * @return JSONObject
+     */
+    public JSONObject code2Session(String js_code) {
+        String url = weiXinProperties.getCode2Session();
+        url = url.replace("{appid}", weiXinProperties.getAppId())
+                .replace("{secret}", weiXinProperties.getAppSecret())
+                .replace("{js_code}", js_code);
+        return HttpRequest.exchangeJsonObject(HttpMethod.GET, url, null);
+    }
+
+    /**
+     * POST 获取手机号 该接口用于将code换取用户手机号。 说明,每个code只能使用一次,code的有效期为5min。
+     *
+     * @param code 手机号获取凭证
+     * @return JSONObject
+     */
+    public JSONObject getPhoneNumber(String code) {
+        String url = weiXinProperties.getGetPhoneNumber();
+        url = url.replace("{accessToken}", getStableAccessToken());
+        Map<String, Object> map = new LinkedHashMap<>();
+        map.put("code", code);
+        return HttpRequest.exchangeJsonObject(HttpMethod.POST, url, map);
+    }
+
+    /**
+     * POST 该接口用于发送订阅消息。
+     *
+     * @param data 请求参数
+     * @param openId 用户openId
+     * @param templateId 订阅模板id
+     * @param page 小程序跳转链接
+     * @return JSONObject
+     */
+    public JSONObject sendMessage(Map<String, Object> data, String openId, String templateId, String page) {
+        if (wxEnabled) {
+            String url = weiXinProperties.getSendMessage();
+            url = url.replace("{accessToken}", getStableAccessToken());
+            Map<String, Object> map = getSendMessageDto(data, openId, templateId, page);
+            return HttpRequest.exchangeJsonObject(HttpMethod.POST, url, map);
+        }
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("message", "测试环境");
+        return jsonObject;
+    }
+
+    private Map<String, Object> getSendMessageDto(Map<String, Object> data, String openId, String templateId, String page) {
+        Map<String, Object> map = new HashMap<>();
+        map.put("touser", openId);
+        map.put("template_id", templateId);
+        map.put("page", page);
+        map.put("miniprogram_state", weiXinProperties.getMiniProgramState());
+        map.put("lang", "zh_CN");
+        map.put("data", data);
+        return map;
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/system/domain/Merchants.java b/oying-system/src/main/java/com/oying/modules/system/domain/Merchants.java
new file mode 100644
index 0000000..139f7b5
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/system/domain/Merchants.java
@@ -0,0 +1,68 @@
+package com.oying.modules.system.domain;
+
+import com.oying.base.BaseEntity;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import java.sql.Timestamp;
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+* @description /
+* @author lixin
+* @date 2025-05-29
+**/
+@Getter
+@Setter
+@TableName("sys_merchants")
+public class Merchants extends BaseEntity implements Serializable {
+
+    @TableId(value = "merchants_id", type = IdType.AUTO)
+    @ApiModelProperty(value = "ID")
+    private Long merchantsId;
+
+    @NotBlank
+    @ApiModelProperty(value = "名称")
+    private String merchantName;
+
+    @NotBlank
+    @ApiModelProperty(value = "商户编码")
+    private String merchantCode;
+
+    @NotBlank
+    @ApiModelProperty(value = "营业执照号")
+    private String businessLicense;
+
+    @NotBlank
+    @ApiModelProperty(value = "营业执照号路径")
+    private String businessLicensePath;
+
+    @NotBlank
+    @ApiModelProperty(value = "联系手机")
+    private String contactMobile;
+
+    @ApiModelProperty(value = "排序")
+    private Integer merchantsSort;
+
+    @ApiModelProperty(value = "状态")
+    private String enabled = "1";
+
+    @ApiModelProperty(value = "审核人")
+    private String authUser;
+
+    @ApiModelProperty(value = "审核时间")
+    private Timestamp authTime;
+
+    @ApiModelProperty(value = "审核信息")
+    private String authMessage;
+
+    public void copy(Merchants source){
+        BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/system/domain/dto/MerchantsQueryCriteria.java b/oying-system/src/main/java/com/oying/modules/system/domain/dto/MerchantsQueryCriteria.java
new file mode 100644
index 0000000..f56c7a0
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/system/domain/dto/MerchantsQueryCriteria.java
@@ -0,0 +1,36 @@
+package com.oying.modules.system.domain.dto;
+
+import lombok.Data;
+import java.sql.Timestamp;
+import java.util.List;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+* @author lixin
+* @date 2025-05-29
+**/
+@Data
+public class MerchantsQueryCriteria{
+
+    @ApiModelProperty(value = "页码", example = "1")
+    private Integer page = 1;
+
+    @ApiModelProperty(value = "每页数据量", example = "10")
+    private Integer size = 10;
+
+    @ApiModelProperty(value = "名称")
+    private String merchantName;
+
+    @ApiModelProperty(value = "商户编码")
+    private String merchantCode;
+
+    @ApiModelProperty(value = "营业执照号")
+    private String businessLicense;
+
+    @ApiModelProperty(value = "联系手机")
+    private String contactMobile;
+
+    @ApiModelProperty(value = "状态")
+    private String enabled;
+    private List<Timestamp> createTime;
+}
diff --git a/oying-system/src/main/java/com/oying/modules/system/mapper/MerchantsMapper.java b/oying-system/src/main/java/com/oying/modules/system/mapper/MerchantsMapper.java
new file mode 100644
index 0000000..c1ea786
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/system/mapper/MerchantsMapper.java
@@ -0,0 +1,22 @@
+package com.oying.modules.system.mapper;
+
+import com.oying.modules.system.domain.Merchants;
+import com.oying.modules.system.domain.dto.MerchantsQueryCriteria;
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Mapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+* @author lixin
+* @date 2025-05-29
+**/
+@Mapper
+public interface MerchantsMapper extends BaseMapper<Merchants> {
+
+    IPage<Merchants> findAll(@Param("criteria") MerchantsQueryCriteria criteria, Page<Object> page);
+
+    List<Merchants> findAll(@Param("criteria") MerchantsQueryCriteria criteria);
+}
diff --git a/oying-system/src/main/java/com/oying/modules/system/rest/DeptController.java b/oying-system/src/main/java/com/oying/modules/system/rest/DeptController.java
index 3245954..68314fd 100644
--- a/oying-system/src/main/java/com/oying/modules/system/rest/DeptController.java
+++ b/oying-system/src/main/java/com/oying/modules/system/rest/DeptController.java
@@ -3,6 +3,7 @@
 import cn.hutool.core.collection.CollectionUtil;
 import com.oying.modules.system.domain.Dept;
 import com.oying.modules.system.domain.dto.DeptQueryCriteria;
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -16,14 +17,15 @@
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+
 import javax.servlet.http.HttpServletResponse;
 import java.util.*;
 import java.util.stream.Collectors;
 
 /**
-* @author Z
-* @date 2019-03-25
-*/
+ * @author Z
+ * @date 2019-03-25
+ */
 @RestController
 @RequiredArgsConstructor
 @Api(tags = "系统:机构管理")
@@ -43,22 +45,22 @@
     @ApiOperation("查询机构")
     @GetMapping
     @PreAuthorize("@el.check('user:list','dept:list')")
-    public ResponseEntity<PageResult<Dept>> queryDept(DeptQueryCriteria criteria) throws Exception {
+    public ResponseEntity<Object> queryDept(DeptQueryCriteria criteria) throws Exception {
         List<Dept> depts = deptService.queryAll(criteria, true);
-        return new ResponseEntity<>(PageUtil.toPage(depts),HttpStatus.OK);
+        return new ResponseEntity<>(R.success(PageUtil.toPage(depts)), HttpStatus.OK);
     }
 
     @ApiOperation("查询机构:根据ID获取同级与上级数据")
     @PostMapping("/superior")
     @PreAuthorize("@el.check('user:list','dept:list')")
     public ResponseEntity<Object> getDeptSuperior(@RequestBody List<Long> ids, @RequestParam(defaultValue = "false") Boolean exclude) {
-        Set<Dept> deptSet  = new LinkedHashSet<>();
+        Set<Dept> deptSet = new LinkedHashSet<>();
         for (Long id : ids) {
             Dept dept = deptService.findById(id);
             List<Dept> depts = deptService.getSuperior(dept, new ArrayList<>());
-            if(exclude){
+            if (exclude) {
                 for (Dept data : depts) {
-                    if(data.getId().equals(dept.getPid())) {
+                    if (data.getId().equals(dept.getPid())) {
                         data.setSubCount(data.getSubCount() - 1);
                     }
                 }
@@ -67,46 +69,46 @@
             }
             deptSet.addAll(depts);
         }
-        return new ResponseEntity<>(deptService.buildTree(new ArrayList<>(deptSet)),HttpStatus.OK);
+        return new ResponseEntity<>(R.success(deptService.buildTree(new ArrayList<>(deptSet))), HttpStatus.OK);
     }
 
     @Log("新增机构")
     @ApiOperation("新增机构")
     @PostMapping
     @PreAuthorize("@el.check('dept:add')")
-    public ResponseEntity<Object> createDept(@Validated @RequestBody Dept resources){
+    public ResponseEntity<Object> createDept(@Validated @RequestBody Dept resources) {
         if (resources.getId() != null) {
-            throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
+            throw new BadRequestException("A new " + ENTITY_NAME + " cannot already have an ID");
         }
         deptService.create(resources);
-        return new ResponseEntity<>(HttpStatus.CREATED);
+        return new ResponseEntity<>(R.success(), HttpStatus.CREATED);
     }
 
     @Log("修改机构")
     @ApiOperation("修改机构")
     @PutMapping
     @PreAuthorize("@el.check('dept:edit')")
-    public ResponseEntity<Object> updateDept(@Validated(Dept.Update.class) @RequestBody Dept resources){
+    public ResponseEntity<Object> updateDept(@Validated(Dept.Update.class) @RequestBody Dept resources) {
         deptService.update(resources);
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(), HttpStatus.NO_CONTENT);
     }
 
     @Log("删除机构")
     @ApiOperation("删除机构")
     @DeleteMapping
     @PreAuthorize("@el.check('dept:del')")
-    public ResponseEntity<Object> deleteDept(@RequestBody Set<Long> ids){
+    public ResponseEntity<Object> deleteDept(@RequestBody Set<Long> ids) {
         Set<Dept> depts = new HashSet<>();
         for (Long id : ids) {
             List<Dept> deptList = deptService.findByPid(id);
             depts.add(deptService.findById(id));
-            if(CollectionUtil.isNotEmpty(deptList)){
+            if (CollectionUtil.isNotEmpty(deptList)) {
                 depts = deptService.getDeleteDepts(deptList, depts);
             }
         }
         // 验证是否被角色或用户关联
         deptService.verification(depts);
         deptService.delete(depts);
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(),HttpStatus.OK);
     }
 }
diff --git a/oying-system/src/main/java/com/oying/modules/system/rest/DictController.java b/oying-system/src/main/java/com/oying/modules/system/rest/DictController.java
index 48685d8..bd863b0 100644
--- a/oying-system/src/main/java/com/oying/modules/system/rest/DictController.java
+++ b/oying-system/src/main/java/com/oying/modules/system/rest/DictController.java
@@ -3,6 +3,7 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.oying.modules.system.domain.Dict;
 import com.oying.modules.system.domain.dto.DictQueryCriteria;
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -15,15 +16,16 @@
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.List;
 import java.util.Set;
 
 /**
-* @author Z
-* @date 2019-04-10
-*/
+ * @author Z
+ * @date 2019-04-10
+ */
 @RestController
 @RequiredArgsConstructor
 @Api(tags = "系统:字典管理")
@@ -43,45 +45,45 @@
     @ApiOperation("查询字典")
     @GetMapping(value = "/all")
     @PreAuthorize("@el.check('dict:list')")
-    public ResponseEntity<List<Dict>> queryAllDict(){
-        return new ResponseEntity<>(dictService.queryAll(new DictQueryCriteria()),HttpStatus.OK);
+    public ResponseEntity<Object> queryAllDict() {
+        return new ResponseEntity<>(R.success(dictService.queryAll(new DictQueryCriteria())), HttpStatus.OK);
     }
 
     @ApiOperation("查询字典")
     @GetMapping
     @PreAuthorize("@el.check('dict:list')")
-    public ResponseEntity<PageResult<Dict>> queryDict(DictQueryCriteria criteria){
+    public ResponseEntity<Object> queryDict(DictQueryCriteria criteria) {
         Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
-        return new ResponseEntity<>(dictService.queryAll(criteria, page),HttpStatus.OK);
+        return new ResponseEntity<>(R.success(dictService.queryAll(criteria, page)), HttpStatus.OK);
     }
 
     @Log("新增字典")
     @ApiOperation("新增字典")
     @PostMapping
     @PreAuthorize("@el.check('dict:add')")
-    public ResponseEntity<Object> createDict(@Validated @RequestBody Dict resources){
+    public ResponseEntity<Object> createDict(@Validated @RequestBody Dict resources) {
         if (resources.getId() != null) {
-            throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
+            throw new BadRequestException("A new " + ENTITY_NAME + " cannot already have an ID");
         }
         dictService.create(resources);
-        return new ResponseEntity<>(HttpStatus.CREATED);
+        return new ResponseEntity<>(R.success(), HttpStatus.CREATED);
     }
 
     @Log("修改字典")
     @ApiOperation("修改字典")
     @PutMapping
     @PreAuthorize("@el.check('dict:edit')")
-    public ResponseEntity<Object> updateDict(@Validated(Dict.Update.class) @RequestBody Dict resources){
+    public ResponseEntity<Object> updateDict(@Validated(Dict.Update.class) @RequestBody Dict resources) {
         dictService.update(resources);
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(), HttpStatus.NO_CONTENT);
     }
 
     @Log("删除字典")
     @ApiOperation("删除字典")
     @DeleteMapping
     @PreAuthorize("@el.check('dict:del')")
-    public ResponseEntity<Object> deleteDict(@RequestBody Set<Long> ids){
+    public ResponseEntity<Object> deleteDict(@RequestBody Set<Long> ids) {
         dictService.delete(ids);
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 }
diff --git a/oying-system/src/main/java/com/oying/modules/system/rest/DictDetailController.java b/oying-system/src/main/java/com/oying/modules/system/rest/DictDetailController.java
index 693aaed..90640b6 100644
--- a/oying-system/src/main/java/com/oying/modules/system/rest/DictDetailController.java
+++ b/oying-system/src/main/java/com/oying/modules/system/rest/DictDetailController.java
@@ -2,6 +2,7 @@
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.oying.modules.system.domain.DictDetail;
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -15,14 +16,15 @@
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 /**
-* @author Z
-* @date 2019-04-10
-*/
+ * @author Z
+ * @date 2019-04-10
+ */
 @RestController
 @RequiredArgsConstructor
 @Api(tags = "系统:字典详情管理")
@@ -34,49 +36,49 @@
 
     @ApiOperation("查询字典详情")
     @GetMapping
-    public ResponseEntity<PageResult<DictDetail>> queryDictDetail(DictDetailQueryCriteria criteria){
+    public ResponseEntity<Object> queryDictDetail(DictDetailQueryCriteria criteria) {
         Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
-        return new ResponseEntity<>(dictDetailService.queryAll(criteria, page),HttpStatus.OK);
+        return new ResponseEntity<>(R.success(dictDetailService.queryAll(criteria, page)), HttpStatus.OK);
     }
 
     @ApiOperation("查询多个字典详情")
     @GetMapping(value = "/map")
-    public ResponseEntity<Object> getDictDetailMaps(@RequestParam String dictName){
+    public ResponseEntity<Object> getDictDetailMaps(@RequestParam String dictName) {
         String[] names = dictName.split("[,,]");
         Map<String, List<DictDetail>> dictMap = new HashMap<>(16);
         for (String name : names) {
             dictMap.put(name, dictDetailService.getDictByName(name));
         }
-        return new ResponseEntity<>(dictMap, HttpStatus.OK);
+        return new ResponseEntity<>(R.success(dictMap), HttpStatus.OK);
     }
 
     @Log("新增字典详情")
     @ApiOperation("新增字典详情")
     @PostMapping
     @PreAuthorize("@el.check('dict:add')")
-    public ResponseEntity<Object> createDictDetail(@Validated @RequestBody DictDetail resources){
+    public ResponseEntity<Object> createDictDetail(@Validated @RequestBody DictDetail resources) {
         if (resources.getId() != null) {
-            throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
+            throw new BadRequestException("A new " + ENTITY_NAME + " cannot already have an ID");
         }
         dictDetailService.create(resources);
-        return new ResponseEntity<>(HttpStatus.CREATED);
+        return new ResponseEntity<>(R.success(), HttpStatus.CREATED);
     }
 
     @Log("修改字典详情")
     @ApiOperation("修改字典详情")
     @PutMapping
     @PreAuthorize("@el.check('dict:edit')")
-    public ResponseEntity<Object> updateDictDetail(@Validated(DictDetail.Update.class) @RequestBody DictDetail resources){
+    public ResponseEntity<Object> updateDictDetail(@Validated(DictDetail.Update.class) @RequestBody DictDetail resources) {
         dictDetailService.update(resources);
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(), HttpStatus.NO_CONTENT);
     }
 
     @Log("删除字典详情")
     @ApiOperation("删除字典详情")
     @DeleteMapping(value = "/{id}")
     @PreAuthorize("@el.check('dict:del')")
-    public ResponseEntity<Object> deleteDictDetail(@PathVariable Long id){
+    public ResponseEntity<Object> deleteDictDetail(@PathVariable Long id) {
         dictDetailService.delete(id);
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 }
diff --git a/oying-system/src/main/java/com/oying/modules/system/rest/JobController.java b/oying-system/src/main/java/com/oying/modules/system/rest/JobController.java
index 1638bee..1ce8bce 100644
--- a/oying-system/src/main/java/com/oying/modules/system/rest/JobController.java
+++ b/oying-system/src/main/java/com/oying/modules/system/rest/JobController.java
@@ -3,6 +3,7 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.oying.modules.system.domain.Job;
 import com.oying.modules.system.domain.dto.JobQueryCriteria;
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -15,14 +16,15 @@
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.Set;
 
 /**
-* @author Z
-* @date 2019-03-29
-*/
+ * @author Z
+ * @date 2019-03-29
+ */
 @RestController
 @RequiredArgsConstructor
 @Api(tags = "系统:岗位管理")
@@ -42,40 +44,40 @@
     @ApiOperation("查询岗位")
     @GetMapping
     @PreAuthorize("@el.check('job:list','user:list')")
-    public ResponseEntity<PageResult<Job>> queryJob(JobQueryCriteria criteria){
+    public ResponseEntity<Object> queryJob(JobQueryCriteria criteria) {
         Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
-        return new ResponseEntity<>(jobService.queryAll(criteria, page),HttpStatus.OK);
+        return new ResponseEntity<>(R.success(jobService.queryAll(criteria, page)), HttpStatus.OK);
     }
 
     @Log("新增岗位")
     @ApiOperation("新增岗位")
     @PostMapping
     @PreAuthorize("@el.check('job:add')")
-    public ResponseEntity<Object> createJob(@Validated @RequestBody Job resources){
+    public ResponseEntity<Object> createJob(@Validated @RequestBody Job resources) {
         if (resources.getId() != null) {
-            throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
+            throw new BadRequestException("A new " + ENTITY_NAME + " cannot already have an ID");
         }
         jobService.create(resources);
-        return new ResponseEntity<>(HttpStatus.CREATED);
+        return new ResponseEntity<>(R.success(), HttpStatus.CREATED);
     }
 
     @Log("修改岗位")
     @ApiOperation("修改岗位")
     @PutMapping
     @PreAuthorize("@el.check('job:edit')")
-    public ResponseEntity<Object> updateJob(@Validated(Job.Update.class) @RequestBody Job resources){
+    public ResponseEntity<Object> updateJob(@Validated(Job.Update.class) @RequestBody Job resources) {
         jobService.update(resources);
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(), HttpStatus.NO_CONTENT);
     }
 
     @Log("删除岗位")
     @ApiOperation("删除岗位")
     @DeleteMapping
     @PreAuthorize("@el.check('job:del')")
-    public ResponseEntity<Object> deleteJob(@RequestBody Set<Long> ids){
+    public ResponseEntity<Object> deleteJob(@RequestBody Set<Long> ids) {
         // 验证是否被用户关联
         jobService.verification(ids);
         jobService.delete(ids);
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 }
diff --git a/oying-system/src/main/java/com/oying/modules/system/rest/MenuController.java b/oying-system/src/main/java/com/oying/modules/system/rest/MenuController.java
index 3ee9b2a..09ee649 100644
--- a/oying-system/src/main/java/com/oying/modules/system/rest/MenuController.java
+++ b/oying-system/src/main/java/com/oying/modules/system/rest/MenuController.java
@@ -4,6 +4,7 @@
 import com.oying.modules.system.domain.Menu;
 import com.oying.modules.system.domain.dto.MenuQueryCriteria;
 import com.oying.modules.system.domain.dto.MenuVo;
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -18,6 +19,7 @@
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+
 import javax.servlet.http.HttpServletResponse;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -44,50 +46,50 @@
 
     @GetMapping(value = "/build")
     @ApiOperation("获取前端所需菜单")
-    public ResponseEntity<List<MenuVo>> buildMenus(){
+    public ResponseEntity<Object> buildMenus() {
         List<Menu> menuList = menuService.findByUser(SecurityUtils.getCurrentUserId());
         List<Menu> menus = menuService.buildTree(menuList);
-        return new ResponseEntity<>(menuService.buildMenus(menus),HttpStatus.OK);
+        return new ResponseEntity<>(R.success(menuService.buildMenus(menus)), HttpStatus.OK);
     }
 
     @ApiOperation("返回全部的菜单")
     @GetMapping(value = "/lazy")
     @PreAuthorize("@el.check('menu:list','roles:list')")
-    public ResponseEntity<List<Menu>> queryAllMenu(@RequestParam Long pid){
-        return new ResponseEntity<>(menuService.getMenus(pid),HttpStatus.OK);
+    public ResponseEntity<Object> queryAllMenu(@RequestParam Long pid) {
+        return new ResponseEntity<>(R.success(menuService.getMenus(pid)), HttpStatus.OK);
     }
 
     @ApiOperation("根据菜单ID返回所有子节点ID,包含自身ID")
     @GetMapping(value = "/child")
     @PreAuthorize("@el.check('menu:list','roles:list')")
-    public ResponseEntity<Object> childMenu(@RequestParam Long id){
+    public ResponseEntity<Object> childMenu(@RequestParam Long id) {
         Set<Menu> menuSet = new HashSet<>();
         List<Menu> menuList = menuService.getMenus(id);
         menuSet.add(menuService.getById(id));
         menuSet = menuService.getChildMenus(menuList, menuSet);
         Set<Long> ids = menuSet.stream().map(Menu::getId).collect(Collectors.toSet());
-        return new ResponseEntity<>(ids,HttpStatus.OK);
+        return new ResponseEntity<>(R.success(ids), HttpStatus.OK);
     }
 
     @GetMapping
     @ApiOperation("查询菜单")
     @PreAuthorize("@el.check('menu:list')")
-    public ResponseEntity<PageResult<Menu>> queryMenu(MenuQueryCriteria criteria) throws Exception {
+    public ResponseEntity<Object> queryMenu(MenuQueryCriteria criteria) throws Exception {
         List<Menu> menuList = menuService.queryAll(criteria, true);
-        return new ResponseEntity<>(PageUtil.toPage(menuList),HttpStatus.OK);
+        return new ResponseEntity<>(R.success(PageUtil.toPage(menuList)), HttpStatus.OK);
     }
 
     @ApiOperation("查询菜单:根据ID获取同级与上级数据")
     @PostMapping("/superior")
     @PreAuthorize("@el.check('menu:list')")
-    public ResponseEntity<List<Menu>> getMenuSuperior(@RequestBody List<Long> ids) {
+    public ResponseEntity<Object> getMenuSuperior(@RequestBody List<Long> ids) {
         Set<Menu> menus = new LinkedHashSet<>();
-        if(CollectionUtil.isNotEmpty(ids)){
+        if (CollectionUtil.isNotEmpty(ids)) {
             for (Long id : ids) {
                 Menu menu = menuService.findById(id);
                 List<Menu> menuList = menuService.getSuperior(menu, new ArrayList<>());
                 for (Menu data : menuList) {
-                    if(data.getId().equals(menu.getPid())) {
+                    if (data.getId().equals(menu.getPid())) {
                         data.setSubCount(data.getSubCount() - 1);
                     }
                 }
@@ -95,37 +97,37 @@
             }
             // 编辑菜单时不显示自己以及自己下级的数据,避免出现PID数据环形问题
             menus = menus.stream().filter(i -> !ids.contains(i.getId())).collect(Collectors.toSet());
-            return new ResponseEntity<>(menuService.buildTree(new ArrayList<>(menus)),HttpStatus.OK);
+            return new ResponseEntity<>(R.success(menuService.buildTree(new ArrayList<>(menus))), HttpStatus.OK);
         }
-        return new ResponseEntity<>(menuService.getMenus(null),HttpStatus.OK);
+        return new ResponseEntity<>(R.success(menuService.getMenus(null)), HttpStatus.OK);
     }
 
     @Log("新增菜单")
     @ApiOperation("新增菜单")
     @PostMapping
     @PreAuthorize("@el.check('menu:add')")
-    public ResponseEntity<Object> createMenu(@Validated @RequestBody Menu resources){
+    public ResponseEntity<Object> createMenu(@Validated @RequestBody Menu resources) {
         if (resources.getId() != null) {
-            throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
+            throw new BadRequestException("A new " + ENTITY_NAME + " cannot already have an ID");
         }
         menuService.create(resources);
-        return new ResponseEntity<>(HttpStatus.CREATED);
+        return new ResponseEntity<>(R.success(), HttpStatus.CREATED);
     }
 
     @Log("修改菜单")
     @ApiOperation("修改菜单")
     @PutMapping
     @PreAuthorize("@el.check('menu:edit')")
-    public ResponseEntity<Object> updateMenu(@Validated(Menu.Update.class) @RequestBody Menu resources){
+    public ResponseEntity<Object> updateMenu(@Validated(Menu.Update.class) @RequestBody Menu resources) {
         menuService.update(resources);
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(), HttpStatus.NO_CONTENT);
     }
 
     @Log("删除菜单")
     @ApiOperation("删除菜单")
     @DeleteMapping
     @PreAuthorize("@el.check('menu:del')")
-    public ResponseEntity<Object> deleteMenu(@RequestBody Set<Long> ids){
+    public ResponseEntity<Object> deleteMenu(@RequestBody Set<Long> ids) {
         Set<Menu> menuSet = new HashSet<>();
         for (Long id : ids) {
             List<Menu> menuList = menuService.getMenus(id);
@@ -133,6 +135,6 @@
             menuSet = menuService.getChildMenus(menuList, menuSet);
         }
         menuService.delete(menuSet);
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 }
diff --git a/oying-system/src/main/java/com/oying/modules/system/rest/MerchantsController.java b/oying-system/src/main/java/com/oying/modules/system/rest/MerchantsController.java
new file mode 100644
index 0000000..6339318
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/system/rest/MerchantsController.java
@@ -0,0 +1,74 @@
+package com.oying.modules.system.rest;
+
+import com.oying.annotation.Log;
+import com.oying.modules.system.domain.Merchants;
+import com.oying.modules.system.service.MerchantsService;
+import com.oying.modules.system.domain.dto.MerchantsQueryCriteria;
+import com.oying.utils.R;
+import lombok.RequiredArgsConstructor;
+import java.util.List;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import io.swagger.annotations.*;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.oying.utils.PageResult;
+
+/**
+* @author lixin
+* @date 2025-05-29
+**/
+@RestController
+@RequiredArgsConstructor
+@Api(tags = "系统:商户信息")
+@RequestMapping("/api/merchants")
+public class MerchantsController {
+
+    private final MerchantsService merchantsService;
+
+    @ApiOperation("导出数据")
+    @GetMapping(value = "/download")
+    @PreAuthorize("@el.check('merchants:list')")
+    public void exportMerchants(HttpServletResponse response, MerchantsQueryCriteria criteria) throws IOException {
+        merchantsService.download(merchantsService.queryAll(criteria), response);
+    }
+
+    @GetMapping
+    @ApiOperation("查询商户信息")
+    @PreAuthorize("@el.check('merchants:list')")
+    public ResponseEntity<Object> queryMerchants(MerchantsQueryCriteria criteria){
+        Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
+        return new ResponseEntity<>(R.success(merchantsService.queryAll(criteria,page)),HttpStatus.OK);
+    }
+
+    @PostMapping
+    @Log("新增商户信息")
+    @ApiOperation("新增商户信息")
+    @PreAuthorize("@el.check('merchants:add')")
+    public ResponseEntity<Object> createMerchants(@Validated @RequestBody Merchants resources){
+        merchantsService.create(resources);
+        return new ResponseEntity<>(R.success(),HttpStatus.CREATED);
+    }
+
+    @PutMapping
+    @Log("修改商户信息")
+    @ApiOperation("修改商户信息")
+    @PreAuthorize("@el.check('merchants:edit')")
+    public ResponseEntity<Object> updateMerchants(@Validated @RequestBody Merchants resources){
+        merchantsService.update(resources);
+        return new ResponseEntity<>(R.success(),HttpStatus.NO_CONTENT);
+    }
+
+    @DeleteMapping
+    @Log("删除商户信息")
+    @ApiOperation("删除商户信息")
+    @PreAuthorize("@el.check('merchants:del')")
+    public ResponseEntity<Object> deleteMerchants(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
+        merchantsService.deleteAll(ids);
+        return new ResponseEntity<>(R.success(),HttpStatus.OK);
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/system/rest/MonitorController.java b/oying-system/src/main/java/com/oying/modules/system/rest/MonitorController.java
index 27eaf86..f780bc1 100644
--- a/oying-system/src/main/java/com/oying/modules/system/rest/MonitorController.java
+++ b/oying-system/src/main/java/com/oying/modules/system/rest/MonitorController.java
@@ -1,5 +1,6 @@
 package com.oying.modules.system.rest;
 
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -25,6 +26,6 @@
     @ApiOperation("查询服务监控")
     @PreAuthorize("@el.check('monitor:list')")
     public ResponseEntity<Object> queryMonitor(){
-        return new ResponseEntity<>(serverService.getServers(),HttpStatus.OK);
+        return new ResponseEntity<>(R.success(serverService.getServers()),HttpStatus.OK);
     }
 }
diff --git a/oying-system/src/main/java/com/oying/modules/system/rest/RoleController.java b/oying-system/src/main/java/com/oying/modules/system/rest/RoleController.java
index fd62232..c002f31 100644
--- a/oying-system/src/main/java/com/oying/modules/system/rest/RoleController.java
+++ b/oying-system/src/main/java/com/oying/modules/system/rest/RoleController.java
@@ -3,6 +3,7 @@
 import cn.hutool.core.lang.Dict;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.oying.modules.system.domain.Role;
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -17,6 +18,7 @@
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.Collections;
@@ -41,8 +43,8 @@
     @ApiOperation("获取单个role")
     @GetMapping(value = "/{id}")
     @PreAuthorize("@el.check('roles:list')")
-    public ResponseEntity<Role> findRoleById(@PathVariable Long id){
-        return new ResponseEntity<>(roleService.findById(id), HttpStatus.OK);
+    public ResponseEntity<Object> findRoleById(@PathVariable Long id) {
+        return new ResponseEntity<>(R.success(roleService.findById(id)), HttpStatus.OK);
     }
 
     @ApiOperation("导出角色数据")
@@ -55,63 +57,63 @@
     @ApiOperation("返回全部的角色")
     @GetMapping(value = "/all")
     @PreAuthorize("@el.check('roles:list','user:add','user:edit')")
-    public ResponseEntity<List<Role>> queryAllRole(){
-        return new ResponseEntity<>(roleService.queryAll(),HttpStatus.OK);
+    public ResponseEntity<Object> queryAllRole() {
+        return new ResponseEntity<>(R.success(roleService.queryAll()), HttpStatus.OK);
     }
 
     @ApiOperation("查询角色")
     @GetMapping
     @PreAuthorize("@el.check('roles:list')")
-    public ResponseEntity<PageResult<Role>> queryRole(RoleQueryCriteria criteria){
+    public ResponseEntity<Object> queryRole(RoleQueryCriteria criteria) {
         Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
-        return new ResponseEntity<>(roleService.queryAll(criteria, page),HttpStatus.OK);
+        return new ResponseEntity<>(R.success(roleService.queryAll(criteria, page)), HttpStatus.OK);
     }
 
     @ApiOperation("获取用户级别")
     @GetMapping(value = "/level")
-    public ResponseEntity<Object> getRoleLevel(){
-        return new ResponseEntity<>(Dict.create().set("level", getLevels(null)),HttpStatus.OK);
+    public ResponseEntity<Object> getRoleLevel() {
+        return new ResponseEntity<>(R.success(Dict.create().set("level", getLevels(null))), HttpStatus.OK);
     }
 
     @Log("新增角色")
     @ApiOperation("新增角色")
     @PostMapping
     @PreAuthorize("@el.check('roles:add')")
-    public ResponseEntity<Object> createRole(@Validated @RequestBody Role resources){
+    public ResponseEntity<Object> createRole(@Validated @RequestBody Role resources) {
         if (resources.getId() != null) {
-            throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
+            throw new BadRequestException("A new " + ENTITY_NAME + " cannot already have an ID");
         }
         getLevels(resources.getLevel());
         roleService.create(resources);
-        return new ResponseEntity<>(HttpStatus.CREATED);
+        return new ResponseEntity<>(R.success(), HttpStatus.CREATED);
     }
 
     @Log("修改角色")
     @ApiOperation("修改角色")
     @PutMapping
     @PreAuthorize("@el.check('roles:edit')")
-    public ResponseEntity<Object> updateRole(@Validated(Role.Update.class) @RequestBody Role resources){
+    public ResponseEntity<Object> updateRole(@Validated(Role.Update.class) @RequestBody Role resources) {
         getLevels(resources.getLevel());
         roleService.update(resources);
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(), HttpStatus.NO_CONTENT);
     }
 
     @Log("修改角色菜单")
     @ApiOperation("修改角色菜单")
     @PutMapping(value = "/menu")
     @PreAuthorize("@el.check('roles:edit')")
-    public ResponseEntity<Object> updateRoleMenu(@RequestBody Role resources){
+    public ResponseEntity<Object> updateRoleMenu(@RequestBody Role resources) {
         Role role = roleService.getById(resources.getId());
         getLevels(role.getLevel());
         roleService.updateMenu(resources);
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(), HttpStatus.NO_CONTENT);
     }
 
     @Log("删除角色")
     @ApiOperation("删除角色")
     @DeleteMapping
     @PreAuthorize("@el.check('roles:del')")
-    public ResponseEntity<Object> deleteRole(@RequestBody Set<Long> ids){
+    public ResponseEntity<Object> deleteRole(@RequestBody Set<Long> ids) {
         for (Long id : ids) {
             Role role = roleService.getById(id);
             getLevels(role.getLevel());
@@ -119,18 +121,19 @@
         // 验证是否被用户关联
         roleService.verification(ids);
         roleService.delete(ids);
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 
     /**
      * 获取用户的角色级别
+     *
      * @return /
      */
-    private int getLevels(Integer level){
+    private int getLevels(Integer level) {
         List<Integer> levels = roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(Role::getLevel).collect(Collectors.toList());
         int min = Collections.min(levels);
-        if(level != null){
-            if(level < min){
+        if (level != null) {
+            if (level < min) {
                 throw new BadRequestException("权限不足,你的角色级别:" + min + ",低于操作的角色级别:" + level);
             }
         }
diff --git a/oying-system/src/main/java/com/oying/modules/system/rest/UserController.java b/oying-system/src/main/java/com/oying/modules/system/rest/UserController.java
index a1ce620..29c06fe 100644
--- a/oying-system/src/main/java/com/oying/modules/system/rest/UserController.java
+++ b/oying-system/src/main/java/com/oying/modules/system/rest/UserController.java
@@ -6,13 +6,10 @@
 import com.oying.modules.system.domain.Role;
 import com.oying.modules.system.domain.User;
 import com.oying.modules.system.domain.dto.UserPassVo;
+import com.oying.utils.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
-import com.oying.utils.PageResult;
-import com.oying.utils.PageUtil;
-import com.oying.utils.RsaUtils;
-import com.oying.utils.SecurityUtils;
 import com.oying.annotation.Log;
 import com.oying.config.properties.RsaProperties;
 import com.oying.modules.system.service.DataService;
@@ -32,6 +29,7 @@
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
+
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.*;
@@ -64,7 +62,7 @@
     @ApiOperation("查询用户")
     @GetMapping
     @PreAuthorize("@el.check('user:list')")
-    public ResponseEntity<PageResult<User>> queryUser(UserQueryCriteria criteria){
+    public ResponseEntity<Object> queryUser(UserQueryCriteria criteria) {
         Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
         if (!ObjectUtils.isEmpty(criteria.getDeptId())) {
             criteria.getDeptIds().add(criteria.getDeptId());
@@ -76,30 +74,30 @@
         // 数据权限
         List<Long> dataScopes = dataService.getDeptIds(userService.findByName(SecurityUtils.getCurrentUsername()));
         // criteria.getDeptIds() 不为空并且数据权限不为空则取交集
-        if (!CollectionUtils.isEmpty(criteria.getDeptIds()) && !CollectionUtils.isEmpty(dataScopes)){
+        if (!CollectionUtils.isEmpty(criteria.getDeptIds()) && !CollectionUtils.isEmpty(dataScopes)) {
             // 取交集
             criteria.getDeptIds().retainAll(dataScopes);
-            if(!CollectionUtil.isEmpty(criteria.getDeptIds())){
-                return new ResponseEntity<>(userService.queryAll(criteria,page),HttpStatus.OK);
+            if (!CollectionUtil.isEmpty(criteria.getDeptIds())) {
+                return new ResponseEntity<>(R.success(userService.queryAll(criteria, page)), HttpStatus.OK);
             }
         } else {
             // 否则取并集
             criteria.getDeptIds().addAll(dataScopes);
-            return new ResponseEntity<>(userService.queryAll(criteria,page),HttpStatus.OK);
+            return new ResponseEntity<>(R.success(userService.queryAll(criteria, page)), HttpStatus.OK);
         }
-        return new ResponseEntity<>(PageUtil.noData(),HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 
     @Log("新增用户")
     @ApiOperation("新增用户")
     @PostMapping
     @PreAuthorize("@el.check('user:add')")
-    public ResponseEntity<Object> createUser(@Validated @RequestBody User resources){
+    public ResponseEntity<Object> createUser(@Validated @RequestBody User resources) {
         checkLevel(resources);
         // 默认密码 123456
         resources.setPassword(passwordEncoder.encode("123456"));
         userService.create(resources);
-        return new ResponseEntity<>(HttpStatus.CREATED);
+        return new ResponseEntity<>(R.success(),HttpStatus.CREATED);
     }
 
     @Log("修改用户")
@@ -109,50 +107,50 @@
     public ResponseEntity<Object> updateUser(@Validated(User.Update.class) @RequestBody User resources) throws Exception {
         checkLevel(resources);
         userService.update(resources);
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(),HttpStatus.NO_CONTENT);
     }
 
     @Log("修改用户:个人中心")
     @ApiOperation("修改用户:个人中心")
     @PutMapping(value = "center")
-    public ResponseEntity<Object> centerUser(@Validated(User.Update.class) @RequestBody User resources){
-        if(!resources.getId().equals(SecurityUtils.getCurrentUserId())){
+    public ResponseEntity<Object> centerUser(@Validated(User.Update.class) @RequestBody User resources) {
+        if (!resources.getId().equals(SecurityUtils.getCurrentUserId())) {
             throw new BadRequestException("不能修改他人资料");
         }
         userService.updateCenter(resources);
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(),HttpStatus.NO_CONTENT);
     }
 
     @Log("删除用户")
     @ApiOperation("删除用户")
     @DeleteMapping
     @PreAuthorize("@el.check('user:del')")
-    public ResponseEntity<Object> deleteUser(@RequestBody Set<Long> ids){
+    public ResponseEntity<Object> deleteUser(@RequestBody Set<Long> ids) {
         for (Long id : ids) {
-            Integer currentLevel =  Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(Role::getLevel).collect(Collectors.toList()));
-            Integer optLevel =  Collections.min(roleService.findByUsersId(id).stream().map(Role::getLevel).collect(Collectors.toList()));
+            Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(Role::getLevel).collect(Collectors.toList()));
+            Integer optLevel = Collections.min(roleService.findByUsersId(id).stream().map(Role::getLevel).collect(Collectors.toList()));
             if (currentLevel > optLevel) {
                 throw new BadRequestException("角色权限不足,不能删除:" + userService.findById(id).getUsername());
             }
         }
         userService.delete(ids);
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(),HttpStatus.OK);
     }
 
     @ApiOperation("修改密码")
     @PostMapping(value = "/updatePass")
     public ResponseEntity<Object> updateUserPass(@RequestBody UserPassVo passVo) throws Exception {
-        String oldPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,passVo.getOldPass());
-        String newPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,passVo.getNewPass());
+        String oldPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, passVo.getOldPass());
+        String newPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, passVo.getNewPass());
         User user = userService.findByName(SecurityUtils.getCurrentUsername());
-        if(!passwordEncoder.matches(oldPass, user.getPassword())){
+        if (!passwordEncoder.matches(oldPass, user.getPassword())) {
             throw new BadRequestException("修改失败,旧密码错误");
         }
-        if(passwordEncoder.matches(newPass, user.getPassword())){
+        if (passwordEncoder.matches(newPass, user.getPassword())) {
             throw new BadRequestException("新密码不能与旧密码相同");
         }
-        userService.updatePass(user.getUsername(),passwordEncoder.encode(newPass));
-        return new ResponseEntity<>(HttpStatus.OK);
+        userService.updatePass(user.getUsername(), passwordEncoder.encode(newPass));
+        return new ResponseEntity<>(R.success(),HttpStatus.OK);
     }
 
     @ApiOperation("重置密码")
@@ -160,35 +158,36 @@
     public ResponseEntity<Object> resetPwd(@RequestBody Set<Long> ids) {
         String pwd = passwordEncoder.encode("123456");
         userService.resetPwd(ids, pwd);
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(),HttpStatus.OK);
     }
 
     @ApiOperation("修改头像")
     @PostMapping(value = "/updateAvatar")
-    public ResponseEntity<Object> updateUserAvatar(@RequestParam MultipartFile avatar){
-        return new ResponseEntity<>(userService.updateAvatar(avatar), HttpStatus.OK);
+    public ResponseEntity<Object> updateUserAvatar(@RequestParam MultipartFile avatar) {
+        return new ResponseEntity<>(R.success(userService.updateAvatar(avatar)), HttpStatus.OK);
     }
 
     @Log("修改邮箱")
     @ApiOperation("修改邮箱")
     @PostMapping(value = "/updateEmail/{code}")
     public ResponseEntity<Object> updateUserEmail(@PathVariable String code, @RequestBody User resources) throws Exception {
-        String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,resources.getPassword());
+        String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, resources.getPassword());
         User user = userService.findByName(SecurityUtils.getCurrentUsername());
-        if(!passwordEncoder.matches(password, user.getPassword())){
+        if (!passwordEncoder.matches(password, user.getPassword())) {
             throw new BadRequestException("密码错误");
         }
         verificationCodeService.validated(CodeEnum.EMAIL_RESET_EMAIL_CODE.getKey() + resources.getEmail(), code);
-        userService.updateEmail(user.getUsername(),resources.getEmail());
-        return new ResponseEntity<>(HttpStatus.OK);
+        userService.updateEmail(user.getUsername(), resources.getEmail());
+        return new ResponseEntity<>(R.success(),HttpStatus.OK);
     }
 
     /**
      * 如果当前用户的角色级别低于创建用户的角色级别,则抛出权限不足的错误
+     *
      * @param resources /
      */
     private void checkLevel(User resources) {
-        Integer currentLevel =  Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(Role::getLevel).collect(Collectors.toList()));
+        Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(Role::getLevel).collect(Collectors.toList()));
         Integer optLevel = roleService.findByRoles(resources.getRoles());
         if (currentLevel > optLevel) {
             throw new BadRequestException("角色权限不足");
diff --git a/oying-system/src/main/java/com/oying/modules/system/rest/VerifyController.java b/oying-system/src/main/java/com/oying/modules/system/rest/VerifyController.java
index ca1b4e9..8eb4df8 100644
--- a/oying-system/src/main/java/com/oying/modules/system/rest/VerifyController.java
+++ b/oying-system/src/main/java/com/oying/modules/system/rest/VerifyController.java
@@ -1,5 +1,6 @@
 package com.oying.modules.system.rest;
 
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -31,7 +32,7 @@
     public ResponseEntity<Object> resetEmail(@RequestParam String email){
         EmailDto emailDto = verificationCodeService.sendEmail(email, CodeEnum.EMAIL_RESET_EMAIL_CODE.getKey());
         emailService.send(emailDto,emailService.find());
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(),HttpStatus.OK);
     }
 
     @PostMapping(value = "/email/resetPass")
@@ -39,7 +40,7 @@
     public ResponseEntity<Object> resetPass(@RequestParam String email){
         EmailDto emailDto = verificationCodeService.sendEmail(email, CodeEnum.EMAIL_RESET_PWD_CODE.getKey());
         emailService.send(emailDto,emailService.find());
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(),HttpStatus.OK);
     }
 
     @GetMapping(value = "/validated")
@@ -56,6 +57,6 @@
             default:
                 break;
         }
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(),HttpStatus.OK);
     }
 }
diff --git a/oying-system/src/main/java/com/oying/modules/system/service/MerchantsService.java b/oying-system/src/main/java/com/oying/modules/system/service/MerchantsService.java
new file mode 100644
index 0000000..c822ba9
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/system/service/MerchantsService.java
@@ -0,0 +1,59 @@
+package com.oying.modules.system.service;
+
+import com.oying.modules.system.domain.Merchants;
+import com.oying.modules.system.domain.dto.MerchantsQueryCriteria;
+import java.util.List;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.oying.utils.PageResult;
+
+/**
+* @description 服务接口
+* @author lixin
+* @date 2025-05-29
+**/
+public interface MerchantsService extends IService<Merchants> {
+
+    /**
+    * 查询数据分页
+    * @param criteria 条件
+    * @param page 分页参数
+    * @return PageResult
+    */
+    PageResult<Merchants> queryAll(MerchantsQueryCriteria criteria, Page<Object> page);
+
+    /**
+    * 查询所有数据不分页
+    * @param criteria 条件参数
+    * @return List<MerchantsDto>
+    */
+    List<Merchants> queryAll(MerchantsQueryCriteria criteria);
+
+    /**
+    * 创建
+    * @param resources /
+    */
+    void create(Merchants resources);
+
+    /**
+    * 编辑
+    * @param resources /
+    */
+    void update(Merchants resources);
+
+    /**
+    * 多选删除
+    * @param ids /
+    */
+    void deleteAll(List<Long> ids);
+
+    /**
+    * 导出数据
+    * @param all 待导出的数据
+    * @param response /
+    * @throws IOException /
+    */
+    void download(List<Merchants> all, HttpServletResponse response) throws IOException;
+}
diff --git a/oying-system/src/main/java/com/oying/modules/system/service/impl/MerchantsServiceImpl.java b/oying-system/src/main/java/com/oying/modules/system/service/impl/MerchantsServiceImpl.java
new file mode 100644
index 0000000..ca6c22c
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/system/service/impl/MerchantsServiceImpl.java
@@ -0,0 +1,86 @@
+package com.oying.modules.system.service.impl;
+
+import com.oying.modules.system.domain.Merchants;
+import com.oying.utils.FileUtil;
+import lombok.RequiredArgsConstructor;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.oying.modules.system.service.MerchantsService;
+import com.oying.modules.system.domain.dto.MerchantsQueryCriteria;
+import com.oying.modules.system.mapper.MerchantsMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.oying.utils.PageUtil;
+import java.util.List;
+import java.util.Map;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import com.oying.utils.PageResult;
+
+/**
+* @description 服务实现
+* @author lixin
+* @date 2025-05-29
+**/
+@Service
+@RequiredArgsConstructor
+public class MerchantsServiceImpl extends ServiceImpl<MerchantsMapper, Merchants> implements MerchantsService {
+
+    private final MerchantsMapper merchantsMapper;
+
+    @Override
+    public PageResult<Merchants> queryAll(MerchantsQueryCriteria criteria, Page<Object> page){
+        return PageUtil.toPage(merchantsMapper.findAll(criteria, page));
+    }
+
+    @Override
+    public List<Merchants> queryAll(MerchantsQueryCriteria criteria){
+        return merchantsMapper.findAll(criteria);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void create(Merchants resources) {
+        merchantsMapper.insert(resources);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void update(Merchants resources) {
+        Merchants merchants = getById(resources.getMerchantsId());
+        merchants.copy(resources);
+        merchantsMapper.updateById(merchants);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteAll(List<Long> ids) {
+        merchantsMapper.deleteBatchIds(ids);
+    }
+
+    @Override
+    public void download(List<Merchants> all, HttpServletResponse response) throws IOException {
+        List<Map<String, Object>> list = new ArrayList<>();
+        for (Merchants merchants : all) {
+            Map<String, Object> map = new LinkedHashMap<>();
+            map.put("名称", merchants.getMerchantName());
+            map.put("商户编码", merchants.getMerchantCode());
+            map.put("营业执照号", merchants.getBusinessLicense());
+            map.put("营业执照号路径", merchants.getBusinessLicensePath());
+            map.put("联系手机", merchants.getContactMobile());
+            map.put("排序", merchants.getMerchantsSort());
+            map.put("状态", merchants.getEnabled());
+            map.put("审核人", merchants.getAuthUser());
+            map.put("审核时间", merchants.getAuthTime());
+            map.put("审核信息", merchants.getAuthMessage());
+            map.put("创建者", merchants.getCreateBy());
+            map.put("更新者", merchants.getUpdateBy());
+            map.put("创建日期", merchants.getCreateTime());
+            map.put("更新时间", merchants.getUpdateTime());
+            list.add(map);
+        }
+        FileUtil.downloadExcel(list, response);
+    }
+}
diff --git a/oying-system/src/main/resources/config/application-dev.yml b/oying-system/src/main/resources/config/application-dev.yml
index 1880cf2..3ea16c0 100644
--- a/oying-system/src/main/resources/config/application-dev.yml
+++ b/oying-system/src/main/resources/config/application-dev.yml
@@ -111,8 +111,62 @@
     path: /opt/oying/file/
     avatar: /opt/oying/avatar/
   windows:
-    path: C:\oying\file\
-    avatar: C:\oying\avatar\
+    path: d:\data\oying\file\
+    avatar: d:\data\oying\avatar\
   # 文件大小 /M
   maxSize: 100
   avatarMaxSize: 5
+
+  # 短信验证码key 时间
+sms:
+  key: oying-sms-key-
+  time: 300
+
+#微信配置
+wx:
+  # 测试环境
+  enabled: false
+  # AppID
+  app-id: wx2273296a5569cbad
+  # AppSecret
+  app-secret: 4526d72d885be322b17d0694cd6d03f1
+  # 跳转小程序类型 developer为开发版;trial为体验版;formal为正式版;默认为正式版
+  mini-program-state: trial
+  #  access_token的KEY
+  token-key: wx_access_token
+  #  access_token的失效时间间隔,微信是2小时,此处隔7200秒就重新获取
+  token-time: 7200
+  # 微信URL调用
+  #  POST 获取稳定版接口调用凭据 获取小程序全局唯一后台接口调用凭据,token有效期为7200s,开发者需要进行妥善保存。
+  get-stable-access-token: https://api.weixin.qq.com/cgi-bin/stable_token
+  #  GET 小程序登录 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程
+  code2-session: https://api.weixin.qq.com/sns/jscode2session?appid={appid}&secret={secret}&js_code={js_code}&grant_type=authorization_code
+  #  POST 获取手机号 该接口用于将code换取用户手机号。 说明,每个code只能使用一次,code的有效期为5min。
+  get-phone-number: https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={accessToken}
+  #  POST 该接口用于发送订阅消息。
+  send-message: https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={accessToken}
+
+# 汇旺财
+swift-pass:
+  # 密钥
+  key: qqqqqqqqqqqqqqqqqqqq
+  # 私钥
+  mch-private-key: qqqqqqqqqqqq
+  # 公钥
+  plat-public-key: qqqqq
+  # 门店编号
+  mch-id: 1111
+  # 签名方式
+  sign-type: MD5
+  # 原生JS
+  is-raw: 1
+  # 是否小程序支付
+  is-minipg: 1
+  # AppID
+  app-id: wx2273296a5569cbad
+  # 请求url
+  req-url: https://pay.hstypay.com/v2/pay/gateway
+  # 支付通知地址
+  notify-url: https://localhost/oying/api/swiftPass/alipayCallback
+  # 退款通知地址
+  refund-url: https://localhost/oying/api/swiftPass/returnNotify
diff --git a/oying-system/src/main/resources/config/application-prod.yml b/oying-system/src/main/resources/config/application-prod.yml
index f3cc9c8..cefa2d9 100644
--- a/oying-system/src/main/resources/config/application-prod.yml
+++ b/oying-system/src/main/resources/config/application-prod.yml
@@ -127,3 +127,56 @@
   # 文件大小 /M
   maxSize: 100
   avatarMaxSize: 5
+  # 短信验证码key 时间
+sms:
+  key: oying-sms-key-
+  time: 300
+
+#微信配置
+wx:
+  # 测试环境
+  enabled: false
+  # AppID
+  app-id: wx2273296a5569cbad
+  # AppSecret
+  app-secret: 4526d72d885be322b17d0694cd6d03f1
+  # 跳转小程序类型 developer为开发版;trial为体验版;formal为正式版;默认为正式版
+  mini-program-state: trial
+  #  access_token的KEY
+  token-key: wx_access_token
+  #  access_token的失效时间间隔,微信是2小时,此处隔7200秒就重新获取
+  token-time: 7200
+  # 微信URL调用
+  #  POST 获取稳定版接口调用凭据 获取小程序全局唯一后台接口调用凭据,token有效期为7200s,开发者需要进行妥善保存。
+  get-stable-access-token: https://api.weixin.qq.com/cgi-bin/stable_token
+  #  GET 小程序登录 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程
+  code2-session: https://api.weixin.qq.com/sns/jscode2session?appid={appid}&secret={secret}&js_code={js_code}&grant_type=authorization_code
+  #  POST 获取手机号 该接口用于将code换取用户手机号。 说明,每个code只能使用一次,code的有效期为5min。
+  get-phone-number: https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={accessToken}
+  #  POST 该接口用于发送订阅消息。
+  send-message: https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={accessToken}
+
+# 汇旺财
+swift-pass:
+  # 密钥1
+  key: qqqqqqqqqqqqqqqqqqqq
+  # 私钥
+  mch-private-key: qqqqqqqqqqqq
+  # 公钥
+  plat-public-key: qqqqq
+  # 门店编号1
+  mch-id: 1111
+  # 签名方式
+  sign-type: MD5
+  # 原生JS
+  is-raw: 1
+  # 是否小程序支付
+  is-minipg: 1
+  # AppID
+  app-id: wx2273296a5569cbad
+  # 请求url
+  req-url: https://pay.hstypay.com/v2/pay/gateway
+  # 支付通知地址
+  notify-url: https://localhost/oying/api/swiftPass/alipayCallback
+  # 退款通知地址
+  refund-url: https://localhost/oying/api/swiftPass/returnNotify
diff --git a/oying-system/src/main/resources/config/application.yml b/oying-system/src/main/resources/config/application.yml
index d139423..b916632 100644
--- a/oying-system/src/main/resources/config/application.yml
+++ b/oying-system/src/main/resources/config/application.yml
@@ -33,10 +33,10 @@
 
   redis:
     #数据库索引
-    database: ${REDIS_DB:1}
-    host: ${REDIS_HOST:127.0.0.1}
-    port: ${REDIS_PORT:6379}
-    password: ${REDIS_PWD:}
+    database: 0
+    host: 127.0.0.1
+    port: 6379
+    password:
     #连接超时时间
     timeout: 5000
     # 连接池配置
diff --git a/oying-system/src/main/resources/mapper/pc/category/PlatformCategoryMapper.xml b/oying-system/src/main/resources/mapper/pc/category/PlatformCategoryMapper.xml
new file mode 100644
index 0000000..be265d3
--- /dev/null
+++ b/oying-system/src/main/resources/mapper/pc/category/PlatformCategoryMapper.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.oying.modules.pc.category.mapper.PlatformCategoryMapper">
+    <resultMap id="BaseResultMap" type="com.oying.modules.pc.category.domain.PlatformCategory">
+        <id column="category_id" property="categoryId"/>
+        <result column="parent_id" property="parentId"/>
+        <result column="name" property="name"/>
+        <result column="level" property="level"/>
+        <result column="sort_weight" property="sortWeight"/>
+        <result column="icon_id" property="iconId"/>
+        <result column="status" property="status"/>
+        <result column="active" property="active"/>
+        <result column="create_by" property="createBy"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_by" property="updateBy"/>
+        <result column="update_time" property="updateTime"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        category_id, parent_id, name, level, sort_weight, icon_id, status, active, create_by, create_time, update_by, update_time
+    </sql>
+
+    <select id="findAll" resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from pc_platform_category
+        <where>
+            <if test="criteria.active != null">
+                and active = #{criteria.active}
+            </if>
+        </where>
+        order by category_id desc
+    </select>
+</mapper>
\ No newline at end of file
diff --git a/oying-system/src/main/resources/mapper/pc/product/ProductMapper.xml b/oying-system/src/main/resources/mapper/pc/product/ProductMapper.xml
new file mode 100644
index 0000000..43a18b8
--- /dev/null
+++ b/oying-system/src/main/resources/mapper/pc/product/ProductMapper.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.oying.modules.pc.product.mapper.ProductMapper">
+    <resultMap id="BaseResultMap" type="com.oying.modules.pc.product.domain.Product">
+        <id column="product_id" property="productId"/>
+        <result column="store_id" property="storeId"/>
+        <result column="code" property="code"/>
+        <result column="barcode" property="barcode"/>
+        <result column="name" property="name"/>
+        <result column="title" property="title"/>
+        <result column="category_id" property="categoryId"/>
+        <result column="second_category_id" property="secondCategoryId"/>
+        <result column="status" property="status"/>
+        <result column="main_image" property="mainImage"/>
+        <result column="detail_image" property="detailImage"/>
+        <result column="description" property="description"/>
+        <result column="price" property="price"/>
+        <result column="stock_quantity" property="stockQuantity"/>
+        <result column="min_purchase_quantity" property="minPurchaseQuantity"/>
+        <result column="warn_stock" property="warnStock"/>
+        <result column="weight" property="weight"/>
+        <result column="width" property="width"/>
+        <result column="length" property="length"/>
+        <result column="height" property="height"/>
+        <result column="deleted_flag" property="deletedFlag"/>
+        <result column="version" property="version"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        product_id, store_id, code, barcode, name, title, category_id, second_category_id, status, main_image, detail_image, description, price, stock_quantity, min_purchase_quantity, warn_stock, weight, width, length, height, deleted_flag, create_by, create_time, update_by, update_time, version
+    </sql>
+
+    <select id="findAll" resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from pc_product
+        <where>
+            <if test="criteria.storeId != null">
+                and store_id = #{criteria.storeId}
+            </if>
+            <if test="criteria.categoryId != null">
+                and category_id = #{criteria.categoryId}
+            </if>
+            <if test="criteria.secondCategoryId != null">
+                and second_category_id = #{criteria.secondCategoryId}
+            </if>
+            <if test="criteria.blurry != null and criteria.blurry != ''">
+                and (name like concat('%',#{criteria.blurry},'%') or title like concat('%',#{criteria.blurry},'%'))
+            </if>
+            <if test="criteria.status != null">
+                and status = #{criteria.status}
+            </if>
+            <if test="criteria.active != null">
+                and active = #{criteria.active}
+            </if>
+        </where>
+        order by product_id desc
+    </select>
+
+</mapper>
\ No newline at end of file
diff --git a/oying-system/src/main/resources/mapper/pc/search/SearchMapper.xml b/oying-system/src/main/resources/mapper/pc/search/SearchMapper.xml
new file mode 100644
index 0000000..3c8bb8d
--- /dev/null
+++ b/oying-system/src/main/resources/mapper/pc/search/SearchMapper.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.oying.modules.pc.store.mapper.StoreMapper">
+<!--
+    <resultMap id="storeWithProductResultMap" type="com.oying.modules.pc.store.domain.Store">
+        <result property="storeId" column="store_id"/>
+        <result property="merchantId" column="merchant_id"/>
+        <result property="platformCategoryId" column="platform_category_id"/>
+        <result property="storeName" column="store_name"/>
+        <result property="description" column="description"/>
+        <result property="deliveryFee" column="delivery_fee"/>
+        <result property="deliveryMinimum" column="delivery_minimum"/>
+        <result property="contactPhone" column="contact_phone"/>
+        <collection property="products" ofType="Product">
+            <id column="product_id" property="productId"/>
+            <result column="store_id" property="storeId"/>
+            <result column="title" property="title"/>
+            <result column="status" property="status"/>
+            <result column="description" property="description"/>
+            <result column="price" property="price"/>
+            <result column="stock_quantity" property="stockQuantity"/>
+            <result column="min_purchase_quantity" property="minPurchaseQuantity"/>
+            <result column="warn_stock" property="warnStock"/>
+            <result column="weight" property="weight"/>
+            <result column="version" property="version"/>
+        </collection>
+    </resultMap>
+
+    <select id="queryNearStoreWithProduct" resultMap="storeWithProductResultMap">
+        SELECT
+        s.store_id AS storeId,
+        s.store_name AS storeName,
+        s.logo_image_id AS logoImageId,
+        ST_Distance_Sphere(POINT(#{criteria.longitude}, #{criteria.latitude}), POINT(s.longitude, s.latitude)) AS distance,
+        MATCH(s.store_name) AGAINST(#{criteria.blurry}) AS storeNameMatchScore
+        FROM pc_store s inner join pc_product p ON s.store_id = p.product_id
+        WHERE
+        ST_Distance_Sphere(POINT(#{criteria.longitude}, #{criteria.latitude}), POINT(s.longitude, s.latitude)) &lt;= #{criteria.radius}
+        AND ST_Distance_Sphere(POINT(#{criteria.longitude}, #{criteria.latitude}), POINT(s.longitude, s.latitude)) &lt;= s.radius
+        AND s.status = 1000
+        AND p.status in (1000, 1001, 1002)
+        AND p.deleted_flag = 0
+        AND CURRENT_TIME() BETWEEN s.open_time AND s.close_time
+        <choose>
+            <when test="criteria.blurry != null and criteria.blurry != ''">
+                AND (MATCH(s.store_name) AGAINST(#{criteria.blurry} IN NATURAL LANGUAGE MODE) OR MATCH(p.title) AGAINST(#{criteria.blurry} IN NATURAL LANGUAGE MODE))
+            </when>
+            <otherwise>
+
+            </otherwise>
+        </choose>
+    </select>-->
+
+</mapper>
\ No newline at end of file
diff --git a/oying-system/src/main/resources/mapper/pc/store/StoreCategoryMapper.xml b/oying-system/src/main/resources/mapper/pc/store/StoreCategoryMapper.xml
new file mode 100644
index 0000000..f79f66c
--- /dev/null
+++ b/oying-system/src/main/resources/mapper/pc/store/StoreCategoryMapper.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.oying.modules.pc.store.mapper.StoreCategoryMapper">
+    <resultMap id="BaseResultMap" type="com.oying.modules.pc.store.domain.StoreCategory">
+        <id column="category_id" property="categoryId"/>
+        <result column="parent_id" property="parentId"/>
+        <result column="name" property="name"/>
+        <result column="level" property="level"/>
+        <result column="sort_weight" property="sortWeight"/>
+        <result column="icon_id" property="iconId"/>
+        <result column="status" property="status"/>
+        <result column="active" property="active"/>
+        <result column="create_by" property="createBy"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_by" property="updateBy"/>
+        <result column="update_time" property="updateTime"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        category_id, parent_id, name, level, sort_weight, icon_id, status, active, create_by, create_time, update_by, update_time
+    </sql>
+
+    <select id="findAll" resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from pc_store_category
+        <where>
+            <if test="criteria.storeId != null ">
+                and store_id = #{criteria.storeId}
+            </if>
+            <if test="criteria.level != null ">
+                and level = #{criteria.level}
+            </if>
+            <if test="criteria.active != null ">
+                and active = #{criteria.active}
+            </if>
+        </where>
+        order by category_id desc
+    </select>
+</mapper>
\ No newline at end of file
diff --git a/oying-system/src/main/resources/mapper/pc/store/StoreMapper.xml b/oying-system/src/main/resources/mapper/pc/store/StoreMapper.xml
new file mode 100644
index 0000000..564abeb
--- /dev/null
+++ b/oying-system/src/main/resources/mapper/pc/store/StoreMapper.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.oying.modules.pc.store.mapper.StoreMapper">
+
+    <resultMap id="StoreResult" type="com.oying.modules.pc.store.domain.Store">
+        <result property="storeId" column="store_id"/>
+        <result property="merchantId" column="merchant_id"/>
+        <result property="platformCategoryId" column="platform_category_id"/>
+        <result property="storeType" column="store_type"/>
+        <result property="storeCode" column="store_code"/>
+        <result property="storeName" column="store_name"/>
+        <result property="businessScope" column="business_scope"/>
+        <result property="status" column="status"/>
+        <result property="logoImageId" column="logo_image_id"/>
+        <result property="coverImageId" column="cover_image_id"/>
+        <result property="description" column="description"/>
+        <result property="tags" column="tags"/>
+        <result property="deliveryFee" column="delivery_fee"/>
+        <result property="deliveryMinimum" column="delivery_minimum"/>
+        <result property="contactPhone" column="contact_phone"/>
+        <result property="openTime" column="open_time"/>
+        <result property="closeTime" column="close_time"/>
+        <result property="address" column="address"/>
+        <result property="longitude" column="longitude"/>
+        <result property="latitude" column="latitude"/>
+        <result property="geoHash" column="geo_hash"/>
+        <result property="coordinateSystem" column="coordinate_system"/>
+        <result property="radius" column="radius"/>
+        <result property="createBy" column="create_by"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateBy" column="update_by"/>
+        <result property="updateTime" column="update_time"/>
+    </resultMap>
+
+    <sql id="store_column_list">
+        store_id, merchant_id, platform_category_id, store_type, store_code, store_name, business_scope, status, logo_image_id,
+        cover_image_id, description, tags, delivery_fee, delivery_minimum, contact_phone, open_time, close_time,
+        address, longitude, latitude, geo_hash, geo_point, coordinate_system, radius, create_by, create_time, update_by, update_time
+    </sql>
+
+    <sql id="selectStoreVo">
+        select
+        store_id, merchant_id, platform_category_id, store_type, store_code, store_name, business_scope, status, logo_image_id,
+        cover_image_id, description, tags, delivery_fee, delivery_minimum, contact_phone, open_time, close_time,
+        address, longitude, latitude, geo_hash, geo_point, coordinate_system, radius, create_by, create_time, update_by, update_time from pc_store
+    </sql>
+
+    <select id="selectStoreList" resultMap="StoreResult">
+        <include refid="selectStoreVo"/>
+        <where>
+            <if test="criteria.merchantId != null ">and merchant_id = #{criteria.merchantId}</if>
+            <if test="criteria.storeName != null and criteria.storeName != ''">
+                and store_name like concat('%', #{criteria.storeName}, '%')
+            </if>
+            <if test="criteria.status != null ">and status = #{criteria.status}</if>
+        </where>
+    </select>
+
+    <select id="selectStoreByMerchantId" resultMap="StoreResult">
+        <include refid="selectStoreVo"/>
+        where merchant_id = #{merchantId}
+    </select>
+
+    <select id="queryNearStores" resultType="com.oying.modules.pc.search.domain.dto.StoreSearchDto">
+        SELECT
+        <trim prefix="" suffix="" suffixOverrides=",">
+            s.store_id AS storeId,
+            s.store_name AS storeName,
+            s.logo_image AS logoImage,
+            <!--<if test="criteria.longitude != null and criteria.latitude != null and criteria.radius != null">
+                ST_Distance_Sphere(
+                    POINT(#{criteria.longitude}, #{criteria.latitude}),
+                    POINT(s.longitude, s.latitude)
+                ) AS distance,</if>
+            <if test="criteria.blurry != null and criteria.blurry != ''">
+                MATCH(s.store_name) AGAINST(#{criteria.blurry}) AS matchScore
+            </if>-->
+        </trim>
+        FROM pc_store s
+        <where>
+            <!-- 位置条件 -->
+            <if test="criteria.longitude != null and criteria.latitude != null and criteria.radius != null">
+                AND ST_Distance_Sphere(POINT(#{criteria.longitude}, #{criteria.latitude}), POINT(s.longitude,
+                s.latitude)) &lt;= #{criteria.radius}
+                AND ST_Distance_Sphere(POINT(#{criteria.longitude}, #{criteria.latitude}), POINT(s.longitude,
+                s.latitude)) &lt;= s.radius
+            </if>
+
+            <!-- 店铺名称模糊查询 AND s.name LIKE CONCAT('%', #{criteria.blurry}, '%') -->
+            <if test="criteria.blurry != null and criteria.blurry != ''">
+                AND MATCH(s.store_name) AGAINST(#{criteria.blurry} IN NATURAL LANGUAGE MODE)
+            </if>
+
+            <!-- 营业状态 -->
+            <if test="criteria.status != null">
+                AND s.status = #{criteria.status}
+            </if>
+
+            <!-- 类目ID -->
+            <if test="criteria.platformCategoryId != null">
+                AND s.platform_category_id = #{criteria.platformCategoryId}
+            </if>
+        </where>
+    </select>
+
+</mapper>
\ No newline at end of file
diff --git a/oying-system/src/main/resources/mapper/pc/store/StoreQualificationMapper.xml b/oying-system/src/main/resources/mapper/pc/store/StoreQualificationMapper.xml
new file mode 100644
index 0000000..76b3c9c
--- /dev/null
+++ b/oying-system/src/main/resources/mapper/pc/store/StoreQualificationMapper.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.oying.modules.pc.store.mapper.StoreQualificationMapper">
+    <resultMap id="BaseResultMap" type="com.oying.modules.pc.store.domain.StoreQualification">
+        <id column="qualification_id" property="qualificationId"/>
+        <result column="store_id" property="storeId"/>
+        <result column="qualification_type" property="qualificationType"/>
+        <result column="qualification_number" property="qualificationNumber"/>
+        <result column="qualification_name" property="qualificationName"/>
+        <result column="qualification_image_id" property="qualificationImageId"/>
+        <result column="start_date" property="startDate"/>
+        <result column="end_date" property="endDate"/>
+        <result column="status" property="status"/>
+        <result column="create_by" property="createBy"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_by" property="updateBy"/>
+        <result column="update_time" property="updateTime"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        qualification_id, store_id, qualification_type, qualification_number, qualification_name, qualification_image_id, start_date, end_date, status,
+        create_by, create_time, update_by, update_time
+    </sql>
+
+    <select id="findAll" resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from pc_store_qualification
+        <where>
+            <if test="criteria.storeId != null">
+                and store_id = #{criteria.storeId}
+            </if>
+        </where>
+        order by qualification_id desc
+    </select>
+</mapper>
\ No newline at end of file
diff --git a/oying-system/src/main/resources/mapper/system/MerchantsMapper.xml b/oying-system/src/main/resources/mapper/system/MerchantsMapper.xml
new file mode 100644
index 0000000..526dea8
--- /dev/null
+++ b/oying-system/src/main/resources/mapper/system/MerchantsMapper.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.oying.modules.system.mapper.MerchantsMapper">
+    <resultMap id="BaseResultMap" type="com.oying.modules.system.domain.Merchants">
+        <id column="merchants_id" property="merchantsId"/>
+        <result column="merchant_name" property="merchantName"/>
+        <result column="merchant_code" property="merchantCode"/>
+        <result column="business_license" property="businessLicense"/>
+        <result column="business_license_path" property="businessLicensePath"/>
+        <result column="contact_mobile" property="contactMobile"/>
+        <result column="merchants_sort" property="merchantsSort"/>
+        <result column="enabled" property="enabled"/>
+        <result column="create_by" property="createBy"/>
+        <result column="update_by" property="updateBy"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="auth_user" property="authUser"/>
+        <result column="auth_time" property="authTime"/>
+        <result column="auth_message" property="authMessage"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        merchants_id, merchant_name, merchant_code, business_license, business_license_path, contact_mobile, merchants_sort, enabled, create_by, update_by, create_time, update_time, auth_user, auth_time, auth_message
+    </sql>
+
+    <select id="findAll" resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from sys_merchants
+        <where>
+            <if test="criteria.blurry != null and criteria.blurry != ''">
+                and (
+                merchant_name like concat('%', #{criteria.blurry}, '%')
+                or merchant_code like concat('%', #{criteria.blurry}, '%')
+                or business_license like concat('%', #{criteria.blurry}, '%')
+                or contact_mobile like concat('%', #{criteria.blurry}, '%')
+                )
+            </if>
+            <if test="criteria.enabled != null">
+                and enabled = #{criteria.enabled}
+            </if>
+            <if test="criteria.createTime != null and criteria.createTime.size() > 0">
+                AND create_time BETWEEN #{criteria.createTime[0]} AND #{criteria.createTime[1]}
+            </if>
+        </where>
+        order by merchants_sort desc
+    </select>
+</mapper>
diff --git a/oying-tools/src/main/java/com/oying/rest/EmailController.java b/oying-tools/src/main/java/com/oying/rest/EmailController.java
index 6d45449..dca9078 100644
--- a/oying-tools/src/main/java/com/oying/rest/EmailController.java
+++ b/oying-tools/src/main/java/com/oying/rest/EmailController.java
@@ -1,6 +1,7 @@
 package com.oying.rest;
 
 import com.oying.service.EmailService;
+import com.oying.utils.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -14,6 +15,7 @@
 
 /**
  * 发送邮件
+ *
  * @author Z
  * @date 2018/09/28 6:55:53
  */
@@ -26,8 +28,8 @@
     private final EmailService emailService;
 
     @GetMapping
-    public ResponseEntity<EmailConfig> queryEmailConfig(){
-        return new ResponseEntity<>(emailService.find(),HttpStatus.OK);
+    public ResponseEntity<Object> queryEmailConfig() {
+        return new ResponseEntity<>(R.success(emailService.find()), HttpStatus.OK);
     }
 
     @Log("配置邮件")
@@ -35,14 +37,14 @@
     @ApiOperation("配置邮件")
     public ResponseEntity<Object> updateEmailConfig(@Validated @RequestBody EmailConfig emailConfig) throws Exception {
         emailService.config(emailConfig, emailService.find());
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 
     @Log("发送邮件")
     @PostMapping
     @ApiOperation("发送邮件")
-    public ResponseEntity<Object> sendEmail(@Validated @RequestBody EmailDto emailDto){
-        emailService.send(emailDto,emailService.find());
-        return new ResponseEntity<>(HttpStatus.OK);
+    public ResponseEntity<Object> sendEmail(@Validated @RequestBody EmailDto emailDto) {
+        emailService.send(emailDto, emailService.find());
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 }
diff --git a/oying-tools/src/main/java/com/oying/rest/LocalStorageController.java b/oying-tools/src/main/java/com/oying/rest/LocalStorageController.java
index 47ffe3b..9db5c12 100644
--- a/oying-tools/src/main/java/com/oying/rest/LocalStorageController.java
+++ b/oying-tools/src/main/java/com/oying/rest/LocalStorageController.java
@@ -2,6 +2,7 @@
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.oying.service.LocalStorageService;
+import com.oying.utils.R;
 import lombok.RequiredArgsConstructor;
 import com.oying.annotation.Log;
 import com.oying.domain.LocalStorage;
@@ -16,13 +17,14 @@
 import org.springframework.web.bind.annotation.*;
 import io.swagger.annotations.*;
 import org.springframework.web.multipart.MultipartFile;
+
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 
 /**
-* @author Z
-* @date 2019-09-05
-*/
+ * @author Z
+ * @date 2019-09-05
+ */
 @RestController
 @RequiredArgsConstructor
 @Api(tags = "工具:本地存储管理")
@@ -34,9 +36,9 @@
     @GetMapping
     @ApiOperation("查询文件")
     @PreAuthorize("@el.check('storage:list')")
-    public ResponseEntity<PageResult<LocalStorage>> queryFile(LocalStorageQueryCriteria criteria){
+    public ResponseEntity<Object> queryFile(LocalStorageQueryCriteria criteria) {
         Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
-        return new ResponseEntity<>(localStorageService.queryAll(criteria,page),HttpStatus.OK);
+        return new ResponseEntity<>(R.success(localStorageService.queryAll(criteria, page)), HttpStatus.OK);
     }
 
     @ApiOperation("导出数据")
@@ -49,30 +51,30 @@
     @PostMapping
     @ApiOperation("上传文件")
     @PreAuthorize("@el.check('storage:add')")
-    public ResponseEntity<Object> createFile(@RequestParam String name, @RequestParam("file") MultipartFile file){
+    public ResponseEntity<Object> createFile(@RequestParam String name, @RequestParam("file") MultipartFile file) {
         localStorageService.create(name, file);
-        return new ResponseEntity<>(HttpStatus.CREATED);
+        return new ResponseEntity<>(R.success(), HttpStatus.CREATED);
     }
 
     @ApiOperation("上传图片")
     @PostMapping("/pictures")
-    public ResponseEntity<LocalStorage> uploadPicture(@RequestParam MultipartFile file){
+    public ResponseEntity<Object> uploadPicture(@RequestParam MultipartFile file) {
         // 判断文件是否为图片
         String suffix = FileUtil.getExtensionName(file.getOriginalFilename());
-        if(!FileUtil.IMAGE.equals(FileUtil.getFileType(suffix))){
+        if (!FileUtil.IMAGE.equals(FileUtil.getFileType(suffix))) {
             throw new BadRequestException("只能上传图片");
         }
         LocalStorage localStorage = localStorageService.create(null, file);
-        return new ResponseEntity<>(localStorage, HttpStatus.OK);
+        return new ResponseEntity<>(R.success(localStorage), HttpStatus.OK);
     }
 
     @PutMapping
     @Log("修改文件")
     @ApiOperation("修改文件")
     @PreAuthorize("@el.check('storage:edit')")
-    public ResponseEntity<Object> updateFile(@Validated @RequestBody LocalStorage resources){
+    public ResponseEntity<Object> updateFile(@Validated @RequestBody LocalStorage resources) {
         localStorageService.update(resources);
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        return new ResponseEntity<>(R.success(), HttpStatus.NO_CONTENT);
     }
 
     @Log("删除文件")
@@ -80,6 +82,6 @@
     @ApiOperation("多选删除")
     public ResponseEntity<Object> deleteFile(@RequestBody Long[] ids) {
         localStorageService.deleteAll(ids);
-        return new ResponseEntity<>(HttpStatus.OK);
+        return new ResponseEntity<>(R.success(), HttpStatus.OK);
     }
 }
diff --git a/pom.xml b/pom.xml
index a2fef79..489ecc4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -210,6 +210,20 @@
             <version>${fastjson2.version}</version>
         </dependency>
 
+        <!-- 请求跳过ssl证书验证 -->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpmime</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpcore</artifactId>
+        </dependency>
+
         <!-- Java图形验证码 -->
         <dependency>
             <groupId>com.github.whvcse</groupId>

--
Gitblit v1.9.3