Sfoglia il codice sorgente

登录注册功能完成;授权完成一大半

Huanyi 3 settimane fa
parent
commit
c8ea633112
39 ha cambiato i file con 1309 aggiunte e 69 eliminazioni
  1. 11 1
      pom.xml
  2. 0 1
      ruoyi-admin/pom.xml
  3. 1 5
      ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
  4. 3 27
      ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java
  5. 1 0
      ruoyi-admin/src/main/resources/application.yml
  6. 5 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java
  7. 1 2
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/WechatAppletRegisterBody.java
  8. 16 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/CustomerService.java
  9. 5 0
      ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java
  10. 26 0
      ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/CustomerNameTranslationImpl.java
  11. 1 0
      ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  12. 5 0
      ruoyi-modules/ruoyi-system/pom.xml
  13. 68 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysComplaintController.java
  14. 38 19
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysCustomerController.java
  15. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java
  16. 55 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysComplaint.java
  17. 3 2
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCustomer.java
  18. 51 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysComplaintBo.java
  19. 3 3
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysCustomerBo.java
  20. 74 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysComplaintVo.java
  21. 17 3
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysCustomerVo.java
  22. 12 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysComplaintMapper.java
  23. 30 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysComplaintService.java
  24. 5 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysCustomerService.java
  25. 70 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysComplaintServiceImpl.java
  26. 64 3
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysCustomerServiceImpl.java
  27. 5 0
      ruoyi-modules/yingpaipay-erp/pom.xml
  28. 40 0
      ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/controller/ErpClientController.java
  29. 291 0
      ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/domain/ErpClient.java
  30. 41 0
      ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/domain/query/ErpClientQuery.java
  31. 149 0
      ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/domain/vo/ErpClientVo.java
  32. 13 0
      ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/mapper/ErpClientMapper.java
  33. 23 0
      ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/service/IErpClientService.java
  34. 70 0
      ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/service/impl/ErpClientServiceImpl.java
  35. 41 2
      script/sql/sqlserver/v1/create.sql
  36. 1 0
      yingpaipay-api/pom.xml
  37. 31 0
      yingpaipay-api/yingpaipay-api-bom/pom.xml
  38. 18 0
      yingpaipay-api/yingpaipay-api-erp/pom.xml
  39. 20 0
      yingpaipay-api/yingpaipay-api-erp/src/main/java/org/dromara/yingpaipay/api/erp/CommonErpClientService.java

+ 11 - 1
pom.xml

@@ -124,6 +124,15 @@
                 <scope>import</scope>
             </dependency>
 
+            <!-- yingpaipay-api 的依赖配置-->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>yingpaipay-api-bom</artifactId>
+                <version>${revision}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
             <dependency>
                 <groupId>org.springdoc</groupId>
                 <artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
@@ -365,11 +374,12 @@
     </dependencyManagement>
 
     <modules>
+        <module>yingpaipay-api/yingpaipay-api-bom</module>
+        <module>yingpaipay-api</module>
         <module>ruoyi-admin</module>
         <module>ruoyi-common</module>
         <module>ruoyi-extend</module>
         <module>ruoyi-modules</module>
-        <module>yingpaipay-api</module>
     </modules>
     <packaging>pom</packaging>
 

+ 0 - 1
ruoyi-admin/pom.xml

@@ -93,7 +93,6 @@
             <artifactId>ruoyi-workflow</artifactId>
         </dependency>
 
-        <!--  盈派支付ERP模块  -->
         <dependency>
             <groupId>org.dromara</groupId>
             <artifactId>yingpaipay-erp</artifactId>

+ 1 - 5
ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java

@@ -234,11 +234,7 @@ public class AuthController {
         String unionId = body.getUnionId();
         String phone = body.getPhone();
         String nickname = body.getNickname();
-        String avatar = body.getAvatar();
-
-        if (StringUtils.isEmpty(openId) || StringUtils.isEmpty(unionId) || StringUtils.isEmpty(phone)) {
-            return R.fail("必要参数不能为空");
-        }
+        Long avatar = body.getAvatar();
 
         registerService.wechatRegister(openId, unionId, phone, nickname, avatar);
         return R.ok();

+ 3 - 27
ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java

@@ -120,39 +120,15 @@ public class SysRegisterService {
         SpringUtils.context().publishEvent(logininforEvent);
     }
 
-    public void wechatRegister(String openId, String unionId, String phone, String nickname, String avatar) {
+    public void wechatRegister(String openId, String unionId, String phone, String nickname, Long avatar) {
         SysCustomer customer = new SysCustomer();
         customer.setWechatOpenid(openId);
         customer.setWechatUnionid(unionId);
         customer.setPhone(phone);
         customer.setUserName(StringUtils.isNotEmpty(nickname) ? nickname : "用户" + phone.substring(phone.length() - 4));
-        
-        if (StringUtils.isNotEmpty(avatar)) {
-            try {
-                String base64Data = avatar;
-                if (base64Data.startsWith("data:image/")) {
-                    String[] parts = base64Data.split(",");
-                    if (parts.length == 2) {
-                        String imageData = parts[1];
-                        String contentType = parts[0].split(";")[0].split(":")[1];
-                        String suffix = contentType.split("/")[1];
-                        
-                        byte[] imageBytes = Base64.decode(imageData);
-                        String fileName = "avatar_" + System.currentTimeMillis() + "." + suffix;
-                        java.io.File tempFile = java.io.File.createTempFile("upload_", fileName);
-                        FileUtil.writeBytes(imageBytes, tempFile);
-                        
-                        SysOssVo ossVo = ossService.upload(tempFile);
-                        customer.setAvatar(ossVo.getOssId());
-                        
-                        tempFile.delete();
-                    }
-                }
-            } catch (Exception e) {
-                throw new UserException("头像上传失败: " + e.getMessage());
-            }
+        if (avatar != null) {
+            customer.setAvatar(avatar);
         }
-        
         int result = customerMapper.insert(customer);
         if (result <= 0) {
             throw new UserException("用户注册失败");

+ 1 - 0
ruoyi-admin/src/main/resources/application.yml

@@ -106,6 +106,7 @@ security:
     - /*/api-docs
     - /*/api-docs/**
     - /warm-flow-ui/config
+    - /resource/oss/upload
 
 # 多租户配置
 tenant:

+ 5 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java

@@ -86,6 +86,11 @@ public interface CacheNames {
      */
     String SYS_AGREEMENT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_agreement";
 
+    /**
+     * 客户昵称
+     */
+    String SYS_CUSTOMER_NAME = "sys_customer_name#30d";
+
     /**
      * 在线用户
      */

+ 1 - 2
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/WechatAppletRegisterBody.java

@@ -15,7 +15,6 @@ public class WechatAppletRegisterBody implements Serializable {
     @NotBlank(message = "openId不能为空")
     private String openId;
 
-    @NotBlank(message = "unionId不能为空")
     private String unionId;
 
     @NotBlank(message = "手机号不能为空")
@@ -23,5 +22,5 @@ public class WechatAppletRegisterBody implements Serializable {
 
     private String nickname;
 
-    private String avatar;
+    private Long avatar;
 }

+ 16 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/CustomerService.java

@@ -0,0 +1,16 @@
+package org.dromara.common.core.service;
+
+/**
+ * 通用 客户服务
+ */
+public interface CustomerService {
+
+    /**
+     * 通过客户ID查询客户昵称
+     *
+     * @param customerId 客户ID
+     * @return 客户昵称
+     */
+    String selectUserNameById(Long customerId);
+
+}

+ 5 - 0
ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java

@@ -32,4 +32,9 @@ public interface TransConstant {
      */
     String OSS_ID_TO_URL = "oss_id_to_url";
 
+    /**
+     * 客户id转昵称
+     */
+    String CUSTOMER_ID_TO_NAME = "customer_id_to_name";
+
 }

+ 26 - 0
ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/CustomerNameTranslationImpl.java

@@ -0,0 +1,26 @@
+package org.dromara.common.translation.core.impl;
+
+import lombok.AllArgsConstructor;
+import org.dromara.common.core.service.CustomerService;
+import org.dromara.common.translation.annotation.TranslationType;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.common.translation.core.TranslationInterface;
+
+/**
+ * 客户昵称翻译实现
+ */
+@AllArgsConstructor
+@TranslationType(type = TransConstant.CUSTOMER_ID_TO_NAME)
+public class CustomerNameTranslationImpl implements TranslationInterface<String> {
+
+    private final CustomerService customerService;
+
+    @Override
+    public String translation(Object key, String other) {
+        if (key instanceof Long id) {
+            return customerService.selectUserNameById(id);
+        }
+        return null;
+    }
+
+}

+ 1 - 0
ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -4,3 +4,4 @@ org.dromara.common.translation.core.impl.DictTypeTranslationImpl
 org.dromara.common.translation.core.impl.OssUrlTranslationImpl
 org.dromara.common.translation.core.impl.UserNameTranslationImpl
 org.dromara.common.translation.core.impl.NicknameTranslationImpl
+org.dromara.common.translation.core.impl.CustomerNameTranslationImpl

+ 5 - 0
ruoyi-modules/ruoyi-system/pom.xml

@@ -22,6 +22,11 @@
             <artifactId>ruoyi-common-core</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>yingpaipay-api-erp</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>org.dromara</groupId>
             <artifactId>ruoyi-common-doc</artifactId>

+ 68 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysComplaintController.java

@@ -0,0 +1,68 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.stp.StpUtil;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysComplaintBo;
+import org.dromara.system.domain.vo.SysComplaintVo;
+import org.dromara.system.service.ISysComplaintService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 投诉建议管理
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/complaint")
+public class SysComplaintController extends BaseController {
+
+    private final ISysComplaintService sysComplaintService;
+
+    /**
+     * 查询投诉建议列表(管理端)
+     */
+    @SaCheckPermission("system:complaint:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysComplaintVo> list(SysComplaintBo bo, PageQuery pageQuery) {
+        return sysComplaintService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 提交投诉建议(小程序端,需登录)
+     */
+    @Log(title = "投诉建议", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping
+    public R<Void> submit(@Validated @RequestBody SysComplaintBo bo) {
+        String loginId = StpUtil.getLoginIdAsString();
+        Long customerId = Long.parseLong(loginId.replace("customer:", ""));
+        bo.setCustomerId(customerId);
+        return toAjax(sysComplaintService.insertByBo(bo));
+    }
+
+    /**
+     * 删除投诉建议(管理端)
+     *
+     * @param ids 主键串
+     */
+    @SaCheckPermission("system:complaint:remove")
+    @Log(title = "投诉建议", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable Long[] ids) {
+        return toAjax(sysComplaintService.deleteWithValidByIds(List.of(ids)));
+    }
+
+}

+ 38 - 19
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysCustomerController.java

@@ -1,6 +1,7 @@
 package org.dromara.system.controller.system;
 
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.stp.StpUtil;
 import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
 import lombok.RequiredArgsConstructor;
@@ -34,10 +35,33 @@ public class SysCustomerController extends BaseController {
 
     private final ISysCustomerService sysCustomerService;
 
+    /**
+     * 获取当前登录客户信息
+     */
+    @GetMapping("/getInfo")
+    public R<SysCustomerVo> getMyInfo() {
+        String loginId = StpUtil.getLoginIdAsString();
+        Long customerId = Long.parseLong(loginId.replace("customer:", ""));
+        return R.ok(sysCustomerService.queryById(customerId));
+    }
+
+    /**
+     * 更新当前登录客户信息
+     */
+    @Log(title = "客户管理", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping("/updateProfile")
+    public R<Void> updateMyInfo(@RequestBody SysCustomerBo bo) {
+        String loginId = StpUtil.getLoginIdAsString();
+        Long customerId = Long.parseLong(loginId.replace("customer:", ""));
+        bo.setId(customerId);
+        return toAjax(sysCustomerService.updateByBo(bo));
+    }
+
     /**
      * 查询客户列表
      */
-    @SaCheckPermission("system:customer:list")
+    @SaCheckPermission("customer:customer:list")
     @GetMapping("/list")
     public TableDataInfo<SysCustomerVo> list(SysCustomerBo bo, PageQuery pageQuery) {
         return sysCustomerService.queryPageList(bo, pageQuery);
@@ -48,7 +72,7 @@ public class SysCustomerController extends BaseController {
      *
      * @param id 主键
      */
-    @SaCheckPermission("system:customer:query")
+    @SaCheckPermission("customer:customer:query")
     @GetMapping("/{id}")
     public R<SysCustomerVo> getInfo(@NotNull(message = "主键不能为空")
                                     @PathVariable Long id) {
@@ -56,26 +80,21 @@ public class SysCustomerController extends BaseController {
     }
 
     /**
-     * 修改客户
+     * 授权客户
+     *
+     * @param id             客户ID
+     * @param authCustomerId 授权客户ID
+     * @Author: Antigravity
      */
-    @SaCheckPermission("system:customer:edit")
+    @SaCheckPermission("customer:customer:auth")
     @Log(title = "客户管理", businessType = BusinessType.UPDATE)
     @RepeatSubmit()
-    @PutMapping()
-    public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysCustomerBo bo) {
+    @PutMapping("/auth")
+    public R<Void> auth(@NotNull(message = "客户ID不能为空") Long id,
+                        @NotEmpty(message = "授权客户ERP编码不能为空") String authClientFNum) {
+        SysCustomerBo bo = new SysCustomerBo();
+        bo.setId(id);
+        bo.setAuthClientFNum(authClientFNum);
         return toAjax(sysCustomerService.updateByBo(bo));
     }
-
-    /**
-     * 删除客户
-     *
-     * @param ids 主键串
-     */
-    @SaCheckPermission("system:customer:remove")
-    @Log(title = "客户管理", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{ids}")
-    public R<Void> remove(@NotEmpty(message = "主键不能为空")
-                          @PathVariable Long[] ids) {
-        return toAjax(sysCustomerService.deleteWithValidByIds(List.of(ids), true));
-    }
 }

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java

@@ -65,7 +65,7 @@ public class SysOssController extends BaseController {
      *
      * @param file 文件
      */
-    @SaCheckPermission("system:oss:upload")
+    // @SaCheckPermission("system:oss:upload")
     @Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
     @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
     public R<SysOssUploadVo> upload(@RequestPart("file") MultipartFile file) {

+ 55 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysComplaint.java

@@ -0,0 +1,55 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serial;
+
+/**
+ * 投诉建议表 sys_complaint
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_complaint")
+public class SysComplaint extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 投诉建议ID
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 反馈类型(字典值)
+     */
+    private String feedbackType;
+
+    /**
+     * 反馈内容
+     */
+    private String content;
+
+    /**
+     * 图片OSS ID列表(JSON数组字符串)
+     */
+    private String images;
+
+    /**
+     * 投诉客户ID
+     */
+    private Long customerId;
+
+    /**
+     * 删除标志(0代表存在 1代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+}

+ 3 - 2
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCustomer.java

@@ -1,5 +1,6 @@
 package org.dromara.system.domain;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -50,9 +51,9 @@ public class SysCustomer extends TenantEntity {
     private String wechatUnionid;
 
     /**
-     * 授权客户ID
+     * 授权客户ERP编码
      */
-    private String authCustomerId;
+    private String authClientFNum;
 
     /**
      * 头像OSS ID

+ 51 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysComplaintBo.java

@@ -0,0 +1,51 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysComplaint;
+
+/**
+ * 投诉建议业务对象 sys_complaint
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysComplaint.class, reverseConvertGenerate = false)
+public class SysComplaintBo extends BaseEntity {
+
+    /**
+     * 投诉建议ID
+     */
+    private Long id;
+
+    /**
+     * 反馈类型(字典值)
+     */
+    private String feedbackType;
+
+    /**
+     * 反馈内容
+     */
+    @NotBlank(message = "反馈内容不能为空")
+    @Size(max = 2000, message = "反馈内容长度不能超过{max}个字符")
+    private String content;
+
+    /**
+     * 图片OSS ID列表(JSON数组字符串)
+     */
+    private String images;
+
+    /**
+     * 投诉客户ID
+     */
+    private Long customerId;
+
+    /**
+     * 客户姓名(模糊搜索用,不持久化)
+     */
+    private String customerName;
+
+}

+ 3 - 3
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysCustomerBo.java

@@ -50,10 +50,10 @@ public class SysCustomerBo extends BaseEntity {
     private String wechatUnionid;
 
     /**
-     * 授权客户ID
+     * 授权客户ERP编码
      */
-    @Size(min = 0, max = 255, message = "授权客户ID长度不能超过{max}个字符")
-    private String authCustomerId;
+    @Size(min = 0, max = 100, message = "授权客户ERP编码长度不能超过{max}个字符")
+    private String authClientFNum;
 
     /**
      * 头像OSS ID

+ 74 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysComplaintVo.java

@@ -0,0 +1,74 @@
+package org.dromara.system.domain.vo;
+
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.system.domain.SysComplaint;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 投诉建议视图对象 sys_complaint
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysComplaint.class)
+public class SysComplaintVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 投诉建议ID
+     */
+    @ExcelProperty(value = "ID")
+    private Long id;
+
+    /**
+     * 反馈类型
+     */
+    @ExcelProperty(value = "反馈类型")
+    private String feedbackType;
+
+    /**
+     * 反馈内容
+     */
+    @ExcelProperty(value = "反馈内容")
+    private String content;
+
+    /**
+     * 图片OSS ID列表(逗号拼接字符串,如 1,2,3)
+     */
+    @ExcelProperty(value = "图片")
+    private String images;
+
+    /**
+     * 图片URL列表(逗号拼接,通过OSS ID翻译)
+     */
+    @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "images")
+    private String imageUrls;
+
+    /**
+     * 投诉客户ID
+     */
+    @ExcelProperty(value = "客户ID")
+    private Long customerId;
+
+    /**
+     * 客户昵称(通过客户ID翻译)
+     */
+    @Translation(type = TransConstant.CUSTOMER_ID_TO_NAME, mapper = "customerId")
+    private String customerNickname;
+
+    /**
+     * 创建时间
+     */
+    @ExcelProperty(value = "提交时间")
+    private Date createTime;
+
+}

+ 17 - 3
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysCustomerVo.java

@@ -4,6 +4,8 @@ import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
 import cn.idev.excel.annotation.ExcelProperty;
 import io.github.linpeilie.annotations.AutoMapper;
 import lombok.Data;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
 import org.dromara.system.domain.SysCustomer;
 
 import java.io.Serial;
@@ -54,10 +56,16 @@ public class SysCustomerVo implements Serializable {
     private String wechatUnionid;
 
     /**
-     * 授权客户ID
+     * 授权客户ERP编码
      */
-    @ExcelProperty(value = "授权客户ID")
-    private String authCustomerId;
+    @ExcelProperty(value = "授权客户ERP编码")
+    private String authClientFNum;
+
+    /**
+     * 授权客户名称
+     */
+    @ExcelProperty(value = "授权客户名称")
+    private String authClientName;
 
     /**
      * 头像OSS ID
@@ -65,6 +73,12 @@ public class SysCustomerVo implements Serializable {
     @ExcelProperty(value = "头像OSS ID")
     private Long avatar;
 
+    /**
+     * 头像URL(通过OSS ID翻译)
+     */
+    @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "avatar")
+    private String avatarUrl;
+
     /**
      * 创建时间
      */

+ 12 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysComplaintMapper.java

@@ -0,0 +1,12 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysComplaint;
+import org.dromara.system.domain.vo.SysComplaintVo;
+
+/**
+ * 投诉建议 数据层
+ */
+public interface SysComplaintMapper extends BaseMapperPlus<SysComplaint, SysComplaintVo> {
+
+}

+ 30 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysComplaintService.java

@@ -0,0 +1,30 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysComplaintBo;
+import org.dromara.system.domain.vo.SysComplaintVo;
+
+import java.util.Collection;
+
+/**
+ * 投诉建议 Service接口
+ */
+public interface ISysComplaintService {
+
+    /**
+     * 分页查询投诉建议列表
+     */
+    TableDataInfo<SysComplaintVo> queryPageList(SysComplaintBo bo, PageQuery pageQuery);
+
+    /**
+     * 新增投诉建议
+     */
+    Boolean insertByBo(SysComplaintBo bo);
+
+    /**
+     * 批量删除投诉建议
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids);
+
+}

+ 5 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysCustomerService.java

@@ -43,4 +43,9 @@ public interface ISysCustomerService {
      * 根据微信OpenID查询客户
      */
     SysCustomerVo queryByWechatOpenid(String wechatOpenid);
+
+    /**
+     * 通过客户ID查询客户昵称
+     */
+    String selectUserNameById(Long customerId);
 }

+ 70 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysComplaintServiceImpl.java

@@ -0,0 +1,70 @@
+package org.dromara.system.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysComplaint;
+import org.dromara.system.domain.SysCustomer;
+import org.dromara.system.domain.bo.SysComplaintBo;
+import org.dromara.system.domain.vo.SysComplaintVo;
+import org.dromara.system.mapper.SysComplaintMapper;
+import org.dromara.system.mapper.SysCustomerMapper;
+import org.dromara.system.service.ISysComplaintService;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 投诉建议 Service业务层处理
+ */
+@RequiredArgsConstructor
+@Service
+public class SysComplaintServiceImpl implements ISysComplaintService {
+
+    private final SysComplaintMapper baseMapper;
+    private final SysCustomerMapper customerMapper;
+
+    @Override
+    public TableDataInfo<SysComplaintVo> queryPageList(SysComplaintBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<SysComplaint> lqw = buildQueryWrapper(bo);
+        Page<SysComplaintVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    private LambdaQueryWrapper<SysComplaint> buildQueryWrapper(SysComplaintBo bo) {
+        LambdaQueryWrapper<SysComplaint> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StringUtils.isNotBlank(bo.getFeedbackType()), SysComplaint::getFeedbackType, bo.getFeedbackType());
+        if (StringUtils.isNotBlank(bo.getCustomerName())) {
+            List<Long> customerIds = customerMapper.selectList(
+                Wrappers.lambdaQuery(SysCustomer.class)
+                    .select(SysCustomer::getId)
+                    .like(SysCustomer::getUserName, bo.getCustomerName())
+            ).stream().map(SysCustomer::getId).collect(Collectors.toList());
+            if (customerIds.isEmpty()) {
+                customerIds = List.of(0L);
+            }
+            lqw.in(SysComplaint::getCustomerId, customerIds);
+        }
+        lqw.orderByDesc(SysComplaint::getId);
+        return lqw;
+    }
+
+    @Override
+    public Boolean insertByBo(SysComplaintBo bo) {
+        SysComplaint add = MapstructUtils.convert(bo, SysComplaint.class);
+        return baseMapper.insert(add) > 0;
+    }
+
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids) {
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+
+}

+ 64 - 3
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysCustomerServiceImpl.java

@@ -4,18 +4,26 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.service.CustomerService;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.CacheUtils;
 import org.dromara.system.domain.SysCustomer;
 import org.dromara.system.domain.bo.SysCustomerBo;
 import org.dromara.system.domain.vo.SysCustomerVo;
 import org.dromara.system.mapper.SysCustomerMapper;
 import org.dromara.system.service.ISysCustomerService;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 
+import org.dromara.yingpaipay.api.erp.CommonErpClientService;
+
 import java.util.Collection;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 客户管理 Service业务层处理
@@ -24,16 +32,19 @@ import java.util.Collection;
  */
 @RequiredArgsConstructor
 @Service
-public class SysCustomerServiceImpl implements ISysCustomerService {
+public class SysCustomerServiceImpl implements ISysCustomerService, CustomerService {
 
     private final SysCustomerMapper baseMapper;
+    private final CommonErpClientService commonErpClientService;
 
     /**
      * 查询客户
      */
     @Override
     public SysCustomerVo queryById(Long id) {
-        return baseMapper.selectVoById(id);
+        SysCustomerVo vo = baseMapper.selectVoById(id);
+        fillAuthClientName(vo);
+        return vo;
     }
 
     /**
@@ -43,9 +54,44 @@ public class SysCustomerServiceImpl implements ISysCustomerService {
     public TableDataInfo<SysCustomerVo> queryPageList(SysCustomerBo bo, PageQuery pageQuery) {
         LambdaQueryWrapper<SysCustomer> lqw = buildQueryWrapper(bo);
         Page<SysCustomerVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        fillAuthClientName(result.getRecords());
         return TableDataInfo.build(result);
     }
 
+    /**
+     * 批量填充授权客户名称
+     */
+    private void fillAuthClientName(List<SysCustomerVo> list) {
+        if (StringUtils.isEmpty(list)) {
+            return;
+        }
+        List<String> authClientFNums = list.stream()
+            .map(SysCustomerVo::getAuthClientFNum)
+            .filter(StringUtils::isNotBlank)
+            .distinct()
+            .toList();
+        if (StringUtils.isEmpty(authClientFNums)) {
+            return;
+        }
+        Map<String, String> nameMap = commonErpClientService.selectNameByFNums(authClientFNums);
+        list.forEach(vo -> {
+            if (StringUtils.isNotBlank(vo.getAuthClientFNum())) {
+                vo.setAuthClientName(nameMap.get(vo.getAuthClientFNum()));
+            }
+        });
+    }
+
+    /**
+     * 单个填充授权客户名称
+     */
+    private void fillAuthClientName(SysCustomerVo vo) {
+        if (vo == null || StringUtils.isBlank(vo.getAuthClientFNum())) {
+            return;
+        }
+        Map<String, String> nameMap = commonErpClientService.selectNameByFNums(List.of(vo.getAuthClientFNum()));
+        vo.setAuthClientName(nameMap.get(vo.getAuthClientFNum()));
+    }
+
     private LambdaQueryWrapper<SysCustomer> buildQueryWrapper(SysCustomerBo bo) {
         LambdaQueryWrapper<SysCustomer> lqw = Wrappers.lambdaQuery();
         lqw.like(StringUtils.isNotBlank(bo.getUserName()), SysCustomer::getUserName, bo.getUserName());
@@ -61,7 +107,11 @@ public class SysCustomerServiceImpl implements ISysCustomerService {
     @Override
     public Boolean updateByBo(SysCustomerBo bo) {
         SysCustomer update = MapstructUtils.convert(bo, SysCustomer.class);
-        return baseMapper.updateById(update) > 0;
+        boolean result = baseMapper.updateById(update) > 0;
+        if (result && bo.getId() != null) {
+            CacheUtils.evict(CacheNames.SYS_CUSTOMER_NAME, bo.getId());
+        }
+        return result;
     }
 
     /**
@@ -87,4 +137,15 @@ public class SysCustomerServiceImpl implements ISysCustomerService {
                 .eq(SysCustomer::getWechatOpenid, wechatOpenid)
         );
     }
+
+    @Cacheable(cacheNames = CacheNames.SYS_CUSTOMER_NAME, key = "#customerId")
+    @Override
+    public String selectUserNameById(Long customerId) {
+        SysCustomer customer = baseMapper.selectOne(
+            Wrappers.lambdaQuery(SysCustomer.class)
+                .select(SysCustomer::getUserName)
+                .eq(SysCustomer::getId, customerId)
+        );
+        return customer != null ? customer.getUserName() : null;
+    }
 }

+ 5 - 0
ruoyi-modules/yingpaipay-erp/pom.xml

@@ -23,6 +23,11 @@
             <artifactId>ruoyi-common-core</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>yingpaipay-api-erp</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>org.dromara</groupId>
             <artifactId>ruoyi-common-doc</artifactId>

+ 40 - 0
ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/controller/ErpClientController.java

@@ -0,0 +1,40 @@
+package org.dromara.yingpaipay.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.yingpaipay.domain.query.ErpClientQuery;
+import org.dromara.yingpaipay.domain.vo.ErpClientVo;
+import org.dromara.yingpaipay.service.IErpClientService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * HTSail_Alu 客户档案查询接口
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/erp/client")
+public class ErpClientController {
+
+    private final IErpClientService erpClientService;
+
+    /**
+     * 分页查询客户列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo<ErpClientVo> list(ErpClientQuery query, PageQuery pageQuery) {
+        return erpClientService.queryPageList(query, pageQuery);
+    }
+
+    /**
+     * 查询客户详情
+     */
+    @GetMapping("/{fRowId}")
+    public R<ErpClientVo> getInfo(@PathVariable String fRowId) {
+        return R.ok(erpClientService.queryById(fRowId));
+    }
+
+}

+ 291 - 0
ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/domain/ErpClient.java

@@ -0,0 +1,291 @@
+package org.dromara.yingpaipay.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.yingpaipay.domain.vo.ErpClientVo;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * HTSail_Alu 客户档案 t_Bdi_Client
+ */
+@Data
+@AutoMapper(target = ErpClientVo.class)
+@TableName("t_Bdi_Client")
+public class ErpClient implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 序号(主键)
+     */
+    @TableId("FRowID")
+    private String fRowId;
+
+    /**
+     * 代码
+     */
+    @TableField("FNum")
+    private String fNum;
+
+    /**
+     * 名称
+     */
+    @TableField("FName")
+    private String fName;
+
+    /**
+     * 分类(国内,国外)
+     */
+    @TableField("FClass")
+    private String fClass;
+
+    /**
+     * 地区
+     */
+    @TableField("AreaID")
+    private String areaId;
+
+    /**
+     * 销售部门
+     */
+    @TableField("SaleDept")
+    private String saleDept;
+
+    /**
+     * 负责人
+     */
+    @TableField("DutyMan")
+    private String dutyMan;
+
+    /**
+     * 业务员
+     */
+    @TableField("SaleMan")
+    private String saleMan;
+
+    /**
+     * 跟单员
+     */
+    @TableField("TraceMan")
+    private String traceMan;
+
+    /**
+     * 客户经理
+     */
+    @TableField("ManagerMan")
+    private String managerMan;
+
+    /**
+     * 信用额度
+     */
+    @TableField("CreditAmt")
+    private BigDecimal creditAmt;
+
+    /**
+     * 合同期限
+     */
+    @TableField("ContractLimit")
+    private String contractLimit;
+
+    /**
+     * 付款方式
+     */
+    @TableField("PayMode")
+    private String payMode;
+
+    /**
+     * 计提日期
+     */
+    @TableField("DeductDate")
+    private Date deductDate;
+
+    /**
+     * 联系人
+     */
+    @TableField("ContactMan")
+    private String contactMan;
+
+    /**
+     * 地址
+     */
+    @TableField("ContactAddr")
+    private String contactAddr;
+
+    /**
+     * 电话
+     */
+    @TableField("ContactTel")
+    private String contactTel;
+
+    /**
+     * 手机
+     */
+    @TableField("ContactMobile")
+    private String contactMobile;
+
+    /**
+     * 传真
+     */
+    @TableField("ContactFax")
+    private String contactFax;
+
+    /**
+     * 邮编
+     */
+    @TableField("ContactPost")
+    private String contactPost;
+
+    /**
+     * 网址
+     */
+    @TableField("ContactNet")
+    private String contactNet;
+
+    /**
+     * 邮箱
+     */
+    @TableField("ContactEmail")
+    private String contactEmail;
+
+    /**
+     * 窗体功能ID
+     */
+    @TableField("FormID")
+    private String formId;
+
+    /**
+     * 公司ID
+     */
+    @TableField("CompanyID")
+    private Integer companyId;
+
+    /**
+     * 树记录号
+     */
+    @TableField("TreeControl")
+    private String treeControl;
+
+    /**
+     * 级联ID
+     */
+    @TableField("ParentRowID")
+    private String parentRowId;
+
+    /**
+     * 暂停使用(0正常 1停用)
+     */
+    @TableField("StopUse")
+    private Integer stopUse;
+
+    /**
+     * 编辑人
+     */
+    @TableField("ModifyName")
+    private String modifyName;
+
+    /**
+     * 编辑时间
+     */
+    @TableField("ModifyDate")
+    private Date modifyDate;
+
+    /**
+     * 创建人
+     */
+    @TableField("EnterName")
+    private String enterName;
+
+    /**
+     * 创建时间
+     */
+    @TableField("EnterDate")
+    private Date enterDate;
+
+    /**
+     * 客户简称
+     */
+    @TableField("ShortName")
+    private String shortName;
+
+    /**
+     * 经销商ID
+     */
+    @TableField("DealerID")
+    private String dealerId;
+
+    /**
+     * 是否经销商
+     */
+    @TableField("IsDealer")
+    private Integer isDealer;
+
+    /**
+     * 铝价品种
+     */
+    @TableField("AluVariety")
+    private String aluVariety;
+
+    /**
+     * 获价类型
+     */
+    @TableField("AluGainKind")
+    private String aluGainKind;
+
+    /**
+     * 标签名称
+     */
+    @TableField("ClientLabel")
+    private String clientLabel;
+
+    /**
+     * 信用等级
+     */
+    @TableField("CreditRating")
+    private String creditRating;
+
+    /**
+     * 拼音码
+     */
+    @TableField("PYCode")
+    private String pyCode;
+
+    /**
+     * 销售部门ID
+     */
+    @TableField("DeptID")
+    private String deptId;
+
+    /**
+     * 首单日期
+     */
+    @TableField("FirstDate")
+    private Date firstDate;
+
+    /**
+     * 铝材客户
+     */
+    @TableField("IsAlu")
+    private Integer isAlu;
+
+    /**
+     * 铝模客户
+     */
+    @TableField("IsAluPlate")
+    private Integer isAluPlate;
+
+}

+ 41 - 0
ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/domain/query/ErpClientQuery.java

@@ -0,0 +1,41 @@
+package org.dromara.yingpaipay.domain.query;
+
+import lombok.Data;
+
+/**
+ * HTSail_Alu 客户档案查询条件
+ */
+@Data
+public class ErpClientQuery {
+
+    /**
+     * 客户名称(模糊)
+     */
+    private String fName;
+
+    /**
+     * 客户代码(模糊)
+     */
+    private String fNum;
+
+    /**
+     * 客户简称(模糊)
+     */
+    private String shortName;
+
+    /**
+     * 拼音码(模糊)
+     */
+    private String pyCode;
+
+    /**
+     * 暂停使用(0正常 1停用,不传则查全部)
+     */
+    private Integer stopUse;
+
+    /**
+     * 分类(国内/国外)
+     */
+    private String fClass;
+
+}

+ 149 - 0
ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/domain/vo/ErpClientVo.java

@@ -0,0 +1,149 @@
+package org.dromara.yingpaipay.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.yingpaipay.domain.ErpClient;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * HTSail_Alu 客户档案 VO
+ */
+@Data
+@AutoMapper(target = ErpClient.class)
+public class ErpClientVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 序号(主键)
+     */
+    private String fRowId;
+
+    /**
+     * 代码
+     */
+    private String fNum;
+
+    /**
+     * 名称
+     */
+    private String fName;
+
+    /**
+     * 客户简称
+     */
+    private String shortName;
+
+    /**
+     * 分类(国内,国外)
+     */
+    private String fClass;
+
+    /**
+     * 销售部门
+     */
+    private String saleDept;
+
+    /**
+     * 业务员
+     */
+    private String saleMan;
+
+    /**
+     * 负责人
+     */
+    private String dutyMan;
+
+    /**
+     * 付款方式
+     */
+    private String payMode;
+
+    /**
+     * 信用额度
+     */
+    private BigDecimal creditAmt;
+
+    /**
+     * 信用等级
+     */
+    private String creditRating;
+
+    /**
+     * 联系人
+     */
+    private String contactMan;
+
+    /**
+     * 地址
+     */
+    private String contactAddr;
+
+    /**
+     * 电话
+     */
+    private String contactTel;
+
+    /**
+     * 手机
+     */
+    private String contactMobile;
+
+    /**
+     * 邮箱
+     */
+    private String contactEmail;
+
+    /**
+     * 公司ID
+     */
+    private Integer companyId;
+
+    /**
+     * 暂停使用(0正常 1停用)
+     */
+    private Integer stopUse;
+
+    /**
+     * 是否经销商
+     */
+    private Integer isDealer;
+
+    /**
+     * 铝材客户
+     */
+    private Integer isAlu;
+
+    /**
+     * 铝模客户
+     */
+    private Integer isAluPlate;
+
+    /**
+     * 首单日期
+     */
+    private Date firstDate;
+
+    /**
+     * 创建人
+     */
+    private String enterName;
+
+    /**
+     * 创建时间
+     */
+    private Date enterDate;
+
+}

+ 13 - 0
ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/mapper/ErpClientMapper.java

@@ -0,0 +1,13 @@
+package org.dromara.yingpaipay.mapper;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.yingpaipay.domain.ErpClient;
+import org.dromara.yingpaipay.domain.vo.ErpClientVo;
+
+/**
+ * HTSail_Alu 客户档案 Mapper
+ */
+@DS("htsail_alu")
+public interface ErpClientMapper extends BaseMapperPlus<ErpClient, ErpClientVo> {
+}

+ 23 - 0
ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/service/IErpClientService.java

@@ -0,0 +1,23 @@
+package org.dromara.yingpaipay.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.yingpaipay.domain.query.ErpClientQuery;
+import org.dromara.yingpaipay.domain.vo.ErpClientVo;
+
+/**
+ * HTSail_Alu 客户档案 Service
+ */
+public interface IErpClientService {
+
+    /**
+     * 分页查询客户列表
+     */
+    TableDataInfo<ErpClientVo> queryPageList(ErpClientQuery query, PageQuery pageQuery);
+
+    /**
+     * 根据主键查询客户详情
+     */
+    ErpClientVo queryById(String fRowId);
+
+}

+ 70 - 0
ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/yingpaipay/service/impl/ErpClientServiceImpl.java

@@ -0,0 +1,70 @@
+package org.dromara.yingpaipay.service.impl;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.yingpaipay.domain.ErpClient;
+import org.dromara.yingpaipay.domain.query.ErpClientQuery;
+import org.dromara.yingpaipay.domain.vo.ErpClientVo;
+import org.dromara.yingpaipay.mapper.ErpClientMapper;
+import org.dromara.yingpaipay.api.erp.CommonErpClientService;
+import org.dromara.yingpaipay.service.IErpClientService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * HTSail_Alu 客户档案 Service实现
+ *
+ * @Author: Antigravity
+ */
+@DS("htsail_alu")
+@RequiredArgsConstructor
+@Service
+public class ErpClientServiceImpl implements IErpClientService, CommonErpClientService {
+
+    private final ErpClientMapper baseMapper;
+
+    @Override
+    public Map<String, String> selectNameByFNums(List<String> authClientFNums) {
+        if (authClientFNums == null || authClientFNums.isEmpty()) {
+            return Map.of();
+        }
+        List<ErpClient> clients = baseMapper.selectList(Wrappers.lambdaQuery(ErpClient.class)
+            .select(ErpClient::getFNum, ErpClient::getFName)
+            .in(ErpClient::getFNum, authClientFNums));
+        return clients.stream().collect(Collectors.toMap(ErpClient::getFNum, ErpClient::getFName, (v1, v2) -> v1));
+    }
+
+    @Override
+    public TableDataInfo<ErpClientVo> queryPageList(ErpClientQuery query, PageQuery pageQuery) {
+        LambdaQueryWrapper<ErpClient> lqw = buildQueryWrapper(query);
+        Page<ErpClientVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    @Override
+    public ErpClientVo queryById(String fRowId) {
+        return baseMapper.selectVoById(fRowId);
+    }
+
+    private LambdaQueryWrapper<ErpClient> buildQueryWrapper(ErpClientQuery query) {
+        LambdaQueryWrapper<ErpClient> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(query.getFName()), ErpClient::getFName, query.getFName());
+        lqw.like(StringUtils.isNotBlank(query.getFNum()), ErpClient::getFNum, query.getFNum());
+        lqw.like(StringUtils.isNotBlank(query.getShortName()), ErpClient::getShortName, query.getShortName());
+        lqw.like(StringUtils.isNotBlank(query.getPyCode()), ErpClient::getPyCode, query.getPyCode());
+        lqw.eq(StringUtils.isNotBlank(query.getFClass()), ErpClient::getFClass, query.getFClass());
+        lqw.eq(query.getStopUse() != null, ErpClient::getStopUse, query.getStopUse());
+        lqw.orderByAsc(ErpClient::getFNum);
+        return lqw;
+    }
+
+}

+ 41 - 2
script/sql/sqlserver/v1/create.sql

@@ -35,7 +35,7 @@ create table sys_customer
     phone              nvarchar(11)      DEFAULT ('') NULL,
     wechat_openid      nvarchar(255)     DEFAULT ('') NULL,
     wechat_unionid     nvarchar(255)     DEFAULT ('') NULL,
-    auth_customer_id   nvarchar(255)     DEFAULT ('') NULL,
+    auth_client_fnum   nvarchar(100)     DEFAULT ('') NULL,
     avatar             bigint            DEFAULT (NULL) NULL,
     tenant_id          nvarchar(20)      DEFAULT ('000000') NULL,
     create_dept        bigint,
@@ -85,7 +85,7 @@ EXEC sys.sp_addextendedproperty
     'MS_Description', N'授权客户ID' ,
     'SCHEMA', N'dbo',
     'TABLE', N'sys_customer',
-    'COLUMN', N'auth_customer_id'
+    'COLUMN', N'auth_client_fnum'
 GO
 EXEC sys.sp_addextendedproperty
     'MS_Description', N'头像OSS ID' ,
@@ -140,3 +140,42 @@ EXEC sys.sp_addextendedproperty
     'SCHEMA', N'dbo',
     'TABLE', N'sys_customer'
 GO
+
+-- ----------------------------
+-- 投诉建议表
+-- ----------------------------
+create table sys_complaint
+(
+    id              bigint            NOT NULL,
+    feedback_type   nvarchar(50)      DEFAULT ('') NULL,
+    content         nvarchar(MAX)     DEFAULT ('') NULL,
+    images          nvarchar(MAX)     DEFAULT ('') NULL,
+    customer_id     bigint            DEFAULT (NULL) NULL,
+    tenant_id       nvarchar(20)      DEFAULT ('000000') NULL,
+    create_dept     bigint,
+    create_by       bigint,
+    create_time     datetime2(7),
+    update_by       bigint,
+    update_time     datetime2(7),
+    del_flag        nchar             DEFAULT ('0') NULL,
+    CONSTRAINT PK__sys_complaint__id PRIMARY KEY CLUSTERED (id)
+    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+    ON [PRIMARY]
+)
+ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty 'MS_Description', N'投诉建议ID', 'SCHEMA', N'dbo', 'TABLE', N'sys_complaint', 'COLUMN', N'id'
+GO
+EXEC sys.sp_addextendedproperty 'MS_Description', N'反馈类型(字典值)', 'SCHEMA', N'dbo', 'TABLE', N'sys_complaint', 'COLUMN', N'feedback_type'
+GO
+EXEC sys.sp_addextendedproperty 'MS_Description', N'反馈内容', 'SCHEMA', N'dbo', 'TABLE', N'sys_complaint', 'COLUMN', N'content'
+GO
+EXEC sys.sp_addextendedproperty 'MS_Description', N'图片OSS ID列表(逗号拼接字符串,如 1,2,3)', 'SCHEMA', N'dbo', 'TABLE', N'sys_complaint', 'COLUMN', N'images'
+GO
+EXEC sys.sp_addextendedproperty 'MS_Description', N'投诉客户ID', 'SCHEMA', N'dbo', 'TABLE', N'sys_complaint', 'COLUMN', N'customer_id'
+GO
+EXEC sys.sp_addextendedproperty 'MS_Description', N'租户ID', 'SCHEMA', N'dbo', 'TABLE', N'sys_complaint', 'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty 'MS_Description', N'投诉建议表', 'SCHEMA', N'dbo', 'TABLE', N'sys_complaint'
+GO

+ 1 - 0
yingpaipay-api/pom.xml

@@ -10,6 +10,7 @@
     <modelVersion>4.0.0</modelVersion>
 
     <modules>
+        <module>yingpaipay-api-erp</module>
     </modules>
 
     <artifactId>yingpaipay-api</artifactId>

+ 31 - 0
yingpaipay-api/yingpaipay-api-bom/pom.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.dromara</groupId>
+    <artifactId>yingpaipay-api-bom</artifactId>
+    <version>${revision}</version>
+    <packaging>pom</packaging>
+
+    <description>
+        yingpaipay-api-bom 盈派支付 API 依赖项版本管理
+    </description>
+
+    <properties>
+        <revision>5.6.1</revision>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <!-- ERP 模块接口 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>yingpaipay-api-erp</artifactId>
+                <version>${revision}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+</project>

+ 18 - 0
yingpaipay-api/yingpaipay-api-erp/pom.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>yingpaipay-api</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>yingpaipay-api-erp</artifactId>
+
+    <description>
+        盈派支付 - ERP 模块跨模块接口定义
+    </description>
+
+</project>

+ 20 - 0
yingpaipay-api/yingpaipay-api-erp/src/main/java/org/dromara/yingpaipay/api/erp/CommonErpClientService.java

@@ -0,0 +1,20 @@
+package org.dromara.yingpaipay.api.erp;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * ERP 客户公共服务接口
+ *
+ * @Author: Antigravity
+ */
+public interface CommonErpClientService {
+
+    /**
+     * 根据授权客户编码列表查询客户名称映射
+     *
+     * @param authClientFNums 授权客户编码列表 (FNum)
+     * @return Map<编码, 名称>
+     */
+    Map<String, String> selectNameByFNums(List<String> authClientFNums);
+}