From 7582d22d2ad0b341d5ba4b7fd4135115349e6f19 Mon Sep 17 00:00:00 2001 From: van Date: Sat, 9 May 2026 23:27:52 +0800 Subject: [PATCH] 1 --- .../ruoyi/jarvis/domain/TgScalperPhone.java | 88 ++++++------- .../jarvis/mapper/TgScalperPhoneMapper.java | 5 +- .../impl/TgScalperPhoneServiceImpl.java | 119 +++++++++++++++--- .../mapper/jarvis/TgScalperPhoneMapper.xml | 26 ++-- sql/jarvis_tg_scalper_phone.sql | 10 +- ...s_tg_scalper_phone_phones_json_upgrade.sql | 21 ++++ 6 files changed, 183 insertions(+), 86 deletions(-) create mode 100644 sql/jarvis_tg_scalper_phone_phones_json_upgrade.sql diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/domain/TgScalperPhone.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/domain/TgScalperPhone.java index bcc1661..09e33a9 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/domain/TgScalperPhone.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/domain/TgScalperPhone.java @@ -1,12 +1,14 @@ package com.ruoyi.jarvis.domain; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.core.domain.BaseEntity; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** - * TG 黄牛电话库 jarvis_tg_scalper_phone + * TG黄牛电话库(开/慢开前置命中则不走TG,一条可含多个 11 位手机号) + * + * @author jarvis */ public class TgScalperPhone extends BaseEntity { @@ -14,11 +16,13 @@ public class TgScalperPhone extends BaseEntity private Long id; - /** 11位手机号 */ - @Excel(name = "手机号") - private String phone; + /** JSON 数组字符串,如 ["13800138000","13900139000"] */ + @Excel(name = "手机号数组") + private String phones; + + /** 列表查询条件:匹配号码(JSON 数组包含精确匹配,或 phones 文本模糊) */ + private String phoneQuery; - /** 命中时直接回复企微的备注 */ @Excel(name = "备注") private String remark; @@ -26,56 +30,36 @@ public class TgScalperPhone extends BaseEntity @Excel(name = "状态", readConverterExp = "0=禁用,1=启用") private Integer status; - public Long getId() - { - return id; - } + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date createTime; - public void setId(Long id) - { - this.id = id; - } + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; - public String getPhone() - { - return phone; - } - - public void setPhone(String phone) - { - this.phone = phone; - } - - public String getRemark() - { - return remark; - } - - public void setRemark(String remark) - { - this.remark = remark; - } - - public Integer getStatus() - { - return status; - } - - public void setStatus(Integer status) - { - this.status = status; - } + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + public String getPhones() { return phones; } + public void setPhones(String phones) { this.phones = phones; } + public String getPhoneQuery() { return phoneQuery; } + public void setPhoneQuery(String phoneQuery) { this.phoneQuery = phoneQuery; } + public String getRemark() { return remark; } + public void setRemark(String remark) { this.remark = remark; } + public Integer getStatus() { return status; } + public void setStatus(Integer status) { this.status = status; } + @Override + public Date getCreateTime() { return createTime; } + @Override + public void setCreateTime(Date createTime) { this.createTime = createTime; } + @Override + public Date getUpdateTime() { return updateTime; } + @Override + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) - .append("id", getId()) - .append("phone", getPhone()) - .append("remark", getRemark()) - .append("status", getStatus()) - .append("createTime", getCreateTime()) - .append("updateTime", getUpdateTime()) - .toString(); + return "TgScalperPhone{id=" + id + ", phones=" + phones + ", remark=" + remark + ", status=" + status + "}"; } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/TgScalperPhoneMapper.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/TgScalperPhoneMapper.java index 6fde8aa..d820321 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/TgScalperPhoneMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/TgScalperPhoneMapper.java @@ -1,6 +1,7 @@ package com.ruoyi.jarvis.mapper; import java.util.List; +import org.apache.ibatis.annotations.Param; import com.ruoyi.jarvis.domain.TgScalperPhone; /** @@ -12,8 +13,8 @@ public interface TgScalperPhoneMapper List selectTgScalperPhoneList(TgScalperPhone q); - /** 按手机号查(不限状态,供唯一性校验) */ - TgScalperPhone selectTgScalperPhoneByPhone(String phone); + /** 某号码是否已被其它行占用(JSON 数组含该号) */ + Long selectIdHavingPhone(@Param("excludeId") Long excludeId, @Param("cellPhone") String cellPhone); /** 启用状态下按手机号查(开/慢走前置) */ TgScalperPhone selectEnabledByPhone(String phone); diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/TgScalperPhoneServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/TgScalperPhoneServiceImpl.java index 000c9d4..d221ece 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/TgScalperPhoneServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/TgScalperPhoneServiceImpl.java @@ -1,10 +1,15 @@ package com.ruoyi.jarvis.service.impl; +import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import java.util.regex.Pattern; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.jarvis.domain.TgScalperPhone; import com.ruoyi.jarvis.mapper.TgScalperPhoneMapper; @@ -37,44 +42,41 @@ public class TgScalperPhoneServiceImpl implements ITgScalperPhoneService { return null; } - return tgScalperPhoneMapper.selectEnabledByPhone(phone.trim()); + String p = phone.trim(); + if (!MOBILE_11.matcher(p).matches()) + { + return null; + } + return tgScalperPhoneMapper.selectEnabledByPhone(p); } @Override public int insertTgScalperPhone(TgScalperPhone row) { - validatePhone(row.getPhone()); + String phonesJson = normalizePhonesJson(row.getPhones()); + row.setPhones(phonesJson); if (!StringUtils.hasText(row.getRemark())) { throw new ServiceException("备注不能为空"); } - TgScalperPhone exist = tgScalperPhoneMapper.selectTgScalperPhoneByPhone(row.getPhone().trim()); - if (exist != null) - { - throw new ServiceException("手机号已存在"); - } + assertNoPhoneConflictAcrossRows(null, phonesJson); if (row.getStatus() == null) { row.setStatus(1); } - row.setPhone(row.getPhone().trim()); return tgScalperPhoneMapper.insertTgScalperPhone(row); } @Override public int updateTgScalperPhone(TgScalperPhone row) { - validatePhone(row.getPhone()); + String phonesJson = normalizePhonesJson(row.getPhones()); + row.setPhones(phonesJson); if (!StringUtils.hasText(row.getRemark())) { throw new ServiceException("备注不能为空"); } - TgScalperPhone other = tgScalperPhoneMapper.selectTgScalperPhoneByPhone(row.getPhone().trim()); - if (other != null && !other.getId().equals(row.getId())) - { - throw new ServiceException("手机号已存在"); - } - row.setPhone(row.getPhone().trim()); + assertNoPhoneConflictAcrossRows(row.getId(), phonesJson); return tgScalperPhoneMapper.updateTgScalperPhone(row); } @@ -90,11 +92,92 @@ public class TgScalperPhoneServiceImpl implements ITgScalperPhoneService return tgScalperPhoneMapper.deleteTgScalperPhoneById(id); } - private static void validatePhone(String phone) + private void assertNoPhoneConflictAcrossRows(Long excludeId, String phonesJson) { - if (!StringUtils.hasText(phone) || !MOBILE_11.matcher(phone.trim()).matches()) + for (String cell : parseDistinctPhones(phonesJson)) { - throw new ServiceException("请输入正确的11位手机号"); + Long hit = tgScalperPhoneMapper.selectIdHavingPhone(excludeId, cell); + if (hit != null) + { + throw new ServiceException("手机号已在其他记录中出现:" + cell); + } } } + + /** 接受 JSON 数组字符串或非 JSON 的单个号码,规范为 JSON 数组字符串 */ + private static String normalizePhonesJson(String raw) + { + if (!StringUtils.hasText(raw)) + { + throw new ServiceException("请至少填写一个11位手机号"); + } + String s = raw.trim(); + List cells = new ArrayList<>(); + if (s.startsWith("[")) + { + try + { + JSONArray arr = JSON.parseArray(s); + for (int i = 0; i < arr.size(); i++) + { + Object o = arr.get(i); + if (o != null) + { + cells.add(String.valueOf(o).trim()); + } + } + } + catch (Exception e) + { + throw new ServiceException("phones 须为 JSON 数组,如 [\"13800138000\"]"); + } + } + else + { + for (String part : s.split("[,,;;\\s]+")) + { + String t = part.trim(); + if (StringUtils.hasText(t)) + { + cells.add(t); + } + } + } + Set uniq = new LinkedHashSet<>(); + for (String c : cells) + { + if (!MOBILE_11.matcher(c).matches()) + { + throw new ServiceException("请输入正确的11位手机号:" + c); + } + uniq.add(c); + } + if (uniq.isEmpty()) + { + throw new ServiceException("请至少填写一个11位手机号"); + } + return JSON.toJSONString(new ArrayList<>(uniq)); + } + + private static List parseDistinctPhones(String phonesJson) + { + List out = new ArrayList<>(); + try + { + JSONArray arr = JSON.parseArray(phonesJson); + for (int i = 0; i < arr.size(); i++) + { + Object o = arr.get(i); + if (o != null) + { + out.add(String.valueOf(o).trim()); + } + } + } + catch (Exception e) + { + throw new ServiceException("数据损坏:phones 非合法 JSON 数组"); + } + return out; + } } diff --git a/ruoyi-system/src/main/resources/mapper/jarvis/TgScalperPhoneMapper.xml b/ruoyi-system/src/main/resources/mapper/jarvis/TgScalperPhoneMapper.xml index 820eea0..8286bca 100644 --- a/ruoyi-system/src/main/resources/mapper/jarvis/TgScalperPhoneMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/jarvis/TgScalperPhoneMapper.xml @@ -6,7 +6,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + @@ -14,14 +14,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select id, phone, remark, status, create_time, update_time + select id, phones, remark, status, create_time, update_time from jarvis_tg_scalper_phone - + select id from jarvis_tg_scalper_phone + where JSON_CONTAINS(phones, JSON_QUOTE(#{cellPhone}), '$') + and id != #{excludeId} limit 1 insert into jarvis_tg_scalper_phone - phone, + phones, remark, status, create_time, - #{phone}, + #{phones}, #{remark}, #{status}, sysdate(), @@ -64,7 +70,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" update jarvis_tg_scalper_phone - phone = #{phone}, + phones = #{phones}, remark = #{remark}, status = #{status}, update_time = sysdate(), diff --git a/sql/jarvis_tg_scalper_phone.sql b/sql/jarvis_tg_scalper_phone.sql index 1d6a49c..6158901 100644 --- a/sql/jarvis_tg_scalper_phone.sql +++ b/sql/jarvis_tg_scalper_phone.sql @@ -1,19 +1,21 @@ -- TG 管理:黄牛电话库(企微「开」「慢开」命中则直接返回备注,不请求 Telegram) CREATE TABLE IF NOT EXISTS `jarvis_tg_scalper_phone` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', - `phone` varchar(11) NOT NULL COMMENT '11位手机号', + `phones` json NOT NULL COMMENT '11位手机号JSON数组,如 ["13800138000","13900139000"]', `remark` varchar(2000) NOT NULL COMMENT '命中时直接回复的备注', `status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '0禁用 1启用', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), - UNIQUE KEY `uk_phone` (`phone`), KEY `idx_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='TG黄牛电话库(开/慢开前置命中则不走TG)'; --- 菜单:挂在系统管理下(parent_id=2,与企微跟踪等同);执行后请为角色分配权限并清缓存 +-- 若表由旧版(含 phone 单列)创建,请执行 jarvis_tg_scalper_phone_phones_json_upgrade.sql + +-- 菜单:挂在「系统管理」下。 +-- 标准若依 ry_*.sql:menu_id=1 为系统管理目录,menu_id=2 为「系统监控」目录(勿把 2 当成系统管理)。 INSERT INTO sys_menu VALUES ( - 2120, 'TG管理-黄牛电话库', 2, 12, 'tgScalperPhone', 'jarvis/tgScalperPhone/index', '', '', 1, 0, 'C', '0', '0', + 2120, 'TG管理-黄牛电话库', 1, 12, 'tgScalperPhone', 'jarvis/tgScalperPhone/index', '', '', 1, 0, 'C', '0', '0', 'jarvis:tg:scalperPhone:list', 'phone', 'admin', sysdate(), '', NULL, '开/慢开前置匹配,命中则不请求 Telegram' ); INSERT INTO sys_menu VALUES ( diff --git a/sql/jarvis_tg_scalper_phone_phones_json_upgrade.sql b/sql/jarvis_tg_scalper_phone_phones_json_upgrade.sql new file mode 100644 index 0000000..be10f16 --- /dev/null +++ b/sql/jarvis_tg_scalper_phone_phones_json_upgrade.sql @@ -0,0 +1,21 @@ +-- 已从单列 phone 升级为 phones JSON 数组的库执行此脚本(仅迁移,不含建表) +-- 执行前请备份。 + +ALTER TABLE `jarvis_tg_scalper_phone` + ADD COLUMN `phones` JSON NULL COMMENT '11位手机号JSON数组' AFTER `id`; + +UPDATE `jarvis_tg_scalper_phone` +SET `phones` = JSON_ARRAY(`phone`) +WHERE `phones` IS NULL AND `phone` IS NOT NULL AND `phone` != ''; + +UPDATE `jarvis_tg_scalper_phone` +SET `phones` = JSON_ARRAY() +WHERE `phones` IS NULL; + +-- 若建表时未建唯一索引 uk_phone,请跳过本句或改为你的实际索引名 +ALTER TABLE `jarvis_tg_scalper_phone` DROP INDEX `uk_phone`; + +ALTER TABLE `jarvis_tg_scalper_phone` DROP COLUMN `phone`; + +ALTER TABLE `jarvis_tg_scalper_phone` + MODIFY COLUMN `phones` JSON NOT NULL COMMENT '11位手机号JSON数组,如 ["13800138000","13900139000"]';