diff --git a/dl_admin/ruoyi-admin/pom.xml b/dl_admin/ruoyi-admin/pom.xml
index 6595d34..cbfa14f 100644
--- a/dl_admin/ruoyi-admin/pom.xml
+++ b/dl_admin/ruoyi-admin/pom.xml
@@ -133,6 +133,12 @@
spring-websocket
5.3.31
+
+
+ org.lionsoul
+ ip2region
+ 2.7.0
+
diff --git a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/base/controller/WebController.java b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/base/controller/WebController.java
index 08f6ead..6d8561c 100644
--- a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/base/controller/WebController.java
+++ b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/base/controller/WebController.java
@@ -3,14 +3,18 @@ package com.ruoyi.base.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.base.domain.BaseInquiry;
import com.ruoyi.base.domain.BasePic;
import com.ruoyi.base.domain.BaseSiteInfo;
+import com.ruoyi.base.service.IBaseInquiryService;
import com.ruoyi.base.service.IBasePicService;
import com.ruoyi.base.service.IBaseSiteInfoService;
import com.ruoyi.busi.domain.BusiCategory;
+import com.ruoyi.busi.domain.BusiInquiryItem;
import com.ruoyi.busi.domain.BusiProdNew;
import com.ruoyi.busi.service.IBusiCategoryService;
import com.ruoyi.busi.service.IBusiProdNewService;
+import com.ruoyi.busi.utils.CommonUtils;
import com.ruoyi.busi.vo.BusiCategoryVO;
import com.ruoyi.busi.vo.ProdNewVO;
import com.ruoyi.busi.vo.WebDetailVO;
@@ -27,8 +31,11 @@ import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.HttpRequestHandler;
import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
@@ -48,11 +55,15 @@ public class WebController extends BaseController {
@Autowired
private IBasePicService basePicService;
@Autowired
+ private IBaseInquiryService baseInquiryService;
+ @Autowired
private IBusiCategoryService categoryService;
@Autowired
private IBaseSiteInfoService siteInfoService;
@Autowired
private IBusiProdNewService prodNewService;
+ @Autowired
+ private CommonUtils commonUtils;
/**
* 导航栏接口--所有分类
@@ -286,4 +297,43 @@ public class WebController extends BaseController {
Page page = new Page<>(pageNum,pageSize);
return R.ok(prodNewService.searchTextAll(tenantId,text,page));
}
+
+ /**
+ * 查询盘设置-都有哪些字段需要填写,是否必填
+ * @author vinjor-M
+ * @date 10:04 2025/7/8
+ * @return com.ruoyi.common.core.domain.AjaxResult
+ **/
+ @ApiOperation("查询盘设置-都有哪些字段需要填写,是否必填")
+ @ApiImplicitParam(name = "tenantId", value = "站点唯一码", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
+ @GetMapping("/inquirySet")
+ public R inquirySet(@RequestParam(required = true) String tenantId, HttpServletRequest request){
+ String ip = CommonUtils.getIpAddr(request);
+ System.out.println(ip);
+ System.out.println(CommonUtils.getAddr(ip));
+ return R.ok(baseInquiryService.getInquiry(tenantId));
+ }
+
+ /**
+ * 提交在线询盘表单
+ * @author vinjor-M
+ * @date 10:04 2025/7/8
+ * @return com.ruoyi.common.core.domain.AjaxResult
+ **/
+ @ApiOperation("提交在线询盘表单")
+ @ApiImplicitParams(value = {
+ @ApiImplicitParam(name = "companyName", value = "公司名称", required = false, paramType = "body"),
+ @ApiImplicitParam(name = "name", value = "姓名", required = false, paramType = "body"),
+ @ApiImplicitParam(name = "tel", value = "电话或WhatsApp", required = false, paramType = "body"),
+ @ApiImplicitParam(name = "title", value = "标题", required = false, paramType = "body"),
+ @ApiImplicitParam(name = "content", value = "内容", required = true, paramType = "body"),
+ @ApiImplicitParam(name = "email", value = "email", required = false, paramType = "body"),
+ @ApiImplicitParam(name = "tenantId", value = "公司名称", required = true, paramType = "body")
+ })
+ @PostMapping("/inquirySave")
+ public R inquirySave(@ApiIgnore @RequestBody BusiInquiryItem inquiryItem, HttpServletRequest request){
+ String ip = CommonUtils.getIpAddr(request);
+ System.out.println(CommonUtils.getAddr(ip));
+ return R.ok();
+ }
}
diff --git a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/base/domain/BaseInquiry.java b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/base/domain/BaseInquiry.java
index 0b2f875..939d1d7 100644
--- a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/base/domain/BaseInquiry.java
+++ b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/base/domain/BaseInquiry.java
@@ -4,6 +4,8 @@ import com.ruoyi.common.annotation.Excel;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import com.ruoyi.common.core.domain.DlBaseEntity;
@@ -20,52 +22,74 @@ import com.ruoyi.common.core.domain.DlBaseEntity;
@Builder
@NoArgsConstructor
@AllArgsConstructor
+@ApiModel(value = "BaseInquiry", description = "询盘设置实体")
public class BaseInquiry extends DlBaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键 */
@TableId(type = IdType.ASSIGN_UUID)
+ @ApiModelProperty("主键")
private String id;
/** 是否开启填写公司名称 */
@Excel(name = "公司名称")
+ @ApiModelProperty("公司名称字段是否显示")
private Boolean company;
/** 公司名称是否必填 */
@Excel(name = "公司名称是否必填")
+ @ApiModelProperty("公司名称是否必填")
private Boolean companyMust;
+ /** 是否开启填写email */
+ @Excel(name = "是否开启填写email")
+ @ApiModelProperty("email字段是否显示")
+ private Boolean email;
+
+ /** email是否必填 */
+ @Excel(name = "email是否必填")
+ @ApiModelProperty("email字段是否必填")
+ private Boolean emailMust;
+
/** 是否开启填写电话/WhatsApp */
@Excel(name = "电话/WhatsApp")
+ @ApiModelProperty("电话/WhatsApp字段是否显示")
private Boolean tel;
/** 是否必填 */
@Excel(name = "是否必填")
+ @ApiModelProperty("电话/WhatsApp字段是否必填")
private Boolean telMust;
/** 是否开启填写标题 */
@Excel(name = "标题")
+ @ApiModelProperty("标题字段是否显示")
private Boolean title;
/** 是否必填 */
@Excel(name = "是否必填")
+ @ApiModelProperty("标题字段是否必填")
private Boolean titleMust;
/** 是否开启填写姓名 */
@Excel(name = "姓名")
+ @ApiModelProperty("姓名字段是否显示")
private Boolean name;
/** 是否必填 */
@Excel(name = "是否必填")
+ @ApiModelProperty("姓名字段是否必填")
private Boolean nameMust;
/** 提示文字(内容) */
@Excel(name = "提示文字", readConverterExp = "内=容")
+ @ApiModelProperty("提示文字(以placeholder形式显示在多行文本框中,要求输入内容时,这个提示以其他方式显示在多行文本框上方或下方)")
private String content;
/** 站点唯一编码(租户id) */
@Excel(name = "站点唯一编码", readConverterExp = "租=户id")
+ @ApiModelProperty("站点唯一编码")
private String tenantId;
}
diff --git a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/controller/BusiInquiryItemController.java b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/controller/BusiInquiryItemController.java
new file mode 100644
index 0000000..1a8dbce
--- /dev/null
+++ b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/controller/BusiInquiryItemController.java
@@ -0,0 +1,112 @@
+package com.ruoyi.busi.controller;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.busi.domain.BusiInquiryItem;
+import com.ruoyi.busi.service.IBusiInquiryItemService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 在线询盘记录Controller
+ *
+ * @author vinjor-m
+ * @date 2025-07-10
+ */
+@RestController
+@RequestMapping("/busi/inquiryItem")
+public class BusiInquiryItemController extends BaseController
+{
+ @Autowired
+ private IBusiInquiryItemService busiInquiryItemService;
+
+ /**
+ * 查询在线询盘记录列表
+ */
+ @PreAuthorize("@ss.hasPermi('busi:inquiryItem:list')")
+ @GetMapping("/list")
+ public AjaxResult list(BusiInquiryItem busiInquiryItem,
+ @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum,
+ @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize)
+ {
+ Page page = new Page<>(pageNum, pageSize);
+ IPage list = busiInquiryItemService.queryListPage(busiInquiryItem,page);
+ return success(list);
+ }
+
+ /**
+ * 导出在线询盘记录列表
+ */
+ @PreAuthorize("@ss.hasPermi('busi:inquiryItem:export')")
+ @Log(title = "在线询盘记录", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, BusiInquiryItem busiInquiryItem)
+ {
+ List list = busiInquiryItemService.list();
+ ExcelUtil util = new ExcelUtil(BusiInquiryItem.class);
+ util.exportExcel(response, list, "在线询盘记录数据");
+ }
+
+ /**
+ * 获取在线询盘记录详细信息
+ */
+ @PreAuthorize("@ss.hasPermi('busi:inquiryItem:query')")
+ @GetMapping(value = "/{id}")
+ public AjaxResult getInfo(@PathVariable("id") String id)
+ {
+ return success(busiInquiryItemService.getById(id));
+ }
+
+ /**
+ * 新增在线询盘记录
+ */
+ @PreAuthorize("@ss.hasPermi('busi:inquiryItem:add')")
+ @Log(title = "在线询盘记录", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BusiInquiryItem busiInquiryItem)
+ {
+ return toAjax(busiInquiryItemService.save(busiInquiryItem));
+ }
+
+ /**
+ * 修改在线询盘记录
+ */
+ @PreAuthorize("@ss.hasPermi('busi:inquiryItem:edit')")
+ @Log(title = "在线询盘记录", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BusiInquiryItem busiInquiryItem)
+ {
+ return toAjax(busiInquiryItemService.updateById(busiInquiryItem));
+ }
+
+ /**
+ * 删除在线询盘记录
+ */
+ @PreAuthorize("@ss.hasPermi('busi:inquiryItem:remove')")
+ @Log(title = "在线询盘记录", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ List list = new ArrayList<>(Arrays.asList(ids));
+ return toAjax(busiInquiryItemService.removeByIds(list));
+ }
+}
diff --git a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/domain/BusiInquiryItem.java b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/domain/BusiInquiryItem.java
new file mode 100644
index 0000000..9128b66
--- /dev/null
+++ b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/domain/BusiInquiryItem.java
@@ -0,0 +1,88 @@
+package com.ruoyi.busi.domain;
+
+import com.ruoyi.common.annotation.Excel;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.*;
+import com.ruoyi.common.core.domain.DlBaseEntity;
+
+/**
+ * 在线询盘记录对象 dl_busi_inquiry_item
+ *
+ * @author vinjor-m
+ * @date 2025-07-10
+ */
+@TableName("dl_busi_inquiry_item")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@ApiModel(value = "BusiInquiryItem", description = "在线询盘实体")
+public class BusiInquiryItem extends DlBaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 主键 */
+ @TableId(type = IdType.ASSIGN_UUID)
+ private String id;
+
+ /** 公司名称 */
+ @Excel(name = "公司名称")
+ @ApiModelProperty("公司名称")
+ private String companyName;
+
+ /** 姓名 */
+ @Excel(name = "姓名")
+ @ApiModelProperty("姓名")
+ private String name;
+
+ /** 电话 */
+ @Excel(name = "电话")
+ @ApiModelProperty("电话")
+ private String tel;
+
+ /** 标题 */
+ @Excel(name = "标题")
+ @ApiModelProperty("标题")
+ private String title;
+
+ /** 内容 */
+ @Excel(name = "内容")
+ @ApiModelProperty("内容")
+ private String content;
+
+ /** 电子邮件 */
+ @Excel(name = "电子邮件")
+ @ApiModelProperty("电子邮件")
+ private String email;
+
+ /** 来源IP */
+ @Excel(name = "来源IP")
+ @ApiModelProperty("来源IP")
+ private String ip;
+
+ /** 来源国家 */
+ @Excel(name = "来源国家")
+ @ApiModelProperty("来源国家")
+ private String national;
+
+ /** 洲 */
+ @Excel(name = "洲")
+ @ApiModelProperty("洲")
+ private String oceania;
+
+ /** 页面路径 */
+ @Excel(name = "页面路径")
+ private String pageUrl;
+
+ /** 站点唯一编码(租户id) */
+ @Excel(name = "站点唯一编码", readConverterExp = "租=户id")
+ @ApiModelProperty("站点唯一编码")
+ private String tenantId;
+
+}
diff --git a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/mapper/BusiInquiryItemMapper.java b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/mapper/BusiInquiryItemMapper.java
new file mode 100644
index 0000000..e7b27b0
--- /dev/null
+++ b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/mapper/BusiInquiryItemMapper.java
@@ -0,0 +1,21 @@
+package com.ruoyi.busi.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.busi.domain.BusiInquiryItem;
+import org.apache.ibatis.annotations.Param;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 在线询盘记录Mapper接口
+ *
+ * @author vinjor-m
+ * @date 2025-07-10
+ */
+@Mapper
+public interface BusiInquiryItemMapper extends BaseMapper
+{
+ IPage queryListPage(@Param("entity") BusiInquiryItem entity, Page page);
+}
diff --git a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/service/IBusiInquiryItemService.java b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/service/IBusiInquiryItemService.java
new file mode 100644
index 0000000..e46991e
--- /dev/null
+++ b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/service/IBusiInquiryItemService.java
@@ -0,0 +1,18 @@
+package com.ruoyi.busi.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.busi.domain.BusiInquiryItem;
+
+/**
+ * 在线询盘记录Service接口
+ *
+ * @author vinjor-m
+ * @date 2025-07-10
+ */
+public interface IBusiInquiryItemService extends IService
+{
+ IPage queryListPage(BusiInquiryItem pageReqVO, Page page);
+}
diff --git a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/service/impl/BusiInquiryItemServiceImpl.java b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/service/impl/BusiInquiryItemServiceImpl.java
new file mode 100644
index 0000000..fbd9356
--- /dev/null
+++ b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/service/impl/BusiInquiryItemServiceImpl.java
@@ -0,0 +1,30 @@
+package com.ruoyi.busi.service.impl;
+
+import java.util.List;
+import com.ruoyi.common.utils.DateUtils;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.busi.mapper.BusiInquiryItemMapper;
+import com.ruoyi.busi.domain.BusiInquiryItem;
+import com.ruoyi.busi.service.IBusiInquiryItemService;
+
+/**
+ * 在线询盘记录Service业务层处理
+ *
+ * @author vinjor-m
+ * @date 2025-07-10
+ */
+@Service
+public class BusiInquiryItemServiceImpl extends ServiceImpl implements IBusiInquiryItemService
+{
+ @Autowired
+ private BusiInquiryItemMapper busiInquiryItemMapper;
+
+ @Override
+ public IPage queryListPage(BusiInquiryItem pageReqVO, Page page) {
+ return busiInquiryItemMapper.queryListPage(pageReqVO, page);
+ }
+}
diff --git a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/utils/CommonUtils.java b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/utils/CommonUtils.java
new file mode 100644
index 0000000..4b9a5f1
--- /dev/null
+++ b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/utils/CommonUtils.java
@@ -0,0 +1,79 @@
+package com.ruoyi.busi.utils;
+import cn.hutool.core.util.StrUtil;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.util.IOUtils;
+import org.lionsoul.ip2region.xdb.Searcher;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.*;
+import java.util.stream.Collectors;
+/**
+ * 通用方法
+ * @author 马文杰
+ * @version 1.0
+ */
+@Component
+@Slf4j
+public class CommonUtils {
+
+ private static final String UNKNOWN = "unknown";
+
+ /**
+ * 获取 IP地址
+ * 使用 Nginx等反向代理软件, 则不能通过 request.getRemoteAddr()获取 IP地址
+ * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,
+ * X-Forwarded-For中第一个非 unknown的有效IP字符串,则为真实IP地址
+ */
+ public static String getIpAddr(HttpServletRequest request) {
+ String ip = request.getHeader("x-forwarded-for");
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getRemoteAddr();
+ }
+ return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
+ }
+
+ @SneakyThrows
+ public static String getAddr(String ip){
+ ClassPathResource resource = new ClassPathResource("ip2region.xdb");
+ InputStream inputStream = resource.getInputStream();
+ String dbPath = "src/main/resources/ip2region.xdb";
+ // 1、从 dbPath 加载整个 xdb 到内存。
+ byte[] cBuff;
+ try {
+ cBuff = IOUtils.toByteArray(inputStream);
+ } catch (Exception e) {
+ log.info("failed to load content from %s: %s\n", dbPath, e);
+ return null;
+ }
+
+ // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
+ Searcher searcher;
+ try {
+ searcher = Searcher.newWithBuffer(cBuff);
+ } catch (Exception e) {
+ log.info("failed to create content cached searcher: %s\n", e);
+ return null;
+ }
+ // 3、查询
+ try {
+ String region = searcher.search(ip);
+ return region;
+ } catch (Exception e) {
+ log.info("failed to search(%s): %s\n", ip, e);
+ }
+ return null;
+ }
+
+}
diff --git a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/utils/NoticeUtils.java b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/utils/NoticeUtils.java
deleted file mode 100644
index 0737c58..0000000
--- a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/busi/utils/NoticeUtils.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.ruoyi.busi.utils;
-import cn.hutool.core.util.StrUtil;
-import org.springframework.stereotype.Component;
-
-import java.util.*;
-import java.util.stream.Collectors;
-/**
- * 文本相似度对比
- * @author 朱春云
- * @version 1.0
- */
-@Component
-public class NoticeUtils {
-
- /**
- * 比较两个文本字符串的相似度
- * @param str1 文本1
- * @param str2 文本2
- * @return 相似度值,范围在0到1之间,值越大相似度越高
- */
- public static double computeJaccardSimilarity(String str1, String str2) {
- if (str1 == null || str2 == null || (str1.isEmpty() && str2.isEmpty())) {
- return 1.0; // 空字符串认为完全相同
- }
- if (str1.isEmpty() || str2.isEmpty()) {
- return 0.0; // 一个为空另一个非空,认为完全不同
- }
-
- Set set1 = Arrays.stream(str1.split("\\s+")).collect(Collectors.toSet());
- Set set2 = Arrays.stream(str2.split("\\s+")).collect(Collectors.toSet());
-
- Set intersection = new HashSet<>(set1);
- intersection.retainAll(set2);
-
- Set union = new HashSet<>(set1);
- union.addAll(set2); // 正确的并集
-
- if (union.isEmpty()) {
- return 0.0; // 安全处理,避免除以零
- }
-
- return (double) intersection.size() / union.size();
- }
-
- /**
- * 翻译通告的博主类型字典
- * @author vinjor-M
- * @date 17:10 2025/3/25
- * @return java.lang.String
- **/
- public String translateBloggerTypes(String bloggerTypes, Map categoryMap){
- List rtnList = new ArrayList<>();
- List bloggerTypeList = Arrays.asList(bloggerTypes.split(StrUtil.COMMA));
- bloggerTypeList.forEach(item->{
- if(categoryMap.get(item)!=null){
- rtnList.add(categoryMap.get(item));
- }
- });
- return String.join(" ",rtnList);
- }
-
-
-}
diff --git a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/xdb/Header.java b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/xdb/Header.java
new file mode 100644
index 0000000..c1c6839
--- /dev/null
+++ b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/xdb/Header.java
@@ -0,0 +1,38 @@
+// Copyright 2022 The Ip2Region Authors. All rights reserved.
+// Use of this source code is governed by a Apache2.0-style
+// license that can be found in the LICENSE file.
+// @Author Lion
+// @Date 2022/06/23
+
+package com.ruoyi.xdb;
+
+import org.lionsoul.ip2region.xdb.Searcher;
+
+public class Header {
+ public final int version;
+ public final int indexPolicy;
+ public final int createdAt;
+ public final int startIndexPtr;
+ public final int endIndexPtr;
+ public final byte[] buffer;
+
+ public Header(byte[] buff) {
+ assert buff.length >= 16;
+ version = Searcher.getInt2(buff, 0);
+ indexPolicy = Searcher.getInt2(buff, 2);
+ createdAt = Searcher.getInt(buff, 4);
+ startIndexPtr = Searcher.getInt(buff, 8);
+ endIndexPtr = Searcher.getInt(buff, 12);
+ buffer = buff;
+ }
+
+ @Override public String toString() {
+ return "{" +
+ "Version: " + version + ',' +
+ "IndexPolicy: " + indexPolicy + ',' +
+ "CreatedAt: " + createdAt + ',' +
+ "StartIndexPtr: " + startIndexPtr + ',' +
+ "EndIndexPtr: " + endIndexPtr +
+ '}';
+ }
+}
diff --git a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/xdb/Searcher.java b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/xdb/Searcher.java
new file mode 100644
index 0000000..6bc6512
--- /dev/null
+++ b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/xdb/Searcher.java
@@ -0,0 +1,281 @@
+// Copyright 2022 The Ip2Region Authors. All rights reserved.
+// Use of this source code is governed by a Apache2.0-style
+// license that can be found in the LICENSE file.
+
+package com.ruoyi.xdb;
+
+// xdb searcher (Not thread safe implementation)
+// @Author Lion
+// @Date 2022/06/23
+
+
+import org.lionsoul.ip2region.xdb.Header;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+public class Searcher {
+ // constant defined copied from the xdb maker
+ public static final int HeaderInfoLength = 256;
+ public static final int VectorIndexRows = 256;
+ public static final int VectorIndexCols = 256;
+ public static final int VectorIndexSize = 8;
+ public static final int SegmentIndexSize = 14;
+
+ // random access file handle for file based search
+ private final RandomAccessFile handle;
+
+ private int ioCount = 0;
+
+ // vector index.
+ // use the byte[] instead of VectorIndex entry array to keep
+ // the minimal memory allocation.
+ private final byte[] vectorIndex;
+
+ // xdb content buffer, used for in-memory search
+ private final byte[] contentBuff;
+
+ // --- static method to create searchers
+
+ public static Searcher newWithFileOnly(String dbPath) throws IOException {
+ return new Searcher(dbPath, null, null);
+ }
+
+ public static Searcher newWithVectorIndex(String dbPath, byte[] vectorIndex) throws IOException {
+ return new Searcher(dbPath, vectorIndex, null);
+ }
+
+ public static Searcher newWithBuffer(byte[] cBuff) throws IOException {
+ return new Searcher(null, null, cBuff);
+ }
+
+ // --- End of creator
+
+ public Searcher(String dbFile, byte[] vectorIndex, byte[] cBuff) throws IOException {
+ if (cBuff != null) {
+ this.handle = null;
+ this.vectorIndex = null;
+ this.contentBuff = cBuff;
+ } else {
+ this.handle = new RandomAccessFile(dbFile, "r");
+ this.vectorIndex = vectorIndex;
+ this.contentBuff = null;
+ }
+ }
+
+ public void close() throws IOException {
+ if (this.handle != null) {
+ this.handle.close();
+ }
+ }
+
+ public int getIOCount() {
+ return ioCount;
+ }
+
+ public String search(String ipStr) throws Exception {
+ long ip = checkIP(ipStr);
+ return search(ip);
+ }
+
+ public String search(long ip) throws IOException {
+ // reset the global counter
+ this.ioCount = 0;
+
+ // locate the segment index block based on the vector index
+ long sPtr = 0, ePtr = 0;
+ int il0 = (int) ((ip >> 24) & 0xFF);
+ int il1 = (int) ((ip >> 16) & 0xFF);
+ int idx = il0 * VectorIndexCols * VectorIndexSize + il1 * VectorIndexSize;
+ // System.out.printf("il0: %d, il1: %d, idx: %d\n", il0, il1, idx);
+ if (vectorIndex != null) {
+ sPtr = getIntLong(vectorIndex, idx);
+ ePtr = getIntLong(vectorIndex, idx + 4);
+ } else if (contentBuff != null) {
+ sPtr = getIntLong(contentBuff, HeaderInfoLength + idx);
+ ePtr = getIntLong(contentBuff, HeaderInfoLength + idx + 4);
+ } else {
+ final byte[] buff = new byte[VectorIndexSize];
+ read(HeaderInfoLength + idx, buff);
+ sPtr = getIntLong(buff, 0);
+ ePtr = getIntLong(buff, 4);
+ }
+
+ // System.out.printf("sPtr: %d, ePtr: %d\n", sPtr, ePtr);
+
+ // binary search the segment index block to get the region info
+ final byte[] buff = new byte[SegmentIndexSize];
+ int dataLen = -1;
+ long dataPtr = -1, l = 0, h = (ePtr - sPtr) / SegmentIndexSize;
+ while (l <= h) {
+ long m = (l + h) >> 1;
+ long p = sPtr + m * SegmentIndexSize;
+
+ // read the segment index
+ read(p, buff);
+ long sip = getIntLong(buff, 0);
+ if (ip < sip) {
+ h = m - 1;
+ } else {
+ long eip = getIntLong(buff, 4);
+ if (ip > eip) {
+ l = m + 1;
+ } else {
+ dataLen = getInt2(buff, 8);
+ dataPtr = getIntLong(buff, 10);
+ break;
+ }
+ }
+ }
+
+ // empty match interception
+ // System.out.printf("dataLen: %d, dataPtr: %d\n", dataLen, dataPtr);
+ if (dataPtr < 0) {
+ return null;
+ }
+
+ // load and return the region data
+ final byte[] regionBuff = new byte[dataLen];
+ read(dataPtr, regionBuff);
+ return new String(regionBuff, "utf-8");
+ }
+
+ protected void read(long offset, byte[] buffer) throws IOException {
+ // check the in-memory buffer first
+ if (contentBuff != null) {
+ // @TODO: reduce data copying, directly decode the data ?
+ // @TODO: added by Leon at 2025/06/10, when offset is negative and the content byte is not going to work.
+ // we need a better solution for the content buffer which is greater than (2^31 - 1 << 2)
+ int int_idx = (int) offset;
+ if (int_idx < 0) {
+ throw new IOException("No content buffer policy for NOW since the xdb is too large, use file or vectorIndex instead");
+ }
+
+ System.arraycopy(contentBuff, int_idx, buffer, 0, buffer.length);
+ return;
+ }
+
+ // read from the file handle
+ assert handle != null;
+ handle.seek(offset);
+
+ this.ioCount++;
+ int rLen = handle.read(buffer);
+ if (rLen != buffer.length) {
+ throw new IOException("incomplete read: read bytes should be " + buffer.length);
+ }
+ }
+
+ // --- static cache util function
+
+ public static org.lionsoul.ip2region.xdb.Header loadHeader(RandomAccessFile handle) throws IOException {
+ handle.seek(0);
+ final byte[] buff = new byte[HeaderInfoLength];
+ handle.read(buff);
+ return new org.lionsoul.ip2region.xdb.Header(buff);
+ }
+
+ public static org.lionsoul.ip2region.xdb.Header loadHeaderFromFile(String dbPath) throws IOException {
+ final RandomAccessFile handle = new RandomAccessFile(dbPath, "r");
+ final Header header = loadHeader(handle);
+ handle.close();
+ return header;
+ }
+
+ public static byte[] loadVectorIndex(RandomAccessFile handle) throws IOException {
+ handle.seek(HeaderInfoLength);
+ int len = VectorIndexRows * VectorIndexCols * VectorIndexSize;
+ final byte[] buff = new byte[len];
+ int rLen = handle.read(buff);
+ if (rLen != len) {
+ throw new IOException("incomplete read: read bytes should be " + len);
+ }
+
+ return buff;
+ }
+
+ public static byte[] loadVectorIndexFromFile(String dbPath) throws IOException {
+ final RandomAccessFile handle = new RandomAccessFile(dbPath, "r");
+ final byte[] vIndex = loadVectorIndex(handle);
+ handle.close();
+ return vIndex;
+ }
+
+ public static byte[] loadContent(RandomAccessFile handle) throws IOException {
+ handle.seek(0);
+ final byte[] buff = new byte[(int) handle.length()];
+ int rLen = handle.read(buff);
+ if (rLen != buff.length) {
+ throw new IOException("incomplete read: read bytes should be " + buff.length);
+ }
+
+ return buff;
+ }
+
+ public static byte[] loadContentFromFile(String dbPath) throws IOException {
+ final RandomAccessFile handle = new RandomAccessFile(dbPath, "r");
+ final byte[] content = loadContent(handle);
+ handle.close();
+ return content;
+ }
+
+ // --- End cache load util function
+
+ // --- static util method
+
+ /* get an int from a byte array start from the specified offset */
+ public static long getIntLong(byte[] b, int offset) {
+ return (
+ ((b[offset++] & 0x000000FFL)) |
+ ((b[offset++] << 8) & 0x0000FF00L) |
+ ((b[offset++] << 16) & 0x00FF0000L) |
+ ((b[offset ] << 24) & 0xFF000000L)
+ );
+ }
+
+ public static int getInt(byte[] b, int offset) {
+ return (
+ ((b[offset++] & 0x000000FF)) |
+ ((b[offset++] << 8) & 0x0000FF00) |
+ ((b[offset++] << 16) & 0x00FF0000) |
+ ((b[offset ] << 24) & 0xFF000000)
+ );
+ }
+
+ public static int getInt2(byte[] b, int offset) {
+ return (
+ ((b[offset++] & 0x000000FF)) |
+ ((b[offset ] << 8) & 0x0000FF00)
+ );
+ }
+
+ /* long int to ip string */
+ public static String long2ip( long ip )
+ {
+ return String.valueOf((ip >> 24) & 0xFF) + '.' +
+ ((ip >> 16) & 0xFF) + '.' + ((ip >> 8) & 0xFF) + '.' + ((ip) & 0xFF);
+ }
+
+ public static final byte[] shiftIndex = {24, 16, 8, 0};
+
+ /* check the specified ip address */
+ public static long checkIP(String ip) throws Exception {
+ String[] ps = ip.split("\\.");
+ if (ps.length != 4) {
+ throw new Exception("invalid ip address `" + ip + "`");
+ }
+
+ long ipDst = 0;
+ for (int i = 0; i < ps.length; i++) {
+ int val = Integer.parseInt(ps[i]);
+ if (val > 255) {
+ throw new Exception("ip part `"+ps[i]+"` should be less then 256");
+ }
+
+ ipDst |= ((long) val << shiftIndex[i]);
+ }
+
+ return ipDst & 0xFFFFFFFFL;
+ }
+
+}
\ No newline at end of file
diff --git a/dl_admin/ruoyi-admin/src/main/resources/ip2region.xdb b/dl_admin/ruoyi-admin/src/main/resources/ip2region.xdb
new file mode 100644
index 0000000..7052c05
Binary files /dev/null and b/dl_admin/ruoyi-admin/src/main/resources/ip2region.xdb differ
diff --git a/dl_admin/ruoyi-admin/src/main/resources/ip2region/ip2region.xdb b/dl_admin/ruoyi-admin/src/main/resources/ip2region/ip2region.xdb
new file mode 100644
index 0000000..7052c05
Binary files /dev/null and b/dl_admin/ruoyi-admin/src/main/resources/ip2region/ip2region.xdb differ
diff --git a/dl_admin/ruoyi-admin/src/main/resources/mapper/base/BaseInquiryMapper.xml b/dl_admin/ruoyi-admin/src/main/resources/mapper/base/BaseInquiryMapper.xml
index cb813a3..b4ffd1f 100644
--- a/dl_admin/ruoyi-admin/src/main/resources/mapper/base/BaseInquiryMapper.xml
+++ b/dl_admin/ruoyi-admin/src/main/resources/mapper/base/BaseInquiryMapper.xml
@@ -8,6 +8,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+
+
@@ -24,7 +26,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
- select id, company, company_must, tel, tel_must, title, title_must, name, name_must, content, tenant_id, creator, create_time, updater, update_time, del_flag from dl_base_inquiry
+ select id, company, company_must,email,email_must, tel, tel_must, title, title_must, name, name_must, content, tenant_id, creator, create_time, updater, update_time, del_flag from dl_base_inquiry