UserService.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <?php
  2. namespace app\data\service;
  3. use think\admin\Service;
  4. /**
  5. * 用户数据接口服务
  6. * Class UserService
  7. * @package app\store\service
  8. */
  9. class UserService extends Service
  10. {
  11. const APITYPE_WAP = 'wap';
  12. const APITYPE_WEB = 'web';
  13. const APITYPE_WXAPP = 'wxapp';
  14. const APITYPE_WECHAT = 'wechat';
  15. const APITYPE_IOSAPP = 'iosapp';
  16. const APITYPE_ANDROID = 'android';
  17. const TYPES = [
  18. // 接口通道配置(不需要的直接注释)
  19. UserService::APITYPE_WAP => [
  20. 'name' => '手机浏览器',
  21. 'auth' => 'phone',
  22. ],
  23. UserService::APITYPE_WEB => [
  24. 'name' => '电脑浏览器',
  25. 'auth' => 'phone',
  26. ],
  27. UserService::APITYPE_IOSAPP => [
  28. 'name' => '苹果应用',
  29. 'auth' => 'phone',
  30. ],
  31. UserService::APITYPE_ANDROID => [
  32. 'name' => '安卓应用',
  33. 'auth' => 'phone',
  34. ],
  35. UserService::APITYPE_WXAPP => [
  36. 'name' => '微信小程序',
  37. 'auth' => 'openid1',
  38. ],
  39. UserService::APITYPE_WECHAT => [
  40. 'name' => '微信服务号',
  41. 'auth' => 'openid2',
  42. ],
  43. ];
  44. /**
  45. * 认证有效时间
  46. * @var integer
  47. */
  48. private $expire = 7200;
  49. /**
  50. * 获取用户数据
  51. * @param string $type 接口类型
  52. * @param integer $uuid 用户UID
  53. * @return array
  54. */
  55. public function get(string $type, int $uuid): array
  56. {
  57. $user = $this->app->db->name('DataUser')->where(['id' => $uuid, 'deleted' => 0])->findOrEmpty();
  58. $data = $this->app->db->name('DataUserToken')->where(['uid' => $uuid, 'type' => $type])->where(function ($query) {
  59. $query->where(['tokenv' => ''])->whereOr(['tokenv' => $this->_buildTokenVerify()]);
  60. })->findOrEmpty();
  61. $user['token'] = ['token' => $data['token'], 'expire' => $data['time']];
  62. unset($user['deleted'], $user['password']);
  63. return $user;
  64. }
  65. /**
  66. * 更新用户用户参数
  67. * @param array $map 查询条件
  68. * @param array $data 更新数据
  69. * @param string $type 接口类型
  70. * @param boolean $force 强刷令牌
  71. * @return array
  72. * @throws \think\db\exception\DbException
  73. */
  74. public function set(array $map, array $data, string $type, bool $force = false): array
  75. {
  76. unset($data['id'], $data['deleted'], $data['create_at']);
  77. if ($uuid = $this->app->db->name('DataUser')->where($map)->where(['deleted' => 0])->value('id')) {
  78. if (!empty($data)) {
  79. $map = ['id' => $uuid, 'deleted' => 0];
  80. $this->app->db->name('DataUser')->strict(false)->where($map)->update($data);
  81. }
  82. } else {
  83. $uuid = $this->app->db->name('DataUser')->strict(false)->insertGetId($data);
  84. }
  85. if ($force) $this->token(intval($uuid), $type);
  86. return $this->get($type, $uuid);
  87. }
  88. /**
  89. * 同步刷新用户余额
  90. * @param int $uuid 用户UID
  91. * @param array $nots 排除的订单
  92. * @return array [total,count]
  93. * @throws \think\db\exception\DbException
  94. */
  95. public function balance(int $uuid, array $nots = []): array
  96. {
  97. $total = $this->app->db->name('DataUserBalance')->where(['uid' => $uuid, 'deleted' => 0])->sum('amount');
  98. $total += $this->app->db->name('DataUserBalanceTransfer')->where(['uid' => $uuid, 'deleted' => 0])->sum('amount');
  99. $count = $this->app->db->name('DataUserBalanceTransfer')->where(['from' => $uuid, 'deleted' => 0])->sum('amount');
  100. if (empty($nots)) {
  101. $count += $this->app->db->name('ShopOrder')->whereRaw("uid={$uuid} and status>1")->sum('amount_balance');
  102. $this->app->db->name('DataUser')->where(['id' => $uuid])->update(['balance_total' => $total, 'balance_used' => $count]);
  103. } else {
  104. $count += $this->app->db->name('ShopOrder')->whereRaw("uid={$uuid} and status>1")->whereNotIn('order_no', $nots)->sum('amount_balance');
  105. }
  106. return [$total, $count];
  107. }
  108. /**
  109. * 检查 TOKEN 是否有效
  110. * @param string $type 接口类型
  111. * @param string $token 认证令牌
  112. * @param array $data 认证数据
  113. * @return array [ 检查状态,状态描述,用户UID, 有效时间 ]
  114. * @throws \think\db\exception\DataNotFoundException
  115. * @throws \think\db\exception\DbException
  116. * @throws \think\db\exception\ModelNotFoundException
  117. */
  118. public function check(string $type, string $token, array $data = []): array
  119. {
  120. if (empty($data)) {
  121. $map = ['type' => $type, 'token' => $token];
  122. $data = $this->app->db->name('DataUserToken')->where($map)->find();
  123. }
  124. if (empty($data) || empty($data['uid'])) {
  125. return [0, '请重新登录,登录认证无效', 0, 0];
  126. } elseif ($data['time'] < time()) {
  127. return [0, '请重新登录,登录认证失效', 0, 0];
  128. } elseif ($token !== 'token' && $data['tokenv'] !== $this->_buildTokenVerify()) {
  129. return [0, '请重新登录,客户端已更换', 0, 0];
  130. } else {
  131. $this->expire($type, $token);
  132. return [1, '登录验证成功', $data['uid'], $data['time']];
  133. }
  134. }
  135. /**
  136. * 延期 TOKEN 有效时间
  137. * @param string $type 接口类型
  138. * @param string $token 授权令牌
  139. * @throws \think\db\exception\DbException
  140. */
  141. public function expire(string $type, string $token)
  142. {
  143. $map = ['type' => $type, 'token' => $token];
  144. $this->app->db->name('DataUserToken')->where($map)->update([
  145. 'time' => time() + $this->expire,
  146. ]);
  147. }
  148. /**
  149. * 列表绑定用户数据
  150. * @param array $list 原数据列表
  151. * @param string $keys 用户UID字段
  152. * @param string $bind 绑定字段名称
  153. * @param string $column 返回用户字段
  154. * @return array
  155. */
  156. public function buildByUid(array &$list, string $keys = 'uid', string $bind = 'user', string $column = '*'): array
  157. {
  158. if (count($list) < 1) return $list;
  159. $uids = array_unique(array_column($list, $keys));
  160. $users = $this->app->db->name('DataUser')->whereIn('id', $uids)->column($column, 'id');
  161. foreach ($list as &$vo) $vo[$bind] = $users[$vo[$keys]] ?? [];
  162. return $list;
  163. }
  164. /**
  165. * 获取用户数据统计
  166. * @param int $uuid 用户UID
  167. * @return array
  168. */
  169. public function total(int $uuid): array
  170. {
  171. $query = $this->app->db->name('DataUser');
  172. return ['my_invite' => $query->where(['from' => $uuid])->count()];
  173. }
  174. /**
  175. * 生成新的用户令牌
  176. * @param int $uuid 授权用户
  177. * @param string $type 接口类型
  178. * @return array [创建状态, 状态描述, 令牌数据]
  179. * @throws \think\db\exception\DbException
  180. */
  181. public function token(int $uuid, string $type): array
  182. {
  183. // 清理无效认证数据
  184. $map1 = [['time', '<', $time = time()]];
  185. $map2 = [['uid', '=', $uuid], ['type', '=', $type]];
  186. $this->app->db->name('DataUserToken')->whereOr([$map1, $map2])->delete();
  187. // 创建新的认证数据
  188. do $map = ['type' => $type, 'token' => md5(uniqid() . rand(100, 999))];
  189. while ($this->app->db->name('DataUserToken')->where($map)->count() > 0);
  190. // 写入用户认证数据
  191. $data = array_merge($map, ['uid' => $uuid, 'time' => $time + $this->expire, 'tokenv' => $this->_buildTokenVerify()]);
  192. if ($this->app->db->name('DataUserToken')->insert($data) !== false) {
  193. return [1, '刷新认证成功', $data];
  194. } else {
  195. return [0, '刷新认证失败', []];
  196. }
  197. }
  198. /**
  199. * 获取令牌的认证值
  200. * @return string
  201. */
  202. private function _buildTokenVerify(): string
  203. {
  204. return md5($this->app->request->server('HTTP_USER_AGENT', '-'));
  205. }
  206. }