Region.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <?php
  2. /**
  3. *
  4. * @copyright ©2020 点小铺
  5. * @author hanj
  6. * @link: https://dyuit.com
  7. * Created by VSCode
  8. */
  9. namespace app\common\model;
  10. use think\Cache;
  11. use app\common\library\helper;
  12. /**
  13. * 地区模型
  14. * Class Region
  15. * @package app\common\model
  16. */
  17. class Region extends BaseModel
  18. {
  19. protected $name = 'region';
  20. protected $createTime = false;
  21. protected $updateTime = false;
  22. /**
  23. * 类型自动转换
  24. * @var array
  25. */
  26. protected $type = [
  27. 'id' => 'integer',
  28. 'pid' => 'integer',
  29. 'level' => 'integer',
  30. ];
  31. // 当前数据版本号
  32. private static $version = '1.2.3';
  33. // 县级市别名 (兼容微信端命名)
  34. private static $county = [
  35. '省直辖县级行政区划',
  36. '自治区直辖县级行政区划',
  37. ];
  38. /**
  39. * 根据id获取地区名称
  40. * @param $id
  41. * @return string
  42. */
  43. public static function getNameById($id)
  44. {
  45. return $id > 0 ? self::getCacheAll()[$id]['name'] : '其他';
  46. }
  47. /**
  48. * 根据名称获取地区id
  49. * @param $name
  50. * @param int $level
  51. * @param int $pid
  52. * @return mixed
  53. */
  54. public static function getIdByName($name, $level = 0, $pid = 0)
  55. {
  56. // 兼容:微信端"省直辖县级行政区划"
  57. if (in_array($name, static::$county)) {
  58. $name = '直辖县级';
  59. }
  60. $data = self::getCacheAll();
  61. foreach ($data as $item) {
  62. if ($item['name'] == $name && $item['level'] == $level && $item['pid'] == $pid)
  63. return $item['id'];
  64. }
  65. return 0;
  66. }
  67. /**
  68. * 获取所有地区(树状结构)
  69. * @return mixed
  70. */
  71. public static function getCacheTree()
  72. {
  73. return static::getCacheData('tree');
  74. }
  75. /**
  76. * 获取所有地区列表
  77. * @return mixed
  78. */
  79. public static function getCacheAll()
  80. {
  81. return static::getCacheData('all');
  82. }
  83. /**
  84. * 获取所有地区的总数
  85. * @return mixed
  86. */
  87. public static function getCacheCounts()
  88. {
  89. return static::getCacheData('counts');
  90. }
  91. /**
  92. * 获取缓存中的数据(存入静态变量)
  93. * @param null $item
  94. * @return array|mixed
  95. */
  96. private static function getCacheData($item = null)
  97. {
  98. static $cacheData = [];
  99. if (empty($cacheData)) {
  100. $static = new static;
  101. $cacheData = $static->regionCache();
  102. }
  103. if (is_null($item)) {
  104. return $cacheData;
  105. }
  106. return $cacheData[$item];
  107. }
  108. /**
  109. * 获取地区缓存
  110. * @return array|mixed
  111. * @throws \think\db\exception\DataNotFoundException
  112. * @throws \think\db\exception\ModelNotFoundException
  113. * @throws \think\exception\DbException
  114. */
  115. private function regionCache()
  116. {
  117. // 缓存的数据
  118. $complete = Cache::get('region');
  119. // 如果存在缓存则返回缓存的数据,否则从数据库中查询
  120. // 条件1: 获取缓存数据
  121. // 条件2: 数据版本号要与当前一致
  122. if (
  123. !empty($complete)
  124. && isset($complete['version'])
  125. && $complete['version'] == self::$version
  126. ) {
  127. return $complete;
  128. }
  129. // 所有地区
  130. $allList = $tempList = $this->getAllList();
  131. // 已完成的数据
  132. $complete = [
  133. 'all' => $allList,
  134. 'tree' => $this->getTreeList($allList),
  135. 'counts' => $this->getCount($allList),
  136. 'version' => self::$version,
  137. ];
  138. // 写入缓存
  139. Cache::tag('cache')->set('region', $complete);
  140. return $complete;
  141. }
  142. private static function getCount($allList)
  143. {
  144. $counts = [
  145. 'total' => count($allList),
  146. 'province' => 0,
  147. 'city' => 0,
  148. 'region' => 0,
  149. ];
  150. $level = [1 => 'province', 2 => 'city', 3 => 'region'];
  151. foreach ($allList as $item) {
  152. $counts[$level[$item['level']]]++;
  153. }
  154. return $counts;
  155. }
  156. /**
  157. * 格式化为树状格式
  158. * @param $allList
  159. * @return array
  160. */
  161. private function getTreeList($allList)
  162. {
  163. $treeList = [];
  164. foreach ($allList as $pKey => $province) {
  165. if ($province['level'] == 1) { // 省份
  166. $treeList[$province['id']] = $province;
  167. unset($allList[$pKey]);
  168. foreach ($allList as $cKey => $city) {
  169. if ($city['level'] == 2 && $city['pid'] == $province['id']) { // 城市
  170. $treeList[$province['id']]['city'][$city['id']] = $city;
  171. unset($allList[$cKey]);
  172. foreach ($allList as $rKey => $region) {
  173. if ($region['level'] == 3 && $region['pid'] == $city['id']) { // 地区
  174. $treeList[$province['id']]['city'][$city['id']]['region'][$region['id']] = $region;
  175. unset($allList[$rKey]);
  176. }
  177. }
  178. }
  179. }
  180. }
  181. }
  182. return $treeList;
  183. }
  184. /**
  185. * 从数据库中获取所有地区
  186. * @return array
  187. * @throws \think\db\exception\DataNotFoundException
  188. * @throws \think\db\exception\ModelNotFoundException
  189. * @throws \think\exception\DbException
  190. */
  191. private function getAllList()
  192. {
  193. $list = self::useGlobalScope(false)
  194. ->field('id, pid, name, level')
  195. ->select()
  196. ->toArray();
  197. return helper::arrayColumn2Key($list, 'id');
  198. }
  199. }