RegionStatistics.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. <?php
  2. namespace common\models\statistics;
  3. use common\models\base\BaseActiveRecord;
  4. use common\enums\RedisKeyEnum;
  5. use common\models\common\Region;
  6. use yii\db\Expression;
  7. use Yii;
  8. use yii\redis\Connection;
  9. use function GuzzleHttp\json_decode;
  10. /**
  11. *
  12. * This is the model class for table "{{%region_statistics}}".
  13. * @property int $id 记录ID
  14. * @property int $mall_id 商城ID
  15. * @property int $province_id 省份编号
  16. * @property int $city_id 城市编号
  17. * @property int $pay_num 支付数
  18. * @property int $order_num 下单数
  19. * @property float $order_money 下单金额
  20. * @property float $pay_money 支付金额
  21. */
  22. class RegionStatistics extends BaseActiveRecord
  23. {
  24. public static $regionData = [];
  25. public static $provinceIds = [];
  26. public static $provinceName =[];
  27. public static $provinceStatistics = [];
  28. /**
  29. * {@inheritdoc}
  30. */
  31. public static function tableName() {
  32. return '{{%region_statistics}}';
  33. }
  34. /**
  35. * {@inheritdoc}
  36. */
  37. public function rules()
  38. {
  39. return [
  40. [['mall_id'], 'required'],
  41. [['mall_id', 'order_num', 'pay_num', 'province_id', 'city_id'], 'integer'],
  42. [['order_money', 'pay_money'],'number']
  43. ];
  44. }
  45. /**
  46. * {@inheritdoc}
  47. */
  48. public function attributeLabels()
  49. {
  50. return [
  51. 'id' => 'ID',
  52. 'mall_id' => '商城id',
  53. 'province_id' => '省份编号',
  54. 'city_id' => '城市编号',
  55. 'pay_num' => '支付量',
  56. 'order_num' => '订单量',
  57. 'order_money' => '下单金额',
  58. 'pay_money' => '支付金额'
  59. ];
  60. }
  61. public function behaviors() {
  62. return [];
  63. }
  64. /**
  65. * 区域订单统计
  66. *
  67. * @param int mall_id 商城ID
  68. * @author hpei
  69. * @return array
  70. */
  71. public static function getData($mall_id) {
  72. try {
  73. self::getDefaultRegion($mall_id);
  74. $redis = \Yii::$app->redis;
  75. $cacheKey = RedisKeyEnum::suffix(RedisKeyEnum::REGION_STATISTICS, 'mall_id_' . $mall_id);
  76. $regionStatistics = $redis->get($cacheKey);
  77. if (!$regionStatistics) {
  78. $regionStatistics = self::createCacheData($mall_id);
  79. self::setCache($mall_id, $regionStatistics);
  80. } else {
  81. $regionStatistics = json_decode($regionStatistics, true);
  82. }
  83. return self::setProvinceName($regionStatistics);
  84. } catch (\Exception $e) {
  85. Yii::error('读取地区统计缓存异常:' . $e->getMessage());
  86. return empty(self::$provinceStatistics) ? [] : self::setProvinceName(self::$provinceStatistics);
  87. }
  88. }
  89. /**
  90. * 添加统计
  91. *
  92. * @param array data [mall_id=>mall_id,city_id=>city_id,province_id=>province_id,order=>money|pay=>money]
  93. * @author hpei
  94. * @return bool
  95. */
  96. public static function saveData($data) {
  97. try {
  98. $mall_id = $data['mall_id'];
  99. $city_id = $data['city_id'];
  100. $province_id = $data['province_id'];
  101. if (!$mall_id || !$city_id || !$province_id) {
  102. // self::$static_error = 'mall_id city_id province_id 为空';
  103. // return false;
  104. return true;
  105. }
  106. self::getDefaultRegion($mall_id);
  107. $region = self::getOne([['=','mall_id', $mall_id], ['=', 'city_id', $city_id]]);
  108. $config = \Yii::$app->getComponents()['redis'];
  109. unset($config['class']);
  110. $redis = new Connection($config);
  111. $cacheKey = RedisKeyEnum::suffix(RedisKeyEnum::REGION_STATISTICS, 'mall_id_' . $mall_id);
  112. $regionStatistics = $redis->get($cacheKey);
  113. $order_money = (isset($data['order']) && !empty($data['order'])) ? $data['order'] : 0;
  114. $order_num = (isset($data['order']) && !empty($data['order'])) ? 1 : 0;
  115. $pay_money = (isset($data['pay']) && !empty($data['pay'])) ? $data['pay'] : 0;
  116. $pay_num = (isset($data['pay']) && !empty($data['pay'])) ? 1 : 0;
  117. if (!empty($region)) {
  118. $region->order_money += $order_money;
  119. $region->order_num += $order_num;
  120. $region->pay_money += $pay_money;
  121. $region->pay_num += $pay_num;
  122. $region->save();
  123. } else {
  124. $regionData = array_column(self::$regionData, null, 'city_id');
  125. $regionData[$city_id]['order_money'] = $order_money;
  126. $regionData[$city_id]['order_num'] = $order_num;
  127. $regionData[$city_id]['pay_money'] = $pay_money;
  128. $regionData[$city_id]['pay_num'] = $pay_num;
  129. Yii::$app->db->createCommand()->batchInsert(self::tableName(), ['mall_id', 'province_id', 'city_id', 'order_money', 'order_num', 'pay_money', 'pay_num'], $regionData)->execute();
  130. }
  131. //有缓存在缓存上递增数据,没有缓存读取数据库
  132. if (!empty($regionStatistics)) {
  133. $regionStatistics = json_decode($regionStatistics, true);
  134. $regionStatistics = array_column($regionStatistics, null, 'province_id');
  135. if(!empty($regionStatistics[$province_id]['order_money'])){
  136. $regionStatistics[$province_id]['order_money'] += $order_money;
  137. }else{
  138. $regionStatistics[$province_id]['order_money'] = $order_money;
  139. }
  140. if(!empty($regionStatistics[$province_id]['order_num'])){
  141. $regionStatistics[$province_id]['order_num'] += $order_num;
  142. }else{
  143. $regionStatistics[$province_id]['order_num'] = $order_num;
  144. }
  145. if(!empty($regionStatistics[$province_id]['pay_money'])){
  146. $regionStatistics[$province_id]['pay_money'] += $pay_money;
  147. }else{
  148. $regionStatistics[$province_id]['pay_money'] = $pay_money;
  149. }
  150. if(!empty($regionStatistics[$province_id]['pay_num'])){
  151. $regionStatistics[$province_id]['pay_num'] += $pay_num;
  152. }else{
  153. $regionStatistics[$province_id]['pay_num'] = $pay_num;
  154. }
  155. } else {
  156. $regionStatistics = self::getProvinceStatistics($mall_id);
  157. }
  158. self::setCache($mall_id, array_values($regionStatistics));
  159. return true;
  160. } catch (\Exception $e) {
  161. self::$static_error = $e->getMessage().$e->getFile().$e->getLine();
  162. return false;
  163. }
  164. }
  165. /**
  166. * 设置缓存
  167. *
  168. * @param int mall_id
  169. * @param array|string|int $regionStatistics
  170. * @return bool
  171. */
  172. public static function setCache($mall_id, $regionStatistics) {
  173. $config = \Yii::$app->getComponents()['redis'];
  174. unset($config['class']);
  175. $redis = new Connection($config);
  176. try {
  177. $cacheKey = RedisKeyEnum::suffix(RedisKeyEnum::REGION_STATISTICS, 'mall_id_' . $mall_id);
  178. $redis->del($cacheKey);
  179. if (is_array($regionStatistics)) {
  180. $redis->set($cacheKey, json_encode($regionStatistics, JSON_UNESCAPED_UNICODE));
  181. } else {
  182. }
  183. $redis->close();
  184. } catch (\Exception $e) {
  185. Yii::error('设置区域统计缓存异常:'.$e->getMessage());
  186. $redis->close();
  187. }
  188. }
  189. /**
  190. * 生成缓存数据 如果数据库没有数据则入库
  191. */
  192. public static function createCacheData($mall_id) {
  193. try {
  194. $regionStatistics = self::find()
  195. ->where(['mall_id' => $mall_id])
  196. ->andWhere(['in', 'province_id', self::$provinceIds])
  197. ->select(['province_id', 'pay_money'])->groupBy('province_id')->asArray()->all();
  198. //如果不存在给默认值,并把默认值入库
  199. if (empty($regionStatistics)) {
  200. $regionStatistics = self::$provinceStatistics;
  201. Yii::$app->db->createCommand()->batchInsert(self::tableName(), ['mall_id', 'province_id', 'city_id', 'order_money', 'order_num', 'pay_money', 'pay_num'], self::$regionData)->execute();
  202. }
  203. return $regionStatistics;
  204. } catch (\Exception $e) {
  205. throw new \Exception('地区缓存。生成缓存数据' . $e->getMessage() . ',行数:' . $e->getLine());
  206. }
  207. }
  208. /**
  209. * 设置默认区域
  210. *
  211. * @param array regionData 入库的数据
  212. * @param array provinceIds 省份ID
  213. * @param array provinceStatistics 展示的默认数据
  214. * @return void
  215. */
  216. public static function getDefaultRegion($mall_id) {
  217. $regionList = Region::find()
  218. ->where(['level' => [1, 2]])
  219. ->select(['name', 'id', 'level', 'parent_id', new Expression('0 as pay_money')])
  220. ->asArray()->all();
  221. $name = [];
  222. $regionData = [];
  223. $provinceIds = [];
  224. $provinceStatistics = [];
  225. array_walk($regionList, function($region) use(&$provinceIds, &$provinceStatistics, &$regionData, &$name, $mall_id) {
  226. if ($region['level'] == 2) {
  227. $regionData[] = [
  228. 'mall_id' => $mall_id,
  229. 'province_id' => $region['parent_id'],
  230. 'city_id' => $region['id'],
  231. 'order_money' => 0,
  232. 'order_num' => 0,
  233. 'pay_money' => 0,
  234. 'pay_num' => 0];
  235. }
  236. if ($region['level'] == 1) {
  237. $provinceIds[] = $region['id'];
  238. $name[$region['id']] = $region['name'];
  239. $region['province_id'] = $region['id'];
  240. unset($region['level'], $region['parent_id'], $region['name'], $region['id']);
  241. $provinceStatistics[] = $region;
  242. }
  243. });
  244. self::$provinceName = $name;
  245. self::$regionData = $regionData;
  246. self::$provinceIds = $provinceIds;
  247. self::$provinceStatistics = $provinceStatistics;
  248. }
  249. /**
  250. * 统计数据添加省份名称
  251. *
  252. * @param array provinceStatistics
  253. */
  254. public static function setProvinceName($provinceStatistics) {
  255. $provinceName = self::$provinceName;
  256. array_walk($provinceStatistics, function(&$region) use($provinceName) {
  257. $region['name'] = $provinceName[$region['province_id']]??'';
  258. });
  259. return $provinceStatistics;
  260. }
  261. /**
  262. *
  263. */
  264. public static function getProvinceStatistics($mall_id) {
  265. return self::find()->where(['mall_id' => $mall_id])
  266. ->select(['province_id', 'sum(pay_money) pay_money'])
  267. ->groupBy('province_id')->asArray()->all();
  268. }
  269. /**
  270. * 重新设置缓存
  271. */
  272. public static function resetCache($mall_id) {
  273. try {
  274. self::getDefaultRegion($mall_id);
  275. $regionStatistics = self::createCacheData($mall_id);
  276. self::setCache($mall_id, $regionStatistics);
  277. } catch (\Exception $e) {
  278. throw new \Exception($e->getMessage());
  279. }
  280. }
  281. }