Commit 7b98a3f3f390304c3c9e94e9c7e27c48994560fb
Merge remote-tracking branch 'origin/master' into feature/springdoc
# Conflicts: # README.md # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/ProductPropertyViewRespVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyAndValueRespVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyPageReqVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueCreateReqVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueRespVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueUpdateReqVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuCreateOrUpdateReqVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuPageReqVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuPageRespVO.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuRespVO.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/property/AppProductPropertyValueDetailRespVO.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderPageReqVO.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/TradeOrderItemRespVO.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/TradeOrderRespVO.java # yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java # yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayNotifyOrderReqVO.java # yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayRefundOrderReqVO.java # yudao-server/pom.xml # yudao-server/src/main/java/cn/iocoder/yudao/module/shop/controller/app/AppShopOrderController.java
Showing
466 changed files
with
17546 additions
and
4307 deletions
Too many changes.
To preserve performance only 100 of 466 files are displayed.
README.md
| 1 | -**严肃声明:现在、未来都不会有商业版本,所有功能全部开源!** | ||
| 2 | - | ||
| 3 | -**拒绝虚假开源,售卖商业版,程序员不骗程序员!!** | 1 | +**严肃声明:现在、未来都不会有商业版本,所有代码全部开源!** |
| 4 | 2 | ||
| 5 | **「我喜欢写代码,乐此不疲」** | 3 | **「我喜欢写代码,乐此不疲」** |
| 6 | **「我喜欢做开源,以此为乐」** | 4 | **「我喜欢做开源,以此为乐」** |
| @@ -27,7 +25,7 @@ | @@ -27,7 +25,7 @@ | ||
| 27 | 25 | ||
| 28 | * 管理后台的 Vue3 版本采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) ,Vue2 版本采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) | 26 | * 管理后台的 Vue3 版本采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) ,Vue2 版本采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) |
| 29 | * 管理后台的移动端采用 [uni-app](https://github.com/dcloudio/uni-app) 方案,一份代码多终端适配,同时支持 APP、小程序、H5! | 27 | * 管理后台的移动端采用 [uni-app](https://github.com/dcloudio/uni-app) 方案,一份代码多终端适配,同时支持 APP、小程序、H5! |
| 30 | -* 后端采用 Spring Boot、MySQL + MyBatis Plus、Redis + Redisson | 28 | +* 后端采用 Spring Boot 多模块架构、MySQL + MyBatis Plus、Redis + Redisson |
| 31 | * 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等 | 29 | * 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等 |
| 32 | * 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录 | 30 | * 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录 |
| 33 | * 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能 | 31 | * 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能 |
| @@ -38,12 +36,12 @@ | @@ -38,12 +36,12 @@ | ||
| 38 | * 集成阿里云、腾讯云等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务 | 36 | * 集成阿里云、腾讯云等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务 |
| 39 | * 集成报表设计器,支持数据报表、图形报表、打印设计等 | 37 | * 集成报表设计器,支持数据报表、图形报表、打印设计等 |
| 40 | 38 | ||
| 41 | -| 项目名 | 说明 | 传送门 | | ||
| 42 | -|--------------------|------------------------|-----------------------------------------------------------------------------------------------------------------------------------| | ||
| 43 | -| `ruoyi-vue-pro` | Spring Boot 多模块 | **[Gitee](https://gitee.com/zhijiantianya/ruoyi-vue-pro)** [Github](https://github.com/YunaiV/ruoyi-vue-pro) | | ||
| 44 | -| `yudao-cloud` | Spring Cloud 微服务 | **[Gitee](https://gitee.com/zhijiantianya/yudao-cloud)** [Github](https://github.com/YunaiV/yudao-cloud) | | ||
| 45 | -| `Spring-Boot-Labs` | Spring Boot & Cloud 入门 | **[Gitee](https://gitee.com/zhijiantianya/SpringBoot-Labs)** [Github](https://github.com/YunaiV/SpringBoot-Labs) | | ||
| 46 | - | `ruoyi-vue-pro-mini` | 精简版 移除工作流 支付等模块| **[Gitee](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/mini)** | | 39 | +| 项目名 | 说明 | 传送门 | |
| 40 | +|----------------------|------------------------|-------------------------------------------------------------------------------------------------------------------------------------| | ||
| 41 | +| `ruoyi-vue-pro` | Spring Boot 多模块 | **[Gitee](https://gitee.com/zhijiantianya/ruoyi-vue-pro)** [Github](https://github.com/YunaiV/ruoyi-vue-pro) | | ||
| 42 | +| `yudao-cloud` | Spring Cloud 微服务 | **[Gitee](https://gitee.com/zhijiantianya/yudao-cloud)** [Github](https://github.com/YunaiV/yudao-cloud) | | ||
| 43 | +| `Spring-Boot-Labs` | Spring Boot & Cloud 入门 | **[Gitee](https://gitee.com/zhijiantianya/SpringBoot-Labs)** [Github](https://github.com/YunaiV/SpringBoot-Labs) | | ||
| 44 | +| `ruoyi-vue-pro-mini` | 精简版:移除工作流、支付等模块 | **[Gitee](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/mini)** | | ||
| 47 | 45 | ||
| 48 | ## 😎 开源协议 | 46 | ## 😎 开源协议 |
| 49 | 47 | ||
| @@ -96,8 +94,9 @@ | @@ -96,8 +94,9 @@ | ||
| 96 | | ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 | | 94 | | ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 | |
| 97 | | 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 | | 95 | | 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 | |
| 98 | | | 通知公告 | 系统通知公告信息发布维护 | | 96 | | | 通知公告 | 系统通知公告信息发布维护 | |
| 99 | -| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 | | 97 | +| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 | |
| 100 | | 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 | | 98 | | 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 | |
| 99 | +| 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 | | ||
| 101 | 100 | ||
| 102 | ### 工作流程 | 101 | ### 工作流程 |
| 103 | 102 | ||
| @@ -132,7 +131,7 @@ ps:核心功能已经实现,正在对接微信小程序中... | @@ -132,7 +131,7 @@ ps:核心功能已经实现,正在对接微信小程序中... | ||
| 132 | | | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 | | 131 | | | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 | |
| 133 | | 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 | | 132 | | 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 | |
| 134 | | ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 | | 133 | | ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 | |
| 135 | -| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 | | 134 | +| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 | |
| 136 | | 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 | | 135 | | 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 | |
| 137 | | | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 | | 136 | | | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 | |
| 138 | | | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 | | 137 | | | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 | |
| @@ -169,47 +168,47 @@ ps:核心功能已经实现,正在对接微信小程序中... | @@ -169,47 +168,47 @@ ps:核心功能已经实现,正在对接微信小程序中... | ||
| 169 | 168 | ||
| 170 | ## 🐨 技术栈 | 169 | ## 🐨 技术栈 |
| 171 | 170 | ||
| 172 | -| 项目 | 说明 | | ||
| 173 | -|-------------------------|-----------------------| | ||
| 174 | -| `yudao-dependencies` | Maven 依赖版本管理 | | ||
| 175 | -| `yudao-framework` | Java 框架拓展 | | ||
| 176 | -| `yudao-server` | 管理后台 + 用户 APP 的服务端 | | ||
| 177 | -| `yudao-ui-admin` | 管理后台的 Vue2 前端项目 | | ||
| 178 | -| `yudao-ui-admin-vue3` | 管理后台的 Vue3 前端项目 | | ||
| 179 | -| `yudao-ui-admin-uniapp` | 管理后台的 uni-app 多端项目 | | ||
| 180 | -| `yudao-ui-app` | 用户 APP 的 UI 界面 | | ||
| 181 | -| `yudao-module-system` | 系统功能的 Module 模块 | | ||
| 182 | -| `yudao-module-member` | 会员中心的 Module 模块 | | ||
| 183 | -| `yudao-module-infra` | 基础设施的 Module 模块 | | ||
| 184 | -| `yudao-module-tool` | 研发工具的 Module 模块 | | ||
| 185 | -| `yudao-module-bpm` | 工作流程的 Module 模块 | | ||
| 186 | -| `yudao-module-pay` | 支付系统的 Module 模块 | | 171 | +| 项目 | 说明 | |
| 172 | +|------------------------------|--------------------| | ||
| 173 | +| `yudao-dependencies` | Maven 依赖版本管理 | | ||
| 174 | +| `yudao-framework` | Java 框架拓展 | | ||
| 175 | +| `yudao-server` | 管理后台 + 用户 APP 的服务端 | | ||
| 176 | +| `yudao-ui-admin` | 管理后台的 Vue2 前端项目 | | ||
| 177 | +| `yudao-ui-admin-vue3` | 管理后台的 Vue3 前端项目 | | ||
| 178 | +| `yudao-ui-admin-uniapp` | 管理后台的 uni-app 多端项目 | | ||
| 179 | +| `yudao-ui-app` | 用户 APP 的 UI 界面 | | ||
| 180 | +| `yudao-module-system` | 系统功能的 Module 模块 | | ||
| 181 | +| `yudao-module-member` | 会员中心的 Module 模块 | | ||
| 182 | +| `yudao-module-infra` | 基础设施的 Module 模块 | | ||
| 183 | +| `yudao-module-bpm` | 工作流程的 Module 模块 | | ||
| 184 | +| `yudao-module-pay` | 支付系统的 Module 模块 | | ||
| 185 | +| `yudao-module-visualization` | 大屏报表 Module 模块 | | ||
| 187 | 186 | ||
| 188 | ### 后端 | 187 | ### 后端 |
| 189 | 188 | ||
| 190 | -| 框架 | 说明 | 版本 | 学习指南 | | ||
| 191 | -|---------------------------------------------------------------------------------------------|-----------------------|-------------|----------------------------------------------------------------| | ||
| 192 | -| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.7.6 | [文档](https://github.com/YunaiV/SpringBoot-Labs) | | ||
| 193 | -| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | | | ||
| 194 | -| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.15 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) | | ||
| 195 | -| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) | | ||
| 196 | -| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) | | ||
| 197 | -| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 | | | ||
| 198 | -| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.18.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) | | ||
| 199 | -| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.24 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) | | ||
| 200 | -| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.7.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) | | ||
| 201 | -| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.5 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) | | ||
| 202 | -| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.7.2 | [文档](https://doc.iocoder.cn/bpm/) | | ||
| 203 | -| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) | | ||
| 204 | -| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 4.0.0 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) | | ||
| 205 | -| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) | | 189 | +| 框架 | 说明 | 版本 | 学习指南 | |
| 190 | +|---------------------------------------------------------------------------------------------|------------------|-------------|----------------------------------------------------------------| | ||
| 191 | +| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.7.6 | [文档](https://github.com/YunaiV/SpringBoot-Labs) | | ||
| 192 | +| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | | | ||
| 193 | +| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.15 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) | | ||
| 194 | +| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) | | ||
| 195 | +| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) | | ||
| 196 | +| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 | | | ||
| 197 | +| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.18.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) | | ||
| 198 | +| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.24 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) | | ||
| 199 | +| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.7.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) | | ||
| 200 | +| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.5 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) | | ||
| 201 | +| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.7.2 | [文档](https://doc.iocoder.cn/bpm/) | | ||
| 202 | +| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) | | ||
| 203 | +| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 4.0.0 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) | | ||
| 204 | +| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) | | ||
| 206 | | [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.12.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) | | 205 | | [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.12.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) | |
| 207 | -| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.7.9 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) | | ||
| 208 | -| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | | | ||
| 209 | -| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.5.3.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) | | ||
| 210 | -| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.24 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) | | ||
| 211 | -| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - | | ||
| 212 | -| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.8.0 | - | | 206 | +| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.7.9 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) | |
| 207 | +| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | | | ||
| 208 | +| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.5.3.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) | | ||
| 209 | +| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.24 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) | | ||
| 210 | +| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - | | ||
| 211 | +| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.8.0 | - | | ||
| 213 | 212 | ||
| 214 | ### [管理后台 Vue2 前端](./yudao-ui-admin) | 213 | ### [管理后台 Vue2 前端](./yudao-ui-admin) |
| 215 | 214 | ||
| @@ -220,22 +219,22 @@ ps:核心功能已经实现,正在对接微信小程序中... | @@ -220,22 +219,22 @@ ps:核心功能已经实现,正在对接微信小程序中... | ||
| 220 | 219 | ||
| 221 | ### [管理后台 Vue3 前端](./yudao-ui-admin-vue3) | 220 | ### [管理后台 Vue3 前端](./yudao-ui-admin-vue3) |
| 222 | 221 | ||
| 223 | -| 框架 | 说明 | 版本 | | 222 | +| 框架 | 说明 | 版本 | |
| 224 | |----------------------------------------------------------------------|:------------:|:------:| | 223 | |----------------------------------------------------------------------|:------------:|:------:| |
| 225 | -| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.45 | | ||
| 226 | -| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.0.2 | | ||
| 227 | -| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.27 | | 224 | +| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.45 | |
| 225 | +| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.0.3 | | ||
| 226 | +| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.28 | | ||
| 228 | | [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.9.4 | | 227 | | [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.9.4 | |
| 229 | | [pinia](https://pinia.vuejs.org/) | vuex5 | 2.0.28 | | 228 | | [pinia](https://pinia.vuejs.org/) | vuex5 | 2.0.28 | |
| 230 | -| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 | | ||
| 231 | -| [vxe-table](https://vxetable.cn/) | vue最强表单 | 4.3.7 | | 229 | +| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 | |
| 230 | +| [vxe-table](https://vxetable.cn/) | vue最强表单 | 4.3.7 | | ||
| 232 | 231 | ||
| 233 | ### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp) | 232 | ### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp) |
| 234 | 233 | ||
| 235 | -| 框架 | 说明 | 版本 | | ||
| 236 | -|----------------------------------------------------------------------|------------------|--------| | ||
| 237 | -| [uni-app](hhttps://github.com/dcloudio/uni-app) | 跨平台框架 | 2.0.0 | | ||
| 238 | -| [uni-ui](https://github.com/dcloudio/uni-ui) | 基于 uni-app 的 UI 框架 | 1.4.20 | | 234 | +| 框架 | 说明 | 版本 | |
| 235 | +|-------------------------------------------------|--------------------|--------| | ||
| 236 | +| [uni-app](hhttps://github.com/dcloudio/uni-app) | 跨平台框架 | 2.0.0 | | ||
| 237 | +| [uni-ui](https://github.com/dcloudio/uni-ui) | 基于 uni-app 的 UI 框架 | 1.4.20 | | ||
| 239 | 238 | ||
| 240 | ## 🐷 演示图 | 239 | ## 🐷 演示图 |
| 241 | 240 |
http-client.env.json
| @@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
| 5 | "adminTenentId": "1", | 5 | "adminTenentId": "1", |
| 6 | 6 | ||
| 7 | "appApi": "http://127.0.0.1:48080/app-api", | 7 | "appApi": "http://127.0.0.1:48080/app-api", |
| 8 | - "appToken": "test1", | 8 | + "appToken": "test247", |
| 9 | "appTenentId": "1" | 9 | "appTenentId": "1" |
| 10 | }, | 10 | }, |
| 11 | "gateway": { | 11 | "gateway": { |
pom.xml
| @@ -14,12 +14,12 @@ | @@ -14,12 +14,12 @@ | ||
| 14 | <module>yudao-server</module> | 14 | <module>yudao-server</module> |
| 15 | <!-- 各种 module 拓展 --> | 15 | <!-- 各种 module 拓展 --> |
| 16 | <module>yudao-module-member</module> | 16 | <module>yudao-module-member</module> |
| 17 | - <module>yudao-module-bpm</module> | ||
| 18 | <module>yudao-module-system</module> | 17 | <module>yudao-module-system</module> |
| 19 | <module>yudao-module-infra</module> | 18 | <module>yudao-module-infra</module> |
| 20 | <module>yudao-module-pay</module> | 19 | <module>yudao-module-pay</module> |
| 21 | - <module>yudao-module-mall</module> | 20 | +<!-- <module>yudao-module-bpm</module>--> |
| 22 | <module>yudao-module-visualization</module> | 21 | <module>yudao-module-visualization</module> |
| 22 | +<!-- <module>yudao-module-mall</module>--> | ||
| 23 | <!-- 示例项目 --> | 23 | <!-- 示例项目 --> |
| 24 | <module>yudao-example</module> | 24 | <module>yudao-example</module> |
| 25 | </modules> | 25 | </modules> |
yudao-dependencies/pom.xml
| @@ -24,7 +24,7 @@ | @@ -24,7 +24,7 @@ | ||
| 24 | <!-- DB 相关 --> | 24 | <!-- DB 相关 --> |
| 25 | <druid.version>1.2.15</druid.version> | 25 | <druid.version>1.2.15</druid.version> |
| 26 | <mybatis-plus.version>3.5.2</mybatis-plus.version> | 26 | <mybatis-plus.version>3.5.2</mybatis-plus.version> |
| 27 | - <mybatis-plus-generator.version>3.5.3</mybatis-plus-generator.version> | 27 | + <mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version> |
| 28 | <dynamic-datasource.version>3.6.0</dynamic-datasource.version> | 28 | <dynamic-datasource.version>3.6.0</dynamic-datasource.version> |
| 29 | <redisson.version>3.18.0</redisson.version> | 29 | <redisson.version>3.18.0</redisson.version> |
| 30 | <!-- 服务保障相关 --> | 30 | <!-- 服务保障相关 --> |
| @@ -56,6 +56,7 @@ | @@ -56,6 +56,7 @@ | ||
| 56 | <tika-core.version>2.6.0</tika-core.version> | 56 | <tika-core.version>2.6.0</tika-core.version> |
| 57 | <aj-captcha.version>1.3.0</aj-captcha.version> | 57 | <aj-captcha.version>1.3.0</aj-captcha.version> |
| 58 | <netty-all.version>4.1.85.Final</netty-all.version> | 58 | <netty-all.version>4.1.85.Final</netty-all.version> |
| 59 | + <ip2region.version>2.6.6</ip2region.version> | ||
| 59 | <!-- 三方云服务相关 --> | 60 | <!-- 三方云服务相关 --> |
| 60 | <okio.version>3.0.0</okio.version> | 61 | <okio.version>3.0.0</okio.version> |
| 61 | <okhttp3.version>4.10.0</okhttp3.version> | 62 | <okhttp3.version>4.10.0</okhttp3.version> |
| @@ -132,6 +133,11 @@ | @@ -132,6 +133,11 @@ | ||
| 132 | </dependency> | 133 | </dependency> |
| 133 | <dependency> | 134 | <dependency> |
| 134 | <groupId>cn.iocoder.boot</groupId> | 135 | <groupId>cn.iocoder.boot</groupId> |
| 136 | + <artifactId>yudao-spring-boot-starter-biz-ip</artifactId> | ||
| 137 | + <version>${revision}</version> | ||
| 138 | + </dependency> | ||
| 139 | + <dependency> | ||
| 140 | + <groupId>cn.iocoder.boot</groupId> | ||
| 135 | <artifactId>yudao-spring-boot-starter-captcha</artifactId> | 141 | <artifactId>yudao-spring-boot-starter-captcha</artifactId> |
| 136 | <version>${revision}</version> | 142 | <version>${revision}</version> |
| 137 | </dependency> | 143 | </dependency> |
| @@ -503,6 +509,12 @@ | @@ -503,6 +509,12 @@ | ||
| 503 | <version>${netty-all.version}</version> | 509 | <version>${netty-all.version}</version> |
| 504 | </dependency> | 510 | </dependency> |
| 505 | 511 | ||
| 512 | + <dependency> | ||
| 513 | + <groupId>org.lionsoul</groupId> | ||
| 514 | + <artifactId>ip2region</artifactId> | ||
| 515 | + <version>${ip2region.version}</version> | ||
| 516 | + </dependency> | ||
| 517 | + | ||
| 506 | <!-- 三方云服务相关 --> | 518 | <!-- 三方云服务相关 --> |
| 507 | <dependency> | 519 | <dependency> |
| 508 | <groupId>com.squareup.okio</groupId> | 520 | <groupId>com.squareup.okio</groupId> |
yudao-framework/pom.xml
| @@ -36,6 +36,7 @@ | @@ -36,6 +36,7 @@ | ||
| 36 | <module>yudao-spring-boot-starter-biz-tenant</module> | 36 | <module>yudao-spring-boot-starter-biz-tenant</module> |
| 37 | <module>yudao-spring-boot-starter-biz-data-permission</module> | 37 | <module>yudao-spring-boot-starter-biz-data-permission</module> |
| 38 | <module>yudao-spring-boot-starter-biz-error-code</module> | 38 | <module>yudao-spring-boot-starter-biz-error-code</module> |
| 39 | + <module>yudao-spring-boot-starter-biz-ip</module> | ||
| 39 | 40 | ||
| 40 | <module>yudao-spring-boot-starter-flowable</module> | 41 | <module>yudao-spring-boot-starter-flowable</module> |
| 41 | <module>yudao-spring-boot-starter-captcha</module> | 42 | <module>yudao-spring-boot-starter-captcha</module> |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/CommonStatusEnum.java
| @@ -20,7 +20,6 @@ public enum CommonStatusEnum implements IntArrayValuable { | @@ -20,7 +20,6 @@ public enum CommonStatusEnum implements IntArrayValuable { | ||
| 20 | 20 | ||
| 21 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CommonStatusEnum::getStatus).toArray(); | 21 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CommonStatusEnum::getStatus).toArray(); |
| 22 | 22 | ||
| 23 | - | ||
| 24 | /** | 23 | /** |
| 25 | * 状态值 | 24 | * 状态值 |
| 26 | */ | 25 | */ |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/TerminalEnum.java
| @@ -15,11 +15,12 @@ import java.util.Arrays; | @@ -15,11 +15,12 @@ import java.util.Arrays; | ||
| 15 | @Getter | 15 | @Getter |
| 16 | public enum TerminalEnum implements IntArrayValuable { | 16 | public enum TerminalEnum implements IntArrayValuable { |
| 17 | 17 | ||
| 18 | - //TODO terminal 重复,请参考 '订单来源终端:[1:小程序 2:H5 3:iOS 4:安卓]' | ||
| 19 | - MINI_PROGRAM(1, "小程序"), | ||
| 20 | - H5(2, "H5"), | ||
| 21 | - IOS(3, "iOS"), | ||
| 22 | - ANDROID(3, "安卓"),; | 18 | + WECHAT_MINI_PROGRAM(10, "微信小程序"), |
| 19 | + WECHAT_WAP(11, "微信公众号"), | ||
| 20 | + H5(20, "H5 网页"), | ||
| 21 | + IOS(31, "苹果 App"), | ||
| 22 | + ANDROID(32, "安卓 App"), | ||
| 23 | + ; | ||
| 23 | 24 | ||
| 24 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TerminalEnum::getTerminal).toArray(); | 25 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TerminalEnum::getTerminal).toArray(); |
| 25 | 26 |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java
| @@ -25,6 +25,8 @@ public class DateUtils { | @@ -25,6 +25,8 @@ public class DateUtils { | ||
| 25 | 25 | ||
| 26 | public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss"; | 26 | public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss"; |
| 27 | 27 | ||
| 28 | + public static final String FORMAT_HOUR_MINUTE_SECOND = "HH:mm:ss"; | ||
| 29 | + | ||
| 28 | /** | 30 | /** |
| 29 | * 将 LocalDateTime 转换成 Date | 31 | * 将 LocalDateTime 转换成 Date |
| 30 | * | 32 | * |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
| @@ -12,6 +12,11 @@ import java.time.LocalDateTime; | @@ -12,6 +12,11 @@ import java.time.LocalDateTime; | ||
| 12 | */ | 12 | */ |
| 13 | public class LocalDateTimeUtils { | 13 | public class LocalDateTimeUtils { |
| 14 | 14 | ||
| 15 | + /** | ||
| 16 | + * 空的 LocalDateTime 对象,主要用于 DB 唯一索引的默认值 | ||
| 17 | + */ | ||
| 18 | + public static LocalDateTime EMPTY = buildTime(1970, 1, 1); | ||
| 19 | + | ||
| 15 | public static LocalDateTime addTime(Duration duration) { | 20 | public static LocalDateTime addTime(Duration duration) { |
| 16 | return LocalDateTime.now().plus(duration); | 21 | return LocalDateTime.now().plus(duration); |
| 17 | } | 22 | } |
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java
| @@ -227,7 +227,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { | @@ -227,7 +227,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { | ||
| 227 | // 调用 | 227 | // 调用 |
| 228 | Expression expression = rule.getExpression(tableName, tableAlias); | 228 | Expression expression = rule.getExpression(tableName, tableAlias); |
| 229 | // 断言 | 229 | // 断言 |
| 230 | - assertEquals("u.dept_id IN (10, 20) OR u.id = 1", expression.toString()); | 230 | + assertEquals("(u.dept_id IN (10, 20) OR u.id = 1)", expression.toString()); |
| 231 | assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); | 231 | assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); |
| 232 | } | 232 | } |
| 233 | } | 233 | } |
yudao-framework/yudao-spring-boot-starter-biz-ip/pom.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| 4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| 5 | + <parent> | ||
| 6 | + <artifactId>yudao-framework</artifactId> | ||
| 7 | + <groupId>cn.iocoder.boot</groupId> | ||
| 8 | + <version>${revision}</version> | ||
| 9 | + </parent> | ||
| 10 | + <modelVersion>4.0.0</modelVersion> | ||
| 11 | + <artifactId>yudao-spring-boot-starter-biz-ip</artifactId> | ||
| 12 | + <packaging>jar</packaging> | ||
| 13 | + | ||
| 14 | + <name>${project.artifactId}</name> | ||
| 15 | + <description>IP 拓展,支持如下功能: | ||
| 16 | + 1. IP 功能:查询 IP 对应的城市信息 | ||
| 17 | + 基于 https://gitee.com/lionsoul/ip2region 实现 | ||
| 18 | + 2. 城市功能:查询城市编码对应的城市信息 | ||
| 19 | + 基于 https://github.com/modood/Administrative-divisions-of-China 实现 | ||
| 20 | + </description> | ||
| 21 | + <url>https://github.com/YunaiV/ruoyi-vue-pro</url> | ||
| 22 | + | ||
| 23 | + <properties> | ||
| 24 | + <ip2region.version>2.6.6</ip2region.version> | ||
| 25 | + </properties> | ||
| 26 | + | ||
| 27 | + <dependencies> | ||
| 28 | + <dependency> | ||
| 29 | + <groupId>cn.iocoder.boot</groupId> | ||
| 30 | + <artifactId>yudao-common</artifactId> | ||
| 31 | + </dependency> | ||
| 32 | + | ||
| 33 | + <!-- IP地址检索 --> | ||
| 34 | + <dependency> | ||
| 35 | + <groupId>org.lionsoul</groupId> | ||
| 36 | + <artifactId>ip2region</artifactId> | ||
| 37 | + </dependency> | ||
| 38 | + | ||
| 39 | + <dependency> | ||
| 40 | + <groupId>org.projectlombok</groupId> | ||
| 41 | + <artifactId>lombok</artifactId> | ||
| 42 | + </dependency> | ||
| 43 | + | ||
| 44 | + <dependency> | ||
| 45 | + <groupId>org.slf4j</groupId> | ||
| 46 | + <artifactId>slf4j-api</artifactId> | ||
| 47 | + <scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 --> | ||
| 48 | + </dependency> | ||
| 49 | + | ||
| 50 | + <!-- Test 测试相关 --> | ||
| 51 | + <dependency> | ||
| 52 | + <groupId>cn.iocoder.boot</groupId> | ||
| 53 | + <artifactId>yudao-spring-boot-starter-test</artifactId> | ||
| 54 | + <scope>test</scope> | ||
| 55 | + </dependency> | ||
| 56 | + </dependencies> | ||
| 57 | + | ||
| 58 | +</project> |
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ip.core; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; | ||
| 4 | +import lombok.AllArgsConstructor; | ||
| 5 | +import lombok.Data; | ||
| 6 | +import lombok.NoArgsConstructor; | ||
| 7 | + | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 区域节点,包括国家、省份、城市、地区等信息 | ||
| 12 | + * | ||
| 13 | + * 数据可见 resources/area.csv 文件 | ||
| 14 | + * | ||
| 15 | + * @author 芋道源码 | ||
| 16 | + */ | ||
| 17 | +@Data | ||
| 18 | +@AllArgsConstructor | ||
| 19 | +@NoArgsConstructor | ||
| 20 | +public class Area { | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 编号 - 全球,即根目录 | ||
| 24 | + */ | ||
| 25 | + public static final Integer ID_GLOBAL = 0; | ||
| 26 | + /** | ||
| 27 | + * 编号 - 中国 | ||
| 28 | + */ | ||
| 29 | + public static final Integer ID_CHINA = 1; | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 编号 | ||
| 33 | + */ | ||
| 34 | + private Integer id; | ||
| 35 | + /** | ||
| 36 | + * 名字 | ||
| 37 | + */ | ||
| 38 | + private String name; | ||
| 39 | + /** | ||
| 40 | + * 类型 | ||
| 41 | + * | ||
| 42 | + * 枚举 {@link AreaTypeEnum} | ||
| 43 | + */ | ||
| 44 | + private Integer type; | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 父节点 | ||
| 48 | + */ | ||
| 49 | + private Area parent; | ||
| 50 | + /** | ||
| 51 | + * 子节点 | ||
| 52 | + */ | ||
| 53 | + private List<Area> children; | ||
| 54 | + | ||
| 55 | +} |
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/enums/AreaTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ip.core.enums; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | ||
| 4 | +import lombok.AllArgsConstructor; | ||
| 5 | +import lombok.Getter; | ||
| 6 | + | ||
| 7 | +import java.util.Arrays; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 区域类型枚举 | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +@AllArgsConstructor | ||
| 15 | +@Getter | ||
| 16 | +public enum AreaTypeEnum implements IntArrayValuable { | ||
| 17 | + | ||
| 18 | + COUNTRY(1, "国家"), | ||
| 19 | + PROVINCE(2, "省份"), | ||
| 20 | + CITY(3, "城市"), | ||
| 21 | + DISTRICT(4, "地区"), // 县、镇、区等 | ||
| 22 | + ; | ||
| 23 | + | ||
| 24 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AreaTypeEnum::getType).toArray(); | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 类型 | ||
| 28 | + */ | ||
| 29 | + private final Integer type; | ||
| 30 | + /** | ||
| 31 | + * 名字 | ||
| 32 | + */ | ||
| 33 | + private final String name; | ||
| 34 | + | ||
| 35 | + @Override | ||
| 36 | + public int[] array() { | ||
| 37 | + return ARRAYS; | ||
| 38 | + } | ||
| 39 | +} |
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ip.core.utils; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.io.resource.ResourceUtil; | ||
| 4 | +import cn.hutool.core.lang.Assert; | ||
| 5 | +import cn.hutool.core.text.csv.CsvRow; | ||
| 6 | +import cn.hutool.core.text.csv.CsvUtil; | ||
| 7 | +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | ||
| 8 | +import cn.iocoder.yudao.framework.ip.core.Area; | ||
| 9 | +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; | ||
| 10 | +import lombok.extern.slf4j.Slf4j; | ||
| 11 | + | ||
| 12 | +import java.util.ArrayList; | ||
| 13 | +import java.util.HashMap; | ||
| 14 | +import java.util.List; | ||
| 15 | +import java.util.Map; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * 区域工具类 | ||
| 19 | + * | ||
| 20 | + * @author 芋道源码 | ||
| 21 | + */ | ||
| 22 | +@Slf4j | ||
| 23 | +public class AreaUtils { | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 初始化 SEARCHER | ||
| 27 | + */ | ||
| 28 | + @SuppressWarnings("InstantiationOfUtilityClass") | ||
| 29 | + private final static AreaUtils INSTANCE = new AreaUtils(); | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * Area 内存缓存,提升访问速度 | ||
| 33 | + */ | ||
| 34 | + private static Map<Integer, Area> areas; | ||
| 35 | + | ||
| 36 | + private AreaUtils() { | ||
| 37 | + long now = System.currentTimeMillis(); | ||
| 38 | + areas = new HashMap<>(); | ||
| 39 | + areas.put(Area.ID_GLOBAL, new Area(Area.ID_GLOBAL, "全球", 0, | ||
| 40 | + null, new ArrayList<>())); | ||
| 41 | + // 从 csv 中加载数据 | ||
| 42 | + List<CsvRow> rows = CsvUtil.getReader().read(ResourceUtil.getUtf8Reader("area.csv")).getRows(); | ||
| 43 | + rows.remove(0); // 删除 header | ||
| 44 | + for (CsvRow row : rows) { | ||
| 45 | + // 创建 Area 对象 | ||
| 46 | + Area area = new Area(Integer.valueOf(row.get(0)), row.get(1), Integer.valueOf(row.get(2)), | ||
| 47 | + null, new ArrayList<>()); | ||
| 48 | + // 添加到 areas 中 | ||
| 49 | + areas.put(area.getId(), area); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + // 构建父子关系:因为 Area 中没有 parentId 字段,所以需要重复读取 | ||
| 53 | + for (CsvRow row : rows) { | ||
| 54 | + Area area = areas.get(Integer.valueOf(row.get(0))); // 自己 | ||
| 55 | + Area parent = areas.get(Integer.valueOf(row.get(3))); // 父 | ||
| 56 | + Assert.isTrue(area != parent, "{}:父子节点相同", area.getName()); | ||
| 57 | + area.setParent(parent); | ||
| 58 | + parent.getChildren().add(area); | ||
| 59 | + } | ||
| 60 | + log.info("启动加载 AreaUtils 成功,耗时 ({}) 毫秒", System.currentTimeMillis() - now); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * 获得指定编号对应的区域 | ||
| 65 | + * | ||
| 66 | + * @param id 区域编号 | ||
| 67 | + * @return 区域 | ||
| 68 | + */ | ||
| 69 | + public static Area getArea(Integer id) { | ||
| 70 | + return areas.get(id); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + /** | ||
| 74 | + * 格式化区域 | ||
| 75 | + * | ||
| 76 | + * @param id 区域编号 | ||
| 77 | + * @return 格式化后的区域 | ||
| 78 | + */ | ||
| 79 | + public static String format(Integer id) { | ||
| 80 | + return format(id, " "); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + /** | ||
| 84 | + * 格式化区域 | ||
| 85 | + * | ||
| 86 | + * 例如说: | ||
| 87 | + * 1. id = “静安区”时:上海 上海市 静安区 | ||
| 88 | + * 2. id = “上海市”时:上海 上海市 | ||
| 89 | + * 3. id = “上海”时:上海 | ||
| 90 | + * 4. id = “美国”时:美国 | ||
| 91 | + * 当区域在中国时,默认不显示中国 | ||
| 92 | + * | ||
| 93 | + * @param id 区域编号 | ||
| 94 | + * @param separator 分隔符 | ||
| 95 | + * @return 格式化后的区域 | ||
| 96 | + */ | ||
| 97 | + public static String format(Integer id, String separator) { | ||
| 98 | + // 获得区域 | ||
| 99 | + Area area = areas.get(id); | ||
| 100 | + if (area == null) { | ||
| 101 | + return null; | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + // 格式化 | ||
| 105 | + StringBuilder sb = new StringBuilder(); | ||
| 106 | + for (int i = 0; i < AreaTypeEnum.values().length; i++) { // 避免死循环 | ||
| 107 | + sb.insert(0, area.getName()); | ||
| 108 | + // “递归”父节点 | ||
| 109 | + area = area.getParent(); | ||
| 110 | + if (area == null | ||
| 111 | + || ObjectUtils.equalsAny(area.getId(), Area.ID_GLOBAL, Area.ID_CHINA)) { // 跳过父节点为中国的情况 | ||
| 112 | + break; | ||
| 113 | + } | ||
| 114 | + sb.insert(0, separator); | ||
| 115 | + } | ||
| 116 | + return sb.toString(); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | +} |
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtils.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ip.core.utils; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.io.resource.ResourceUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.ip.core.Area; | ||
| 5 | +import lombok.SneakyThrows; | ||
| 6 | +import lombok.extern.slf4j.Slf4j; | ||
| 7 | +import org.lionsoul.ip2region.xdb.Searcher; | ||
| 8 | + | ||
| 9 | +import java.io.IOException; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * IP 工具类 | ||
| 13 | + * | ||
| 14 | + * IP 数据源来自 ip2region.xdb 精简版,基于 <a href="https://gitee.com/zhijiantianya/ip2region"/> 项目 | ||
| 15 | + * | ||
| 16 | + * @author wanglhup | ||
| 17 | + */ | ||
| 18 | +@Slf4j | ||
| 19 | +public class IPUtils { | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 初始化 SEARCHER | ||
| 23 | + */ | ||
| 24 | + @SuppressWarnings("InstantiationOfUtilityClass") | ||
| 25 | + private final static IPUtils INSTANCE = new IPUtils(); | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * IP 查询器,启动加载到内存中 | ||
| 29 | + */ | ||
| 30 | + private static Searcher SEARCHER; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 私有化构造 | ||
| 34 | + */ | ||
| 35 | + private IPUtils() { | ||
| 36 | + try { | ||
| 37 | + long now = System.currentTimeMillis(); | ||
| 38 | + byte[] bytes = ResourceUtil.readBytes("ip2region.xdb"); | ||
| 39 | + SEARCHER = Searcher.newWithBuffer(bytes); | ||
| 40 | + log.info("启动加载 IPUtils 成功,耗时 ({}) 毫秒", System.currentTimeMillis() - now); | ||
| 41 | + } catch (IOException e) { | ||
| 42 | + log.error("启动加载 IPUtils 失败", e); | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 查询 IP 对应的地区编号 | ||
| 48 | + * | ||
| 49 | + * @param ip IP 地址,格式为 127.0.0.1 | ||
| 50 | + * @return 地区id | ||
| 51 | + */ | ||
| 52 | + @SneakyThrows | ||
| 53 | + public static Integer getAreaId(String ip) { | ||
| 54 | + return Integer.parseInt(SEARCHER.search(ip)); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * 查询 IP 对应的地区编号 | ||
| 59 | + * | ||
| 60 | + * @param ip IP 地址的时间戳,格式参考{@link Searcher#checkIP(String)} 的返回 | ||
| 61 | + * @return 地区编号 | ||
| 62 | + */ | ||
| 63 | + @SneakyThrows | ||
| 64 | + public static Integer getAreaId(long ip) { | ||
| 65 | + return Integer.parseInt(SEARCHER.search(ip)); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + /** | ||
| 69 | + * 查询 IP 对应的地区 | ||
| 70 | + * | ||
| 71 | + * @param ip IP 地址,格式为 127.0.0.1 | ||
| 72 | + * @return 地区 | ||
| 73 | + */ | ||
| 74 | + public static Area getArea(String ip) { | ||
| 75 | + return AreaUtils.getArea(getAreaId(ip)); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + /** | ||
| 79 | + * 查询 IP 对应的地区 | ||
| 80 | + * | ||
| 81 | + * @param ip IP 地址的时间戳,格式参考{@link Searcher#checkIP(String)} 的返回 | ||
| 82 | + * @return 地区 | ||
| 83 | + */ | ||
| 84 | + public static Area getArea(long ip) { | ||
| 85 | + return AreaUtils.getArea(getAreaId(ip)); | ||
| 86 | + } | ||
| 87 | +} |
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/package-info.java
0 → 100644
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv
0 → 100644
| 1 | +id,name,type,parentId | ||
| 2 | +1,中国,1,0 | ||
| 3 | +2,蒙古,1,0 | ||
| 4 | +3,朝鲜,1,0 | ||
| 5 | +4,韩国,1,0 | ||
| 6 | +5,日本,1,0 | ||
| 7 | +6,菲律宾,1,0 | ||
| 8 | +7,越南,1,0 | ||
| 9 | +8,老挝,1,0 | ||
| 10 | +9,柬埔寨,1,0 | ||
| 11 | +10,缅甸,1,0 | ||
| 12 | +11,泰国,1,0 | ||
| 13 | +12,马来西亚,1,0 | ||
| 14 | +13,文莱,1,0 | ||
| 15 | +14,新加坡,1,0 | ||
| 16 | +15,印度尼西亚,1,0 | ||
| 17 | +16,东帝汶,1,0 | ||
| 18 | +17,尼泊尔,1,0 | ||
| 19 | +18,不丹,1,0 | ||
| 20 | +19,孟加拉国,1,0 | ||
| 21 | +20,印度,1,0 | ||
| 22 | +21,巴基斯坦,1,0 | ||
| 23 | +22,斯里兰卡,1,0 | ||
| 24 | +23,马尔代夫,1,0 | ||
| 25 | +24,哈萨克斯坦,1,0 | ||
| 26 | +25,吉尔吉斯斯坦,1,0 | ||
| 27 | +26,塔吉克斯坦,1,0 | ||
| 28 | +27,乌兹别克斯坦,1,0 | ||
| 29 | +28,土库曼斯坦,1,0 | ||
| 30 | +29,阿富汗,1,0 | ||
| 31 | +30,伊拉克,1,0 | ||
| 32 | +31,伊朗,1,0 | ||
| 33 | +32,叙利亚,1,0 | ||
| 34 | +33,约旦,1,0 | ||
| 35 | +34,黎巴嫩,1,0 | ||
| 36 | +35,以色列,1,0 | ||
| 37 | +36,巴勒斯坦,1,0 | ||
| 38 | +37,沙特阿拉伯,1,0 | ||
| 39 | +38,巴林,1,0 | ||
| 40 | +39,卡塔尔,1,0 | ||
| 41 | +40,科威特,1,0 | ||
| 42 | +41,阿拉伯联合酋长国,1,0 | ||
| 43 | +42,阿曼,1,0 | ||
| 44 | +43,也门,1,0 | ||
| 45 | +44,格鲁吉亚,1,0 | ||
| 46 | +45,亚美尼亚,1,0 | ||
| 47 | +46,阿塞拜疆,1,0 | ||
| 48 | +47,土耳其,1,0 | ||
| 49 | +48,塞浦路斯,1,0 | ||
| 50 | +49,芬兰,1,0 | ||
| 51 | +50,瑞典,1,0 | ||
| 52 | +51,挪威,1,0 | ||
| 53 | +52,冰岛,1,0 | ||
| 54 | +53,丹麦,1,0 | ||
| 55 | +54,爱沙尼亚,1,0 | ||
| 56 | +55,拉脱维亚,1,0 | ||
| 57 | +56,立陶宛,1,0 | ||
| 58 | +57,白俄罗斯,1,0 | ||
| 59 | +58,俄罗斯,1,0 | ||
| 60 | +59,乌克兰,1,0 | ||
| 61 | +60,摩尔多瓦,1,0 | ||
| 62 | +61,波兰,1,0 | ||
| 63 | +62,捷克,1,0 | ||
| 64 | +63,斯洛伐克,1,0 | ||
| 65 | +64,匈牙利,1,0 | ||
| 66 | +65,德国,1,0 | ||
| 67 | +66,奥地利,1,0 | ||
| 68 | +67,瑞士,1,0 | ||
| 69 | +68,列支敦士登,1,0 | ||
| 70 | +69,英国,1,0 | ||
| 71 | +70,爱尔兰,1,0 | ||
| 72 | +71,荷兰,1,0 | ||
| 73 | +72,比利时,1,0 | ||
| 74 | +73,卢森堡,1,0 | ||
| 75 | +74,法国,1,0 | ||
| 76 | +75,摩纳哥,1,0 | ||
| 77 | +76,罗马尼亚,1,0 | ||
| 78 | +77,保加利亚,1,0 | ||
| 79 | +78,塞尔维亚,1,0 | ||
| 80 | +79,马其顿,1,0 | ||
| 81 | +80,阿尔巴尼亚,1,0 | ||
| 82 | +81,希腊,1,0 | ||
| 83 | +82,斯洛文尼亚,1,0 | ||
| 84 | +83,克罗地亚,1,0 | ||
| 85 | +84,波斯尼亚和墨塞哥维那,1,0 | ||
| 86 | +85,意大利,1,0 | ||
| 87 | +86,梵蒂冈,1,0 | ||
| 88 | +87,圣马力诺,1,0 | ||
| 89 | +88,马耳他,1,0 | ||
| 90 | +89,西班牙,1,0 | ||
| 91 | +90,葡萄牙,1,0 | ||
| 92 | +91,安道尔共和国,1,0 | ||
| 93 | +92,埃及,1,0 | ||
| 94 | +93,利比亚,1,0 | ||
| 95 | +94,苏丹,1,0 | ||
| 96 | +95,突尼斯,1,0 | ||
| 97 | +96,阿尔及利亚,1,0 | ||
| 98 | +97,摩洛哥,1,0 | ||
| 99 | +98,亚速尔群岛,1,0 | ||
| 100 | +99,马德拉群岛,1,0 | ||
| 101 | +100,埃塞俄比亚,1,0 | ||
| 102 | +101,厄立特里亚,1,0 | ||
| 103 | +102,索马里,1,0 | ||
| 104 | +103,吉布提,1,0 | ||
| 105 | +104,肯尼亚,1,0 | ||
| 106 | +105,坦桑尼亚,1,0 | ||
| 107 | +106,乌干达,1,0 | ||
| 108 | +107,卢旺达,1,0 | ||
| 109 | +108,布隆迪,1,0 | ||
| 110 | +109,塞舌尔,1,0 | ||
| 111 | +110,圣多美及普林西比,1,0 | ||
| 112 | +111,塞内加尔,1,0 | ||
| 113 | +112,冈比亚,1,0 | ||
| 114 | +113,马里,1,0 | ||
| 115 | +114,布基纳法索,1,0 | ||
| 116 | +115,几内亚,1,0 | ||
| 117 | +116,几内亚比绍,1,0 | ||
| 118 | +117,佛得角,1,0 | ||
| 119 | +118,塞拉利昂,1,0 | ||
| 120 | +119,利比里亚,1,0 | ||
| 121 | +120,科特迪瓦,1,0 | ||
| 122 | +121,加纳,1,0 | ||
| 123 | +122,多哥,1,0 | ||
| 124 | +123,贝宁,1,0 | ||
| 125 | +124,尼日尔,1,0 | ||
| 126 | +125,加那利群岛,1,0 | ||
| 127 | +126,赞比亚,1,0 | ||
| 128 | +127,安哥拉,1,0 | ||
| 129 | +128,津巴布韦,1,0 | ||
| 130 | +129,马拉维,1,0 | ||
| 131 | +130,莫桑比克,1,0 | ||
| 132 | +131,博茨瓦纳,1,0 | ||
| 133 | +132,纳米比亚,1,0 | ||
| 134 | +133,南非,1,0 | ||
| 135 | +134,斯威士兰,1,0 | ||
| 136 | +135,莱索托,1,0 | ||
| 137 | +136,马达加斯加,1,0 | ||
| 138 | +137,科摩罗,1,0 | ||
| 139 | +138,毛里求斯,1,0 | ||
| 140 | +139,留尼旺,1,0 | ||
| 141 | +140,圣赫勒拿,1,0 | ||
| 142 | +141,澳大利亚,1,0 | ||
| 143 | +142,新西兰,1,0 | ||
| 144 | +143,巴布亚新几内亚,1,0 | ||
| 145 | +144,所罗门群岛,1,0 | ||
| 146 | +145,瓦努阿图共和国,1,0 | ||
| 147 | +146,密克罗尼西亚,1,0 | ||
| 148 | +147,马绍尔群岛,1,0 | ||
| 149 | +148,帕劳,1,0 | ||
| 150 | +149,瑙鲁,1,0 | ||
| 151 | +150,基里巴斯,1,0 | ||
| 152 | +151,图瓦卢,1,0 | ||
| 153 | +152,萨摩亚,1,0 | ||
| 154 | +153,斐济,1,0 | ||
| 155 | +154,汤加,1,0 | ||
| 156 | +155,库克群岛,1,0 | ||
| 157 | +156,关岛,1,0 | ||
| 158 | +157,新喀里多尼亚,1,0 | ||
| 159 | +158,法属波利尼西亚,1,0 | ||
| 160 | +159,皮特凯恩岛,1,0 | ||
| 161 | +160,瓦利斯与富图纳,1,0 | ||
| 162 | +161,纽埃,1,0 | ||
| 163 | +162,托克劳,1,0 | ||
| 164 | +163,美属萨摩亚,1,0 | ||
| 165 | +164,北马里亚纳,1,0 | ||
| 166 | +165,加拿大,1,0 | ||
| 167 | +166,美国,1,0 | ||
| 168 | +167,墨西哥,1,0 | ||
| 169 | +168,格陵兰,1,0 | ||
| 170 | +169,危地马拉,1,0 | ||
| 171 | +170,伯利兹,1,0 | ||
| 172 | +171,萨尔瓦多,1,0 | ||
| 173 | +172,洪都拉斯,1,0 | ||
| 174 | +173,尼加拉瓜,1,0 | ||
| 175 | +174,哥斯达黎加,1,0 | ||
| 176 | +175,巴拿马,1,0 | ||
| 177 | +176,巴哈马,1,0 | ||
| 178 | +177,古巴,1,0 | ||
| 179 | +178,牙买加,1,0 | ||
| 180 | +179,海地,1,0 | ||
| 181 | +180,多米尼加共和国,1,0 | ||
| 182 | +181,安提瓜和巴布达,1,0 | ||
| 183 | +182,圣基茨和尼维斯,1,0 | ||
| 184 | +183,多米尼克,1,0 | ||
| 185 | +184,圣卢西亚,1,0 | ||
| 186 | +185,圣文森特和格林纳丁斯,1,0 | ||
| 187 | +186,格林纳达,1,0 | ||
| 188 | +187,巴巴多斯,1,0 | ||
| 189 | +188,特立尼达和多巴哥,1,0 | ||
| 190 | +189,波多黎各,1,0 | ||
| 191 | +190,英属维尔京群岛,1,0 | ||
| 192 | +191,美属维尔京群岛,1,0 | ||
| 193 | +192,安圭拉,1,0 | ||
| 194 | +193,蒙特塞拉特岛,1,0 | ||
| 195 | +194,瓜德罗普,1,0 | ||
| 196 | +195,马提尼克,1,0 | ||
| 197 | +196,荷属安的列斯,1,0 | ||
| 198 | +197,阿鲁巴,1,0 | ||
| 199 | +198,特克斯和凯科斯群岛,1,0 | ||
| 200 | +199,开曼群岛,1,0 | ||
| 201 | +200,百慕大,1,0 | ||
| 202 | +201,哥伦比亚,1,0 | ||
| 203 | +202,委内瑞拉,1,0 | ||
| 204 | +203,圭亚那,1,0 | ||
| 205 | +204,法属圭亚那,1,0 | ||
| 206 | +205,苏里南,1,0 | ||
| 207 | +206,厄瓜多尔,1,0 | ||
| 208 | +207,秘鲁,1,0 | ||
| 209 | +208,玻利维亚,1,0 | ||
| 210 | +209,巴西,1,0 | ||
| 211 | +210,智利,1,0 | ||
| 212 | +211,阿根廷,1,0 | ||
| 213 | +212,乌拉圭,1,0 | ||
| 214 | +213,巴拉圭,1,0 | ||
| 215 | +214,波黑,1,0 | ||
| 216 | +215,直布罗陀,1,0 | ||
| 217 | +216,新喀里多尼亚群岛,1,0 | ||
| 218 | +217,瓦利斯和富图纳群岛,1,0 | ||
| 219 | +218,泽西岛,1,0 | ||
| 220 | +219,黑山,1,0 | ||
| 221 | +220,英属马恩岛,1,0 | ||
| 222 | +221,尼日利亚,1,0 | ||
| 223 | +222,喀麦隆,1,0 | ||
| 224 | +223,加蓬,1,0 | ||
| 225 | +224,乍得,1,0 | ||
| 226 | +225,刚果共和国,1,0 | ||
| 227 | +226,中非共和国,1,0 | ||
| 228 | +227,南苏丹,1,0 | ||
| 229 | +228,赤道几内亚,1,0 | ||
| 230 | +229,毛里塔尼亚,1,0 | ||
| 231 | +230,刚果民主共和国,1,0 | ||
| 232 | +231,留尼汪岛,1,0 | ||
| 233 | +232,格陵兰岛,1,0 | ||
| 234 | +233,法罗群岛,1,0 | ||
| 235 | +234,根西岛,1,0 | ||
| 236 | +235,百慕大群岛,1,0 | ||
| 237 | +236,圣皮埃尔和密克隆群岛,1,0 | ||
| 238 | +237,法属圣马丁,1,0 | ||
| 239 | +238,奥兰群岛,1,0 | ||
| 240 | +239,北马里亚纳群岛,1,0 | ||
| 241 | +240,库拉索,1,0 | ||
| 242 | +241,博内尔岛,1,0 | ||
| 243 | +242,圣马丁岛,1,0 | ||
| 244 | +243,圣巴泰勒米岛,1,0 | ||
| 245 | +244,福克兰群岛,1,0 | ||
| 246 | +245,圣多美和普林西比,1,0 | ||
| 247 | +246,英属印度洋领地,1,0 | ||
| 248 | +247,东萨摩亚,1,0 | ||
| 249 | +248,诺福克岛,1,0 | ||
| 250 | +110000,北京,2,1 | ||
| 251 | +120000,天津,2,1 | ||
| 252 | +130000,河北省,2,1 | ||
| 253 | +140000,山西省,2,1 | ||
| 254 | +150000,内蒙古自治区,2,1 | ||
| 255 | +210000,辽宁省,2,1 | ||
| 256 | +220000,吉林省,2,1 | ||
| 257 | +230000,黑龙江省,2,1 | ||
| 258 | +310000,上海,2,1 | ||
| 259 | +320000,江苏省,2,1 | ||
| 260 | +330000,浙江省,2,1 | ||
| 261 | +340000,安徽省,2,1 | ||
| 262 | +350000,福建省,2,1 | ||
| 263 | +360000,江西省,2,1 | ||
| 264 | +370000,山东省,2,1 | ||
| 265 | +410000,河南省,2,1 | ||
| 266 | +420000,湖北省,2,1 | ||
| 267 | +430000,湖南省,2,1 | ||
| 268 | +440000,广东省,2,1 | ||
| 269 | +450000,广西壮族自治区,2,1 | ||
| 270 | +460000,海南省,2,1 | ||
| 271 | +500000,重庆,2,1 | ||
| 272 | +510000,四川省,2,1 | ||
| 273 | +520000,贵州省,2,1 | ||
| 274 | +530000,云南省,2,1 | ||
| 275 | +540000,西藏自治区,2,1 | ||
| 276 | +610000,陕西省,2,1 | ||
| 277 | +620000,甘肃省,2,1 | ||
| 278 | +630000,青海省,2,1 | ||
| 279 | +640000,宁夏回族自治区,2,1 | ||
| 280 | +650000,新疆维吾尔自治区,2,1 | ||
| 281 | +110100,北京市,3,110000 | ||
| 282 | +120100,天津市,3,120000 | ||
| 283 | +130100,石家庄市,3,130000 | ||
| 284 | +130200,唐山市,3,130000 | ||
| 285 | +130300,秦皇岛市,3,130000 | ||
| 286 | +130400,邯郸市,3,130000 | ||
| 287 | +130500,邢台市,3,130000 | ||
| 288 | +130600,保定市,3,130000 | ||
| 289 | +130700,张家口市,3,130000 | ||
| 290 | +130800,承德市,3,130000 | ||
| 291 | +130900,沧州市,3,130000 | ||
| 292 | +131000,廊坊市,3,130000 | ||
| 293 | +131100,衡水市,3,130000 | ||
| 294 | +140100,太原市,3,140000 | ||
| 295 | +140200,大同市,3,140000 | ||
| 296 | +140300,阳泉市,3,140000 | ||
| 297 | +140400,长治市,3,140000 | ||
| 298 | +140500,晋城市,3,140000 | ||
| 299 | +140600,朔州市,3,140000 | ||
| 300 | +140700,晋中市,3,140000 | ||
| 301 | +140800,运城市,3,140000 | ||
| 302 | +140900,忻州市,3,140000 | ||
| 303 | +141000,临汾市,3,140000 | ||
| 304 | +141100,吕梁市,3,140000 | ||
| 305 | +150100,呼和浩特市,3,150000 | ||
| 306 | +150200,包头市,3,150000 | ||
| 307 | +150300,乌海市,3,150000 | ||
| 308 | +150400,赤峰市,3,150000 | ||
| 309 | +150500,通辽市,3,150000 | ||
| 310 | +150600,鄂尔多斯市,3,150000 | ||
| 311 | +150700,呼伦贝尔市,3,150000 | ||
| 312 | +150800,巴彦淖尔市,3,150000 | ||
| 313 | +150900,乌兰察布市,3,150000 | ||
| 314 | +152200,兴安盟,3,150000 | ||
| 315 | +152500,锡林郭勒盟,3,150000 | ||
| 316 | +152900,阿拉善盟,3,150000 | ||
| 317 | +210100,沈阳市,3,210000 | ||
| 318 | +210200,大连市,3,210000 | ||
| 319 | +210300,鞍山市,3,210000 | ||
| 320 | +210400,抚顺市,3,210000 | ||
| 321 | +210500,本溪市,3,210000 | ||
| 322 | +210600,丹东市,3,210000 | ||
| 323 | +210700,锦州市,3,210000 | ||
| 324 | +210800,营口市,3,210000 | ||
| 325 | +210900,阜新市,3,210000 | ||
| 326 | +211000,辽阳市,3,210000 | ||
| 327 | +211100,盘锦市,3,210000 | ||
| 328 | +211200,铁岭市,3,210000 | ||
| 329 | +211300,朝阳市,3,210000 | ||
| 330 | +211400,葫芦岛市,3,210000 | ||
| 331 | +220100,长春市,3,220000 | ||
| 332 | +220200,吉林市,3,220000 | ||
| 333 | +220300,四平市,3,220000 | ||
| 334 | +220400,辽源市,3,220000 | ||
| 335 | +220500,通化市,3,220000 | ||
| 336 | +220600,白山市,3,220000 | ||
| 337 | +220700,松原市,3,220000 | ||
| 338 | +220800,白城市,3,220000 | ||
| 339 | +222400,延边朝鲜族自治州,3,220000 | ||
| 340 | +230100,哈尔滨市,3,230000 | ||
| 341 | +230200,齐齐哈尔市,3,230000 | ||
| 342 | +230300,鸡西市,3,230000 | ||
| 343 | +230400,鹤岗市,3,230000 | ||
| 344 | +230500,双鸭山市,3,230000 | ||
| 345 | +230600,大庆市,3,230000 | ||
| 346 | +230700,伊春市,3,230000 | ||
| 347 | +230800,佳木斯市,3,230000 | ||
| 348 | +230900,七台河市,3,230000 | ||
| 349 | +231000,牡丹江市,3,230000 | ||
| 350 | +231100,黑河市,3,230000 | ||
| 351 | +231200,绥化市,3,230000 | ||
| 352 | +232700,大兴安岭地区,3,230000 | ||
| 353 | +310100,上海市,3,310000 | ||
| 354 | +320100,南京市,3,320000 | ||
| 355 | +320200,无锡市,3,320000 | ||
| 356 | +320300,徐州市,3,320000 | ||
| 357 | +320400,常州市,3,320000 | ||
| 358 | +320500,苏州市,3,320000 | ||
| 359 | +320600,南通市,3,320000 | ||
| 360 | +320700,连云港市,3,320000 | ||
| 361 | +320800,淮安市,3,320000 | ||
| 362 | +320900,盐城市,3,320000 | ||
| 363 | +321000,扬州市,3,320000 | ||
| 364 | +321100,镇江市,3,320000 | ||
| 365 | +321200,泰州市,3,320000 | ||
| 366 | +321300,宿迁市,3,320000 | ||
| 367 | +330100,杭州市,3,330000 | ||
| 368 | +330200,宁波市,3,330000 | ||
| 369 | +330300,温州市,3,330000 | ||
| 370 | +330400,嘉兴市,3,330000 | ||
| 371 | +330500,湖州市,3,330000 | ||
| 372 | +330600,绍兴市,3,330000 | ||
| 373 | +330700,金华市,3,330000 | ||
| 374 | +330800,衢州市,3,330000 | ||
| 375 | +330900,舟山市,3,330000 | ||
| 376 | +331000,台州市,3,330000 | ||
| 377 | +331100,丽水市,3,330000 | ||
| 378 | +340100,合肥市,3,340000 | ||
| 379 | +340200,芜湖市,3,340000 | ||
| 380 | +340300,蚌埠市,3,340000 | ||
| 381 | +340400,淮南市,3,340000 | ||
| 382 | +340500,马鞍山市,3,340000 | ||
| 383 | +340600,淮北市,3,340000 | ||
| 384 | +340700,铜陵市,3,340000 | ||
| 385 | +340800,安庆市,3,340000 | ||
| 386 | +341000,黄山市,3,340000 | ||
| 387 | +341100,滁州市,3,340000 | ||
| 388 | +341200,阜阳市,3,340000 | ||
| 389 | +341300,宿州市,3,340000 | ||
| 390 | +341500,六安市,3,340000 | ||
| 391 | +341600,亳州市,3,340000 | ||
| 392 | +341700,池州市,3,340000 | ||
| 393 | +341800,宣城市,3,340000 | ||
| 394 | +350100,福州市,3,350000 | ||
| 395 | +350200,厦门市,3,350000 | ||
| 396 | +350300,莆田市,3,350000 | ||
| 397 | +350400,三明市,3,350000 | ||
| 398 | +350500,泉州市,3,350000 | ||
| 399 | +350600,漳州市,3,350000 | ||
| 400 | +350700,南平市,3,350000 | ||
| 401 | +350800,龙岩市,3,350000 | ||
| 402 | +350900,宁德市,3,350000 | ||
| 403 | +360100,南昌市,3,360000 | ||
| 404 | +360200,景德镇市,3,360000 | ||
| 405 | +360300,萍乡市,3,360000 | ||
| 406 | +360400,九江市,3,360000 | ||
| 407 | +360500,新余市,3,360000 | ||
| 408 | +360600,鹰潭市,3,360000 | ||
| 409 | +360700,赣州市,3,360000 | ||
| 410 | +360800,吉安市,3,360000 | ||
| 411 | +360900,宜春市,3,360000 | ||
| 412 | +361000,抚州市,3,360000 | ||
| 413 | +361100,上饶市,3,360000 | ||
| 414 | +370100,济南市,3,370000 | ||
| 415 | +370200,青岛市,3,370000 | ||
| 416 | +370300,淄博市,3,370000 | ||
| 417 | +370400,枣庄市,3,370000 | ||
| 418 | +370500,东营市,3,370000 | ||
| 419 | +370600,烟台市,3,370000 | ||
| 420 | +370700,潍坊市,3,370000 | ||
| 421 | +370800,济宁市,3,370000 | ||
| 422 | +370900,泰安市,3,370000 | ||
| 423 | +371000,威海市,3,370000 | ||
| 424 | +371100,日照市,3,370000 | ||
| 425 | +371300,临沂市,3,370000 | ||
| 426 | +371400,德州市,3,370000 | ||
| 427 | +371500,聊城市,3,370000 | ||
| 428 | +371600,滨州市,3,370000 | ||
| 429 | +371700,菏泽市,3,370000 | ||
| 430 | +410100,郑州市,3,410000 | ||
| 431 | +410200,开封市,3,410000 | ||
| 432 | +410300,洛阳市,3,410000 | ||
| 433 | +410400,平顶山市,3,410000 | ||
| 434 | +410500,安阳市,3,410000 | ||
| 435 | +410600,鹤壁市,3,410000 | ||
| 436 | +410700,新乡市,3,410000 | ||
| 437 | +410800,焦作市,3,410000 | ||
| 438 | +410900,濮阳市,3,410000 | ||
| 439 | +411000,许昌市,3,410000 | ||
| 440 | +411100,漯河市,3,410000 | ||
| 441 | +411200,三门峡市,3,410000 | ||
| 442 | +411300,南阳市,3,410000 | ||
| 443 | +411400,商丘市,3,410000 | ||
| 444 | +411500,信阳市,3,410000 | ||
| 445 | +411600,周口市,3,410000 | ||
| 446 | +411700,驻马店市,3,410000 | ||
| 447 | +419000,省直辖县级行政区划,3,410000 | ||
| 448 | +420100,武汉市,3,420000 | ||
| 449 | +420200,黄石市,3,420000 | ||
| 450 | +420300,十堰市,3,420000 | ||
| 451 | +420500,宜昌市,3,420000 | ||
| 452 | +420600,襄阳市,3,420000 | ||
| 453 | +420700,鄂州市,3,420000 | ||
| 454 | +420800,荆门市,3,420000 | ||
| 455 | +420900,孝感市,3,420000 | ||
| 456 | +421000,荆州市,3,420000 | ||
| 457 | +421100,黄冈市,3,420000 | ||
| 458 | +421200,咸宁市,3,420000 | ||
| 459 | +421300,随州市,3,420000 | ||
| 460 | +422800,恩施土家族苗族自治州,3,420000 | ||
| 461 | +429000,省直辖县级行政区划,3,420000 | ||
| 462 | +430100,长沙市,3,430000 | ||
| 463 | +430200,株洲市,3,430000 | ||
| 464 | +430300,湘潭市,3,430000 | ||
| 465 | +430400,衡阳市,3,430000 | ||
| 466 | +430500,邵阳市,3,430000 | ||
| 467 | +430600,岳阳市,3,430000 | ||
| 468 | +430700,常德市,3,430000 | ||
| 469 | +430800,张家界市,3,430000 | ||
| 470 | +430900,益阳市,3,430000 | ||
| 471 | +431000,郴州市,3,430000 | ||
| 472 | +431100,永州市,3,430000 | ||
| 473 | +431200,怀化市,3,430000 | ||
| 474 | +431300,娄底市,3,430000 | ||
| 475 | +433100,湘西土家族苗族自治州,3,430000 | ||
| 476 | +440100,广州市,3,440000 | ||
| 477 | +440200,韶关市,3,440000 | ||
| 478 | +440300,深圳市,3,440000 | ||
| 479 | +440400,珠海市,3,440000 | ||
| 480 | +440500,汕头市,3,440000 | ||
| 481 | +440600,佛山市,3,440000 | ||
| 482 | +440700,江门市,3,440000 | ||
| 483 | +440800,湛江市,3,440000 | ||
| 484 | +440900,茂名市,3,440000 | ||
| 485 | +441200,肇庆市,3,440000 | ||
| 486 | +441300,惠州市,3,440000 | ||
| 487 | +441400,梅州市,3,440000 | ||
| 488 | +441500,汕尾市,3,440000 | ||
| 489 | +441600,河源市,3,440000 | ||
| 490 | +441700,阳江市,3,440000 | ||
| 491 | +441800,清远市,3,440000 | ||
| 492 | +441900,东莞市,3,440000 | ||
| 493 | +442000,中山市,3,440000 | ||
| 494 | +445100,潮州市,3,440000 | ||
| 495 | +445200,揭阳市,3,440000 | ||
| 496 | +445300,云浮市,3,440000 | ||
| 497 | +450100,南宁市,3,450000 | ||
| 498 | +450200,柳州市,3,450000 | ||
| 499 | +450300,桂林市,3,450000 | ||
| 500 | +450400,梧州市,3,450000 | ||
| 501 | +450500,北海市,3,450000 | ||
| 502 | +450600,防城港市,3,450000 | ||
| 503 | +450700,钦州市,3,450000 | ||
| 504 | +450800,贵港市,3,450000 | ||
| 505 | +450900,玉林市,3,450000 | ||
| 506 | +451000,百色市,3,450000 | ||
| 507 | +451100,贺州市,3,450000 | ||
| 508 | +451200,河池市,3,450000 | ||
| 509 | +451300,来宾市,3,450000 | ||
| 510 | +451400,崇左市,3,450000 | ||
| 511 | +460100,海口市,3,460000 | ||
| 512 | +460200,三亚市,3,460000 | ||
| 513 | +460300,三沙市,3,460000 | ||
| 514 | +460400,儋州市,3,460000 | ||
| 515 | +469000,省直辖县级行政区划,3,460000 | ||
| 516 | +500100,重庆市,3,500000 | ||
| 517 | +510100,成都市,3,510000 | ||
| 518 | +510300,自贡市,3,510000 | ||
| 519 | +510400,攀枝花市,3,510000 | ||
| 520 | +510500,泸州市,3,510000 | ||
| 521 | +510600,德阳市,3,510000 | ||
| 522 | +510700,绵阳市,3,510000 | ||
| 523 | +510800,广元市,3,510000 | ||
| 524 | +510900,遂宁市,3,510000 | ||
| 525 | +511000,内江市,3,510000 | ||
| 526 | +511100,乐山市,3,510000 | ||
| 527 | +511300,南充市,3,510000 | ||
| 528 | +511400,眉山市,3,510000 | ||
| 529 | +511500,宜宾市,3,510000 | ||
| 530 | +511600,广安市,3,510000 | ||
| 531 | +511700,达州市,3,510000 | ||
| 532 | +511800,雅安市,3,510000 | ||
| 533 | +511900,巴中市,3,510000 | ||
| 534 | +512000,资阳市,3,510000 | ||
| 535 | +513200,阿坝藏族羌族自治州,3,510000 | ||
| 536 | +513300,甘孜藏族自治州,3,510000 | ||
| 537 | +513400,凉山彝族自治州,3,510000 | ||
| 538 | +520100,贵阳市,3,520000 | ||
| 539 | +520200,六盘水市,3,520000 | ||
| 540 | +520300,遵义市,3,520000 | ||
| 541 | +520400,安顺市,3,520000 | ||
| 542 | +520500,毕节市,3,520000 | ||
| 543 | +520600,铜仁市,3,520000 | ||
| 544 | +522300,黔西南布依族苗族自治州,3,520000 | ||
| 545 | +522600,黔东南苗族侗族自治州,3,520000 | ||
| 546 | +522700,黔南布依族苗族自治州,3,520000 | ||
| 547 | +530100,昆明市,3,530000 | ||
| 548 | +530300,曲靖市,3,530000 | ||
| 549 | +530400,玉溪市,3,530000 | ||
| 550 | +530500,保山市,3,530000 | ||
| 551 | +530600,昭通市,3,530000 | ||
| 552 | +530700,丽江市,3,530000 | ||
| 553 | +530800,普洱市,3,530000 | ||
| 554 | +530900,临沧市,3,530000 | ||
| 555 | +532300,楚雄彝族自治州,3,530000 | ||
| 556 | +532500,红河哈尼族彝族自治州,3,530000 | ||
| 557 | +532600,文山壮族苗族自治州,3,530000 | ||
| 558 | +532800,西双版纳傣族自治州,3,530000 | ||
| 559 | +532900,大理白族自治州,3,530000 | ||
| 560 | +533100,德宏傣族景颇族自治州,3,530000 | ||
| 561 | +533300,怒江傈僳族自治州,3,530000 | ||
| 562 | +533400,迪庆藏族自治州,3,530000 | ||
| 563 | +540100,拉萨市,3,540000 | ||
| 564 | +540200,日喀则市,3,540000 | ||
| 565 | +540300,昌都市,3,540000 | ||
| 566 | +540400,林芝市,3,540000 | ||
| 567 | +540500,山南市,3,540000 | ||
| 568 | +540600,那曲市,3,540000 | ||
| 569 | +542500,阿里地区,3,540000 | ||
| 570 | +610100,西安市,3,610000 | ||
| 571 | +610200,铜川市,3,610000 | ||
| 572 | +610300,宝鸡市,3,610000 | ||
| 573 | +610400,咸阳市,3,610000 | ||
| 574 | +610500,渭南市,3,610000 | ||
| 575 | +610600,延安市,3,610000 | ||
| 576 | +610700,汉中市,3,610000 | ||
| 577 | +610800,榆林市,3,610000 | ||
| 578 | +610900,安康市,3,610000 | ||
| 579 | +611000,商洛市,3,610000 | ||
| 580 | +620100,兰州市,3,620000 | ||
| 581 | +620200,嘉峪关市,3,620000 | ||
| 582 | +620300,金昌市,3,620000 | ||
| 583 | +620400,白银市,3,620000 | ||
| 584 | +620500,天水市,3,620000 | ||
| 585 | +620600,武威市,3,620000 | ||
| 586 | +620700,张掖市,3,620000 | ||
| 587 | +620800,平凉市,3,620000 | ||
| 588 | +620900,酒泉市,3,620000 | ||
| 589 | +621000,庆阳市,3,620000 | ||
| 590 | +621100,定西市,3,620000 | ||
| 591 | +621200,陇南市,3,620000 | ||
| 592 | +622900,临夏回族自治州,3,620000 | ||
| 593 | +623000,甘南藏族自治州,3,620000 | ||
| 594 | +630100,西宁市,3,630000 | ||
| 595 | +630200,海东市,3,630000 | ||
| 596 | +632200,海北藏族自治州,3,630000 | ||
| 597 | +632300,黄南藏族自治州,3,630000 | ||
| 598 | +632500,海南藏族自治州,3,630000 | ||
| 599 | +632600,果洛藏族自治州,3,630000 | ||
| 600 | +632700,玉树藏族自治州,3,630000 | ||
| 601 | +632800,海西蒙古族藏族自治州,3,630000 | ||
| 602 | +640100,银川市,3,640000 | ||
| 603 | +640200,石嘴山市,3,640000 | ||
| 604 | +640300,吴忠市,3,640000 | ||
| 605 | +640400,固原市,3,640000 | ||
| 606 | +640500,中卫市,3,640000 | ||
| 607 | +650100,乌鲁木齐市,3,650000 | ||
| 608 | +650200,克拉玛依市,3,650000 | ||
| 609 | +650400,吐鲁番市,3,650000 | ||
| 610 | +650500,哈密市,3,650000 | ||
| 611 | +652300,昌吉回族自治州,3,650000 | ||
| 612 | +652700,博尔塔拉蒙古自治州,3,650000 | ||
| 613 | +652800,巴音郭楞蒙古自治州,3,650000 | ||
| 614 | +652900,阿克苏地区,3,650000 | ||
| 615 | +653000,克孜勒苏柯尔克孜自治州,3,650000 | ||
| 616 | +653100,喀什地区,3,650000 | ||
| 617 | +653200,和田地区,3,650000 | ||
| 618 | +654000,伊犁哈萨克自治州,3,650000 | ||
| 619 | +654200,塔城地区,3,650000 | ||
| 620 | +654300,阿勒泰地区,3,650000 | ||
| 621 | +659000,自治区直辖县级行政区划,3,650000 | ||
| 622 | +110101,东城区,4,110100 | ||
| 623 | +110102,西城区,4,110100 | ||
| 624 | +110105,朝阳区,4,110100 | ||
| 625 | +110106,丰台区,4,110100 | ||
| 626 | +110107,石景山区,4,110100 | ||
| 627 | +110108,海淀区,4,110100 | ||
| 628 | +110109,门头沟区,4,110100 | ||
| 629 | +110111,房山区,4,110100 | ||
| 630 | +110112,通州区,4,110100 | ||
| 631 | +110113,顺义区,4,110100 | ||
| 632 | +110114,昌平区,4,110100 | ||
| 633 | +110115,大兴区,4,110100 | ||
| 634 | +110116,怀柔区,4,110100 | ||
| 635 | +110117,平谷区,4,110100 | ||
| 636 | +110118,密云区,4,110100 | ||
| 637 | +110119,延庆区,4,110100 | ||
| 638 | +120101,和平区,4,120100 | ||
| 639 | +120102,河东区,4,120100 | ||
| 640 | +120103,河西区,4,120100 | ||
| 641 | +120104,南开区,4,120100 | ||
| 642 | +120105,河北区,4,120100 | ||
| 643 | +120106,红桥区,4,120100 | ||
| 644 | +120110,东丽区,4,120100 | ||
| 645 | +120111,西青区,4,120100 | ||
| 646 | +120112,津南区,4,120100 | ||
| 647 | +120113,北辰区,4,120100 | ||
| 648 | +120114,武清区,4,120100 | ||
| 649 | +120115,宝坻区,4,120100 | ||
| 650 | +120116,滨海新区,4,120100 | ||
| 651 | +120117,宁河区,4,120100 | ||
| 652 | +120118,静海区,4,120100 | ||
| 653 | +120119,蓟州区,4,120100 | ||
| 654 | +130102,长安区,4,130100 | ||
| 655 | +130104,桥西区,4,130100 | ||
| 656 | +130105,新华区,4,130100 | ||
| 657 | +130107,井陉矿区,4,130100 | ||
| 658 | +130108,裕华区,4,130100 | ||
| 659 | +130109,藁城区,4,130100 | ||
| 660 | +130110,鹿泉区,4,130100 | ||
| 661 | +130111,栾城区,4,130100 | ||
| 662 | +130121,井陉县,4,130100 | ||
| 663 | +130123,正定县,4,130100 | ||
| 664 | +130125,行唐县,4,130100 | ||
| 665 | +130126,灵寿县,4,130100 | ||
| 666 | +130127,高邑县,4,130100 | ||
| 667 | +130128,深泽县,4,130100 | ||
| 668 | +130129,赞皇县,4,130100 | ||
| 669 | +130130,无极县,4,130100 | ||
| 670 | +130131,平山县,4,130100 | ||
| 671 | +130132,元氏县,4,130100 | ||
| 672 | +130133,赵县,4,130100 | ||
| 673 | +130171,石家庄高新技术产业开发区,4,130100 | ||
| 674 | +130172,石家庄循环化工园区,4,130100 | ||
| 675 | +130181,辛集市,4,130100 | ||
| 676 | +130183,晋州市,4,130100 | ||
| 677 | +130184,新乐市,4,130100 | ||
| 678 | +130202,路南区,4,130200 | ||
| 679 | +130203,路北区,4,130200 | ||
| 680 | +130204,古冶区,4,130200 | ||
| 681 | +130205,开平区,4,130200 | ||
| 682 | +130207,丰南区,4,130200 | ||
| 683 | +130208,丰润区,4,130200 | ||
| 684 | +130209,曹妃甸区,4,130200 | ||
| 685 | +130224,滦南县,4,130200 | ||
| 686 | +130225,乐亭县,4,130200 | ||
| 687 | +130227,迁西县,4,130200 | ||
| 688 | +130229,玉田县,4,130200 | ||
| 689 | +130271,河北唐山芦台经济开发区,4,130200 | ||
| 690 | +130272,唐山市汉沽管理区,4,130200 | ||
| 691 | +130273,唐山高新技术产业开发区,4,130200 | ||
| 692 | +130274,河北唐山海港经济开发区,4,130200 | ||
| 693 | +130281,遵化市,4,130200 | ||
| 694 | +130283,迁安市,4,130200 | ||
| 695 | +130284,滦州市,4,130200 | ||
| 696 | +130302,海港区,4,130300 | ||
| 697 | +130303,山海关区,4,130300 | ||
| 698 | +130304,北戴河区,4,130300 | ||
| 699 | +130306,抚宁区,4,130300 | ||
| 700 | +130321,青龙满族自治县,4,130300 | ||
| 701 | +130322,昌黎县,4,130300 | ||
| 702 | +130324,卢龙县,4,130300 | ||
| 703 | +130371,秦皇岛市经济技术开发区,4,130300 | ||
| 704 | +130372,北戴河新区,4,130300 | ||
| 705 | +130402,邯山区,4,130400 | ||
| 706 | +130403,丛台区,4,130400 | ||
| 707 | +130404,复兴区,4,130400 | ||
| 708 | +130406,峰峰矿区,4,130400 | ||
| 709 | +130407,肥乡区,4,130400 | ||
| 710 | +130408,永年区,4,130400 | ||
| 711 | +130423,临漳县,4,130400 | ||
| 712 | +130424,成安县,4,130400 | ||
| 713 | +130425,大名县,4,130400 | ||
| 714 | +130426,涉县,4,130400 | ||
| 715 | +130427,磁县,4,130400 | ||
| 716 | +130430,邱县,4,130400 | ||
| 717 | +130431,鸡泽县,4,130400 | ||
| 718 | +130432,广平县,4,130400 | ||
| 719 | +130433,馆陶县,4,130400 | ||
| 720 | +130434,魏县,4,130400 | ||
| 721 | +130435,曲周县,4,130400 | ||
| 722 | +130471,邯郸经济技术开发区,4,130400 | ||
| 723 | +130473,邯郸冀南新区,4,130400 | ||
| 724 | +130481,武安市,4,130400 | ||
| 725 | +130502,襄都区,4,130500 | ||
| 726 | +130503,信都区,4,130500 | ||
| 727 | +130505,任泽区,4,130500 | ||
| 728 | +130506,南和区,4,130500 | ||
| 729 | +130522,临城县,4,130500 | ||
| 730 | +130523,内丘县,4,130500 | ||
| 731 | +130524,柏乡县,4,130500 | ||
| 732 | +130525,隆尧县,4,130500 | ||
| 733 | +130528,宁晋县,4,130500 | ||
| 734 | +130529,巨鹿县,4,130500 | ||
| 735 | +130530,新河县,4,130500 | ||
| 736 | +130531,广宗县,4,130500 | ||
| 737 | +130532,平乡县,4,130500 | ||
| 738 | +130533,威县,4,130500 | ||
| 739 | +130534,清河县,4,130500 | ||
| 740 | +130535,临西县,4,130500 | ||
| 741 | +130571,河北邢台经济开发区,4,130500 | ||
| 742 | +130581,南宫市,4,130500 | ||
| 743 | +130582,沙河市,4,130500 | ||
| 744 | +130602,竞秀区,4,130600 | ||
| 745 | +130606,莲池区,4,130600 | ||
| 746 | +130607,满城区,4,130600 | ||
| 747 | +130608,清苑区,4,130600 | ||
| 748 | +130609,徐水区,4,130600 | ||
| 749 | +130623,涞水县,4,130600 | ||
| 750 | +130624,阜平县,4,130600 | ||
| 751 | +130626,定兴县,4,130600 | ||
| 752 | +130627,唐县,4,130600 | ||
| 753 | +130628,高阳县,4,130600 | ||
| 754 | +130629,容城县,4,130600 | ||
| 755 | +130630,涞源县,4,130600 | ||
| 756 | +130631,望都县,4,130600 | ||
| 757 | +130632,安新县,4,130600 | ||
| 758 | +130633,易县,4,130600 | ||
| 759 | +130634,曲阳县,4,130600 | ||
| 760 | +130635,蠡县,4,130600 | ||
| 761 | +130636,顺平县,4,130600 | ||
| 762 | +130637,博野县,4,130600 | ||
| 763 | +130638,雄县,4,130600 | ||
| 764 | +130671,保定高新技术产业开发区,4,130600 | ||
| 765 | +130672,保定白沟新城,4,130600 | ||
| 766 | +130681,涿州市,4,130600 | ||
| 767 | +130682,定州市,4,130600 | ||
| 768 | +130683,安国市,4,130600 | ||
| 769 | +130684,高碑店市,4,130600 | ||
| 770 | +130702,桥东区,4,130700 | ||
| 771 | +130703,桥西区,4,130700 | ||
| 772 | +130705,宣化区,4,130700 | ||
| 773 | +130706,下花园区,4,130700 | ||
| 774 | +130708,万全区,4,130700 | ||
| 775 | +130709,崇礼区,4,130700 | ||
| 776 | +130722,张北县,4,130700 | ||
| 777 | +130723,康保县,4,130700 | ||
| 778 | +130724,沽源县,4,130700 | ||
| 779 | +130725,尚义县,4,130700 | ||
| 780 | +130726,蔚县,4,130700 | ||
| 781 | +130727,阳原县,4,130700 | ||
| 782 | +130728,怀安县,4,130700 | ||
| 783 | +130730,怀来县,4,130700 | ||
| 784 | +130731,涿鹿县,4,130700 | ||
| 785 | +130732,赤城县,4,130700 | ||
| 786 | +130771,张家口经济开发区,4,130700 | ||
| 787 | +130772,张家口市察北管理区,4,130700 | ||
| 788 | +130773,张家口市塞北管理区,4,130700 | ||
| 789 | +130802,双桥区,4,130800 | ||
| 790 | +130803,双滦区,4,130800 | ||
| 791 | +130804,鹰手营子矿区,4,130800 | ||
| 792 | +130821,承德县,4,130800 | ||
| 793 | +130822,兴隆县,4,130800 | ||
| 794 | +130824,滦平县,4,130800 | ||
| 795 | +130825,隆化县,4,130800 | ||
| 796 | +130826,丰宁满族自治县,4,130800 | ||
| 797 | +130827,宽城满族自治县,4,130800 | ||
| 798 | +130828,围场满族蒙古族自治县,4,130800 | ||
| 799 | +130871,承德高新技术产业开发区,4,130800 | ||
| 800 | +130881,平泉市,4,130800 | ||
| 801 | +130902,新华区,4,130900 | ||
| 802 | +130903,运河区,4,130900 | ||
| 803 | +130921,沧县,4,130900 | ||
| 804 | +130922,青县,4,130900 | ||
| 805 | +130923,东光县,4,130900 | ||
| 806 | +130924,海兴县,4,130900 | ||
| 807 | +130925,盐山县,4,130900 | ||
| 808 | +130926,肃宁县,4,130900 | ||
| 809 | +130927,南皮县,4,130900 | ||
| 810 | +130928,吴桥县,4,130900 | ||
| 811 | +130929,献县,4,130900 | ||
| 812 | +130930,孟村回族自治县,4,130900 | ||
| 813 | +130971,河北沧州经济开发区,4,130900 | ||
| 814 | +130972,沧州高新技术产业开发区,4,130900 | ||
| 815 | +130973,沧州渤海新区,4,130900 | ||
| 816 | +130981,泊头市,4,130900 | ||
| 817 | +130982,任丘市,4,130900 | ||
| 818 | +130983,黄骅市,4,130900 | ||
| 819 | +130984,河间市,4,130900 | ||
| 820 | +131002,安次区,4,131000 | ||
| 821 | +131003,广阳区,4,131000 | ||
| 822 | +131022,固安县,4,131000 | ||
| 823 | +131023,永清县,4,131000 | ||
| 824 | +131024,香河县,4,131000 | ||
| 825 | +131025,大城县,4,131000 | ||
| 826 | +131026,文安县,4,131000 | ||
| 827 | +131028,大厂回族自治县,4,131000 | ||
| 828 | +131071,廊坊经济技术开发区,4,131000 | ||
| 829 | +131081,霸州市,4,131000 | ||
| 830 | +131082,三河市,4,131000 | ||
| 831 | +131102,桃城区,4,131100 | ||
| 832 | +131103,冀州区,4,131100 | ||
| 833 | +131121,枣强县,4,131100 | ||
| 834 | +131122,武邑县,4,131100 | ||
| 835 | +131123,武强县,4,131100 | ||
| 836 | +131124,饶阳县,4,131100 | ||
| 837 | +131125,安平县,4,131100 | ||
| 838 | +131126,故城县,4,131100 | ||
| 839 | +131127,景县,4,131100 | ||
| 840 | +131128,阜城县,4,131100 | ||
| 841 | +131171,河北衡水高新技术产业开发区,4,131100 | ||
| 842 | +131172,衡水滨湖新区,4,131100 | ||
| 843 | +131182,深州市,4,131100 | ||
| 844 | +140105,小店区,4,140100 | ||
| 845 | +140106,迎泽区,4,140100 | ||
| 846 | +140107,杏花岭区,4,140100 | ||
| 847 | +140108,尖草坪区,4,140100 | ||
| 848 | +140109,万柏林区,4,140100 | ||
| 849 | +140110,晋源区,4,140100 | ||
| 850 | +140121,清徐县,4,140100 | ||
| 851 | +140122,阳曲县,4,140100 | ||
| 852 | +140123,娄烦县,4,140100 | ||
| 853 | +140171,山西转型综合改革示范区,4,140100 | ||
| 854 | +140181,古交市,4,140100 | ||
| 855 | +140212,新荣区,4,140200 | ||
| 856 | +140213,平城区,4,140200 | ||
| 857 | +140214,云冈区,4,140200 | ||
| 858 | +140215,云州区,4,140200 | ||
| 859 | +140221,阳高县,4,140200 | ||
| 860 | +140222,天镇县,4,140200 | ||
| 861 | +140223,广灵县,4,140200 | ||
| 862 | +140224,灵丘县,4,140200 | ||
| 863 | +140225,浑源县,4,140200 | ||
| 864 | +140226,左云县,4,140200 | ||
| 865 | +140271,山西大同经济开发区,4,140200 | ||
| 866 | +140302,城区,4,140300 | ||
| 867 | +140303,矿区,4,140300 | ||
| 868 | +140311,郊区,4,140300 | ||
| 869 | +140321,平定县,4,140300 | ||
| 870 | +140322,盂县,4,140300 | ||
| 871 | +140403,潞州区,4,140400 | ||
| 872 | +140404,上党区,4,140400 | ||
| 873 | +140405,屯留区,4,140400 | ||
| 874 | +140406,潞城区,4,140400 | ||
| 875 | +140423,襄垣县,4,140400 | ||
| 876 | +140425,平顺县,4,140400 | ||
| 877 | +140426,黎城县,4,140400 | ||
| 878 | +140427,壶关县,4,140400 | ||
| 879 | +140428,长子县,4,140400 | ||
| 880 | +140429,武乡县,4,140400 | ||
| 881 | +140430,沁县,4,140400 | ||
| 882 | +140431,沁源县,4,140400 | ||
| 883 | +140471,山西长治高新技术产业园区,4,140400 | ||
| 884 | +140502,城区,4,140500 | ||
| 885 | +140521,沁水县,4,140500 | ||
| 886 | +140522,阳城县,4,140500 | ||
| 887 | +140524,陵川县,4,140500 | ||
| 888 | +140525,泽州县,4,140500 | ||
| 889 | +140581,高平市,4,140500 | ||
| 890 | +140602,朔城区,4,140600 | ||
| 891 | +140603,平鲁区,4,140600 | ||
| 892 | +140621,山阴县,4,140600 | ||
| 893 | +140622,应县,4,140600 | ||
| 894 | +140623,右玉县,4,140600 | ||
| 895 | +140671,山西朔州经济开发区,4,140600 | ||
| 896 | +140681,怀仁市,4,140600 | ||
| 897 | +140702,榆次区,4,140700 | ||
| 898 | +140703,太谷区,4,140700 | ||
| 899 | +140721,榆社县,4,140700 | ||
| 900 | +140722,左权县,4,140700 | ||
| 901 | +140723,和顺县,4,140700 | ||
| 902 | +140724,昔阳县,4,140700 | ||
| 903 | +140725,寿阳县,4,140700 | ||
| 904 | +140727,祁县,4,140700 | ||
| 905 | +140728,平遥县,4,140700 | ||
| 906 | +140729,灵石县,4,140700 | ||
| 907 | +140781,介休市,4,140700 | ||
| 908 | +140802,盐湖区,4,140800 | ||
| 909 | +140821,临猗县,4,140800 | ||
| 910 | +140822,万荣县,4,140800 | ||
| 911 | +140823,闻喜县,4,140800 | ||
| 912 | +140824,稷山县,4,140800 | ||
| 913 | +140825,新绛县,4,140800 | ||
| 914 | +140826,绛县,4,140800 | ||
| 915 | +140827,垣曲县,4,140800 | ||
| 916 | +140828,夏县,4,140800 | ||
| 917 | +140829,平陆县,4,140800 | ||
| 918 | +140830,芮城县,4,140800 | ||
| 919 | +140881,永济市,4,140800 | ||
| 920 | +140882,河津市,4,140800 | ||
| 921 | +140902,忻府区,4,140900 | ||
| 922 | +140921,定襄县,4,140900 | ||
| 923 | +140922,五台县,4,140900 | ||
| 924 | +140923,代县,4,140900 | ||
| 925 | +140924,繁峙县,4,140900 | ||
| 926 | +140925,宁武县,4,140900 | ||
| 927 | +140926,静乐县,4,140900 | ||
| 928 | +140927,神池县,4,140900 | ||
| 929 | +140928,五寨县,4,140900 | ||
| 930 | +140929,岢岚县,4,140900 | ||
| 931 | +140930,河曲县,4,140900 | ||
| 932 | +140931,保德县,4,140900 | ||
| 933 | +140932,偏关县,4,140900 | ||
| 934 | +140971,五台山风景名胜区,4,140900 | ||
| 935 | +140981,原平市,4,140900 | ||
| 936 | +141002,尧都区,4,141000 | ||
| 937 | +141021,曲沃县,4,141000 | ||
| 938 | +141022,翼城县,4,141000 | ||
| 939 | +141023,襄汾县,4,141000 | ||
| 940 | +141024,洪洞县,4,141000 | ||
| 941 | +141025,古县,4,141000 | ||
| 942 | +141026,安泽县,4,141000 | ||
| 943 | +141027,浮山县,4,141000 | ||
| 944 | +141028,吉县,4,141000 | ||
| 945 | +141029,乡宁县,4,141000 | ||
| 946 | +141030,大宁县,4,141000 | ||
| 947 | +141031,隰县,4,141000 | ||
| 948 | +141032,永和县,4,141000 | ||
| 949 | +141033,蒲县,4,141000 | ||
| 950 | +141034,汾西县,4,141000 | ||
| 951 | +141081,侯马市,4,141000 | ||
| 952 | +141082,霍州市,4,141000 | ||
| 953 | +141102,离石区,4,141100 | ||
| 954 | +141121,文水县,4,141100 | ||
| 955 | +141122,交城县,4,141100 | ||
| 956 | +141123,兴县,4,141100 | ||
| 957 | +141124,临县,4,141100 | ||
| 958 | +141125,柳林县,4,141100 | ||
| 959 | +141126,石楼县,4,141100 | ||
| 960 | +141127,岚县,4,141100 | ||
| 961 | +141128,方山县,4,141100 | ||
| 962 | +141129,中阳县,4,141100 | ||
| 963 | +141130,交口县,4,141100 | ||
| 964 | +141181,孝义市,4,141100 | ||
| 965 | +141182,汾阳市,4,141100 | ||
| 966 | +150102,新城区,4,150100 | ||
| 967 | +150103,回民区,4,150100 | ||
| 968 | +150104,玉泉区,4,150100 | ||
| 969 | +150105,赛罕区,4,150100 | ||
| 970 | +150121,土默特左旗,4,150100 | ||
| 971 | +150122,托克托县,4,150100 | ||
| 972 | +150123,和林格尔县,4,150100 | ||
| 973 | +150124,清水河县,4,150100 | ||
| 974 | +150125,武川县,4,150100 | ||
| 975 | +150172,呼和浩特经济技术开发区,4,150100 | ||
| 976 | +150202,东河区,4,150200 | ||
| 977 | +150203,昆都仑区,4,150200 | ||
| 978 | +150204,青山区,4,150200 | ||
| 979 | +150205,石拐区,4,150200 | ||
| 980 | +150206,白云鄂博矿区,4,150200 | ||
| 981 | +150207,九原区,4,150200 | ||
| 982 | +150221,土默特右旗,4,150200 | ||
| 983 | +150222,固阳县,4,150200 | ||
| 984 | +150223,达尔罕茂明安联合旗,4,150200 | ||
| 985 | +150271,包头稀土高新技术产业开发区,4,150200 | ||
| 986 | +150302,海勃湾区,4,150300 | ||
| 987 | +150303,海南区,4,150300 | ||
| 988 | +150304,乌达区,4,150300 | ||
| 989 | +150402,红山区,4,150400 | ||
| 990 | +150403,元宝山区,4,150400 | ||
| 991 | +150404,松山区,4,150400 | ||
| 992 | +150421,阿鲁科尔沁旗,4,150400 | ||
| 993 | +150422,巴林左旗,4,150400 | ||
| 994 | +150423,巴林右旗,4,150400 | ||
| 995 | +150424,林西县,4,150400 | ||
| 996 | +150425,克什克腾旗,4,150400 | ||
| 997 | +150426,翁牛特旗,4,150400 | ||
| 998 | +150428,喀喇沁旗,4,150400 | ||
| 999 | +150429,宁城县,4,150400 | ||
| 1000 | +150430,敖汉旗,4,150400 | ||
| 1001 | +150502,科尔沁区,4,150500 | ||
| 1002 | +150521,科尔沁左翼中旗,4,150500 | ||
| 1003 | +150522,科尔沁左翼后旗,4,150500 | ||
| 1004 | +150523,开鲁县,4,150500 | ||
| 1005 | +150524,库伦旗,4,150500 | ||
| 1006 | +150525,奈曼旗,4,150500 | ||
| 1007 | +150526,扎鲁特旗,4,150500 | ||
| 1008 | +150571,通辽经济技术开发区,4,150500 | ||
| 1009 | +150581,霍林郭勒市,4,150500 | ||
| 1010 | +150602,东胜区,4,150600 | ||
| 1011 | +150603,康巴什区,4,150600 | ||
| 1012 | +150621,达拉特旗,4,150600 | ||
| 1013 | +150622,准格尔旗,4,150600 | ||
| 1014 | +150623,鄂托克前旗,4,150600 | ||
| 1015 | +150624,鄂托克旗,4,150600 | ||
| 1016 | +150625,杭锦旗,4,150600 | ||
| 1017 | +150626,乌审旗,4,150600 | ||
| 1018 | +150627,伊金霍洛旗,4,150600 | ||
| 1019 | +150702,海拉尔区,4,150700 | ||
| 1020 | +150703,扎赉诺尔区,4,150700 | ||
| 1021 | +150721,阿荣旗,4,150700 | ||
| 1022 | +150722,莫力达瓦达斡尔族自治旗,4,150700 | ||
| 1023 | +150723,鄂伦春自治旗,4,150700 | ||
| 1024 | +150724,鄂温克族自治旗,4,150700 | ||
| 1025 | +150725,陈巴尔虎旗,4,150700 | ||
| 1026 | +150726,新巴尔虎左旗,4,150700 | ||
| 1027 | +150727,新巴尔虎右旗,4,150700 | ||
| 1028 | +150781,满洲里市,4,150700 | ||
| 1029 | +150782,牙克石市,4,150700 | ||
| 1030 | +150783,扎兰屯市,4,150700 | ||
| 1031 | +150784,额尔古纳市,4,150700 | ||
| 1032 | +150785,根河市,4,150700 | ||
| 1033 | +150802,临河区,4,150800 | ||
| 1034 | +150821,五原县,4,150800 | ||
| 1035 | +150822,磴口县,4,150800 | ||
| 1036 | +150823,乌拉特前旗,4,150800 | ||
| 1037 | +150824,乌拉特中旗,4,150800 | ||
| 1038 | +150825,乌拉特后旗,4,150800 | ||
| 1039 | +150826,杭锦后旗,4,150800 | ||
| 1040 | +150902,集宁区,4,150900 | ||
| 1041 | +150921,卓资县,4,150900 | ||
| 1042 | +150922,化德县,4,150900 | ||
| 1043 | +150923,商都县,4,150900 | ||
| 1044 | +150924,兴和县,4,150900 | ||
| 1045 | +150925,凉城县,4,150900 | ||
| 1046 | +150926,察哈尔右翼前旗,4,150900 | ||
| 1047 | +150927,察哈尔右翼中旗,4,150900 | ||
| 1048 | +150928,察哈尔右翼后旗,4,150900 | ||
| 1049 | +150929,四子王旗,4,150900 | ||
| 1050 | +150981,丰镇市,4,150900 | ||
| 1051 | +152201,乌兰浩特市,4,152200 | ||
| 1052 | +152202,阿尔山市,4,152200 | ||
| 1053 | +152221,科尔沁右翼前旗,4,152200 | ||
| 1054 | +152222,科尔沁右翼中旗,4,152200 | ||
| 1055 | +152223,扎赉特旗,4,152200 | ||
| 1056 | +152224,突泉县,4,152200 | ||
| 1057 | +152501,二连浩特市,4,152500 | ||
| 1058 | +152502,锡林浩特市,4,152500 | ||
| 1059 | +152522,阿巴嘎旗,4,152500 | ||
| 1060 | +152523,苏尼特左旗,4,152500 | ||
| 1061 | +152524,苏尼特右旗,4,152500 | ||
| 1062 | +152525,东乌珠穆沁旗,4,152500 | ||
| 1063 | +152526,西乌珠穆沁旗,4,152500 | ||
| 1064 | +152527,太仆寺旗,4,152500 | ||
| 1065 | +152528,镶黄旗,4,152500 | ||
| 1066 | +152529,正镶白旗,4,152500 | ||
| 1067 | +152530,正蓝旗,4,152500 | ||
| 1068 | +152531,多伦县,4,152500 | ||
| 1069 | +152571,乌拉盖管委会,4,152500 | ||
| 1070 | +152921,阿拉善左旗,4,152900 | ||
| 1071 | +152922,阿拉善右旗,4,152900 | ||
| 1072 | +152923,额济纳旗,4,152900 | ||
| 1073 | +152971,内蒙古阿拉善高新技术产业开发区,4,152900 | ||
| 1074 | +210102,和平区,4,210100 | ||
| 1075 | +210103,沈河区,4,210100 | ||
| 1076 | +210104,大东区,4,210100 | ||
| 1077 | +210105,皇姑区,4,210100 | ||
| 1078 | +210106,铁西区,4,210100 | ||
| 1079 | +210111,苏家屯区,4,210100 | ||
| 1080 | +210112,浑南区,4,210100 | ||
| 1081 | +210113,沈北新区,4,210100 | ||
| 1082 | +210114,于洪区,4,210100 | ||
| 1083 | +210115,辽中区,4,210100 | ||
| 1084 | +210123,康平县,4,210100 | ||
| 1085 | +210124,法库县,4,210100 | ||
| 1086 | +210181,新民市,4,210100 | ||
| 1087 | +210202,中山区,4,210200 | ||
| 1088 | +210203,西岗区,4,210200 | ||
| 1089 | +210204,沙河口区,4,210200 | ||
| 1090 | +210211,甘井子区,4,210200 | ||
| 1091 | +210212,旅顺口区,4,210200 | ||
| 1092 | +210213,金州区,4,210200 | ||
| 1093 | +210214,普兰店区,4,210200 | ||
| 1094 | +210224,长海县,4,210200 | ||
| 1095 | +210281,瓦房店市,4,210200 | ||
| 1096 | +210283,庄河市,4,210200 | ||
| 1097 | +210302,铁东区,4,210300 | ||
| 1098 | +210303,铁西区,4,210300 | ||
| 1099 | +210304,立山区,4,210300 | ||
| 1100 | +210311,千山区,4,210300 | ||
| 1101 | +210321,台安县,4,210300 | ||
| 1102 | +210323,岫岩满族自治县,4,210300 | ||
| 1103 | +210381,海城市,4,210300 | ||
| 1104 | +210402,新抚区,4,210400 | ||
| 1105 | +210403,东洲区,4,210400 | ||
| 1106 | +210404,望花区,4,210400 | ||
| 1107 | +210411,顺城区,4,210400 | ||
| 1108 | +210421,抚顺县,4,210400 | ||
| 1109 | +210422,新宾满族自治县,4,210400 | ||
| 1110 | +210423,清原满族自治县,4,210400 | ||
| 1111 | +210502,平山区,4,210500 | ||
| 1112 | +210503,溪湖区,4,210500 | ||
| 1113 | +210504,明山区,4,210500 | ||
| 1114 | +210505,南芬区,4,210500 | ||
| 1115 | +210521,本溪满族自治县,4,210500 | ||
| 1116 | +210522,桓仁满族自治县,4,210500 | ||
| 1117 | +210602,元宝区,4,210600 | ||
| 1118 | +210603,振兴区,4,210600 | ||
| 1119 | +210604,振安区,4,210600 | ||
| 1120 | +210624,宽甸满族自治县,4,210600 | ||
| 1121 | +210681,东港市,4,210600 | ||
| 1122 | +210682,凤城市,4,210600 | ||
| 1123 | +210702,古塔区,4,210700 | ||
| 1124 | +210703,凌河区,4,210700 | ||
| 1125 | +210711,太和区,4,210700 | ||
| 1126 | +210726,黑山县,4,210700 | ||
| 1127 | +210727,义县,4,210700 | ||
| 1128 | +210781,凌海市,4,210700 | ||
| 1129 | +210782,北镇市,4,210700 | ||
| 1130 | +210802,站前区,4,210800 | ||
| 1131 | +210803,西市区,4,210800 | ||
| 1132 | +210804,鲅鱼圈区,4,210800 | ||
| 1133 | +210811,老边区,4,210800 | ||
| 1134 | +210881,盖州市,4,210800 | ||
| 1135 | +210882,大石桥市,4,210800 | ||
| 1136 | +210902,海州区,4,210900 | ||
| 1137 | +210903,新邱区,4,210900 | ||
| 1138 | +210904,太平区,4,210900 | ||
| 1139 | +210905,清河门区,4,210900 | ||
| 1140 | +210911,细河区,4,210900 | ||
| 1141 | +210921,阜新蒙古族自治县,4,210900 | ||
| 1142 | +210922,彰武县,4,210900 | ||
| 1143 | +211002,白塔区,4,211000 | ||
| 1144 | +211003,文圣区,4,211000 | ||
| 1145 | +211004,宏伟区,4,211000 | ||
| 1146 | +211005,弓长岭区,4,211000 | ||
| 1147 | +211011,太子河区,4,211000 | ||
| 1148 | +211021,辽阳县,4,211000 | ||
| 1149 | +211081,灯塔市,4,211000 | ||
| 1150 | +211102,双台子区,4,211100 | ||
| 1151 | +211103,兴隆台区,4,211100 | ||
| 1152 | +211104,大洼区,4,211100 | ||
| 1153 | +211122,盘山县,4,211100 | ||
| 1154 | +211202,银州区,4,211200 | ||
| 1155 | +211204,清河区,4,211200 | ||
| 1156 | +211221,铁岭县,4,211200 | ||
| 1157 | +211223,西丰县,4,211200 | ||
| 1158 | +211224,昌图县,4,211200 | ||
| 1159 | +211281,调兵山市,4,211200 | ||
| 1160 | +211282,开原市,4,211200 | ||
| 1161 | +211302,双塔区,4,211300 | ||
| 1162 | +211303,龙城区,4,211300 | ||
| 1163 | +211321,朝阳县,4,211300 | ||
| 1164 | +211322,建平县,4,211300 | ||
| 1165 | +211324,喀喇沁左翼蒙古族自治县,4,211300 | ||
| 1166 | +211381,北票市,4,211300 | ||
| 1167 | +211382,凌源市,4,211300 | ||
| 1168 | +211402,连山区,4,211400 | ||
| 1169 | +211403,龙港区,4,211400 | ||
| 1170 | +211404,南票区,4,211400 | ||
| 1171 | +211421,绥中县,4,211400 | ||
| 1172 | +211422,建昌县,4,211400 | ||
| 1173 | +211481,兴城市,4,211400 | ||
| 1174 | +220102,南关区,4,220100 | ||
| 1175 | +220103,宽城区,4,220100 | ||
| 1176 | +220104,朝阳区,4,220100 | ||
| 1177 | +220105,二道区,4,220100 | ||
| 1178 | +220106,绿园区,4,220100 | ||
| 1179 | +220112,双阳区,4,220100 | ||
| 1180 | +220113,九台区,4,220100 | ||
| 1181 | +220122,农安县,4,220100 | ||
| 1182 | +220171,长春经济技术开发区,4,220100 | ||
| 1183 | +220172,长春净月高新技术产业开发区,4,220100 | ||
| 1184 | +220173,长春高新技术产业开发区,4,220100 | ||
| 1185 | +220174,长春汽车经济技术开发区,4,220100 | ||
| 1186 | +220182,榆树市,4,220100 | ||
| 1187 | +220183,德惠市,4,220100 | ||
| 1188 | +220184,公主岭市,4,220100 | ||
| 1189 | +220202,昌邑区,4,220200 | ||
| 1190 | +220203,龙潭区,4,220200 | ||
| 1191 | +220204,船营区,4,220200 | ||
| 1192 | +220211,丰满区,4,220200 | ||
| 1193 | +220221,永吉县,4,220200 | ||
| 1194 | +220271,吉林经济开发区,4,220200 | ||
| 1195 | +220272,吉林高新技术产业开发区,4,220200 | ||
| 1196 | +220273,吉林中国新加坡食品区,4,220200 | ||
| 1197 | +220281,蛟河市,4,220200 | ||
| 1198 | +220282,桦甸市,4,220200 | ||
| 1199 | +220283,舒兰市,4,220200 | ||
| 1200 | +220284,磐石市,4,220200 | ||
| 1201 | +220302,铁西区,4,220300 | ||
| 1202 | +220303,铁东区,4,220300 | ||
| 1203 | +220322,梨树县,4,220300 | ||
| 1204 | +220323,伊通满族自治县,4,220300 | ||
| 1205 | +220382,双辽市,4,220300 | ||
| 1206 | +220402,龙山区,4,220400 | ||
| 1207 | +220403,西安区,4,220400 | ||
| 1208 | +220421,东丰县,4,220400 | ||
| 1209 | +220422,东辽县,4,220400 | ||
| 1210 | +220502,东昌区,4,220500 | ||
| 1211 | +220503,二道江区,4,220500 | ||
| 1212 | +220521,通化县,4,220500 | ||
| 1213 | +220523,辉南县,4,220500 | ||
| 1214 | +220524,柳河县,4,220500 | ||
| 1215 | +220581,梅河口市,4,220500 | ||
| 1216 | +220582,集安市,4,220500 | ||
| 1217 | +220602,浑江区,4,220600 | ||
| 1218 | +220605,江源区,4,220600 | ||
| 1219 | +220621,抚松县,4,220600 | ||
| 1220 | +220622,靖宇县,4,220600 | ||
| 1221 | +220623,长白朝鲜族自治县,4,220600 | ||
| 1222 | +220681,临江市,4,220600 | ||
| 1223 | +220702,宁江区,4,220700 | ||
| 1224 | +220721,前郭尔罗斯蒙古族自治县,4,220700 | ||
| 1225 | +220722,长岭县,4,220700 | ||
| 1226 | +220723,乾安县,4,220700 | ||
| 1227 | +220771,吉林松原经济开发区,4,220700 | ||
| 1228 | +220781,扶余市,4,220700 | ||
| 1229 | +220802,洮北区,4,220800 | ||
| 1230 | +220821,镇赉县,4,220800 | ||
| 1231 | +220822,通榆县,4,220800 | ||
| 1232 | +220871,吉林白城经济开发区,4,220800 | ||
| 1233 | +220881,洮南市,4,220800 | ||
| 1234 | +220882,大安市,4,220800 | ||
| 1235 | +222401,延吉市,4,222400 | ||
| 1236 | +222402,图们市,4,222400 | ||
| 1237 | +222403,敦化市,4,222400 | ||
| 1238 | +222404,珲春市,4,222400 | ||
| 1239 | +222405,龙井市,4,222400 | ||
| 1240 | +222406,和龙市,4,222400 | ||
| 1241 | +222424,汪清县,4,222400 | ||
| 1242 | +222426,安图县,4,222400 | ||
| 1243 | +230102,道里区,4,230100 | ||
| 1244 | +230103,南岗区,4,230100 | ||
| 1245 | +230104,道外区,4,230100 | ||
| 1246 | +230108,平房区,4,230100 | ||
| 1247 | +230109,松北区,4,230100 | ||
| 1248 | +230110,香坊区,4,230100 | ||
| 1249 | +230111,呼兰区,4,230100 | ||
| 1250 | +230112,阿城区,4,230100 | ||
| 1251 | +230113,双城区,4,230100 | ||
| 1252 | +230123,依兰县,4,230100 | ||
| 1253 | +230124,方正县,4,230100 | ||
| 1254 | +230125,宾县,4,230100 | ||
| 1255 | +230126,巴彦县,4,230100 | ||
| 1256 | +230127,木兰县,4,230100 | ||
| 1257 | +230128,通河县,4,230100 | ||
| 1258 | +230129,延寿县,4,230100 | ||
| 1259 | +230183,尚志市,4,230100 | ||
| 1260 | +230184,五常市,4,230100 | ||
| 1261 | +230202,龙沙区,4,230200 | ||
| 1262 | +230203,建华区,4,230200 | ||
| 1263 | +230204,铁锋区,4,230200 | ||
| 1264 | +230205,昂昂溪区,4,230200 | ||
| 1265 | +230206,富拉尔基区,4,230200 | ||
| 1266 | +230207,碾子山区,4,230200 | ||
| 1267 | +230208,梅里斯达斡尔族区,4,230200 | ||
| 1268 | +230221,龙江县,4,230200 | ||
| 1269 | +230223,依安县,4,230200 | ||
| 1270 | +230224,泰来县,4,230200 | ||
| 1271 | +230225,甘南县,4,230200 | ||
| 1272 | +230227,富裕县,4,230200 | ||
| 1273 | +230229,克山县,4,230200 | ||
| 1274 | +230230,克东县,4,230200 | ||
| 1275 | +230231,拜泉县,4,230200 | ||
| 1276 | +230281,讷河市,4,230200 | ||
| 1277 | +230302,鸡冠区,4,230300 | ||
| 1278 | +230303,恒山区,4,230300 | ||
| 1279 | +230304,滴道区,4,230300 | ||
| 1280 | +230305,梨树区,4,230300 | ||
| 1281 | +230306,城子河区,4,230300 | ||
| 1282 | +230307,麻山区,4,230300 | ||
| 1283 | +230321,鸡东县,4,230300 | ||
| 1284 | +230381,虎林市,4,230300 | ||
| 1285 | +230382,密山市,4,230300 | ||
| 1286 | +230402,向阳区,4,230400 | ||
| 1287 | +230403,工农区,4,230400 | ||
| 1288 | +230404,南山区,4,230400 | ||
| 1289 | +230405,兴安区,4,230400 | ||
| 1290 | +230406,东山区,4,230400 | ||
| 1291 | +230407,兴山区,4,230400 | ||
| 1292 | +230421,萝北县,4,230400 | ||
| 1293 | +230422,绥滨县,4,230400 | ||
| 1294 | +230502,尖山区,4,230500 | ||
| 1295 | +230503,岭东区,4,230500 | ||
| 1296 | +230505,四方台区,4,230500 | ||
| 1297 | +230506,宝山区,4,230500 | ||
| 1298 | +230521,集贤县,4,230500 | ||
| 1299 | +230522,友谊县,4,230500 | ||
| 1300 | +230523,宝清县,4,230500 | ||
| 1301 | +230524,饶河县,4,230500 | ||
| 1302 | +230602,萨尔图区,4,230600 | ||
| 1303 | +230603,龙凤区,4,230600 | ||
| 1304 | +230604,让胡路区,4,230600 | ||
| 1305 | +230605,红岗区,4,230600 | ||
| 1306 | +230606,大同区,4,230600 | ||
| 1307 | +230621,肇州县,4,230600 | ||
| 1308 | +230622,肇源县,4,230600 | ||
| 1309 | +230623,林甸县,4,230600 | ||
| 1310 | +230624,杜尔伯特蒙古族自治县,4,230600 | ||
| 1311 | +230671,大庆高新技术产业开发区,4,230600 | ||
| 1312 | +230717,伊美区,4,230700 | ||
| 1313 | +230718,乌翠区,4,230700 | ||
| 1314 | +230719,友好区,4,230700 | ||
| 1315 | +230722,嘉荫县,4,230700 | ||
| 1316 | +230723,汤旺县,4,230700 | ||
| 1317 | +230724,丰林县,4,230700 | ||
| 1318 | +230725,大箐山县,4,230700 | ||
| 1319 | +230726,南岔县,4,230700 | ||
| 1320 | +230751,金林区,4,230700 | ||
| 1321 | +230781,铁力市,4,230700 | ||
| 1322 | +230803,向阳区,4,230800 | ||
| 1323 | +230804,前进区,4,230800 | ||
| 1324 | +230805,东风区,4,230800 | ||
| 1325 | +230811,郊区,4,230800 | ||
| 1326 | +230822,桦南县,4,230800 | ||
| 1327 | +230826,桦川县,4,230800 | ||
| 1328 | +230828,汤原县,4,230800 | ||
| 1329 | +230881,同江市,4,230800 | ||
| 1330 | +230882,富锦市,4,230800 | ||
| 1331 | +230883,抚远市,4,230800 | ||
| 1332 | +230902,新兴区,4,230900 | ||
| 1333 | +230903,桃山区,4,230900 | ||
| 1334 | +230904,茄子河区,4,230900 | ||
| 1335 | +230921,勃利县,4,230900 | ||
| 1336 | +231002,东安区,4,231000 | ||
| 1337 | +231003,阳明区,4,231000 | ||
| 1338 | +231004,爱民区,4,231000 | ||
| 1339 | +231005,西安区,4,231000 | ||
| 1340 | +231025,林口县,4,231000 | ||
| 1341 | +231071,牡丹江经济技术开发区,4,231000 | ||
| 1342 | +231081,绥芬河市,4,231000 | ||
| 1343 | +231083,海林市,4,231000 | ||
| 1344 | +231084,宁安市,4,231000 | ||
| 1345 | +231085,穆棱市,4,231000 | ||
| 1346 | +231086,东宁市,4,231000 | ||
| 1347 | +231102,爱辉区,4,231100 | ||
| 1348 | +231123,逊克县,4,231100 | ||
| 1349 | +231124,孙吴县,4,231100 | ||
| 1350 | +231181,北安市,4,231100 | ||
| 1351 | +231182,五大连池市,4,231100 | ||
| 1352 | +231183,嫩江市,4,231100 | ||
| 1353 | +231202,北林区,4,231200 | ||
| 1354 | +231221,望奎县,4,231200 | ||
| 1355 | +231222,兰西县,4,231200 | ||
| 1356 | +231223,青冈县,4,231200 | ||
| 1357 | +231224,庆安县,4,231200 | ||
| 1358 | +231225,明水县,4,231200 | ||
| 1359 | +231226,绥棱县,4,231200 | ||
| 1360 | +231281,安达市,4,231200 | ||
| 1361 | +231282,肇东市,4,231200 | ||
| 1362 | +231283,海伦市,4,231200 | ||
| 1363 | +232701,漠河市,4,232700 | ||
| 1364 | +232721,呼玛县,4,232700 | ||
| 1365 | +232722,塔河县,4,232700 | ||
| 1366 | +232761,加格达奇区,4,232700 | ||
| 1367 | +232762,松岭区,4,232700 | ||
| 1368 | +232763,新林区,4,232700 | ||
| 1369 | +232764,呼中区,4,232700 | ||
| 1370 | +310101,黄浦区,4,310100 | ||
| 1371 | +310104,徐汇区,4,310100 | ||
| 1372 | +310105,长宁区,4,310100 | ||
| 1373 | +310106,静安区,4,310100 | ||
| 1374 | +310107,普陀区,4,310100 | ||
| 1375 | +310109,虹口区,4,310100 | ||
| 1376 | +310110,杨浦区,4,310100 | ||
| 1377 | +310112,闵行区,4,310100 | ||
| 1378 | +310113,宝山区,4,310100 | ||
| 1379 | +310114,嘉定区,4,310100 | ||
| 1380 | +310115,浦东新区,4,310100 | ||
| 1381 | +310116,金山区,4,310100 | ||
| 1382 | +310117,松江区,4,310100 | ||
| 1383 | +310118,青浦区,4,310100 | ||
| 1384 | +310120,奉贤区,4,310100 | ||
| 1385 | +310151,崇明区,4,310100 | ||
| 1386 | +320102,玄武区,4,320100 | ||
| 1387 | +320104,秦淮区,4,320100 | ||
| 1388 | +320105,建邺区,4,320100 | ||
| 1389 | +320106,鼓楼区,4,320100 | ||
| 1390 | +320111,浦口区,4,320100 | ||
| 1391 | +320113,栖霞区,4,320100 | ||
| 1392 | +320114,雨花台区,4,320100 | ||
| 1393 | +320115,江宁区,4,320100 | ||
| 1394 | +320116,六合区,4,320100 | ||
| 1395 | +320117,溧水区,4,320100 | ||
| 1396 | +320118,高淳区,4,320100 | ||
| 1397 | +320205,锡山区,4,320200 | ||
| 1398 | +320206,惠山区,4,320200 | ||
| 1399 | +320211,滨湖区,4,320200 | ||
| 1400 | +320213,梁溪区,4,320200 | ||
| 1401 | +320214,新吴区,4,320200 | ||
| 1402 | +320281,江阴市,4,320200 | ||
| 1403 | +320282,宜兴市,4,320200 | ||
| 1404 | +320302,鼓楼区,4,320300 | ||
| 1405 | +320303,云龙区,4,320300 | ||
| 1406 | +320305,贾汪区,4,320300 | ||
| 1407 | +320311,泉山区,4,320300 | ||
| 1408 | +320312,铜山区,4,320300 | ||
| 1409 | +320321,丰县,4,320300 | ||
| 1410 | +320322,沛县,4,320300 | ||
| 1411 | +320324,睢宁县,4,320300 | ||
| 1412 | +320371,徐州经济技术开发区,4,320300 | ||
| 1413 | +320381,新沂市,4,320300 | ||
| 1414 | +320382,邳州市,4,320300 | ||
| 1415 | +320402,天宁区,4,320400 | ||
| 1416 | +320404,钟楼区,4,320400 | ||
| 1417 | +320411,新北区,4,320400 | ||
| 1418 | +320412,武进区,4,320400 | ||
| 1419 | +320413,金坛区,4,320400 | ||
| 1420 | +320481,溧阳市,4,320400 | ||
| 1421 | +320505,虎丘区,4,320500 | ||
| 1422 | +320506,吴中区,4,320500 | ||
| 1423 | +320507,相城区,4,320500 | ||
| 1424 | +320508,姑苏区,4,320500 | ||
| 1425 | +320509,吴江区,4,320500 | ||
| 1426 | +320571,苏州工业园区,4,320500 | ||
| 1427 | +320581,常熟市,4,320500 | ||
| 1428 | +320582,张家港市,4,320500 | ||
| 1429 | +320583,昆山市,4,320500 | ||
| 1430 | +320585,太仓市,4,320500 | ||
| 1431 | +320612,通州区,4,320600 | ||
| 1432 | +320613,崇川区,4,320600 | ||
| 1433 | +320614,海门区,4,320600 | ||
| 1434 | +320623,如东县,4,320600 | ||
| 1435 | +320671,南通经济技术开发区,4,320600 | ||
| 1436 | +320681,启东市,4,320600 | ||
| 1437 | +320682,如皋市,4,320600 | ||
| 1438 | +320685,海安市,4,320600 | ||
| 1439 | +320703,连云区,4,320700 | ||
| 1440 | +320706,海州区,4,320700 | ||
| 1441 | +320707,赣榆区,4,320700 | ||
| 1442 | +320722,东海县,4,320700 | ||
| 1443 | +320723,灌云县,4,320700 | ||
| 1444 | +320724,灌南县,4,320700 | ||
| 1445 | +320771,连云港经济技术开发区,4,320700 | ||
| 1446 | +320772,连云港高新技术产业开发区,4,320700 | ||
| 1447 | +320803,淮安区,4,320800 | ||
| 1448 | +320804,淮阴区,4,320800 | ||
| 1449 | +320812,清江浦区,4,320800 | ||
| 1450 | +320813,洪泽区,4,320800 | ||
| 1451 | +320826,涟水县,4,320800 | ||
| 1452 | +320830,盱眙县,4,320800 | ||
| 1453 | +320831,金湖县,4,320800 | ||
| 1454 | +320871,淮安经济技术开发区,4,320800 | ||
| 1455 | +320902,亭湖区,4,320900 | ||
| 1456 | +320903,盐都区,4,320900 | ||
| 1457 | +320904,大丰区,4,320900 | ||
| 1458 | +320921,响水县,4,320900 | ||
| 1459 | +320922,滨海县,4,320900 | ||
| 1460 | +320923,阜宁县,4,320900 | ||
| 1461 | +320924,射阳县,4,320900 | ||
| 1462 | +320925,建湖县,4,320900 | ||
| 1463 | +320971,盐城经济技术开发区,4,320900 | ||
| 1464 | +320981,东台市,4,320900 | ||
| 1465 | +321002,广陵区,4,321000 | ||
| 1466 | +321003,邗江区,4,321000 | ||
| 1467 | +321012,江都区,4,321000 | ||
| 1468 | +321023,宝应县,4,321000 | ||
| 1469 | +321071,扬州经济技术开发区,4,321000 | ||
| 1470 | +321081,仪征市,4,321000 | ||
| 1471 | +321084,高邮市,4,321000 | ||
| 1472 | +321102,京口区,4,321100 | ||
| 1473 | +321111,润州区,4,321100 | ||
| 1474 | +321112,丹徒区,4,321100 | ||
| 1475 | +321171,镇江新区,4,321100 | ||
| 1476 | +321181,丹阳市,4,321100 | ||
| 1477 | +321182,扬中市,4,321100 | ||
| 1478 | +321183,句容市,4,321100 | ||
| 1479 | +321202,海陵区,4,321200 | ||
| 1480 | +321203,高港区,4,321200 | ||
| 1481 | +321204,姜堰区,4,321200 | ||
| 1482 | +321271,泰州医药高新技术产业开发区,4,321200 | ||
| 1483 | +321281,兴化市,4,321200 | ||
| 1484 | +321282,靖江市,4,321200 | ||
| 1485 | +321283,泰兴市,4,321200 | ||
| 1486 | +321302,宿城区,4,321300 | ||
| 1487 | +321311,宿豫区,4,321300 | ||
| 1488 | +321322,沭阳县,4,321300 | ||
| 1489 | +321323,泗阳县,4,321300 | ||
| 1490 | +321324,泗洪县,4,321300 | ||
| 1491 | +321371,宿迁经济技术开发区,4,321300 | ||
| 1492 | +330102,上城区,4,330100 | ||
| 1493 | +330105,拱墅区,4,330100 | ||
| 1494 | +330106,西湖区,4,330100 | ||
| 1495 | +330108,滨江区,4,330100 | ||
| 1496 | +330109,萧山区,4,330100 | ||
| 1497 | +330110,余杭区,4,330100 | ||
| 1498 | +330111,富阳区,4,330100 | ||
| 1499 | +330112,临安区,4,330100 | ||
| 1500 | +330113,临平区,4,330100 | ||
| 1501 | +330114,钱塘区,4,330100 | ||
| 1502 | +330122,桐庐县,4,330100 | ||
| 1503 | +330127,淳安县,4,330100 | ||
| 1504 | +330182,建德市,4,330100 | ||
| 1505 | +330203,海曙区,4,330200 | ||
| 1506 | +330205,江北区,4,330200 | ||
| 1507 | +330206,北仑区,4,330200 | ||
| 1508 | +330211,镇海区,4,330200 | ||
| 1509 | +330212,鄞州区,4,330200 | ||
| 1510 | +330213,奉化区,4,330200 | ||
| 1511 | +330225,象山县,4,330200 | ||
| 1512 | +330226,宁海县,4,330200 | ||
| 1513 | +330281,余姚市,4,330200 | ||
| 1514 | +330282,慈溪市,4,330200 | ||
| 1515 | +330302,鹿城区,4,330300 | ||
| 1516 | +330303,龙湾区,4,330300 | ||
| 1517 | +330304,瓯海区,4,330300 | ||
| 1518 | +330305,洞头区,4,330300 | ||
| 1519 | +330324,永嘉县,4,330300 | ||
| 1520 | +330326,平阳县,4,330300 | ||
| 1521 | +330327,苍南县,4,330300 | ||
| 1522 | +330328,文成县,4,330300 | ||
| 1523 | +330329,泰顺县,4,330300 | ||
| 1524 | +330371,温州经济技术开发区,4,330300 | ||
| 1525 | +330381,瑞安市,4,330300 | ||
| 1526 | +330382,乐清市,4,330300 | ||
| 1527 | +330383,龙港市,4,330300 | ||
| 1528 | +330402,南湖区,4,330400 | ||
| 1529 | +330411,秀洲区,4,330400 | ||
| 1530 | +330421,嘉善县,4,330400 | ||
| 1531 | +330424,海盐县,4,330400 | ||
| 1532 | +330481,海宁市,4,330400 | ||
| 1533 | +330482,平湖市,4,330400 | ||
| 1534 | +330483,桐乡市,4,330400 | ||
| 1535 | +330502,吴兴区,4,330500 | ||
| 1536 | +330503,南浔区,4,330500 | ||
| 1537 | +330521,德清县,4,330500 | ||
| 1538 | +330522,长兴县,4,330500 | ||
| 1539 | +330523,安吉县,4,330500 | ||
| 1540 | +330602,越城区,4,330600 | ||
| 1541 | +330603,柯桥区,4,330600 | ||
| 1542 | +330604,上虞区,4,330600 | ||
| 1543 | +330624,新昌县,4,330600 | ||
| 1544 | +330681,诸暨市,4,330600 | ||
| 1545 | +330683,嵊州市,4,330600 | ||
| 1546 | +330702,婺城区,4,330700 | ||
| 1547 | +330703,金东区,4,330700 | ||
| 1548 | +330723,武义县,4,330700 | ||
| 1549 | +330726,浦江县,4,330700 | ||
| 1550 | +330727,磐安县,4,330700 | ||
| 1551 | +330781,兰溪市,4,330700 | ||
| 1552 | +330782,义乌市,4,330700 | ||
| 1553 | +330783,东阳市,4,330700 | ||
| 1554 | +330784,永康市,4,330700 | ||
| 1555 | +330802,柯城区,4,330800 | ||
| 1556 | +330803,衢江区,4,330800 | ||
| 1557 | +330822,常山县,4,330800 | ||
| 1558 | +330824,开化县,4,330800 | ||
| 1559 | +330825,龙游县,4,330800 | ||
| 1560 | +330881,江山市,4,330800 | ||
| 1561 | +330902,定海区,4,330900 | ||
| 1562 | +330903,普陀区,4,330900 | ||
| 1563 | +330921,岱山县,4,330900 | ||
| 1564 | +330922,嵊泗县,4,330900 | ||
| 1565 | +331002,椒江区,4,331000 | ||
| 1566 | +331003,黄岩区,4,331000 | ||
| 1567 | +331004,路桥区,4,331000 | ||
| 1568 | +331022,三门县,4,331000 | ||
| 1569 | +331023,天台县,4,331000 | ||
| 1570 | +331024,仙居县,4,331000 | ||
| 1571 | +331081,温岭市,4,331000 | ||
| 1572 | +331082,临海市,4,331000 | ||
| 1573 | +331083,玉环市,4,331000 | ||
| 1574 | +331102,莲都区,4,331100 | ||
| 1575 | +331121,青田县,4,331100 | ||
| 1576 | +331122,缙云县,4,331100 | ||
| 1577 | +331123,遂昌县,4,331100 | ||
| 1578 | +331124,松阳县,4,331100 | ||
| 1579 | +331125,云和县,4,331100 | ||
| 1580 | +331126,庆元县,4,331100 | ||
| 1581 | +331127,景宁畲族自治县,4,331100 | ||
| 1582 | +331181,龙泉市,4,331100 | ||
| 1583 | +340102,瑶海区,4,340100 | ||
| 1584 | +340103,庐阳区,4,340100 | ||
| 1585 | +340104,蜀山区,4,340100 | ||
| 1586 | +340111,包河区,4,340100 | ||
| 1587 | +340121,长丰县,4,340100 | ||
| 1588 | +340122,肥东县,4,340100 | ||
| 1589 | +340123,肥西县,4,340100 | ||
| 1590 | +340124,庐江县,4,340100 | ||
| 1591 | +340171,合肥高新技术产业开发区,4,340100 | ||
| 1592 | +340172,合肥经济技术开发区,4,340100 | ||
| 1593 | +340173,合肥新站高新技术产业开发区,4,340100 | ||
| 1594 | +340181,巢湖市,4,340100 | ||
| 1595 | +340202,镜湖区,4,340200 | ||
| 1596 | +340207,鸠江区,4,340200 | ||
| 1597 | +340209,弋江区,4,340200 | ||
| 1598 | +340210,湾沚区,4,340200 | ||
| 1599 | +340212,繁昌区,4,340200 | ||
| 1600 | +340223,南陵县,4,340200 | ||
| 1601 | +340271,芜湖经济技术开发区,4,340200 | ||
| 1602 | +340272,安徽芜湖三山经济开发区,4,340200 | ||
| 1603 | +340281,无为市,4,340200 | ||
| 1604 | +340302,龙子湖区,4,340300 | ||
| 1605 | +340303,蚌山区,4,340300 | ||
| 1606 | +340304,禹会区,4,340300 | ||
| 1607 | +340311,淮上区,4,340300 | ||
| 1608 | +340321,怀远县,4,340300 | ||
| 1609 | +340322,五河县,4,340300 | ||
| 1610 | +340323,固镇县,4,340300 | ||
| 1611 | +340371,蚌埠市高新技术开发区,4,340300 | ||
| 1612 | +340372,蚌埠市经济开发区,4,340300 | ||
| 1613 | +340402,大通区,4,340400 | ||
| 1614 | +340403,田家庵区,4,340400 | ||
| 1615 | +340404,谢家集区,4,340400 | ||
| 1616 | +340405,八公山区,4,340400 | ||
| 1617 | +340406,潘集区,4,340400 | ||
| 1618 | +340421,凤台县,4,340400 | ||
| 1619 | +340422,寿县,4,340400 | ||
| 1620 | +340503,花山区,4,340500 | ||
| 1621 | +340504,雨山区,4,340500 | ||
| 1622 | +340506,博望区,4,340500 | ||
| 1623 | +340521,当涂县,4,340500 | ||
| 1624 | +340522,含山县,4,340500 | ||
| 1625 | +340523,和县,4,340500 | ||
| 1626 | +340602,杜集区,4,340600 | ||
| 1627 | +340603,相山区,4,340600 | ||
| 1628 | +340604,烈山区,4,340600 | ||
| 1629 | +340621,濉溪县,4,340600 | ||
| 1630 | +340705,铜官区,4,340700 | ||
| 1631 | +340706,义安区,4,340700 | ||
| 1632 | +340711,郊区,4,340700 | ||
| 1633 | +340722,枞阳县,4,340700 | ||
| 1634 | +340802,迎江区,4,340800 | ||
| 1635 | +340803,大观区,4,340800 | ||
| 1636 | +340811,宜秀区,4,340800 | ||
| 1637 | +340822,怀宁县,4,340800 | ||
| 1638 | +340825,太湖县,4,340800 | ||
| 1639 | +340826,宿松县,4,340800 | ||
| 1640 | +340827,望江县,4,340800 | ||
| 1641 | +340828,岳西县,4,340800 | ||
| 1642 | +340871,安徽安庆经济开发区,4,340800 | ||
| 1643 | +340881,桐城市,4,340800 | ||
| 1644 | +340882,潜山市,4,340800 | ||
| 1645 | +341002,屯溪区,4,341000 | ||
| 1646 | +341003,黄山区,4,341000 | ||
| 1647 | +341004,徽州区,4,341000 | ||
| 1648 | +341021,歙县,4,341000 | ||
| 1649 | +341022,休宁县,4,341000 | ||
| 1650 | +341023,黟县,4,341000 | ||
| 1651 | +341024,祁门县,4,341000 | ||
| 1652 | +341102,琅琊区,4,341100 | ||
| 1653 | +341103,南谯区,4,341100 | ||
| 1654 | +341122,来安县,4,341100 | ||
| 1655 | +341124,全椒县,4,341100 | ||
| 1656 | +341125,定远县,4,341100 | ||
| 1657 | +341126,凤阳县,4,341100 | ||
| 1658 | +341171,中新苏滁高新技术产业开发区,4,341100 | ||
| 1659 | +341172,滁州经济技术开发区,4,341100 | ||
| 1660 | +341181,天长市,4,341100 | ||
| 1661 | +341182,明光市,4,341100 | ||
| 1662 | +341202,颍州区,4,341200 | ||
| 1663 | +341203,颍东区,4,341200 | ||
| 1664 | +341204,颍泉区,4,341200 | ||
| 1665 | +341221,临泉县,4,341200 | ||
| 1666 | +341222,太和县,4,341200 | ||
| 1667 | +341225,阜南县,4,341200 | ||
| 1668 | +341226,颍上县,4,341200 | ||
| 1669 | +341271,阜阳合肥现代产业园区,4,341200 | ||
| 1670 | +341272,阜阳经济技术开发区,4,341200 | ||
| 1671 | +341282,界首市,4,341200 | ||
| 1672 | +341302,埇桥区,4,341300 | ||
| 1673 | +341321,砀山县,4,341300 | ||
| 1674 | +341322,萧县,4,341300 | ||
| 1675 | +341323,灵璧县,4,341300 | ||
| 1676 | +341324,泗县,4,341300 | ||
| 1677 | +341371,宿州马鞍山现代产业园区,4,341300 | ||
| 1678 | +341372,宿州经济技术开发区,4,341300 | ||
| 1679 | +341502,金安区,4,341500 | ||
| 1680 | +341503,裕安区,4,341500 | ||
| 1681 | +341504,叶集区,4,341500 | ||
| 1682 | +341522,霍邱县,4,341500 | ||
| 1683 | +341523,舒城县,4,341500 | ||
| 1684 | +341524,金寨县,4,341500 | ||
| 1685 | +341525,霍山县,4,341500 | ||
| 1686 | +341602,谯城区,4,341600 | ||
| 1687 | +341621,涡阳县,4,341600 | ||
| 1688 | +341622,蒙城县,4,341600 | ||
| 1689 | +341623,利辛县,4,341600 | ||
| 1690 | +341702,贵池区,4,341700 | ||
| 1691 | +341721,东至县,4,341700 | ||
| 1692 | +341722,石台县,4,341700 | ||
| 1693 | +341723,青阳县,4,341700 | ||
| 1694 | +341802,宣州区,4,341800 | ||
| 1695 | +341821,郎溪县,4,341800 | ||
| 1696 | +341823,泾县,4,341800 | ||
| 1697 | +341824,绩溪县,4,341800 | ||
| 1698 | +341825,旌德县,4,341800 | ||
| 1699 | +341871,宣城市经济开发区,4,341800 | ||
| 1700 | +341881,宁国市,4,341800 | ||
| 1701 | +341882,广德市,4,341800 | ||
| 1702 | +350102,鼓楼区,4,350100 | ||
| 1703 | +350103,台江区,4,350100 | ||
| 1704 | +350104,仓山区,4,350100 | ||
| 1705 | +350105,马尾区,4,350100 | ||
| 1706 | +350111,晋安区,4,350100 | ||
| 1707 | +350112,长乐区,4,350100 | ||
| 1708 | +350121,闽侯县,4,350100 | ||
| 1709 | +350122,连江县,4,350100 | ||
| 1710 | +350123,罗源县,4,350100 | ||
| 1711 | +350124,闽清县,4,350100 | ||
| 1712 | +350125,永泰县,4,350100 | ||
| 1713 | +350128,平潭县,4,350100 | ||
| 1714 | +350181,福清市,4,350100 | ||
| 1715 | +350203,思明区,4,350200 | ||
| 1716 | +350205,海沧区,4,350200 | ||
| 1717 | +350206,湖里区,4,350200 | ||
| 1718 | +350211,集美区,4,350200 | ||
| 1719 | +350212,同安区,4,350200 | ||
| 1720 | +350213,翔安区,4,350200 | ||
| 1721 | +350302,城厢区,4,350300 | ||
| 1722 | +350303,涵江区,4,350300 | ||
| 1723 | +350304,荔城区,4,350300 | ||
| 1724 | +350305,秀屿区,4,350300 | ||
| 1725 | +350322,仙游县,4,350300 | ||
| 1726 | +350404,三元区,4,350400 | ||
| 1727 | +350405,沙县区,4,350400 | ||
| 1728 | +350421,明溪县,4,350400 | ||
| 1729 | +350423,清流县,4,350400 | ||
| 1730 | +350424,宁化县,4,350400 | ||
| 1731 | +350425,大田县,4,350400 | ||
| 1732 | +350426,尤溪县,4,350400 | ||
| 1733 | +350428,将乐县,4,350400 | ||
| 1734 | +350429,泰宁县,4,350400 | ||
| 1735 | +350430,建宁县,4,350400 | ||
| 1736 | +350481,永安市,4,350400 | ||
| 1737 | +350502,鲤城区,4,350500 | ||
| 1738 | +350503,丰泽区,4,350500 | ||
| 1739 | +350504,洛江区,4,350500 | ||
| 1740 | +350505,泉港区,4,350500 | ||
| 1741 | +350521,惠安县,4,350500 | ||
| 1742 | +350524,安溪县,4,350500 | ||
| 1743 | +350525,永春县,4,350500 | ||
| 1744 | +350526,德化县,4,350500 | ||
| 1745 | +350527,金门县,4,350500 | ||
| 1746 | +350581,石狮市,4,350500 | ||
| 1747 | +350582,晋江市,4,350500 | ||
| 1748 | +350583,南安市,4,350500 | ||
| 1749 | +350602,芗城区,4,350600 | ||
| 1750 | +350603,龙文区,4,350600 | ||
| 1751 | +350604,龙海区,4,350600 | ||
| 1752 | +350605,长泰区,4,350600 | ||
| 1753 | +350622,云霄县,4,350600 | ||
| 1754 | +350623,漳浦县,4,350600 | ||
| 1755 | +350624,诏安县,4,350600 | ||
| 1756 | +350626,东山县,4,350600 | ||
| 1757 | +350627,南靖县,4,350600 | ||
| 1758 | +350628,平和县,4,350600 | ||
| 1759 | +350629,华安县,4,350600 | ||
| 1760 | +350702,延平区,4,350700 | ||
| 1761 | +350703,建阳区,4,350700 | ||
| 1762 | +350721,顺昌县,4,350700 | ||
| 1763 | +350722,浦城县,4,350700 | ||
| 1764 | +350723,光泽县,4,350700 | ||
| 1765 | +350724,松溪县,4,350700 | ||
| 1766 | +350725,政和县,4,350700 | ||
| 1767 | +350781,邵武市,4,350700 | ||
| 1768 | +350782,武夷山市,4,350700 | ||
| 1769 | +350783,建瓯市,4,350700 | ||
| 1770 | +350802,新罗区,4,350800 | ||
| 1771 | +350803,永定区,4,350800 | ||
| 1772 | +350821,长汀县,4,350800 | ||
| 1773 | +350823,上杭县,4,350800 | ||
| 1774 | +350824,武平县,4,350800 | ||
| 1775 | +350825,连城县,4,350800 | ||
| 1776 | +350881,漳平市,4,350800 | ||
| 1777 | +350902,蕉城区,4,350900 | ||
| 1778 | +350921,霞浦县,4,350900 | ||
| 1779 | +350922,古田县,4,350900 | ||
| 1780 | +350923,屏南县,4,350900 | ||
| 1781 | +350924,寿宁县,4,350900 | ||
| 1782 | +350925,周宁县,4,350900 | ||
| 1783 | +350926,柘荣县,4,350900 | ||
| 1784 | +350981,福安市,4,350900 | ||
| 1785 | +350982,福鼎市,4,350900 | ||
| 1786 | +360102,东湖区,4,360100 | ||
| 1787 | +360103,西湖区,4,360100 | ||
| 1788 | +360104,青云谱区,4,360100 | ||
| 1789 | +360111,青山湖区,4,360100 | ||
| 1790 | +360112,新建区,4,360100 | ||
| 1791 | +360113,红谷滩区,4,360100 | ||
| 1792 | +360121,南昌县,4,360100 | ||
| 1793 | +360123,安义县,4,360100 | ||
| 1794 | +360124,进贤县,4,360100 | ||
| 1795 | +360202,昌江区,4,360200 | ||
| 1796 | +360203,珠山区,4,360200 | ||
| 1797 | +360222,浮梁县,4,360200 | ||
| 1798 | +360281,乐平市,4,360200 | ||
| 1799 | +360302,安源区,4,360300 | ||
| 1800 | +360313,湘东区,4,360300 | ||
| 1801 | +360321,莲花县,4,360300 | ||
| 1802 | +360322,上栗县,4,360300 | ||
| 1803 | +360323,芦溪县,4,360300 | ||
| 1804 | +360402,濂溪区,4,360400 | ||
| 1805 | +360403,浔阳区,4,360400 | ||
| 1806 | +360404,柴桑区,4,360400 | ||
| 1807 | +360423,武宁县,4,360400 | ||
| 1808 | +360424,修水县,4,360400 | ||
| 1809 | +360425,永修县,4,360400 | ||
| 1810 | +360426,德安县,4,360400 | ||
| 1811 | +360428,都昌县,4,360400 | ||
| 1812 | +360429,湖口县,4,360400 | ||
| 1813 | +360430,彭泽县,4,360400 | ||
| 1814 | +360481,瑞昌市,4,360400 | ||
| 1815 | +360482,共青城市,4,360400 | ||
| 1816 | +360483,庐山市,4,360400 | ||
| 1817 | +360502,渝水区,4,360500 | ||
| 1818 | +360521,分宜县,4,360500 | ||
| 1819 | +360602,月湖区,4,360600 | ||
| 1820 | +360603,余江区,4,360600 | ||
| 1821 | +360681,贵溪市,4,360600 | ||
| 1822 | +360702,章贡区,4,360700 | ||
| 1823 | +360703,南康区,4,360700 | ||
| 1824 | +360704,赣县区,4,360700 | ||
| 1825 | +360722,信丰县,4,360700 | ||
| 1826 | +360723,大余县,4,360700 | ||
| 1827 | +360724,上犹县,4,360700 | ||
| 1828 | +360725,崇义县,4,360700 | ||
| 1829 | +360726,安远县,4,360700 | ||
| 1830 | +360728,定南县,4,360700 | ||
| 1831 | +360729,全南县,4,360700 | ||
| 1832 | +360730,宁都县,4,360700 | ||
| 1833 | +360731,于都县,4,360700 | ||
| 1834 | +360732,兴国县,4,360700 | ||
| 1835 | +360733,会昌县,4,360700 | ||
| 1836 | +360734,寻乌县,4,360700 | ||
| 1837 | +360735,石城县,4,360700 | ||
| 1838 | +360781,瑞金市,4,360700 | ||
| 1839 | +360783,龙南市,4,360700 | ||
| 1840 | +360802,吉州区,4,360800 | ||
| 1841 | +360803,青原区,4,360800 | ||
| 1842 | +360821,吉安县,4,360800 | ||
| 1843 | +360822,吉水县,4,360800 | ||
| 1844 | +360823,峡江县,4,360800 | ||
| 1845 | +360824,新干县,4,360800 | ||
| 1846 | +360825,永丰县,4,360800 | ||
| 1847 | +360826,泰和县,4,360800 | ||
| 1848 | +360827,遂川县,4,360800 | ||
| 1849 | +360828,万安县,4,360800 | ||
| 1850 | +360829,安福县,4,360800 | ||
| 1851 | +360830,永新县,4,360800 | ||
| 1852 | +360881,井冈山市,4,360800 | ||
| 1853 | +360902,袁州区,4,360900 | ||
| 1854 | +360921,奉新县,4,360900 | ||
| 1855 | +360922,万载县,4,360900 | ||
| 1856 | +360923,上高县,4,360900 | ||
| 1857 | +360924,宜丰县,4,360900 | ||
| 1858 | +360925,靖安县,4,360900 | ||
| 1859 | +360926,铜鼓县,4,360900 | ||
| 1860 | +360981,丰城市,4,360900 | ||
| 1861 | +360982,樟树市,4,360900 | ||
| 1862 | +360983,高安市,4,360900 | ||
| 1863 | +361002,临川区,4,361000 | ||
| 1864 | +361003,东乡区,4,361000 | ||
| 1865 | +361021,南城县,4,361000 | ||
| 1866 | +361022,黎川县,4,361000 | ||
| 1867 | +361023,南丰县,4,361000 | ||
| 1868 | +361024,崇仁县,4,361000 | ||
| 1869 | +361025,乐安县,4,361000 | ||
| 1870 | +361026,宜黄县,4,361000 | ||
| 1871 | +361027,金溪县,4,361000 | ||
| 1872 | +361028,资溪县,4,361000 | ||
| 1873 | +361030,广昌县,4,361000 | ||
| 1874 | +361102,信州区,4,361100 | ||
| 1875 | +361103,广丰区,4,361100 | ||
| 1876 | +361104,广信区,4,361100 | ||
| 1877 | +361123,玉山县,4,361100 | ||
| 1878 | +361124,铅山县,4,361100 | ||
| 1879 | +361125,横峰县,4,361100 | ||
| 1880 | +361126,弋阳县,4,361100 | ||
| 1881 | +361127,余干县,4,361100 | ||
| 1882 | +361128,鄱阳县,4,361100 | ||
| 1883 | +361129,万年县,4,361100 | ||
| 1884 | +361130,婺源县,4,361100 | ||
| 1885 | +361181,德兴市,4,361100 | ||
| 1886 | +370102,历下区,4,370100 | ||
| 1887 | +370103,市中区,4,370100 | ||
| 1888 | +370104,槐荫区,4,370100 | ||
| 1889 | +370105,天桥区,4,370100 | ||
| 1890 | +370112,历城区,4,370100 | ||
| 1891 | +370113,长清区,4,370100 | ||
| 1892 | +370114,章丘区,4,370100 | ||
| 1893 | +370115,济阳区,4,370100 | ||
| 1894 | +370116,莱芜区,4,370100 | ||
| 1895 | +370117,钢城区,4,370100 | ||
| 1896 | +370124,平阴县,4,370100 | ||
| 1897 | +370126,商河县,4,370100 | ||
| 1898 | +370171,济南高新技术产业开发区,4,370100 | ||
| 1899 | +370202,市南区,4,370200 | ||
| 1900 | +370203,市北区,4,370200 | ||
| 1901 | +370211,黄岛区,4,370200 | ||
| 1902 | +370212,崂山区,4,370200 | ||
| 1903 | +370213,李沧区,4,370200 | ||
| 1904 | +370214,城阳区,4,370200 | ||
| 1905 | +370215,即墨区,4,370200 | ||
| 1906 | +370271,青岛高新技术产业开发区,4,370200 | ||
| 1907 | +370281,胶州市,4,370200 | ||
| 1908 | +370283,平度市,4,370200 | ||
| 1909 | +370285,莱西市,4,370200 | ||
| 1910 | +370302,淄川区,4,370300 | ||
| 1911 | +370303,张店区,4,370300 | ||
| 1912 | +370304,博山区,4,370300 | ||
| 1913 | +370305,临淄区,4,370300 | ||
| 1914 | +370306,周村区,4,370300 | ||
| 1915 | +370321,桓台县,4,370300 | ||
| 1916 | +370322,高青县,4,370300 | ||
| 1917 | +370323,沂源县,4,370300 | ||
| 1918 | +370402,市中区,4,370400 | ||
| 1919 | +370403,薛城区,4,370400 | ||
| 1920 | +370404,峄城区,4,370400 | ||
| 1921 | +370405,台儿庄区,4,370400 | ||
| 1922 | +370406,山亭区,4,370400 | ||
| 1923 | +370481,滕州市,4,370400 | ||
| 1924 | +370502,东营区,4,370500 | ||
| 1925 | +370503,河口区,4,370500 | ||
| 1926 | +370505,垦利区,4,370500 | ||
| 1927 | +370522,利津县,4,370500 | ||
| 1928 | +370523,广饶县,4,370500 | ||
| 1929 | +370571,东营经济技术开发区,4,370500 | ||
| 1930 | +370572,东营港经济开发区,4,370500 | ||
| 1931 | +370602,芝罘区,4,370600 | ||
| 1932 | +370611,福山区,4,370600 | ||
| 1933 | +370612,牟平区,4,370600 | ||
| 1934 | +370613,莱山区,4,370600 | ||
| 1935 | +370614,蓬莱区,4,370600 | ||
| 1936 | +370671,烟台高新技术产业开发区,4,370600 | ||
| 1937 | +370672,烟台经济技术开发区,4,370600 | ||
| 1938 | +370681,龙口市,4,370600 | ||
| 1939 | +370682,莱阳市,4,370600 | ||
| 1940 | +370683,莱州市,4,370600 | ||
| 1941 | +370685,招远市,4,370600 | ||
| 1942 | +370686,栖霞市,4,370600 | ||
| 1943 | +370687,海阳市,4,370600 | ||
| 1944 | +370702,潍城区,4,370700 | ||
| 1945 | +370703,寒亭区,4,370700 | ||
| 1946 | +370704,坊子区,4,370700 | ||
| 1947 | +370705,奎文区,4,370700 | ||
| 1948 | +370724,临朐县,4,370700 | ||
| 1949 | +370725,昌乐县,4,370700 | ||
| 1950 | +370772,潍坊滨海经济技术开发区,4,370700 | ||
| 1951 | +370781,青州市,4,370700 | ||
| 1952 | +370782,诸城市,4,370700 | ||
| 1953 | +370783,寿光市,4,370700 | ||
| 1954 | +370784,安丘市,4,370700 | ||
| 1955 | +370785,高密市,4,370700 | ||
| 1956 | +370786,昌邑市,4,370700 | ||
| 1957 | +370811,任城区,4,370800 | ||
| 1958 | +370812,兖州区,4,370800 | ||
| 1959 | +370826,微山县,4,370800 | ||
| 1960 | +370827,鱼台县,4,370800 | ||
| 1961 | +370828,金乡县,4,370800 | ||
| 1962 | +370829,嘉祥县,4,370800 | ||
| 1963 | +370830,汶上县,4,370800 | ||
| 1964 | +370831,泗水县,4,370800 | ||
| 1965 | +370832,梁山县,4,370800 | ||
| 1966 | +370871,济宁高新技术产业开发区,4,370800 | ||
| 1967 | +370881,曲阜市,4,370800 | ||
| 1968 | +370883,邹城市,4,370800 | ||
| 1969 | +370902,泰山区,4,370900 | ||
| 1970 | +370911,岱岳区,4,370900 | ||
| 1971 | +370921,宁阳县,4,370900 | ||
| 1972 | +370923,东平县,4,370900 | ||
| 1973 | +370982,新泰市,4,370900 | ||
| 1974 | +370983,肥城市,4,370900 | ||
| 1975 | +371002,环翠区,4,371000 | ||
| 1976 | +371003,文登区,4,371000 | ||
| 1977 | +371071,威海火炬高技术产业开发区,4,371000 | ||
| 1978 | +371072,威海经济技术开发区,4,371000 | ||
| 1979 | +371073,威海临港经济技术开发区,4,371000 | ||
| 1980 | +371082,荣成市,4,371000 | ||
| 1981 | +371083,乳山市,4,371000 | ||
| 1982 | +371102,东港区,4,371100 | ||
| 1983 | +371103,岚山区,4,371100 | ||
| 1984 | +371121,五莲县,4,371100 | ||
| 1985 | +371122,莒县,4,371100 | ||
| 1986 | +371171,日照经济技术开发区,4,371100 | ||
| 1987 | +371302,兰山区,4,371300 | ||
| 1988 | +371311,罗庄区,4,371300 | ||
| 1989 | +371312,河东区,4,371300 | ||
| 1990 | +371321,沂南县,4,371300 | ||
| 1991 | +371322,郯城县,4,371300 | ||
| 1992 | +371323,沂水县,4,371300 | ||
| 1993 | +371324,兰陵县,4,371300 | ||
| 1994 | +371325,费县,4,371300 | ||
| 1995 | +371326,平邑县,4,371300 | ||
| 1996 | +371327,莒南县,4,371300 | ||
| 1997 | +371328,蒙阴县,4,371300 | ||
| 1998 | +371329,临沭县,4,371300 | ||
| 1999 | +371371,临沂高新技术产业开发区,4,371300 | ||
| 2000 | +371402,德城区,4,371400 | ||
| 2001 | +371403,陵城区,4,371400 | ||
| 2002 | +371422,宁津县,4,371400 | ||
| 2003 | +371423,庆云县,4,371400 | ||
| 2004 | +371424,临邑县,4,371400 | ||
| 2005 | +371425,齐河县,4,371400 | ||
| 2006 | +371426,平原县,4,371400 | ||
| 2007 | +371427,夏津县,4,371400 | ||
| 2008 | +371428,武城县,4,371400 | ||
| 2009 | +371471,德州经济技术开发区,4,371400 | ||
| 2010 | +371472,德州运河经济开发区,4,371400 | ||
| 2011 | +371481,乐陵市,4,371400 | ||
| 2012 | +371482,禹城市,4,371400 | ||
| 2013 | +371502,东昌府区,4,371500 | ||
| 2014 | +371503,茌平区,4,371500 | ||
| 2015 | +371521,阳谷县,4,371500 | ||
| 2016 | +371522,莘县,4,371500 | ||
| 2017 | +371524,东阿县,4,371500 | ||
| 2018 | +371525,冠县,4,371500 | ||
| 2019 | +371526,高唐县,4,371500 | ||
| 2020 | +371581,临清市,4,371500 | ||
| 2021 | +371602,滨城区,4,371600 | ||
| 2022 | +371603,沾化区,4,371600 | ||
| 2023 | +371621,惠民县,4,371600 | ||
| 2024 | +371622,阳信县,4,371600 | ||
| 2025 | +371623,无棣县,4,371600 | ||
| 2026 | +371625,博兴县,4,371600 | ||
| 2027 | +371681,邹平市,4,371600 | ||
| 2028 | +371702,牡丹区,4,371700 | ||
| 2029 | +371703,定陶区,4,371700 | ||
| 2030 | +371721,曹县,4,371700 | ||
| 2031 | +371722,单县,4,371700 | ||
| 2032 | +371723,成武县,4,371700 | ||
| 2033 | +371724,巨野县,4,371700 | ||
| 2034 | +371725,郓城县,4,371700 | ||
| 2035 | +371726,鄄城县,4,371700 | ||
| 2036 | +371728,东明县,4,371700 | ||
| 2037 | +371771,菏泽经济技术开发区,4,371700 | ||
| 2038 | +371772,菏泽高新技术开发区,4,371700 | ||
| 2039 | +410102,中原区,4,410100 | ||
| 2040 | +410103,二七区,4,410100 | ||
| 2041 | +410104,管城回族区,4,410100 | ||
| 2042 | +410105,金水区,4,410100 | ||
| 2043 | +410106,上街区,4,410100 | ||
| 2044 | +410108,惠济区,4,410100 | ||
| 2045 | +410122,中牟县,4,410100 | ||
| 2046 | +410171,郑州经济技术开发区,4,410100 | ||
| 2047 | +410172,郑州高新技术产业开发区,4,410100 | ||
| 2048 | +410173,郑州航空港经济综合实验区,4,410100 | ||
| 2049 | +410181,巩义市,4,410100 | ||
| 2050 | +410182,荥阳市,4,410100 | ||
| 2051 | +410183,新密市,4,410100 | ||
| 2052 | +410184,新郑市,4,410100 | ||
| 2053 | +410185,登封市,4,410100 | ||
| 2054 | +410202,龙亭区,4,410200 | ||
| 2055 | +410203,顺河回族区,4,410200 | ||
| 2056 | +410204,鼓楼区,4,410200 | ||
| 2057 | +410205,禹王台区,4,410200 | ||
| 2058 | +410212,祥符区,4,410200 | ||
| 2059 | +410221,杞县,4,410200 | ||
| 2060 | +410222,通许县,4,410200 | ||
| 2061 | +410223,尉氏县,4,410200 | ||
| 2062 | +410225,兰考县,4,410200 | ||
| 2063 | +410302,老城区,4,410300 | ||
| 2064 | +410303,西工区,4,410300 | ||
| 2065 | +410304,瀍河回族区,4,410300 | ||
| 2066 | +410305,涧西区,4,410300 | ||
| 2067 | +410307,偃师区,4,410300 | ||
| 2068 | +410308,孟津区,4,410300 | ||
| 2069 | +410311,洛龙区,4,410300 | ||
| 2070 | +410323,新安县,4,410300 | ||
| 2071 | +410324,栾川县,4,410300 | ||
| 2072 | +410325,嵩县,4,410300 | ||
| 2073 | +410326,汝阳县,4,410300 | ||
| 2074 | +410327,宜阳县,4,410300 | ||
| 2075 | +410328,洛宁县,4,410300 | ||
| 2076 | +410329,伊川县,4,410300 | ||
| 2077 | +410371,洛阳高新技术产业开发区,4,410300 | ||
| 2078 | +410402,新华区,4,410400 | ||
| 2079 | +410403,卫东区,4,410400 | ||
| 2080 | +410404,石龙区,4,410400 | ||
| 2081 | +410411,湛河区,4,410400 | ||
| 2082 | +410421,宝丰县,4,410400 | ||
| 2083 | +410422,叶县,4,410400 | ||
| 2084 | +410423,鲁山县,4,410400 | ||
| 2085 | +410425,郏县,4,410400 | ||
| 2086 | +410471,平顶山高新技术产业开发区,4,410400 | ||
| 2087 | +410472,平顶山市城乡一体化示范区,4,410400 | ||
| 2088 | +410481,舞钢市,4,410400 | ||
| 2089 | +410482,汝州市,4,410400 | ||
| 2090 | +410502,文峰区,4,410500 | ||
| 2091 | +410503,北关区,4,410500 | ||
| 2092 | +410505,殷都区,4,410500 | ||
| 2093 | +410506,龙安区,4,410500 | ||
| 2094 | +410522,安阳县,4,410500 | ||
| 2095 | +410523,汤阴县,4,410500 | ||
| 2096 | +410526,滑县,4,410500 | ||
| 2097 | +410527,内黄县,4,410500 | ||
| 2098 | +410571,安阳高新技术产业开发区,4,410500 | ||
| 2099 | +410581,林州市,4,410500 | ||
| 2100 | +410602,鹤山区,4,410600 | ||
| 2101 | +410603,山城区,4,410600 | ||
| 2102 | +410611,淇滨区,4,410600 | ||
| 2103 | +410621,浚县,4,410600 | ||
| 2104 | +410622,淇县,4,410600 | ||
| 2105 | +410671,鹤壁经济技术开发区,4,410600 | ||
| 2106 | +410702,红旗区,4,410700 | ||
| 2107 | +410703,卫滨区,4,410700 | ||
| 2108 | +410704,凤泉区,4,410700 | ||
| 2109 | +410711,牧野区,4,410700 | ||
| 2110 | +410721,新乡县,4,410700 | ||
| 2111 | +410724,获嘉县,4,410700 | ||
| 2112 | +410725,原阳县,4,410700 | ||
| 2113 | +410726,延津县,4,410700 | ||
| 2114 | +410727,封丘县,4,410700 | ||
| 2115 | +410771,新乡高新技术产业开发区,4,410700 | ||
| 2116 | +410772,新乡经济技术开发区,4,410700 | ||
| 2117 | +410773,新乡市平原城乡一体化示范区,4,410700 | ||
| 2118 | +410781,卫辉市,4,410700 | ||
| 2119 | +410782,辉县市,4,410700 | ||
| 2120 | +410783,长垣市,4,410700 | ||
| 2121 | +410802,解放区,4,410800 | ||
| 2122 | +410803,中站区,4,410800 | ||
| 2123 | +410804,马村区,4,410800 | ||
| 2124 | +410811,山阳区,4,410800 | ||
| 2125 | +410821,修武县,4,410800 | ||
| 2126 | +410822,博爱县,4,410800 | ||
| 2127 | +410823,武陟县,4,410800 | ||
| 2128 | +410825,温县,4,410800 | ||
| 2129 | +410871,焦作城乡一体化示范区,4,410800 | ||
| 2130 | +410882,沁阳市,4,410800 | ||
| 2131 | +410883,孟州市,4,410800 | ||
| 2132 | +410902,华龙区,4,410900 | ||
| 2133 | +410922,清丰县,4,410900 | ||
| 2134 | +410923,南乐县,4,410900 | ||
| 2135 | +410926,范县,4,410900 | ||
| 2136 | +410927,台前县,4,410900 | ||
| 2137 | +410928,濮阳县,4,410900 | ||
| 2138 | +410971,河南濮阳工业园区,4,410900 | ||
| 2139 | +410972,濮阳经济技术开发区,4,410900 | ||
| 2140 | +411002,魏都区,4,411000 | ||
| 2141 | +411003,建安区,4,411000 | ||
| 2142 | +411024,鄢陵县,4,411000 | ||
| 2143 | +411025,襄城县,4,411000 | ||
| 2144 | +411071,许昌经济技术开发区,4,411000 | ||
| 2145 | +411081,禹州市,4,411000 | ||
| 2146 | +411082,长葛市,4,411000 | ||
| 2147 | +411102,源汇区,4,411100 | ||
| 2148 | +411103,郾城区,4,411100 | ||
| 2149 | +411104,召陵区,4,411100 | ||
| 2150 | +411121,舞阳县,4,411100 | ||
| 2151 | +411122,临颍县,4,411100 | ||
| 2152 | +411171,漯河经济技术开发区,4,411100 | ||
| 2153 | +411202,湖滨区,4,411200 | ||
| 2154 | +411203,陕州区,4,411200 | ||
| 2155 | +411221,渑池县,4,411200 | ||
| 2156 | +411224,卢氏县,4,411200 | ||
| 2157 | +411271,河南三门峡经济开发区,4,411200 | ||
| 2158 | +411281,义马市,4,411200 | ||
| 2159 | +411282,灵宝市,4,411200 | ||
| 2160 | +411302,宛城区,4,411300 | ||
| 2161 | +411303,卧龙区,4,411300 | ||
| 2162 | +411321,南召县,4,411300 | ||
| 2163 | +411322,方城县,4,411300 | ||
| 2164 | +411323,西峡县,4,411300 | ||
| 2165 | +411324,镇平县,4,411300 | ||
| 2166 | +411325,内乡县,4,411300 | ||
| 2167 | +411326,淅川县,4,411300 | ||
| 2168 | +411327,社旗县,4,411300 | ||
| 2169 | +411328,唐河县,4,411300 | ||
| 2170 | +411329,新野县,4,411300 | ||
| 2171 | +411330,桐柏县,4,411300 | ||
| 2172 | +411371,南阳高新技术产业开发区,4,411300 | ||
| 2173 | +411372,南阳市城乡一体化示范区,4,411300 | ||
| 2174 | +411381,邓州市,4,411300 | ||
| 2175 | +411402,梁园区,4,411400 | ||
| 2176 | +411403,睢阳区,4,411400 | ||
| 2177 | +411421,民权县,4,411400 | ||
| 2178 | +411422,睢县,4,411400 | ||
| 2179 | +411423,宁陵县,4,411400 | ||
| 2180 | +411424,柘城县,4,411400 | ||
| 2181 | +411425,虞城县,4,411400 | ||
| 2182 | +411426,夏邑县,4,411400 | ||
| 2183 | +411471,豫东综合物流产业聚集区,4,411400 | ||
| 2184 | +411472,河南商丘经济开发区,4,411400 | ||
| 2185 | +411481,永城市,4,411400 | ||
| 2186 | +411502,浉河区,4,411500 | ||
| 2187 | +411503,平桥区,4,411500 | ||
| 2188 | +411521,罗山县,4,411500 | ||
| 2189 | +411522,光山县,4,411500 | ||
| 2190 | +411523,新县,4,411500 | ||
| 2191 | +411524,商城县,4,411500 | ||
| 2192 | +411525,固始县,4,411500 | ||
| 2193 | +411526,潢川县,4,411500 | ||
| 2194 | +411527,淮滨县,4,411500 | ||
| 2195 | +411528,息县,4,411500 | ||
| 2196 | +411571,信阳高新技术产业开发区,4,411500 | ||
| 2197 | +411602,川汇区,4,411600 | ||
| 2198 | +411603,淮阳区,4,411600 | ||
| 2199 | +411621,扶沟县,4,411600 | ||
| 2200 | +411622,西华县,4,411600 | ||
| 2201 | +411623,商水县,4,411600 | ||
| 2202 | +411624,沈丘县,4,411600 | ||
| 2203 | +411625,郸城县,4,411600 | ||
| 2204 | +411627,太康县,4,411600 | ||
| 2205 | +411628,鹿邑县,4,411600 | ||
| 2206 | +411671,河南周口经济开发区,4,411600 | ||
| 2207 | +411681,项城市,4,411600 | ||
| 2208 | +411702,驿城区,4,411700 | ||
| 2209 | +411721,西平县,4,411700 | ||
| 2210 | +411722,上蔡县,4,411700 | ||
| 2211 | +411723,平舆县,4,411700 | ||
| 2212 | +411724,正阳县,4,411700 | ||
| 2213 | +411725,确山县,4,411700 | ||
| 2214 | +411726,泌阳县,4,411700 | ||
| 2215 | +411727,汝南县,4,411700 | ||
| 2216 | +411728,遂平县,4,411700 | ||
| 2217 | +411729,新蔡县,4,411700 | ||
| 2218 | +411771,河南驻马店经济开发区,4,411700 | ||
| 2219 | +419001,济源市,4,419000 | ||
| 2220 | +420102,江岸区,4,420100 | ||
| 2221 | +420103,江汉区,4,420100 | ||
| 2222 | +420104,硚口区,4,420100 | ||
| 2223 | +420105,汉阳区,4,420100 | ||
| 2224 | +420106,武昌区,4,420100 | ||
| 2225 | +420107,青山区,4,420100 | ||
| 2226 | +420111,洪山区,4,420100 | ||
| 2227 | +420112,东西湖区,4,420100 | ||
| 2228 | +420113,汉南区,4,420100 | ||
| 2229 | +420114,蔡甸区,4,420100 | ||
| 2230 | +420115,江夏区,4,420100 | ||
| 2231 | +420116,黄陂区,4,420100 | ||
| 2232 | +420117,新洲区,4,420100 | ||
| 2233 | +420202,黄石港区,4,420200 | ||
| 2234 | +420203,西塞山区,4,420200 | ||
| 2235 | +420204,下陆区,4,420200 | ||
| 2236 | +420205,铁山区,4,420200 | ||
| 2237 | +420222,阳新县,4,420200 | ||
| 2238 | +420281,大冶市,4,420200 | ||
| 2239 | +420302,茅箭区,4,420300 | ||
| 2240 | +420303,张湾区,4,420300 | ||
| 2241 | +420304,郧阳区,4,420300 | ||
| 2242 | +420322,郧西县,4,420300 | ||
| 2243 | +420323,竹山县,4,420300 | ||
| 2244 | +420324,竹溪县,4,420300 | ||
| 2245 | +420325,房县,4,420300 | ||
| 2246 | +420381,丹江口市,4,420300 | ||
| 2247 | +420502,西陵区,4,420500 | ||
| 2248 | +420503,伍家岗区,4,420500 | ||
| 2249 | +420504,点军区,4,420500 | ||
| 2250 | +420505,猇亭区,4,420500 | ||
| 2251 | +420506,夷陵区,4,420500 | ||
| 2252 | +420525,远安县,4,420500 | ||
| 2253 | +420526,兴山县,4,420500 | ||
| 2254 | +420527,秭归县,4,420500 | ||
| 2255 | +420528,长阳土家族自治县,4,420500 | ||
| 2256 | +420529,五峰土家族自治县,4,420500 | ||
| 2257 | +420581,宜都市,4,420500 | ||
| 2258 | +420582,当阳市,4,420500 | ||
| 2259 | +420583,枝江市,4,420500 | ||
| 2260 | +420602,襄城区,4,420600 | ||
| 2261 | +420606,樊城区,4,420600 | ||
| 2262 | +420607,襄州区,4,420600 | ||
| 2263 | +420624,南漳县,4,420600 | ||
| 2264 | +420625,谷城县,4,420600 | ||
| 2265 | +420626,保康县,4,420600 | ||
| 2266 | +420682,老河口市,4,420600 | ||
| 2267 | +420683,枣阳市,4,420600 | ||
| 2268 | +420684,宜城市,4,420600 | ||
| 2269 | +420702,梁子湖区,4,420700 | ||
| 2270 | +420703,华容区,4,420700 | ||
| 2271 | +420704,鄂城区,4,420700 | ||
| 2272 | +420802,东宝区,4,420800 | ||
| 2273 | +420804,掇刀区,4,420800 | ||
| 2274 | +420822,沙洋县,4,420800 | ||
| 2275 | +420881,钟祥市,4,420800 | ||
| 2276 | +420882,京山市,4,420800 | ||
| 2277 | +420902,孝南区,4,420900 | ||
| 2278 | +420921,孝昌县,4,420900 | ||
| 2279 | +420922,大悟县,4,420900 | ||
| 2280 | +420923,云梦县,4,420900 | ||
| 2281 | +420981,应城市,4,420900 | ||
| 2282 | +420982,安陆市,4,420900 | ||
| 2283 | +420984,汉川市,4,420900 | ||
| 2284 | +421002,沙市区,4,421000 | ||
| 2285 | +421003,荆州区,4,421000 | ||
| 2286 | +421022,公安县,4,421000 | ||
| 2287 | +421024,江陵县,4,421000 | ||
| 2288 | +421071,荆州经济技术开发区,4,421000 | ||
| 2289 | +421081,石首市,4,421000 | ||
| 2290 | +421083,洪湖市,4,421000 | ||
| 2291 | +421087,松滋市,4,421000 | ||
| 2292 | +421088,监利市,4,421000 | ||
| 2293 | +421102,黄州区,4,421100 | ||
| 2294 | +421121,团风县,4,421100 | ||
| 2295 | +421122,红安县,4,421100 | ||
| 2296 | +421123,罗田县,4,421100 | ||
| 2297 | +421124,英山县,4,421100 | ||
| 2298 | +421125,浠水县,4,421100 | ||
| 2299 | +421126,蕲春县,4,421100 | ||
| 2300 | +421127,黄梅县,4,421100 | ||
| 2301 | +421171,龙感湖管理区,4,421100 | ||
| 2302 | +421181,麻城市,4,421100 | ||
| 2303 | +421182,武穴市,4,421100 | ||
| 2304 | +421202,咸安区,4,421200 | ||
| 2305 | +421221,嘉鱼县,4,421200 | ||
| 2306 | +421222,通城县,4,421200 | ||
| 2307 | +421223,崇阳县,4,421200 | ||
| 2308 | +421224,通山县,4,421200 | ||
| 2309 | +421281,赤壁市,4,421200 | ||
| 2310 | +421303,曾都区,4,421300 | ||
| 2311 | +421321,随县,4,421300 | ||
| 2312 | +421381,广水市,4,421300 | ||
| 2313 | +422801,恩施市,4,422800 | ||
| 2314 | +422802,利川市,4,422800 | ||
| 2315 | +422822,建始县,4,422800 | ||
| 2316 | +422823,巴东县,4,422800 | ||
| 2317 | +422825,宣恩县,4,422800 | ||
| 2318 | +422826,咸丰县,4,422800 | ||
| 2319 | +422827,来凤县,4,422800 | ||
| 2320 | +422828,鹤峰县,4,422800 | ||
| 2321 | +429004,仙桃市,4,429000 | ||
| 2322 | +429005,潜江市,4,429000 | ||
| 2323 | +429006,天门市,4,429000 | ||
| 2324 | +429021,神农架林区,4,429000 | ||
| 2325 | +430102,芙蓉区,4,430100 | ||
| 2326 | +430103,天心区,4,430100 | ||
| 2327 | +430104,岳麓区,4,430100 | ||
| 2328 | +430105,开福区,4,430100 | ||
| 2329 | +430111,雨花区,4,430100 | ||
| 2330 | +430112,望城区,4,430100 | ||
| 2331 | +430121,长沙县,4,430100 | ||
| 2332 | +430181,浏阳市,4,430100 | ||
| 2333 | +430182,宁乡市,4,430100 | ||
| 2334 | +430202,荷塘区,4,430200 | ||
| 2335 | +430203,芦淞区,4,430200 | ||
| 2336 | +430204,石峰区,4,430200 | ||
| 2337 | +430211,天元区,4,430200 | ||
| 2338 | +430212,渌口区,4,430200 | ||
| 2339 | +430223,攸县,4,430200 | ||
| 2340 | +430224,茶陵县,4,430200 | ||
| 2341 | +430225,炎陵县,4,430200 | ||
| 2342 | +430271,云龙示范区,4,430200 | ||
| 2343 | +430281,醴陵市,4,430200 | ||
| 2344 | +430302,雨湖区,4,430300 | ||
| 2345 | +430304,岳塘区,4,430300 | ||
| 2346 | +430321,湘潭县,4,430300 | ||
| 2347 | +430371,湖南湘潭高新技术产业园区,4,430300 | ||
| 2348 | +430372,湘潭昭山示范区,4,430300 | ||
| 2349 | +430373,湘潭九华示范区,4,430300 | ||
| 2350 | +430381,湘乡市,4,430300 | ||
| 2351 | +430382,韶山市,4,430300 | ||
| 2352 | +430405,珠晖区,4,430400 | ||
| 2353 | +430406,雁峰区,4,430400 | ||
| 2354 | +430407,石鼓区,4,430400 | ||
| 2355 | +430408,蒸湘区,4,430400 | ||
| 2356 | +430412,南岳区,4,430400 | ||
| 2357 | +430421,衡阳县,4,430400 | ||
| 2358 | +430422,衡南县,4,430400 | ||
| 2359 | +430423,衡山县,4,430400 | ||
| 2360 | +430424,衡东县,4,430400 | ||
| 2361 | +430426,祁东县,4,430400 | ||
| 2362 | +430471,衡阳综合保税区,4,430400 | ||
| 2363 | +430472,湖南衡阳高新技术产业园区,4,430400 | ||
| 2364 | +430473,湖南衡阳松木经济开发区,4,430400 | ||
| 2365 | +430481,耒阳市,4,430400 | ||
| 2366 | +430482,常宁市,4,430400 | ||
| 2367 | +430502,双清区,4,430500 | ||
| 2368 | +430503,大祥区,4,430500 | ||
| 2369 | +430511,北塔区,4,430500 | ||
| 2370 | +430522,新邵县,4,430500 | ||
| 2371 | +430523,邵阳县,4,430500 | ||
| 2372 | +430524,隆回县,4,430500 | ||
| 2373 | +430525,洞口县,4,430500 | ||
| 2374 | +430527,绥宁县,4,430500 | ||
| 2375 | +430528,新宁县,4,430500 | ||
| 2376 | +430529,城步苗族自治县,4,430500 | ||
| 2377 | +430581,武冈市,4,430500 | ||
| 2378 | +430582,邵东市,4,430500 | ||
| 2379 | +430602,岳阳楼区,4,430600 | ||
| 2380 | +430603,云溪区,4,430600 | ||
| 2381 | +430611,君山区,4,430600 | ||
| 2382 | +430621,岳阳县,4,430600 | ||
| 2383 | +430623,华容县,4,430600 | ||
| 2384 | +430624,湘阴县,4,430600 | ||
| 2385 | +430626,平江县,4,430600 | ||
| 2386 | +430671,岳阳市屈原管理区,4,430600 | ||
| 2387 | +430681,汨罗市,4,430600 | ||
| 2388 | +430682,临湘市,4,430600 | ||
| 2389 | +430702,武陵区,4,430700 | ||
| 2390 | +430703,鼎城区,4,430700 | ||
| 2391 | +430721,安乡县,4,430700 | ||
| 2392 | +430722,汉寿县,4,430700 | ||
| 2393 | +430723,澧县,4,430700 | ||
| 2394 | +430724,临澧县,4,430700 | ||
| 2395 | +430725,桃源县,4,430700 | ||
| 2396 | +430726,石门县,4,430700 | ||
| 2397 | +430771,常德市西洞庭管理区,4,430700 | ||
| 2398 | +430781,津市市,4,430700 | ||
| 2399 | +430802,永定区,4,430800 | ||
| 2400 | +430811,武陵源区,4,430800 | ||
| 2401 | +430821,慈利县,4,430800 | ||
| 2402 | +430822,桑植县,4,430800 | ||
| 2403 | +430902,资阳区,4,430900 | ||
| 2404 | +430903,赫山区,4,430900 | ||
| 2405 | +430921,南县,4,430900 | ||
| 2406 | +430922,桃江县,4,430900 | ||
| 2407 | +430923,安化县,4,430900 | ||
| 2408 | +430971,益阳市大通湖管理区,4,430900 | ||
| 2409 | +430972,湖南益阳高新技术产业园区,4,430900 | ||
| 2410 | +430981,沅江市,4,430900 | ||
| 2411 | +431002,北湖区,4,431000 | ||
| 2412 | +431003,苏仙区,4,431000 | ||
| 2413 | +431021,桂阳县,4,431000 | ||
| 2414 | +431022,宜章县,4,431000 | ||
| 2415 | +431023,永兴县,4,431000 | ||
| 2416 | +431024,嘉禾县,4,431000 | ||
| 2417 | +431025,临武县,4,431000 | ||
| 2418 | +431026,汝城县,4,431000 | ||
| 2419 | +431027,桂东县,4,431000 | ||
| 2420 | +431028,安仁县,4,431000 | ||
| 2421 | +431081,资兴市,4,431000 | ||
| 2422 | +431102,零陵区,4,431100 | ||
| 2423 | +431103,冷水滩区,4,431100 | ||
| 2424 | +431122,东安县,4,431100 | ||
| 2425 | +431123,双牌县,4,431100 | ||
| 2426 | +431124,道县,4,431100 | ||
| 2427 | +431125,江永县,4,431100 | ||
| 2428 | +431126,宁远县,4,431100 | ||
| 2429 | +431127,蓝山县,4,431100 | ||
| 2430 | +431128,新田县,4,431100 | ||
| 2431 | +431129,江华瑶族自治县,4,431100 | ||
| 2432 | +431171,永州经济技术开发区,4,431100 | ||
| 2433 | +431173,永州市回龙圩管理区,4,431100 | ||
| 2434 | +431181,祁阳市,4,431100 | ||
| 2435 | +431202,鹤城区,4,431200 | ||
| 2436 | +431221,中方县,4,431200 | ||
| 2437 | +431222,沅陵县,4,431200 | ||
| 2438 | +431223,辰溪县,4,431200 | ||
| 2439 | +431224,溆浦县,4,431200 | ||
| 2440 | +431225,会同县,4,431200 | ||
| 2441 | +431226,麻阳苗族自治县,4,431200 | ||
| 2442 | +431227,新晃侗族自治县,4,431200 | ||
| 2443 | +431228,芷江侗族自治县,4,431200 | ||
| 2444 | +431229,靖州苗族侗族自治县,4,431200 | ||
| 2445 | +431230,通道侗族自治县,4,431200 | ||
| 2446 | +431271,怀化市洪江管理区,4,431200 | ||
| 2447 | +431281,洪江市,4,431200 | ||
| 2448 | +431302,娄星区,4,431300 | ||
| 2449 | +431321,双峰县,4,431300 | ||
| 2450 | +431322,新化县,4,431300 | ||
| 2451 | +431381,冷水江市,4,431300 | ||
| 2452 | +431382,涟源市,4,431300 | ||
| 2453 | +433101,吉首市,4,433100 | ||
| 2454 | +433122,泸溪县,4,433100 | ||
| 2455 | +433123,凤凰县,4,433100 | ||
| 2456 | +433124,花垣县,4,433100 | ||
| 2457 | +433125,保靖县,4,433100 | ||
| 2458 | +433126,古丈县,4,433100 | ||
| 2459 | +433127,永顺县,4,433100 | ||
| 2460 | +433130,龙山县,4,433100 | ||
| 2461 | +440103,荔湾区,4,440100 | ||
| 2462 | +440104,越秀区,4,440100 | ||
| 2463 | +440105,海珠区,4,440100 | ||
| 2464 | +440106,天河区,4,440100 | ||
| 2465 | +440111,白云区,4,440100 | ||
| 2466 | +440112,黄埔区,4,440100 | ||
| 2467 | +440113,番禺区,4,440100 | ||
| 2468 | +440114,花都区,4,440100 | ||
| 2469 | +440115,南沙区,4,440100 | ||
| 2470 | +440117,从化区,4,440100 | ||
| 2471 | +440118,增城区,4,440100 | ||
| 2472 | +440203,武江区,4,440200 | ||
| 2473 | +440204,浈江区,4,440200 | ||
| 2474 | +440205,曲江区,4,440200 | ||
| 2475 | +440222,始兴县,4,440200 | ||
| 2476 | +440224,仁化县,4,440200 | ||
| 2477 | +440229,翁源县,4,440200 | ||
| 2478 | +440232,乳源瑶族自治县,4,440200 | ||
| 2479 | +440233,新丰县,4,440200 | ||
| 2480 | +440281,乐昌市,4,440200 | ||
| 2481 | +440282,南雄市,4,440200 | ||
| 2482 | +440303,罗湖区,4,440300 | ||
| 2483 | +440304,福田区,4,440300 | ||
| 2484 | +440305,南山区,4,440300 | ||
| 2485 | +440306,宝安区,4,440300 | ||
| 2486 | +440307,龙岗区,4,440300 | ||
| 2487 | +440308,盐田区,4,440300 | ||
| 2488 | +440309,龙华区,4,440300 | ||
| 2489 | +440310,坪山区,4,440300 | ||
| 2490 | +440311,光明区,4,440300 | ||
| 2491 | +440402,香洲区,4,440400 | ||
| 2492 | +440403,斗门区,4,440400 | ||
| 2493 | +440404,金湾区,4,440400 | ||
| 2494 | +440507,龙湖区,4,440500 | ||
| 2495 | +440511,金平区,4,440500 | ||
| 2496 | +440512,濠江区,4,440500 | ||
| 2497 | +440513,潮阳区,4,440500 | ||
| 2498 | +440514,潮南区,4,440500 | ||
| 2499 | +440515,澄海区,4,440500 | ||
| 2500 | +440523,南澳县,4,440500 | ||
| 2501 | +440604,禅城区,4,440600 | ||
| 2502 | +440605,南海区,4,440600 | ||
| 2503 | +440606,顺德区,4,440600 | ||
| 2504 | +440607,三水区,4,440600 | ||
| 2505 | +440608,高明区,4,440600 | ||
| 2506 | +440703,蓬江区,4,440700 | ||
| 2507 | +440704,江海区,4,440700 | ||
| 2508 | +440705,新会区,4,440700 | ||
| 2509 | +440781,台山市,4,440700 | ||
| 2510 | +440783,开平市,4,440700 | ||
| 2511 | +440784,鹤山市,4,440700 | ||
| 2512 | +440785,恩平市,4,440700 | ||
| 2513 | +440802,赤坎区,4,440800 | ||
| 2514 | +440803,霞山区,4,440800 | ||
| 2515 | +440804,坡头区,4,440800 | ||
| 2516 | +440811,麻章区,4,440800 | ||
| 2517 | +440823,遂溪县,4,440800 | ||
| 2518 | +440825,徐闻县,4,440800 | ||
| 2519 | +440881,廉江市,4,440800 | ||
| 2520 | +440882,雷州市,4,440800 | ||
| 2521 | +440883,吴川市,4,440800 | ||
| 2522 | +440902,茂南区,4,440900 | ||
| 2523 | +440904,电白区,4,440900 | ||
| 2524 | +440981,高州市,4,440900 | ||
| 2525 | +440982,化州市,4,440900 | ||
| 2526 | +440983,信宜市,4,440900 | ||
| 2527 | +441202,端州区,4,441200 | ||
| 2528 | +441203,鼎湖区,4,441200 | ||
| 2529 | +441204,高要区,4,441200 | ||
| 2530 | +441223,广宁县,4,441200 | ||
| 2531 | +441224,怀集县,4,441200 | ||
| 2532 | +441225,封开县,4,441200 | ||
| 2533 | +441226,德庆县,4,441200 | ||
| 2534 | +441284,四会市,4,441200 | ||
| 2535 | +441302,惠城区,4,441300 | ||
| 2536 | +441303,惠阳区,4,441300 | ||
| 2537 | +441322,博罗县,4,441300 | ||
| 2538 | +441323,惠东县,4,441300 | ||
| 2539 | +441324,龙门县,4,441300 | ||
| 2540 | +441402,梅江区,4,441400 | ||
| 2541 | +441403,梅县区,4,441400 | ||
| 2542 | +441422,大埔县,4,441400 | ||
| 2543 | +441423,丰顺县,4,441400 | ||
| 2544 | +441424,五华县,4,441400 | ||
| 2545 | +441426,平远县,4,441400 | ||
| 2546 | +441427,蕉岭县,4,441400 | ||
| 2547 | +441481,兴宁市,4,441400 | ||
| 2548 | +441502,城区,4,441500 | ||
| 2549 | +441521,海丰县,4,441500 | ||
| 2550 | +441523,陆河县,4,441500 | ||
| 2551 | +441581,陆丰市,4,441500 | ||
| 2552 | +441602,源城区,4,441600 | ||
| 2553 | +441621,紫金县,4,441600 | ||
| 2554 | +441622,龙川县,4,441600 | ||
| 2555 | +441623,连平县,4,441600 | ||
| 2556 | +441624,和平县,4,441600 | ||
| 2557 | +441625,东源县,4,441600 | ||
| 2558 | +441702,江城区,4,441700 | ||
| 2559 | +441704,阳东区,4,441700 | ||
| 2560 | +441721,阳西县,4,441700 | ||
| 2561 | +441781,阳春市,4,441700 | ||
| 2562 | +441802,清城区,4,441800 | ||
| 2563 | +441803,清新区,4,441800 | ||
| 2564 | +441821,佛冈县,4,441800 | ||
| 2565 | +441823,阳山县,4,441800 | ||
| 2566 | +441825,连山壮族瑶族自治县,4,441800 | ||
| 2567 | +441826,连南瑶族自治县,4,441800 | ||
| 2568 | +441881,英德市,4,441800 | ||
| 2569 | +441882,连州市,4,441800 | ||
| 2570 | +445102,湘桥区,4,445100 | ||
| 2571 | +445103,潮安区,4,445100 | ||
| 2572 | +445122,饶平县,4,445100 | ||
| 2573 | +445202,榕城区,4,445200 | ||
| 2574 | +445203,揭东区,4,445200 | ||
| 2575 | +445222,揭西县,4,445200 | ||
| 2576 | +445224,惠来县,4,445200 | ||
| 2577 | +445281,普宁市,4,445200 | ||
| 2578 | +445302,云城区,4,445300 | ||
| 2579 | +445303,云安区,4,445300 | ||
| 2580 | +445321,新兴县,4,445300 | ||
| 2581 | +445322,郁南县,4,445300 | ||
| 2582 | +445381,罗定市,4,445300 | ||
| 2583 | +450102,兴宁区,4,450100 | ||
| 2584 | +450103,青秀区,4,450100 | ||
| 2585 | +450105,江南区,4,450100 | ||
| 2586 | +450107,西乡塘区,4,450100 | ||
| 2587 | +450108,良庆区,4,450100 | ||
| 2588 | +450109,邕宁区,4,450100 | ||
| 2589 | +450110,武鸣区,4,450100 | ||
| 2590 | +450123,隆安县,4,450100 | ||
| 2591 | +450124,马山县,4,450100 | ||
| 2592 | +450125,上林县,4,450100 | ||
| 2593 | +450126,宾阳县,4,450100 | ||
| 2594 | +450181,横州市,4,450100 | ||
| 2595 | +450202,城中区,4,450200 | ||
| 2596 | +450203,鱼峰区,4,450200 | ||
| 2597 | +450204,柳南区,4,450200 | ||
| 2598 | +450205,柳北区,4,450200 | ||
| 2599 | +450206,柳江区,4,450200 | ||
| 2600 | +450222,柳城县,4,450200 | ||
| 2601 | +450223,鹿寨县,4,450200 | ||
| 2602 | +450224,融安县,4,450200 | ||
| 2603 | +450225,融水苗族自治县,4,450200 | ||
| 2604 | +450226,三江侗族自治县,4,450200 | ||
| 2605 | +450302,秀峰区,4,450300 | ||
| 2606 | +450303,叠彩区,4,450300 | ||
| 2607 | +450304,象山区,4,450300 | ||
| 2608 | +450305,七星区,4,450300 | ||
| 2609 | +450311,雁山区,4,450300 | ||
| 2610 | +450312,临桂区,4,450300 | ||
| 2611 | +450321,阳朔县,4,450300 | ||
| 2612 | +450323,灵川县,4,450300 | ||
| 2613 | +450324,全州县,4,450300 | ||
| 2614 | +450325,兴安县,4,450300 | ||
| 2615 | +450326,永福县,4,450300 | ||
| 2616 | +450327,灌阳县,4,450300 | ||
| 2617 | +450328,龙胜各族自治县,4,450300 | ||
| 2618 | +450329,资源县,4,450300 | ||
| 2619 | +450330,平乐县,4,450300 | ||
| 2620 | +450332,恭城瑶族自治县,4,450300 | ||
| 2621 | +450381,荔浦市,4,450300 | ||
| 2622 | +450403,万秀区,4,450400 | ||
| 2623 | +450405,长洲区,4,450400 | ||
| 2624 | +450406,龙圩区,4,450400 | ||
| 2625 | +450421,苍梧县,4,450400 | ||
| 2626 | +450422,藤县,4,450400 | ||
| 2627 | +450423,蒙山县,4,450400 | ||
| 2628 | +450481,岑溪市,4,450400 | ||
| 2629 | +450502,海城区,4,450500 | ||
| 2630 | +450503,银海区,4,450500 | ||
| 2631 | +450512,铁山港区,4,450500 | ||
| 2632 | +450521,合浦县,4,450500 | ||
| 2633 | +450602,港口区,4,450600 | ||
| 2634 | +450603,防城区,4,450600 | ||
| 2635 | +450621,上思县,4,450600 | ||
| 2636 | +450681,东兴市,4,450600 | ||
| 2637 | +450702,钦南区,4,450700 | ||
| 2638 | +450703,钦北区,4,450700 | ||
| 2639 | +450721,灵山县,4,450700 | ||
| 2640 | +450722,浦北县,4,450700 | ||
| 2641 | +450802,港北区,4,450800 | ||
| 2642 | +450803,港南区,4,450800 | ||
| 2643 | +450804,覃塘区,4,450800 | ||
| 2644 | +450821,平南县,4,450800 | ||
| 2645 | +450881,桂平市,4,450800 | ||
| 2646 | +450902,玉州区,4,450900 | ||
| 2647 | +450903,福绵区,4,450900 | ||
| 2648 | +450921,容县,4,450900 | ||
| 2649 | +450922,陆川县,4,450900 | ||
| 2650 | +450923,博白县,4,450900 | ||
| 2651 | +450924,兴业县,4,450900 | ||
| 2652 | +450981,北流市,4,450900 | ||
| 2653 | +451002,右江区,4,451000 | ||
| 2654 | +451003,田阳区,4,451000 | ||
| 2655 | +451022,田东县,4,451000 | ||
| 2656 | +451024,德保县,4,451000 | ||
| 2657 | +451026,那坡县,4,451000 | ||
| 2658 | +451027,凌云县,4,451000 | ||
| 2659 | +451028,乐业县,4,451000 | ||
| 2660 | +451029,田林县,4,451000 | ||
| 2661 | +451030,西林县,4,451000 | ||
| 2662 | +451031,隆林各族自治县,4,451000 | ||
| 2663 | +451081,靖西市,4,451000 | ||
| 2664 | +451082,平果市,4,451000 | ||
| 2665 | +451102,八步区,4,451100 | ||
| 2666 | +451103,平桂区,4,451100 | ||
| 2667 | +451121,昭平县,4,451100 | ||
| 2668 | +451122,钟山县,4,451100 | ||
| 2669 | +451123,富川瑶族自治县,4,451100 | ||
| 2670 | +451202,金城江区,4,451200 | ||
| 2671 | +451203,宜州区,4,451200 | ||
| 2672 | +451221,南丹县,4,451200 | ||
| 2673 | +451222,天峨县,4,451200 | ||
| 2674 | +451223,凤山县,4,451200 | ||
| 2675 | +451224,东兰县,4,451200 | ||
| 2676 | +451225,罗城仫佬族自治县,4,451200 | ||
| 2677 | +451226,环江毛南族自治县,4,451200 | ||
| 2678 | +451227,巴马瑶族自治县,4,451200 | ||
| 2679 | +451228,都安瑶族自治县,4,451200 | ||
| 2680 | +451229,大化瑶族自治县,4,451200 | ||
| 2681 | +451302,兴宾区,4,451300 | ||
| 2682 | +451321,忻城县,4,451300 | ||
| 2683 | +451322,象州县,4,451300 | ||
| 2684 | +451323,武宣县,4,451300 | ||
| 2685 | +451324,金秀瑶族自治县,4,451300 | ||
| 2686 | +451381,合山市,4,451300 | ||
| 2687 | +451402,江州区,4,451400 | ||
| 2688 | +451421,扶绥县,4,451400 | ||
| 2689 | +451422,宁明县,4,451400 | ||
| 2690 | +451423,龙州县,4,451400 | ||
| 2691 | +451424,大新县,4,451400 | ||
| 2692 | +451425,天等县,4,451400 | ||
| 2693 | +451481,凭祥市,4,451400 | ||
| 2694 | +460105,秀英区,4,460100 | ||
| 2695 | +460106,龙华区,4,460100 | ||
| 2696 | +460107,琼山区,4,460100 | ||
| 2697 | +460108,美兰区,4,460100 | ||
| 2698 | +460202,海棠区,4,460200 | ||
| 2699 | +460203,吉阳区,4,460200 | ||
| 2700 | +460204,天涯区,4,460200 | ||
| 2701 | +460205,崖州区,4,460200 | ||
| 2702 | +460321,西沙群岛,4,460300 | ||
| 2703 | +460322,南沙群岛,4,460300 | ||
| 2704 | +460323,中沙群岛的岛礁及其海域,4,460300 | ||
| 2705 | +469001,五指山市,4,469000 | ||
| 2706 | +469002,琼海市,4,469000 | ||
| 2707 | +469005,文昌市,4,469000 | ||
| 2708 | +469006,万宁市,4,469000 | ||
| 2709 | +469007,东方市,4,469000 | ||
| 2710 | +469021,定安县,4,469000 | ||
| 2711 | +469022,屯昌县,4,469000 | ||
| 2712 | +469023,澄迈县,4,469000 | ||
| 2713 | +469024,临高县,4,469000 | ||
| 2714 | +469025,白沙黎族自治县,4,469000 | ||
| 2715 | +469026,昌江黎族自治县,4,469000 | ||
| 2716 | +469027,乐东黎族自治县,4,469000 | ||
| 2717 | +469028,陵水黎族自治县,4,469000 | ||
| 2718 | +469029,保亭黎族苗族自治县,4,469000 | ||
| 2719 | +469030,琼中黎族苗族自治县,4,469000 | ||
| 2720 | +500101,万州区,4,500100 | ||
| 2721 | +500102,涪陵区,4,500100 | ||
| 2722 | +500103,渝中区,4,500100 | ||
| 2723 | +500104,大渡口区,4,500100 | ||
| 2724 | +500105,江北区,4,500100 | ||
| 2725 | +500106,沙坪坝区,4,500100 | ||
| 2726 | +500107,九龙坡区,4,500100 | ||
| 2727 | +500108,南岸区,4,500100 | ||
| 2728 | +500109,北碚区,4,500100 | ||
| 2729 | +500110,綦江区,4,500100 | ||
| 2730 | +500111,大足区,4,500100 | ||
| 2731 | +500112,渝北区,4,500100 | ||
| 2732 | +500113,巴南区,4,500100 | ||
| 2733 | +500114,黔江区,4,500100 | ||
| 2734 | +500115,长寿区,4,500100 | ||
| 2735 | +500116,江津区,4,500100 | ||
| 2736 | +500117,合川区,4,500100 | ||
| 2737 | +500118,永川区,4,500100 | ||
| 2738 | +500119,南川区,4,500100 | ||
| 2739 | +500120,璧山区,4,500100 | ||
| 2740 | +500151,铜梁区,4,500100 | ||
| 2741 | +500152,潼南区,4,500100 | ||
| 2742 | +500153,荣昌区,4,500100 | ||
| 2743 | +500154,开州区,4,500100 | ||
| 2744 | +500155,梁平区,4,500100 | ||
| 2745 | +500156,武隆区,4,500100 | ||
| 2746 | +500229,城口县,4,500100 | ||
| 2747 | +500230,丰都县,4,500100 | ||
| 2748 | +500231,垫江县,4,500100 | ||
| 2749 | +500233,忠县,4,500100 | ||
| 2750 | +500235,云阳县,4,500100 | ||
| 2751 | +500236,奉节县,4,500100 | ||
| 2752 | +500237,巫山县,4,500100 | ||
| 2753 | +500238,巫溪县,4,500100 | ||
| 2754 | +500240,石柱土家族自治县,4,500100 | ||
| 2755 | +500241,秀山土家族苗族自治县,4,500100 | ||
| 2756 | +500242,酉阳土家族苗族自治县,4,500100 | ||
| 2757 | +500243,彭水苗族土家族自治县,4,500100 | ||
| 2758 | +510104,锦江区,4,510100 | ||
| 2759 | +510105,青羊区,4,510100 | ||
| 2760 | +510106,金牛区,4,510100 | ||
| 2761 | +510107,武侯区,4,510100 | ||
| 2762 | +510108,成华区,4,510100 | ||
| 2763 | +510112,龙泉驿区,4,510100 | ||
| 2764 | +510113,青白江区,4,510100 | ||
| 2765 | +510114,新都区,4,510100 | ||
| 2766 | +510115,温江区,4,510100 | ||
| 2767 | +510116,双流区,4,510100 | ||
| 2768 | +510117,郫都区,4,510100 | ||
| 2769 | +510118,新津区,4,510100 | ||
| 2770 | +510121,金堂县,4,510100 | ||
| 2771 | +510129,大邑县,4,510100 | ||
| 2772 | +510131,蒲江县,4,510100 | ||
| 2773 | +510181,都江堰市,4,510100 | ||
| 2774 | +510182,彭州市,4,510100 | ||
| 2775 | +510183,邛崃市,4,510100 | ||
| 2776 | +510184,崇州市,4,510100 | ||
| 2777 | +510185,简阳市,4,510100 | ||
| 2778 | +510302,自流井区,4,510300 | ||
| 2779 | +510303,贡井区,4,510300 | ||
| 2780 | +510304,大安区,4,510300 | ||
| 2781 | +510311,沿滩区,4,510300 | ||
| 2782 | +510321,荣县,4,510300 | ||
| 2783 | +510322,富顺县,4,510300 | ||
| 2784 | +510402,东区,4,510400 | ||
| 2785 | +510403,西区,4,510400 | ||
| 2786 | +510411,仁和区,4,510400 | ||
| 2787 | +510421,米易县,4,510400 | ||
| 2788 | +510422,盐边县,4,510400 | ||
| 2789 | +510502,江阳区,4,510500 | ||
| 2790 | +510503,纳溪区,4,510500 | ||
| 2791 | +510504,龙马潭区,4,510500 | ||
| 2792 | +510521,泸县,4,510500 | ||
| 2793 | +510522,合江县,4,510500 | ||
| 2794 | +510524,叙永县,4,510500 | ||
| 2795 | +510525,古蔺县,4,510500 | ||
| 2796 | +510603,旌阳区,4,510600 | ||
| 2797 | +510604,罗江区,4,510600 | ||
| 2798 | +510623,中江县,4,510600 | ||
| 2799 | +510681,广汉市,4,510600 | ||
| 2800 | +510682,什邡市,4,510600 | ||
| 2801 | +510683,绵竹市,4,510600 | ||
| 2802 | +510703,涪城区,4,510700 | ||
| 2803 | +510704,游仙区,4,510700 | ||
| 2804 | +510705,安州区,4,510700 | ||
| 2805 | +510722,三台县,4,510700 | ||
| 2806 | +510723,盐亭县,4,510700 | ||
| 2807 | +510725,梓潼县,4,510700 | ||
| 2808 | +510726,北川羌族自治县,4,510700 | ||
| 2809 | +510727,平武县,4,510700 | ||
| 2810 | +510781,江油市,4,510700 | ||
| 2811 | +510802,利州区,4,510800 | ||
| 2812 | +510811,昭化区,4,510800 | ||
| 2813 | +510812,朝天区,4,510800 | ||
| 2814 | +510821,旺苍县,4,510800 | ||
| 2815 | +510822,青川县,4,510800 | ||
| 2816 | +510823,剑阁县,4,510800 | ||
| 2817 | +510824,苍溪县,4,510800 | ||
| 2818 | +510903,船山区,4,510900 | ||
| 2819 | +510904,安居区,4,510900 | ||
| 2820 | +510921,蓬溪县,4,510900 | ||
| 2821 | +510923,大英县,4,510900 | ||
| 2822 | +510981,射洪市,4,510900 | ||
| 2823 | +511002,市中区,4,511000 | ||
| 2824 | +511011,东兴区,4,511000 | ||
| 2825 | +511024,威远县,4,511000 | ||
| 2826 | +511025,资中县,4,511000 | ||
| 2827 | +511071,内江经济开发区,4,511000 | ||
| 2828 | +511083,隆昌市,4,511000 | ||
| 2829 | +511102,市中区,4,511100 | ||
| 2830 | +511111,沙湾区,4,511100 | ||
| 2831 | +511112,五通桥区,4,511100 | ||
| 2832 | +511113,金口河区,4,511100 | ||
| 2833 | +511123,犍为县,4,511100 | ||
| 2834 | +511124,井研县,4,511100 | ||
| 2835 | +511126,夹江县,4,511100 | ||
| 2836 | +511129,沐川县,4,511100 | ||
| 2837 | +511132,峨边彝族自治县,4,511100 | ||
| 2838 | +511133,马边彝族自治县,4,511100 | ||
| 2839 | +511181,峨眉山市,4,511100 | ||
| 2840 | +511302,顺庆区,4,511300 | ||
| 2841 | +511303,高坪区,4,511300 | ||
| 2842 | +511304,嘉陵区,4,511300 | ||
| 2843 | +511321,南部县,4,511300 | ||
| 2844 | +511322,营山县,4,511300 | ||
| 2845 | +511323,蓬安县,4,511300 | ||
| 2846 | +511324,仪陇县,4,511300 | ||
| 2847 | +511325,西充县,4,511300 | ||
| 2848 | +511381,阆中市,4,511300 | ||
| 2849 | +511402,东坡区,4,511400 | ||
| 2850 | +511403,彭山区,4,511400 | ||
| 2851 | +511421,仁寿县,4,511400 | ||
| 2852 | +511423,洪雅县,4,511400 | ||
| 2853 | +511424,丹棱县,4,511400 | ||
| 2854 | +511425,青神县,4,511400 | ||
| 2855 | +511502,翠屏区,4,511500 | ||
| 2856 | +511503,南溪区,4,511500 | ||
| 2857 | +511504,叙州区,4,511500 | ||
| 2858 | +511523,江安县,4,511500 | ||
| 2859 | +511524,长宁县,4,511500 | ||
| 2860 | +511525,高县,4,511500 | ||
| 2861 | +511526,珙县,4,511500 | ||
| 2862 | +511527,筠连县,4,511500 | ||
| 2863 | +511528,兴文县,4,511500 | ||
| 2864 | +511529,屏山县,4,511500 | ||
| 2865 | +511602,广安区,4,511600 | ||
| 2866 | +511603,前锋区,4,511600 | ||
| 2867 | +511621,岳池县,4,511600 | ||
| 2868 | +511622,武胜县,4,511600 | ||
| 2869 | +511623,邻水县,4,511600 | ||
| 2870 | +511681,华蓥市,4,511600 | ||
| 2871 | +511702,通川区,4,511700 | ||
| 2872 | +511703,达川区,4,511700 | ||
| 2873 | +511722,宣汉县,4,511700 | ||
| 2874 | +511723,开江县,4,511700 | ||
| 2875 | +511724,大竹县,4,511700 | ||
| 2876 | +511725,渠县,4,511700 | ||
| 2877 | +511771,达州经济开发区,4,511700 | ||
| 2878 | +511781,万源市,4,511700 | ||
| 2879 | +511802,雨城区,4,511800 | ||
| 2880 | +511803,名山区,4,511800 | ||
| 2881 | +511822,荥经县,4,511800 | ||
| 2882 | +511823,汉源县,4,511800 | ||
| 2883 | +511824,石棉县,4,511800 | ||
| 2884 | +511825,天全县,4,511800 | ||
| 2885 | +511826,芦山县,4,511800 | ||
| 2886 | +511827,宝兴县,4,511800 | ||
| 2887 | +511902,巴州区,4,511900 | ||
| 2888 | +511903,恩阳区,4,511900 | ||
| 2889 | +511921,通江县,4,511900 | ||
| 2890 | +511922,南江县,4,511900 | ||
| 2891 | +511923,平昌县,4,511900 | ||
| 2892 | +511971,巴中经济开发区,4,511900 | ||
| 2893 | +512002,雁江区,4,512000 | ||
| 2894 | +512021,安岳县,4,512000 | ||
| 2895 | +512022,乐至县,4,512000 | ||
| 2896 | +513201,马尔康市,4,513200 | ||
| 2897 | +513221,汶川县,4,513200 | ||
| 2898 | +513222,理县,4,513200 | ||
| 2899 | +513223,茂县,4,513200 | ||
| 2900 | +513224,松潘县,4,513200 | ||
| 2901 | +513225,九寨沟县,4,513200 | ||
| 2902 | +513226,金川县,4,513200 | ||
| 2903 | +513227,小金县,4,513200 | ||
| 2904 | +513228,黑水县,4,513200 | ||
| 2905 | +513230,壤塘县,4,513200 | ||
| 2906 | +513231,阿坝县,4,513200 | ||
| 2907 | +513232,若尔盖县,4,513200 | ||
| 2908 | +513233,红原县,4,513200 | ||
| 2909 | +513301,康定市,4,513300 | ||
| 2910 | +513322,泸定县,4,513300 | ||
| 2911 | +513323,丹巴县,4,513300 | ||
| 2912 | +513324,九龙县,4,513300 | ||
| 2913 | +513325,雅江县,4,513300 | ||
| 2914 | +513326,道孚县,4,513300 | ||
| 2915 | +513327,炉霍县,4,513300 | ||
| 2916 | +513328,甘孜县,4,513300 | ||
| 2917 | +513329,新龙县,4,513300 | ||
| 2918 | +513330,德格县,4,513300 | ||
| 2919 | +513331,白玉县,4,513300 | ||
| 2920 | +513332,石渠县,4,513300 | ||
| 2921 | +513333,色达县,4,513300 | ||
| 2922 | +513334,理塘县,4,513300 | ||
| 2923 | +513335,巴塘县,4,513300 | ||
| 2924 | +513336,乡城县,4,513300 | ||
| 2925 | +513337,稻城县,4,513300 | ||
| 2926 | +513338,得荣县,4,513300 | ||
| 2927 | +513401,西昌市,4,513400 | ||
| 2928 | +513402,会理市,4,513400 | ||
| 2929 | +513422,木里藏族自治县,4,513400 | ||
| 2930 | +513423,盐源县,4,513400 | ||
| 2931 | +513424,德昌县,4,513400 | ||
| 2932 | +513426,会东县,4,513400 | ||
| 2933 | +513427,宁南县,4,513400 | ||
| 2934 | +513428,普格县,4,513400 | ||
| 2935 | +513429,布拖县,4,513400 | ||
| 2936 | +513430,金阳县,4,513400 | ||
| 2937 | +513431,昭觉县,4,513400 | ||
| 2938 | +513432,喜德县,4,513400 | ||
| 2939 | +513433,冕宁县,4,513400 | ||
| 2940 | +513434,越西县,4,513400 | ||
| 2941 | +513435,甘洛县,4,513400 | ||
| 2942 | +513436,美姑县,4,513400 | ||
| 2943 | +513437,雷波县,4,513400 | ||
| 2944 | +520102,南明区,4,520100 | ||
| 2945 | +520103,云岩区,4,520100 | ||
| 2946 | +520111,花溪区,4,520100 | ||
| 2947 | +520112,乌当区,4,520100 | ||
| 2948 | +520113,白云区,4,520100 | ||
| 2949 | +520115,观山湖区,4,520100 | ||
| 2950 | +520121,开阳县,4,520100 | ||
| 2951 | +520122,息烽县,4,520100 | ||
| 2952 | +520123,修文县,4,520100 | ||
| 2953 | +520181,清镇市,4,520100 | ||
| 2954 | +520201,钟山区,4,520200 | ||
| 2955 | +520203,六枝特区,4,520200 | ||
| 2956 | +520204,水城区,4,520200 | ||
| 2957 | +520281,盘州市,4,520200 | ||
| 2958 | +520302,红花岗区,4,520300 | ||
| 2959 | +520303,汇川区,4,520300 | ||
| 2960 | +520304,播州区,4,520300 | ||
| 2961 | +520322,桐梓县,4,520300 | ||
| 2962 | +520323,绥阳县,4,520300 | ||
| 2963 | +520324,正安县,4,520300 | ||
| 2964 | +520325,道真仡佬族苗族自治县,4,520300 | ||
| 2965 | +520326,务川仡佬族苗族自治县,4,520300 | ||
| 2966 | +520327,凤冈县,4,520300 | ||
| 2967 | +520328,湄潭县,4,520300 | ||
| 2968 | +520329,余庆县,4,520300 | ||
| 2969 | +520330,习水县,4,520300 | ||
| 2970 | +520381,赤水市,4,520300 | ||
| 2971 | +520382,仁怀市,4,520300 | ||
| 2972 | +520402,西秀区,4,520400 | ||
| 2973 | +520403,平坝区,4,520400 | ||
| 2974 | +520422,普定县,4,520400 | ||
| 2975 | +520423,镇宁布依族苗族自治县,4,520400 | ||
| 2976 | +520424,关岭布依族苗族自治县,4,520400 | ||
| 2977 | +520425,紫云苗族布依族自治县,4,520400 | ||
| 2978 | +520502,七星关区,4,520500 | ||
| 2979 | +520521,大方县,4,520500 | ||
| 2980 | +520523,金沙县,4,520500 | ||
| 2981 | +520524,织金县,4,520500 | ||
| 2982 | +520525,纳雍县,4,520500 | ||
| 2983 | +520526,威宁彝族回族苗族自治县,4,520500 | ||
| 2984 | +520527,赫章县,4,520500 | ||
| 2985 | +520581,黔西市,4,520500 | ||
| 2986 | +520602,碧江区,4,520600 | ||
| 2987 | +520603,万山区,4,520600 | ||
| 2988 | +520621,江口县,4,520600 | ||
| 2989 | +520622,玉屏侗族自治县,4,520600 | ||
| 2990 | +520623,石阡县,4,520600 | ||
| 2991 | +520624,思南县,4,520600 | ||
| 2992 | +520625,印江土家族苗族自治县,4,520600 | ||
| 2993 | +520626,德江县,4,520600 | ||
| 2994 | +520627,沿河土家族自治县,4,520600 | ||
| 2995 | +520628,松桃苗族自治县,4,520600 | ||
| 2996 | +522301,兴义市,4,522300 | ||
| 2997 | +522302,兴仁市,4,522300 | ||
| 2998 | +522323,普安县,4,522300 | ||
| 2999 | +522324,晴隆县,4,522300 | ||
| 3000 | +522325,贞丰县,4,522300 | ||
| 3001 | +522326,望谟县,4,522300 | ||
| 3002 | +522327,册亨县,4,522300 | ||
| 3003 | +522328,安龙县,4,522300 | ||
| 3004 | +522601,凯里市,4,522600 | ||
| 3005 | +522622,黄平县,4,522600 | ||
| 3006 | +522623,施秉县,4,522600 | ||
| 3007 | +522624,三穗县,4,522600 | ||
| 3008 | +522625,镇远县,4,522600 | ||
| 3009 | +522626,岑巩县,4,522600 | ||
| 3010 | +522627,天柱县,4,522600 | ||
| 3011 | +522628,锦屏县,4,522600 | ||
| 3012 | +522629,剑河县,4,522600 | ||
| 3013 | +522630,台江县,4,522600 | ||
| 3014 | +522631,黎平县,4,522600 | ||
| 3015 | +522632,榕江县,4,522600 | ||
| 3016 | +522633,从江县,4,522600 | ||
| 3017 | +522634,雷山县,4,522600 | ||
| 3018 | +522635,麻江县,4,522600 | ||
| 3019 | +522636,丹寨县,4,522600 | ||
| 3020 | +522701,都匀市,4,522700 | ||
| 3021 | +522702,福泉市,4,522700 | ||
| 3022 | +522722,荔波县,4,522700 | ||
| 3023 | +522723,贵定县,4,522700 | ||
| 3024 | +522725,瓮安县,4,522700 | ||
| 3025 | +522726,独山县,4,522700 | ||
| 3026 | +522727,平塘县,4,522700 | ||
| 3027 | +522728,罗甸县,4,522700 | ||
| 3028 | +522729,长顺县,4,522700 | ||
| 3029 | +522730,龙里县,4,522700 | ||
| 3030 | +522731,惠水县,4,522700 | ||
| 3031 | +522732,三都水族自治县,4,522700 | ||
| 3032 | +530102,五华区,4,530100 | ||
| 3033 | +530103,盘龙区,4,530100 | ||
| 3034 | +530111,官渡区,4,530100 | ||
| 3035 | +530112,西山区,4,530100 | ||
| 3036 | +530113,东川区,4,530100 | ||
| 3037 | +530114,呈贡区,4,530100 | ||
| 3038 | +530115,晋宁区,4,530100 | ||
| 3039 | +530124,富民县,4,530100 | ||
| 3040 | +530125,宜良县,4,530100 | ||
| 3041 | +530126,石林彝族自治县,4,530100 | ||
| 3042 | +530127,嵩明县,4,530100 | ||
| 3043 | +530128,禄劝彝族苗族自治县,4,530100 | ||
| 3044 | +530129,寻甸回族彝族自治县,4,530100 | ||
| 3045 | +530181,安宁市,4,530100 | ||
| 3046 | +530302,麒麟区,4,530300 | ||
| 3047 | +530303,沾益区,4,530300 | ||
| 3048 | +530304,马龙区,4,530300 | ||
| 3049 | +530322,陆良县,4,530300 | ||
| 3050 | +530323,师宗县,4,530300 | ||
| 3051 | +530324,罗平县,4,530300 | ||
| 3052 | +530325,富源县,4,530300 | ||
| 3053 | +530326,会泽县,4,530300 | ||
| 3054 | +530381,宣威市,4,530300 | ||
| 3055 | +530402,红塔区,4,530400 | ||
| 3056 | +530403,江川区,4,530400 | ||
| 3057 | +530423,通海县,4,530400 | ||
| 3058 | +530424,华宁县,4,530400 | ||
| 3059 | +530425,易门县,4,530400 | ||
| 3060 | +530426,峨山彝族自治县,4,530400 | ||
| 3061 | +530427,新平彝族傣族自治县,4,530400 | ||
| 3062 | +530428,元江哈尼族彝族傣族自治县,4,530400 | ||
| 3063 | +530481,澄江市,4,530400 | ||
| 3064 | +530502,隆阳区,4,530500 | ||
| 3065 | +530521,施甸县,4,530500 | ||
| 3066 | +530523,龙陵县,4,530500 | ||
| 3067 | +530524,昌宁县,4,530500 | ||
| 3068 | +530581,腾冲市,4,530500 | ||
| 3069 | +530602,昭阳区,4,530600 | ||
| 3070 | +530621,鲁甸县,4,530600 | ||
| 3071 | +530622,巧家县,4,530600 | ||
| 3072 | +530623,盐津县,4,530600 | ||
| 3073 | +530624,大关县,4,530600 | ||
| 3074 | +530625,永善县,4,530600 | ||
| 3075 | +530626,绥江县,4,530600 | ||
| 3076 | +530627,镇雄县,4,530600 | ||
| 3077 | +530628,彝良县,4,530600 | ||
| 3078 | +530629,威信县,4,530600 | ||
| 3079 | +530681,水富市,4,530600 | ||
| 3080 | +530702,古城区,4,530700 | ||
| 3081 | +530721,玉龙纳西族自治县,4,530700 | ||
| 3082 | +530722,永胜县,4,530700 | ||
| 3083 | +530723,华坪县,4,530700 | ||
| 3084 | +530724,宁蒗彝族自治县,4,530700 | ||
| 3085 | +530802,思茅区,4,530800 | ||
| 3086 | +530821,宁洱哈尼族彝族自治县,4,530800 | ||
| 3087 | +530822,墨江哈尼族自治县,4,530800 | ||
| 3088 | +530823,景东彝族自治县,4,530800 | ||
| 3089 | +530824,景谷傣族彝族自治县,4,530800 | ||
| 3090 | +530825,镇沅彝族哈尼族拉祜族自治县,4,530800 | ||
| 3091 | +530826,江城哈尼族彝族自治县,4,530800 | ||
| 3092 | +530827,孟连傣族拉祜族佤族自治县,4,530800 | ||
| 3093 | +530828,澜沧拉祜族自治县,4,530800 | ||
| 3094 | +530829,西盟佤族自治县,4,530800 | ||
| 3095 | +530902,临翔区,4,530900 | ||
| 3096 | +530921,凤庆县,4,530900 | ||
| 3097 | +530922,云县,4,530900 | ||
| 3098 | +530923,永德县,4,530900 | ||
| 3099 | +530924,镇康县,4,530900 | ||
| 3100 | +530925,双江拉祜族佤族布朗族傣族自治县,4,530900 | ||
| 3101 | +530926,耿马傣族佤族自治县,4,530900 | ||
| 3102 | +530927,沧源佤族自治县,4,530900 | ||
| 3103 | +532301,楚雄市,4,532300 | ||
| 3104 | +532302,禄丰市,4,532300 | ||
| 3105 | +532322,双柏县,4,532300 | ||
| 3106 | +532323,牟定县,4,532300 | ||
| 3107 | +532324,南华县,4,532300 | ||
| 3108 | +532325,姚安县,4,532300 | ||
| 3109 | +532326,大姚县,4,532300 | ||
| 3110 | +532327,永仁县,4,532300 | ||
| 3111 | +532328,元谋县,4,532300 | ||
| 3112 | +532329,武定县,4,532300 | ||
| 3113 | +532501,个旧市,4,532500 | ||
| 3114 | +532502,开远市,4,532500 | ||
| 3115 | +532503,蒙自市,4,532500 | ||
| 3116 | +532504,弥勒市,4,532500 | ||
| 3117 | +532523,屏边苗族自治县,4,532500 | ||
| 3118 | +532524,建水县,4,532500 | ||
| 3119 | +532525,石屏县,4,532500 | ||
| 3120 | +532527,泸西县,4,532500 | ||
| 3121 | +532528,元阳县,4,532500 | ||
| 3122 | +532529,红河县,4,532500 | ||
| 3123 | +532530,金平苗族瑶族傣族自治县,4,532500 | ||
| 3124 | +532531,绿春县,4,532500 | ||
| 3125 | +532532,河口瑶族自治县,4,532500 | ||
| 3126 | +532601,文山市,4,532600 | ||
| 3127 | +532622,砚山县,4,532600 | ||
| 3128 | +532623,西畴县,4,532600 | ||
| 3129 | +532624,麻栗坡县,4,532600 | ||
| 3130 | +532625,马关县,4,532600 | ||
| 3131 | +532626,丘北县,4,532600 | ||
| 3132 | +532627,广南县,4,532600 | ||
| 3133 | +532628,富宁县,4,532600 | ||
| 3134 | +532801,景洪市,4,532800 | ||
| 3135 | +532822,勐海县,4,532800 | ||
| 3136 | +532823,勐腊县,4,532800 | ||
| 3137 | +532901,大理市,4,532900 | ||
| 3138 | +532922,漾濞彝族自治县,4,532900 | ||
| 3139 | +532923,祥云县,4,532900 | ||
| 3140 | +532924,宾川县,4,532900 | ||
| 3141 | +532925,弥渡县,4,532900 | ||
| 3142 | +532926,南涧彝族自治县,4,532900 | ||
| 3143 | +532927,巍山彝族回族自治县,4,532900 | ||
| 3144 | +532928,永平县,4,532900 | ||
| 3145 | +532929,云龙县,4,532900 | ||
| 3146 | +532930,洱源县,4,532900 | ||
| 3147 | +532931,剑川县,4,532900 | ||
| 3148 | +532932,鹤庆县,4,532900 | ||
| 3149 | +533102,瑞丽市,4,533100 | ||
| 3150 | +533103,芒市,4,533100 | ||
| 3151 | +533122,梁河县,4,533100 | ||
| 3152 | +533123,盈江县,4,533100 | ||
| 3153 | +533124,陇川县,4,533100 | ||
| 3154 | +533301,泸水市,4,533300 | ||
| 3155 | +533323,福贡县,4,533300 | ||
| 3156 | +533324,贡山独龙族怒族自治县,4,533300 | ||
| 3157 | +533325,兰坪白族普米族自治县,4,533300 | ||
| 3158 | +533401,香格里拉市,4,533400 | ||
| 3159 | +533422,德钦县,4,533400 | ||
| 3160 | +533423,维西傈僳族自治县,4,533400 | ||
| 3161 | +540102,城关区,4,540100 | ||
| 3162 | +540103,堆龙德庆区,4,540100 | ||
| 3163 | +540104,达孜区,4,540100 | ||
| 3164 | +540121,林周县,4,540100 | ||
| 3165 | +540122,当雄县,4,540100 | ||
| 3166 | +540123,尼木县,4,540100 | ||
| 3167 | +540124,曲水县,4,540100 | ||
| 3168 | +540127,墨竹工卡县,4,540100 | ||
| 3169 | +540171,格尔木藏青工业园区,4,540100 | ||
| 3170 | +540172,拉萨经济技术开发区,4,540100 | ||
| 3171 | +540173,西藏文化旅游创意园区,4,540100 | ||
| 3172 | +540174,达孜工业园区,4,540100 | ||
| 3173 | +540202,桑珠孜区,4,540200 | ||
| 3174 | +540221,南木林县,4,540200 | ||
| 3175 | +540222,江孜县,4,540200 | ||
| 3176 | +540223,定日县,4,540200 | ||
| 3177 | +540224,萨迦县,4,540200 | ||
| 3178 | +540225,拉孜县,4,540200 | ||
| 3179 | +540226,昂仁县,4,540200 | ||
| 3180 | +540227,谢通门县,4,540200 | ||
| 3181 | +540228,白朗县,4,540200 | ||
| 3182 | +540229,仁布县,4,540200 | ||
| 3183 | +540230,康马县,4,540200 | ||
| 3184 | +540231,定结县,4,540200 | ||
| 3185 | +540232,仲巴县,4,540200 | ||
| 3186 | +540233,亚东县,4,540200 | ||
| 3187 | +540234,吉隆县,4,540200 | ||
| 3188 | +540235,聂拉木县,4,540200 | ||
| 3189 | +540236,萨嘎县,4,540200 | ||
| 3190 | +540237,岗巴县,4,540200 | ||
| 3191 | +540302,卡若区,4,540300 | ||
| 3192 | +540321,江达县,4,540300 | ||
| 3193 | +540322,贡觉县,4,540300 | ||
| 3194 | +540323,类乌齐县,4,540300 | ||
| 3195 | +540324,丁青县,4,540300 | ||
| 3196 | +540325,察雅县,4,540300 | ||
| 3197 | +540326,八宿县,4,540300 | ||
| 3198 | +540327,左贡县,4,540300 | ||
| 3199 | +540328,芒康县,4,540300 | ||
| 3200 | +540329,洛隆县,4,540300 | ||
| 3201 | +540330,边坝县,4,540300 | ||
| 3202 | +540402,巴宜区,4,540400 | ||
| 3203 | +540421,工布江达县,4,540400 | ||
| 3204 | +540422,米林县,4,540400 | ||
| 3205 | +540423,墨脱县,4,540400 | ||
| 3206 | +540424,波密县,4,540400 | ||
| 3207 | +540425,察隅县,4,540400 | ||
| 3208 | +540426,朗县,4,540400 | ||
| 3209 | +540502,乃东区,4,540500 | ||
| 3210 | +540521,扎囊县,4,540500 | ||
| 3211 | +540522,贡嘎县,4,540500 | ||
| 3212 | +540523,桑日县,4,540500 | ||
| 3213 | +540524,琼结县,4,540500 | ||
| 3214 | +540525,曲松县,4,540500 | ||
| 3215 | +540526,措美县,4,540500 | ||
| 3216 | +540527,洛扎县,4,540500 | ||
| 3217 | +540528,加查县,4,540500 | ||
| 3218 | +540529,隆子县,4,540500 | ||
| 3219 | +540530,错那县,4,540500 | ||
| 3220 | +540531,浪卡子县,4,540500 | ||
| 3221 | +540602,色尼区,4,540600 | ||
| 3222 | +540621,嘉黎县,4,540600 | ||
| 3223 | +540622,比如县,4,540600 | ||
| 3224 | +540623,聂荣县,4,540600 | ||
| 3225 | +540624,安多县,4,540600 | ||
| 3226 | +540625,申扎县,4,540600 | ||
| 3227 | +540626,索县,4,540600 | ||
| 3228 | +540627,班戈县,4,540600 | ||
| 3229 | +540628,巴青县,4,540600 | ||
| 3230 | +540629,尼玛县,4,540600 | ||
| 3231 | +540630,双湖县,4,540600 | ||
| 3232 | +542521,普兰县,4,542500 | ||
| 3233 | +542522,札达县,4,542500 | ||
| 3234 | +542523,噶尔县,4,542500 | ||
| 3235 | +542524,日土县,4,542500 | ||
| 3236 | +542525,革吉县,4,542500 | ||
| 3237 | +542526,改则县,4,542500 | ||
| 3238 | +542527,措勤县,4,542500 | ||
| 3239 | +610102,新城区,4,610100 | ||
| 3240 | +610103,碑林区,4,610100 | ||
| 3241 | +610104,莲湖区,4,610100 | ||
| 3242 | +610111,灞桥区,4,610100 | ||
| 3243 | +610112,未央区,4,610100 | ||
| 3244 | +610113,雁塔区,4,610100 | ||
| 3245 | +610114,阎良区,4,610100 | ||
| 3246 | +610115,临潼区,4,610100 | ||
| 3247 | +610116,长安区,4,610100 | ||
| 3248 | +610117,高陵区,4,610100 | ||
| 3249 | +610118,鄠邑区,4,610100 | ||
| 3250 | +610122,蓝田县,4,610100 | ||
| 3251 | +610124,周至县,4,610100 | ||
| 3252 | +610202,王益区,4,610200 | ||
| 3253 | +610203,印台区,4,610200 | ||
| 3254 | +610204,耀州区,4,610200 | ||
| 3255 | +610222,宜君县,4,610200 | ||
| 3256 | +610302,渭滨区,4,610300 | ||
| 3257 | +610303,金台区,4,610300 | ||
| 3258 | +610304,陈仓区,4,610300 | ||
| 3259 | +610305,凤翔区,4,610300 | ||
| 3260 | +610323,岐山县,4,610300 | ||
| 3261 | +610324,扶风县,4,610300 | ||
| 3262 | +610326,眉县,4,610300 | ||
| 3263 | +610327,陇县,4,610300 | ||
| 3264 | +610328,千阳县,4,610300 | ||
| 3265 | +610329,麟游县,4,610300 | ||
| 3266 | +610330,凤县,4,610300 | ||
| 3267 | +610331,太白县,4,610300 | ||
| 3268 | +610402,秦都区,4,610400 | ||
| 3269 | +610403,杨陵区,4,610400 | ||
| 3270 | +610404,渭城区,4,610400 | ||
| 3271 | +610422,三原县,4,610400 | ||
| 3272 | +610423,泾阳县,4,610400 | ||
| 3273 | +610424,乾县,4,610400 | ||
| 3274 | +610425,礼泉县,4,610400 | ||
| 3275 | +610426,永寿县,4,610400 | ||
| 3276 | +610428,长武县,4,610400 | ||
| 3277 | +610429,旬邑县,4,610400 | ||
| 3278 | +610430,淳化县,4,610400 | ||
| 3279 | +610431,武功县,4,610400 | ||
| 3280 | +610481,兴平市,4,610400 | ||
| 3281 | +610482,彬州市,4,610400 | ||
| 3282 | +610502,临渭区,4,610500 | ||
| 3283 | +610503,华州区,4,610500 | ||
| 3284 | +610522,潼关县,4,610500 | ||
| 3285 | +610523,大荔县,4,610500 | ||
| 3286 | +610524,合阳县,4,610500 | ||
| 3287 | +610525,澄城县,4,610500 | ||
| 3288 | +610526,蒲城县,4,610500 | ||
| 3289 | +610527,白水县,4,610500 | ||
| 3290 | +610528,富平县,4,610500 | ||
| 3291 | +610581,韩城市,4,610500 | ||
| 3292 | +610582,华阴市,4,610500 | ||
| 3293 | +610602,宝塔区,4,610600 | ||
| 3294 | +610603,安塞区,4,610600 | ||
| 3295 | +610621,延长县,4,610600 | ||
| 3296 | +610622,延川县,4,610600 | ||
| 3297 | +610625,志丹县,4,610600 | ||
| 3298 | +610626,吴起县,4,610600 | ||
| 3299 | +610627,甘泉县,4,610600 | ||
| 3300 | +610628,富县,4,610600 | ||
| 3301 | +610629,洛川县,4,610600 | ||
| 3302 | +610630,宜川县,4,610600 | ||
| 3303 | +610631,黄龙县,4,610600 | ||
| 3304 | +610632,黄陵县,4,610600 | ||
| 3305 | +610681,子长市,4,610600 | ||
| 3306 | +610702,汉台区,4,610700 | ||
| 3307 | +610703,南郑区,4,610700 | ||
| 3308 | +610722,城固县,4,610700 | ||
| 3309 | +610723,洋县,4,610700 | ||
| 3310 | +610724,西乡县,4,610700 | ||
| 3311 | +610725,勉县,4,610700 | ||
| 3312 | +610726,宁强县,4,610700 | ||
| 3313 | +610727,略阳县,4,610700 | ||
| 3314 | +610728,镇巴县,4,610700 | ||
| 3315 | +610729,留坝县,4,610700 | ||
| 3316 | +610730,佛坪县,4,610700 | ||
| 3317 | +610802,榆阳区,4,610800 | ||
| 3318 | +610803,横山区,4,610800 | ||
| 3319 | +610822,府谷县,4,610800 | ||
| 3320 | +610824,靖边县,4,610800 | ||
| 3321 | +610825,定边县,4,610800 | ||
| 3322 | +610826,绥德县,4,610800 | ||
| 3323 | +610827,米脂县,4,610800 | ||
| 3324 | +610828,佳县,4,610800 | ||
| 3325 | +610829,吴堡县,4,610800 | ||
| 3326 | +610830,清涧县,4,610800 | ||
| 3327 | +610831,子洲县,4,610800 | ||
| 3328 | +610881,神木市,4,610800 | ||
| 3329 | +610902,汉滨区,4,610900 | ||
| 3330 | +610921,汉阴县,4,610900 | ||
| 3331 | +610922,石泉县,4,610900 | ||
| 3332 | +610923,宁陕县,4,610900 | ||
| 3333 | +610924,紫阳县,4,610900 | ||
| 3334 | +610925,岚皋县,4,610900 | ||
| 3335 | +610926,平利县,4,610900 | ||
| 3336 | +610927,镇坪县,4,610900 | ||
| 3337 | +610929,白河县,4,610900 | ||
| 3338 | +610981,旬阳市,4,610900 | ||
| 3339 | +611002,商州区,4,611000 | ||
| 3340 | +611021,洛南县,4,611000 | ||
| 3341 | +611022,丹凤县,4,611000 | ||
| 3342 | +611023,商南县,4,611000 | ||
| 3343 | +611024,山阳县,4,611000 | ||
| 3344 | +611025,镇安县,4,611000 | ||
| 3345 | +611026,柞水县,4,611000 | ||
| 3346 | +620102,城关区,4,620100 | ||
| 3347 | +620103,七里河区,4,620100 | ||
| 3348 | +620104,西固区,4,620100 | ||
| 3349 | +620105,安宁区,4,620100 | ||
| 3350 | +620111,红古区,4,620100 | ||
| 3351 | +620121,永登县,4,620100 | ||
| 3352 | +620122,皋兰县,4,620100 | ||
| 3353 | +620123,榆中县,4,620100 | ||
| 3354 | +620171,兰州新区,4,620100 | ||
| 3355 | +620201,嘉峪关市,4,620200 | ||
| 3356 | +620302,金川区,4,620300 | ||
| 3357 | +620321,永昌县,4,620300 | ||
| 3358 | +620402,白银区,4,620400 | ||
| 3359 | +620403,平川区,4,620400 | ||
| 3360 | +620421,靖远县,4,620400 | ||
| 3361 | +620422,会宁县,4,620400 | ||
| 3362 | +620423,景泰县,4,620400 | ||
| 3363 | +620502,秦州区,4,620500 | ||
| 3364 | +620503,麦积区,4,620500 | ||
| 3365 | +620521,清水县,4,620500 | ||
| 3366 | +620522,秦安县,4,620500 | ||
| 3367 | +620523,甘谷县,4,620500 | ||
| 3368 | +620524,武山县,4,620500 | ||
| 3369 | +620525,张家川回族自治县,4,620500 | ||
| 3370 | +620602,凉州区,4,620600 | ||
| 3371 | +620621,民勤县,4,620600 | ||
| 3372 | +620622,古浪县,4,620600 | ||
| 3373 | +620623,天祝藏族自治县,4,620600 | ||
| 3374 | +620702,甘州区,4,620700 | ||
| 3375 | +620721,肃南裕固族自治县,4,620700 | ||
| 3376 | +620722,民乐县,4,620700 | ||
| 3377 | +620723,临泽县,4,620700 | ||
| 3378 | +620724,高台县,4,620700 | ||
| 3379 | +620725,山丹县,4,620700 | ||
| 3380 | +620802,崆峒区,4,620800 | ||
| 3381 | +620821,泾川县,4,620800 | ||
| 3382 | +620822,灵台县,4,620800 | ||
| 3383 | +620823,崇信县,4,620800 | ||
| 3384 | +620825,庄浪县,4,620800 | ||
| 3385 | +620826,静宁县,4,620800 | ||
| 3386 | +620881,华亭市,4,620800 | ||
| 3387 | +620902,肃州区,4,620900 | ||
| 3388 | +620921,金塔县,4,620900 | ||
| 3389 | +620922,瓜州县,4,620900 | ||
| 3390 | +620923,肃北蒙古族自治县,4,620900 | ||
| 3391 | +620924,阿克塞哈萨克族自治县,4,620900 | ||
| 3392 | +620981,玉门市,4,620900 | ||
| 3393 | +620982,敦煌市,4,620900 | ||
| 3394 | +621002,西峰区,4,621000 | ||
| 3395 | +621021,庆城县,4,621000 | ||
| 3396 | +621022,环县,4,621000 | ||
| 3397 | +621023,华池县,4,621000 | ||
| 3398 | +621024,合水县,4,621000 | ||
| 3399 | +621025,正宁县,4,621000 | ||
| 3400 | +621026,宁县,4,621000 | ||
| 3401 | +621027,镇原县,4,621000 | ||
| 3402 | +621102,安定区,4,621100 | ||
| 3403 | +621121,通渭县,4,621100 | ||
| 3404 | +621122,陇西县,4,621100 | ||
| 3405 | +621123,渭源县,4,621100 | ||
| 3406 | +621124,临洮县,4,621100 | ||
| 3407 | +621125,漳县,4,621100 | ||
| 3408 | +621126,岷县,4,621100 | ||
| 3409 | +621202,武都区,4,621200 | ||
| 3410 | +621221,成县,4,621200 | ||
| 3411 | +621222,文县,4,621200 | ||
| 3412 | +621223,宕昌县,4,621200 | ||
| 3413 | +621224,康县,4,621200 | ||
| 3414 | +621225,西和县,4,621200 | ||
| 3415 | +621226,礼县,4,621200 | ||
| 3416 | +621227,徽县,4,621200 | ||
| 3417 | +621228,两当县,4,621200 | ||
| 3418 | +622901,临夏市,4,622900 | ||
| 3419 | +622921,临夏县,4,622900 | ||
| 3420 | +622922,康乐县,4,622900 | ||
| 3421 | +622923,永靖县,4,622900 | ||
| 3422 | +622924,广河县,4,622900 | ||
| 3423 | +622925,和政县,4,622900 | ||
| 3424 | +622926,东乡族自治县,4,622900 | ||
| 3425 | +622927,积石山保安族东乡族撒拉族自治县,4,622900 | ||
| 3426 | +623001,合作市,4,623000 | ||
| 3427 | +623021,临潭县,4,623000 | ||
| 3428 | +623022,卓尼县,4,623000 | ||
| 3429 | +623023,舟曲县,4,623000 | ||
| 3430 | +623024,迭部县,4,623000 | ||
| 3431 | +623025,玛曲县,4,623000 | ||
| 3432 | +623026,碌曲县,4,623000 | ||
| 3433 | +623027,夏河县,4,623000 | ||
| 3434 | +630102,城东区,4,630100 | ||
| 3435 | +630103,城中区,4,630100 | ||
| 3436 | +630104,城西区,4,630100 | ||
| 3437 | +630105,城北区,4,630100 | ||
| 3438 | +630106,湟中区,4,630100 | ||
| 3439 | +630121,大通回族土族自治县,4,630100 | ||
| 3440 | +630123,湟源县,4,630100 | ||
| 3441 | +630202,乐都区,4,630200 | ||
| 3442 | +630203,平安区,4,630200 | ||
| 3443 | +630222,民和回族土族自治县,4,630200 | ||
| 3444 | +630223,互助土族自治县,4,630200 | ||
| 3445 | +630224,化隆回族自治县,4,630200 | ||
| 3446 | +630225,循化撒拉族自治县,4,630200 | ||
| 3447 | +632221,门源回族自治县,4,632200 | ||
| 3448 | +632222,祁连县,4,632200 | ||
| 3449 | +632223,海晏县,4,632200 | ||
| 3450 | +632224,刚察县,4,632200 | ||
| 3451 | +632301,同仁市,4,632300 | ||
| 3452 | +632322,尖扎县,4,632300 | ||
| 3453 | +632323,泽库县,4,632300 | ||
| 3454 | +632324,河南蒙古族自治县,4,632300 | ||
| 3455 | +632521,共和县,4,632500 | ||
| 3456 | +632522,同德县,4,632500 | ||
| 3457 | +632523,贵德县,4,632500 | ||
| 3458 | +632524,兴海县,4,632500 | ||
| 3459 | +632525,贵南县,4,632500 | ||
| 3460 | +632621,玛沁县,4,632600 | ||
| 3461 | +632622,班玛县,4,632600 | ||
| 3462 | +632623,甘德县,4,632600 | ||
| 3463 | +632624,达日县,4,632600 | ||
| 3464 | +632625,久治县,4,632600 | ||
| 3465 | +632626,玛多县,4,632600 | ||
| 3466 | +632701,玉树市,4,632700 | ||
| 3467 | +632722,杂多县,4,632700 | ||
| 3468 | +632723,称多县,4,632700 | ||
| 3469 | +632724,治多县,4,632700 | ||
| 3470 | +632725,囊谦县,4,632700 | ||
| 3471 | +632726,曲麻莱县,4,632700 | ||
| 3472 | +632801,格尔木市,4,632800 | ||
| 3473 | +632802,德令哈市,4,632800 | ||
| 3474 | +632803,茫崖市,4,632800 | ||
| 3475 | +632821,乌兰县,4,632800 | ||
| 3476 | +632822,都兰县,4,632800 | ||
| 3477 | +632823,天峻县,4,632800 | ||
| 3478 | +632857,大柴旦行政委员会,4,632800 | ||
| 3479 | +640104,兴庆区,4,640100 | ||
| 3480 | +640105,西夏区,4,640100 | ||
| 3481 | +640106,金凤区,4,640100 | ||
| 3482 | +640121,永宁县,4,640100 | ||
| 3483 | +640122,贺兰县,4,640100 | ||
| 3484 | +640181,灵武市,4,640100 | ||
| 3485 | +640202,大武口区,4,640200 | ||
| 3486 | +640205,惠农区,4,640200 | ||
| 3487 | +640221,平罗县,4,640200 | ||
| 3488 | +640302,利通区,4,640300 | ||
| 3489 | +640303,红寺堡区,4,640300 | ||
| 3490 | +640323,盐池县,4,640300 | ||
| 3491 | +640324,同心县,4,640300 | ||
| 3492 | +640381,青铜峡市,4,640300 | ||
| 3493 | +640402,原州区,4,640400 | ||
| 3494 | +640422,西吉县,4,640400 | ||
| 3495 | +640423,隆德县,4,640400 | ||
| 3496 | +640424,泾源县,4,640400 | ||
| 3497 | +640425,彭阳县,4,640400 | ||
| 3498 | +640502,沙坡头区,4,640500 | ||
| 3499 | +640521,中宁县,4,640500 | ||
| 3500 | +640522,海原县,4,640500 | ||
| 3501 | +650102,天山区,4,650100 | ||
| 3502 | +650103,沙依巴克区,4,650100 | ||
| 3503 | +650104,新市区,4,650100 | ||
| 3504 | +650105,水磨沟区,4,650100 | ||
| 3505 | +650106,头屯河区,4,650100 | ||
| 3506 | +650107,达坂城区,4,650100 | ||
| 3507 | +650109,米东区,4,650100 | ||
| 3508 | +650121,乌鲁木齐县,4,650100 | ||
| 3509 | +650202,独山子区,4,650200 | ||
| 3510 | +650203,克拉玛依区,4,650200 | ||
| 3511 | +650204,白碱滩区,4,650200 | ||
| 3512 | +650205,乌尔禾区,4,650200 | ||
| 3513 | +650402,高昌区,4,650400 | ||
| 3514 | +650421,鄯善县,4,650400 | ||
| 3515 | +650422,托克逊县,4,650400 | ||
| 3516 | +650502,伊州区,4,650500 | ||
| 3517 | +650521,巴里坤哈萨克自治县,4,650500 | ||
| 3518 | +650522,伊吾县,4,650500 | ||
| 3519 | +652301,昌吉市,4,652300 | ||
| 3520 | +652302,阜康市,4,652300 | ||
| 3521 | +652323,呼图壁县,4,652300 | ||
| 3522 | +652324,玛纳斯县,4,652300 | ||
| 3523 | +652325,奇台县,4,652300 | ||
| 3524 | +652327,吉木萨尔县,4,652300 | ||
| 3525 | +652328,木垒哈萨克自治县,4,652300 | ||
| 3526 | +652701,博乐市,4,652700 | ||
| 3527 | +652702,阿拉山口市,4,652700 | ||
| 3528 | +652722,精河县,4,652700 | ||
| 3529 | +652723,温泉县,4,652700 | ||
| 3530 | +652801,库尔勒市,4,652800 | ||
| 3531 | +652822,轮台县,4,652800 | ||
| 3532 | +652823,尉犁县,4,652800 | ||
| 3533 | +652824,若羌县,4,652800 | ||
| 3534 | +652825,且末县,4,652800 | ||
| 3535 | +652826,焉耆回族自治县,4,652800 | ||
| 3536 | +652827,和静县,4,652800 | ||
| 3537 | +652828,和硕县,4,652800 | ||
| 3538 | +652829,博湖县,4,652800 | ||
| 3539 | +652871,库尔勒经济技术开发区,4,652800 | ||
| 3540 | +652901,阿克苏市,4,652900 | ||
| 3541 | +652902,库车市,4,652900 | ||
| 3542 | +652922,温宿县,4,652900 | ||
| 3543 | +652924,沙雅县,4,652900 | ||
| 3544 | +652925,新和县,4,652900 | ||
| 3545 | +652926,拜城县,4,652900 | ||
| 3546 | +652927,乌什县,4,652900 | ||
| 3547 | +652928,阿瓦提县,4,652900 | ||
| 3548 | +652929,柯坪县,4,652900 | ||
| 3549 | +653001,阿图什市,4,653000 | ||
| 3550 | +653022,阿克陶县,4,653000 | ||
| 3551 | +653023,阿合奇县,4,653000 | ||
| 3552 | +653024,乌恰县,4,653000 | ||
| 3553 | +653101,喀什市,4,653100 | ||
| 3554 | +653121,疏附县,4,653100 | ||
| 3555 | +653122,疏勒县,4,653100 | ||
| 3556 | +653123,英吉沙县,4,653100 | ||
| 3557 | +653124,泽普县,4,653100 | ||
| 3558 | +653125,莎车县,4,653100 | ||
| 3559 | +653126,叶城县,4,653100 | ||
| 3560 | +653127,麦盖提县,4,653100 | ||
| 3561 | +653128,岳普湖县,4,653100 | ||
| 3562 | +653129,伽师县,4,653100 | ||
| 3563 | +653130,巴楚县,4,653100 | ||
| 3564 | +653131,塔什库尔干塔吉克自治县,4,653100 | ||
| 3565 | +653201,和田市,4,653200 | ||
| 3566 | +653221,和田县,4,653200 | ||
| 3567 | +653222,墨玉县,4,653200 | ||
| 3568 | +653223,皮山县,4,653200 | ||
| 3569 | +653224,洛浦县,4,653200 | ||
| 3570 | +653225,策勒县,4,653200 | ||
| 3571 | +653226,于田县,4,653200 | ||
| 3572 | +653227,民丰县,4,653200 | ||
| 3573 | +654002,伊宁市,4,654000 | ||
| 3574 | +654003,奎屯市,4,654000 | ||
| 3575 | +654004,霍尔果斯市,4,654000 | ||
| 3576 | +654021,伊宁县,4,654000 | ||
| 3577 | +654022,察布查尔锡伯自治县,4,654000 | ||
| 3578 | +654023,霍城县,4,654000 | ||
| 3579 | +654024,巩留县,4,654000 | ||
| 3580 | +654025,新源县,4,654000 | ||
| 3581 | +654026,昭苏县,4,654000 | ||
| 3582 | +654027,特克斯县,4,654000 | ||
| 3583 | +654028,尼勒克县,4,654000 | ||
| 3584 | +654201,塔城市,4,654200 | ||
| 3585 | +654202,乌苏市,4,654200 | ||
| 3586 | +654203,沙湾市,4,654200 | ||
| 3587 | +654221,额敏县,4,654200 | ||
| 3588 | +654224,托里县,4,654200 | ||
| 3589 | +654225,裕民县,4,654200 | ||
| 3590 | +654226,和布克赛尔蒙古自治县,4,654200 | ||
| 3591 | +654301,阿勒泰市,4,654300 | ||
| 3592 | +654321,布尔津县,4,654300 | ||
| 3593 | +654322,富蕴县,4,654300 | ||
| 3594 | +654323,福海县,4,654300 | ||
| 3595 | +654324,哈巴河县,4,654300 | ||
| 3596 | +654325,青河县,4,654300 | ||
| 3597 | +654326,吉木乃县,4,654300 | ||
| 3598 | +659001,石河子市,4,659000 | ||
| 3599 | +659002,阿拉尔市,4,659000 | ||
| 3600 | +659003,图木舒克市,4,659000 | ||
| 3601 | +659004,五家渠市,4,659000 | ||
| 3602 | +659005,北屯市,4,659000 | ||
| 3603 | +659006,铁门关市,4,659000 | ||
| 3604 | +659007,双河市,4,659000 | ||
| 3605 | +659008,可克达拉市,4,659000 | ||
| 3606 | +659009,昆玉市,4,659000 | ||
| 3607 | +659010,胡杨河市,4,659000 | ||
| 3608 | +659011,新星市,4,659000 |
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/ip2region.xdb
0 → 100644
No preview for this file type
yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtilsTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ip.core.utils; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import cn.iocoder.yudao.framework.ip.core.Area; | ||
| 5 | +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; | ||
| 6 | +import org.junit.jupiter.api.Test; | ||
| 7 | + | ||
| 8 | +import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * {@link AreaUtils} 的单元测试 | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +public class AreaUtilsTest { | ||
| 16 | + | ||
| 17 | + @Test | ||
| 18 | + public void testGetArea() { | ||
| 19 | + // 调用:北京 | ||
| 20 | + Area area = AreaUtils.getArea(110100); | ||
| 21 | + // 断言 | ||
| 22 | + assertEquals(area.getId(), 110100); | ||
| 23 | + assertEquals(area.getName(), "北京市"); | ||
| 24 | + assertEquals(area.getType(), AreaTypeEnum.CITY.getType()); | ||
| 25 | + assertEquals(area.getParent().getId(), 110000); | ||
| 26 | + assertEquals(area.getChildren().size(), 16); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + @Test | ||
| 30 | + public void testFormat() { | ||
| 31 | + assertEquals(AreaUtils.format(110105), "北京 北京市 朝阳区"); | ||
| 32 | + assertEquals(AreaUtils.format(1), "中国"); | ||
| 33 | + assertEquals(AreaUtils.format(2), "蒙古"); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | +} |
yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtilsTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ip.core.utils; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.ip.core.Area; | ||
| 4 | +import org.junit.jupiter.api.Test; | ||
| 5 | +import org.lionsoul.ip2region.xdb.Searcher; | ||
| 6 | + | ||
| 7 | + | ||
| 8 | +import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * {@link IPUtils} 的单元测试 | ||
| 12 | + * | ||
| 13 | + * @author wanglhup | ||
| 14 | + */ | ||
| 15 | +public class IPUtilsTest { | ||
| 16 | + | ||
| 17 | + @Test | ||
| 18 | + public void testGetAreaId_string() { | ||
| 19 | + // 120.202.4.0|120.202.4.255|420600 | ||
| 20 | + Integer areaId = IPUtils.getAreaId("120.202.4.50"); | ||
| 21 | + assertEquals(420600, areaId); | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + @Test | ||
| 25 | + public void testGetAreaId_long() throws Exception { | ||
| 26 | + // 120.203.123.0|120.203.133.255|360900 | ||
| 27 | + long ip = Searcher.checkIP("120.203.123.250"); | ||
| 28 | + Integer areaId = IPUtils.getAreaId(ip); | ||
| 29 | + assertEquals(360900, areaId); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + @Test | ||
| 33 | + public void testGetArea_string() { | ||
| 34 | + // 120.202.4.0|120.202.4.255|420600 | ||
| 35 | + Area area = IPUtils.getArea("120.202.4.50"); | ||
| 36 | + assertEquals("襄阳市", area.getName()); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + @Test | ||
| 40 | + public void testGetArea_long() throws Exception { | ||
| 41 | + // 120.203.123.0|120.203.133.255|360900 | ||
| 42 | + long ip = Searcher.checkIP("120.203.123.252"); | ||
| 43 | + Area area = IPUtils.getArea(ip); | ||
| 44 | + assertEquals("宜春市", area.getName()); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | +} |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/PayProperties.java
| @@ -13,26 +13,23 @@ import javax.validation.constraints.NotEmpty; | @@ -13,26 +13,23 @@ import javax.validation.constraints.NotEmpty; | ||
| 13 | public class PayProperties { | 13 | public class PayProperties { |
| 14 | 14 | ||
| 15 | /** | 15 | /** |
| 16 | - * 支付回调地址 | 16 | + * 回调地址 |
| 17 | + * | ||
| 18 | + * 实际上,对应的 PayNotifyController 的 notifyCallback 方法的 URL | ||
| 19 | + * | ||
| 17 | * 注意,支付渠道统一回调到 payNotifyUrl 地址,由支付模块统一处理;然后,自己的支付模块,在回调 PayAppDO.payNotifyUrl 地址 | 20 | * 注意,支付渠道统一回调到 payNotifyUrl 地址,由支付模块统一处理;然后,自己的支付模块,在回调 PayAppDO.payNotifyUrl 地址 |
| 18 | */ | 21 | */ |
| 19 | - @NotEmpty(message = "支付回调地址不能为空") | ||
| 20 | - @URL(message = "支付回调地址的格式必须是 URL") | ||
| 21 | - private String payNotifyUrl; | ||
| 22 | - /** | ||
| 23 | - * 退款回调地址 | ||
| 24 | - * 注意点,同 {@link #payNotifyUrl} 属性 | ||
| 25 | - */ | ||
| 26 | - @NotEmpty(message = "退款回调地址不能为空") | ||
| 27 | - @URL(message = "退款回调地址的格式必须是 URL") | ||
| 28 | - private String refundNotifyUrl; | ||
| 29 | - | 22 | + @NotEmpty(message = "回调地址不能为空") |
| 23 | + @URL(message = "回调地址的格式必须是 URL") | ||
| 24 | + private String callbackUrl; | ||
| 30 | 25 | ||
| 31 | /** | 26 | /** |
| 32 | - * 支付完成的返回地址 | 27 | + * 回跳地址 |
| 28 | + * | ||
| 29 | + * 实际上,对应的 PayNotifyController 的 returnCallback 方法的 URL | ||
| 33 | */ | 30 | */ |
| 34 | - @URL(message = "支付返回的地址的格式必须是 URL") | ||
| 35 | - @NotEmpty(message = "支付返回的地址不能为空") | ||
| 36 | - private String payReturnUrl; | 31 | + @URL(message = "回跳地址的格式必须是 URL") |
| 32 | + @NotEmpty(message = "回跳地址不能为空") | ||
| 33 | + private String returnUrl; | ||
| 37 | 34 | ||
| 38 | } | 35 | } |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayNotifyDataDTO.java
| @@ -21,9 +21,9 @@ public class PayNotifyDataDTO { | @@ -21,9 +21,9 @@ public class PayNotifyDataDTO { | ||
| 21 | */ | 21 | */ |
| 22 | private String body; | 22 | private String body; |
| 23 | 23 | ||
| 24 | - | ||
| 25 | /** | 24 | /** |
| 26 | * HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数 | 25 | * HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数 |
| 27 | */ | 26 | */ |
| 28 | private Map<String,String> params; | 27 | private Map<String,String> params; |
| 28 | + | ||
| 29 | } | 29 | } |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderUnifiedReqDTO.java
| @@ -62,7 +62,7 @@ public class PayOrderUnifiedReqDTO { | @@ -62,7 +62,7 @@ public class PayOrderUnifiedReqDTO { | ||
| 62 | */ | 62 | */ |
| 63 | @NotNull(message = "支付金额不能为空") | 63 | @NotNull(message = "支付金额不能为空") |
| 64 | @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") | 64 | @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") |
| 65 | - private Long amount; | 65 | + private Integer amount; |
| 66 | 66 | ||
| 67 | /** | 67 | /** |
| 68 | * 支付过期时间 | 68 | * 支付过期时间 |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayRefundUnifiedReqDTO.java
| @@ -63,7 +63,7 @@ public class PayRefundUnifiedReqDTO { | @@ -63,7 +63,7 @@ public class PayRefundUnifiedReqDTO { | ||
| 63 | */ | 63 | */ |
| 64 | @NotNull(message = "退款金额不能为空") | 64 | @NotNull(message = "退款金额不能为空") |
| 65 | @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") | 65 | @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") |
| 66 | - private Long amount; | 66 | + private Integer amount; |
| 67 | 67 | ||
| 68 | /** | 68 | /** |
| 69 | * 退款结果 notify 回调地址, 支付宝退款不需要回调地址, 微信需要 | 69 | * 退款结果 notify 回调地址, 支付宝退款不需要回调地址, 微信需要 |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
| @@ -69,7 +69,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | @@ -69,7 +69,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | ||
| 69 | this.init(); | 69 | this.init(); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | - protected Double calculateAmount(Long amount) { | 72 | + protected Double calculateAmount(Integer amount) { |
| 73 | return amount / 100.0; | 73 | return amount / 100.0; |
| 74 | } | 74 | } |
| 75 | 75 |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXLitePayClient.java
| @@ -26,6 +26,8 @@ import com.github.binarywang.wxpay.service.WxPayService; | @@ -26,6 +26,8 @@ import com.github.binarywang.wxpay.service.WxPayService; | ||
| 26 | import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; | 26 | import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; |
| 27 | import lombok.extern.slf4j.Slf4j; | 27 | import lombok.extern.slf4j.Slf4j; |
| 28 | 28 | ||
| 29 | +import java.time.ZoneId; | ||
| 30 | +import java.util.Date; | ||
| 29 | import java.util.Objects; | 31 | import java.util.Objects; |
| 30 | 32 | ||
| 31 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | 33 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| @@ -119,7 +121,7 @@ public class WXLitePayClient extends AbstractPayClient<WXPayClientConfig> { | @@ -119,7 +121,7 @@ public class WXLitePayClient extends AbstractPayClient<WXPayClientConfig> { | ||
| 119 | .setTotal(reqDTO | 121 | .setTotal(reqDTO |
| 120 | .getAmount() | 122 | .getAmount() |
| 121 | .intValue())); // 单位分 | 123 | .intValue())); // 单位分 |
| 122 | - request.setTimeExpire(DateUtil.format(reqDTO.getExpireTime(), "yyyy-MM-dd'T'HH:mm:ssXXX")); // v3的时间格式 | 124 | + request.setTimeExpire(DateUtil.format(Date.from(reqDTO.getExpireTime().atZone(ZoneId.systemDefault()).toInstant()), "yyyy-MM-dd'T'HH:mm:ssXXX")); // v3的时间格式 |
| 123 | request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(getOpenid(reqDTO))); | 125 | request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(getOpenid(reqDTO))); |
| 124 | request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp())); | 126 | request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp())); |
| 125 | request.setNotifyUrl(reqDTO.getNotifyUrl()); | 127 | request.setNotifyUrl(reqDTO.getNotifyUrl()); |
| @@ -167,7 +169,8 @@ public class WXLitePayClient extends AbstractPayClient<WXPayClientConfig> { | @@ -167,7 +169,8 @@ public class WXLitePayClient extends AbstractPayClient<WXPayClientConfig> { | ||
| 167 | return PayOrderNotifyRespDTO | 169 | return PayOrderNotifyRespDTO |
| 168 | .builder() | 170 | .builder() |
| 169 | .orderExtensionNo(result.getOutTradeNo()) | 171 | .orderExtensionNo(result.getOutTradeNo()) |
| 170 | - .channelOrderNo(result.getTradeState()) | 172 | + .channelOrderNo(result.getTransactionId()) |
| 173 | + .channelUserId(result.getPayer().getOpenid()) | ||
| 171 | .successTime(LocalDateTimeUtil.parse(result.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ssXXX")) | 174 | .successTime(LocalDateTimeUtil.parse(result.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ssXXX")) |
| 172 | .data(data.getBody()) | 175 | .data(data.getBody()) |
| 173 | .build(); | 176 | .build(); |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXNativePayClient.java
| @@ -24,6 +24,8 @@ import com.github.binarywang.wxpay.service.WxPayService; | @@ -24,6 +24,8 @@ import com.github.binarywang.wxpay.service.WxPayService; | ||
| 24 | import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; | 24 | import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; |
| 25 | import lombok.extern.slf4j.Slf4j; | 25 | import lombok.extern.slf4j.Slf4j; |
| 26 | 26 | ||
| 27 | +import java.time.ZoneId; | ||
| 28 | +import java.util.Date; | ||
| 27 | import java.util.Objects; | 29 | import java.util.Objects; |
| 28 | 30 | ||
| 29 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | 31 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| @@ -98,7 +100,7 @@ public class WXNativePayClient extends AbstractPayClient<WXPayClientConfig> { | @@ -98,7 +100,7 @@ public class WXNativePayClient extends AbstractPayClient<WXPayClientConfig> { | ||
| 98 | .outTradeNo(reqDTO.getMerchantOrderId()) | 100 | .outTradeNo(reqDTO.getMerchantOrderId()) |
| 99 | .body(reqDTO.getBody()) | 101 | .body(reqDTO.getBody()) |
| 100 | .totalFee(reqDTO.getAmount().intValue()) // 单位分 | 102 | .totalFee(reqDTO.getAmount().intValue()) // 单位分 |
| 101 | - .timeExpire(DateUtil.format(reqDTO.getExpireTime(), "yyyy-MM-dd'T'HH:mm:ssXXX")) | 103 | + .timeExpire(DateUtil.format(Date.from(reqDTO.getExpireTime().atZone(ZoneId.systemDefault()).toInstant()), "yyyy-MM-dd'T'HH:mm:ssXXX")) |
| 102 | .spbillCreateIp(reqDTO.getUserIp()) | 104 | .spbillCreateIp(reqDTO.getUserIp()) |
| 103 | .notifyUrl(reqDTO.getNotifyUrl()) | 105 | .notifyUrl(reqDTO.getNotifyUrl()) |
| 104 | .productId(tradeType) | 106 | .productId(tradeType) |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java
| 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.wx; | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.wx; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.bean.BeanUtil; | 3 | import cn.hutool.core.bean.BeanUtil; |
| 4 | -import cn.hutool.core.date.DateUtil; | ||
| 5 | import cn.hutool.core.date.LocalDateTimeUtil; | 4 | import cn.hutool.core.date.LocalDateTimeUtil; |
| 5 | +import cn.hutool.core.date.TemporalAccessorUtil; | ||
| 6 | import cn.hutool.core.lang.Assert; | 6 | import cn.hutool.core.lang.Assert; |
| 7 | import cn.hutool.core.map.MapUtil; | 7 | import cn.hutool.core.map.MapUtil; |
| 8 | import cn.hutool.core.util.StrUtil; | 8 | import cn.hutool.core.util.StrUtil; |
| @@ -26,6 +26,8 @@ import com.github.binarywang.wxpay.service.WxPayService; | @@ -26,6 +26,8 @@ import com.github.binarywang.wxpay.service.WxPayService; | ||
| 26 | import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; | 26 | import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; |
| 27 | import lombok.extern.slf4j.Slf4j; | 27 | import lombok.extern.slf4j.Slf4j; |
| 28 | 28 | ||
| 29 | +import java.time.LocalDateTime; | ||
| 30 | +import java.time.ZoneId; | ||
| 29 | import java.util.Objects; | 31 | import java.util.Objects; |
| 30 | 32 | ||
| 31 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | 33 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| @@ -98,8 +100,8 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> { | @@ -98,8 +100,8 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> { | ||
| 98 | WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder() | 100 | WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder() |
| 99 | .outTradeNo(reqDTO.getMerchantOrderId()) | 101 | .outTradeNo(reqDTO.getMerchantOrderId()) |
| 100 | .body(reqDTO.getBody()) | 102 | .body(reqDTO.getBody()) |
| 101 | - .totalFee(reqDTO.getAmount().intValue()) // 单位分 | ||
| 102 | - .timeExpire(DateUtil.format(reqDTO.getExpireTime(), "yyyy-MM-dd'T'HH:mm:ssXXX")) | 103 | + .totalFee(reqDTO.getAmount()) // 单位分 |
| 104 | + .timeExpire(formatDate(reqDTO.getExpireTime())) | ||
| 103 | .spbillCreateIp(reqDTO.getUserIp()) | 105 | .spbillCreateIp(reqDTO.getUserIp()) |
| 104 | .openid(getOpenid(reqDTO)) | 106 | .openid(getOpenid(reqDTO)) |
| 105 | .notifyUrl(reqDTO.getNotifyUrl()) | 107 | .notifyUrl(reqDTO.getNotifyUrl()) |
| @@ -113,8 +115,8 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> { | @@ -113,8 +115,8 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> { | ||
| 113 | WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); | 115 | WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); |
| 114 | request.setOutTradeNo(reqDTO.getMerchantOrderId()); | 116 | request.setOutTradeNo(reqDTO.getMerchantOrderId()); |
| 115 | request.setDescription(reqDTO.getBody()); | 117 | request.setDescription(reqDTO.getBody()); |
| 116 | - request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getAmount().intValue())); // 单位分 | ||
| 117 | - request.setTimeExpire(DateUtil.format(reqDTO.getExpireTime(), "yyyy-MM-dd'T'HH:mm:ssXXX")); | 118 | + request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getAmount())); // 单位分 |
| 119 | + request.setTimeExpire(formatDate(reqDTO.getExpireTime())); | ||
| 118 | request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(getOpenid(reqDTO))); | 120 | request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(getOpenid(reqDTO))); |
| 119 | request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp())); | 121 | request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp())); |
| 120 | request.setNotifyUrl(reqDTO.getNotifyUrl()); | 122 | request.setNotifyUrl(reqDTO.getNotifyUrl()); |
| @@ -194,4 +196,8 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> { | @@ -194,4 +196,8 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> { | ||
| 194 | throw new UnsupportedOperationException(); | 196 | throw new UnsupportedOperationException(); |
| 195 | } | 197 | } |
| 196 | 198 | ||
| 199 | + private static String formatDate(LocalDateTime time) { | ||
| 200 | + return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), "yyyy-MM-dd'T'HH:mm:ssXXX"); | ||
| 201 | + } | ||
| 202 | + | ||
| 197 | } | 203 | } |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java renamed to yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn.iocoder.yudao.framework.pay.core.client.impl/PayClientFactoryImplIntegrationTest.java
| 1 | -package cn.iocoder.yudao.framework.core.client.impl; | 1 | +package cn.iocoder.yudao.framework.pay.core.client.impl; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.io.IoUtil; | 3 | import cn.hutool.core.io.IoUtil; |
| 4 | import cn.hutool.core.util.RandomUtil; | 4 | import cn.hutool.core.util.RandomUtil; |
| @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 6 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 6 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 7 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; | 7 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 8 | import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; | 8 | import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; |
| 9 | -import cn.iocoder.yudao.framework.pay.core.client.impl.PayClientFactoryImpl; | ||
| 10 | import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; | 9 | import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; |
| 11 | import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayQrPayClient; | 10 | import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayQrPayClient; |
| 12 | import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayWapPayClient; | 11 | import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayWapPayClient; |
| @@ -14,6 +13,7 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig; | @@ -14,6 +13,7 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig; | ||
| 14 | import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPubPayClient; | 13 | import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPubPayClient; |
| 15 | import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; | 14 | import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; |
| 16 | import com.alipay.api.response.AlipayTradePrecreateResponse; | 15 | import com.alipay.api.response.AlipayTradePrecreateResponse; |
| 16 | +import org.junit.jupiter.api.Disabled; | ||
| 17 | import org.junit.jupiter.api.Test; | 17 | import org.junit.jupiter.api.Test; |
| 18 | 18 | ||
| 19 | import java.io.FileInputStream; | 19 | import java.io.FileInputStream; |
| @@ -24,7 +24,8 @@ import java.io.FileNotFoundException; | @@ -24,7 +24,8 @@ import java.io.FileNotFoundException; | ||
| 24 | * | 24 | * |
| 25 | * @author 芋道源码 | 25 | * @author 芋道源码 |
| 26 | */ | 26 | */ |
| 27 | -public class PayClientFactoryImplTest { | 27 | +@Disabled |
| 28 | +public class PayClientFactoryImplIntegrationTest { | ||
| 28 | 29 | ||
| 29 | private final PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl(); | 30 | private final PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl(); |
| 30 | 31 | ||
| @@ -91,7 +92,7 @@ public class PayClientFactoryImplTest { | @@ -91,7 +92,7 @@ public class PayClientFactoryImplTest { | ||
| 91 | PayClient client = payClientFactory.getPayClient(channelId); | 92 | PayClient client = payClientFactory.getPayClient(channelId); |
| 92 | // 发起支付 | 93 | // 发起支付 |
| 93 | PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO(); | 94 | PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO(); |
| 94 | - reqDTO.setNotifyUrl("http://niubi.natapp1.cc/api/pay/order/notify/alipay-qr/1"); // TODO @tina: 这里改成你的 natapp 回调地址 | 95 | + reqDTO.setNotifyUrl("http://yunai.natapp1.cc/admin-api/pay/notify/callback/18"); // TODO @tina: 这里改成你的 natapp 回调地址 |
| 95 | CommonResult<AlipayTradePrecreateResponse> result = (CommonResult<AlipayTradePrecreateResponse>) client.unifiedOrder(reqDTO); | 96 | CommonResult<AlipayTradePrecreateResponse> result = (CommonResult<AlipayTradePrecreateResponse>) client.unifiedOrder(reqDTO); |
| 96 | System.out.println(JsonUtils.toJsonString(result)); | 97 | System.out.println(JsonUtils.toJsonString(result)); |
| 97 | System.out.println(result.getData().getQrCode()); | 98 | System.out.println(result.getData().getQrCode()); |
| @@ -121,7 +122,7 @@ public class PayClientFactoryImplTest { | @@ -121,7 +122,7 @@ public class PayClientFactoryImplTest { | ||
| 121 | 122 | ||
| 122 | private static PayOrderUnifiedReqDTO buildPayOrderUnifiedReqDTO() { | 123 | private static PayOrderUnifiedReqDTO buildPayOrderUnifiedReqDTO() { |
| 123 | PayOrderUnifiedReqDTO reqDTO = new PayOrderUnifiedReqDTO(); | 124 | PayOrderUnifiedReqDTO reqDTO = new PayOrderUnifiedReqDTO(); |
| 124 | - reqDTO.setAmount(123L); | 125 | + reqDTO.setAmount(123); |
| 125 | reqDTO.setSubject("IPhone 13"); | 126 | reqDTO.setSubject("IPhone 13"); |
| 126 | reqDTO.setBody("biubiubiu"); | 127 | reqDTO.setBody("biubiubiu"); |
| 127 | reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis())); | 128 | reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis())); |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn.iocoder.yudao.framework.pay.core.client.impl/alipay/AlipayQrPayClientTest.java
| @@ -73,7 +73,7 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { | @@ -73,7 +73,7 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { | ||
| 73 | Long shopOrderId = System.currentTimeMillis(); | 73 | Long shopOrderId = System.currentTimeMillis(); |
| 74 | PayOrderUnifiedReqDTO reqDTO=new PayOrderUnifiedReqDTO(); | 74 | PayOrderUnifiedReqDTO reqDTO=new PayOrderUnifiedReqDTO(); |
| 75 | reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis())); | 75 | reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis())); |
| 76 | - reqDTO.setAmount(1L); | 76 | + reqDTO.setAmount(1); |
| 77 | reqDTO.setBody("内容:" + shopOrderId); | 77 | reqDTO.setBody("内容:" + shopOrderId); |
| 78 | reqDTO.setSubject("标题:"+shopOrderId); | 78 | reqDTO.setSubject("标题:"+shopOrderId); |
| 79 | String notify="http://niubi.natapp1.cc/api/pay/order/notify"; | 79 | String notify="http://niubi.natapp1.cc/api/pay/order/notify"; |
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java
| @@ -35,8 +35,8 @@ public class AliyunSmsCodeMapping implements SmsCodeMapping { | @@ -35,8 +35,8 @@ public class AliyunSmsCodeMapping implements SmsCodeMapping { | ||
| 35 | case "isv.OUT_OF_SERVICE": return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH; | 35 | case "isv.OUT_OF_SERVICE": return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH; |
| 36 | case "isv.MOBILE_NUMBER_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID; | 36 | case "isv.MOBILE_NUMBER_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID; |
| 37 | case "isv.TEMPLATE_MISSING_PARAMETERS": return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR; | 37 | case "isv.TEMPLATE_MISSING_PARAMETERS": return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR; |
| 38 | + default: return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN; | ||
| 38 | } | 39 | } |
| 39 | - return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN; | ||
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | } | 42 | } |
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnoreAspect.java
| 1 | package cn.iocoder.yudao.framework.tenant.core.aop; | 1 | package cn.iocoder.yudao.framework.tenant.core.aop; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | 3 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; |
| 4 | +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | ||
| 4 | import lombok.extern.slf4j.Slf4j; | 5 | import lombok.extern.slf4j.Slf4j; |
| 5 | import org.aspectj.lang.ProceedingJoinPoint; | 6 | import org.aspectj.lang.ProceedingJoinPoint; |
| 6 | import org.aspectj.lang.annotation.Around; | 7 | import org.aspectj.lang.annotation.Around; |
| @@ -11,6 +12,8 @@ import org.aspectj.lang.annotation.Aspect; | @@ -11,6 +12,8 @@ import org.aspectj.lang.annotation.Aspect; | ||
| 11 | * 例如说,一个定时任务,读取所有数据,进行处理。 | 12 | * 例如说,一个定时任务,读取所有数据,进行处理。 |
| 12 | * 又例如说,读取所有数据,进行缓存。 | 13 | * 又例如说,读取所有数据,进行缓存。 |
| 13 | * | 14 | * |
| 15 | + * 整体逻辑的实现,和 {@link TenantUtils#executeIgnore(Runnable)} 需要保持一致 | ||
| 16 | + * | ||
| 14 | * @author 芋道源码 | 17 | * @author 芋道源码 |
| 15 | */ | 18 | */ |
| 16 | @Aspect | 19 | @Aspect |
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java
| @@ -2,6 +2,10 @@ package cn.iocoder.yudao.framework.tenant.core.util; | @@ -2,6 +2,10 @@ package cn.iocoder.yudao.framework.tenant.core.util; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | 3 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; |
| 4 | 4 | ||
| 5 | +import java.util.Map; | ||
| 6 | + | ||
| 7 | +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; | ||
| 8 | + | ||
| 5 | /** | 9 | /** |
| 6 | * 多租户 Util | 10 | * 多租户 Util |
| 7 | * | 11 | * |
| @@ -32,4 +36,32 @@ public class TenantUtils { | @@ -32,4 +36,32 @@ public class TenantUtils { | ||
| 32 | } | 36 | } |
| 33 | } | 37 | } |
| 34 | 38 | ||
| 39 | + /** | ||
| 40 | + * 忽略租户,执行对应的逻辑 | ||
| 41 | + * | ||
| 42 | + * @param runnable 逻辑 | ||
| 43 | + */ | ||
| 44 | + public static void executeIgnore(Runnable runnable) { | ||
| 45 | + Boolean oldIgnore = TenantContextHolder.isIgnore(); | ||
| 46 | + try { | ||
| 47 | + TenantContextHolder.setIgnore(true); | ||
| 48 | + // 执行逻辑 | ||
| 49 | + runnable.run(); | ||
| 50 | + } finally { | ||
| 51 | + TenantContextHolder.setIgnore(oldIgnore); | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * 将多租户编号,添加到 header 中 | ||
| 57 | + * | ||
| 58 | + * @param headers HTTP 请求 headers | ||
| 59 | + */ | ||
| 60 | + public static void addTenantHeader(Map<String, String> headers) { | ||
| 61 | + Long tenantId = TenantContextHolder.getTenantId(); | ||
| 62 | + if (tenantId != null) { | ||
| 63 | + headers.put(HEADER_TENANT_ID, tenantId.toString()); | ||
| 64 | + } | ||
| 65 | + } | ||
| 66 | + | ||
| 35 | } | 67 | } |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/s3/S3FileClient.java
| @@ -9,10 +9,11 @@ import io.minio.*; | @@ -9,10 +9,11 @@ import io.minio.*; | ||
| 9 | import java.io.ByteArrayInputStream; | 9 | import java.io.ByteArrayInputStream; |
| 10 | 10 | ||
| 11 | import static cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig.ENDPOINT_ALIYUN; | 11 | import static cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig.ENDPOINT_ALIYUN; |
| 12 | +import static cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig.ENDPOINT_TENCENT; | ||
| 12 | 13 | ||
| 13 | /** | 14 | /** |
| 14 | * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务 | 15 | * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务 |
| 15 | - * | 16 | + * <p> |
| 16 | * S3 协议的客户端,采用亚马逊提供的 software.amazon.awssdk.s3 库 | 17 | * S3 协议的客户端,采用亚马逊提供的 software.amazon.awssdk.s3 库 |
| 17 | * | 18 | * |
| 18 | * @author 芋道源码 | 19 | * @author 芋道源码 |
| @@ -78,6 +79,11 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { | @@ -78,6 +79,11 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { | ||
| 78 | .replaceAll("-internal", "")// 去除内网 Endpoint 的后缀 | 79 | .replaceAll("-internal", "")// 去除内网 Endpoint 的后缀 |
| 79 | .replaceAll("https://", ""); | 80 | .replaceAll("https://", ""); |
| 80 | } | 81 | } |
| 82 | + // 腾讯云必须有 region,否则会报错 | ||
| 83 | + if (config.getEndpoint().contains(ENDPOINT_TENCENT)) { | ||
| 84 | + return StrUtil.subAfter(config.getEndpoint(), ".cos.", false) | ||
| 85 | + .replaceAll("." + ENDPOINT_TENCENT, ""); // 去除 Endpoint | ||
| 86 | + } | ||
| 81 | return null; | 87 | return null; |
| 82 | } | 88 | } |
| 83 | 89 |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/s3/S3FileClientConfig.java
| @@ -19,6 +19,7 @@ public class S3FileClientConfig implements FileClientConfig { | @@ -19,6 +19,7 @@ public class S3FileClientConfig implements FileClientConfig { | ||
| 19 | 19 | ||
| 20 | public static final String ENDPOINT_QINIU = "qiniucs.com"; | 20 | public static final String ENDPOINT_QINIU = "qiniucs.com"; |
| 21 | public static final String ENDPOINT_ALIYUN = "aliyuncs.com"; | 21 | public static final String ENDPOINT_ALIYUN = "aliyuncs.com"; |
| 22 | + public static final String ENDPOINT_TENCENT = "myqcloud.com"; | ||
| 22 | 23 | ||
| 23 | /** | 24 | /** |
| 24 | * 节点地址 | 25 | * 节点地址 |
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/config/YudaoMQAutoConfiguration.java
| @@ -8,8 +8,11 @@ import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | @@ -8,8 +8,11 @@ import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | ||
| 8 | import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor; | 8 | import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor; |
| 9 | import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; | 9 | import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; |
| 10 | import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener; | 10 | import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener; |
| 11 | +import cn.iocoder.yudao.framework.mq.job.RedisPendingMessageResendJob; | ||
| 11 | import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; | 12 | import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; |
| 12 | import lombok.extern.slf4j.Slf4j; | 13 | import lombok.extern.slf4j.Slf4j; |
| 14 | +import org.redisson.api.RedissonClient; | ||
| 15 | +import org.springframework.beans.factory.annotation.Value; | ||
| 13 | import org.springframework.boot.autoconfigure.AutoConfiguration; | 16 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 14 | import org.springframework.context.annotation.Bean; | 17 | import org.springframework.context.annotation.Bean; |
| 15 | import org.springframework.data.redis.connection.RedisServerCommands; | 18 | import org.springframework.data.redis.connection.RedisServerCommands; |
| @@ -24,7 +27,7 @@ import org.springframework.data.redis.listener.ChannelTopic; | @@ -24,7 +27,7 @@ import org.springframework.data.redis.listener.ChannelTopic; | ||
| 24 | import org.springframework.data.redis.listener.RedisMessageListenerContainer; | 27 | import org.springframework.data.redis.listener.RedisMessageListenerContainer; |
| 25 | import org.springframework.data.redis.stream.DefaultStreamMessageListenerContainerX; | 28 | import org.springframework.data.redis.stream.DefaultStreamMessageListenerContainerX; |
| 26 | import org.springframework.data.redis.stream.StreamMessageListenerContainer; | 29 | import org.springframework.data.redis.stream.StreamMessageListenerContainer; |
| 27 | -import org.springframework.scheduling.annotation.Async; | 30 | +import org.springframework.scheduling.annotation.EnableScheduling; |
| 28 | 31 | ||
| 29 | import java.util.List; | 32 | import java.util.List; |
| 30 | import java.util.Properties; | 33 | import java.util.Properties; |
| @@ -35,6 +38,7 @@ import java.util.Properties; | @@ -35,6 +38,7 @@ import java.util.Properties; | ||
| 35 | * @author 芋道源码 | 38 | * @author 芋道源码 |
| 36 | */ | 39 | */ |
| 37 | @Slf4j | 40 | @Slf4j |
| 41 | +@EnableScheduling // 启用定时任务,用于 RedisPendingMessageResendJob 重发消息 | ||
| 38 | @AutoConfiguration(after = YudaoRedisAutoConfiguration.class) | 42 | @AutoConfiguration(after = YudaoRedisAutoConfiguration.class) |
| 39 | public class YudaoMQAutoConfiguration { | 43 | public class YudaoMQAutoConfiguration { |
| 40 | 44 | ||
| @@ -70,8 +74,19 @@ public class YudaoMQAutoConfiguration { | @@ -70,8 +74,19 @@ public class YudaoMQAutoConfiguration { | ||
| 70 | } | 74 | } |
| 71 | 75 | ||
| 72 | /** | 76 | /** |
| 77 | + * 创建 Redis Stream 重新消费的任务 | ||
| 78 | + */ | ||
| 79 | + @Bean | ||
| 80 | + public RedisPendingMessageResendJob redisPendingMessageResendJob(List<AbstractStreamMessageListener<?>> listeners, | ||
| 81 | + RedisMQTemplate redisTemplate, | ||
| 82 | + @Value("${spring.application.name}") String groupName, | ||
| 83 | + RedissonClient redissonClient) { | ||
| 84 | + return new RedisPendingMessageResendJob(listeners, redisTemplate, groupName, redissonClient); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + /** | ||
| 73 | * 创建 Redis Stream 集群消费的容器 | 88 | * 创建 Redis Stream 集群消费的容器 |
| 74 | - * | 89 | + * <p> |
| 75 | * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html | 90 | * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html |
| 76 | */ | 91 | */ |
| 77 | @Bean(initMethod = "start", destroyMethod = "stop") | 92 | @Bean(initMethod = "start", destroyMethod = "stop") |
| @@ -99,7 +114,8 @@ public class YudaoMQAutoConfiguration { | @@ -99,7 +114,8 @@ public class YudaoMQAutoConfiguration { | ||
| 99 | // 创建 listener 对应的消费者分组 | 114 | // 创建 listener 对应的消费者分组 |
| 100 | try { | 115 | try { |
| 101 | redisTemplate.opsForStream().createGroup(listener.getStreamKey(), listener.getGroup()); | 116 | redisTemplate.opsForStream().createGroup(listener.getStreamKey(), listener.getGroup()); |
| 102 | - } catch (Exception ignore) {} | 117 | + } catch (Exception ignore) { |
| 118 | + } | ||
| 103 | // 设置 listener 对应的 redisTemplate | 119 | // 设置 listener 对应的 redisTemplate |
| 104 | listener.setRedisMQTemplate(redisMQTemplate); | 120 | listener.setRedisMQTemplate(redisMQTemplate); |
| 105 | // 创建 Consumer 对象 | 121 | // 创建 Consumer 对象 |
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/job/RedisPendingMessageResendJob.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.mq.job; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | ||
| 5 | +import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener; | ||
| 6 | +import lombok.AllArgsConstructor; | ||
| 7 | +import lombok.extern.slf4j.Slf4j; | ||
| 8 | +import org.redisson.api.RLock; | ||
| 9 | +import org.redisson.api.RedissonClient; | ||
| 10 | +import org.springframework.data.redis.connection.stream.Consumer; | ||
| 11 | +import org.springframework.data.redis.connection.stream.MapRecord; | ||
| 12 | +import org.springframework.data.redis.connection.stream.PendingMessagesSummary; | ||
| 13 | +import org.springframework.data.redis.connection.stream.ReadOffset; | ||
| 14 | +import org.springframework.data.redis.connection.stream.StreamOffset; | ||
| 15 | +import org.springframework.data.redis.connection.stream.StreamRecords; | ||
| 16 | +import org.springframework.data.redis.core.StreamOperations; | ||
| 17 | +import org.springframework.scheduling.annotation.Scheduled; | ||
| 18 | + | ||
| 19 | +import java.util.List; | ||
| 20 | +import java.util.Map; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * 这个任务用于处理,crash 之后的消费者未消费完的消息 | ||
| 24 | + */ | ||
| 25 | +@Slf4j | ||
| 26 | +@AllArgsConstructor | ||
| 27 | +public class RedisPendingMessageResendJob { | ||
| 28 | + | ||
| 29 | + private static final String LOCK_KEY = "redis:pending:msg:lock"; | ||
| 30 | + | ||
| 31 | + private final List<AbstractStreamMessageListener<?>> listeners; | ||
| 32 | + private final RedisMQTemplate redisTemplate; | ||
| 33 | + private final String groupName; | ||
| 34 | + private final RedissonClient redissonClient; | ||
| 35 | + | ||
| 36 | + /** | ||
| 37 | + * 一分钟执行一次,这里选择每分钟的35秒执行,是为了避免整点任务过多的问题 | ||
| 38 | + */ | ||
| 39 | + @Scheduled(cron = "35 * * * * ?") | ||
| 40 | + public void messageResend() { | ||
| 41 | + RLock lock = redissonClient.getLock(LOCK_KEY); | ||
| 42 | + // 尝试加锁 | ||
| 43 | + if (lock.tryLock()) { | ||
| 44 | + try { | ||
| 45 | + execute(); | ||
| 46 | + } catch (Exception ex) { | ||
| 47 | + log.error("[messageResend][执行异常]", ex); | ||
| 48 | + } finally { | ||
| 49 | + lock.unlock(); | ||
| 50 | + } | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + private void execute() { | ||
| 55 | + StreamOperations<String, Object, Object> ops = redisTemplate.getRedisTemplate().opsForStream(); | ||
| 56 | + listeners.forEach(listener -> { | ||
| 57 | + PendingMessagesSummary pendingMessagesSummary = ops.pending(listener.getStreamKey(), groupName); | ||
| 58 | + // 每个消费者的 pending 队列消息数量 | ||
| 59 | + Map<String, Long> pendingMessagesPerConsumer = pendingMessagesSummary.getPendingMessagesPerConsumer(); | ||
| 60 | + pendingMessagesPerConsumer.forEach((consumerName, pendingMessageCount) -> { | ||
| 61 | + log.info("[processPendingMessage][消费者({}) 消息数量({})]", consumerName, pendingMessageCount); | ||
| 62 | + | ||
| 63 | + // 从消费者的 pending 队列中读取消息 | ||
| 64 | + List<MapRecord<String, Object, Object>> records = ops.read(Consumer.from(groupName, consumerName), StreamOffset.create(listener.getStreamKey(), ReadOffset.from("0"))); | ||
| 65 | + if (CollUtil.isEmpty(records)) { | ||
| 66 | + return; | ||
| 67 | + } | ||
| 68 | + for (MapRecord<String, Object, Object> record : records) { | ||
| 69 | + // 重新投递消息 | ||
| 70 | + redisTemplate.getRedisTemplate().opsForStream().add(StreamRecords.newRecord() | ||
| 71 | + .ofObject(record.getValue()) // 设置内容 | ||
| 72 | + .withStreamKey(listener.getStreamKey())); | ||
| 73 | + | ||
| 74 | + // ack 消息消费完成 | ||
| 75 | + redisTemplate.getRedisTemplate().opsForStream().acknowledge(groupName, record); | ||
| 76 | + } | ||
| 77 | + }); | ||
| 78 | + }); | ||
| 79 | + } | ||
| 80 | +} |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.mybatis.core.mapper; | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.mybatis.core.mapper; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||
| 5 | import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; | 6 | import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; |
| 6 | import com.baomidou.mybatisplus.core.conditions.Wrapper; | 7 | import com.baomidou.mybatisplus.core.conditions.Wrapper; |
| 7 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | 8 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| @@ -75,9 +76,13 @@ public interface BaseMapperX<T> extends BaseMapper<T> { | @@ -75,9 +76,13 @@ public interface BaseMapperX<T> extends BaseMapper<T> { | ||
| 75 | return selectList(new LambdaQueryWrapper<T>().in(field, values)); | 76 | return selectList(new LambdaQueryWrapper<T>().in(field, values)); |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 79 | + default List<T> selectList(SFunction<T, ?> leField, SFunction<T, ?> geField, Object value) { | ||
| 80 | + return selectList(new LambdaQueryWrapper<T>().le(leField, value).ge(geField, value)); | ||
| 81 | + } | ||
| 82 | + | ||
| 78 | /** | 83 | /** |
| 79 | * 逐条插入,适合少量数据插入,或者对性能要求不高的场景 | 84 | * 逐条插入,适合少量数据插入,或者对性能要求不高的场景 |
| 80 | - * | 85 | + * <p> |
| 81 | * 如果大量,请使用 {@link com.baomidou.mybatisplus.extension.service.impl.ServiceImpl#saveBatch(Collection)} 方法 | 86 | * 如果大量,请使用 {@link com.baomidou.mybatisplus.extension.service.impl.ServiceImpl#saveBatch(Collection)} 方法 |
| 82 | * 使用示例,可见 RoleMenuBatchInsertMapper、UserRoleBatchInsertMapper 类 | 87 | * 使用示例,可见 RoleMenuBatchInsertMapper、UserRoleBatchInsertMapper 类 |
| 83 | * | 88 | * |
yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java
| @@ -33,6 +33,10 @@ public class AssertUtils { | @@ -33,6 +33,10 @@ public class AssertUtils { | ||
| 33 | public static void assertPojoEquals(Object expected, Object actual, String... ignoreFields) { | 33 | public static void assertPojoEquals(Object expected, Object actual, String... ignoreFields) { |
| 34 | Field[] expectedFields = ReflectUtil.getFields(expected.getClass()); | 34 | Field[] expectedFields = ReflectUtil.getFields(expected.getClass()); |
| 35 | Arrays.stream(expectedFields).forEach(expectedField -> { | 35 | Arrays.stream(expectedFields).forEach(expectedField -> { |
| 36 | + // 忽略 jacoco 自动生成的 $jacocoData 属性的情况 | ||
| 37 | + if (expectedField.isSynthetic()) { | ||
| 38 | + return; | ||
| 39 | + } | ||
| 36 | // 如果是忽略的属性,则不进行比对 | 40 | // 如果是忽略的属性,则不进行比对 |
| 37 | if (ArrayUtil.contains(ignoreFields, expectedField.getName())) { | 41 | if (ArrayUtil.contains(ignoreFields, expectedField.getName())) { |
| 38 | return; | 42 | return; |
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/LocalTimeJson.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.jackson.core.databind; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; | ||
| 4 | +import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; | ||
| 5 | + | ||
| 6 | +import java.time.ZoneId; | ||
| 7 | +import java.time.format.DateTimeFormatter; | ||
| 8 | + | ||
| 9 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_HOUR_MINUTE_SECOND; | ||
| 10 | + | ||
| 11 | +public class LocalTimeJson { | ||
| 12 | + | ||
| 13 | + public static final LocalTimeSerializer SERIALIZER = new LocalTimeSerializer(DateTimeFormatter | ||
| 14 | + .ofPattern(FORMAT_HOUR_MINUTE_SECOND) | ||
| 15 | + .withZone(ZoneId.systemDefault())); | ||
| 16 | + | ||
| 17 | + public static final LocalTimeDeserializer DESERIALIZABLE = new LocalTimeDeserializer(DateTimeFormatter | ||
| 18 | + .ofPattern(FORMAT_HOUR_MINUTE_SECOND) | ||
| 19 | + .withZone(ZoneId.systemDefault())); | ||
| 20 | + | ||
| 21 | +} |
yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/application-unit-test.yaml
| @@ -9,7 +9,7 @@ spring: | @@ -9,7 +9,7 @@ spring: | ||
| 9 | # 数据源配置项 | 9 | # 数据源配置项 |
| 10 | datasource: | 10 | datasource: |
| 11 | name: ruoyi-vue-pro | 11 | name: ruoyi-vue-pro |
| 12 | - url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 | 12 | + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 |
| 13 | driver-class-name: org.h2.Driver | 13 | driver-class-name: org.h2.Driver |
| 14 | username: sa | 14 | username: sa |
| 15 | password: | 15 | password: |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileContentDAOImpl.java
| 1 | package cn.iocoder.yudao.module.infra.dal.mysql.file; | 1 | package cn.iocoder.yudao.module.infra.dal.mysql.file; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.iocoder.yudao.framework.file.core.client.db.DBFileContentFrameworkDAO; | 4 | import cn.iocoder.yudao.framework.file.core.client.db.DBFileContentFrameworkDAO; |
| 4 | import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileContentDO; | 5 | import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileContentDO; |
| 5 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | 6 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| 6 | import org.springframework.stereotype.Repository; | 7 | import org.springframework.stereotype.Repository; |
| 7 | 8 | ||
| 8 | import javax.annotation.Resource; | 9 | import javax.annotation.Resource; |
| 10 | +import java.util.List; | ||
| 11 | +import java.util.Optional; | ||
| 9 | 12 | ||
| 10 | @Repository | 13 | @Repository |
| 11 | public class FileContentDAOImpl implements DBFileContentFrameworkDAO { | 14 | public class FileContentDAOImpl implements DBFileContentFrameworkDAO { |
| @@ -27,9 +30,11 @@ public class FileContentDAOImpl implements DBFileContentFrameworkDAO { | @@ -27,9 +30,11 @@ public class FileContentDAOImpl implements DBFileContentFrameworkDAO { | ||
| 27 | 30 | ||
| 28 | @Override | 31 | @Override |
| 29 | public byte[] selectContent(Long configId, String path) { | 32 | public byte[] selectContent(Long configId, String path) { |
| 30 | - FileContentDO fileContentDO = fileContentMapper.selectOne( | ||
| 31 | - buildQuery(configId, path).select(FileContentDO::getContent)); | ||
| 32 | - return fileContentDO != null ? fileContentDO.getContent() : null; | 33 | + List<FileContentDO> list = fileContentMapper.selectList( |
| 34 | + buildQuery(configId, path).select(FileContentDO::getContent).orderByDesc(FileContentDO::getId)); | ||
| 35 | + return Optional.ofNullable(CollUtil.getFirst(list)) | ||
| 36 | + .map(FileContentDO::getContent) | ||
| 37 | + .orElse(null); | ||
| 33 | } | 38 | } |
| 34 | 39 | ||
| 35 | private LambdaQueryWrapper<FileContentDO> buildQuery(Long configId, String path) { | 40 | private LambdaQueryWrapper<FileContentDO> buildQuery(Long configId, String path) { |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilder.java
| @@ -18,6 +18,8 @@ import org.springframework.stereotype.Component; | @@ -18,6 +18,8 @@ import org.springframework.stereotype.Component; | ||
| 18 | import java.util.*; | 18 | import java.util.*; |
| 19 | 19 | ||
| 20 | import static cn.hutool.core.text.CharSequenceUtil.*; | 20 | import static cn.hutool.core.text.CharSequenceUtil.*; |
| 21 | +import static cn.hutool.core.util.RandomUtil.randomEle; | ||
| 22 | +import static cn.hutool.core.util.RandomUtil.randomInt; | ||
| 21 | 23 | ||
| 22 | /** | 24 | /** |
| 23 | * 代码生成器的 Builder,负责: | 25 | * 代码生成器的 Builder,负责: |
| @@ -128,6 +130,7 @@ public class CodegenBuilder { | @@ -128,6 +130,7 @@ public class CodegenBuilder { | ||
| 128 | // 初始化 Column 列的默认字段 | 130 | // 初始化 Column 列的默认字段 |
| 129 | processColumnOperation(column); // 处理 CRUD 相关的字段的默认值 | 131 | processColumnOperation(column); // 处理 CRUD 相关的字段的默认值 |
| 130 | processColumnUI(column); // 处理 UI 相关的字段的默认值 | 132 | processColumnUI(column); // 处理 UI 相关的字段的默认值 |
| 133 | + processColumnExample(column); // 处理字段的 swagger example 示例 | ||
| 131 | } | 134 | } |
| 132 | return columns; | 135 | return columns; |
| 133 | } | 136 | } |
| @@ -169,4 +172,42 @@ public class CodegenBuilder { | @@ -169,4 +172,42 @@ public class CodegenBuilder { | ||
| 169 | } | 172 | } |
| 170 | } | 173 | } |
| 171 | 174 | ||
| 175 | + /** | ||
| 176 | + * 处理字段的 swagger example 示例 | ||
| 177 | + * | ||
| 178 | + * @param column 字段 | ||
| 179 | + */ | ||
| 180 | + private void processColumnExample(CodegenColumnDO column) { | ||
| 181 | + // id、price、count 等可能是整数的后缀 | ||
| 182 | + if (StrUtil.endWithAnyIgnoreCase(column.getJavaField(), "id", "price", "count")) { | ||
| 183 | + column.setExample(String.valueOf(randomInt(1, Short.MAX_VALUE))); | ||
| 184 | + return; | ||
| 185 | + } | ||
| 186 | + // name | ||
| 187 | + if (StrUtil.endWithIgnoreCase(column.getJavaField(), "name")) { | ||
| 188 | + column.setExample(randomEle(new String[]{"张三", "李四", "王五", "赵六", "芋艿"})); | ||
| 189 | + return; | ||
| 190 | + } | ||
| 191 | + // status | ||
| 192 | + if (StrUtil.endWithAnyIgnoreCase(column.getJavaField(), "status", "type")) { | ||
| 193 | + column.setExample(randomEle(new String[]{"1", "2"})); | ||
| 194 | + return; | ||
| 195 | + } | ||
| 196 | + // url | ||
| 197 | + if (StrUtil.endWithIgnoreCase(column.getColumnName(), "url")) { | ||
| 198 | + column.setExample("https://www.iocoder.cn"); | ||
| 199 | + return; | ||
| 200 | + } | ||
| 201 | + // reason | ||
| 202 | + if (StrUtil.endWithIgnoreCase(column.getColumnName(), "reason")) { | ||
| 203 | + column.setExample(randomEle(new String[]{"不喜欢", "不对", "不好", "不香"})); | ||
| 204 | + return; | ||
| 205 | + } | ||
| 206 | + // description、memo、remark | ||
| 207 | + if (StrUtil.endWithAnyIgnoreCase(column.getColumnName(), "description", "memo", "remark")) { | ||
| 208 | + column.setExample(randomEle(new String[]{"你猜", "随便", "你说的对"})); | ||
| 209 | + return; | ||
| 210 | + } | ||
| 211 | + } | ||
| 212 | + | ||
| 172 | } | 213 | } |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
| 1 | package cn.iocoder.yudao.module.infra.service.file; | 1 | package cn.iocoder.yudao.module.infra.service.file; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.hutool.core.io.resource.ResourceUtil; | 3 | import cn.hutool.core.io.resource.ResourceUtil; |
| 5 | import cn.hutool.core.util.IdUtil; | 4 | import cn.hutool.core.util.IdUtil; |
| 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| @@ -20,7 +19,6 @@ import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; | @@ -20,7 +19,6 @@ import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; | ||
| 20 | import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer; | 19 | import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer; |
| 21 | import lombok.Getter; | 20 | import lombok.Getter; |
| 22 | import lombok.extern.slf4j.Slf4j; | 21 | import lombok.extern.slf4j.Slf4j; |
| 23 | -import org.springframework.context.annotation.Lazy; | ||
| 24 | import org.springframework.scheduling.annotation.Scheduled; | 22 | import org.springframework.scheduling.annotation.Scheduled; |
| 25 | import org.springframework.stereotype.Service; | 23 | import org.springframework.stereotype.Service; |
| 26 | import org.springframework.transaction.annotation.Transactional; | 24 | import org.springframework.transaction.annotation.Transactional; |
| @@ -79,20 +77,36 @@ public class FileConfigServiceImpl implements FileConfigService { | @@ -79,20 +77,36 @@ public class FileConfigServiceImpl implements FileConfigService { | ||
| 79 | @Resource | 77 | @Resource |
| 80 | private Validator validator; | 78 | private Validator validator; |
| 81 | 79 | ||
| 82 | - @Resource | ||
| 83 | - @Lazy // 注入自己,所以延迟加载 | ||
| 84 | - private FileConfigService self; | ||
| 85 | - | ||
| 86 | @Override | 80 | @Override |
| 87 | @PostConstruct | 81 | @PostConstruct |
| 88 | public void initFileClients() { | 82 | public void initFileClients() { |
| 89 | - // 获取文件配置,如果有更新 | ||
| 90 | - List<FileConfigDO> configs = loadFileConfigIfUpdate(maxUpdateTime); | ||
| 91 | - if (CollUtil.isEmpty(configs)) { | 83 | + initLocalCacheIfUpdate(null); |
| 84 | + } | ||
| 85 | + | ||
| 86 | + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | ||
| 87 | + public void schedulePeriodicRefresh() { | ||
| 88 | + initLocalCacheIfUpdate(this.maxUpdateTime); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + /** | ||
| 92 | + * 刷新本地缓存 | ||
| 93 | + * | ||
| 94 | + * @param maxUpdateTime 最大更新时间 | ||
| 95 | + * 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存 | ||
| 96 | + * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存 | ||
| 97 | + */ | ||
| 98 | + private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) { | ||
| 99 | + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。 | ||
| 100 | + // 如果没有增量的数据变化,则不进行本地缓存的刷新 | ||
| 101 | + if (maxUpdateTime != null | ||
| 102 | + && fileConfigMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) { | ||
| 103 | + log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime); | ||
| 92 | return; | 104 | return; |
| 93 | } | 105 | } |
| 106 | + List<FileConfigDO> configs = fileConfigMapper.selectList(); | ||
| 107 | + log.info("[initLocalCacheIfUpdate][缓存文件配置,数量为:{}]", configs.size()); | ||
| 94 | 108 | ||
| 95 | - // 创建或更新支付 Client | 109 | + // 第二步:构建缓存。创建或更新文件 Client |
| 96 | configs.forEach(config -> { | 110 | configs.forEach(config -> { |
| 97 | fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig()); | 111 | fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig()); |
| 98 | // 如果是 master,进行设置 | 112 | // 如果是 master,进行设置 |
| @@ -101,35 +115,8 @@ public class FileConfigServiceImpl implements FileConfigService { | @@ -101,35 +115,8 @@ public class FileConfigServiceImpl implements FileConfigService { | ||
| 101 | } | 115 | } |
| 102 | }); | 116 | }); |
| 103 | 117 | ||
| 104 | - // 写入缓存 | ||
| 105 | - maxUpdateTime = CollectionUtils.getMaxValue(configs, FileConfigDO::getUpdateTime); | ||
| 106 | - log.info("[initFileClients][初始化 FileConfig 数量为 {}]", configs.size()); | ||
| 107 | - } | ||
| 108 | - | ||
| 109 | - @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | ||
| 110 | - public void schedulePeriodicRefresh() { | ||
| 111 | - self.initFileClients(); | ||
| 112 | - } | ||
| 113 | - | ||
| 114 | - /** | ||
| 115 | - * 如果文件配置发生变化,从数据库中获取最新的全量文件配置。 | ||
| 116 | - * 如果未发生变化,则返回空 | ||
| 117 | - * | ||
| 118 | - * @param maxUpdateTime 当前文件配置的最大更新时间 | ||
| 119 | - * @return 文件配置列表 | ||
| 120 | - */ | ||
| 121 | - private List<FileConfigDO> loadFileConfigIfUpdate(LocalDateTime maxUpdateTime) { | ||
| 122 | - // 第一步,判断是否要更新。 | ||
| 123 | - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 | ||
| 124 | - log.info("[loadFileConfigIfUpdate][首次加载全量文件配置]"); | ||
| 125 | - } else { // 判断数据库中是否有更新的文件配置 | ||
| 126 | - if (fileConfigMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) { | ||
| 127 | - return null; | ||
| 128 | - } | ||
| 129 | - log.info("[loadFileConfigIfUpdate][增量加载全量文件配置]"); | ||
| 130 | - } | ||
| 131 | - // 第二步,如果有更新,则从数据库加载所有文件配置 | ||
| 132 | - return fileConfigMapper.selectList(); | 118 | + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。 |
| 119 | + this.maxUpdateTime = CollectionUtils.getMaxValue(configs, FileConfigDO::getUpdateTime); | ||
| 133 | } | 120 | } |
| 134 | 121 | ||
| 135 | @Override | 122 | @Override |
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm
| 1 | <template> | 1 | <template> |
| 2 | <ContentWrap> | 2 | <ContentWrap> |
| 3 | <!-- 列表 --> | 3 | <!-- 列表 --> |
| 4 | - <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar"> | 4 | + <XTable @register="registerTable"> |
| 5 | <template #toolbar_buttons> | 5 | <template #toolbar_buttons> |
| 6 | <!-- 操作:新增 --> | 6 | <!-- 操作:新增 --> |
| 7 | <XButton | 7 | <XButton |
| @@ -43,7 +43,7 @@ | @@ -43,7 +43,7 @@ | ||
| 43 | @click="handleDelete(row.id)" | 43 | @click="handleDelete(row.id)" |
| 44 | /> | 44 | /> |
| 45 | </template> | 45 | </template> |
| 46 | - </vxe-grid> | 46 | + </XTable> |
| 47 | </ContentWrap> | 47 | </ContentWrap> |
| 48 | <!-- 弹窗 --> | 48 | <!-- 弹窗 --> |
| 49 | <XModal id="${classNameVar}Model" :loading="modelLoading" v-model="modelVisible" :title="modelTitle"> | 49 | <XModal id="${classNameVar}Model" :loading="modelLoading" v-model="modelVisible" :title="modelTitle"> |
| @@ -79,8 +79,7 @@ | @@ -79,8 +79,7 @@ | ||
| 79 | import { ref, unref } from 'vue' | 79 | import { ref, unref } from 'vue' |
| 80 | import { useI18n } from '@/hooks/web/useI18n' | 80 | import { useI18n } from '@/hooks/web/useI18n' |
| 81 | import { useMessage } from '@/hooks/web/useMessage' | 81 | import { useMessage } from '@/hooks/web/useMessage' |
| 82 | -import { useVxeGrid } from '@/hooks/web/useVxeGrid' | ||
| 83 | -import { VxeGridInstance } from 'vxe-table' | 82 | +import { useXTable } from '@/hooks/web/useXTable' |
| 84 | import { FormExpose } from '@/components/Form' | 83 | import { FormExpose } from '@/components/Form' |
| 85 | // 业务相关的 import | 84 | // 业务相关的 import |
| 86 | import { rules, allSchemas } from './${classNameVar}.data' | 85 | import { rules, allSchemas } from './${classNameVar}.data' |
| @@ -90,8 +89,7 @@ const { t } = useI18n() // 国际化 | @@ -90,8 +89,7 @@ const { t } = useI18n() // 国际化 | ||
| 90 | const message = useMessage() // 消息弹窗 | 89 | const message = useMessage() // 消息弹窗 |
| 91 | 90 | ||
| 92 | // 列表相关的变量 | 91 | // 列表相关的变量 |
| 93 | -const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref | ||
| 94 | -const { gridOptions, getList, deleteData, exportList } = useVxeGrid<${simpleClassName}Api.${simpleClassName}VO>({ | 92 | +const [registerTable, { reload, deleteData, exportList }] = useXTable({ |
| 95 | allSchemas: allSchemas, | 93 | allSchemas: allSchemas, |
| 96 | getListApi: ${simpleClassName}Api.get${simpleClassName}PageApi, | 94 | getListApi: ${simpleClassName}Api.get${simpleClassName}PageApi, |
| 97 | deleteApi: ${simpleClassName}Api.delete${simpleClassName}Api, | 95 | deleteApi: ${simpleClassName}Api.delete${simpleClassName}Api, |
| @@ -123,7 +121,7 @@ const handleCreate = () => { | @@ -123,7 +121,7 @@ const handleCreate = () => { | ||
| 123 | 121 | ||
| 124 | // 导出操作 | 122 | // 导出操作 |
| 125 | const handleExport = async () => { | 123 | const handleExport = async () => { |
| 126 | - await exportList(xGrid, '${table.classComment}.xls') | 124 | + await exportList('${table.classComment}.xls') |
| 127 | } | 125 | } |
| 128 | 126 | ||
| 129 | // 修改操作 | 127 | // 修改操作 |
| @@ -145,7 +143,7 @@ const handleDetail = async (rowId: number) => { | @@ -145,7 +143,7 @@ const handleDetail = async (rowId: number) => { | ||
| 145 | 143 | ||
| 146 | // 删除操作 | 144 | // 删除操作 |
| 147 | const handleDelete = async (rowId: number) => { | 145 | const handleDelete = async (rowId: number) => { |
| 148 | - await deleteData(xGrid, rowId) | 146 | + await deleteData(rowId) |
| 149 | } | 147 | } |
| 150 | 148 | ||
| 151 | // 提交按钮 | 149 | // 提交按钮 |
| @@ -169,7 +167,7 @@ const submitForm = async () => { | @@ -169,7 +167,7 @@ const submitForm = async () => { | ||
| 169 | } finally { | 167 | } finally { |
| 170 | actionLoading.value = false | 168 | actionLoading.value = false |
| 171 | // 刷新列表 | 169 | // 刷新列表 |
| 172 | - await getList(xGrid) | 170 | + await reload() |
| 173 | } | 171 | } |
| 174 | } | 172 | } |
| 175 | }) | 173 | }) |
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceTest.java
| @@ -79,7 +79,7 @@ public class FileServiceTest extends BaseDbUnitTest { | @@ -79,7 +79,7 @@ public class FileServiceTest extends BaseDbUnitTest { | ||
| 79 | FileClient client = mock(FileClient.class); | 79 | FileClient client = mock(FileClient.class); |
| 80 | when(fileConfigService.getMasterFileClient()).thenReturn(client); | 80 | when(fileConfigService.getMasterFileClient()).thenReturn(client); |
| 81 | String url = randomString(); | 81 | String url = randomString(); |
| 82 | - when(client.upload(same(content), same(path), same("image/jpeg"))).thenReturn(url); | 82 | + when(client.upload(same(content), same(path), eq("image/jpeg"))).thenReturn(url); |
| 83 | when(client.getId()).thenReturn(10L); | 83 | when(client.getId()).thenReturn(10L); |
| 84 | String name = "单测文件名"; | 84 | String name = "单测文件名"; |
| 85 | // 调用 | 85 | // 调用 |
yudao-module-infra/yudao-module-infra-biz/src/test/resources/application-unit-test.yaml
| @@ -9,7 +9,7 @@ spring: | @@ -9,7 +9,7 @@ spring: | ||
| 9 | # 数据源配置项 | 9 | # 数据源配置项 |
| 10 | datasource: | 10 | datasource: |
| 11 | name: ruoyi-vue-pro | 11 | name: ruoyi-vue-pro |
| 12 | - url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 | 12 | + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 |
| 13 | driver-class-name: org.h2.Driver | 13 | driver-class-name: org.h2.Driver |
| 14 | username: sa | 14 | username: sa |
| 15 | password: | 15 | password: |
yudao-module-mall/pom.xml
| @@ -15,18 +15,15 @@ | @@ -15,18 +15,15 @@ | ||
| 15 | <name>${project.artifactId}</name> | 15 | <name>${project.artifactId}</name> |
| 16 | 16 | ||
| 17 | <description> | 17 | <description> |
| 18 | - 商城大模块,由 product 商品、promotion 营销、trade 交易 coupon等组成 | 18 | + 商城大模块,由 product 商品、promotion 营销、trade 交易等组成 |
| 19 | </description> | 19 | </description> |
| 20 | <modules> | 20 | <modules> |
| 21 | -<!-- <module>yudao-module-coupon-api</module>--> | ||
| 22 | -<!-- <module>yudao-module-coupon-biz</module>--> | ||
| 23 | <module>yudao-module-promotion-api</module> | 21 | <module>yudao-module-promotion-api</module> |
| 24 | <module>yudao-module-promotion-biz</module> | 22 | <module>yudao-module-promotion-biz</module> |
| 25 | <module>yudao-module-product-api</module> | 23 | <module>yudao-module-product-api</module> |
| 26 | <module>yudao-module-product-biz</module> | 24 | <module>yudao-module-product-biz</module> |
| 27 | <module>yudao-module-trade-api</module> | 25 | <module>yudao-module-trade-api</module> |
| 28 | <module>yudao-module-trade-biz</module> | 26 | <module>yudao-module-trade-biz</module> |
| 29 | - | ||
| 30 | </modules> | 27 | </modules> |
| 31 | 28 | ||
| 32 | </project> | 29 | </project> |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/property/ProductPropertyValueApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.api.property; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; | ||
| 4 | + | ||
| 5 | +import java.util.Collection; | ||
| 6 | +import java.util.List; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 商品属性值 API 接口 | ||
| 10 | + * | ||
| 11 | + * @author 芋道源码 | ||
| 12 | + */ | ||
| 13 | +public interface ProductPropertyValueApi { | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 根据编号数组,获得属性值列表 | ||
| 17 | + * | ||
| 18 | + * @param ids 编号数组 | ||
| 19 | + * @return 属性值明细列表 | ||
| 20 | + */ | ||
| 21 | + List<ProductPropertyValueDetailRespDTO> getPropertyValueDetailList(Collection<Long> ids); | ||
| 22 | + | ||
| 23 | +} |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/property/dto/ProductPropertyValueDetailRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.api.property.dto; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 商品属性项的明细 Response DTO | ||
| 7 | + * | ||
| 8 | + * @author 芋道源码 | ||
| 9 | + */ | ||
| 10 | +@Data | ||
| 11 | +public class ProductPropertyValueDetailRespDTO { | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * 属性的编号 | ||
| 15 | + */ | ||
| 16 | + private Long propertyId; | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 属性的名称 | ||
| 20 | + */ | ||
| 21 | + private String propertyName; | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * 属性值的编号 | ||
| 25 | + */ | ||
| 26 | + private Long valueId; | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 属性值的名称 | ||
| 30 | + */ | ||
| 31 | + private String valueName; | ||
| 32 | + | ||
| 33 | +} |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java
| @@ -19,16 +19,16 @@ public class ProductSkuRespDTO { | @@ -19,16 +19,16 @@ public class ProductSkuRespDTO { | ||
| 19 | */ | 19 | */ |
| 20 | private Long id; | 20 | private Long id; |
| 21 | /** | 21 | /** |
| 22 | - * 商品 SKU 名字 | ||
| 23 | - */ | ||
| 24 | - private String name; | ||
| 25 | - /** | ||
| 26 | * SPU 编号 | 22 | * SPU 编号 |
| 27 | */ | 23 | */ |
| 28 | private Long spuId; | 24 | private Long spuId; |
| 25 | + /** | ||
| 26 | + * SPU 名字 | ||
| 27 | + */ | ||
| 28 | + private String spuName; | ||
| 29 | 29 | ||
| 30 | /** | 30 | /** |
| 31 | - * 规格值数组,JSON 格式 | 31 | + * 属性数组,JSON 格式 |
| 32 | */ | 32 | */ |
| 33 | private List<Property> properties; | 33 | private List<Property> properties; |
| 34 | /** | 34 | /** |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
| @@ -15,28 +15,30 @@ public interface ErrorCodeConstants { | @@ -15,28 +15,30 @@ public interface ErrorCodeConstants { | ||
| 15 | ErrorCode CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1008001002, "父分类不能是二级分类"); | 15 | ErrorCode CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1008001002, "父分类不能是二级分类"); |
| 16 | ErrorCode CATEGORY_EXISTS_CHILDREN = new ErrorCode(1008001003, "存在子分类,无法删除"); | 16 | ErrorCode CATEGORY_EXISTS_CHILDREN = new ErrorCode(1008001003, "存在子分类,无法删除"); |
| 17 | ErrorCode CATEGORY_DISABLED = new ErrorCode(1008001004, "商品分类({})已禁用,无法使用"); | 17 | ErrorCode CATEGORY_DISABLED = new ErrorCode(1008001004, "商品分类({})已禁用,无法使用"); |
| 18 | - ErrorCode CATEGORY_LEVEL_ERROR = new ErrorCode(1008001005, "商品分类不正确,原因:必须使用第三级的商品分类下"); | ||
| 19 | 18 | ||
| 20 | // ========== 商品品牌相关编号 1008002000 ========== | 19 | // ========== 商品品牌相关编号 1008002000 ========== |
| 21 | ErrorCode BRAND_NOT_EXISTS = new ErrorCode(1008002000, "品牌不存在"); | 20 | ErrorCode BRAND_NOT_EXISTS = new ErrorCode(1008002000, "品牌不存在"); |
| 22 | ErrorCode BRAND_DISABLED = new ErrorCode(1008002001, "品牌不存在"); | 21 | ErrorCode BRAND_DISABLED = new ErrorCode(1008002001, "品牌不存在"); |
| 23 | ErrorCode BRAND_NAME_EXISTS = new ErrorCode(1008002002, "品牌名称已存在"); | 22 | ErrorCode BRAND_NAME_EXISTS = new ErrorCode(1008002002, "品牌名称已存在"); |
| 24 | 23 | ||
| 25 | - // ========== 商品规格名称 1008003000 ========== | ||
| 26 | - ErrorCode PROPERTY_NOT_EXISTS = new ErrorCode(1008003000, "规格名称不存在"); | ||
| 27 | - ErrorCode PROPERTY_EXISTS = new ErrorCode(1008003001, "规格名称已存在"); | 24 | + // ========== 商品属性项 1008003000 ========== |
| 25 | + ErrorCode PROPERTY_NOT_EXISTS = new ErrorCode(1008003000, "属性项不存在"); | ||
| 26 | + ErrorCode PROPERTY_EXISTS = new ErrorCode(1008003001, "属性项的名称已存在"); | ||
| 27 | + ErrorCode PROPERTY_DELETE_FAIL_VALUE_EXISTS = new ErrorCode(1008003002, "属性项下存在属性值,无法删除"); | ||
| 28 | 28 | ||
| 29 | - // ========== 规格值 1008004000 ========== | ||
| 30 | - ErrorCode PROPERTY_VALUE_NOT_EXISTS = new ErrorCode(1008004000, "规格值不存在"); | ||
| 31 | - ErrorCode PROPERTY_VALUE_EXISTS = new ErrorCode(1008004001, "规格值已存在"); | 29 | + // ========== 商品属性值 1008004000 ========== |
| 30 | + ErrorCode PROPERTY_VALUE_NOT_EXISTS = new ErrorCode(1008004000, "属性值不存在"); | ||
| 31 | + ErrorCode PROPERTY_VALUE_EXISTS = new ErrorCode(1008004001, "属性值的名称已存在"); | ||
| 32 | 32 | ||
| 33 | // ========== 商品 SPU 1008005000 ========== | 33 | // ========== 商品 SPU 1008005000 ========== |
| 34 | ErrorCode SPU_NOT_EXISTS = new ErrorCode(1008005000, "商品 SPU 不存在"); | 34 | ErrorCode SPU_NOT_EXISTS = new ErrorCode(1008005000, "商品 SPU 不存在"); |
| 35 | + ErrorCode SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR = new ErrorCode(1008005001, "商品分类不正确,原因:必须使用第三级的商品分类下"); | ||
| 36 | + ErrorCode SPU_NOT_ENABLE = new ErrorCode(1008005002, "商品 SPU 不处于上架状态"); | ||
| 35 | 37 | ||
| 36 | // ========== 商品 SKU 1008006000 ========== | 38 | // ========== 商品 SKU 1008006000 ========== |
| 37 | ErrorCode SKU_NOT_EXISTS = new ErrorCode(1008006000, "商品 SKU 不存在"); | 39 | ErrorCode SKU_NOT_EXISTS = new ErrorCode(1008006000, "商品 SKU 不存在"); |
| 38 | ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品 SKU 的属性组合存在重复"); | 40 | ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品 SKU 的属性组合存在重复"); |
| 39 | - ErrorCode SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1008006002, "一个 SPU 下的每个 SKU,其规格数必须一致"); | 41 | + ErrorCode SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1008006002, "一个 SPU 下的每个 SKU,其属性项必须一致"); |
| 40 | ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1008006003, "一个 SPU 下的每个 SKU,必须不重复"); | 42 | ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1008006003, "一个 SPU 下的每个 SKU,必须不重复"); |
| 41 | ErrorCode SKU_STOCK_NOT_ENOUGH = new ErrorCode(1008006004, "商品 SKU 库存不足"); | 43 | ErrorCode SKU_STOCK_NOT_ENOUGH = new ErrorCode(1008006004, "商品 SKU 库存不足"); |
| 42 | 44 |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuSpecTypeEnum.java
| @@ -21,11 +21,11 @@ public enum ProductSpuSpecTypeEnum implements IntArrayValuable { | @@ -21,11 +21,11 @@ public enum ProductSpuSpecTypeEnum implements IntArrayValuable { | ||
| 21 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductSpuSpecTypeEnum::getType).toArray(); | 21 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductSpuSpecTypeEnum::getType).toArray(); |
| 22 | 22 | ||
| 23 | /** | 23 | /** |
| 24 | - * 规格 | 24 | + * 规格类型 |
| 25 | */ | 25 | */ |
| 26 | private final Integer type; | 26 | private final Integer type; |
| 27 | /** | 27 | /** |
| 28 | - * 规格名 | 28 | + * 规格名称 |
| 29 | */ | 29 | */ |
| 30 | private final String name; | 30 | private final String name; |
| 31 | 31 |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java
| @@ -35,4 +35,14 @@ public enum ProductSpuStatusEnum implements IntArrayValuable { | @@ -35,4 +35,14 @@ public enum ProductSpuStatusEnum implements IntArrayValuable { | ||
| 35 | return ARRAYS; | 35 | return ARRAYS; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | + /** | ||
| 39 | + * 判断是否处于【上架】状态 | ||
| 40 | + * | ||
| 41 | + * @param status 状态 | ||
| 42 | + * @return 是否处于【上架】状态 | ||
| 43 | + */ | ||
| 44 | + public static boolean isEnable(Integer status) { | ||
| 45 | + return ENABLE.getStatus().equals(status); | ||
| 46 | + } | ||
| 47 | + | ||
| 38 | } | 48 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/property/ProductPropertyValueApiImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.api.property; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; | ||
| 4 | +import cn.iocoder.yudao.module.product.convert.propertyvalue.ProductPropertyValueConvert; | ||
| 5 | +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; | ||
| 6 | +import org.springframework.stereotype.Service; | ||
| 7 | +import org.springframework.validation.annotation.Validated; | ||
| 8 | + | ||
| 9 | +import javax.annotation.Resource; | ||
| 10 | +import java.util.Collection; | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * 商品属性值 API 实现类 | ||
| 15 | + * | ||
| 16 | + * @author 芋道源码 | ||
| 17 | + */ | ||
| 18 | +@Service | ||
| 19 | +@Validated | ||
| 20 | +public class ProductPropertyValueApiImpl implements ProductPropertyValueApi { | ||
| 21 | + | ||
| 22 | + @Resource | ||
| 23 | + private ProductPropertyValueService productPropertyValueService; | ||
| 24 | + | ||
| 25 | + @Override | ||
| 26 | + public List<ProductPropertyValueDetailRespDTO> getPropertyValueDetailList(Collection<Long> ids) { | ||
| 27 | + return ProductPropertyValueConvert.INSTANCE.convertList02( | ||
| 28 | + productPropertyValueService.getPropertyValueDetailList(ids)); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | +} |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java
| 1 | package cn.iocoder.yudao.module.product.controller.admin.property; | 1 | package cn.iocoder.yudao.module.product.controller.admin.property; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*; | 6 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*; |
| 7 | +import cn.iocoder.yudao.module.product.convert.property.ProductPropertyConvert; | ||
| 8 | +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; | ||
| 9 | +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; | ||
| 6 | import cn.iocoder.yudao.module.product.service.property.ProductPropertyService; | 10 | import cn.iocoder.yudao.module.product.service.property.ProductPropertyService; |
| 11 | +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; | ||
| 7 | import io.swagger.v3.oas.annotations.tags.Tag; | 12 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 8 | import io.swagger.v3.oas.annotations.Parameter; | 13 | import io.swagger.v3.oas.annotations.Parameter; |
| 9 | import io.swagger.v3.oas.annotations.Operation; | 14 | import io.swagger.v3.oas.annotations.Operation; |
| @@ -13,12 +18,13 @@ import org.springframework.web.bind.annotation.*; | @@ -13,12 +18,13 @@ import org.springframework.web.bind.annotation.*; | ||
| 13 | 18 | ||
| 14 | import javax.annotation.Resource; | 19 | import javax.annotation.Resource; |
| 15 | import javax.validation.Valid; | 20 | import javax.validation.Valid; |
| 16 | - | 21 | +import java.util.Collections; |
| 17 | import java.util.List; | 22 | import java.util.List; |
| 18 | 23 | ||
| 19 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 24 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 25 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | ||
| 20 | 26 | ||
| 21 | -@Tag(name = "管理后台 - 规格名称") | 27 | +@Tag(name = "管理后台 - 商品属性项") |
| 22 | @RestController | 28 | @RestController |
| 23 | @RequestMapping("/product/property") | 29 | @RequestMapping("/product/property") |
| 24 | @Validated | 30 | @Validated |
| @@ -26,16 +32,18 @@ public class ProductPropertyController { | @@ -26,16 +32,18 @@ public class ProductPropertyController { | ||
| 26 | 32 | ||
| 27 | @Resource | 33 | @Resource |
| 28 | private ProductPropertyService productPropertyService; | 34 | private ProductPropertyService productPropertyService; |
| 35 | + @Resource | ||
| 36 | + private ProductPropertyValueService productPropertyValueService; | ||
| 29 | 37 | ||
| 30 | @PostMapping("/create") | 38 | @PostMapping("/create") |
| 31 | - @Operation(summary = "创建规格名称") | 39 | + @Operation(summary = "创建属性项") |
| 32 | @PreAuthorize("@ss.hasPermission('product:property:create')") | 40 | @PreAuthorize("@ss.hasPermission('product:property:create')") |
| 33 | public CommonResult<Long> createProperty(@Valid @RequestBody ProductPropertyCreateReqVO createReqVO) { | 41 | public CommonResult<Long> createProperty(@Valid @RequestBody ProductPropertyCreateReqVO createReqVO) { |
| 34 | return success(productPropertyService.createProperty(createReqVO)); | 42 | return success(productPropertyService.createProperty(createReqVO)); |
| 35 | } | 43 | } |
| 36 | 44 | ||
| 37 | @PutMapping("/update") | 45 | @PutMapping("/update") |
| 38 | - @Operation(summary = "更新规格名称") | 46 | + @Operation(summary = "更新属性项") |
| 39 | @PreAuthorize("@ss.hasPermission('product:property:update')") | 47 | @PreAuthorize("@ss.hasPermission('product:property:update')") |
| 40 | public CommonResult<Boolean> updateProperty(@Valid @RequestBody ProductPropertyUpdateReqVO updateReqVO) { | 48 | public CommonResult<Boolean> updateProperty(@Valid @RequestBody ProductPropertyUpdateReqVO updateReqVO) { |
| 41 | productPropertyService.updateProperty(updateReqVO); | 49 | productPropertyService.updateProperty(updateReqVO); |
| @@ -43,7 +51,7 @@ public class ProductPropertyController { | @@ -43,7 +51,7 @@ public class ProductPropertyController { | ||
| 43 | } | 51 | } |
| 44 | 52 | ||
| 45 | @DeleteMapping("/delete") | 53 | @DeleteMapping("/delete") |
| 46 | - @Operation(summary = "删除规格名称") | 54 | + @Operation(summary = "删除属性项") |
| 47 | @Parameter(name = "id", description = "编号", required = true) | 55 | @Parameter(name = "id", description = "编号", required = true) |
| 48 | @PreAuthorize("@ss.hasPermission('product:property:delete')") | 56 | @PreAuthorize("@ss.hasPermission('product:property:delete')") |
| 49 | public CommonResult<Boolean> deleteProperty(@RequestParam("id") Long id) { | 57 | public CommonResult<Boolean> deleteProperty(@RequestParam("id") Long id) { |
| @@ -52,32 +60,40 @@ public class ProductPropertyController { | @@ -52,32 +60,40 @@ public class ProductPropertyController { | ||
| 52 | } | 60 | } |
| 53 | 61 | ||
| 54 | @GetMapping("/get") | 62 | @GetMapping("/get") |
| 55 | - @Operation(summary = "获得规格名称") | 63 | + @Operation(summary = "获得属性项") |
| 56 | @Parameter(name = "id", description = "编号", required = true, example = "1024") | 64 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 57 | @PreAuthorize("@ss.hasPermission('product:property:query')") | 65 | @PreAuthorize("@ss.hasPermission('product:property:query')") |
| 58 | public CommonResult<ProductPropertyRespVO> getProperty(@RequestParam("id") Long id) { | 66 | public CommonResult<ProductPropertyRespVO> getProperty(@RequestParam("id") Long id) { |
| 59 | - return success(productPropertyService.getProperty(id)); | 67 | + return success(ProductPropertyConvert.INSTANCE.convert(productPropertyService.getProperty(id))); |
| 60 | } | 68 | } |
| 61 | 69 | ||
| 62 | @GetMapping("/list") | 70 | @GetMapping("/list") |
| 63 | - @Operation(summary = "获得规格名称列表") | 71 | + @Operation(summary = "获得属性项列表") |
| 64 | @PreAuthorize("@ss.hasPermission('product:property:query')") | 72 | @PreAuthorize("@ss.hasPermission('product:property:query')") |
| 65 | public CommonResult<List<ProductPropertyRespVO>> getPropertyList(@Valid ProductPropertyListReqVO listReqVO) { | 73 | public CommonResult<List<ProductPropertyRespVO>> getPropertyList(@Valid ProductPropertyListReqVO listReqVO) { |
| 66 | - return success(productPropertyService.getPropertyList(listReqVO)); | 74 | + return success(ProductPropertyConvert.INSTANCE.convertList(productPropertyService.getPropertyList(listReqVO))); |
| 67 | } | 75 | } |
| 68 | 76 | ||
| 69 | @GetMapping("/page") | 77 | @GetMapping("/page") |
| 70 | - @Operation(summary = "获得规格名称分页") | 78 | + @Operation(summary = "获得属性项分页") |
| 71 | @PreAuthorize("@ss.hasPermission('product:property:query')") | 79 | @PreAuthorize("@ss.hasPermission('product:property:query')") |
| 72 | public CommonResult<PageResult<ProductPropertyRespVO>> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) { | 80 | public CommonResult<PageResult<ProductPropertyRespVO>> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) { |
| 73 | - return success(productPropertyService.getPropertyPage(pageVO)); | 81 | + return success(ProductPropertyConvert.INSTANCE.convertPage(productPropertyService.getPropertyPage(pageVO))); |
| 74 | } | 82 | } |
| 75 | 83 | ||
| 76 | - @GetMapping("/listAndValue") | ||
| 77 | - @Operation(summary = "获得规格名称列表") | 84 | + @GetMapping("/get-value-list") |
| 85 | + @Operation(summary = "获得属性项列表") | ||
| 78 | @PreAuthorize("@ss.hasPermission('product:property:query')") | 86 | @PreAuthorize("@ss.hasPermission('product:property:query')") |
| 79 | public CommonResult<List<ProductPropertyAndValueRespVO>> getPropertyAndValueList(@Valid ProductPropertyListReqVO listReqVO) { | 87 | public CommonResult<List<ProductPropertyAndValueRespVO>> getPropertyAndValueList(@Valid ProductPropertyListReqVO listReqVO) { |
| 80 | - return success(productPropertyService.getPropertyAndValueList(listReqVO)); | 88 | + // 查询属性项 |
| 89 | + List<ProductPropertyDO> keys = productPropertyService.getPropertyList(listReqVO); | ||
| 90 | + if (CollUtil.isEmpty(keys)) { | ||
| 91 | + return success(Collections.emptyList()); | ||
| 92 | + } | ||
| 93 | + // 查询属性值 | ||
| 94 | + List<ProductPropertyValueDO> values = productPropertyValueService.getPropertyValueListByPropertyId( | ||
| 95 | + convertSet(keys, ProductPropertyDO::getId)); | ||
| 96 | + return success(ProductPropertyConvert.INSTANCE.convertList(keys, values)); | ||
| 81 | } | 97 | } |
| 82 | 98 | ||
| 83 | } | 99 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java
| @@ -2,11 +2,11 @@ package cn.iocoder.yudao.module.product.controller.admin.property; | @@ -2,11 +2,11 @@ package cn.iocoder.yudao.module.product.controller.admin.property; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | -import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyPageReqVO; | ||
| 6 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO; | 5 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO; |
| 7 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO; | 6 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO; |
| 8 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; | 7 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; |
| 9 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO; | 8 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO; |
| 9 | +import cn.iocoder.yudao.module.product.convert.propertyvalue.ProductPropertyValueConvert; | ||
| 10 | import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; | 10 | import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; |
| 11 | import io.swagger.v3.oas.annotations.tags.Tag; | 11 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 12 | import io.swagger.v3.oas.annotations.Parameter; | 12 | import io.swagger.v3.oas.annotations.Parameter; |
| @@ -20,7 +20,7 @@ import javax.validation.Valid; | @@ -20,7 +20,7 @@ import javax.validation.Valid; | ||
| 20 | 20 | ||
| 21 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 21 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 22 | 22 | ||
| 23 | -@Tag(name = "管理后台 - 规格值名称") | 23 | +@Tag(name = "管理后台 - 商品属性值") |
| 24 | @RestController | 24 | @RestController |
| 25 | @RequestMapping("/product/property/value") | 25 | @RequestMapping("/product/property/value") |
| 26 | @Validated | 26 | @Validated |
| @@ -30,14 +30,14 @@ public class ProductPropertyValueController { | @@ -30,14 +30,14 @@ public class ProductPropertyValueController { | ||
| 30 | private ProductPropertyValueService productPropertyValueService; | 30 | private ProductPropertyValueService productPropertyValueService; |
| 31 | 31 | ||
| 32 | @PostMapping("/create") | 32 | @PostMapping("/create") |
| 33 | - @Operation(summary = "创建规格名称") | 33 | + @Operation(summary = "创建属性值") |
| 34 | @PreAuthorize("@ss.hasPermission('product:property:create')") | 34 | @PreAuthorize("@ss.hasPermission('product:property:create')") |
| 35 | public CommonResult<Long> createProperty(@Valid @RequestBody ProductPropertyValueCreateReqVO createReqVO) { | 35 | public CommonResult<Long> createProperty(@Valid @RequestBody ProductPropertyValueCreateReqVO createReqVO) { |
| 36 | return success(productPropertyValueService.createPropertyValue(createReqVO)); | 36 | return success(productPropertyValueService.createPropertyValue(createReqVO)); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | @PutMapping("/update") | 39 | @PutMapping("/update") |
| 40 | - @Operation(summary = "更新规格名称") | 40 | + @Operation(summary = "更新属性值") |
| 41 | @PreAuthorize("@ss.hasPermission('product:property:update')") | 41 | @PreAuthorize("@ss.hasPermission('product:property:update')") |
| 42 | public CommonResult<Boolean> updateProperty(@Valid @RequestBody ProductPropertyValueUpdateReqVO updateReqVO) { | 42 | public CommonResult<Boolean> updateProperty(@Valid @RequestBody ProductPropertyValueUpdateReqVO updateReqVO) { |
| 43 | productPropertyValueService.updatePropertyValue(updateReqVO); | 43 | productPropertyValueService.updatePropertyValue(updateReqVO); |
| @@ -45,7 +45,7 @@ public class ProductPropertyValueController { | @@ -45,7 +45,7 @@ public class ProductPropertyValueController { | ||
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | @DeleteMapping("/delete") | 47 | @DeleteMapping("/delete") |
| 48 | - @Operation(summary = "删除规格名称") | 48 | + @Operation(summary = "删除属性值") |
| 49 | @Parameter(name = "id", description = "编号", required = true) | 49 | @Parameter(name = "id", description = "编号", required = true) |
| 50 | @PreAuthorize("@ss.hasPermission('product:property:delete')") | 50 | @PreAuthorize("@ss.hasPermission('product:property:delete')") |
| 51 | public CommonResult<Boolean> deleteProperty(@RequestParam("id") Long id) { | 51 | public CommonResult<Boolean> deleteProperty(@RequestParam("id") Long id) { |
| @@ -54,17 +54,17 @@ public class ProductPropertyValueController { | @@ -54,17 +54,17 @@ public class ProductPropertyValueController { | ||
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | @GetMapping("/get") | 56 | @GetMapping("/get") |
| 57 | - @Operation(summary = "获得规格名称") | 57 | + @Operation(summary = "获得属性值") |
| 58 | @Parameter(name = "id", description = "编号", required = true, example = "1024") | 58 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 59 | @PreAuthorize("@ss.hasPermission('product:property:query')") | 59 | @PreAuthorize("@ss.hasPermission('product:property:query')") |
| 60 | public CommonResult<ProductPropertyValueRespVO> getProperty(@RequestParam("id") Long id) { | 60 | public CommonResult<ProductPropertyValueRespVO> getProperty(@RequestParam("id") Long id) { |
| 61 | - return success(productPropertyValueService.getPropertyValue(id)); | 61 | + return success(ProductPropertyValueConvert.INSTANCE.convert(productPropertyValueService.getPropertyValue(id))); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | @GetMapping("/page") | 64 | @GetMapping("/page") |
| 65 | - @Operation(summary = "获得规格名称分页") | 65 | + @Operation(summary = "获得属性值分页") |
| 66 | @PreAuthorize("@ss.hasPermission('product:property:query')") | 66 | @PreAuthorize("@ss.hasPermission('product:property:query')") |
| 67 | public CommonResult<PageResult<ProductPropertyValueRespVO>> getPropertyValuePage(@Valid ProductPropertyValuePageReqVO pageVO) { | 67 | public CommonResult<PageResult<ProductPropertyValueRespVO>> getPropertyValuePage(@Valid ProductPropertyValuePageReqVO pageVO) { |
| 68 | - return success(productPropertyValueService.getPropertyValueListPage(pageVO)); | 68 | + return success(ProductPropertyValueConvert.INSTANCE.convertPage(productPropertyValueService.getPropertyValuePage(pageVO))); |
| 69 | } | 69 | } |
| 70 | } | 70 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/ProductPropertyViewRespVO.java
| 1 | -package cn.iocoder.yudao.module.product.controller.admin.property.vo; | ||
| 2 | - | ||
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | -import lombok.Data; | ||
| 5 | -import lombok.ToString; | ||
| 6 | - | ||
| 7 | -import java.util.List; | ||
| 8 | - | ||
| 9 | -/** | ||
| 10 | - * @Description: ProductPropertyViewRespVO | ||
| 11 | - * @Author: franky | ||
| 12 | - * @CreateDate: 2022/7/5 21:29 | ||
| 13 | - * @Version: 1.0.0 | ||
| 14 | - */ | ||
| 15 | -@Schema(description = "管理后台 - 规格名称详情展示 Request VO") | ||
| 16 | -@Data | ||
| 17 | -@ToString(callSuper = true) | ||
| 18 | -public class ProductPropertyViewRespVO { | ||
| 19 | - | ||
| 20 | - @Schema(description = "规格名称id", example = "1") | ||
| 21 | - public Long propertyId; | ||
| 22 | - | ||
| 23 | - @Schema(description = "规格名称", example = "内存") | ||
| 24 | - public String name; | ||
| 25 | - | ||
| 26 | - @Schema(description = "规格属性值集合", example = "[{\"v1\":11,\"v2\":\"64G\"},{\"v1\":10,\"v2\":\"32G\"}]") | ||
| 27 | - public List<Tuple2> propertyValues; | ||
| 28 | - | ||
| 29 | - @Data | ||
| 30 | - @Schema(description = "规格属性值元组") | ||
| 31 | - public static class Tuple2 { | ||
| 32 | - private final long id; | ||
| 33 | - private final String name; | ||
| 34 | - | ||
| 35 | - public Tuple2(Long id, String name) { | ||
| 36 | - this.id = id; | ||
| 37 | - this.name = name; | ||
| 38 | - } | ||
| 39 | - | ||
| 40 | - } | ||
| 41 | - | ||
| 42 | - | ||
| 43 | -} |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyAndValueRespVO.java
| 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; | 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; | ||
| 4 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | import lombok.Data; | 4 | import lombok.Data; |
| 6 | -import lombok.EqualsAndHashCode; | ||
| 7 | -import lombok.ToString; | ||
| 8 | 5 | ||
| 9 | -import java.time.LocalDateTime; | ||
| 10 | import java.util.List; | 6 | import java.util.List; |
| 11 | 7 | ||
| 12 | -@Schema(description = "管理后台 - 规格 + 规格值 Response VO") | 8 | +@Schema(description = "管理后台 - 商品属性项 + 属性值 Response VO") |
| 13 | @Data | 9 | @Data |
| 14 | -@EqualsAndHashCode(callSuper = true) | ||
| 15 | -@ToString(callSuper = true) | ||
| 16 | -public class ProductPropertyAndValueRespVO extends ProductPropertyBaseVO { | 10 | +public class ProductPropertyAndValueRespVO { |
| 17 | 11 | ||
| 18 | - @Schema(description = "规格的编号", required = true, example = "1024") | 12 | + @ApiModelProperty(value = "属性项的编号", required = true, example = "1024") |
| 19 | private Long id; | 13 | private Long id; |
| 20 | 14 | ||
| 21 | - @Schema(description = "创建时间", required = true) | ||
| 22 | - private LocalDateTime createTime; | 15 | + @ApiModelProperty(value = "属性项的名称", required = true, example = "颜色") |
| 16 | + private String name; | ||
| 23 | 17 | ||
| 24 | /** | 18 | /** |
| 25 | - * 规格值的集合 | 19 | + * 属性值的集合 |
| 26 | */ | 20 | */ |
| 27 | - private List<ProductPropertyValueRespVO> values; | 21 | + private List<Value> values; |
| 22 | + | ||
| 23 | + @ApiModel("管理后台 - 属性值的简单 Response VO") | ||
| 24 | + @Data | ||
| 25 | + public static class Value { | ||
| 26 | + | ||
| 27 | + @Schema(description = "属性值的编号", required = true, example = "2048") | ||
| 28 | + private Long id; | ||
| 29 | + | ||
| 30 | + @Schema(description = "属性值的名称", required = true, example = "红色") | ||
| 31 | + private String name; | ||
| 32 | + | ||
| 33 | + } | ||
| 28 | 34 | ||
| 29 | } | 35 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java
| 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; | 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; |
| 2 | + | ||
| 2 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 3 | import lombok.Data; | 4 | import lombok.Data; |
| 4 | 5 | ||
| 5 | import javax.validation.constraints.NotBlank; | 6 | import javax.validation.constraints.NotBlank; |
| 6 | -import javax.validation.constraints.NotNull; | ||
| 7 | 7 | ||
| 8 | /** | 8 | /** |
| 9 | - * 规格名称 Base VO,提供给添加、修改、详细的子 VO 使用 | 9 | + * 商品属性项 Base VO,提供给添加、修改、详细的子 VO 使用 |
| 10 | * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | 10 | * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 |
| 11 | */ | 11 | */ |
| 12 | @Data | 12 | @Data |
| 13 | public class ProductPropertyBaseVO { | 13 | public class ProductPropertyBaseVO { |
| 14 | 14 | ||
| 15 | - @Schema(description = "规格名称", required = true, example = "颜色") | ||
| 16 | - @NotBlank(message = "规格名称不能为空") | 15 | + @Schema(description = "名称", required = true, example = "颜色") |
| 16 | + @NotBlank(message = "名称不能为空") | ||
| 17 | private String name; | 17 | private String name; |
| 18 | 18 | ||
| 19 | @Schema(description = "备注", example = "颜色") | 19 | @Schema(description = "备注", example = "颜色") |
| 20 | private String remark; | 20 | private String remark; |
| 21 | 21 | ||
| 22 | - @Schema(description = "状态-参见 CommonStatusEnum 枚举", required = true, example = "1") | ||
| 23 | - @NotNull(message = "状态不能为空") | ||
| 24 | - private Integer status; | ||
| 25 | - | ||
| 26 | } | 22 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java
| 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; | 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; |
| 2 | + | ||
| 2 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 3 | import lombok.Data; | 4 | import lombok.Data; |
| 4 | import lombok.EqualsAndHashCode; | 5 | import lombok.EqualsAndHashCode; |
| 5 | import lombok.ToString; | 6 | import lombok.ToString; |
| 6 | 7 | ||
| 7 | -@Schema(description = "管理后台 - 规格名称创建 Request VO") | 8 | +@Schema(description = "管理后台 - 属性项创建 Request VO") |
| 8 | @Data | 9 | @Data |
| 9 | @EqualsAndHashCode(callSuper = true) | 10 | @EqualsAndHashCode(callSuper = true) |
| 10 | @ToString(callSuper = true) | 11 | @ToString(callSuper = true) |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java
| @@ -4,15 +4,12 @@ import io.swagger.v3.oas.annotations.media.Schema; | @@ -4,15 +4,12 @@ import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | import lombok.Data; | 4 | import lombok.Data; |
| 5 | import lombok.ToString; | 5 | import lombok.ToString; |
| 6 | 6 | ||
| 7 | -@Schema(description = "管理后台 - 规格名称 List Request VO") | 7 | +@Schema(description = "管理后台 - 属性项 List Request VO") |
| 8 | @Data | 8 | @Data |
| 9 | @ToString(callSuper = true) | 9 | @ToString(callSuper = true) |
| 10 | public class ProductPropertyListReqVO { | 10 | public class ProductPropertyListReqVO { |
| 11 | 11 | ||
| 12 | - @Schema(description = "规格名称", example = "颜色") | 12 | + @Schema(description = "名称", example = "颜色") |
| 13 | private String name; | 13 | private String name; |
| 14 | 14 | ||
| 15 | - @Schema(description = "状态,参见 CommonStatusEnum 枚举", required = true, example = "1") | ||
| 16 | - private Integer status; | ||
| 17 | - | ||
| 18 | } | 15 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyPageReqVO.java
| @@ -11,16 +11,16 @@ import java.time.LocalDateTime; | @@ -11,16 +11,16 @@ import java.time.LocalDateTime; | ||
| 11 | 11 | ||
| 12 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | 12 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| 13 | 13 | ||
| 14 | -@Schema(description = "管理后台 - 规格名称分页 Request VO") | 14 | +@Schema(description = "管理后台 - 属性项 Request VO") |
| 15 | @Data | 15 | @Data |
| 16 | @EqualsAndHashCode(callSuper = true) | 16 | @EqualsAndHashCode(callSuper = true) |
| 17 | @ToString(callSuper = true) | 17 | @ToString(callSuper = true) |
| 18 | public class ProductPropertyPageReqVO extends PageParam { | 18 | public class ProductPropertyPageReqVO extends PageParam { |
| 19 | 19 | ||
| 20 | - @Schema(description = "规格名称", example = "颜色") | 20 | + @Schema(description = "名称", example = "颜色") |
| 21 | private String name; | 21 | private String name; |
| 22 | 22 | ||
| 23 | - @Schema(description = "状态,参见 CommonStatusEnum 枚举", required = true, example = "1") | 23 | + @Schema(description = "状态-参见 CommonStatusEnum 枚举", required = true, example = "1") |
| 24 | private Integer status; | 24 | private Integer status; |
| 25 | 25 | ||
| 26 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | 26 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java
| @@ -7,13 +7,13 @@ import lombok.ToString; | @@ -7,13 +7,13 @@ import lombok.ToString; | ||
| 7 | 7 | ||
| 8 | import java.time.LocalDateTime; | 8 | import java.time.LocalDateTime; |
| 9 | 9 | ||
| 10 | -@Schema(description = "管理后台 - 规格 + 规格值 Response VO") | 10 | +@Schema(description = "管理后台 - 属性项 Response VO") |
| 11 | @Data | 11 | @Data |
| 12 | @EqualsAndHashCode(callSuper = true) | 12 | @EqualsAndHashCode(callSuper = true) |
| 13 | @ToString(callSuper = true) | 13 | @ToString(callSuper = true) |
| 14 | public class ProductPropertyRespVO extends ProductPropertyBaseVO { | 14 | public class ProductPropertyRespVO extends ProductPropertyBaseVO { |
| 15 | 15 | ||
| 16 | - @Schema(description = "规格的编号", required = true, example = "1024") | 16 | + @Schema(description = "编号", required = true, example = "1024") |
| 17 | private Long id; | 17 | private Long id; |
| 18 | 18 | ||
| 19 | @Schema(description = "创建时间", required = true) | 19 | @Schema(description = "创建时间", required = true) |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java
| 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; | 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; |
| 2 | + | ||
| 2 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 3 | -import lombok.*; | ||
| 4 | -import javax.validation.constraints.*; | 4 | +import lombok.Data; |
| 5 | +import lombok.EqualsAndHashCode; | ||
| 6 | +import lombok.ToString; | ||
| 7 | + | ||
| 8 | +import javax.validation.constraints.NotNull; | ||
| 5 | 9 | ||
| 6 | -@Schema(description = "管理后台 - 规格名称更新 Request VO") | 10 | +@Schema(description = "管理后台 - 属性项更新 Request VO") |
| 7 | @Data | 11 | @Data |
| 8 | @EqualsAndHashCode(callSuper = true) | 12 | @EqualsAndHashCode(callSuper = true) |
| 9 | @ToString(callSuper = true) | 13 | @ToString(callSuper = true) |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java
| 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.value; | 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.value; |
| 2 | + | ||
| 2 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 3 | import lombok.Data; | 4 | import lombok.Data; |
| 4 | 5 | ||
| @@ -6,24 +7,20 @@ import javax.validation.constraints.NotEmpty; | @@ -6,24 +7,20 @@ import javax.validation.constraints.NotEmpty; | ||
| 6 | import javax.validation.constraints.NotNull; | 7 | import javax.validation.constraints.NotNull; |
| 7 | 8 | ||
| 8 | /** | 9 | /** |
| 9 | -* 规格值 Base VO,提供给添加、修改、详细的子 VO 使用 | 10 | +* 属性值 Base VO,提供给添加、修改、详细的子 VO 使用 |
| 10 | * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | 11 | * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 |
| 11 | */ | 12 | */ |
| 12 | @Data | 13 | @Data |
| 13 | public class ProductPropertyValueBaseVO { | 14 | public class ProductPropertyValueBaseVO { |
| 14 | 15 | ||
| 15 | - @Schema(description = "规格编号", required = true, example = "1024") | ||
| 16 | - @NotNull(message = "规格编号不能为空") | 16 | + @Schema(description = "属性项的编号", required = true, example = "1024") |
| 17 | + @NotNull(message = "属性项的编号不能为空") | ||
| 17 | private Long propertyId; | 18 | private Long propertyId; |
| 18 | 19 | ||
| 19 | - @Schema(description = "规格值名字", required = true, example = "红色") | ||
| 20 | - @NotEmpty(message = "规格值名字不能为空") | 20 | + @Schema(description = "名称", required = true, example = "红色") |
| 21 | + @NotEmpty(message = "名称名字不能为空") | ||
| 21 | private String name; | 22 | private String name; |
| 22 | 23 | ||
| 23 | - @Schema(description = "状态,参见 CommonStatusEnum 枚举", required = true, example = "1") | ||
| 24 | - @NotNull(message = "状态不能为空") | ||
| 25 | - private Integer status; | ||
| 26 | - | ||
| 27 | @Schema(description = "备注", example = "颜色") | 24 | @Schema(description = "备注", example = "颜色") |
| 28 | private String remark; | 25 | private String remark; |
| 29 | 26 |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueCreateReqVO.java
| 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.value; | 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.value; |
| 2 | + | ||
| 2 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 3 | import lombok.*; | 4 | import lombok.*; |
| 4 | 5 | ||
| 5 | -@Schema(description = "管理后台 - 规格值创建 Request VO") | 6 | +@Schema(description = "管理后台 - 商品属性值创建 Request VO") |
| 6 | @Data | 7 | @Data |
| 7 | @EqualsAndHashCode(callSuper = true) | 8 | @EqualsAndHashCode(callSuper = true) |
| 8 | @ToString(callSuper = true) | 9 | @ToString(callSuper = true) |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueDetailRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.controller.admin.property.vo.value; | ||
| 2 | + | ||
| 3 | +import io.swagger.annotations.ApiModel; | ||
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +@ApiModel("管理后台 - 商品属性值的明细 Response VO") | ||
| 8 | +@Data | ||
| 9 | +public class ProductPropertyValueDetailRespVO { | ||
| 10 | + | ||
| 11 | + @ApiModelProperty(value = "属性的编号", required = true, example = "1") | ||
| 12 | + private Long propertyId; | ||
| 13 | + | ||
| 14 | + @ApiModelProperty(value = "属性的名称", required = true, example = "颜色") | ||
| 15 | + private String propertyName; | ||
| 16 | + | ||
| 17 | + @ApiModelProperty(value = "属性值的编号", required = true, example = "1024") | ||
| 18 | + private Long valueId; | ||
| 19 | + | ||
| 20 | + @ApiModelProperty(value = "属性值的名称", required = true, example = "红色") | ||
| 21 | + private String valueName; | ||
| 22 | + | ||
| 23 | +} |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java
| @@ -5,26 +5,20 @@ import io.swagger.v3.oas.annotations.media.Schema; | @@ -5,26 +5,20 @@ import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | import lombok.Data; | 5 | import lombok.Data; |
| 6 | import lombok.EqualsAndHashCode; | 6 | import lombok.EqualsAndHashCode; |
| 7 | import lombok.ToString; | 7 | import lombok.ToString; |
| 8 | -import org.springframework.format.annotation.DateTimeFormat; | ||
| 9 | 8 | ||
| 10 | -import javax.validation.constraints.NotEmpty; | ||
| 11 | -import java.util.Date; | ||
| 12 | - | ||
| 13 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 14 | - | ||
| 15 | -@Schema(description = "管理后台 - 规格名称值分页 Request VO") | 9 | +@Schema(description = "管理后台 - 商品属性值分页 Request VO") |
| 16 | @Data | 10 | @Data |
| 17 | @EqualsAndHashCode(callSuper = true) | 11 | @EqualsAndHashCode(callSuper = true) |
| 18 | @ToString(callSuper = true) | 12 | @ToString(callSuper = true) |
| 19 | public class ProductPropertyValuePageReqVO extends PageParam { | 13 | public class ProductPropertyValuePageReqVO extends PageParam { |
| 20 | 14 | ||
| 21 | - @Schema(description = "规格id", example = "1024") | 15 | + @Schema(description = "属性项的编号", example = "1024") |
| 22 | private String propertyId; | 16 | private String propertyId; |
| 23 | 17 | ||
| 24 | - @Schema(description = "规格值", example = "红色") | 18 | + @Schema(description = "名称", example = "红色") |
| 25 | private String name; | 19 | private String name; |
| 26 | 20 | ||
| 27 | - @Schema(description = "状态,参见 CommonStatusEnum 枚举", required = true, example = "1") | 21 | + @Schema(description = "状态 - 参见 CommonStatusEnum 枚举", required = true, example = "1") |
| 28 | private Integer status; | 22 | private Integer status; |
| 29 | 23 | ||
| 30 | } | 24 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueRespVO.java
| @@ -7,13 +7,13 @@ import lombok.ToString; | @@ -7,13 +7,13 @@ import lombok.ToString; | ||
| 7 | 7 | ||
| 8 | import java.time.LocalDateTime; | 8 | import java.time.LocalDateTime; |
| 9 | 9 | ||
| 10 | -@Schema(description = "管理后台 - 规格值 Response VO") | 10 | +@Schema(description = "管理后台 - 商品属性值 Response VO") |
| 11 | @Data | 11 | @Data |
| 12 | @EqualsAndHashCode(callSuper = true) | 12 | @EqualsAndHashCode(callSuper = true) |
| 13 | @ToString(callSuper = true) | 13 | @ToString(callSuper = true) |
| 14 | public class ProductPropertyValueRespVO extends ProductPropertyValueBaseVO { | 14 | public class ProductPropertyValueRespVO extends ProductPropertyValueBaseVO { |
| 15 | 15 | ||
| 16 | - @Schema(description = "主键", required = true, example = "10") | 16 | + @Schema(description = "编号", required = true, example = "10") |
| 17 | private Long id; | 17 | private Long id; |
| 18 | 18 | ||
| 19 | @Schema(description = "创建时间") | 19 | @Schema(description = "创建时间") |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueUpdateReqVO.java
| 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.value; | 1 | package cn.iocoder.yudao.module.product.controller.admin.property.vo.value; |
| 2 | + | ||
| 2 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 3 | import lombok.*; | 4 | import lombok.*; |
| 4 | import javax.validation.constraints.*; | 5 | import javax.validation.constraints.*; |
| 5 | 6 | ||
| 6 | -@Schema(description = "管理后台 - 规格值更新 Request VO") | 7 | +@Schema(description = "管理后台 - 商品属性值更新 Request VO") |
| 7 | @Data | 8 | @Data |
| 8 | @EqualsAndHashCode(callSuper = true) | 9 | @EqualsAndHashCode(callSuper = true) |
| 9 | @ToString(callSuper = true) | 10 | @ToString(callSuper = true) |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
| @@ -3,7 +3,9 @@ package cn.iocoder.yudao.module.product.controller.admin.sku.vo; | @@ -3,7 +3,9 @@ package cn.iocoder.yudao.module.product.controller.admin.sku.vo; | ||
| 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | import cn.iocoder.yudao.framework.common.validation.InEnum; | 4 | import cn.iocoder.yudao.framework.common.validation.InEnum; |
| 5 | import io.swagger.v3.oas.annotations.media.Schema; | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | +import lombok.AllArgsConstructor; | ||
| 6 | import lombok.Data; | 7 | import lombok.Data; |
| 8 | +import lombok.NoArgsConstructor; | ||
| 7 | 9 | ||
| 8 | import javax.validation.constraints.NotEmpty; | 10 | import javax.validation.constraints.NotEmpty; |
| 9 | import javax.validation.constraints.NotNull; | 11 | import javax.validation.constraints.NotNull; |
| @@ -15,54 +17,56 @@ import javax.validation.constraints.NotNull; | @@ -15,54 +17,56 @@ import javax.validation.constraints.NotNull; | ||
| 15 | @Data | 17 | @Data |
| 16 | public class ProductSkuBaseVO { | 18 | public class ProductSkuBaseVO { |
| 17 | 19 | ||
| 18 | - @Schema(description = "商品 SKU 名字", required = true, example = "芋道") | 20 | + @Schema(description = "商品 SKU 名字", required = true, example = "芋道") |
| 19 | @NotEmpty(message = "商品 SKU 名字不能为空") | 21 | @NotEmpty(message = "商品 SKU 名字不能为空") |
| 20 | private String name; | 22 | private String name; |
| 21 | 23 | ||
| 22 | - @Schema(description = "销售价格,单位:分", required = true, example = "1024") | 24 | + @Schema(description = "销售价格,单位:分", required = true, example = "1024", notes = "单位:分") |
| 23 | @NotNull(message = "销售价格,单位:分不能为空") | 25 | @NotNull(message = "销售价格,单位:分不能为空") |
| 24 | private Integer price; | 26 | private Integer price; |
| 25 | 27 | ||
| 26 | - @Schema(description = "市场价,单位:分", example = "1024") | 28 | + @Schema(description = "市场价", example = "1024", notes = "单位:分") |
| 27 | private Integer marketPrice; | 29 | private Integer marketPrice; |
| 28 | 30 | ||
| 29 | - @Schema(description = "成本价,单位:分", example = "1024") | 31 | + @Schema(description = "成本价", example = "1024", notes = "单位:分") |
| 30 | private Integer costPrice; | 32 | private Integer costPrice; |
| 31 | 33 | ||
| 32 | - @Schema(description = "条形码", example = "haha") | 34 | + @Schema(description = "条形码", example = "haha") |
| 33 | private String barCode; | 35 | private String barCode; |
| 34 | 36 | ||
| 35 | - @Schema(description = "图片地址", required = true, example = "https://www.iocoder.cn/xx.png") | 37 | + @Schema(description = "图片地址", required = true, example = "https://www.iocoder.cn/xx.png") |
| 36 | @NotNull(message = "图片地址不能为空") | 38 | @NotNull(message = "图片地址不能为空") |
| 37 | private String picUrl; | 39 | private String picUrl; |
| 38 | 40 | ||
| 39 | - @Schema(description = "SKU 状态,参见 CommonStatusEnum 枚举", required = true, example = "1") | 41 | + @Schema(description = "SKU 状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举") |
| 40 | @NotNull(message = "SKU 状态不能为空") | 42 | @NotNull(message = "SKU 状态不能为空") |
| 41 | @InEnum(CommonStatusEnum.class) | 43 | @InEnum(CommonStatusEnum.class) |
| 42 | private Integer status; | 44 | private Integer status; |
| 43 | 45 | ||
| 44 | - @Schema(description = "库存", required = true, example = "1") | 46 | + @Schema(description = "库存", required = true, example = "1") |
| 45 | @NotNull(message = "库存不能为空") | 47 | @NotNull(message = "库存不能为空") |
| 46 | private Integer stock; | 48 | private Integer stock; |
| 47 | 49 | ||
| 48 | - @Schema(description = "预警预存", example = "1") | 50 | + @Schema(description = "预警预存", example = "1") |
| 49 | private Integer warnStock; | 51 | private Integer warnStock; |
| 50 | 52 | ||
| 51 | - @Schema(description = "商品重量,单位:kg 千克", example = "1") | 53 | + @Schema(description = "商品重量 - 单位:kg 千克", example = "1") |
| 52 | private Double weight; | 54 | private Double weight; |
| 53 | 55 | ||
| 54 | - @Schema(description = "商品体积,单位:m^3 平米", example = "1024") | 56 | + @Schema(description = "商品体积 - 单位:m^3 平米", example = "1024") |
| 55 | private Double volume; | 57 | private Double volume; |
| 56 | 58 | ||
| 57 | - @Schema(description = "规格值") | 59 | + @ApiModel("商品属性") |
| 58 | @Data | 60 | @Data |
| 61 | + @AllArgsConstructor | ||
| 62 | + @NoArgsConstructor | ||
| 59 | public static class Property { | 63 | public static class Property { |
| 60 | 64 | ||
| 61 | - @Schema(description = "属性编号", required = true, example = "1") | 65 | + @Schema(description = "属性编号", required = true, example = "1") |
| 62 | @NotNull(message = "属性编号不能为空") | 66 | @NotNull(message = "属性编号不能为空") |
| 63 | private Long propertyId; | 67 | private Long propertyId; |
| 64 | 68 | ||
| 65 | - @Schema(description = "属性值编号", required = true, example = "1024") | 69 | + @Schema(description = "属性值编号", required = true, example = "1024") |
| 66 | @NotNull(message = "属性值编号不能为空") | 70 | @NotNull(message = "属性值编号不能为空") |
| 67 | private Long valueId; | 71 | private Long valueId; |
| 68 | 72 |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuCreateOrUpdateReqVO.java
| @@ -13,11 +13,8 @@ import java.util.List; | @@ -13,11 +13,8 @@ import java.util.List; | ||
| 13 | @ToString(callSuper = true) | 13 | @ToString(callSuper = true) |
| 14 | public class ProductSkuCreateOrUpdateReqVO extends ProductSkuBaseVO { | 14 | public class ProductSkuCreateOrUpdateReqVO extends ProductSkuBaseVO { |
| 15 | 15 | ||
| 16 | - @Schema(description = "商品 SKU 编号", example = "1") | ||
| 17 | - private Long id; | ||
| 18 | - | ||
| 19 | /** | 16 | /** |
| 20 | - * 规格值数组 | 17 | + * 属性数组 |
| 21 | */ | 18 | */ |
| 22 | private List<Property> properties; | 19 | private List<Property> properties; |
| 23 | 20 |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuRespVO.java
| @@ -21,7 +21,7 @@ public class ProductSkuRespVO extends ProductSkuBaseVO { | @@ -21,7 +21,7 @@ public class ProductSkuRespVO extends ProductSkuBaseVO { | ||
| 21 | private LocalDateTime createTime; | 21 | private LocalDateTime createTime; |
| 22 | 22 | ||
| 23 | /** | 23 | /** |
| 24 | - * 规格值数组 | 24 | + * 属性数组 |
| 25 | */ | 25 | */ |
| 26 | private List<Property> properties; | 26 | private List<Property> properties; |
| 27 | 27 |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.http
0 → 100644
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
| @@ -3,8 +3,13 @@ package cn.iocoder.yudao.module.product.controller.admin.spu; | @@ -3,8 +3,13 @@ package cn.iocoder.yudao.module.product.controller.admin.spu; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; | 5 | import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; |
| 6 | +import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; | ||
| 6 | import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; | 7 | import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; |
| 8 | +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; | ||
| 7 | import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; | 9 | import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; |
| 10 | +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; | ||
| 11 | +import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; | ||
| 12 | +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; | ||
| 8 | import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; | 13 | import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; |
| 9 | import io.swagger.v3.oas.annotations.tags.Tag; | 14 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 10 | import io.swagger.v3.oas.annotations.Parameter; | 15 | import io.swagger.v3.oas.annotations.Parameter; |
| @@ -15,10 +20,11 @@ import org.springframework.web.bind.annotation.*; | @@ -15,10 +20,11 @@ import org.springframework.web.bind.annotation.*; | ||
| 15 | 20 | ||
| 16 | import javax.annotation.Resource; | 21 | import javax.annotation.Resource; |
| 17 | import javax.validation.Valid; | 22 | import javax.validation.Valid; |
| 18 | -import java.util.Collection; | ||
| 19 | import java.util.List; | 23 | import java.util.List; |
| 20 | 24 | ||
| 25 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 21 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 26 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 27 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; | ||
| 22 | 28 | ||
| 23 | @Tag(name = "管理后台 - 商品 SPU") | 29 | @Tag(name = "管理后台 - 商品 SPU") |
| 24 | @RestController | 30 | @RestController |
| @@ -27,64 +33,61 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | @@ -27,64 +33,61 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 27 | public class ProductSpuController { | 33 | public class ProductSpuController { |
| 28 | 34 | ||
| 29 | @Resource | 35 | @Resource |
| 30 | - private ProductSpuService spuService; | 36 | + private ProductSpuService productSpuService; |
| 37 | + @Resource | ||
| 38 | + private ProductSkuService productSkuService; | ||
| 39 | + @Resource | ||
| 40 | + private ProductPropertyValueService productPropertyValueService; | ||
| 31 | 41 | ||
| 32 | @PostMapping("/create") | 42 | @PostMapping("/create") |
| 33 | @Operation(summary = "创建商品 SPU") | 43 | @Operation(summary = "创建商品 SPU") |
| 34 | @PreAuthorize("@ss.hasPermission('product:spu:create')") | 44 | @PreAuthorize("@ss.hasPermission('product:spu:create')") |
| 35 | public CommonResult<Long> createProductSpu(@Valid @RequestBody ProductSpuCreateReqVO createReqVO) { | 45 | public CommonResult<Long> createProductSpu(@Valid @RequestBody ProductSpuCreateReqVO createReqVO) { |
| 36 | - return success(spuService.createSpu(createReqVO)); | 46 | + return success(productSpuService.createSpu(createReqVO)); |
| 37 | } | 47 | } |
| 38 | 48 | ||
| 39 | @PutMapping("/update") | 49 | @PutMapping("/update") |
| 40 | @Operation(summary = "更新商品 SPU") | 50 | @Operation(summary = "更新商品 SPU") |
| 41 | @PreAuthorize("@ss.hasPermission('product:spu:update')") | 51 | @PreAuthorize("@ss.hasPermission('product:spu:update')") |
| 42 | public CommonResult<Boolean> updateSpu(@Valid @RequestBody ProductSpuUpdateReqVO updateReqVO) { | 52 | public CommonResult<Boolean> updateSpu(@Valid @RequestBody ProductSpuUpdateReqVO updateReqVO) { |
| 43 | - spuService.updateSpu(updateReqVO); | 53 | + productSpuService.updateSpu(updateReqVO); |
| 44 | return success(true); | 54 | return success(true); |
| 45 | } | 55 | } |
| 46 | 56 | ||
| 47 | @DeleteMapping("/delete") | 57 | @DeleteMapping("/delete") |
| 48 | @Operation(summary = "删除商品 SPU") | 58 | @Operation(summary = "删除商品 SPU") |
| 49 | - @Parameter(name = "id", description = "编号", required = true) | 59 | + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) |
| 50 | @PreAuthorize("@ss.hasPermission('product:spu:delete')") | 60 | @PreAuthorize("@ss.hasPermission('product:spu:delete')") |
| 51 | public CommonResult<Boolean> deleteSpu(@RequestParam("id") Long id) { | 61 | public CommonResult<Boolean> deleteSpu(@RequestParam("id") Long id) { |
| 52 | - spuService.deleteSpu(id); | 62 | + productSpuService.deleteSpu(id); |
| 53 | return success(true); | 63 | return success(true); |
| 54 | } | 64 | } |
| 55 | 65 | ||
| 56 | - // TODO 芋艿:修改接口 | ||
| 57 | - @GetMapping("/get/detail") | ||
| 58 | - @Operation(summary = "获得商品 SPU") | ||
| 59 | - @Parameter(name = "id", description = "编号", required = true, example = "1024") | 66 | + @GetMapping("/get-detail") |
| 67 | + @Operation(summary = "获得商品 SPU 明细") | ||
| 68 | + @Parameter(name = "id", value = "编号", required = true, example = "1024") | ||
| 60 | @PreAuthorize("@ss.hasPermission('product:spu:query')") | 69 | @PreAuthorize("@ss.hasPermission('product:spu:query')") |
| 61 | public CommonResult<ProductSpuDetailRespVO> getSpuDetail(@RequestParam("id") Long id) { | 70 | public CommonResult<ProductSpuDetailRespVO> getSpuDetail(@RequestParam("id") Long id) { |
| 62 | - return success(spuService.getSpuDetail(id)); | ||
| 63 | - } | ||
| 64 | - | ||
| 65 | - @GetMapping("/get") | ||
| 66 | - @Operation(summary = "获得商品 SPU") | ||
| 67 | - @Parameter(name = "id", description = "编号", required = true, example = "1024") | ||
| 68 | - @PreAuthorize("@ss.hasPermission('product:spu:query')") | ||
| 69 | - public CommonResult<ProductSpuRespVO> getSpu(@RequestParam("id") Long id) { | ||
| 70 | - return success(spuService.getSpu(id)); | ||
| 71 | - } | 71 | + // 获得商品 SPU |
| 72 | + ProductSpuDO spu = productSpuService.getSpu(id); | ||
| 73 | + if (spu == null) { | ||
| 74 | + throw exception(SPU_NOT_EXISTS); | ||
| 75 | + } | ||
| 72 | 76 | ||
| 73 | - | ||
| 74 | - @GetMapping("/list") | ||
| 75 | - @Operation(summary = "获得商品 SPU 列表") | ||
| 76 | - @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048") | ||
| 77 | - @PreAuthorize("@ss.hasPermission('product:spu:query')") | ||
| 78 | - public CommonResult<List<ProductSpuRespVO>> getSpuList(@RequestParam("ids") Collection<Long> ids) { | ||
| 79 | - List<ProductSpuDO> list = spuService.getSpuList(ids); | ||
| 80 | - return success(ProductSpuConvert.INSTANCE.convertList(list)); | 77 | + // 查询商品 SKU |
| 78 | + List<ProductSkuDO> skus = productSkuService.getSkuListBySpuIdAndStatus(spu.getId(), null); | ||
| 79 | + // 查询商品属性 | ||
| 80 | + List<ProductPropertyValueDetailRespBO> propertyValues = productPropertyValueService | ||
| 81 | + .getPropertyValueDetailList(ProductSkuConvert.INSTANCE.convertPropertyValueIds(skus)); | ||
| 82 | + // 拼接 | ||
| 83 | + return success(ProductSpuConvert.INSTANCE.convert03(spu, skus, propertyValues)); | ||
| 81 | } | 84 | } |
| 82 | 85 | ||
| 83 | @GetMapping("/get-simple-list") | 86 | @GetMapping("/get-simple-list") |
| 84 | @Operation(summary = "获得商品 SPU 精简列表") | 87 | @Operation(summary = "获得商品 SPU 精简列表") |
| 85 | @PreAuthorize("@ss.hasPermission('product:spu:query')") | 88 | @PreAuthorize("@ss.hasPermission('product:spu:query')") |
| 86 | public CommonResult<List<ProductSpuSimpleRespVO>> getSpuSimpleList() { | 89 | public CommonResult<List<ProductSpuSimpleRespVO>> getSpuSimpleList() { |
| 87 | - List<ProductSpuDO> list = spuService.getSpuList(); | 90 | + List<ProductSpuDO> list = productSpuService.getSpuList(); |
| 88 | return success(ProductSpuConvert.INSTANCE.convertList02(list)); | 91 | return success(ProductSpuConvert.INSTANCE.convertList02(list)); |
| 89 | } | 92 | } |
| 90 | 93 | ||
| @@ -92,7 +95,7 @@ public class ProductSpuController { | @@ -92,7 +95,7 @@ public class ProductSpuController { | ||
| 92 | @Operation(summary = "获得商品 SPU 分页") | 95 | @Operation(summary = "获得商品 SPU 分页") |
| 93 | @PreAuthorize("@ss.hasPermission('product:spu:query')") | 96 | @PreAuthorize("@ss.hasPermission('product:spu:query')") |
| 94 | public CommonResult<PageResult<ProductSpuRespVO>> getSpuPage(@Valid ProductSpuPageReqVO pageVO) { | 97 | public CommonResult<PageResult<ProductSpuRespVO>> getSpuPage(@Valid ProductSpuPageReqVO pageVO) { |
| 95 | - return success(spuService.getSpuPage(pageVO)); | 98 | + return success(ProductSpuConvert.INSTANCE.convertPage(productSpuService.getSpuPage(pageVO))); |
| 96 | } | 99 | } |
| 97 | 100 | ||
| 98 | } | 101 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java
| @@ -11,81 +11,66 @@ import javax.validation.constraints.NotNull; | @@ -11,81 +11,66 @@ import javax.validation.constraints.NotNull; | ||
| 11 | import java.util.List; | 11 | import java.util.List; |
| 12 | 12 | ||
| 13 | /** | 13 | /** |
| 14 | -* 商品 SPU Base VO,提供给添加、修改、详细的子 VO 使用 | ||
| 15 | -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | ||
| 16 | -*/ | 14 | + * 商品 SPU Base VO,提供给添加、修改、详细的子 VO 使用 |
| 15 | + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | ||
| 16 | + */ | ||
| 17 | @Data | 17 | @Data |
| 18 | public class ProductSpuBaseVO { | 18 | public class ProductSpuBaseVO { |
| 19 | 19 | ||
| 20 | - @Schema(description = "商品名称", required = true, example = "芋道") | 20 | + @Schema(description = = "商品名称", required = true, example = "芋道") |
| 21 | @NotEmpty(message = "商品名称不能为空") | 21 | @NotEmpty(message = "商品名称不能为空") |
| 22 | private String name; | 22 | private String name; |
| 23 | 23 | ||
| 24 | - @Schema(description = "商品编码", example = "yudaoyuanma") | 24 | + @Schema(description = = "商品编码", example = "yudaoyuanma") |
| 25 | private String code; | 25 | private String code; |
| 26 | 26 | ||
| 27 | - @Schema(description = "促销语", example = "好吃!") | 27 | + @Schema(description = = "促销语", example = "好吃!") |
| 28 | private String sellPoint; | 28 | private String sellPoint; |
| 29 | 29 | ||
| 30 | - @Schema(description = "商品详情", required = true, example = "我是商品描述") | 30 | + @Schema(description = = "商品详情", required = true, example = "我是商品描述") |
| 31 | @NotNull(message = "商品详情不能为空") | 31 | @NotNull(message = "商品详情不能为空") |
| 32 | private String description; | 32 | private String description; |
| 33 | 33 | ||
| 34 | - @Schema(description = "商品分类编号", required = true, example = "1") | 34 | + @Schema(description = = "商品分类编号", required = true, example = "1") |
| 35 | @NotNull(message = "商品分类编号不能为空") | 35 | @NotNull(message = "商品分类编号不能为空") |
| 36 | private Long categoryId; | 36 | private Long categoryId; |
| 37 | 37 | ||
| 38 | - @Schema(description = "商品品牌编号", example = "1") | 38 | + @Schema(description = = "商品品牌编号", example = "1") |
| 39 | private Long brandId; | 39 | private Long brandId; |
| 40 | 40 | ||
| 41 | - @Schema(description = "商品图片的数组", required = true) | 41 | + @Schema(description = = "商品图片的数组", required = true) |
| 42 | @NotNull(message = "商品图片的数组不能为空") | 42 | @NotNull(message = "商品图片的数组不能为空") |
| 43 | private List<String> picUrls; | 43 | private List<String> picUrls; |
| 44 | 44 | ||
| 45 | - @Schema(description = "商品视频", required = true) | 45 | + @Schema(description = = "商品视频", required = true) |
| 46 | private String videoUrl; | 46 | private String videoUrl; |
| 47 | 47 | ||
| 48 | - @Schema(description = "排序字段", required = true, example = "1") | 48 | + @Schema(description = = "排序字段", required = true, example = "1") |
| 49 | private Integer sort; | 49 | private Integer sort; |
| 50 | 50 | ||
| 51 | - @Schema(description = "商品状态,参见 ProductSpuStatusEnum 枚举类", required = true, example = "1") | 51 | + @Schema(description = = "商品状态 参见 ProductSpuStatusEnum 枚举类", required = true, example = "1") |
| 52 | @NotNull(message = "商品状态不能为空") | 52 | @NotNull(message = "商品状态不能为空") |
| 53 | @InEnum(ProductSpuStatusEnum.class) | 53 | @InEnum(ProductSpuStatusEnum.class) |
| 54 | private Integer status; | 54 | private Integer status; |
| 55 | 55 | ||
| 56 | // ========== SKU 相关字段 ========= | 56 | // ========== SKU 相关字段 ========= |
| 57 | 57 | ||
| 58 | - @Schema(description = "规格类型,参见 ProductSpuSpecTypeEnum 枚举类", required = true, example = "1") | 58 | + @Schema(description = = "规格类型 参见 ProductSpuSpecTypeEnum 枚举类", required = true, example = "1") |
| 59 | @NotNull(message = "规格类型不能为空") | 59 | @NotNull(message = "规格类型不能为空") |
| 60 | @InEnum(ProductSpuSpecTypeEnum.class) | 60 | @InEnum(ProductSpuSpecTypeEnum.class) |
| 61 | private Integer specType; | 61 | private Integer specType; |
| 62 | 62 | ||
| 63 | - @Schema(description = "是否展示库存", required = true, example = "true") | 63 | + @Schema(description = = "是否展示库存", required = true, example = "true") |
| 64 | @NotNull(message = "是否展示库存不能为空") | 64 | @NotNull(message = "是否展示库存不能为空") |
| 65 | private Boolean showStock; | 65 | private Boolean showStock; |
| 66 | 66 | ||
| 67 | - @Schema(description = "库存", required = true, example = "true") | ||
| 68 | - private Integer totalStock; | ||
| 69 | - | ||
| 70 | - @Schema(description = "市场价", example = "1024") | 67 | + @Schema(description = = "市场价", example = "1024") |
| 71 | private Integer marketPrice; | 68 | private Integer marketPrice; |
| 72 | 69 | ||
| 73 | - @Schema(description = " 最小价格,单位使用:分", required = true, example = "1024") | ||
| 74 | - private Integer minPrice; | ||
| 75 | - | ||
| 76 | - @Schema(description = "最大价格,单位使用:分", required = true, example = "1024") | ||
| 77 | - private Integer maxPrice; | ||
| 78 | - | ||
| 79 | // ========== 统计相关字段 ========= | 70 | // ========== 统计相关字段 ========= |
| 80 | 71 | ||
| 81 | - @Schema(description = "商品销量", example = "1024") | ||
| 82 | - private Integer salesCount; | ||
| 83 | - | ||
| 84 | - @Schema(description = "虚拟销量", required = true, example = "1024") | 72 | + @Schema(description = = "虚拟销量", required = true, example = "1024") |
| 85 | @NotNull(message = "虚拟销量不能为空") | 73 | @NotNull(message = "虚拟销量不能为空") |
| 86 | private Integer virtualSalesCount; | 74 | private Integer virtualSalesCount; |
| 87 | 75 | ||
| 88 | - @Schema(description = "点击量", example = "1024") | ||
| 89 | - private Integer clickCount; | ||
| 90 | - | ||
| 91 | } | 76 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java
| 1 | package cn.iocoder.yudao.module.product.controller.admin.spu.vo; | 1 | package cn.iocoder.yudao.module.product.controller.admin.spu.vo; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO; | 3 | +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueDetailRespVO; |
| 4 | import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO; | 4 | import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO; |
| 5 | import io.swagger.v3.oas.annotations.media.Schema; | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | import lombok.Data; | 6 | import lombok.Data; |
| 7 | import lombok.EqualsAndHashCode; | 7 | import lombok.EqualsAndHashCode; |
| 8 | import lombok.ToString; | 8 | import lombok.ToString; |
| 9 | 9 | ||
| 10 | -import java.time.LocalDateTime; | ||
| 11 | import java.util.List; | 10 | import java.util.List; |
| 12 | 11 | ||
| 13 | -@Schema(description = "管理后台 - 商品 SPU 详细 Response VO,包括关联的 SKU 等信息") | 12 | +@Schema(description = "管理后台 - 商品 SPU 详细 Response VO 包括关联的 SKU 等信息") |
| 14 | @Data | 13 | @Data |
| 15 | @EqualsAndHashCode(callSuper = true) | 14 | @EqualsAndHashCode(callSuper = true) |
| 16 | @ToString(callSuper = true) | 15 | @ToString(callSuper = true) |
| 17 | -public class ProductSpuDetailRespVO extends ProductSpuBaseVO { | 16 | +public class ProductSpuDetailRespVO extends ProductSpuRespVO { |
| 18 | 17 | ||
| 19 | - @Schema(description = "主键", required = true, example = "1") | ||
| 20 | - private Long id; | ||
| 21 | - | ||
| 22 | - @Schema(description = "创建时间") | ||
| 23 | - private LocalDateTime createTime; | 18 | + // ========== SKU 相关字段 ========= |
| 24 | 19 | ||
| 25 | /** | 20 | /** |
| 26 | * SKU 数组 | 21 | * SKU 数组 |
| @@ -34,31 +29,10 @@ public class ProductSpuDetailRespVO extends ProductSpuBaseVO { | @@ -34,31 +29,10 @@ public class ProductSpuDetailRespVO extends ProductSpuBaseVO { | ||
| 34 | public static class Sku extends ProductSkuBaseVO { | 29 | public static class Sku extends ProductSkuBaseVO { |
| 35 | 30 | ||
| 36 | /** | 31 | /** |
| 37 | - * 规格的数组 | 32 | + * 属性数组 |
| 38 | */ | 33 | */ |
| 39 | - private List<ProductSpuDetailRespVO.Property> properties; | 34 | + private List<ProductPropertyValueDetailRespVO> properties; |
| 40 | 35 | ||
| 41 | } | 36 | } |
| 42 | 37 | ||
| 43 | - @Schema(description = "管理后台 - 商品规格的详细 Response VO") | ||
| 44 | - @Data | ||
| 45 | - @EqualsAndHashCode(callSuper = true) | ||
| 46 | - @ToString(callSuper = true) | ||
| 47 | - public static class Property extends ProductSkuBaseVO.Property { | ||
| 48 | - | ||
| 49 | - @Schema(description = "规格的名字", required = true, example = "颜色") | ||
| 50 | - private String propertyName; | ||
| 51 | - | ||
| 52 | - @Schema(description = "规格值的名字", required = true, example = "蓝色") | ||
| 53 | - private String valueName; | ||
| 54 | - | ||
| 55 | - } | ||
| 56 | - | ||
| 57 | - @Schema(description = "分类 id 数组,一直递归到一级父节点", example = "4") | ||
| 58 | - private Long categoryId; | ||
| 59 | - | ||
| 60 | - // TODO @芋艿:在瞅瞅~ | ||
| 61 | - @Schema(description = "规格属性修改和详情展示组合", example = "[{\"propertyId\":2,\"name\":\"内存\",\"propertyValues\":[{\"v1\":11,\"v2\":\"64G\"},{\"v1\":10,\"v2\":\"32G\"}]},{\"propertyId\":3,\"name\":\"尺寸\",\"propertyValues\":[{\"v1\":16,\"v2\":\"6.1\"},{\"v1\":15,\"v2\":\"5.7\"}]}]") | ||
| 62 | - private List<ProductPropertyViewRespVO> productPropertyViews; | ||
| 63 | - | ||
| 64 | } | 38 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
| @@ -18,13 +18,13 @@ public class ProductSpuPageReqVO extends PageParam { | @@ -18,13 +18,13 @@ public class ProductSpuPageReqVO extends PageParam { | ||
| 18 | @Schema(description = "商品编码", example = "yudaoyuanma") | 18 | @Schema(description = "商品编码", example = "yudaoyuanma") |
| 19 | private String code; | 19 | private String code; |
| 20 | 20 | ||
| 21 | - @Schema(description = "分类id", example = "1") | 21 | + @Schema(description = "分类编号", example = "1") |
| 22 | private Long categoryId; | 22 | private Long categoryId; |
| 23 | 23 | ||
| 24 | @Schema(description = "商品品牌编号", example = "1") | 24 | @Schema(description = "商品品牌编号", example = "1") |
| 25 | private Long brandId; | 25 | private Long brandId; |
| 26 | 26 | ||
| 27 | - @Schema(description = "上下架状态,参见 ProductSpuStatusEnum 枚举值", example = "1") | 27 | + @Schema(description = "上下架状态 参见 ProductSpuStatusEnum 枚举值", example = "1") |
| 28 | private Integer status; | 28 | private Integer status; |
| 29 | 29 | ||
| 30 | @Schema(description = "销量最小值", example = "1") | 30 | @Schema(description = "销量最小值", example = "1") |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
| @@ -6,7 +6,6 @@ import lombok.EqualsAndHashCode; | @@ -6,7 +6,6 @@ import lombok.EqualsAndHashCode; | ||
| 6 | import lombok.ToString; | 6 | import lombok.ToString; |
| 7 | 7 | ||
| 8 | import java.time.LocalDateTime; | 8 | import java.time.LocalDateTime; |
| 9 | -import java.util.List; | ||
| 10 | 9 | ||
| 11 | @Schema(description = "管理后台 - 商品 SPU Response VO") | 10 | @Schema(description = "管理后台 - 商品 SPU Response VO") |
| 12 | @Data | 11 | @Data |
| @@ -20,4 +19,22 @@ public class ProductSpuRespVO extends ProductSpuBaseVO { | @@ -20,4 +19,22 @@ public class ProductSpuRespVO extends ProductSpuBaseVO { | ||
| 20 | @Schema(description = "创建时间") | 19 | @Schema(description = "创建时间") |
| 21 | private LocalDateTime createTime; | 20 | private LocalDateTime createTime; |
| 22 | 21 | ||
| 22 | + // ========== SKU 相关字段 ========= | ||
| 23 | + | ||
| 24 | + @ApiModelProperty(value = "库存", required = true, example = "true") | ||
| 25 | + private Integer totalStock; | ||
| 26 | + | ||
| 27 | + @ApiModelProperty(value = " 最小价格,单位使用:分", required = true, example = "1024") | ||
| 28 | + private Integer minPrice; | ||
| 29 | + | ||
| 30 | + @ApiModelProperty(value = "最大价格,单位使用:分", required = true, example = "1024") | ||
| 31 | + private Integer maxPrice; | ||
| 32 | + | ||
| 33 | + @ApiModelProperty(value = "商品销量", example = "1024") | ||
| 34 | + private Integer salesCount; | ||
| 35 | + | ||
| 36 | + // ========== 统计相关字段 ========= | ||
| 37 | + | ||
| 38 | + @ApiModelProperty(value = "点击量", example = "1024") | ||
| 39 | + private Integer clickCount; | ||
| 23 | } | 40 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/package-info.java
0 → 100644
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/property/package-info.java
0 → 100644
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/value/AppProductPropertyValueDetailRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.controller.app.property.vo.value; | ||
| 2 | + | ||
| 3 | +import io.swagger.annotations.ApiModel; | ||
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +@ApiModel("用户 App - 商品属性值的明细 Response VO") | ||
| 8 | +@Data | ||
| 9 | +public class AppProductPropertyValueDetailRespVO { | ||
| 10 | + | ||
| 11 | + @ApiModelProperty(value = "属性的编号", required = true, example = "1") | ||
| 12 | + private Long propertyId; | ||
| 13 | + | ||
| 14 | + @ApiModelProperty(value = "属性的名称", required = true, example = "颜色") | ||
| 15 | + private String propertyName; | ||
| 16 | + | ||
| 17 | + @ApiModelProperty(value = "属性值的编号", required = true, example = "1024") | ||
| 18 | + private Long valueId; | ||
| 19 | + | ||
| 20 | + @ApiModelProperty(value = "属性值的名称", required = true, example = "红色") | ||
| 21 | + private String valueName; | ||
| 22 | + | ||
| 23 | +} |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http
0 → 100644
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java
| 1 | package cn.iocoder.yudao.module.product.controller.app.spu; | 1 | package cn.iocoder.yudao.module.product.controller.app.spu; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.bean.BeanUtil; | 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | -import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO; | ||
| 7 | -import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO; | ||
| 8 | -import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuRespVO; | 6 | +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; |
| 7 | +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO; | ||
| 8 | +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageItemRespVO; | ||
| 9 | +import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; | ||
| 10 | +import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; | ||
| 11 | +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; | ||
| 12 | +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; | ||
| 13 | +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; | ||
| 14 | +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; | ||
| 15 | +import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; | ||
| 16 | +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; | ||
| 9 | import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; | 17 | import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; |
| 10 | import io.swagger.v3.oas.annotations.tags.Tag; | 18 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 11 | import io.swagger.v3.oas.annotations.Operation; | 19 | import io.swagger.v3.oas.annotations.Operation; |
| @@ -17,28 +25,54 @@ import org.springframework.web.bind.annotation.RestController; | @@ -17,28 +25,54 @@ import org.springframework.web.bind.annotation.RestController; | ||
| 17 | 25 | ||
| 18 | import javax.annotation.Resource; | 26 | import javax.annotation.Resource; |
| 19 | import javax.validation.Valid; | 27 | import javax.validation.Valid; |
| 28 | +import java.util.List; | ||
| 20 | 29 | ||
| 30 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 21 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 31 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 32 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_ENABLE; | ||
| 33 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; | ||
| 22 | 34 | ||
| 23 | -@Tag(name = "用户 APP - 商品spu") | 35 | +@Tag(name = "用户 APP - 商品spu") |
| 24 | @RestController | 36 | @RestController |
| 25 | @RequestMapping("/product/spu") | 37 | @RequestMapping("/product/spu") |
| 26 | @Validated | 38 | @Validated |
| 27 | public class AppProductSpuController { | 39 | public class AppProductSpuController { |
| 28 | 40 | ||
| 29 | @Resource | 41 | @Resource |
| 30 | - private ProductSpuService spuService; | 42 | + private ProductSpuService productSpuService; |
| 43 | + @Resource | ||
| 44 | + private ProductSkuService productSkuService; | ||
| 45 | + @Resource | ||
| 46 | + private ProductPropertyValueService productPropertyValueService; | ||
| 31 | 47 | ||
| 32 | @GetMapping("/page") | 48 | @GetMapping("/page") |
| 33 | - @Operation(summary = "获得商品spu分页") | ||
| 34 | - public CommonResult<PageResult<AppSpuPageRespVO>> getSpuPage(@Valid AppSpuPageReqVO pageVO) { | ||
| 35 | - return success(spuService.getSpuPage(pageVO)); | 49 | + @Operation(summary = "获得商品 SPU 分页") |
| 50 | + public CommonResult<PageResult<AppProductSpuPageItemRespVO>> getSpuPage(@Valid AppProductSpuPageReqVO pageVO) { | ||
| 51 | + PageResult<ProductSpuDO> pageResult = productSpuService.getSpuPage(pageVO, ProductSpuStatusEnum.ENABLE.getStatus()); | ||
| 52 | + return success(ProductSpuConvert.INSTANCE.convertPage02(pageResult)); | ||
| 36 | } | 53 | } |
| 37 | 54 | ||
| 38 | - @GetMapping("/") | ||
| 39 | - @Operation(summary = "获取商品 - 通过商品id") | ||
| 40 | - public CommonResult<AppSpuRespVO> getSpu(@RequestParam("spuId") Long spuId) { | ||
| 41 | - AppSpuRespVO appSpuRespVO = BeanUtil.toBean(spuService.getSpu(spuId), AppSpuRespVO.class); | ||
| 42 | - return success(appSpuRespVO); | 55 | + @GetMapping("/get-detail") |
| 56 | + @Operation(summary = "获得商品 SPU 明细") | ||
| 57 | + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) | ||
| 58 | + public CommonResult<AppProductSpuDetailRespVO> getSpuDetail(@RequestParam("id") Long id) { | ||
| 59 | + // 获得商品 SPU | ||
| 60 | + ProductSpuDO spu = productSpuService.getSpu(id); | ||
| 61 | + if (spu == null) { | ||
| 62 | + throw exception(SPU_NOT_EXISTS); | ||
| 63 | + } | ||
| 64 | + if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) { | ||
| 65 | + throw exception(SPU_NOT_ENABLE); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + // 查询商品 SKU | ||
| 69 | + List<ProductSkuDO> skus = productSkuService.getSkuListBySpuIdAndStatus(spu.getId(), | ||
| 70 | + CommonStatusEnum.ENABLE.getStatus()); | ||
| 71 | + // 查询商品属性 | ||
| 72 | + List<ProductPropertyValueDetailRespBO> propertyValues = productPropertyValueService | ||
| 73 | + .getPropertyValueDetailList(ProductSkuConvert.INSTANCE.convertPropertyValueIds(skus)); | ||
| 74 | + // 拼接 | ||
| 75 | + return success(ProductSpuConvert.INSTANCE.convert(spu, skus, propertyValues)); | ||
| 43 | } | 76 | } |
| 77 | + | ||
| 44 | } | 78 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.controller.app.spu.vo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO; | ||
| 4 | +import io.swagger.annotations.ApiModel; | ||
| 5 | +import io.swagger.annotations.ApiModelProperty; | ||
| 6 | +import lombok.Data; | ||
| 7 | + | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 10 | +@ApiModel("用户 App - 商品 SPU 明细 Response VO") | ||
| 11 | +@Data | ||
| 12 | +public class AppProductSpuDetailRespVO { | ||
| 13 | + | ||
| 14 | + @ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1") | ||
| 15 | + private Long id; | ||
| 16 | + | ||
| 17 | + // ========== 基本信息 ========= | ||
| 18 | + | ||
| 19 | + @ApiModelProperty(value = "商品名称", required = true, example = "芋道") | ||
| 20 | + private String name; | ||
| 21 | + | ||
| 22 | + @ApiModelProperty(value = "促销语", example = "好吃!") | ||
| 23 | + private String sellPoint; | ||
| 24 | + | ||
| 25 | + @ApiModelProperty(value = "商品详情", required = true, example = "我是商品描述") | ||
| 26 | + private String description; | ||
| 27 | + | ||
| 28 | + @ApiModelProperty(value = "商品分类编号", required = true, example = "1") | ||
| 29 | + private Long categoryId; | ||
| 30 | + | ||
| 31 | + @ApiModelProperty(value = "商品图片的数组", required = true) | ||
| 32 | + private List<String> picUrls; | ||
| 33 | + | ||
| 34 | + @ApiModelProperty(value = "商品视频", required = true) | ||
| 35 | + private String videoUrl; | ||
| 36 | + | ||
| 37 | + // ========== SKU 相关字段 ========= | ||
| 38 | + | ||
| 39 | + @ApiModelProperty(value = "规格类型", required = true, example = "1", notes = "参见 ProductSpuSpecTypeEnum 枚举类") | ||
| 40 | + private Integer specType; | ||
| 41 | + | ||
| 42 | + @ApiModelProperty(value = "是否展示库存", required = true, example = "true") | ||
| 43 | + private Boolean showStock; | ||
| 44 | + | ||
| 45 | + @ApiModelProperty(value = " 最小价格,单位使用:分", required = true, example = "1024") | ||
| 46 | + private Integer minPrice; | ||
| 47 | + | ||
| 48 | + @ApiModelProperty(value = "最大价格,单位使用:分", required = true, example = "1024") | ||
| 49 | + private Integer maxPrice; | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * SKU 数组 | ||
| 53 | + */ | ||
| 54 | + private List<Sku> skus; | ||
| 55 | + | ||
| 56 | + // ========== 统计相关字段 ========= | ||
| 57 | + | ||
| 58 | + @ApiModelProperty(value = "商品销量", required = true, example = "1024") | ||
| 59 | + private Integer salesCount; | ||
| 60 | + | ||
| 61 | + @ApiModel("用户 App - 商品 SPU 明细的 SKU 信息") | ||
| 62 | + @Data | ||
| 63 | + public static class Sku { | ||
| 64 | + | ||
| 65 | + @ApiModelProperty(value = "商品 SKU 编号", example = "1") | ||
| 66 | + private Long id; | ||
| 67 | + | ||
| 68 | + /** | ||
| 69 | + * 商品属性数组 | ||
| 70 | + */ | ||
| 71 | + private List<AppProductPropertyValueDetailRespVO> properties; | ||
| 72 | + | ||
| 73 | + @ApiModelProperty(value = "销售价格,单位:分", required = true, example = "1024", notes = "单位:分") | ||
| 74 | + private Integer price; | ||
| 75 | + | ||
| 76 | + @ApiModelProperty(value = "市场价", example = "1024", notes = "单位:分") | ||
| 77 | + private Integer marketPrice; | ||
| 78 | + | ||
| 79 | + @ApiModelProperty(value = "图片地址", required = true, example = "https://www.iocoder.cn/xx.png") | ||
| 80 | + private String picUrl; | ||
| 81 | + | ||
| 82 | + @ApiModelProperty(value = "库存", required = true, example = "1") | ||
| 83 | + private Integer stock; | ||
| 84 | + | ||
| 85 | + @ApiModelProperty(value = "商品重量", example = "1", notes = "单位:kg 千克") | ||
| 86 | + private Double weight; | ||
| 87 | + | ||
| 88 | + @ApiModelProperty(value = "商品体积", example = "1024", notes = "单位:m^3 平米") | ||
| 89 | + private Double volume; | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | +} |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.controller.app.spu.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.annotations.ApiModel; | ||
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +import javax.validation.constraints.NotEmpty; | ||
| 8 | +import javax.validation.constraints.NotNull; | ||
| 9 | +import java.util.List; | ||
| 10 | + | ||
| 11 | +@ApiModel("用户 App - 商品 SPU 分页项 Response VO") | ||
| 12 | +@Data | ||
| 13 | +public class AppProductSpuPageItemRespVO { | ||
| 14 | + | ||
| 15 | + @ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1") | ||
| 16 | + private Long id; | ||
| 17 | + | ||
| 18 | + @ApiModelProperty(value = "商品名称", required = true, example = "芋道") | ||
| 19 | + @NotEmpty(message = "商品名称不能为空") | ||
| 20 | + private String name; | ||
| 21 | + | ||
| 22 | + @ApiModelProperty(value = "分类编号", required = true) | ||
| 23 | + @NotNull(message = "分类编号不能为空") | ||
| 24 | + private Long categoryId; | ||
| 25 | + | ||
| 26 | + @ApiModelProperty(value = "商品图片的数组", required = true) | ||
| 27 | + private List<String> picUrls; | ||
| 28 | + | ||
| 29 | + @ApiModelProperty(value = " 最小价格,单位使用:分", required = true, example = "1024") | ||
| 30 | + private Integer minPrice; | ||
| 31 | + | ||
| 32 | + @ApiModelProperty(value = "最大价格,单位使用:分", required = true, example = "1024") | ||
| 33 | + private Integer maxPrice; | ||
| 34 | + | ||
| 35 | + // ========== 统计相关字段 ========= | ||
| 36 | + | ||
| 37 | + @ApiModelProperty(value = "商品销量", example = "1024") | ||
| 38 | + private Integer salesCount; | ||
| 39 | + | ||
| 40 | +} |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.controller.app.spu.vo; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.StrUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 5 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
| 6 | +import io.swagger.annotations.ApiModel; | ||
| 7 | +import io.swagger.annotations.ApiModelProperty; | ||
| 8 | +import lombok.Data; | ||
| 9 | +import lombok.EqualsAndHashCode; | ||
| 10 | +import lombok.ToString; | ||
| 11 | + | ||
| 12 | +import javax.validation.constraints.AssertTrue; | ||
| 13 | + | ||
| 14 | +@ApiModel("用户 App - 商品 SPU 分页 Request VO") | ||
| 15 | +@Data | ||
| 16 | +@EqualsAndHashCode(callSuper = true) | ||
| 17 | +@ToString(callSuper = true) | ||
| 18 | +public class AppProductSpuPageReqVO extends PageParam { | ||
| 19 | + | ||
| 20 | + public static final String SORT_FIELD_PRICE = "price"; | ||
| 21 | + public static final String SORT_FIELD_SALES_COUNT = "salesCount"; | ||
| 22 | + | ||
| 23 | + @ApiModelProperty(value = "分类编号", example = "1") | ||
| 24 | + private Long categoryId; | ||
| 25 | + | ||
| 26 | + @ApiModelProperty(value = "关键字", example = "好看") | ||
| 27 | + private String keyword; | ||
| 28 | + | ||
| 29 | + @ApiModelProperty(value = "排序字段", example = "price", notes = "参见 AppSpuPageReqVO.SORT_FIELD_XXX 常量") | ||
| 30 | + private String sortField; | ||
| 31 | + | ||
| 32 | + @ApiModelProperty(value = "排序方式", example = "true", notes = "true - 升序;false - 降序") | ||
| 33 | + private Boolean sortAsc; | ||
| 34 | + | ||
| 35 | + @AssertTrue(message = "排序字段不合法") | ||
| 36 | + @JsonIgnore | ||
| 37 | + public boolean isSortFieldValid() { | ||
| 38 | + if (StrUtil.isEmpty(sortField)) { | ||
| 39 | + return true; | ||
| 40 | + } | ||
| 41 | + return StrUtil.equalsAny(sortField, SORT_FIELD_PRICE, SORT_FIELD_SALES_COUNT); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | +} |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuPageReqVO.java
| 1 | -package cn.iocoder.yudao.module.product.controller.app.spu.vo; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | -import lombok.Data; | ||
| 6 | -import lombok.EqualsAndHashCode; | ||
| 7 | -import lombok.ToString; | ||
| 8 | - | ||
| 9 | -@Schema(description = "App - 商品spu分页 Request VO") | ||
| 10 | -@Data | ||
| 11 | -@EqualsAndHashCode(callSuper = true) | ||
| 12 | -@ToString(callSuper = true) | ||
| 13 | -public class AppSpuPageReqVO extends PageParam { | ||
| 14 | - | ||
| 15 | - @Schema(description = "分类id") | ||
| 16 | - private Long categoryId; | ||
| 17 | -} |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuPageRespVO.java
| 1 | -package cn.iocoder.yudao.module.product.controller.app.spu.vo; | ||
| 2 | - | ||
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | -import lombok.Data; | ||
| 5 | - | ||
| 6 | -import javax.validation.constraints.NotNull; | ||
| 7 | -import java.util.List; | ||
| 8 | - | ||
| 9 | -@Schema(description = "App - 商品spu分页 Request VO") | ||
| 10 | -@Data | ||
| 11 | -public class AppSpuPageRespVO { | ||
| 12 | - | ||
| 13 | - @Schema(description = "主键", required = true, example = "1") | ||
| 14 | - private Long id; | ||
| 15 | - | ||
| 16 | - @Schema(description = "商品名称") | ||
| 17 | - private String name; | ||
| 18 | - | ||
| 19 | - @Schema(description = "卖点", required = true) | ||
| 20 | - @NotNull(message = "卖点不能为空") | ||
| 21 | - private String sellPoint; | ||
| 22 | - | ||
| 23 | - @Schema(description = "描述", required = true) | ||
| 24 | - @NotNull(message = "描述不能为空") | ||
| 25 | - private String description; | ||
| 26 | - | ||
| 27 | - @Schema(description = "分类id", required = true) | ||
| 28 | - @NotNull(message = "分类id不能为空") | ||
| 29 | - private Long categoryId; | ||
| 30 | - | ||
| 31 | - @Schema(description = "商品主图地址,* 数组,以逗号分隔,最多上传15张", required = true) | ||
| 32 | - @NotNull(message = "商品主图地址,* 数组,以逗号分隔,最多上传15张不能为空") | ||
| 33 | - private List<String> picUrls; | ||
| 34 | - | ||
| 35 | - @Schema(description = "排序字段", required = true) | ||
| 36 | - @NotNull(message = "排序字段不能为空") | ||
| 37 | - private Integer sort; | ||
| 38 | - | ||
| 39 | - @Schema(description = "点赞初始人数") | ||
| 40 | - private Integer likeCount; | ||
| 41 | - | ||
| 42 | - @Schema(description = "价格 单位使用:分") | ||
| 43 | - private Integer price; | ||
| 44 | - | ||
| 45 | - @Schema(description = "库存数量") | ||
| 46 | - private Integer quantity; | ||
| 47 | - | ||
| 48 | - @Schema(description = "上下架状态: 0 上架(开启) 1 下架(禁用)") | ||
| 49 | - private Integer status; | ||
| 50 | - | ||
| 51 | -} |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuRespVO.java
| 1 | -package cn.iocoder.yudao.module.product.controller.app.spu.vo; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO; | ||
| 4 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | -import lombok.Data; | ||
| 6 | -import lombok.EqualsAndHashCode; | ||
| 7 | - | ||
| 8 | -/** | ||
| 9 | - * <p> | ||
| 10 | - * | ||
| 11 | - * </p> | ||
| 12 | - * | ||
| 13 | - * @author LuoWenFeng | ||
| 14 | - */ | ||
| 15 | -@Schema(description = "App - 商品spu Response VO") | ||
| 16 | -@Data | ||
| 17 | -@EqualsAndHashCode(callSuper = true) | ||
| 18 | -public class AppSpuRespVO extends ProductSpuRespVO { | ||
| 19 | - | ||
| 20 | - | ||
| 21 | -} |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java
| 1 | package cn.iocoder.yudao.module.product.convert.property; | 1 | package cn.iocoder.yudao.module.product.convert.property; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 4 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO; | 5 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO; |
| 5 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyCreateReqVO; | 6 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyCreateReqVO; |
| 6 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO; | 7 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO; |
| 7 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyUpdateReqVO; | 8 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyUpdateReqVO; |
| 8 | -import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; | ||
| 9 | import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; | 9 | import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; |
| 10 | import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; | 10 | import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; |
| 11 | import org.mapstruct.Mapper; | 11 | import org.mapstruct.Mapper; |
| 12 | import org.mapstruct.factory.Mappers; | 12 | import org.mapstruct.factory.Mappers; |
| 13 | 13 | ||
| 14 | import java.util.List; | 14 | import java.util.List; |
| 15 | +import java.util.Map; | ||
| 15 | 16 | ||
| 16 | /** | 17 | /** |
| 17 | - * 规格名称 Convert | 18 | + * 属性项 Convert |
| 18 | * | 19 | * |
| 19 | * @author 芋道源码 | 20 | * @author 芋道源码 |
| 20 | */ | 21 | */ |
| @@ -27,12 +28,21 @@ public interface ProductPropertyConvert { | @@ -27,12 +28,21 @@ public interface ProductPropertyConvert { | ||
| 27 | 28 | ||
| 28 | ProductPropertyDO convert(ProductPropertyUpdateReqVO bean); | 29 | ProductPropertyDO convert(ProductPropertyUpdateReqVO bean); |
| 29 | 30 | ||
| 30 | - ProductPropertyAndValueRespVO convert(ProductPropertyRespVO bean); | ||
| 31 | - | ||
| 32 | ProductPropertyRespVO convert(ProductPropertyDO bean); | 31 | ProductPropertyRespVO convert(ProductPropertyDO bean); |
| 33 | 32 | ||
| 34 | List<ProductPropertyRespVO> convertList(List<ProductPropertyDO> list); | 33 | List<ProductPropertyRespVO> convertList(List<ProductPropertyDO> list); |
| 35 | 34 | ||
| 36 | PageResult<ProductPropertyRespVO> convertPage(PageResult<ProductPropertyDO> page); | 35 | PageResult<ProductPropertyRespVO> convertPage(PageResult<ProductPropertyDO> page); |
| 37 | 36 | ||
| 37 | + default List<ProductPropertyAndValueRespVO> convertList(List<ProductPropertyDO> keys, List<ProductPropertyValueDO> values) { | ||
| 38 | + Map<Long, List<ProductPropertyValueDO>> valueMap = CollectionUtils.convertMultiMap(values, ProductPropertyValueDO::getPropertyId); | ||
| 39 | + return CollectionUtils.convertList(keys, key -> { | ||
| 40 | + ProductPropertyAndValueRespVO respVO = convert02(key); | ||
| 41 | + respVO.setValues(convertList02(valueMap.get(key.getId()))); | ||
| 42 | + return respVO; | ||
| 43 | + }); | ||
| 44 | + } | ||
| 45 | + ProductPropertyAndValueRespVO convert02(ProductPropertyDO bean); | ||
| 46 | + List<ProductPropertyAndValueRespVO.Value> convertList02(List<ProductPropertyValueDO> list); | ||
| 47 | + | ||
| 38 | } | 48 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/propertyvalue/ProductPropertyValueConvert.java
| 1 | package cn.iocoder.yudao.module.product.convert.propertyvalue; | 1 | package cn.iocoder.yudao.module.product.convert.propertyvalue; |
| 2 | 2 | ||
| 3 | -import java.util.*; | ||
| 4 | - | ||
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | - | 4 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 5 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||
| 6 | +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; | ||
| 7 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO; | 7 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO; |
| 8 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; | 8 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; |
| 9 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO; | 9 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO; |
| 10 | +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; | ||
| 10 | import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; | 11 | import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; |
| 12 | +import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; | ||
| 11 | import org.mapstruct.Mapper; | 13 | import org.mapstruct.Mapper; |
| 12 | import org.mapstruct.factory.Mappers; | 14 | import org.mapstruct.factory.Mappers; |
| 13 | 15 | ||
| 16 | +import java.util.List; | ||
| 17 | +import java.util.Map; | ||
| 18 | + | ||
| 19 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | ||
| 20 | + | ||
| 14 | /** | 21 | /** |
| 15 | - * 规格值 Convert | 22 | + * 属性值 Convert |
| 16 | * | 23 | * |
| 17 | * @author 芋道源码 | 24 | * @author 芋道源码 |
| 18 | */ | 25 | */ |
| @@ -31,6 +38,18 @@ public interface ProductPropertyValueConvert { | @@ -31,6 +38,18 @@ public interface ProductPropertyValueConvert { | ||
| 31 | 38 | ||
| 32 | PageResult<ProductPropertyValueRespVO> convertPage(PageResult<ProductPropertyValueDO> page); | 39 | PageResult<ProductPropertyValueRespVO> convertPage(PageResult<ProductPropertyValueDO> page); |
| 33 | 40 | ||
| 34 | - List<ProductPropertyValueDO> convertList03(List<ProductPropertyValueCreateReqVO> list); | 41 | + default List<ProductPropertyValueDetailRespBO> convertList(List<ProductPropertyValueDO> values, List<ProductPropertyDO> keys) { |
| 42 | + Map<Long, ProductPropertyDO> keyMap = convertMap(keys, ProductPropertyDO::getId); | ||
| 43 | + return CollectionUtils.convertList(values, value -> { | ||
| 44 | + ProductPropertyValueDetailRespBO valueDetail = new ProductPropertyValueDetailRespBO() | ||
| 45 | + .setValueId(value.getId()).setValueName(value.getName()); | ||
| 46 | + // 设置属性项 | ||
| 47 | + MapUtils.findAndThen(keyMap, value.getPropertyId(), | ||
| 48 | + key -> valueDetail.setPropertyId(key.getId()).setPropertyName(key.getName())); | ||
| 49 | + return valueDetail; | ||
| 50 | + }); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + List<ProductPropertyValueDetailRespDTO> convertList02(List<ProductPropertyValueDetailRespBO> list); | ||
| 35 | 54 | ||
| 36 | } | 55 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
| 1 | package cn.iocoder.yudao.module.product.convert.sku; | 1 | package cn.iocoder.yudao.module.product.convert.sku; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.hutool.core.util.StrUtil; | ||
| 3 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | 5 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 4 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; | 6 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; |
| 5 | import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; | 7 | import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; |
| @@ -10,9 +12,8 @@ import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; | @@ -10,9 +12,8 @@ import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; | ||
| 10 | import org.mapstruct.Mapper; | 12 | import org.mapstruct.Mapper; |
| 11 | import org.mapstruct.factory.Mappers; | 13 | import org.mapstruct.factory.Mappers; |
| 12 | 14 | ||
| 13 | -import java.util.HashMap; | ||
| 14 | -import java.util.List; | ||
| 15 | -import java.util.Map; | 15 | +import java.util.*; |
| 16 | +import java.util.stream.Collectors; | ||
| 16 | 17 | ||
| 17 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | 18 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; |
| 18 | 19 | ||
| @@ -32,11 +33,15 @@ public interface ProductSkuConvert { | @@ -32,11 +33,15 @@ public interface ProductSkuConvert { | ||
| 32 | 33 | ||
| 33 | List<ProductSkuRespVO> convertList(List<ProductSkuDO> list); | 34 | List<ProductSkuRespVO> convertList(List<ProductSkuDO> list); |
| 34 | 35 | ||
| 35 | - List<ProductSkuDO> convertSkuDOList(List<ProductSkuCreateOrUpdateReqVO> list); | 36 | + List<ProductSkuDO> convertList06(List<ProductSkuCreateOrUpdateReqVO> list); |
| 36 | 37 | ||
| 37 | - ProductSkuRespDTO convert02(ProductSkuDO bean); | 38 | + default List<ProductSkuDO> convertList06(List<ProductSkuCreateOrUpdateReqVO> list, Long spuId, String spuName) { |
| 39 | + List<ProductSkuDO> result = convertList06(list); | ||
| 40 | + result.forEach(item -> item.setSpuId(spuId).setSpuName(spuName)); | ||
| 41 | + return result; | ||
| 42 | + } | ||
| 38 | 43 | ||
| 39 | - List<ProductSkuRespDTO> convertList02(List<ProductSkuDO> list); | 44 | + ProductSkuRespDTO convert02(ProductSkuDO bean); |
| 40 | 45 | ||
| 41 | List<ProductSpuDetailRespVO.Sku> convertList03(List<ProductSkuDO> list); | 46 | List<ProductSpuDetailRespVO.Sku> convertList03(List<ProductSkuDO> list); |
| 42 | 47 | ||
| @@ -66,4 +71,23 @@ public interface ProductSkuConvert { | @@ -66,4 +71,23 @@ public interface ProductSkuConvert { | ||
| 66 | return spuIdAndStockMap; | 71 | return spuIdAndStockMap; |
| 67 | } | 72 | } |
| 68 | 73 | ||
| 74 | + default Collection<Long> convertPropertyValueIds(List<ProductSkuDO> list) { | ||
| 75 | + if (CollUtil.isEmpty(list)) { | ||
| 76 | + return new HashSet<>(); | ||
| 77 | + } | ||
| 78 | + return list.stream().filter(item -> item.getProperties() != null) | ||
| 79 | + .flatMap(p -> p.getProperties().stream()) // 遍历多个 Property 属性 | ||
| 80 | + .map(ProductSkuDO.Property::getValueId) // 将每个 Property 转换成对应的 propertyId,最后形成集合 | ||
| 81 | + .collect(Collectors.toSet()); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + default String buildPropertyKey(ProductSkuDO bean) { | ||
| 85 | + if (CollUtil.isEmpty(bean.getProperties())) { | ||
| 86 | + return StrUtil.EMPTY; | ||
| 87 | + } | ||
| 88 | + List<ProductSkuDO.Property> properties = new ArrayList<>(bean.getProperties()); | ||
| 89 | + properties.sort(Comparator.comparing(ProductSkuDO.Property::getValueId)); | ||
| 90 | + return properties.stream().map(m -> String.valueOf(m.getValueId())).collect(Collectors.joining()); | ||
| 91 | + } | ||
| 92 | + | ||
| 69 | } | 93 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
| 1 | package cn.iocoder.yudao.module.product.convert.spu; | 1 | package cn.iocoder.yudao.module.product.convert.spu; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | 5 | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 6 | +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueDetailRespVO; | ||
| 5 | import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; | 7 | import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; |
| 6 | -import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO; | ||
| 7 | -import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO; | 8 | +import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO; |
| 9 | +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO; | ||
| 10 | +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; | ||
| 11 | +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageItemRespVO; | ||
| 12 | +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; | ||
| 8 | import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; | 13 | import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; |
| 14 | +import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; | ||
| 9 | import org.mapstruct.Mapper; | 15 | import org.mapstruct.Mapper; |
| 10 | import org.mapstruct.factory.Mappers; | 16 | import org.mapstruct.factory.Mappers; |
| 11 | 17 | ||
| 18 | +import java.util.ArrayList; | ||
| 12 | import java.util.List; | 19 | import java.util.List; |
| 20 | +import java.util.Map; | ||
| 21 | + | ||
| 22 | +import static cn.hutool.core.util.ObjectUtil.defaultIfNull; | ||
| 23 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | ||
| 13 | 24 | ||
| 14 | /** | 25 | /** |
| 15 | - * 商品spu Convert | 26 | + * 商品 SPU Convert |
| 16 | * | 27 | * |
| 17 | * @author 芋道源码 | 28 | * @author 芋道源码 |
| 18 | */ | 29 | */ |
| @@ -25,18 +36,73 @@ public interface ProductSpuConvert { | @@ -25,18 +36,73 @@ public interface ProductSpuConvert { | ||
| 25 | 36 | ||
| 26 | ProductSpuDO convert(ProductSpuUpdateReqVO bean); | 37 | ProductSpuDO convert(ProductSpuUpdateReqVO bean); |
| 27 | 38 | ||
| 28 | - ProductSpuRespVO convert(ProductSpuDO bean); | ||
| 29 | - | ||
| 30 | - List<ProductSpuRespVO> convertList(List<ProductSpuDO> list); | 39 | + List<ProductSpuDO> convertList(List<ProductSpuDO> list); |
| 31 | 40 | ||
| 32 | PageResult<ProductSpuRespVO> convertPage(PageResult<ProductSpuDO> page); | 41 | PageResult<ProductSpuRespVO> convertPage(PageResult<ProductSpuDO> page); |
| 33 | 42 | ||
| 34 | - ProductSpuPageReqVO convert(AppSpuPageReqVO bean); | ||
| 35 | - | ||
| 36 | - AppSpuPageRespVO convertAppResp(ProductSpuDO list); | 43 | + ProductSpuPageReqVO convert(AppProductSpuPageReqVO bean); |
| 37 | 44 | ||
| 38 | List<ProductSpuRespDTO> convertList2(List<ProductSpuDO> list); | 45 | List<ProductSpuRespDTO> convertList2(List<ProductSpuDO> list); |
| 39 | 46 | ||
| 40 | List<ProductSpuSimpleRespVO> convertList02(List<ProductSpuDO> list); | 47 | List<ProductSpuSimpleRespVO> convertList02(List<ProductSpuDO> list); |
| 41 | 48 | ||
| 49 | + default AppProductSpuDetailRespVO convert(ProductSpuDO spu, List<ProductSkuDO> skus, | ||
| 50 | + List<ProductPropertyValueDetailRespBO> propertyValues) { | ||
| 51 | + AppProductSpuDetailRespVO spuVO = convert02(spu) | ||
| 52 | + .setSalesCount(spu.getSalesCount() + defaultIfNull(spu.getVirtualSalesCount(), 0)); | ||
| 53 | + spuVO.setSkus(convertList03(skus)); | ||
| 54 | + // 处理商品属性 | ||
| 55 | + Map<Long, ProductPropertyValueDetailRespBO> propertyValueMap = convertMap(propertyValues, ProductPropertyValueDetailRespBO::getValueId); | ||
| 56 | + for (int i = 0; i < skus.size(); i++) { | ||
| 57 | + List<ProductSkuDO.Property> properties = skus.get(i).getProperties(); | ||
| 58 | + if (CollUtil.isEmpty(properties)) { | ||
| 59 | + continue; | ||
| 60 | + } | ||
| 61 | + AppProductSpuDetailRespVO.Sku sku = spuVO.getSkus().get(i); | ||
| 62 | + sku.setProperties(new ArrayList<>(properties.size())); | ||
| 63 | + // 遍历每个 properties,设置到 AppSpuDetailRespVO.Sku 中 | ||
| 64 | + properties.forEach(property -> { | ||
| 65 | + ProductPropertyValueDetailRespBO propertyValue = propertyValueMap.get(property.getValueId()); | ||
| 66 | + if (propertyValue == null) { | ||
| 67 | + return; | ||
| 68 | + } | ||
| 69 | + sku.getProperties().add(convert03(propertyValue)); | ||
| 70 | + }); | ||
| 71 | + } | ||
| 72 | + return spuVO; | ||
| 73 | + } | ||
| 74 | + AppProductSpuDetailRespVO convert02(ProductSpuDO spu); | ||
| 75 | + List<AppProductSpuDetailRespVO.Sku> convertList03(List<ProductSkuDO> skus); | ||
| 76 | + AppProductPropertyValueDetailRespVO convert03(ProductPropertyValueDetailRespBO propertyValue); | ||
| 77 | + | ||
| 78 | + PageResult<AppProductSpuPageItemRespVO> convertPage02(PageResult<ProductSpuDO> page); | ||
| 79 | + | ||
| 80 | + default ProductSpuDetailRespVO convert03(ProductSpuDO spu, List<ProductSkuDO> skus, | ||
| 81 | + List<ProductPropertyValueDetailRespBO> propertyValues) { | ||
| 82 | + ProductSpuDetailRespVO spuVO = convert03(spu); | ||
| 83 | + spuVO.setSkus(convertList04(skus)); | ||
| 84 | + // 处理商品属性 | ||
| 85 | + Map<Long, ProductPropertyValueDetailRespBO> propertyValueMap = convertMap(propertyValues, ProductPropertyValueDetailRespBO::getValueId); | ||
| 86 | + for (int i = 0; i < skus.size(); i++) { | ||
| 87 | + List<ProductSkuDO.Property> properties = skus.get(i).getProperties(); | ||
| 88 | + if (CollUtil.isEmpty(properties)) { | ||
| 89 | + continue; | ||
| 90 | + } | ||
| 91 | + ProductSpuDetailRespVO.Sku sku = spuVO.getSkus().get(i); | ||
| 92 | + sku.setProperties(new ArrayList<>(properties.size())); | ||
| 93 | + // 遍历每个 properties,设置到 AppSpuDetailRespVO.Sku 中 | ||
| 94 | + properties.forEach(property -> { | ||
| 95 | + ProductPropertyValueDetailRespBO propertyValue = propertyValueMap.get(property.getValueId()); | ||
| 96 | + if (propertyValue == null) { | ||
| 97 | + return; | ||
| 98 | + } | ||
| 99 | + sku.getProperties().add(convert04(propertyValue)); | ||
| 100 | + }); | ||
| 101 | + } | ||
| 102 | + return spuVO; | ||
| 103 | + } | ||
| 104 | + ProductSpuDetailRespVO convert03(ProductSpuDO spu); | ||
| 105 | + List<ProductSpuDetailRespVO.Sku> convertList04(List<ProductSkuDO> skus); | ||
| 106 | + ProductPropertyValueDetailRespVO convert04(ProductPropertyValueDetailRespBO propertyValue); | ||
| 107 | + | ||
| 42 | } | 108 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java
| 1 | package cn.iocoder.yudao.module.product.dal.dataobject.property; | 1 | package cn.iocoder.yudao.module.product.dal.dataobject.property; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 4 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 5 | import com.baomidou.mybatisplus.annotation.KeySequence; | 4 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 6 | import com.baomidou.mybatisplus.annotation.TableId; | 5 | import com.baomidou.mybatisplus.annotation.TableId; |
| @@ -8,7 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableName; | @@ -8,7 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableName; | ||
| 8 | import lombok.*; | 7 | import lombok.*; |
| 9 | 8 | ||
| 10 | /** | 9 | /** |
| 11 | - * 规格名称 DO | 10 | + * 商品属性项 DO |
| 12 | * | 11 | * |
| 13 | * @author 芋道源码 | 12 | * @author 芋道源码 |
| 14 | */ | 13 | */ |
| @@ -28,20 +27,12 @@ public class ProductPropertyDO extends BaseDO { | @@ -28,20 +27,12 @@ public class ProductPropertyDO extends BaseDO { | ||
| 28 | @TableId | 27 | @TableId |
| 29 | private Long id; | 28 | private Long id; |
| 30 | /** | 29 | /** |
| 31 | - * 规格名称 | 30 | + * 名称 |
| 32 | */ | 31 | */ |
| 33 | private String name; | 32 | private String name; |
| 34 | /** | 33 | /** |
| 35 | - * 状态 | ||
| 36 | - * | ||
| 37 | - * 枚举 {@link CommonStatusEnum} | ||
| 38 | - */ | ||
| 39 | - private Integer status; | ||
| 40 | - /** | ||
| 41 | * 备注 | 34 | * 备注 |
| 42 | */ | 35 | */ |
| 43 | private String remark; | 36 | private String remark; |
| 44 | 37 | ||
| 45 | - // TODO 芋艿:rule;规格属性 (发布商品时,和 SKU 关联);规格参数(搜索商品时,与 Category 关联搜索) | ||
| 46 | - | ||
| 47 | } | 38 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java
| 1 | package cn.iocoder.yudao.module.product.dal.dataobject.property; | 1 | package cn.iocoder.yudao.module.product.dal.dataobject.property; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 4 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 5 | import com.baomidou.mybatisplus.annotation.KeySequence; | 4 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 6 | import com.baomidou.mybatisplus.annotation.TableId; | 5 | import com.baomidou.mybatisplus.annotation.TableId; |
| @@ -9,7 +8,7 @@ import lombok.*; | @@ -9,7 +8,7 @@ import lombok.*; | ||
| 9 | 8 | ||
| 10 | 9 | ||
| 11 | /** | 10 | /** |
| 12 | - * 规格值 DO | 11 | + * 商品属性值 DO |
| 13 | * | 12 | * |
| 14 | * @author 芋道源码 | 13 | * @author 芋道源码 |
| 15 | */ | 14 | */ |
| @@ -29,22 +28,16 @@ public class ProductPropertyValueDO extends BaseDO { | @@ -29,22 +28,16 @@ public class ProductPropertyValueDO extends BaseDO { | ||
| 29 | @TableId | 28 | @TableId |
| 30 | private Long id; | 29 | private Long id; |
| 31 | /** | 30 | /** |
| 32 | - * 规格键编号 | 31 | + * 属性项的编号 |
| 33 | * | 32 | * |
| 34 | * 关联 {@link ProductPropertyDO#getId()} | 33 | * 关联 {@link ProductPropertyDO#getId()} |
| 35 | */ | 34 | */ |
| 36 | private Long propertyId; | 35 | private Long propertyId; |
| 37 | /** | 36 | /** |
| 38 | - * 规格值名字 | 37 | + * 名称 |
| 39 | */ | 38 | */ |
| 40 | private String name; | 39 | private String name; |
| 41 | /** | 40 | /** |
| 42 | - * 状态 | ||
| 43 | - * | ||
| 44 | - * 枚举 {@link CommonStatusEnum} | ||
| 45 | - */ | ||
| 46 | - private Integer status; | ||
| 47 | - /** | ||
| 48 | * 备注 | 41 | * 备注 |
| 49 | * | 42 | * |
| 50 | */ | 43 | */ |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java
| @@ -36,17 +36,19 @@ public class ProductSkuDO extends BaseDO { | @@ -36,17 +36,19 @@ public class ProductSkuDO extends BaseDO { | ||
| 36 | @TableId | 36 | @TableId |
| 37 | private Long id; | 37 | private Long id; |
| 38 | /** | 38 | /** |
| 39 | - * 商品 SKU 名字 | ||
| 40 | - */ | ||
| 41 | - private String name; | ||
| 42 | - /** | ||
| 43 | * SPU 编号 | 39 | * SPU 编号 |
| 44 | * <p> | 40 | * <p> |
| 45 | * 关联 {@link ProductSpuDO#getId()} | 41 | * 关联 {@link ProductSpuDO#getId()} |
| 46 | */ | 42 | */ |
| 47 | private Long spuId; | 43 | private Long spuId; |
| 48 | /** | 44 | /** |
| 49 | - * 规格值数组,JSON 格式 | 45 | + * SPU 名字 |
| 46 | + * | ||
| 47 | + * 冗余 {@link ProductSkuDO#getSpuName()} | ||
| 48 | + */ | ||
| 49 | + private String spuName; | ||
| 50 | + /** | ||
| 51 | + * 属性数组,JSON 格式 | ||
| 50 | */ | 52 | */ |
| 51 | @TableField(typeHandler = PropertyTypeHandler.class) | 53 | @TableField(typeHandler = PropertyTypeHandler.class) |
| 52 | private List<Property> properties; | 54 | private List<Property> properties; |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java
| @@ -3,31 +3,30 @@ package cn.iocoder.yudao.module.product.dal.mysql.property; | @@ -3,31 +3,30 @@ package cn.iocoder.yudao.module.product.dal.mysql.property; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyListReqVO; | ||
| 6 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyPageReqVO; | 7 | import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyPageReqVO; |
| 7 | import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; | 8 | import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; |
| 8 | import org.apache.ibatis.annotations.Mapper; | 9 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 10 | ||
| 10 | import java.util.List; | 11 | import java.util.List; |
| 11 | 12 | ||
| 12 | -/** | ||
| 13 | - * 规格名称 Mapper | ||
| 14 | - * | ||
| 15 | - * @author 芋道源码 | ||
| 16 | - */ | ||
| 17 | @Mapper | 13 | @Mapper |
| 18 | public interface ProductPropertyMapper extends BaseMapperX<ProductPropertyDO> { | 14 | public interface ProductPropertyMapper extends BaseMapperX<ProductPropertyDO> { |
| 19 | 15 | ||
| 20 | default PageResult<ProductPropertyDO> selectPage(ProductPropertyPageReqVO reqVO) { | 16 | default PageResult<ProductPropertyDO> selectPage(ProductPropertyPageReqVO reqVO) { |
| 21 | return selectPage(reqVO, new LambdaQueryWrapperX<ProductPropertyDO>() | 17 | return selectPage(reqVO, new LambdaQueryWrapperX<ProductPropertyDO>() |
| 22 | .likeIfPresent(ProductPropertyDO::getName, reqVO.getName()) | 18 | .likeIfPresent(ProductPropertyDO::getName, reqVO.getName()) |
| 23 | - .eqIfPresent(ProductPropertyDO::getStatus, reqVO.getStatus()) | ||
| 24 | .betweenIfPresent(ProductPropertyDO::getCreateTime, reqVO.getCreateTime()) | 19 | .betweenIfPresent(ProductPropertyDO::getCreateTime, reqVO.getCreateTime()) |
| 25 | .orderByDesc(ProductPropertyDO::getId)); | 20 | .orderByDesc(ProductPropertyDO::getId)); |
| 26 | } | 21 | } |
| 27 | 22 | ||
| 28 | default ProductPropertyDO selectByName(String name) { | 23 | default ProductPropertyDO selectByName(String name) { |
| 29 | - return selectOne(new LambdaQueryWrapperX<ProductPropertyDO>() | ||
| 30 | - .eqIfPresent(ProductPropertyDO::getName, name)); | 24 | + return selectOne(ProductPropertyDO::getName, name); |
| 25 | + } | ||
| 26 | + | ||
| 27 | + default List<ProductPropertyDO> selectList(ProductPropertyListReqVO listReqVO) { | ||
| 28 | + return selectList(new LambdaQueryWrapperX<ProductPropertyDO>() | ||
| 29 | + .eqIfPresent(ProductPropertyDO::getName, listReqVO.getName())); | ||
| 31 | } | 30 | } |
| 32 | 31 | ||
| 33 | } | 32 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java
| @@ -7,17 +7,13 @@ import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.Produc | @@ -7,17 +7,13 @@ import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.Produc | ||
| 7 | import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; | 7 | import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; |
| 8 | import org.apache.ibatis.annotations.Mapper; | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 9 | ||
| 10 | +import java.util.Collection; | ||
| 10 | import java.util.List; | 11 | import java.util.List; |
| 11 | 12 | ||
| 12 | -/** | ||
| 13 | - * 规格值 Mapper | ||
| 14 | - * | ||
| 15 | - * @author 芋道源码 | ||
| 16 | - */ | ||
| 17 | @Mapper | 13 | @Mapper |
| 18 | public interface ProductPropertyValueMapper extends BaseMapperX<ProductPropertyValueDO> { | 14 | public interface ProductPropertyValueMapper extends BaseMapperX<ProductPropertyValueDO> { |
| 19 | 15 | ||
| 20 | - default List<ProductPropertyValueDO> selectListByPropertyId(List<Long> propertyIds) { | 16 | + default List<ProductPropertyValueDO> selectListByPropertyId(Collection<Long> propertyIds) { |
| 21 | return selectList(new LambdaQueryWrapperX<ProductPropertyValueDO>() | 17 | return selectList(new LambdaQueryWrapperX<ProductPropertyValueDO>() |
| 22 | .inIfPresent(ProductPropertyValueDO::getPropertyId, propertyIds)); | 18 | .inIfPresent(ProductPropertyValueDO::getPropertyId, propertyIds)); |
| 23 | } | 19 | } |
| @@ -28,17 +24,20 @@ public interface ProductPropertyValueMapper extends BaseMapperX<ProductPropertyV | @@ -28,17 +24,20 @@ public interface ProductPropertyValueMapper extends BaseMapperX<ProductPropertyV | ||
| 28 | .eq(ProductPropertyValueDO::getName, name)); | 24 | .eq(ProductPropertyValueDO::getName, name)); |
| 29 | } | 25 | } |
| 30 | 26 | ||
| 31 | - default void deletePropertyValueByPropertyId(Long propertyId) { | ||
| 32 | - delete(new LambdaQueryWrapperX<ProductPropertyValueDO>().eq(ProductPropertyValueDO::getPropertyId, propertyId) | ||
| 33 | - .eq(ProductPropertyValueDO::getDeleted, false)); | 27 | + default void deleteByPropertyId(Long propertyId) { |
| 28 | + delete(new LambdaQueryWrapperX<ProductPropertyValueDO>() | ||
| 29 | + .eq(ProductPropertyValueDO::getPropertyId, propertyId)); | ||
| 34 | } | 30 | } |
| 35 | 31 | ||
| 36 | default PageResult<ProductPropertyValueDO> selectPage(ProductPropertyValuePageReqVO reqVO) { | 32 | default PageResult<ProductPropertyValueDO> selectPage(ProductPropertyValuePageReqVO reqVO) { |
| 37 | return selectPage(reqVO, new LambdaQueryWrapperX<ProductPropertyValueDO>() | 33 | return selectPage(reqVO, new LambdaQueryWrapperX<ProductPropertyValueDO>() |
| 38 | .eqIfPresent(ProductPropertyValueDO::getPropertyId, reqVO.getPropertyId()) | 34 | .eqIfPresent(ProductPropertyValueDO::getPropertyId, reqVO.getPropertyId()) |
| 39 | .likeIfPresent(ProductPropertyValueDO::getName, reqVO.getName()) | 35 | .likeIfPresent(ProductPropertyValueDO::getName, reqVO.getName()) |
| 40 | - .eqIfPresent(ProductPropertyValueDO::getStatus, reqVO.getStatus()) | ||
| 41 | .orderByDesc(ProductPropertyValueDO::getId)); | 36 | .orderByDesc(ProductPropertyValueDO::getId)); |
| 42 | } | 37 | } |
| 43 | 38 | ||
| 39 | + default Integer selectCountByPropertyId(Long propertyId) { | ||
| 40 | + return selectCount(ProductPropertyValueDO::getPropertyId, propertyId).intValue(); | ||
| 41 | + } | ||
| 42 | + | ||
| 44 | } | 43 | } |