AccountConfig.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. <?php
  2. /**
  3. * 提现账户配置控制器(客户银行卡配置)
  4. */
  5. namespace app\admin\controller\pay;
  6. use app\common\controller\Backend;
  7. use think\facade\Db;
  8. class AccountConfig extends Backend
  9. {
  10. protected array $noNeedLogin = ['*'];
  11. /**
  12. * 提现账户列表
  13. * @return void
  14. */
  15. public function index(): void
  16. {
  17. $where = [];
  18. // 用户ID搜索
  19. if (!empty($this->request->get('user_id'))) {
  20. $where['wac.user_id'] = $this->request->get('user_id');
  21. }
  22. // 账户类型筛选
  23. if (!empty($this->request->get('account_type'))) {
  24. $where['wac.account_type'] = $this->request->get('account_type');
  25. }
  26. // 银行名称搜索
  27. if (!empty($this->request->get('bank_name'))) {
  28. $where[] = ['wac.bank_name', 'like', '%' . $this->request->get('bank_name') . '%'];
  29. }
  30. // 账户姓名搜索
  31. if (!empty($this->request->get('account_name'))) {
  32. $where[] = ['wac.account_name', 'like', '%' . $this->request->get('account_name') . '%'];
  33. }
  34. // 状态筛选
  35. if ($this->request->get('status') !== '' && $this->request->get('status') !== null) {
  36. $where['wac.status'] = $this->request->get('status');
  37. }
  38. // 排序
  39. $order = [];
  40. if (!empty($this->request->get('order'))) {
  41. $order_a = $this->request->get('order');
  42. $order_a = explode(',', $order_a);
  43. $order[$order_a[0]] = $order_a[1];
  44. } else {
  45. $order['wac.create_time'] = 'desc';
  46. }
  47. // 分页
  48. $page = $this->request->get('page', 1);
  49. $limit = $this->request->get('limit', 20);
  50. // 查询数据
  51. $accountList = Db::name('withdrawal_account_config')
  52. ->alias('wac')
  53. ->leftJoin('user_on u', 'wac.user_id = u.id')
  54. ->field('
  55. wac.id,
  56. wac.user_id,
  57. u.name as user_name,
  58. wac.account_type,
  59. wac.account_name,
  60. wac.bank_name,
  61. wac.bank_branch,
  62. wac.bank_province,
  63. wac.bank_city,
  64. wac.card_number,
  65. wac.alipay_account,
  66. wac.wechat_account,
  67. wac.is_default,
  68. wac.status,
  69. wac.remark,
  70. wac.create_time,
  71. wac.update_time
  72. ')
  73. ->where($where)
  74. ->order($order)
  75. ->paginate([
  76. 'list_rows' => $limit,
  77. 'page' => $page
  78. ]);
  79. $list = $accountList->items();
  80. foreach ($list as &$item) {
  81. // 添加账户类型文本
  82. $item['account_type_text'] = $this->getAccountTypeText($item['account_type']);
  83. // 添加状态文本
  84. $item['status_text'] = $item['status'] ? '启用' : '禁用';
  85. // 添加默认账户文本
  86. $item['is_default_text'] = $item['is_default'] ? '是' : '否';
  87. // 部分掩码显示(保护隐私)
  88. if ($item['card_number']) {
  89. $item['card_number_masked'] = substr($item['card_number'], 0, 4) . '****' . substr($item['card_number'], -4);
  90. }
  91. if ($item['alipay_account']) {
  92. // 支付宝邮箱掩码
  93. if (strpos($item['alipay_account'], '@') !== false) {
  94. list($prefix, $domain) = explode('@', $item['alipay_account']);
  95. if (strlen($prefix) > 3) {
  96. $item['alipay_account_masked'] = substr($prefix, 0, 3) . '***@' . $domain;
  97. } else {
  98. $item['alipay_account_masked'] = $prefix . '***@' . $domain;
  99. }
  100. } else {
  101. $item['alipay_account_masked'] = substr($item['alipay_account'], 0, 3) . '***';
  102. }
  103. }
  104. }
  105. $this->success('查询成功', [
  106. 'list' => $list,
  107. 'total' => $accountList->total()
  108. ]);
  109. }
  110. /**
  111. * 获取账户详情
  112. * @return void
  113. */
  114. public function detail(): void
  115. {
  116. $id = $this->request->get('id');
  117. if (empty($id)) {
  118. $this->error(__('参数错误'));
  119. }
  120. $account = Db::name('withdrawal_account_config')
  121. ->alias('wac')
  122. ->leftJoin('user_on u', 'wac.user_id = u.id')
  123. ->where('wac.id', $id)
  124. ->field('wac.*, u.name as user_name')
  125. ->find();
  126. if (!$account) {
  127. $this->error(__('账户不存在'));
  128. }
  129. // 添加账户类型文本
  130. $account['account_type_text'] = $this->getAccountTypeText($account['account_type']);
  131. $this->success('查询成功', $account);
  132. }
  133. /**
  134. * 新增/编辑提现账户
  135. * @return void
  136. */
  137. public function edit(): void
  138. {
  139. $id = $this->request->post('id');
  140. $userId = $this->request->post('user_id');
  141. $accountType = $this->request->post('account_type');
  142. $accountName = $this->request->post('account_name');
  143. $isDefault = $this->request->post('is_default', 0);
  144. $status = $this->request->post('status', 1);
  145. $remark = $this->request->post('remark', '');
  146. // 根据账户类型接收不同的字段
  147. $bankName = $this->request->post('bank_name', '');
  148. $bankBranch = $this->request->post('bank_branch', '');
  149. $bankProvince = $this->request->post('bank_province', '');
  150. $bankCity = $this->request->post('bank_city', '');
  151. $cardNumber = $this->request->post('card_number', '');
  152. $alipayAccount = $this->request->post('alipay_account', '');
  153. $wechatAccount = $this->request->post('wechat_account', '');
  154. if (empty($userId)) {
  155. $this->error(__('用户ID不能为空'));
  156. }
  157. if (empty($accountType)) {
  158. $this->error(__('请选择账户类型'));
  159. }
  160. if (empty($accountName)) {
  161. $this->error(__('账户姓名不能为空'));
  162. }
  163. // 验证用户是否存在
  164. $userInfo = Db::name('user')
  165. ->where('id', $userId)
  166. ->find();
  167. if (!$userInfo) {
  168. $this->error(__('用户不存在'));
  169. }
  170. // 验证账户类型对应的必填字段
  171. $validationResult = $this->validateAccountFields($accountType, [
  172. 'bank_name' => $bankName,
  173. 'card_number' => $cardNumber,
  174. 'alipay_account' => $alipayAccount,
  175. 'wechat_account' => $wechatAccount
  176. ]);
  177. if ($validationResult !== true) {
  178. $this->error($validationResult);
  179. }
  180. // 验证银行卡号格式(如果是银行卡)
  181. if ($accountType == 'bank' && !empty($cardNumber)) {
  182. if (!preg_match('/^[0-9]{16,19}$/', $cardNumber)) {
  183. $this->error(__('银行卡号格式不正确,应为16-19位数字'));
  184. }
  185. }
  186. // 验证支付宝账号格式
  187. if ($accountType == 'alipay' && !empty($alipayAccount)) {
  188. if (!filter_var($alipayAccount, FILTER_VALIDATE_EMAIL) && !preg_match('/^1[3-9]\d{9}$/', $alipayAccount)) {
  189. $this->error(__('支付宝账号应为邮箱或手机号格式'));
  190. }
  191. }
  192. $data = [
  193. 'user_id' => $userId,
  194. 'account_type' => $accountType,
  195. 'account_name' => $accountName,
  196. 'bank_name' => $accountType == 'bank' ? $bankName : '',
  197. 'bank_branch' => $accountType == 'bank' ? $bankBranch : '',
  198. 'bank_province' => $accountType == 'bank' ? $bankProvince : '',
  199. 'bank_city' => $accountType == 'bank' ? $bankCity : '',
  200. 'card_number' => $accountType == 'bank' ? $cardNumber : '',
  201. 'alipay_account' => $accountType == 'alipay' ? $alipayAccount : '',
  202. 'wechat_account' => $accountType == 'wechat' ? $wechatAccount : '',
  203. 'is_default' => $isDefault,
  204. 'status' => $status,
  205. 'remark' => $remark,
  206. 'update_time' => date('Y-m-d H:i:s')
  207. ];
  208. try {
  209. if (!empty($id)) {
  210. // 编辑
  211. $accountInfo = Db::name('withdrawal_account_config')
  212. ->where('id', $id)
  213. ->find();
  214. if (!$accountInfo) {
  215. $this->error(__('账户不存在'));
  216. }
  217. // 如果设置为默认账户,需要取消该用户的其他默认账户
  218. if ($isDefault == 1) {
  219. Db::name('withdrawal_account_config')
  220. ->where('user_id', $userId)
  221. ->where('id', '<>', $id)
  222. ->where('account_type', $accountType)
  223. ->update(['is_default' => 0]);
  224. }
  225. $result = Db::name('withdrawal_account_config')
  226. ->where('id', $id)
  227. ->update($data);
  228. $message = '编辑成功';
  229. } else {
  230. // 新增
  231. $data['create_time'] = date('Y-m-d H:i:s');
  232. // 检查是否已存在相同账户
  233. $existCheck = Db::name('withdrawal_account_config')
  234. ->where('user_id', $userId)
  235. ->where('account_type', $accountType);
  236. if ($accountType == 'bank') {
  237. $existCheck->where('card_number', $cardNumber);
  238. } elseif ($accountType == 'alipay') {
  239. $existCheck->where('alipay_account', $alipayAccount);
  240. } elseif ($accountType == 'wechat') {
  241. $existCheck->where('wechat_account', $wechatAccount);
  242. }
  243. if ($existCheck->find()) {
  244. throw new \Exception('该账户已存在');
  245. }
  246. // 如果设置为默认账户,需要取消该用户的其他默认账户
  247. if ($isDefault == 1) {
  248. Db::name('withdrawal_account_config')
  249. ->where('user_id', $userId)
  250. ->where('account_type', $accountType)
  251. ->update(['is_default' => 0]);
  252. }
  253. $result = Db::name('withdrawal_account_config')
  254. ->insert($data);
  255. $id = Db::name('withdrawal_account_config')->getLastInsID();
  256. $message = '新增成功';
  257. }
  258. } catch (\Exception $e) {
  259. $this->error('操作失败: ' . $e->getMessage());
  260. }
  261. if ($result) {
  262. $this->success($message, ['id' => $id]);
  263. } else {
  264. $this->error(__('操作失败'));
  265. }
  266. }
  267. /**
  268. * 删除提现账户
  269. * @return void
  270. */
  271. public function delete(): void
  272. {
  273. $id = $this->request->post('id');
  274. if (empty($id)) {
  275. $this->error(__('参数错误'));
  276. }
  277. $accountInfo = Db::name('withdrawal_account_config')
  278. ->where('id', $id)
  279. ->find();
  280. if (!$accountInfo) {
  281. $this->error(__('账户不存在'));
  282. }
  283. // 检查是否正在使用(如果有提现记录)
  284. $hasWithdrawal = Db::name('withdrawal_record')
  285. ->where('account_info', 'like', '%' . $accountInfo['card_number'] . '%')
  286. // ->whereOr('account_info', 'like', '%' . $accountInfo['alipay_account'] . '%')
  287. // ->whereOr('account_info', 'like', '%' . $accountInfo['wechat_account'] . '%')
  288. ->find();
  289. if ($hasWithdrawal) {
  290. $this->error(__('该账户已有提现记录,不能删除'));
  291. }
  292. $result = Db::name('withdrawal_account_config')
  293. ->where('id', $id)
  294. ->delete();
  295. if ($result) {
  296. $this->success('删除成功');
  297. } else {
  298. $this->error(__('删除失败'));
  299. }
  300. }
  301. /**
  302. * 设置默认账户
  303. * @return void
  304. */
  305. public function setDefault(): void
  306. {
  307. $id = $this->request->post('id');
  308. if (empty($id)) {
  309. $this->error(__('参数错误'));
  310. }
  311. $accountInfo = Db::name('withdrawal_account_config')
  312. ->where('id', $id)
  313. ->find();
  314. if (!$accountInfo) {
  315. $this->error(__('账户不存在'));
  316. }
  317. try {
  318. // 取消该用户同类型账户的其他默认设置
  319. Db::name('withdrawal_account_config')
  320. ->where('user_id', $accountInfo['user_id'])
  321. ->where('account_type', $accountInfo['account_type'])
  322. ->where('id', '<>', $id)
  323. ->update(['is_default' => 0]);
  324. // 设置当前账户为默认
  325. $result = Db::name('withdrawal_account_config')
  326. ->where('id', $id)
  327. ->update([
  328. 'is_default' => 1,
  329. 'update_time' => date('Y-m-d H:i:s')
  330. ]);
  331. if ($result) {
  332. $this->success('设置默认成功');
  333. } else {
  334. $this->error(__('设置失败'));
  335. }
  336. } catch (\Exception $e) {
  337. $this->error('操作失败: ' . $e->getMessage());
  338. }
  339. }
  340. /**
  341. * 获取用户的提现账户列表
  342. * @return void
  343. */
  344. public function getUserAccounts(): void
  345. {
  346. $userId = $this->request->get('user_id');
  347. if (empty($userId)) {
  348. $this->error(__('用户ID不能为空'));
  349. }
  350. $accounts = Db::name('withdrawal_account_config')
  351. ->where('user_id', $userId)
  352. ->where('status', 1)
  353. ->order('is_default', 'desc')
  354. ->order('create_time', 'desc')
  355. ->select()
  356. ->toArray();
  357. foreach ($accounts as &$account) {
  358. // 添加账户类型文本
  359. $account['account_type_text'] = $this->getAccountTypeText($account['account_type']);
  360. // 部分掩码显示
  361. if ($account['card_number']) {
  362. $account['card_number_masked'] = substr($account['card_number'], 0, 4) . '****' . substr($account['card_number'], -4);
  363. }
  364. }
  365. $this->success('查询成功', $accounts);
  366. }
  367. /**
  368. * 验证账户字段
  369. * @param string $accountType 账户类型
  370. * @param array $fields 字段值
  371. * @return bool|string
  372. */
  373. private function validateAccountFields(string $accountType, array $fields): bool|string
  374. {
  375. if ($accountType == 'bank') {
  376. if (empty($fields['bank_name'])) {
  377. return '银行名称不能为空';
  378. }
  379. if (empty($fields['card_number'])) {
  380. return '银行卡号不能为空';
  381. }
  382. } elseif ($accountType == 'alipay') {
  383. if (empty($fields['alipay_account'])) {
  384. return '支付宝账号不能为空';
  385. }
  386. } elseif ($accountType == 'wechat') {
  387. if (empty($fields['wechat_account'])) {
  388. return '微信账号不能为空';
  389. }
  390. }
  391. return true;
  392. }
  393. /**
  394. * 获取账户类型文本
  395. * @param string $type
  396. * @return string
  397. */
  398. private function getAccountTypeText(string $type): string
  399. {
  400. $map = [
  401. 'bank' => '银行卡',
  402. 'alipay' => '支付宝',
  403. 'wechat' => '微信'
  404. ];
  405. return $map[$type] ?? '未知类型';
  406. }
  407. /**
  408. * 获取账户类型选项
  409. * @return void
  410. */
  411. public function accountTypeOptions(): void
  412. {
  413. $options = [
  414. ['value' => 'bank', 'label' => '银行卡'],
  415. ['value' => 'alipay', 'label' => '支付宝'],
  416. ['value' => 'wechat', 'label' => '微信']
  417. ];
  418. $this->success('获取成功', $options);
  419. }
  420. /**
  421. * 获取状态选项
  422. * @return void
  423. */
  424. public function statusOptions(): void
  425. {
  426. $options = [
  427. ['value' => 0, 'label' => '禁用'],
  428. ['value' => 1, 'label' => '启用']
  429. ];
  430. $this->success('获取成功', $options);
  431. }
  432. /**
  433. * 获取银行列表(常见银行)
  434. * @return void
  435. */
  436. public function bankList(): void
  437. {
  438. $banks = [
  439. '中国工商银行',
  440. '中国农业银行',
  441. '中国银行',
  442. '中国建设银行',
  443. '交通银行',
  444. '招商银行',
  445. '中信银行',
  446. '中国民生银行',
  447. '中国光大银行',
  448. '华夏银行',
  449. '兴业银行',
  450. '浦发银行',
  451. '平安银行',
  452. '广发银行',
  453. '邮政储蓄银行'
  454. ];
  455. $options = [];
  456. foreach ($banks as $bank) {
  457. $options[] = ['value' => $bank, 'label' => $bank];
  458. }
  459. $this->success('获取成功', $options);
  460. }
  461. }