fix: store risk rules per siteId instead of shared siteType
This commit is contained in:
@@ -15,6 +15,9 @@ public class RiskRule {
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@TableField("site_id")
|
||||
private String siteId;
|
||||
|
||||
@TableField("site_type")
|
||||
private String siteType;
|
||||
|
||||
|
||||
@@ -22,11 +22,22 @@ public class RiskRuleServiceImpl implements RiskRuleService {
|
||||
private final com.par.core.storage.CachedStorageService storageService;
|
||||
private static final ObjectMapper om = new ObjectMapper();
|
||||
|
||||
/** Find by siteId first, fallback to siteType for backward compat */
|
||||
private RiskRule findByIdentifier(String identifier) {
|
||||
// Try siteId first
|
||||
RiskRule rr = mapper.selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<RiskRule>()
|
||||
.eq(RiskRule::getSiteId, identifier).eq(RiskRule::getDeleted, 0)
|
||||
.orderByDesc(RiskRule::getId).last("limit 1"));
|
||||
if (rr != null) return rr;
|
||||
// Fallback to siteType
|
||||
return mapper.selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<RiskRule>()
|
||||
.eq(RiskRule::getSiteType, identifier).eq(RiskRule::getDeleted, 0)
|
||||
.orderByDesc(RiskRule::getId).last("limit 1"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getRules(String siteType) {
|
||||
RiskRule rr = mapper.selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<RiskRule>()
|
||||
.eq(RiskRule::getSiteType, siteType).eq(RiskRule::getDeleted, 0)
|
||||
.orderByDesc(RiskRule::getId).last("limit 1"));
|
||||
RiskRule rr = findByIdentifier(siteType);
|
||||
if (rr == null) return null;
|
||||
try {
|
||||
List<Map<String, Object>> rules = om.readValue(rr.getRulesJson(),
|
||||
@@ -37,16 +48,14 @@ public class RiskRuleServiceImpl implements RiskRuleService {
|
||||
result.put("rules", rules);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("解析风险规则失败 siteType={}", siteType, e);
|
||||
log.error("解析风险规则失败 key={}", siteType, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion(String siteType) {
|
||||
RiskRule rr = mapper.selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<RiskRule>()
|
||||
.eq(RiskRule::getSiteType, siteType).eq(RiskRule::getDeleted, 0)
|
||||
.orderByDesc(RiskRule::getId).last("limit 1"));
|
||||
RiskRule rr = findByIdentifier(siteType);
|
||||
return rr != null ? rr.getVersion() : 0;
|
||||
}
|
||||
|
||||
@@ -55,19 +64,17 @@ public class RiskRuleServiceImpl implements RiskRuleService {
|
||||
try {
|
||||
String json = om.writerWithDefaultPrettyPrinter().writeValueAsString(rules);
|
||||
int nextVer = getVersion(siteType) + 1;
|
||||
// 存 DB
|
||||
RiskRule rr = new RiskRule();
|
||||
rr.setSiteType(siteType);
|
||||
rr.setSiteId(siteType); // siteType param now carries the identifier (siteId)
|
||||
rr.setVersion(nextVer);
|
||||
rr.setRulesJson(json);
|
||||
mapper.insert(rr);
|
||||
// 存七牛云 + 本地缓存
|
||||
String storagePath = String.format("rules/%s/v%d.json", siteType, nextVer);
|
||||
storageService.store(storagePath, json);
|
||||
versionService.incrementByType(siteType);
|
||||
log.info("风险规则已保存: siteType={}, version={}, path={}", siteType, nextVer, storagePath);
|
||||
log.info("风险规则已保存: key={}, version={}, path={}", siteType, nextVer, storagePath);
|
||||
} catch (Exception e) {
|
||||
log.error("保存风险规则失败 siteType={}", siteType, e);
|
||||
log.error("保存风险规则失败 key={}", siteType, e);
|
||||
throw new RuntimeException("保存失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -75,8 +82,13 @@ public class RiskRuleServiceImpl implements RiskRuleService {
|
||||
@Override
|
||||
public List<Map<String, Object>> listVersions(String siteType) {
|
||||
var list = mapper.selectList(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<RiskRule>()
|
||||
.eq(RiskRule::getSiteType, siteType).eq(RiskRule::getDeleted, 0)
|
||||
.eq(RiskRule::getSiteId, siteType).eq(RiskRule::getDeleted, 0)
|
||||
.orderByDesc(RiskRule::getId));
|
||||
if (list.isEmpty()) {
|
||||
list = mapper.selectList(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<RiskRule>()
|
||||
.eq(RiskRule::getSiteType, siteType).eq(RiskRule::getDeleted, 0)
|
||||
.orderByDesc(RiskRule::getId));
|
||||
}
|
||||
List<Map<String, Object>> result = new ArrayList<>();
|
||||
for (var r : list) {
|
||||
result.add(Map.of("version", r.getVersion(), "createdAt", r.getCreatedAt() != null ? r.getCreatedAt().toString() : ""));
|
||||
@@ -87,13 +99,20 @@ public class RiskRuleServiceImpl implements RiskRuleService {
|
||||
@Override
|
||||
public String getVersionContent(String siteType, int version) {
|
||||
var r = mapper.selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<RiskRule>()
|
||||
.eq(RiskRule::getSiteType, siteType).eq(RiskRule::getVersion, version)
|
||||
.eq(RiskRule::getSiteId, siteType).eq(RiskRule::getVersion, version)
|
||||
.eq(RiskRule::getDeleted, 0));
|
||||
if (r == null) {
|
||||
r = mapper.selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<RiskRule>()
|
||||
.eq(RiskRule::getSiteType, siteType).eq(RiskRule::getVersion, version)
|
||||
.eq(RiskRule::getDeleted, 0));
|
||||
}
|
||||
return r != null ? r.getRulesJson() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRules(String siteType) {
|
||||
mapper.delete(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<RiskRule>()
|
||||
.eq(RiskRule::getSiteId, siteType).eq(RiskRule::getDeleted, 0));
|
||||
mapper.delete(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<RiskRule>()
|
||||
.eq(RiskRule::getSiteType, siteType).eq(RiskRule::getDeleted, 0));
|
||||
}
|
||||
@@ -108,6 +127,7 @@ public class RiskRuleServiceImpl implements RiskRuleService {
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("id", rr.getId());
|
||||
m.put("siteType", rr.getSiteType());
|
||||
m.put("siteId", rr.getSiteId());
|
||||
m.put("version", rr.getVersion());
|
||||
m.put("updatedAt", rr.getUpdatedAt());
|
||||
result.add(m);
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE risk_rules ADD COLUMN IF NOT EXISTS site_id VARCHAR(255) DEFAULT NULL AFTER site_type;
|
||||
CREATE INDEX IF NOT EXISTS idx_risk_rules_site_id ON risk_rules(site_id);
|
||||
@@ -299,7 +299,7 @@ const parsed = computed({
|
||||
|
||||
const editSiteName = computed(() => {
|
||||
if (!editType.value) return ''
|
||||
const site = (sites.value||[]).find(s => s.siteType === editType.value)
|
||||
const site = (sites.value||[]).find(s => s.siteId === editType.value)
|
||||
return site ? (site.names||[]).join('/') || site.siteId || editType.value : editType.value
|
||||
})
|
||||
|
||||
@@ -334,8 +334,8 @@ const ruleText = (r) => {
|
||||
}
|
||||
const merged = computed(() => (Array.isArray(sites.value)?sites.value:[]).map(s => ({
|
||||
siteId: s.siteId, names: s.names, siteType: s.siteType,
|
||||
ruleCount: rulesMap.value[s.siteType]?.ruleCount || 0, version: rulesMap.value[s.siteType]?.version || null,
|
||||
updatedAt: rulesMap.value[s.siteType]?.updatedAt || null, rulesJson: rulesMap.value[s.siteType]?.rulesJson || null,
|
||||
ruleCount: rulesMap.value[s.siteId]?.ruleCount || 0, version: rulesMap.value[s.siteId]?.version || null,
|
||||
updatedAt: rulesMap.value[s.siteId]?.updatedAt || null, rulesJson: rulesMap.value[s.siteId]?.rulesJson || null,
|
||||
})))
|
||||
|
||||
// ============ 数据操作 ============
|
||||
@@ -348,17 +348,18 @@ const fetchAll = async () => {
|
||||
const map = {}
|
||||
for (const r of rulesData) {
|
||||
const cnt = (() => { try { return JSON.parse(r.rulesJson||'[]').length } catch { return 0 } })()
|
||||
if (!map[r.siteType] || r.version > map[r.siteType].version)
|
||||
map[r.siteType] = { ruleCount: cnt, version: r.version, updatedAt: r.updatedAt, rulesJson: r.rulesJson }
|
||||
const key = r.siteId || r.siteType // siteId is the new key, fallback to siteType
|
||||
if (!map[key] || r.version > map[key].version)
|
||||
map[key] = { ruleCount: cnt, version: r.version, updatedAt: r.updatedAt, rulesJson: r.rulesJson }
|
||||
}
|
||||
rulesMap.value = map
|
||||
} finally { loading.value = false }
|
||||
}
|
||||
|
||||
const editRule = async (row) => {
|
||||
editType.value = row.siteType
|
||||
editType.value = row.siteId
|
||||
try {
|
||||
const r = await api.raw.get('/admin/risk-rules/'+row.siteType)
|
||||
const r = await api.raw.get('/admin/risk-rules/'+row.siteId)
|
||||
editorJson.value = (r?.data||r)?.rules ? JSON.stringify((r.data||r).rules, null, 2) : '[]'
|
||||
} catch { editorJson.value = '[]' }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user