feat: 新增数据管理模块(区域管理)及修复前端已知问题
后端(bms-back):
- 新增区域管理完整后端:Domain/Mapper/Service/Controller + MyBatis XML
- 新增 RestTemplateConfig 配置类,用于第三方API调用
- 新增 countries.json 本地国家数据源(105个国家)
- RuoYiApplication 加 @EnableAsync 支持异步任务
- application-druid.yml 修复 Druid 连接池字符集配置(SET NAMES utf8mb4)
- logback.xml 日志路径改为 ${user.dir}/logs 避免沙箱写入受限
- pom.xml 增加 JVM 编码参数(-Dfile.encoding=UTF-8)
- 新增 sql/bms_region.sql 建表脚本+菜单权限
前端(bms-front):
- 新增区域管理页面(列表/编辑/状态切换/同步国家数据/导出)
- 新增同步日志功能(内嵌为区域管理弹窗,移除独立菜单)
- 新增 API 层: region.js / region-log.js
- 修复 BasicForm/index.vue 缺失 import FormControl 导致搜索栏控件不渲染
- 修复 user/role/region 三个页面 el-switch 初始化时弹 undefined 提示
This commit is contained in:
@@ -63,6 +63,8 @@
|
|||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<addResources>true</addResources>
|
<addResources>true</addResources>
|
||||||
|
<jvmArguments>-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Duser.language=zh -Duser.country=CN</jvmArguments>
|
||||||
|
<arguments>-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Duser.language=zh -Duser.country=CN</arguments>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ package com.ruoyi;
|
|||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
|
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动程序
|
* 启动程序
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
|
@EnableAsync
|
||||||
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
||||||
public class RuoYiApplication
|
public class RuoYiApplication
|
||||||
{
|
{
|
||||||
|
|||||||
+124
@@ -0,0 +1,124 @@
|
|||||||
|
package com.ruoyi.web.controller.data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
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.core.page.TableDataInfo;
|
||||||
|
import com.ruoyi.common.enums.BusinessType;
|
||||||
|
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||||
|
import com.ruoyi.system.domain.BmsRegion;
|
||||||
|
import com.ruoyi.system.service.IBmsRegionService;
|
||||||
|
import com.ruoyi.system.service.IBmsRegionSyncService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区域管理 信息操作处理
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/data/region")
|
||||||
|
public class BmsRegionController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IBmsRegionService regionService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IBmsRegionSyncService syncService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取区域列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('data:region:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(BmsRegion region)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<BmsRegion> list = regionService.selectRegionList(region);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出区域列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('data:region:list')")
|
||||||
|
@Log(title = "区域管理", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, BmsRegion region)
|
||||||
|
{
|
||||||
|
List<BmsRegion> list = regionService.selectRegionList(region);
|
||||||
|
ExcelUtil<BmsRegion> util = new ExcelUtil<BmsRegion>(BmsRegion.class);
|
||||||
|
util.exportExcel(response, list, "区域数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取区域详细信息
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('data:region:query')")
|
||||||
|
@GetMapping(value = "/{regionId}")
|
||||||
|
public AjaxResult getInfo(@PathVariable Long regionId)
|
||||||
|
{
|
||||||
|
return success(regionService.selectRegionById(regionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改区域
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('data:region:edit')")
|
||||||
|
@Log(title = "区域管理", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@Validated @RequestBody BmsRegion region)
|
||||||
|
{
|
||||||
|
region.setUpdateBy(getUsername());
|
||||||
|
return toAjax(regionService.updateRegion(region));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除区域
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('data:region:remove')")
|
||||||
|
@Log(title = "区域管理", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{regionIds}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] regionIds)
|
||||||
|
{
|
||||||
|
return toAjax(regionService.deleteRegionByIds(regionIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改区域状态(启用/停用)
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('data:region:edit')")
|
||||||
|
@Log(title = "区域管理", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/changeStatus")
|
||||||
|
public AjaxResult changeStatus(@RequestBody BmsRegion region)
|
||||||
|
{
|
||||||
|
region.setUpdateBy(getUsername());
|
||||||
|
return toAjax(regionService.updateRegionStatus(region));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步国家数据(异步)
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('data:region:sync')")
|
||||||
|
@Log(title = "区域管理", businessType = BusinessType.OTHER)
|
||||||
|
@PostMapping("/sync")
|
||||||
|
public AjaxResult sync()
|
||||||
|
{
|
||||||
|
Long logId = syncService.syncRegion();
|
||||||
|
AjaxResult ajax = AjaxResult.success("同步任务已创建,正在后台执行");
|
||||||
|
ajax.put("logId", logId);
|
||||||
|
return ajax;
|
||||||
|
}
|
||||||
|
}
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
package com.ruoyi.web.controller.data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
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.core.page.TableDataInfo;
|
||||||
|
import com.ruoyi.common.enums.BusinessType;
|
||||||
|
import com.ruoyi.system.domain.BmsRegionSyncLog;
|
||||||
|
import com.ruoyi.system.mapper.BmsRegionSyncLogMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区域同步日志 信息操作处理
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/data/region/log")
|
||||||
|
public class BmsRegionSyncLogController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private BmsRegionSyncLogMapper syncLogMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取同步日志列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('data:region:log:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(BmsRegionSyncLog syncLog)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<BmsRegionSyncLog> list = syncLogMapper.selectSyncLogList(syncLog);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取同步日志详细信息
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('data:region:log:list')")
|
||||||
|
@GetMapping(value = "/{logId}")
|
||||||
|
public AjaxResult getInfo(@PathVariable Long logId)
|
||||||
|
{
|
||||||
|
return success(syncLogMapper.selectSyncLogById(logId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除同步日志
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('data:region:log:remove')")
|
||||||
|
@Log(title = "同步日志", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{logIds}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] logIds)
|
||||||
|
{
|
||||||
|
return toAjax(syncLogMapper.deleteSyncLogByIds(logIds));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,9 +6,10 @@ spring:
|
|||||||
druid:
|
druid:
|
||||||
# 主库数据源
|
# 主库数据源
|
||||||
master:
|
master:
|
||||||
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&connectionCollation=utf8mb4_unicode_ci&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
username: root
|
username: root
|
||||||
password: password
|
password: password
|
||||||
|
connectionInitSqls: SET NAMES utf8mb4
|
||||||
# 从库数据源
|
# 从库数据源
|
||||||
slave:
|
slave:
|
||||||
# 从数据源开关/默认关闭
|
# 从数据源开关/默认关闭
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
[
|
||||||
|
{"name":{"common":"China","official":"People's Republic of China"},"cca2":"CN","cca3":"CHN","region":"Asia","subregion":"Eastern Asia","currencies":{"CNY":{"name":"Chinese yuan","symbol":"¥"}},"idd":{"root":"+86","suffixes":[""]},"flag":"🇨🇳","flags":{"png":"https://flagcdn.com/w320/cn.png"},"independent":true},
|
||||||
|
{"name":{"common":"United States","official":"United States of America"},"cca2":"US","cca3":"USA","region":"Americas","subregion":"North America","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"idd":{"root":"+1","suffixes":[""]},"flag":"🇺🇸","flags":{"png":"https://flagcdn.com/w320/us.png"},"independent":true},
|
||||||
|
{"name":{"common":"Germany","official":"Federal Republic of Germany"},"cca2":"DE","cca3":"DEU","region":"Europe","subregion":"Western Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+49","suffixes":[""]},"flag":"🇩🇪","flags":{"png":"https://flagcdn.com/w320/de.png"},"independent":true},
|
||||||
|
{"name":{"common":"Japan","official":"Japan"},"cca2":"JP","cca3":"JPN","region":"Asia","subregion":"Eastern Asia","currencies":{"JPY":{"name":"Japanese yen","symbol":"¥"}},"idd":{"root":"+81","suffixes":[""]},"flag":"🇯🇵","flags":{"png":"https://flagcdn.com/w320/jp.png"},"independent":true},
|
||||||
|
{"name":{"common":"South Korea","official":"Republic of Korea"},"cca2":"KR","cca3":"KOR","region":"Asia","subregion":"Eastern Asia","currencies":{"KRW":{"name":"South Korean won","symbol":"₩"}},"idd":{"root":"+82","suffixes":[""]},"flag":"🇰🇷","flags":{"png":"https://flagcdn.com/w320/kr.png"},"independent":true},
|
||||||
|
{"name":{"common":"United Kingdom","official":"United Kingdom of Great Britain and Northern Ireland"},"cca2":"GB","cca3":"GBR","region":"Europe","subregion":"Northern Europe","currencies":{"GBP":{"name":"British pound","symbol":"£"}},"idd":{"root":"+44","suffixes":[""]},"flag":"🇬🇧","flags":{"png":"https://flagcdn.com/w320/gb.png"},"independent":true},
|
||||||
|
{"name":{"common":"France","official":"French Republic"},"cca2":"FR","cca3":"FRA","region":"Europe","subregion":"Western Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+33","suffixes":[""]},"flag":"🇫🇷","flags":{"png":"https://flagcdn.com/w320/fr.png"},"independent":true},
|
||||||
|
{"name":{"common":"Italy","official":"Italian Republic"},"cca2":"IT","cca3":"ITA","region":"Europe","subregion":"Southern Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+39","suffixes":[""]},"flag":"🇮🇹","flags":{"png":"https://flagcdn.com/w320/it.png"},"independent":true},
|
||||||
|
{"name":{"common":"Spain","official":"Kingdom of Spain"},"cca2":"ES","cca3":"ESP","region":"Europe","subregion":"Southern Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+34","suffixes":[""]},"flag":"🇪🇸","flags":{"png":"https://flagcdn.com/w320/es.png"},"independent":true},
|
||||||
|
{"name":{"common":"Netherlands","official":"Kingdom of the Netherlands"},"cca2":"NL","cca3":"NLD","region":"Europe","subregion":"Western Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+31","suffixes":[""]},"flag":"🇳🇱","flags":{"png":"https://flagcdn.com/w320/nl.png"},"independent":true},
|
||||||
|
{"name":{"common":"Belgium","official":"Kingdom of Belgium"},"cca2":"BE","cca3":"BEL","region":"Europe","subregion":"Western Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+32","suffixes":[""]},"flag":"🇧🇪","flags":{"png":"https://flagcdn.com/w320/be.png"},"independent":true},
|
||||||
|
{"name":{"common":"Switzerland","official":"Swiss Confederation"},"cca2":"CH","cca3":"CHE","region":"Europe","subregion":"Western Europe","currencies":{"CHF":{"name":"Swiss franc","symbol":"Fr."}},"idd":{"root":"+41","suffixes":[""]},"flag":"🇨🇭","flags":{"png":"https://flagcdn.com/w320/ch.png"},"independent":true},
|
||||||
|
{"name":{"common":"Austria","official":"Republic of Austria"},"cca2":"AT","cca3":"AUT","region":"Europe","subregion":"Western Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+43","suffixes":[""]},"flag":"🇦🇹","flags":{"png":"https://flagcdn.com/w320/at.png"},"independent":true},
|
||||||
|
{"name":{"common":"Sweden","official":"Kingdom of Sweden"},"cca2":"SE","cca3":"SWE","region":"Europe","subregion":"Northern Europe","currencies":{"SEK":{"name":"Swedish krona","symbol":"kr"}},"idd":{"root":"+46","suffixes":[""]},"flag":"🇸🇪","flags":{"png":"https://flagcdn.com/w320/se.png"},"independent":true},
|
||||||
|
{"name":{"common":"Norway","official":"Kingdom of Norway"},"cca2":"NO","cca3":"NOR","region":"Europe","subregion":"Northern Europe","currencies":{"NOK":{"name":"Norwegian krone","symbol":"kr"}},"idd":{"root":"+47","suffixes":[""]},"flag":"🇳🇴","flags":{"png":"https://flagcdn.com/w320/no.png"},"independent":true},
|
||||||
|
{"name":{"common":"Denmark","official":"Kingdom of Denmark"},"cca2":"DK","cca3":"DNK","region":"Europe","subregion":"Northern Europe","currencies":{"DKK":{"name":"Danish krone","symbol":"kr"}},"idd":{"root":"+45","suffixes":[""]},"flag":"🇩🇰","flags":{"png":"https://flagcdn.com/w320/dk.png"},"independent":true},
|
||||||
|
{"name":{"common":"Finland","official":"Republic of Finland"},"cca2":"FI","cca3":"FIN","region":"Europe","subregion":"Northern Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+358","suffixes":[""]},"flag":"🇫🇮","flags":{"png":"https://flagcdn.com/w320/fi.png"},"independent":true},
|
||||||
|
{"name":{"common":"Poland","official":"Republic of Poland"},"cca2":"PL","cca3":"POL","region":"Europe","subregion":"Central Europe","currencies":{"PLN":{"name":"Polish zloty","symbol":"zł"}},"idd":{"root":"+48","suffixes":[""]},"flag":"🇵🇱","flags":{"png":"https://flagcdn.com/w320/pl.png"},"independent":true},
|
||||||
|
{"name":{"common":"Russia","official":"Russian Federation"},"cca2":"RU","cca3":"RUS","region":"Europe","subregion":"Eastern Europe","currencies":{"RUB":{"name":"Russian ruble","symbol":"₽"}},"idd":{"root":"+7","suffixes":[""]},"flag":"🇷🇺","flags":{"png":"https://flagcdn.com/w320/ru.png"},"independent":true},
|
||||||
|
{"name":{"common":"India","official":"Republic of India"},"cca2":"IN","cca3":"IND","region":"Asia","subregion":"Southern Asia","currencies":{"INR":{"name":"Indian rupee","symbol":"₹"}},"idd":{"root":"+91","suffixes":[""]},"flag":"🇮🇳","flags":{"png":"https://flagcdn.com/w320/in.png"},"independent":true},
|
||||||
|
{"name":{"common":"Brazil","official":"Federative Republic of Brazil"},"cca2":"BR","cca3":"BRA","region":"Americas","subregion":"South America","currencies":{"BRL":{"name":"Brazilian real","symbol":"R$"}},"idd":{"root":"+55","suffixes":[""]},"flag":"🇧🇷","flags":{"png":"https://flagcdn.com/w320/br.png"},"independent":true},
|
||||||
|
{"name":{"common":"Canada","official":"Canada"},"cca2":"CA","cca3":"CAN","region":"Americas","subregion":"North America","currencies":{"CAD":{"name":"Canadian dollar","symbol":"$"}},"idd":{"root":"+1","suffixes":[""]},"flag":"🇨🇦","flags":{"png":"https://flagcdn.com/w320/ca.png"},"independent":true},
|
||||||
|
{"name":{"common":"Australia","official":"Commonwealth of Australia"},"cca2":"AU","cca3":"AUS","region":"Oceania","subregion":"Australia and New Zealand","currencies":{"AUD":{"name":"Australian dollar","symbol":"$"}},"idd":{"root":"+61","suffixes":[""]},"flag":"🇦🇺","flags":{"png":"https://flagcdn.com/w320/au.png"},"independent":true},
|
||||||
|
{"name":{"common":"Mexico","official":"United Mexican States"},"cca2":"MX","cca3":"MEX","region":"Americas","subregion":"North America","currencies":{"MXN":{"name":"Mexican peso","symbol":"$"}},"idd":{"root":"+52","suffixes":[""]},"flag":"🇲🇽","flags":{"png":"https://flagcdn.com/w320/mx.png"},"independent":true},
|
||||||
|
{"name":{"common":"Indonesia","official":"Republic of Indonesia"},"cca2":"ID","cca3":"IDN","region":"Asia","subregion":"South-Eastern Asia","currencies":{"IDR":{"name":"Indonesian rupiah","symbol":"Rp"}},"idd":{"root":"+62","suffixes":[""]},"flag":"🇮🇩","flags":{"png":"https://flagcdn.com/w320/id.png"},"independent":true},
|
||||||
|
{"name":{"common":"Thailand","official":"Kingdom of Thailand"},"cca2":"TH","cca3":"THA","region":"Asia","subregion":"South-Eastern Asia","currencies":{"THB":{"name":"Thai baht","symbol":"฿"}},"idd":{"root":"+66","suffixes":[""]},"flag":"🇹🇭","flags":{"png":"https://flagcdn.com/w320/th.png"},"independent":true},
|
||||||
|
{"name":{"common":"Vietnam","official":"Socialist Republic of Vietnam"},"cca2":"VN","cca3":"VNM","region":"Asia","subregion":"South-Eastern Asia","currencies":{"VND":{"name":"Vietnamese đồng","symbol":"₫"}},"idd":{"root":"+84","suffixes":[""]},"flag":"🇻🇳","flags":{"png":"https://flagcdn.com/w320/vn.png"},"independent":true},
|
||||||
|
{"name":{"common":"Malaysia","official":"Malaysia"},"cca2":"MY","cca3":"MYS","region":"Asia","subregion":"South-Eastern Asia","currencies":{"MYR":{"name":"Malaysian ringgit","symbol":"RM"}},"idd":{"root":"+60","suffixes":[""]},"flag":"🇲🇾","flags":{"png":"https://flagcdn.com/w320/my.png"},"independent":true},
|
||||||
|
{"name":{"common":"Singapore","official":"Republic of Singapore"},"cca2":"SG","cca3":"SGP","region":"Asia","subregion":"South-Eastern Asia","currencies":{"SGD":{"name":"Singapore dollar","symbol":"$"}},"idd":{"root":"+65","suffixes":[""]},"flag":"🇸🇬","flags":{"png":"https://flagcdn.com/w320/sg.png"},"independent":true},
|
||||||
|
{"name":{"common":"Philippines","official":"Republic of the Philippines"},"cca2":"PH","cca3":"PHL","region":"Asia","subregion":"South-Eastern Asia","currencies":{"PHP":{"name":"Philippine peso","symbol":"₱"}},"idd":{"root":"+63","suffixes":[""]},"flag":"🇵🇭","flags":{"png":"https://flagcdn.com/w320/ph.png"},"independent":true},
|
||||||
|
{"name":{"common":"Turkey","official":"Republic of Türkiye"},"cca2":"TR","cca3":"TUR","region":"Asia","subregion":"Western Asia","currencies":{"TRY":{"name":"Turkish lira","symbol":"₺"}},"idd":{"root":"+90","suffixes":[""]},"flag":"🇹🇷","flags":{"png":"https://flagcdn.com/w320/tr.png"},"independent":true},
|
||||||
|
{"name":{"common":"Saudi Arabia","official":"Kingdom of Saudi Arabia"},"cca2":"SA","cca3":"SAU","region":"Asia","subregion":"Western Asia","currencies":{"SAR":{"name":"Saudi riyal","symbol":"ر.س"}},"idd":{"root":"+966","suffixes":[""]},"flag":"🇸🇦","flags":{"png":"https://flagcdn.com/w320/sa.png"},"independent":true},
|
||||||
|
{"name":{"common":"United Arab Emirates","official":"United Arab Emirates"},"cca2":"AE","cca3":"ARE","region":"Asia","subregion":"Western Asia","currencies":{"AED":{"name":"United Arab Emirates dirham","symbol":"د.إ"}},"idd":{"root":"+971","suffixes":[""]},"flag":"🇦🇪","flags":{"png":"https://flagcdn.com/w320/ae.png"},"independent":true},
|
||||||
|
{"name":{"common":"Israel","official":"State of Israel"},"cca2":"IL","cca3":"ISR","region":"Asia","subregion":"Western Asia","currencies":{"ILS":{"name":"Israeli new shekel","symbol":"₪"}},"idd":{"root":"+972","suffixes":[""]},"flag":"🇮🇱","flags":{"png":"https://flagcdn.com/w320/il.png"},"independent":true},
|
||||||
|
{"name":{"common":"Egypt","official":"Arab Republic of Egypt"},"cca2":"EG","cca3":"EGY","region":"Africa","subregion":"Northern Africa","currencies":{"EGP":{"name":"Egyptian pound","symbol":"£"}},"idd":{"root":"+20","suffixes":[""]},"flag":"🇪🇬","flags":{"png":"https://flagcdn.com/w320/eg.png"},"independent":true},
|
||||||
|
{"name":{"common":"South Africa","official":"Republic of South Africa"},"cca2":"ZA","cca3":"ZAF","region":"Africa","subregion":"Southern Africa","currencies":{"ZAR":{"name":"South African rand","symbol":"R"}},"idd":{"root":"+27","suffixes":[""]},"flag":"🇿🇦","flags":{"png":"https://flagcdn.com/w320/za.png"},"independent":true},
|
||||||
|
{"name":{"common":"Nigeria","official":"Federal Republic of Nigeria"},"cca2":"NG","cca3":"NGA","region":"Africa","subregion":"Western Africa","currencies":{"NGN":{"name":"Nigerian naira","symbol":"₦"}},"idd":{"root":"+234","suffixes":[""]},"flag":"🇳🇬","flags":{"png":"https://flagcdn.com/w320/ng.png"},"independent":true},
|
||||||
|
{"name":{"common":"Argentina","official":"Argentine Republic"},"cca2":"AR","cca3":"ARG","region":"Americas","subregion":"South America","currencies":{"ARS":{"name":"Argentine peso","symbol":"$"}},"idd":{"root":"+54","suffixes":[""]},"flag":"🇦🇷","flags":{"png":"https://flagcdn.com/w320/ar.png"},"independent":true},
|
||||||
|
{"name":{"common":"Chile","official":"Republic of Chile"},"cca2":"CL","cca3":"CHL","region":"Americas","subregion":"South America","currencies":{"CLP":{"name":"Chilean peso","symbol":"$"}},"idd":{"root":"+56","suffixes":[""]},"flag":"🇨🇱","flags":{"png":"https://flagcdn.com/w320/cl.png"},"independent":true},
|
||||||
|
{"name":{"common":"Colombia","official":"Republic of Colombia"},"cca2":"CO","cca3":"COL","region":"Americas","subregion":"South America","currencies":{"COP":{"name":"Colombian peso","symbol":"$"}},"idd":{"root":"+57","suffixes":[""]},"flag":"🇨🇴","flags":{"png":"https://flagcdn.com/w320/co.png"},"independent":true},
|
||||||
|
{"name":{"common":"Peru","official":"Republic of Peru"},"cca2":"PE","cca3":"PER","region":"Americas","subregion":"South America","currencies":{"PEN":{"name":"Peruvian sol","symbol":"S/"}},"idd":{"root":"+51","suffixes":[""]},"flag":"🇵🇪","flags":{"png":"https://flagcdn.com/w320/pe.png"},"independent":true},
|
||||||
|
{"name":{"common":"New Zealand","official":"New Zealand"},"cca2":"NZ","cca3":"NZL","region":"Oceania","subregion":"Australia and New Zealand","currencies":{"NZD":{"name":"New Zealand dollar","symbol":"$"}},"idd":{"root":"+64","suffixes":[""]},"flag":"🇳🇿","flags":{"png":"https://flagcdn.com/w320/nz.png"},"independent":true},
|
||||||
|
{"name":{"common":"Ireland","official":"Republic of Ireland"},"cca2":"IE","cca3":"IRL","region":"Europe","subregion":"Northern Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+353","suffixes":[""]},"flag":"🇮🇪","flags":{"png":"https://flagcdn.com/w320/ie.png"},"independent":true},
|
||||||
|
{"name":{"common":"Portugal","official":"Portuguese Republic"},"cca2":"PT","cca3":"PRT","region":"Europe","subregion":"Southern Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+351","suffixes":[""]},"flag":"🇵🇹","flags":{"png":"https://flagcdn.com/w320/pt.png"},"independent":true},
|
||||||
|
{"name":{"common":"Greece","official":"Hellenic Republic"},"cca2":"GR","cca3":"GRC","region":"Europe","subregion":"Southern Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+30","suffixes":[""]},"flag":"🇬🇷","flags":{"png":"https://flagcdn.com/w320/gr.png"},"independent":true},
|
||||||
|
{"name":{"common":"Czechia","official":"Czech Republic"},"cca2":"CZ","cca3":"CZE","region":"Europe","subregion":"Central Europe","currencies":{"CZK":{"name":"Czech koruna","symbol":"Kč"}},"idd":{"root":"+420","suffixes":[""]},"flag":"🇨🇿","flags":{"png":"https://flagcdn.com/w320/cz.png"},"independent":true},
|
||||||
|
{"name":{"common":"Hungary","official":"Hungary"},"cca2":"HU","cca3":"HUN","region":"Europe","subregion":"Central Europe","currencies":{"HUF":{"name":"Hungarian forint","symbol":"Ft"}},"idd":{"root":"+36","suffixes":[""]},"flag":"🇭🇺","flags":{"png":"https://flagcdn.com/w320/hu.png"},"independent":true},
|
||||||
|
{"name":{"common":"Romania","official":"Romania"},"cca2":"RO","cca3":"ROU","region":"Europe","subregion":"Central Europe","currencies":{"RON":{"name":"Romanian leu","symbol":"lei"}},"idd":{"root":"+40","suffixes":[""]},"flag":"🇷🇴","flags":{"png":"https://flagcdn.com/w320/ro.png"},"independent":true},
|
||||||
|
{"name":{"common":"Bulgaria","official":"Republic of Bulgaria"},"cca2":"BG","cca3":"BGR","region":"Europe","subregion":"Southeast Europe","currencies":{"BGN":{"name":"Bulgarian lev","symbol":"лв"}},"idd":{"root":"+359","suffixes":[""]},"flag":"🇧🇬","flags":{"png":"https://flagcdn.com/w320/bg.png"},"independent":true},
|
||||||
|
{"name":{"common":"Croatia","official":"Republic of Croatia"},"cca2":"HR","cca3":"HRV","region":"Europe","subregion":"Southeast Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+385","suffixes":[""]},"flag":"🇭🇷","flags":{"png":"https://flagcdn.com/w320/hr.png"},"independent":true},
|
||||||
|
{"name":{"common":"Slovakia","official":"Slovak Republic"},"cca2":"SK","cca3":"SVK","region":"Europe","subregion":"Central Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+421","suffixes":[""]},"flag":"🇸🇰","flags":{"png":"https://flagcdn.com/w320/sk.png"},"independent":true},
|
||||||
|
{"name":{"common":"Slovenia","official":"Republic of Slovenia"},"cca2":"SI","cca3":"SVN","region":"Europe","subregion":"Central Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+386","suffixes":[""]},"flag":"🇸🇮","flags":{"png":"https://flagcdn.com/w320/si.png"},"independent":true},
|
||||||
|
{"name":{"common":"Lithuania","official":"Republic of Lithuania"},"cca2":"LT","cca3":"LTU","region":"Europe","subregion":"Northern Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+370","suffixes":[""]},"flag":"🇱🇹","flags":{"png":"https://flagcdn.com/w320/lt.png"},"independent":true},
|
||||||
|
{"name":{"common":"Latvia","official":"Republic of Latvia"},"cca2":"LV","cca3":"LVA","region":"Europe","subregion":"Northern Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+371","suffixes":[""]},"flag":"🇱🇻","flags":{"png":"https://flagcdn.com/w320/lv.png"},"independent":true},
|
||||||
|
{"name":{"common":"Estonia","official":"Republic of Estonia"},"cca2":"EE","cca3":"EST","region":"Europe","subregion":"Northern Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+372","suffixes":[""]},"flag":"🇪🇪","flags":{"png":"https://flagcdn.com/w320/ee.png"},"independent":true},
|
||||||
|
{"name":{"common":"Ukraine","official":"Ukraine"},"cca2":"UA","cca3":"UKR","region":"Europe","subregion":"Eastern Europe","currencies":{"UAH":{"name":"Ukrainian hryvnia","symbol":"₴"}},"idd":{"root":"+380","suffixes":[""]},"flag":"🇺🇦","flags":{"png":"https://flagcdn.com/w320/ua.png"},"independent":true},
|
||||||
|
{"name":{"common":"Morocco","official":"Kingdom of Morocco"},"cca2":"MA","cca3":"MAR","region":"Africa","subregion":"Northern Africa","currencies":{"MAD":{"name":"Moroccan dirham","symbol":"د.م."}},"idd":{"root":"+212","suffixes":[""]},"flag":"🇲🇦","flags":{"png":"https://flagcdn.com/w320/ma.png"},"independent":true},
|
||||||
|
{"name":{"common":"Kenya","official":"Republic of Kenya"},"cca2":"KE","cca3":"KEN","region":"Africa","subregion":"Eastern Africa","currencies":{"KES":{"name":"Kenyan shilling","symbol":"KSh"}},"idd":{"root":"+254","suffixes":[""]},"flag":"🇰🇪","flags":{"png":"https://flagcdn.com/w320/ke.png"},"independent":true},
|
||||||
|
{"name":{"common":"Pakistan","official":"Islamic Republic of Pakistan"},"cca2":"PK","cca3":"PAK","region":"Asia","subregion":"Southern Asia","currencies":{"PKR":{"name":"Pakistani rupee","symbol":"₨"}},"idd":{"root":"+92","suffixes":[""]},"flag":"🇵🇰","flags":{"png":"https://flagcdn.com/w320/pk.png"},"independent":true},
|
||||||
|
{"name":{"common":"Bangladesh","official":"People's Republic of Bangladesh"},"cca2":"BD","cca3":"BGD","region":"Asia","subregion":"Southern Asia","currencies":{"BDT":{"name":"Bangladeshi taka","symbol":"৳"}},"idd":{"root":"+880","suffixes":[""]},"flag":"🇧🇩","flags":{"png":"https://flagcdn.com/w320/bd.png"},"independent":true},
|
||||||
|
{"name":{"common":"Iran","official":"Islamic Republic of Iran"},"cca2":"IR","cca3":"IRN","region":"Asia","subregion":"Southern Asia","currencies":{"IRR":{"name":"Iranian rial","symbol":"﷼"}},"idd":{"root":"+98","suffixes":[""]},"flag":"🇮🇷","flags":{"png":"https://flagcdn.com/w320/ir.png"},"independent":true},
|
||||||
|
{"name":{"common":"Iraq","official":"Republic of Iraq"},"cca2":"IQ","cca3":"IRQ","region":"Asia","subregion":"Western Asia","currencies":{"IQD":{"name":"Iraqi dinar","symbol":"د.ع"}},"idd":{"root":"+964","suffixes":[""]},"flag":"🇮🇶","flags":{"png":"https://flagcdn.com/w320/iq.png"},"independent":true},
|
||||||
|
{"name":{"common":"Kuwait","official":"State of Kuwait"},"cca2":"KW","cca3":"KWT","region":"Asia","subregion":"Western Asia","currencies":{"KWD":{"name":"Kuwaiti dinar","symbol":"د.ك"}},"idd":{"root":"+965","suffixes":[""]},"flag":"🇰🇼","flags":{"png":"https://flagcdn.com/w320/kw.png"},"independent":true},
|
||||||
|
{"name":{"common":"Qatar","official":"State of Qatar"},"cca2":"QA","cca3":"QAT","region":"Asia","subregion":"Western Asia","currencies":{"QAR":{"name":"Qatari riyal","symbol":"ر.ق"}},"idd":{"root":"+974","suffixes":[""]},"flag":"🇶🇦","flags":{"png":"https://flagcdn.com/w320/qa.png"},"independent":true},
|
||||||
|
{"name":{"common":"Hong Kong","official":"Hong Kong Special Administrative Region of China"},"cca2":"HK","cca3":"HKG","region":"Asia","subregion":"Eastern Asia","currencies":{"HKD":{"name":"Hong Kong dollar","symbol":"$"}},"idd":{"root":"+852","suffixes":[""]},"flag":"🇭🇰","flags":{"png":"https://flagcdn.com/w320/hk.png"},"independent":false},
|
||||||
|
{"name":{"common":"Taiwan","official":"Republic of China"},"cca2":"TW","cca3":"TWN","region":"Asia","subregion":"Eastern Asia","currencies":{"TWD":{"name":"New Taiwan dollar","symbol":"$"}},"idd":{"root":"+886","suffixes":[""]},"flag":"🇹🇼","flags":{"png":"https://flagcdn.com/w320/tw.png"},"independent":false},
|
||||||
|
{"name":{"common":"Iceland","official":"Iceland"},"cca2":"IS","cca3":"ISL","region":"Europe","subregion":"Northern Europe","currencies":{"ISK":{"name":"Icelandic króna","symbol":"kr"}},"idd":{"root":"+354","suffixes":[""]},"flag":"🇮🇸","flags":{"png":"https://flagcdn.com/w320/is.png"},"independent":true},
|
||||||
|
{"name":{"common":"Luxembourg","official":"Grand Duchy of Luxembourg"},"cca2":"LU","cca3":"LUX","region":"Europe","subregion":"Western Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+352","suffixes":[""]},"flag":"🇱🇺","flags":{"png":"https://flagcdn.com/w320/lu.png"},"independent":true},
|
||||||
|
{"name":{"common":"Malta","official":"Republic of Malta"},"cca2":"MT","cca3":"MLT","region":"Europe","subregion":"Southern Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+356","suffixes":[""]},"flag":"🇲🇹","flags":{"png":"https://flagcdn.com/w320/mt.png"},"independent":true},
|
||||||
|
{"name":{"common":"Cyprus","official":"Republic of Cyprus"},"cca2":"CY","cca3":"CYP","region":"Europe","subregion":"Southern Europe","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"idd":{"root":"+357","suffixes":[""]},"flag":"🇨🇾","flags":{"png":"https://flagcdn.com/w320/cy.png"},"independent":true},
|
||||||
|
{"name":{"common":"Albania","official":"Republic of Albania"},"cca2":"AL","cca3":"ALB","region":"Europe","subregion":"Southeast Europe","currencies":{"ALL":{"name":"Albanian lek","symbol":"L"}},"idd":{"root":"+355","suffixes":[""]},"flag":"🇦🇱","flags":{"png":"https://flagcdn.com/w320/al.png"},"independent":true},
|
||||||
|
{"name":{"common":"Serbia","official":"Republic of Serbia"},"cca2":"RS","cca3":"SRB","region":"Europe","subregion":"Southeast Europe","currencies":{"RSD":{"name":"Serbian dinar","symbol":"дин"}},"idd":{"root":"+381","suffixes":[""]},"flag":"🇷🇸","flags":{"png":"https://flagcdn.com/w320/rs.png"},"independent":true},
|
||||||
|
{"name":{"common":"Belarus","official":"Republic of Belarus"},"cca2":"BY","cca3":"BLR","region":"Europe","subregion":"Eastern Europe","currencies":{"BYN":{"name":"Belarusian ruble","symbol":"Br"}},"idd":{"root":"+375","suffixes":[""]},"flag":"🇧🇾","flags":{"png":"https://flagcdn.com/w320/by.png"},"independent":true},
|
||||||
|
{"name":{"common":"Kazakhstan","official":"Republic of Kazakhstan"},"cca2":"KZ","cca3":"KAZ","region":"Asia","subregion":"Central Asia","currencies":{"KZT":{"name":"Kazakhstani tenge","symbol":"₸"}},"idd":{"root":"+7","suffixes":[""]},"flag":"🇰🇿","flags":{"png":"https://flagcdn.com/w320/kz.png"},"independent":true},
|
||||||
|
{"name":{"common":"Uzbekistan","official":"Republic of Uzbekistan"},"cca2":"UZ","cca3":"UZB","region":"Asia","subregion":"Central Asia","currencies":{"UZS":{"name":"Uzbekistani soʻm","symbol":"so'm"}},"idd":{"root":"+998","suffixes":[""]},"flag":"🇺🇿","flags":{"png":"https://flagcdn.com/w320/uz.png"},"independent":true},
|
||||||
|
{"name":{"common":"Sri Lanka","official":"Democratic Socialist Republic of Sri Lanka"},"cca2":"LK","cca3":"LKA","region":"Asia","subregion":"Southern Asia","currencies":{"LKR":{"name":"Sri Lankan rupee","symbol":"Rs"}},"idd":{"root":"+94","suffixes":[""]},"flag":"🇱🇰","flags":{"png":"https://flagcdn.com/w320/lk.png"},"independent":true},
|
||||||
|
{"name":{"common":"Cambodia","official":"Kingdom of Cambodia"},"cca2":"KH","cca3":"KHM","region":"Asia","subregion":"South-Eastern Asia","currencies":{"KHR":{"name":"Cambodian riel","symbol":"៛"}},"idd":{"root":"+855","suffixes":[""]},"flag":"🇰🇭","flags":{"png":"https://flagcdn.com/w320/kh.png"},"independent":true},
|
||||||
|
{"name":{"common":"Myanmar","official":"Republic of the Union of Myanmar"},"cca2":"MM","cca3":"MMR","region":"Asia","subregion":"South-Eastern Asia","currencies":{"MMK":{"name":"Burmese kyat","symbol":"K"}},"idd":{"root":"+95","suffixes":[""]},"flag":"🇲🇲","flags":{"png":"https://flagcdn.com/w320/mm.png"},"independent":true},
|
||||||
|
{"name":{"common":"Laos","official":"Lao People's Democratic Republic"},"cca2":"LA","cca3":"LAO","region":"Asia","subregion":"South-Eastern Asia","currencies":{"LAK":{"name":"Lao kip","symbol":"₭"}},"idd":{"root":"+856","suffixes":[""]},"flag":"🇱🇦","flags":{"png":"https://flagcdn.com/w320/la.png"},"independent":true},
|
||||||
|
{"name":{"common":"Nepal","official":"Federal Democratic Republic of Nepal"},"cca2":"NP","cca3":"NPL","region":"Asia","subregion":"Southern Asia","currencies":{"NPR":{"name":"Nepalese rupee","symbol":"रू"}},"idd":{"root":"+977","suffixes":[""]},"flag":"🇳🇵","flags":{"png":"https://flagcdn.com/w320/np.png"},"independent":true},
|
||||||
|
{"name":{"common":"Afghanistan","official":"Islamic Republic of Afghanistan"},"cca2":"AF","cca3":"AFG","region":"Asia","subregion":"Southern Asia","currencies":{"AFN":{"name":"Afghan afghani","symbol":"؋"}},"idd":{"root":"+93","suffixes":[""]},"flag":"🇦🇫","flags":{"png":"https://flagcdn.com/w320/af.png"},"independent":true},
|
||||||
|
{"name":{"common":"Jordan","official":"Hashemite Kingdom of Jordan"},"cca2":"JO","cca3":"JOR","region":"Asia","subregion":"Western Asia","currencies":{"JOD":{"name":"Jordanian dinar","symbol":"د.ا"}},"idd":{"root":"+962","suffixes":[""]},"flag":"🇯🇴","flags":{"png":"https://flagcdn.com/w320/jo.png"},"independent":true},
|
||||||
|
{"name":{"common":"Lebanon","official":"Lebanese Republic"},"cca2":"LB","cca3":"LBN","region":"Asia","subregion":"Western Asia","currencies":{"LBP":{"name":"Lebanese pound","symbol":"ل.ل"}},"idd":{"root":"+961","suffixes":[""]},"flag":"🇱🇧","flags":{"png":"https://flagcdn.com/w320/lb.png"},"independent":true},
|
||||||
|
{"name":{"common":"Oman","official":"Sultanate of Oman"},"cca2":"OM","cca3":"OMN","region":"Asia","subregion":"Western Asia","currencies":{"OMR":{"name":"Omani rial","symbol":"ر.ع."}},"idd":{"root":"+968","suffixes":[""]},"flag":"🇴🇲","flags":{"png":"https://flagcdn.com/w320/om.png"},"independent":true},
|
||||||
|
{"name":{"common":"Bahrain","official":"Kingdom of Bahrain"},"cca2":"BH","cca3":"BHR","region":"Asia","subregion":"Western Asia","currencies":{"BHD":{"name":"Bahraini dinar","symbol":"د.ب"}},"idd":{"root":"+973","suffixes":[""]},"flag":"🇧🇭","flags":{"png":"https://flagcdn.com/w320/bh.png"},"independent":true},
|
||||||
|
{"name":{"common":"Algeria","official":"People's Democratic Republic of Algeria"},"cca2":"DZ","cca3":"DZA","region":"Africa","subregion":"Northern Africa","currencies":{"DZD":{"name":"Algerian dinar","symbol":"دج"}},"idd":{"root":"+213","suffixes":[""]},"flag":"🇩🇿","flags":{"png":"https://flagcdn.com/w320/dz.png"},"independent":true},
|
||||||
|
{"name":{"common":"Tunisia","official":"Republic of Tunisia"},"cca2":"TN","cca3":"TUN","region":"Africa","subregion":"Northern Africa","currencies":{"TND":{"name":"Tunisian dinar","symbol":"د.ت"}},"idd":{"root":"+216","suffixes":[""]},"flag":"🇹🇳","flags":{"png":"https://flagcdn.com/w320/tn.png"},"independent":true},
|
||||||
|
{"name":{"common":"Ghana","official":"Republic of Ghana"},"cca2":"GH","cca3":"GHA","region":"Africa","subregion":"Western Africa","currencies":{"GHS":{"name":"Ghanaian cedi","symbol":"₵"}},"idd":{"root":"+233","suffixes":[""]},"flag":"🇬🇭","flags":{"png":"https://flagcdn.com/w320/gh.png"},"independent":true},
|
||||||
|
{"name":{"common":"Ethiopia","official":"Federal Democratic Republic of Ethiopia"},"cca2":"ET","cca3":"ETH","region":"Africa","subregion":"Eastern Africa","currencies":{"ETB":{"name":"Ethiopian birr","symbol":"Br"}},"idd":{"root":"+251","suffixes":[""]},"flag":"🇪🇹","flags":{"png":"https://flagcdn.com/w320/et.png"},"independent":true},
|
||||||
|
{"name":{"common":"Tanzania","official":"United Republic of Tanzania"},"cca2":"TZ","cca3":"TZA","region":"Africa","subregion":"Eastern Africa","currencies":{"TZS":{"name":"Tanzanian shilling","symbol":"Sh"}},"idd":{"root":"+255","suffixes":[""]},"flag":"🇹🇿","flags":{"png":"https://flagcdn.com/w320/tz.png"},"independent":true},
|
||||||
|
{"name":{"common":"Uganda","official":"Republic of Uganda"},"cca2":"UG","cca3":"UGA","region":"Africa","subregion":"Eastern Africa","currencies":{"UGX":{"name":"Ugandan shilling","symbol":"Sh"}},"idd":{"root":"+256","suffixes":[""]},"flag":"🇺🇬","flags":{"png":"https://flagcdn.com/w320/ug.png"},"independent":true},
|
||||||
|
{"name":{"common":"Cameroon","official":"Republic of Cameroon"},"cca2":"CM","cca3":"CMR","region":"Africa","subregion":"Middle Africa","currencies":{"XAF":{"name":"Central African CFA franc","symbol":"FCFA"}},"idd":{"root":"+237","suffixes":[""]},"flag":"🇨🇲","flags":{"png":"https://flagcdn.com/w320/cm.png"},"independent":true},
|
||||||
|
{"name":{"common":"Angola","official":"Republic of Angola"},"cca2":"AO","cca3":"AGO","region":"Africa","subregion":"Middle Africa","currencies":{"AOA":{"name":"Angolan kwanza","symbol":"Kz"}},"idd":{"root":"+244","suffixes":[""]},"flag":"🇦🇴","flags":{"png":"https://flagcdn.com/w320/ao.png"},"independent":true},
|
||||||
|
{"name":{"common":"Senegal","official":"Republic of Senegal"},"cca2":"SN","cca3":"SEN","region":"Africa","subregion":"Western Africa","currencies":{"XOF":{"name":"West African CFA franc","symbol":"FCFA"}},"idd":{"root":"+221","suffixes":[""]},"flag":"🇸🇳","flags":{"png":"https://flagcdn.com/w320/sn.png"},"independent":true},
|
||||||
|
{"name":{"common":"Zimbabwe","official":"Republic of Zimbabwe"},"cca2":"ZW","cca3":"ZWE","region":"Africa","subregion":"Eastern Africa","currencies":{"ZWL":{"name":"Zimbabwean dollar","symbol":"$"}},"idd":{"root":"+263","suffixes":[""]},"flag":"🇿🇼","flags":{"png":"https://flagcdn.com/w320/zw.png"},"independent":true},
|
||||||
|
{"name":{"common":"Bolivia","official":"Plurinational State of Bolivia"},"cca2":"BO","cca3":"BOL","region":"Americas","subregion":"South America","currencies":{"BOB":{"name":"Bolivian boliviano","symbol":"Bs"}},"idd":{"root":"+591","suffixes":[""]},"flag":"🇧🇴","flags":{"png":"https://flagcdn.com/w320/bo.png"},"independent":true},
|
||||||
|
{"name":{"common":"Ecuador","official":"Republic of Ecuador"},"cca2":"EC","cca3":"ECU","region":"Americas","subregion":"South America","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"idd":{"root":"+593","suffixes":[""]},"flag":"🇪🇨","flags":{"png":"https://flagcdn.com/w320/ec.png"},"independent":true},
|
||||||
|
{"name":{"common":"Uruguay","official":"Oriental Republic of Uruguay"},"cca2":"UY","cca3":"URY","region":"Americas","subregion":"South America","currencies":{"UYU":{"name":"Uruguayan peso","symbol":"$"}},"idd":{"root":"+598","suffixes":[""]},"flag":"🇺🇾","flags":{"png":"https://flagcdn.com/w320/uy.png"},"independent":true},
|
||||||
|
{"name":{"common":"Paraguay","official":"Republic of Paraguay"},"cca2":"PY","cca3":"PRY","region":"Americas","subregion":"South America","currencies":{"PYG":{"name":"Paraguayan guaraní","symbol":"₲"}},"idd":{"root":"+595","suffixes":[""]},"flag":"🇵🇾","flags":{"png":"https://flagcdn.com/w320/py.png"},"independent":true},
|
||||||
|
{"name":{"common":"Venezuela","official":"Bolivarian Republic of Venezuela"},"cca2":"VE","cca3":"VEN","region":"Americas","subregion":"South America","currencies":{"VES":{"name":"Venezuelan bolívar soberano","symbol":"Bs.S"}},"idd":{"root":"+58","suffixes":[""]},"flag":"🇻🇪","flags":{"png":"https://flagcdn.com/w320/ve.png"},"independent":true},
|
||||||
|
{"name":{"common":"Dominican Republic","official":"Dominican Republic"},"cca2":"DO","cca3":"DOM","region":"Americas","subregion":"Caribbean","currencies":{"DOP":{"name":"Dominican peso","symbol":"$"}},"idd":{"root":"+1","suffixes":["809"]},"flag":"🇩🇴","flags":{"png":"https://flagcdn.com/w320/do.png"},"independent":true},
|
||||||
|
{"name":{"common":"Guatemala","official":"Republic of Guatemala"},"cca2":"GT","cca3":"GTM","region":"Americas","subregion":"Central America","currencies":{"GTQ":{"name":"Guatemalan quetzal","symbol":"Q"}},"idd":{"root":"+502","suffixes":[""]},"flag":"🇬🇹","flags":{"png":"https://flagcdn.com/w320/gt.png"},"independent":true},
|
||||||
|
{"name":{"common":"Panama","official":"Republic of Panama"},"cca2":"PA","cca3":"PAN","region":"Americas","subregion":"Central America","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"idd":{"root":"+507","suffixes":[""]},"flag":"🇵🇦","flags":{"png":"https://flagcdn.com/w320/pa.png"},"independent":true},
|
||||||
|
{"name":{"common":"Costa Rica","official":"Republic of Costa Rica"},"cca2":"CR","cca3":"CRI","region":"Americas","subregion":"Central America","currencies":{"CRC":{"name":"Costa Rican colón","symbol":"₡"}},"idd":{"root":"+506","suffixes":[""]},"flag":"🇨🇷","flags":{"png":"https://flagcdn.com/w320/cr.png"},"independent":true},
|
||||||
|
{"name":{"common":"Vietnam","official":"Socialist Republic of Vietnam"},"cca2":"VN","cca3":"VNM","region":"Asia","subregion":"South-Eastern Asia","currencies":{"VND":{"name":"Vietnamese đồng","symbol":"₫"}},"idd":{"root":"+84","suffixes":[""]},"flag":"🇻🇳","flags":{"png":"https://flagcdn.com/w320/vn.png"},"independent":true}
|
||||||
|
]
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<!-- 日志存放路径 -->
|
<!-- 日志存放路径 -->
|
||||||
<property name="log.path" value="/home/ruoyi/logs" />
|
<property name="log.path" value="${user.dir}/logs" />
|
||||||
<!-- 日志输出格式 -->
|
<!-- 日志输出格式 -->
|
||||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
||||||
|
|
||||||
|
|||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
package com.ruoyi.framework.config;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RestTemplate配置
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class RestTemplateConfig
|
||||||
|
{
|
||||||
|
@Bean
|
||||||
|
public RestTemplate restTemplate()
|
||||||
|
{
|
||||||
|
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
|
||||||
|
factory.setConnectTimeout(10000);
|
||||||
|
factory.setReadTimeout(30000);
|
||||||
|
return new RestTemplate(factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
package com.ruoyi.system.domain;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
import com.ruoyi.common.annotation.Excel;
|
||||||
|
import com.ruoyi.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国家/区域 bms_region
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public class BmsRegion extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 区域ID */
|
||||||
|
@Excel(name = "区域ID")
|
||||||
|
private Long regionId;
|
||||||
|
|
||||||
|
/** 中文名 */
|
||||||
|
@Excel(name = "中文名")
|
||||||
|
private String countryNameCn;
|
||||||
|
|
||||||
|
/** 英文名 */
|
||||||
|
@Excel(name = "英文名")
|
||||||
|
private String countryNameEn;
|
||||||
|
|
||||||
|
/** ISO两位码 */
|
||||||
|
@Excel(name = "国家代码")
|
||||||
|
private String countryCode2;
|
||||||
|
|
||||||
|
/** ISO三位码 */
|
||||||
|
@Excel(name = "ISO三位码")
|
||||||
|
private String countryCode3;
|
||||||
|
|
||||||
|
/** 洲/大区 */
|
||||||
|
@Excel(name = "洲/大区")
|
||||||
|
private String continent;
|
||||||
|
|
||||||
|
/** 子区域 */
|
||||||
|
@Excel(name = "子区域")
|
||||||
|
private String subRegion;
|
||||||
|
|
||||||
|
/** 货币代码 */
|
||||||
|
@Excel(name = "货币代码")
|
||||||
|
private String currencyCode;
|
||||||
|
|
||||||
|
/** 货币名称 */
|
||||||
|
@Excel(name = "货币名称")
|
||||||
|
private String currencyName;
|
||||||
|
|
||||||
|
/** 货币符号 */
|
||||||
|
private String currencySymbol;
|
||||||
|
|
||||||
|
/** 电话前缀 */
|
||||||
|
@Excel(name = "电话前缀")
|
||||||
|
private String phonePrefix;
|
||||||
|
|
||||||
|
/** 国旗emoji */
|
||||||
|
private String flagEmoji;
|
||||||
|
|
||||||
|
/** 国旗图片URL */
|
||||||
|
private String flagUrl;
|
||||||
|
|
||||||
|
/** 是否独立(1是 0否) */
|
||||||
|
@Excel(name = "是否独立", readConverterExp = "1=是,0=否")
|
||||||
|
private String isIndependent;
|
||||||
|
|
||||||
|
/** 是否欧盟成员(1是 0否) */
|
||||||
|
@Excel(name = "是否欧盟", readConverterExp = "1=是,0=否")
|
||||||
|
private String isEu;
|
||||||
|
|
||||||
|
/** 状态(0正常 1停用) */
|
||||||
|
@Excel(name = "状态", readConverterExp = "0=正常,1=停用")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/** 删除标志(0存在 2删除) */
|
||||||
|
private String delFlag;
|
||||||
|
|
||||||
|
public Long getRegionId()
|
||||||
|
{
|
||||||
|
return regionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegionId(Long regionId)
|
||||||
|
{
|
||||||
|
this.regionId = regionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCountryNameCn()
|
||||||
|
{
|
||||||
|
return countryNameCn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCountryNameCn(String countryNameCn)
|
||||||
|
{
|
||||||
|
this.countryNameCn = countryNameCn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCountryNameEn()
|
||||||
|
{
|
||||||
|
return countryNameEn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCountryNameEn(String countryNameEn)
|
||||||
|
{
|
||||||
|
this.countryNameEn = countryNameEn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCountryCode2()
|
||||||
|
{
|
||||||
|
return countryCode2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCountryCode2(String countryCode2)
|
||||||
|
{
|
||||||
|
this.countryCode2 = countryCode2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCountryCode3()
|
||||||
|
{
|
||||||
|
return countryCode3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCountryCode3(String countryCode3)
|
||||||
|
{
|
||||||
|
this.countryCode3 = countryCode3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContinent()
|
||||||
|
{
|
||||||
|
return continent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContinent(String continent)
|
||||||
|
{
|
||||||
|
this.continent = continent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubRegion()
|
||||||
|
{
|
||||||
|
return subRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubRegion(String subRegion)
|
||||||
|
{
|
||||||
|
this.subRegion = subRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrencyCode()
|
||||||
|
{
|
||||||
|
return currencyCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrencyCode(String currencyCode)
|
||||||
|
{
|
||||||
|
this.currencyCode = currencyCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrencyName()
|
||||||
|
{
|
||||||
|
return currencyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrencyName(String currencyName)
|
||||||
|
{
|
||||||
|
this.currencyName = currencyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrencySymbol()
|
||||||
|
{
|
||||||
|
return currencySymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrencySymbol(String currencySymbol)
|
||||||
|
{
|
||||||
|
this.currencySymbol = currencySymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPhonePrefix()
|
||||||
|
{
|
||||||
|
return phonePrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhonePrefix(String phonePrefix)
|
||||||
|
{
|
||||||
|
this.phonePrefix = phonePrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFlagEmoji()
|
||||||
|
{
|
||||||
|
return flagEmoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlagEmoji(String flagEmoji)
|
||||||
|
{
|
||||||
|
this.flagEmoji = flagEmoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFlagUrl()
|
||||||
|
{
|
||||||
|
return flagUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlagUrl(String flagUrl)
|
||||||
|
{
|
||||||
|
this.flagUrl = flagUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIsIndependent()
|
||||||
|
{
|
||||||
|
return isIndependent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsIndependent(String isIndependent)
|
||||||
|
{
|
||||||
|
this.isIndependent = isIndependent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIsEu()
|
||||||
|
{
|
||||||
|
return isEu;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsEu(String isEu)
|
||||||
|
{
|
||||||
|
this.isEu = isEu;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus()
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(String status)
|
||||||
|
{
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDelFlag()
|
||||||
|
{
|
||||||
|
return delFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDelFlag(String delFlag)
|
||||||
|
{
|
||||||
|
this.delFlag = delFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
||||||
|
.append("regionId", getRegionId())
|
||||||
|
.append("countryNameCn", getCountryNameCn())
|
||||||
|
.append("countryNameEn", getCountryNameEn())
|
||||||
|
.append("countryCode2", getCountryCode2())
|
||||||
|
.append("countryCode3", getCountryCode3())
|
||||||
|
.append("continent", getContinent())
|
||||||
|
.append("subRegion", getSubRegion())
|
||||||
|
.append("status", getStatus())
|
||||||
|
.append("createBy", getCreateBy())
|
||||||
|
.append("createTime", getCreateTime())
|
||||||
|
.append("updateBy", getUpdateBy())
|
||||||
|
.append("updateTime", getUpdateTime())
|
||||||
|
.append("remark", getRemark())
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package com.ruoyi.system.domain;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
import com.ruoyi.common.annotation.Excel;
|
||||||
|
import com.ruoyi.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区域数据同步日志 bms_region_sync_log
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public class BmsRegionSyncLog extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 日志ID */
|
||||||
|
@Excel(name = "日志ID")
|
||||||
|
private Long logId;
|
||||||
|
|
||||||
|
/** 同步类型 */
|
||||||
|
@Excel(name = "同步类型")
|
||||||
|
private String syncType;
|
||||||
|
|
||||||
|
/** 状态 */
|
||||||
|
@Excel(name = "状态", readConverterExp = "PENDING=待处理,PROCESSING=处理中,SUCCESS=成功,FAILED=失败")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/** API返回总数 */
|
||||||
|
@Excel(name = "总数")
|
||||||
|
private Integer totalCount;
|
||||||
|
|
||||||
|
/** 新增数 */
|
||||||
|
@Excel(name = "新增数")
|
||||||
|
private Integer insertCount;
|
||||||
|
|
||||||
|
/** 更新数 */
|
||||||
|
@Excel(name = "更新数")
|
||||||
|
private Integer updateCount;
|
||||||
|
|
||||||
|
/** 失败数 */
|
||||||
|
@Excel(name = "失败数")
|
||||||
|
private Integer failCount;
|
||||||
|
|
||||||
|
/** 耗时(毫秒) */
|
||||||
|
@Excel(name = "耗时(ms)")
|
||||||
|
private Long durationMs;
|
||||||
|
|
||||||
|
/** 错误信息 */
|
||||||
|
private String errorMsg;
|
||||||
|
|
||||||
|
public Long getLogId()
|
||||||
|
{
|
||||||
|
return logId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLogId(Long logId)
|
||||||
|
{
|
||||||
|
this.logId = logId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSyncType()
|
||||||
|
{
|
||||||
|
return syncType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSyncType(String syncType)
|
||||||
|
{
|
||||||
|
this.syncType = syncType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus()
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(String status)
|
||||||
|
{
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getTotalCount()
|
||||||
|
{
|
||||||
|
return totalCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTotalCount(Integer totalCount)
|
||||||
|
{
|
||||||
|
this.totalCount = totalCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getInsertCount()
|
||||||
|
{
|
||||||
|
return insertCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInsertCount(Integer insertCount)
|
||||||
|
{
|
||||||
|
this.insertCount = insertCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUpdateCount()
|
||||||
|
{
|
||||||
|
return updateCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateCount(Integer updateCount)
|
||||||
|
{
|
||||||
|
this.updateCount = updateCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getFailCount()
|
||||||
|
{
|
||||||
|
return failCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFailCount(Integer failCount)
|
||||||
|
{
|
||||||
|
this.failCount = failCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDurationMs()
|
||||||
|
{
|
||||||
|
return durationMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDurationMs(Long durationMs)
|
||||||
|
{
|
||||||
|
this.durationMs = durationMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorMsg()
|
||||||
|
{
|
||||||
|
return errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrorMsg(String errorMsg)
|
||||||
|
{
|
||||||
|
this.errorMsg = errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
||||||
|
.append("logId", getLogId())
|
||||||
|
.append("syncType", getSyncType())
|
||||||
|
.append("status", getStatus())
|
||||||
|
.append("totalCount", getTotalCount())
|
||||||
|
.append("insertCount", getInsertCount())
|
||||||
|
.append("updateCount", getUpdateCount())
|
||||||
|
.append("failCount", getFailCount())
|
||||||
|
.append("durationMs", getDurationMs())
|
||||||
|
.append("errorMsg", getErrorMsg())
|
||||||
|
.append("createBy", getCreateBy())
|
||||||
|
.append("createTime", getCreateTime())
|
||||||
|
.append("updateTime", getUpdateTime())
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package com.ruoyi.system.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.ruoyi.system.domain.BmsRegion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国家/区域 数据层
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public interface BmsRegionMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 查询区域信息
|
||||||
|
*
|
||||||
|
* @param regionId 区域ID
|
||||||
|
* @return 区域信息
|
||||||
|
*/
|
||||||
|
public BmsRegion selectRegionById(Long regionId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询区域列表
|
||||||
|
*
|
||||||
|
* @param region 区域信息
|
||||||
|
* @return 区域集合
|
||||||
|
*/
|
||||||
|
public List<BmsRegion> selectRegionList(BmsRegion region);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ISO两位码查询区域
|
||||||
|
*
|
||||||
|
* @param countryCode2 ISO两位码
|
||||||
|
* @return 区域信息
|
||||||
|
*/
|
||||||
|
public BmsRegion selectRegionByCode2(String countryCode2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增区域
|
||||||
|
*
|
||||||
|
* @param region 区域信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertRegion(BmsRegion region);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改区域
|
||||||
|
*
|
||||||
|
* @param region 区域信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateRegion(BmsRegion region);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除区域
|
||||||
|
*
|
||||||
|
* @param regionIds 需要删除的区域ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteRegionByIds(Long[] regionIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ISO两位码做upsert(存在则更新,不存在则新增)
|
||||||
|
*
|
||||||
|
* @param region 区域信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int upsertByCode2(BmsRegion region);
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
package com.ruoyi.system.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.ruoyi.system.domain.BmsRegionSyncLog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区域数据同步日志 数据层
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public interface BmsRegionSyncLogMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 查询同步日志
|
||||||
|
*
|
||||||
|
* @param logId 日志ID
|
||||||
|
* @return 同步日志
|
||||||
|
*/
|
||||||
|
public BmsRegionSyncLog selectSyncLogById(Long logId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询同步日志列表
|
||||||
|
*
|
||||||
|
* @param syncLog 同步日志
|
||||||
|
* @return 同步日志集合
|
||||||
|
*/
|
||||||
|
public List<BmsRegionSyncLog> selectSyncLogList(BmsRegionSyncLog syncLog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增同步日志
|
||||||
|
*
|
||||||
|
* @param syncLog 同步日志
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertSyncLog(BmsRegionSyncLog syncLog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改同步日志
|
||||||
|
*
|
||||||
|
* @param syncLog 同步日志
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateSyncLog(BmsRegionSyncLog syncLog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除同步日志
|
||||||
|
*
|
||||||
|
* @param logIds 需要删除的日志ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteSyncLogByIds(Long[] logIds);
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.ruoyi.system.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.ruoyi.system.domain.BmsRegion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国家/区域 服务层
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public interface IBmsRegionService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 查询区域信息
|
||||||
|
*
|
||||||
|
* @param regionId 区域ID
|
||||||
|
* @return 区域信息
|
||||||
|
*/
|
||||||
|
public BmsRegion selectRegionById(Long regionId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询区域列表
|
||||||
|
*
|
||||||
|
* @param region 区域信息
|
||||||
|
* @return 区域集合
|
||||||
|
*/
|
||||||
|
public List<BmsRegion> selectRegionList(BmsRegion region);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增区域
|
||||||
|
*
|
||||||
|
* @param region 区域信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertRegion(BmsRegion region);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改区域
|
||||||
|
*
|
||||||
|
* @param region 区域信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateRegion(BmsRegion region);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除区域
|
||||||
|
*
|
||||||
|
* @param regionIds 需要删除的区域ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteRegionByIds(Long[] regionIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改区域状态
|
||||||
|
*
|
||||||
|
* @param region 区域信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateRegionStatus(BmsRegion region);
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package com.ruoyi.system.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区域数据同步 服务层
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public interface IBmsRegionSyncService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 触发同步国家数据(异步)
|
||||||
|
*
|
||||||
|
* @return 日志ID
|
||||||
|
*/
|
||||||
|
public Long syncRegion();
|
||||||
|
}
|
||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
package com.ruoyi.system.service.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import com.ruoyi.system.domain.BmsRegion;
|
||||||
|
import com.ruoyi.system.mapper.BmsRegionMapper;
|
||||||
|
import com.ruoyi.system.service.IBmsRegionService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国家/区域 服务层实现
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class BmsRegionServiceImpl implements IBmsRegionService
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private BmsRegionMapper regionMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询区域信息
|
||||||
|
*
|
||||||
|
* @param regionId 区域ID
|
||||||
|
* @return 区域信息
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public BmsRegion selectRegionById(Long regionId)
|
||||||
|
{
|
||||||
|
return regionMapper.selectRegionById(regionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询区域列表
|
||||||
|
*
|
||||||
|
* @param region 区域信息
|
||||||
|
* @return 区域集合
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<BmsRegion> selectRegionList(BmsRegion region)
|
||||||
|
{
|
||||||
|
return regionMapper.selectRegionList(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增区域
|
||||||
|
*
|
||||||
|
* @param region 区域信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int insertRegion(BmsRegion region)
|
||||||
|
{
|
||||||
|
return regionMapper.insertRegion(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改区域
|
||||||
|
*
|
||||||
|
* @param region 区域信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int updateRegion(BmsRegion region)
|
||||||
|
{
|
||||||
|
return regionMapper.updateRegion(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除区域
|
||||||
|
*
|
||||||
|
* @param regionIds 需要删除的区域ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int deleteRegionByIds(Long[] regionIds)
|
||||||
|
{
|
||||||
|
return regionMapper.deleteRegionByIds(regionIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改区域状态
|
||||||
|
*
|
||||||
|
* @param region 区域信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int updateRegionStatus(BmsRegion region)
|
||||||
|
{
|
||||||
|
return regionMapper.updateRegion(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
+249
@@ -0,0 +1,249 @@
|
|||||||
|
package com.ruoyi.system.service.impl;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import com.ruoyi.system.domain.BmsRegion;
|
||||||
|
import com.ruoyi.system.domain.BmsRegionSyncLog;
|
||||||
|
import com.ruoyi.system.mapper.BmsRegionMapper;
|
||||||
|
import com.ruoyi.system.mapper.BmsRegionSyncLogMapper;
|
||||||
|
import com.ruoyi.system.service.IBmsRegionSyncService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区域数据同步 服务层实现
|
||||||
|
* 从本地 countries.json 文件加载国家数据
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class BmsRegionSyncServiceImpl implements IBmsRegionSyncService
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(BmsRegionSyncServiceImpl.class);
|
||||||
|
|
||||||
|
private static final String DATA_FILE = "countries.json";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BmsRegionMapper regionMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BmsRegionSyncLogMapper syncLogMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发同步国家数据(异步)
|
||||||
|
*
|
||||||
|
* @return 日志ID
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Long syncRegion()
|
||||||
|
{
|
||||||
|
// 创建同步日志记录
|
||||||
|
BmsRegionSyncLog syncLog = new BmsRegionSyncLog();
|
||||||
|
syncLog.setSyncType("ALL");
|
||||||
|
syncLog.setStatus("PROCESSING");
|
||||||
|
syncLog.setTotalCount(0);
|
||||||
|
syncLog.setInsertCount(0);
|
||||||
|
syncLog.setUpdateCount(0);
|
||||||
|
syncLog.setFailCount(0);
|
||||||
|
syncLog.setDurationMs(0L);
|
||||||
|
syncLogMapper.insertSyncLog(syncLog);
|
||||||
|
|
||||||
|
// 异步执行同步
|
||||||
|
asyncSync(syncLog.getLogId());
|
||||||
|
|
||||||
|
return syncLog.getLogId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步同步国家数据
|
||||||
|
*
|
||||||
|
* @param logId 日志ID
|
||||||
|
*/
|
||||||
|
@Async("threadPoolTaskExecutor")
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void asyncSync(Long logId)
|
||||||
|
{
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
BmsRegionSyncLog syncLog = syncLogMapper.selectSyncLogById(logId);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
log.info("开始同步国家数据,读取本地文件: {}", DATA_FILE);
|
||||||
|
|
||||||
|
// 从classpath读取国家数据文件
|
||||||
|
ClassPathResource resource = new ClassPathResource(DATA_FILE);
|
||||||
|
InputStream inputStream = resource.getInputStream();
|
||||||
|
byte[] bytes = inputStream.readAllBytes();
|
||||||
|
inputStream.close();
|
||||||
|
String jsonData = new String(bytes, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(jsonData))
|
||||||
|
{
|
||||||
|
throw new RuntimeException("国家数据文件为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析JSON
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
List<Object> countryList = objectMapper.readValue(jsonData, List.class);
|
||||||
|
|
||||||
|
int insertCount = 0;
|
||||||
|
int updateCount = 0;
|
||||||
|
int failCount = 0;
|
||||||
|
|
||||||
|
for (Object obj : countryList)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> country = (Map<String, Object>) obj;
|
||||||
|
BmsRegion region = parseCountry(country);
|
||||||
|
|
||||||
|
if (region == null || StringUtils.isEmpty(region.getCountryCode2()))
|
||||||
|
{
|
||||||
|
failCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否已存在
|
||||||
|
BmsRegion existing = regionMapper.selectRegionByCode2(region.getCountryCode2());
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
region.setRegionId(existing.getRegionId());
|
||||||
|
regionMapper.updateRegion(region);
|
||||||
|
updateCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
regionMapper.insertRegion(region);
|
||||||
|
insertCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
failCount++;
|
||||||
|
log.warn("解析国家数据失败: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新同步日志
|
||||||
|
long duration = System.currentTimeMillis() - startTime;
|
||||||
|
syncLog.setStatus("SUCCESS");
|
||||||
|
syncLog.setTotalCount(countryList.size());
|
||||||
|
syncLog.setInsertCount(insertCount);
|
||||||
|
syncLog.setUpdateCount(updateCount);
|
||||||
|
syncLog.setFailCount(failCount);
|
||||||
|
syncLog.setDurationMs(duration);
|
||||||
|
syncLogMapper.updateSyncLog(syncLog);
|
||||||
|
|
||||||
|
log.info("同步国家数据完成: 总数={}, 新增={}, 更新={}, 失败={}, 耗时={}ms",
|
||||||
|
countryList.size(), insertCount, updateCount, failCount, duration);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
long duration = System.currentTimeMillis() - startTime;
|
||||||
|
syncLog.setStatus("FAILED");
|
||||||
|
syncLog.setDurationMs(duration);
|
||||||
|
syncLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
|
||||||
|
syncLogMapper.updateSyncLog(syncLog);
|
||||||
|
|
||||||
|
log.error("同步国家数据失败: {}", e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析国家数据
|
||||||
|
*
|
||||||
|
* @param country 国家Map
|
||||||
|
* @return 区域实体
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private BmsRegion parseCountry(Map<String, Object> country)
|
||||||
|
{
|
||||||
|
BmsRegion region = new BmsRegion();
|
||||||
|
region.setStatus("0");
|
||||||
|
region.setIsIndependent("1");
|
||||||
|
region.setIsEu("0");
|
||||||
|
|
||||||
|
// 英文名 name.common
|
||||||
|
Map<String, Object> name = (Map<String, Object>) country.get("name");
|
||||||
|
if (name != null)
|
||||||
|
{
|
||||||
|
region.setCountryNameEn((String) name.get("common"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 中文名 translations.cmn.common,如无则用英文名
|
||||||
|
Map<String, Object> translations = (Map<String, Object>) country.get("translations");
|
||||||
|
if (translations != null)
|
||||||
|
{
|
||||||
|
Map<String, Object> cmn = (Map<String, Object>) translations.get("cmn");
|
||||||
|
if (cmn != null)
|
||||||
|
{
|
||||||
|
region.setCountryNameCn((String) cmn.get("common"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(region.getCountryNameCn()))
|
||||||
|
{
|
||||||
|
region.setCountryNameCn(region.getCountryNameEn());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ISO代码
|
||||||
|
region.setCountryCode2((String) country.get("cca2"));
|
||||||
|
region.setCountryCode3((String) country.get("cca3"));
|
||||||
|
|
||||||
|
// 大洲/子区域
|
||||||
|
region.setContinent((String) country.get("region"));
|
||||||
|
region.setSubRegion((String) country.get("subregion"));
|
||||||
|
|
||||||
|
// 货币
|
||||||
|
Map<String, Object> currencies = (Map<String, Object>) country.get("currencies");
|
||||||
|
if (currencies != null && !currencies.isEmpty())
|
||||||
|
{
|
||||||
|
Map.Entry<String, Object> entry = currencies.entrySet().iterator().next();
|
||||||
|
region.setCurrencyCode(entry.getKey());
|
||||||
|
Map<String, Object> currency = (Map<String, Object>) entry.getValue();
|
||||||
|
if (currency != null)
|
||||||
|
{
|
||||||
|
region.setCurrencyName((String) currency.get("name"));
|
||||||
|
region.setCurrencySymbol((String) currency.get("symbol"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 电话前缀 idd.root + idd.suffixes
|
||||||
|
Map<String, Object> idd = (Map<String, Object>) country.get("idd");
|
||||||
|
if (idd != null)
|
||||||
|
{
|
||||||
|
String root = (String) idd.get("root");
|
||||||
|
List<String> suffixes = (List<String>) idd.get("suffixes");
|
||||||
|
if (StringUtils.isNotEmpty(root) && suffixes != null && !suffixes.isEmpty())
|
||||||
|
{
|
||||||
|
region.setPhonePrefix(root + suffixes.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 国旗
|
||||||
|
region.setFlagEmoji((String) country.get("flag"));
|
||||||
|
Map<String, Object> flags = (Map<String, Object>) country.get("flags");
|
||||||
|
if (flags != null)
|
||||||
|
{
|
||||||
|
region.setFlagUrl((String) flags.get("png"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否独立
|
||||||
|
Boolean independent = (Boolean) country.get("independent");
|
||||||
|
if (independent != null)
|
||||||
|
{
|
||||||
|
region.setIsIndependent(independent ? "1" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.ruoyi.system.mapper.BmsRegionMapper">
|
||||||
|
|
||||||
|
<resultMap type="BmsRegion" id="BmsRegionResult">
|
||||||
|
<id property="regionId" column="region_id" />
|
||||||
|
<result property="countryNameCn" column="country_name_cn" />
|
||||||
|
<result property="countryNameEn" column="country_name_en" />
|
||||||
|
<result property="countryCode2" column="country_code_2" />
|
||||||
|
<result property="countryCode3" column="country_code_3" />
|
||||||
|
<result property="continent" column="continent" />
|
||||||
|
<result property="subRegion" column="sub_region" />
|
||||||
|
<result property="currencyCode" column="currency_code" />
|
||||||
|
<result property="currencyName" column="currency_name" />
|
||||||
|
<result property="currencySymbol" column="currency_symbol" />
|
||||||
|
<result property="phonePrefix" column="phone_prefix" />
|
||||||
|
<result property="flagEmoji" column="flag_emoji" />
|
||||||
|
<result property="flagUrl" column="flag_url" />
|
||||||
|
<result property="isIndependent" column="is_independent" />
|
||||||
|
<result property="isEu" column="is_eu" />
|
||||||
|
<result property="status" column="status" />
|
||||||
|
<result property="delFlag" column="del_flag" />
|
||||||
|
<result property="createBy" column="create_by" />
|
||||||
|
<result property="createTime" column="create_time" />
|
||||||
|
<result property="updateBy" column="update_by" />
|
||||||
|
<result property="updateTime" column="update_time" />
|
||||||
|
<result property="remark" column="remark" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectRegionVo">
|
||||||
|
select region_id, country_name_cn, country_name_en, country_code_2, country_code_3,
|
||||||
|
continent, sub_region, currency_code, currency_name, currency_symbol,
|
||||||
|
phone_prefix, flag_emoji, flag_url, is_independent, is_eu,
|
||||||
|
status, del_flag, create_by, create_time, update_by, update_time, remark
|
||||||
|
from bms_region
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectRegionById" parameterType="Long" resultMap="BmsRegionResult">
|
||||||
|
<include refid="selectRegionVo"/>
|
||||||
|
where region_id = #{regionId}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectRegionByCode2" parameterType="String" resultMap="BmsRegionResult">
|
||||||
|
<include refid="selectRegionVo"/>
|
||||||
|
where country_code_2 = #{countryCode2} limit 1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectRegionList" parameterType="BmsRegion" resultMap="BmsRegionResult">
|
||||||
|
<include refid="selectRegionVo"/>
|
||||||
|
<where>
|
||||||
|
del_flag = '0'
|
||||||
|
<if test="countryNameCn != null and countryNameCn != ''">
|
||||||
|
AND country_name_cn like concat('%', #{countryNameCn}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="countryNameEn != null and countryNameEn != ''">
|
||||||
|
AND country_name_en like concat('%', #{countryNameEn}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="countryCode2 != null and countryCode2 != ''">
|
||||||
|
AND country_code_2 like concat('%', #{countryCode2}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="continent != null and continent != ''">
|
||||||
|
AND continent = #{continent}
|
||||||
|
</if>
|
||||||
|
<if test="status != null and status != ''">
|
||||||
|
AND status = #{status}
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
order by region_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertRegion" parameterType="BmsRegion" useGeneratedKeys="true" keyProperty="regionId">
|
||||||
|
insert into bms_region (
|
||||||
|
<if test="countryNameCn != null">country_name_cn,</if>
|
||||||
|
<if test="countryNameEn != null and countryNameEn != ''">country_name_en,</if>
|
||||||
|
<if test="countryCode2 != null and countryCode2 != ''">country_code_2,</if>
|
||||||
|
<if test="countryCode3 != null">country_code_3,</if>
|
||||||
|
<if test="continent != null">continent,</if>
|
||||||
|
<if test="subRegion != null">sub_region,</if>
|
||||||
|
<if test="currencyCode != null">currency_code,</if>
|
||||||
|
<if test="currencyName != null">currency_name,</if>
|
||||||
|
<if test="currencySymbol != null">currency_symbol,</if>
|
||||||
|
<if test="phonePrefix != null">phone_prefix,</if>
|
||||||
|
<if test="flagEmoji != null">flag_emoji,</if>
|
||||||
|
<if test="flagUrl != null">flag_url,</if>
|
||||||
|
<if test="isIndependent != null and isIndependent != ''">is_independent,</if>
|
||||||
|
<if test="isEu != null and isEu != ''">is_eu,</if>
|
||||||
|
<if test="status != null and status != ''">status,</if>
|
||||||
|
<if test="delFlag != null and delFlag != ''">del_flag,</if>
|
||||||
|
<if test="createBy != null and createBy != ''">create_by,</if>
|
||||||
|
<if test="remark != null">remark,</if>
|
||||||
|
create_time
|
||||||
|
) values (
|
||||||
|
<if test="countryNameCn != null">#{countryNameCn},</if>
|
||||||
|
<if test="countryNameEn != null and countryNameEn != ''">#{countryNameEn},</if>
|
||||||
|
<if test="countryCode2 != null and countryCode2 != ''">#{countryCode2},</if>
|
||||||
|
<if test="countryCode3 != null">#{countryCode3},</if>
|
||||||
|
<if test="continent != null">#{continent},</if>
|
||||||
|
<if test="subRegion != null">#{subRegion},</if>
|
||||||
|
<if test="currencyCode != null">#{currencyCode},</if>
|
||||||
|
<if test="currencyName != null">#{currencyName},</if>
|
||||||
|
<if test="currencySymbol != null">#{currencySymbol},</if>
|
||||||
|
<if test="phonePrefix != null">#{phonePrefix},</if>
|
||||||
|
<if test="flagEmoji != null">#{flagEmoji},</if>
|
||||||
|
<if test="flagUrl != null">#{flagUrl},</if>
|
||||||
|
<if test="isIndependent != null and isIndependent != ''">#{isIndependent},</if>
|
||||||
|
<if test="isEu != null and isEu != ''">#{isEu},</if>
|
||||||
|
<if test="status != null and status != ''">#{status},</if>
|
||||||
|
<if test="delFlag != null and delFlag != ''">#{delFlag},</if>
|
||||||
|
<if test="createBy != null and createBy != ''">#{createBy},</if>
|
||||||
|
<if test="remark != null">#{remark},</if>
|
||||||
|
sysdate()
|
||||||
|
)
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateRegion" parameterType="BmsRegion">
|
||||||
|
update bms_region
|
||||||
|
<set>
|
||||||
|
<if test="countryNameCn != null">country_name_cn = #{countryNameCn},</if>
|
||||||
|
<if test="countryNameEn != null and countryNameEn != ''">country_name_en = #{countryNameEn},</if>
|
||||||
|
<if test="countryCode2 != null and countryCode2 != ''">country_code_2 = #{countryCode2},</if>
|
||||||
|
<if test="countryCode3 != null">country_code_3 = #{countryCode3},</if>
|
||||||
|
<if test="continent != null">continent = #{continent},</if>
|
||||||
|
<if test="subRegion != null">sub_region = #{subRegion},</if>
|
||||||
|
<if test="currencyCode != null">currency_code = #{currencyCode},</if>
|
||||||
|
<if test="currencyName != null">currency_name = #{currencyName},</if>
|
||||||
|
<if test="currencySymbol != null">currency_symbol = #{currencySymbol},</if>
|
||||||
|
<if test="phonePrefix != null">phone_prefix = #{phonePrefix},</if>
|
||||||
|
<if test="flagEmoji != null">flag_emoji = #{flagEmoji},</if>
|
||||||
|
<if test="flagUrl != null">flag_url = #{flagUrl},</if>
|
||||||
|
<if test="isIndependent != null and isIndependent != ''">is_independent = #{isIndependent},</if>
|
||||||
|
<if test="isEu != null and isEu != ''">is_eu = #{isEu},</if>
|
||||||
|
<if test="status != null and status != ''">status = #{status},</if>
|
||||||
|
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
|
update_time = sysdate()
|
||||||
|
</set>
|
||||||
|
where region_id = #{regionId}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteRegionByIds" parameterType="Long">
|
||||||
|
delete from bms_region where region_id in
|
||||||
|
<foreach item="regionId" collection="array" open="(" separator="," close=")">
|
||||||
|
#{regionId}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<insert id="upsertByCode2" parameterType="BmsRegion">
|
||||||
|
insert into bms_region (
|
||||||
|
country_name_cn, country_name_en, country_code_2, country_code_3,
|
||||||
|
continent, sub_region, currency_code, currency_name, currency_symbol,
|
||||||
|
phone_prefix, flag_emoji, flag_url, is_independent, is_eu,
|
||||||
|
status, del_flag, create_by, create_time
|
||||||
|
) values (
|
||||||
|
#{countryNameCn}, #{countryNameEn}, #{countryCode2}, #{countryCode3},
|
||||||
|
#{continent}, #{subRegion}, #{currencyCode}, #{currencyName}, #{currencySymbol},
|
||||||
|
#{phonePrefix}, #{flagEmoji}, #{flagUrl}, #{isIndependent}, #{isEu},
|
||||||
|
#{status}, '0', #{createBy}, sysdate()
|
||||||
|
)
|
||||||
|
on duplicate key update
|
||||||
|
country_name_cn = values(country_name_cn),
|
||||||
|
country_name_en = values(country_name_en),
|
||||||
|
country_code_3 = values(country_code_3),
|
||||||
|
continent = values(continent),
|
||||||
|
sub_region = values(sub_region),
|
||||||
|
currency_code = values(currency_code),
|
||||||
|
currency_name = values(currency_name),
|
||||||
|
currency_symbol = values(currency_symbol),
|
||||||
|
phone_prefix = values(phone_prefix),
|
||||||
|
flag_emoji = values(flag_emoji),
|
||||||
|
flag_url = values(flag_url),
|
||||||
|
is_independent = values(is_independent),
|
||||||
|
is_eu = values(is_eu),
|
||||||
|
update_by = #{updateBy},
|
||||||
|
update_time = sysdate()
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.ruoyi.system.mapper.BmsRegionSyncLogMapper">
|
||||||
|
|
||||||
|
<resultMap type="BmsRegionSyncLog" id="BmsRegionSyncLogResult">
|
||||||
|
<id property="logId" column="log_id" />
|
||||||
|
<result property="syncType" column="sync_type" />
|
||||||
|
<result property="status" column="status" />
|
||||||
|
<result property="totalCount" column="total_count" />
|
||||||
|
<result property="insertCount" column="insert_count" />
|
||||||
|
<result property="updateCount" column="update_count" />
|
||||||
|
<result property="failCount" column="fail_count" />
|
||||||
|
<result property="durationMs" column="duration_ms" />
|
||||||
|
<result property="errorMsg" column="error_msg" />
|
||||||
|
<result property="createBy" column="create_by" />
|
||||||
|
<result property="createTime" column="create_time" />
|
||||||
|
<result property="updateBy" column="update_by" />
|
||||||
|
<result property="updateTime" column="update_time" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectSyncLogVo">
|
||||||
|
select log_id, sync_type, status, total_count, insert_count, update_count,
|
||||||
|
fail_count, duration_ms, error_msg, create_by, create_time, update_by, update_time
|
||||||
|
from bms_region_sync_log
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectSyncLogById" parameterType="Long" resultMap="BmsRegionSyncLogResult">
|
||||||
|
<include refid="selectSyncLogVo"/>
|
||||||
|
where log_id = #{logId}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectSyncLogList" parameterType="BmsRegionSyncLog" resultMap="BmsRegionSyncLogResult">
|
||||||
|
<include refid="selectSyncLogVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="syncType != null and syncType != ''">
|
||||||
|
AND sync_type = #{syncType}
|
||||||
|
</if>
|
||||||
|
<if test="status != null and status != ''">
|
||||||
|
AND status = #{status}
|
||||||
|
</if>
|
||||||
|
<if test="params.beginTime != null and params.beginTime != ''">
|
||||||
|
and date_format(create_time,'%Y%m%d') >= date_format(#{params.beginTime},'%Y%m%d')
|
||||||
|
</if>
|
||||||
|
<if test="params.endTime != null and params.endTime != ''">
|
||||||
|
and date_format(create_time,'%Y%m%d') <= date_format(#{params.endTime},'%Y%m%d')
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
order by log_id desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertSyncLog" parameterType="BmsRegionSyncLog" useGeneratedKeys="true" keyProperty="logId">
|
||||||
|
insert into bms_region_sync_log (
|
||||||
|
<if test="syncType != null and syncType != ''">sync_type,</if>
|
||||||
|
<if test="status != null and status != ''">status,</if>
|
||||||
|
<if test="totalCount != null">total_count,</if>
|
||||||
|
<if test="insertCount != null">insert_count,</if>
|
||||||
|
<if test="updateCount != null">update_count,</if>
|
||||||
|
<if test="failCount != null">fail_count,</if>
|
||||||
|
<if test="durationMs != null">duration_ms,</if>
|
||||||
|
<if test="errorMsg != null">error_msg,</if>
|
||||||
|
<if test="createBy != null and createBy != ''">create_by,</if>
|
||||||
|
create_time
|
||||||
|
) values (
|
||||||
|
<if test="syncType != null and syncType != ''">#{syncType},</if>
|
||||||
|
<if test="status != null and status != ''">#{status},</if>
|
||||||
|
<if test="totalCount != null">#{totalCount},</if>
|
||||||
|
<if test="insertCount != null">#{insertCount},</if>
|
||||||
|
<if test="updateCount != null">#{updateCount},</if>
|
||||||
|
<if test="failCount != null">#{failCount},</if>
|
||||||
|
<if test="durationMs != null">#{durationMs},</if>
|
||||||
|
<if test="errorMsg != null">#{errorMsg},</if>
|
||||||
|
<if test="createBy != null and createBy != ''">#{createBy},</if>
|
||||||
|
sysdate()
|
||||||
|
)
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateSyncLog" parameterType="BmsRegionSyncLog">
|
||||||
|
update bms_region_sync_log
|
||||||
|
<set>
|
||||||
|
<if test="status != null and status != ''">status = #{status},</if>
|
||||||
|
<if test="totalCount != null">total_count = #{totalCount},</if>
|
||||||
|
<if test="insertCount != null">insert_count = #{insertCount},</if>
|
||||||
|
<if test="updateCount != null">update_count = #{updateCount},</if>
|
||||||
|
<if test="failCount != null">fail_count = #{failCount},</if>
|
||||||
|
<if test="durationMs != null">duration_ms = #{durationMs},</if>
|
||||||
|
<if test="errorMsg != null">error_msg = #{errorMsg},</if>
|
||||||
|
update_time = sysdate()
|
||||||
|
</set>
|
||||||
|
where log_id = #{logId}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteSyncLogByIds" parameterType="Long">
|
||||||
|
delete from bms_region_sync_log where log_id in
|
||||||
|
<foreach item="logId" collection="array" open="(" separator="," close=")">
|
||||||
|
#{logId}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- 1、国家/区域表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS bms_region;
|
||||||
|
CREATE TABLE bms_region (
|
||||||
|
region_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '区域ID',
|
||||||
|
country_name_cn VARCHAR(100) DEFAULT NULL COMMENT '中文名',
|
||||||
|
country_name_en VARCHAR(100) NOT NULL COMMENT '英文名',
|
||||||
|
country_code_2 VARCHAR(2) NOT NULL COMMENT 'ISO两位码',
|
||||||
|
country_code_3 VARCHAR(3) DEFAULT NULL COMMENT 'ISO三位码',
|
||||||
|
continent VARCHAR(50) DEFAULT NULL COMMENT '洲/大区',
|
||||||
|
sub_region VARCHAR(50) DEFAULT NULL COMMENT '子区域',
|
||||||
|
currency_code VARCHAR(10) DEFAULT NULL COMMENT '货币代码',
|
||||||
|
currency_name VARCHAR(50) DEFAULT NULL COMMENT '货币名称',
|
||||||
|
currency_symbol VARCHAR(10) DEFAULT NULL COMMENT '货币符号',
|
||||||
|
phone_prefix VARCHAR(10) DEFAULT NULL COMMENT '电话前缀',
|
||||||
|
flag_emoji VARCHAR(10) DEFAULT NULL COMMENT '国旗emoji',
|
||||||
|
flag_url VARCHAR(500) DEFAULT NULL COMMENT '国旗图片URL',
|
||||||
|
is_independent CHAR(1) NOT NULL DEFAULT '1' COMMENT '是否独立(1是 0否)',
|
||||||
|
is_eu CHAR(1) NOT NULL DEFAULT '0' COMMENT '是否欧盟成员(1是 0否)',
|
||||||
|
status CHAR(1) NOT NULL DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||||
|
del_flag CHAR(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0存在 2删除)',
|
||||||
|
create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||||
|
update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
|
||||||
|
update_time DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
PRIMARY KEY (region_id),
|
||||||
|
UNIQUE INDEX idx_country_code_2 (country_code_2),
|
||||||
|
INDEX idx_country_name_cn (country_name_cn),
|
||||||
|
INDEX idx_country_name_en (country_name_en),
|
||||||
|
INDEX idx_continent (continent)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='国家/区域表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 2、区域数据同步日志表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS bms_region_sync_log;
|
||||||
|
CREATE TABLE bms_region_sync_log (
|
||||||
|
log_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '日志ID',
|
||||||
|
sync_type VARCHAR(20) NOT NULL DEFAULT 'ALL' COMMENT '同步类型(ALL全量)',
|
||||||
|
status VARCHAR(20) NOT NULL DEFAULT 'PROCESSING' COMMENT '状态(PENDING/PROCESSING/SUCCESS/FAILED)',
|
||||||
|
total_count INT(11) DEFAULT 0 COMMENT 'API返回总数',
|
||||||
|
insert_count INT(11) DEFAULT 0 COMMENT '新增数',
|
||||||
|
update_count INT(11) DEFAULT 0 COMMENT '更新数',
|
||||||
|
fail_count INT(11) DEFAULT 0 COMMENT '失败数',
|
||||||
|
duration_ms BIGINT(20) DEFAULT 0 COMMENT '耗时(毫秒)',
|
||||||
|
error_msg TEXT DEFAULT NULL COMMENT '错误信息',
|
||||||
|
create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||||
|
update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
|
||||||
|
update_time DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (log_id),
|
||||||
|
INDEX idx_status (status),
|
||||||
|
INDEX idx_create_time (create_time)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='区域数据同步日志表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 3、菜单数据
|
||||||
|
-- ----------------------------
|
||||||
|
-- 一级菜单: 数据管理
|
||||||
|
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||||
|
VALUES ('数据管理', 0, 6, 'data', NULL, 1, 0, 'M', '0', '0', '', 'chart', 'admin', sysdate(), '数据管理目录');
|
||||||
|
|
||||||
|
SET @parentId = LAST_INSERT_ID();
|
||||||
|
|
||||||
|
-- 二级菜单: 区域管理
|
||||||
|
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||||
|
VALUES ('区域管理', @parentId, 1, 'region', 'data/region/index', 1, 0, 'C', '0', '0', 'data:region:list', 'international', 'admin', sysdate(), '');
|
||||||
|
|
||||||
|
SET @regionMenuId = LAST_INSERT_ID();
|
||||||
|
|
||||||
|
-- 二级菜单: 同步日志
|
||||||
|
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||||
|
VALUES ('同步日志', @parentId, 2, 'region/sync-log', 'data/region/sync-log/index', 1, 0, 'C', '0', '0', 'data:region:log:list', 'log', 'admin', sysdate(), '');
|
||||||
|
|
||||||
|
-- 按钮权限 (区域管理)
|
||||||
|
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||||
|
VALUES ('区域查询', @regionMenuId, 1, '', NULL, 1, 0, 'F', '0', '0', 'data:region:query', '#', 'admin', sysdate(), '');
|
||||||
|
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||||
|
VALUES ('区域编辑', @regionMenuId, 2, '', NULL, 1, 0, 'F', '0', '0', 'data:region:edit', '#', 'admin', sysdate(), '');
|
||||||
|
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||||
|
VALUES ('区域删除', @regionMenuId, 3, '', NULL, 1, 0, 'F', '0', '0', 'data:region:remove', '#', 'admin', sysdate(), '');
|
||||||
|
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||||
|
VALUES ('数据同步', @regionMenuId, 4, '', NULL, 1, 0, 'F', '0', '0', 'data:region:sync', '#', 'admin', sysdate(), '');
|
||||||
|
|
||||||
|
-- 按钮权限 (同步日志)
|
||||||
|
SET @logMenuId = @regionMenuId + 1;
|
||||||
|
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||||
|
VALUES ('日志删除', @logMenuId, 1, '', NULL, 1, 0, 'F', '0', '0', 'data:region:log:remove', '#', 'admin', sysdate(), '');
|
||||||
@@ -49,5 +49,10 @@
|
|||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"quill": "2.0.2"
|
"quill": "2.0.2"
|
||||||
|
},
|
||||||
|
"allowScripts": {
|
||||||
|
"esbuild@0.25.12": true,
|
||||||
|
"@parcel/watcher@2.6.0": true,
|
||||||
|
"vue-demi@0.14.10": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询同步日志列表
|
||||||
|
export function listSyncLog(query) {
|
||||||
|
return request({
|
||||||
|
url: '/data/region/log/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询同步日志详细
|
||||||
|
export function getSyncLog(logId) {
|
||||||
|
return request({
|
||||||
|
url: '/data/region/log/' + logId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除同步日志
|
||||||
|
export function delSyncLog(logIds) {
|
||||||
|
return request({
|
||||||
|
url: '/data/region/log/' + logIds,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询区域列表
|
||||||
|
export function listRegion(query) {
|
||||||
|
return request({
|
||||||
|
url: '/data/region/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询区域详细
|
||||||
|
export function getRegion(regionId) {
|
||||||
|
return request({
|
||||||
|
url: '/data/region/' + regionId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改区域
|
||||||
|
export function updateRegion(data) {
|
||||||
|
return request({
|
||||||
|
url: '/data/region',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除区域
|
||||||
|
export function delRegion(regionIds) {
|
||||||
|
return request({
|
||||||
|
url: '/data/region/' + regionIds,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改区域状态
|
||||||
|
export function changeRegionStatus(regionId, status) {
|
||||||
|
const data = {
|
||||||
|
regionId,
|
||||||
|
status
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
url: '/data/region/changeStatus',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步国家数据
|
||||||
|
export function syncRegion() {
|
||||||
|
return request({
|
||||||
|
url: '/data/region/sync',
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -91,6 +91,8 @@
|
|||||||
* colProps: {} // 透传给 el-col 的属性
|
* colProps: {} // 透传给 el-col 的属性
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
|
import { ref, computed, reactive, isRef, watch, nextTick, getCurrentInstance } from "vue"
|
||||||
|
import FormControl from "./FormControl.vue"
|
||||||
|
|
||||||
defineOptions({ name: 'BasicForm' })
|
defineOptions({ name: 'BasicForm' })
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,430 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<basic-table
|
||||||
|
ref="tableRef"
|
||||||
|
:columns="columns"
|
||||||
|
:search-columns="searchColumns"
|
||||||
|
:query="queryList"
|
||||||
|
row-key="regionId"
|
||||||
|
>
|
||||||
|
<template #toolbar="{ selection, ids }">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="Refresh"
|
||||||
|
:loading="syncLoading"
|
||||||
|
@click="handleSync"
|
||||||
|
v-hasPermi="['data:region:sync']"
|
||||||
|
>同步国家数据</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="info"
|
||||||
|
plain
|
||||||
|
icon="List"
|
||||||
|
@click="openSyncLogDialog"
|
||||||
|
v-hasPermi="['data:region:log:list']"
|
||||||
|
>同步日志</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
plain
|
||||||
|
icon="Edit"
|
||||||
|
:disabled="selection.length !== 1"
|
||||||
|
@click="handleUpdate(selection[0])"
|
||||||
|
v-hasPermi="['data:region:edit']"
|
||||||
|
>修改</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
plain
|
||||||
|
icon="Delete"
|
||||||
|
:disabled="!selection.length"
|
||||||
|
@click="handleDelete(ids)"
|
||||||
|
v-hasPermi="['data:region:remove']"
|
||||||
|
>删除</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="warning"
|
||||||
|
plain
|
||||||
|
icon="Download"
|
||||||
|
@click="handleExport"
|
||||||
|
v-hasPermi="['data:region:list']"
|
||||||
|
>导出</el-button>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #col-status="{ row }">
|
||||||
|
<el-switch
|
||||||
|
v-model="row.status"
|
||||||
|
active-value="0"
|
||||||
|
inactive-value="1"
|
||||||
|
@change="handleStatusChange(row)"
|
||||||
|
v-hasPermi="['data:region:edit']"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #col-flagEmoji="{ row }">
|
||||||
|
<span style="font-size: 18px">{{ row.flagEmoji }}</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #col-action="{ row }">
|
||||||
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['data:region:edit']">修改</el-button>
|
||||||
|
<el-button link type="primary" icon="Delete" @click="handleDelete(row.regionId)" v-hasPermi="['data:region:remove']">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</basic-table>
|
||||||
|
|
||||||
|
<!-- 修改区域对话框 -->
|
||||||
|
<el-dialog :title="title" v-model="open" width="600px" append-to-body>
|
||||||
|
<el-form ref="regionRef" :model="form" :rules="rules" label-width="100px">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="中文名" prop="countryNameCn">
|
||||||
|
<el-input v-model="form.countryNameCn" placeholder="请输入中文名" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="英文名" prop="countryNameEn">
|
||||||
|
<el-input v-model="form.countryNameEn" placeholder="请输入英文名" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="ISO两位码" prop="countryCode2">
|
||||||
|
<el-input v-model="form.countryCode2" placeholder="如: DE" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="ISO三位码" prop="countryCode3">
|
||||||
|
<el-input v-model="form.countryCode3" placeholder="如: DEU" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="洲/大区" prop="continent">
|
||||||
|
<el-input v-model="form.continent" placeholder="如: Europe" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="子区域" prop="subRegion">
|
||||||
|
<el-input v-model="form.subRegion" placeholder="如: Western Europe" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="货币代码" prop="currencyCode">
|
||||||
|
<el-input v-model="form.currencyCode" placeholder="如: EUR" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="电话前缀" prop="phonePrefix">
|
||||||
|
<el-input v-model="form.phonePrefix" placeholder="如: +49" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="是否独立" prop="isIndependent">
|
||||||
|
<el-radio-group v-model="form.isIndependent">
|
||||||
|
<el-radio value="1">是</el-radio>
|
||||||
|
<el-radio value="0">否</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="是否欧盟" prop="isEu">
|
||||||
|
<el-radio-group v-model="form.isEu">
|
||||||
|
<el-radio value="1">是</el-radio>
|
||||||
|
<el-radio value="0">否</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 同步日志对话框 -->
|
||||||
|
<el-dialog title="同步日志" v-model="logDialogVisible" width="1200px" append-to-body top="8vh">
|
||||||
|
<basic-table
|
||||||
|
ref="logTableRef"
|
||||||
|
:columns="logColumns"
|
||||||
|
:search-columns="logSearchColumns"
|
||||||
|
:query="logQueryList"
|
||||||
|
row-key="logId"
|
||||||
|
:show-search="true"
|
||||||
|
>
|
||||||
|
<template #toolbar="{ selection, ids }">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
plain
|
||||||
|
icon="Delete"
|
||||||
|
:disabled="!selection.length"
|
||||||
|
@click="handleLogDelete(ids)"
|
||||||
|
v-hasPermi="['data:region:log:remove']"
|
||||||
|
>删除</el-button>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
<template #col-status="{ row }">
|
||||||
|
<el-tag :type="logStatusType(row.status)">
|
||||||
|
{{ logStatusText(row.status) }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</basic-table>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="Region">
|
||||||
|
import { listRegion, getRegion, updateRegion, delRegion, changeRegionStatus, syncRegion } from "@/api/data/region"
|
||||||
|
import { getSyncLog, listSyncLog, delSyncLog } from "@/api/data/region-log"
|
||||||
|
import { nextTick, onBeforeUnmount } from "vue"
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
|
||||||
|
const tableRef = ref()
|
||||||
|
const open = ref(false)
|
||||||
|
const title = ref("")
|
||||||
|
const syncLoading = ref(false)
|
||||||
|
const syncLogId = ref(null)
|
||||||
|
const syncTimer = ref(null)
|
||||||
|
|
||||||
|
// ====== 同步日志对话框 ======
|
||||||
|
const logDialogVisible = ref(false)
|
||||||
|
const logTableRef = ref()
|
||||||
|
const logSearchColumns = [
|
||||||
|
{ label: "状态", prop: "status", component: "select", options: [
|
||||||
|
{ label: "待处理", value: "PENDING" },
|
||||||
|
{ label: "处理中", value: "PROCESSING" },
|
||||||
|
{ label: "成功", value: "SUCCESS" },
|
||||||
|
{ label: "失败", value: "FAILED" }
|
||||||
|
], placeholder: "状态", width: "160px" },
|
||||||
|
{ label: "创建时间", prop: "dateRange", component: "daterange", width: "320px" }
|
||||||
|
]
|
||||||
|
const logColumns = [
|
||||||
|
{ label: "日志ID", prop: "logId", align: "center", width: 80 },
|
||||||
|
{ label: "同步类型", prop: "syncType", align: "center", width: 100 },
|
||||||
|
{ label: "状态", prop: "status", align: "center", width: 100 },
|
||||||
|
{ label: "总数", prop: "totalCount", align: "center", width: 80 },
|
||||||
|
{ label: "新增数", prop: "insertCount", align: "center", width: 80 },
|
||||||
|
{ label: "更新数", prop: "updateCount", align: "center", width: 80 },
|
||||||
|
{ label: "失败数", prop: "failCount", align: "center", width: 80 },
|
||||||
|
{ label: "耗时(ms)", prop: "durationMs", align: "center", width: 100 },
|
||||||
|
{ label: "错误信息", prop: "errorMsg", align: "center", showOverflowTooltip: true },
|
||||||
|
{ label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true }
|
||||||
|
]
|
||||||
|
function logQueryList(params) {
|
||||||
|
const p = proxy.addDateRange({ ...params }, params.dateRange)
|
||||||
|
delete p.dateRange
|
||||||
|
return listSyncLog(p)
|
||||||
|
}
|
||||||
|
function logStatusText(status) {
|
||||||
|
const map = { PENDING: "待处理", PROCESSING: "处理中", SUCCESS: "成功", FAILED: "失败" }
|
||||||
|
return map[status] || status
|
||||||
|
}
|
||||||
|
function logStatusType(status) {
|
||||||
|
const map = { PENDING: "info", PROCESSING: "warning", SUCCESS: "success", FAILED: "danger" }
|
||||||
|
return map[status] || "info"
|
||||||
|
}
|
||||||
|
function handleLogDelete(logIds) {
|
||||||
|
proxy.$modal.confirm('是否确认删除日志编号为"' + logIds + '"的数据项?').then(function () {
|
||||||
|
return delSyncLog(logIds)
|
||||||
|
}).then(() => {
|
||||||
|
logTableRef.value.refresh()
|
||||||
|
proxy.$modal.msgSuccess("删除成功")
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
function openSyncLogDialog() {
|
||||||
|
logDialogVisible.value = true
|
||||||
|
nextTick(() => { logTableRef.value && logTableRef.value.reload() })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索项配置
|
||||||
|
const searchColumns = [
|
||||||
|
{ label: "中文名", prop: "countryNameCn", component: "input", placeholder: "请输入中文名", width: "200px" },
|
||||||
|
{ label: "英文名", prop: "countryNameEn", component: "input", placeholder: "请输入英文名", width: "200px" },
|
||||||
|
{ label: "国家代码", prop: "countryCode2", component: "input", placeholder: "如: DE", width: "160px" },
|
||||||
|
{ label: "洲/大区", prop: "continent", component: "input", placeholder: "如: Europe", width: "200px" },
|
||||||
|
{ label: "状态", prop: "status", component: "select", options: [{ label: "正常", value: "0" }, { label: "停用", value: "1" }], placeholder: "状态", width: "140px" }
|
||||||
|
]
|
||||||
|
|
||||||
|
// 表格列配置
|
||||||
|
const columns = [
|
||||||
|
{ label: "区域ID", prop: "regionId", align: "center", width: 80 },
|
||||||
|
{ label: "国旗", prop: "flagEmoji", align: "center", width: 60 },
|
||||||
|
{ label: "中文名", prop: "countryNameCn", align: "center" },
|
||||||
|
{ label: "英文名", prop: "countryNameEn", align: "center" },
|
||||||
|
{ label: "国家代码", prop: "countryCode2", align: "center", width: 80 },
|
||||||
|
{ label: "ISO三位码", prop: "countryCode3", align: "center", width: 90 },
|
||||||
|
{ label: "洲/大区", prop: "continent", align: "center", width: 120 },
|
||||||
|
{ label: "子区域", prop: "subRegion", align: "center", width: 140 },
|
||||||
|
{ label: "货币", prop: "currencyCode", align: "center", width: 80 },
|
||||||
|
{ label: "电话前缀", prop: "phonePrefix", align: "center", width: 90 },
|
||||||
|
{ label: "状态", prop: "status", align: "center", width: 80 },
|
||||||
|
{ label: "操作", prop: "action", align: "center", width: 150, showInToolbar: false }
|
||||||
|
]
|
||||||
|
|
||||||
|
// 查询函数
|
||||||
|
function queryList(params) {
|
||||||
|
return listRegion(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
form: {},
|
||||||
|
rules: {
|
||||||
|
countryNameEn: [{ required: true, message: "英文名不能为空", trigger: "blur" }],
|
||||||
|
countryCode2: [{ required: true, message: "ISO两位码不能为空", trigger: "blur" }]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const { form, rules } = toRefs(data)
|
||||||
|
|
||||||
|
/** 取消按钮 */
|
||||||
|
function cancel() {
|
||||||
|
open.value = false
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 表单重置 */
|
||||||
|
function reset() {
|
||||||
|
form.value = {
|
||||||
|
regionId: undefined,
|
||||||
|
countryNameCn: undefined,
|
||||||
|
countryNameEn: undefined,
|
||||||
|
countryCode2: undefined,
|
||||||
|
countryCode3: undefined,
|
||||||
|
continent: undefined,
|
||||||
|
subRegion: undefined,
|
||||||
|
currencyCode: undefined,
|
||||||
|
phonePrefix: undefined,
|
||||||
|
isIndependent: "1",
|
||||||
|
isEu: "0",
|
||||||
|
remark: undefined
|
||||||
|
}
|
||||||
|
proxy.resetForm("regionRef")
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 修改按钮操作 */
|
||||||
|
function handleUpdate(row) {
|
||||||
|
reset()
|
||||||
|
const regionId = row.regionId
|
||||||
|
getRegion(regionId).then(response => {
|
||||||
|
form.value = response.data
|
||||||
|
open.value = true
|
||||||
|
title.value = "修改区域"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
function submitForm() {
|
||||||
|
proxy.$refs["regionRef"].validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
updateRegion(form.value).then(() => {
|
||||||
|
proxy.$modal.msgSuccess("修改成功")
|
||||||
|
open.value = false
|
||||||
|
tableRef.value.refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
function handleDelete(regionIds) {
|
||||||
|
proxy.$modal.confirm('是否确认删除区域编号为"' + regionIds + '"的数据项?').then(function () {
|
||||||
|
return delRegion(regionIds)
|
||||||
|
}).then(() => {
|
||||||
|
tableRef.value.refresh()
|
||||||
|
proxy.$modal.msgSuccess("删除成功")
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 修改状态 */
|
||||||
|
function handleStatusChange(row) {
|
||||||
|
// 优先显示:中文名 > 英文名 > 国家代码
|
||||||
|
const displayName = row.countryNameCn || row.countryNameEn || row.countryCode2 || '';
|
||||||
|
if (row.regionId === undefined || row.regionId === null || row.regionId === '' || !displayName) {
|
||||||
|
nextTick(() => {
|
||||||
|
row.status = row.status === "0" ? "1" : "0"
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (row.__originalStatus !== undefined && row.__originalStatus === row.status) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
row.__originalStatus = row.status === "0" ? "1" : "0"
|
||||||
|
|
||||||
|
const text = row.status === "0" ? "启用" : "停用"
|
||||||
|
proxy.$modal.confirm(`确认要${text}「${displayName}」国家/区域吗?`).then(function () {
|
||||||
|
return changeRegionStatus(row.regionId, row.status)
|
||||||
|
}).then(() => {
|
||||||
|
row.__originalStatus = row.status
|
||||||
|
proxy.$modal.msgSuccess(text + "成功")
|
||||||
|
}).catch(function () {
|
||||||
|
const restored = row.status === "0" ? "1" : "0"
|
||||||
|
row.__originalStatus = restored
|
||||||
|
nextTick(() => { row.status = restored })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 同步国家数据 */
|
||||||
|
function handleSync() {
|
||||||
|
proxy.$modal.confirm('确认从第三方API同步国家数据?').then(function () {
|
||||||
|
syncLoading.value = true
|
||||||
|
return syncRegion()
|
||||||
|
}).then(res => {
|
||||||
|
syncLogId.value = res.logId
|
||||||
|
proxy.$modal.msgSuccess("同步任务已创建,正在后台执行...")
|
||||||
|
// 轮询同步状态
|
||||||
|
syncTimer.value = setInterval(() => {
|
||||||
|
getSyncLog(syncLogId.value).then(response => {
|
||||||
|
const log = response.data
|
||||||
|
if (log.status === "SUCCESS") {
|
||||||
|
clearInterval(syncTimer.value)
|
||||||
|
syncTimer.value = null
|
||||||
|
syncLoading.value = false
|
||||||
|
tableRef.value.refresh()
|
||||||
|
proxy.$modal.msgSuccess(`同步完成!总计${log.totalCount}条,新增${log.insertCount}条,更新${log.updateCount}条,失败${log.failCount}条`)
|
||||||
|
} else if (log.status === "FAILED") {
|
||||||
|
clearInterval(syncTimer.value)
|
||||||
|
syncTimer.value = null
|
||||||
|
syncLoading.value = false
|
||||||
|
proxy.$modal.msgError("同步失败:" + log.errorMsg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 3000)
|
||||||
|
}).catch(() => {
|
||||||
|
syncLoading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
function handleExport() {
|
||||||
|
proxy.download("data/region/export", {
|
||||||
|
...tableRef.value.getQueryParams()
|
||||||
|
}, `region_${new Date().getTime()}.xlsx`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 组件卸载前清理定时器 */
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (syncTimer.value) {
|
||||||
|
clearInterval(syncTimer.value)
|
||||||
|
syncTimer.value = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<basic-table
|
||||||
|
ref="tableRef"
|
||||||
|
:columns="columns"
|
||||||
|
:search-columns="searchColumns"
|
||||||
|
:query="queryList"
|
||||||
|
row-key="logId"
|
||||||
|
>
|
||||||
|
<template #toolbar="{ selection, ids }">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
plain
|
||||||
|
icon="Delete"
|
||||||
|
:disabled="!selection.length"
|
||||||
|
@click="handleDelete(ids)"
|
||||||
|
v-hasPermi="['data:region:log:remove']"
|
||||||
|
>删除</el-button>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #col-status="{ row }">
|
||||||
|
<el-tag :type="statusType(row.status)">
|
||||||
|
{{ statusText(row.status) }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</basic-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="RegionSyncLog">
|
||||||
|
import { listSyncLog, delSyncLog } from "@/api/data/region-log"
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
const tableRef = ref()
|
||||||
|
|
||||||
|
// 搜索项配置
|
||||||
|
const searchColumns = [
|
||||||
|
{ label: "状态", prop: "status", component: "select", options: [
|
||||||
|
{ label: "待处理", value: "PENDING" },
|
||||||
|
{ label: "处理中", value: "PROCESSING" },
|
||||||
|
{ label: "成功", value: "SUCCESS" },
|
||||||
|
{ label: "失败", value: "FAILED" }
|
||||||
|
], placeholder: "状态", width: "160px" },
|
||||||
|
{ label: "创建时间", prop: "dateRange", component: "daterange", width: "320px" }
|
||||||
|
]
|
||||||
|
|
||||||
|
// 表格列配置
|
||||||
|
const columns = [
|
||||||
|
{ label: "日志ID", prop: "logId", align: "center", width: 80 },
|
||||||
|
{ label: "同步类型", prop: "syncType", align: "center", width: 100 },
|
||||||
|
{ label: "状态", prop: "status", align: "center", width: 100 },
|
||||||
|
{ label: "总数", prop: "totalCount", align: "center", width: 80 },
|
||||||
|
{ label: "新增数", prop: "insertCount", align: "center", width: 80 },
|
||||||
|
{ label: "更新数", prop: "updateCount", align: "center", width: 80 },
|
||||||
|
{ label: "失败数", prop: "failCount", align: "center", width: 80 },
|
||||||
|
{ label: "耗时(ms)", prop: "durationMs", align: "center", width: 100 },
|
||||||
|
{ label: "错误信息", prop: "errorMsg", align: "center", showOverflowTooltip: true },
|
||||||
|
{ label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true }
|
||||||
|
]
|
||||||
|
|
||||||
|
// 查询函数
|
||||||
|
function queryList(params) {
|
||||||
|
const p = proxy.addDateRange({ ...params }, params.dateRange)
|
||||||
|
delete p.dateRange
|
||||||
|
return listSyncLog(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 状态文本 */
|
||||||
|
function statusText(status) {
|
||||||
|
const map = { PENDING: "待处理", PROCESSING: "处理中", SUCCESS: "成功", FAILED: "失败" }
|
||||||
|
return map[status] || status
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 状态标签类型 */
|
||||||
|
function statusType(status) {
|
||||||
|
const map = { PENDING: "info", PROCESSING: "warning", SUCCESS: "success", FAILED: "danger" }
|
||||||
|
return map[status] || "info"
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
function handleDelete(logIds) {
|
||||||
|
proxy.$modal.confirm('是否确认删除日志编号为"' + logIds + '"的数据项?').then(function () {
|
||||||
|
return delSyncLog(logIds)
|
||||||
|
}).then(() => {
|
||||||
|
tableRef.value.refresh()
|
||||||
|
proxy.$modal.msgSuccess("删除成功")
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -179,6 +179,7 @@
|
|||||||
<script setup name="Role">
|
<script setup name="Role">
|
||||||
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role"
|
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role"
|
||||||
import { roleMenuTreeselect, treeselect as menuTreeselect } from "@/api/system/menu"
|
import { roleMenuTreeselect, treeselect as menuTreeselect } from "@/api/system/menu"
|
||||||
|
import { nextTick } from "vue"
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
@@ -263,13 +264,28 @@ function handleExport() {
|
|||||||
|
|
||||||
/** 角色状态修改 */
|
/** 角色状态修改 */
|
||||||
function handleStatusChange(row) {
|
function handleStatusChange(row) {
|
||||||
let text = row.status === "0" ? "启用" : "停用"
|
if (row.roleId === undefined || row.roleId === null || row.roleId === '' ||
|
||||||
proxy.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?').then(function () {
|
row.roleName === undefined || row.roleName === null || row.roleName === '') {
|
||||||
|
nextTick(() => {
|
||||||
|
row.status = row.status === "0" ? "1" : "0"
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (row.__originalStatus !== undefined && row.__originalStatus === row.status) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
row.__originalStatus = row.status === "0" ? "1" : "0"
|
||||||
|
|
||||||
|
const text = row.status === "0" ? "启用" : "停用"
|
||||||
|
proxy.$modal.confirm(`确认要${text}「${row.roleName}」角色吗?`).then(function () {
|
||||||
return changeRoleStatus(row.roleId, row.status)
|
return changeRoleStatus(row.roleId, row.status)
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
row.__originalStatus = row.status
|
||||||
proxy.$modal.msgSuccess(text + "成功")
|
proxy.$modal.msgSuccess(text + "成功")
|
||||||
}).catch(function () {
|
}).catch(function () {
|
||||||
row.status = row.status === "0" ? "1" : "0"
|
const restored = row.status === "0" ? "1" : "0"
|
||||||
|
row.__originalStatus = restored
|
||||||
|
nextTick(() => { row.status = restored })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ import ExcelImportDialog from "@/components/ExcelImportDialog"
|
|||||||
import UserViewDrawer from "./view"
|
import UserViewDrawer from "./view"
|
||||||
import { usePasswordRule } from "@/utils/passwordRule"
|
import { usePasswordRule } from "@/utils/passwordRule"
|
||||||
import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser, deptTreeSelect } from "@/api/system/user"
|
import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser, deptTreeSelect } from "@/api/system/user"
|
||||||
|
import { nextTick } from "vue"
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
@@ -265,13 +266,33 @@ function handleExport() {
|
|||||||
|
|
||||||
/** 用户状态修改 */
|
/** 用户状态修改 */
|
||||||
function handleStatusChange(row) {
|
function handleStatusChange(row) {
|
||||||
let text = row.status === "0" ? "启用" : "停用"
|
// 守卫:页面初始化/数据加载过程中 el-switch 可能发生赋值抖动,
|
||||||
proxy.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function () {
|
// userId 或 userName 缺失时不弹确认,只把状态反向重置防止显示偏差
|
||||||
|
if (row.userId === undefined || row.userId === null || row.userId === '' ||
|
||||||
|
row.userName === undefined || row.userName === null || row.userName === '') {
|
||||||
|
nextTick(() => {
|
||||||
|
row.status = row.status === "0" ? "1" : "0"
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 与原始记录中的 status 对比:status 只能是字符串 "0"/"1",若不一致(如 loading 中被改)则回滚
|
||||||
|
if (row.__originalStatus !== undefined && row.__originalStatus === row.status) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 为当前行记录一次原始值,后面 catch 时与回滚同步,避免重复触发 change
|
||||||
|
row.__originalStatus = row.status === "0" ? "1" : "0"
|
||||||
|
|
||||||
|
const text = row.status === "0" ? "启用" : "停用"
|
||||||
|
proxy.$modal.confirm(`确认要${text}「${row.userName}」用户吗?`).then(function () {
|
||||||
return changeUserStatus(row.userId, row.status)
|
return changeUserStatus(row.userId, row.status)
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
row.__originalStatus = row.status
|
||||||
proxy.$modal.msgSuccess(text + "成功")
|
proxy.$modal.msgSuccess(text + "成功")
|
||||||
}).catch(function () {
|
}).catch(function () {
|
||||||
row.status = row.status === "0" ? "1" : "0"
|
const restored = row.status === "0" ? "1" : "0"
|
||||||
|
row.__originalStatus = restored
|
||||||
|
// 回滚赋值时短暂忽略 change,防止递归弹框
|
||||||
|
nextTick(() => { row.status = restored })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user