migrate_rental_user_member_fields.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. <?php
  2. require dirname(__DIR__).'/vendor/autoload.php';
  3. \Dotenv\Dotenv::createUnsafeMutable(dirname(__DIR__))->load();
  4. \support\App::loadAllConfig(['route']);
  5. use support\think\Db;
  6. /**
  7. * 会员开通/续费后台能力:sa_rental_user 加 member_expire_at/member_card_type 字段 + 回填。
  8. * 配合 20261009_add_rental_user_member_fields.sql 与 20261009_add_member_activation_button_permission.sql。
  9. * 可重复执行。
  10. */
  11. if (!in_array('--apply', $argv, true)) {
  12. echo "Plan: add sa_rental_user.member_expire_at / member_card_type + backfill from sa_member_activation_record + insert UserList button menu.\n";
  13. echo "Run with --apply to execute.\n";
  14. exit;
  15. }
  16. $db = Db::connect();
  17. $dbName = $db->getConfig('database');
  18. // 1) ALTER TABLE sa_rental_user
  19. $hasExpireAt = (int) $db->scalar(
  20. "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=? AND TABLE_NAME='sa_rental_user' AND COLUMN_NAME='member_expire_at'",
  21. [$dbName]
  22. );
  23. $hasCardType = (int) $db->scalar(
  24. "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=? AND TABLE_NAME='sa_rental_user' AND COLUMN_NAME='member_card_type'",
  25. [$dbName]
  26. );
  27. if (($hasExpireAt === 0) !== ($hasCardType === 0)) {
  28. throw new RuntimeException('会员字段仅存在一个,请先核对表结构后再执行迁移');
  29. }
  30. if ($hasExpireAt === 0) {
  31. $db->exec("ALTER TABLE `sa_rental_user`
  32. ADD COLUMN `member_expire_at` DATETIME NULL COMMENT '会员到期时间' AFTER `card_gift_balance`,
  33. ADD COLUMN `member_card_type` TINYINT NOT NULL DEFAULT 0 COMMENT '当前会员卡类型 0月卡 1季卡 2半年卡 3年卡' AFTER `member_expire_at`,
  34. ADD KEY `idx_rental_user_member_expire` (`member_expire_at`)");
  35. echo "Added columns member_expire_at / member_card_type to sa_rental_user.\n";
  36. } else {
  37. echo "Columns already exist; skipping ALTER.\n";
  38. }
  39. // 2) Backfill
  40. $updated = $db->exec("UPDATE `sa_rental_user` u
  41. INNER JOIN (
  42. SELECT r.user_id,
  43. CAST(SUBSTRING_INDEX(GROUP_CONCAT(r.card_type ORDER BY r.expire_time DESC), ',', 1) AS UNSIGNED) AS latest_card_type,
  44. MAX(r.expire_time) AS latest_expire_time
  45. FROM `sa_member_activation_record` r
  46. WHERE r.`delete_time` IS NULL
  47. AND r.`status` = 1
  48. AND r.`expire_time` >= NOW()
  49. GROUP BY r.user_id
  50. ) latest ON latest.user_id = u.id
  51. AND u.`member_expire_at` IS NULL
  52. SET u.`member_card_type` = latest.latest_card_type,
  53. u.`member_expire_at` = latest.latest_expire_time");
  54. echo "Backfilled sa_rental_user.member_expire_at / member_card_type from activation records: {$updated} rows.\n";
  55. // 3) Insert UserList 下的「用户会员开通」按钮菜单
  56. $menuId = (int) $db->scalar(
  57. "SELECT id FROM sa_system_menu WHERE slug='core:user:list:memberActivation' AND delete_time IS NULL LIMIT 1"
  58. );
  59. if ($menuId === 0) {
  60. $parentId = (int) $db->scalar(
  61. "SELECT id FROM sa_system_menu WHERE `code`='UserList' AND delete_time IS NULL LIMIT 1"
  62. );
  63. if ($parentId === 0) {
  64. echo "WARN: UserList menu not found; skipping button menu insert.\n";
  65. } else {
  66. $now = date('Y-m-d H:i:s');
  67. $db->execute(
  68. "INSERT INTO sa_system_menu
  69. (parent_id, name, code, slug, type, path, component, method, icon, sort,
  70. link_url, is_iframe, is_keep_alive, is_hidden, is_fixed_tab, is_full_page,
  71. generate_id, generate_key, status, remark, created_by, updated_by, create_time, update_time, delete_time)
  72. VALUES (?, ?, ?, ?, ?, NULL, NULL, ?, NULL, ?, NULL, 2, 2, 2, 2, 2, 0, NULL, 1, ?, 1, 1, ?, ?, NULL)",
  73. [$parentId, '用户会员开通', 'RentalUserMemberActivation', 'core:user:list:memberActivation', 3, 'POST', 110,
  74. '管理员对当前可见小程序租借用户开通或续费会员', $now, $now]
  75. );
  76. $menuId = (int) $db->getPdo()->lastInsertId();
  77. echo "Inserted menu #{$menuId} (用户会员开通).\n";
  78. }
  79. } else {
  80. echo "Menu core:user:list:memberActivation already exists (#{$menuId}); updating label.\n";
  81. $db->execute(
  82. "UPDATE sa_system_menu SET name=?, method='POST', remark=?, update_time=NOW()
  83. WHERE id=? AND delete_time IS NULL",
  84. ['用户会员开通', '管理员对当前可见小程序租借用户开通或续费会员', $menuId]
  85. );
  86. }
  87. // 4) 自动赋给已有 UserList 权限的角色
  88. if ($menuId > 0) {
  89. $granted = $db->execute(
  90. "INSERT INTO sa_system_role_menu (role_id, menu_id)
  91. SELECT DISTINCT srm.role_id, ? FROM sa_system_role_menu srm
  92. INNER JOIN sa_system_menu sm ON sm.id = srm.menu_id AND sm.code='UserList' AND sm.delete_time IS NULL
  93. LEFT JOIN sa_system_role_menu existing
  94. ON existing.role_id = srm.role_id AND existing.menu_id = ?
  95. WHERE existing.id IS NULL",
  96. [$menuId, $menuId]
  97. );
  98. echo "Granted button permission to {$granted} role-menu pairs.\n";
  99. }
  100. echo "Done.\n";