zen_admin 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +76 -0
  3. data/Rakefile +6 -0
  4. data/app/assets/stylesheets/zen_admin/application.css +15 -0
  5. data/app/controllers/zen_admin/application_controller.rb +27 -0
  6. data/app/controllers/zen_admin/dashboard_controller.rb +9 -0
  7. data/app/controllers/zen_admin/sessions_controller.rb +40 -0
  8. data/app/controllers/zen_admin/ui/resources_controller.rb +331 -0
  9. data/app/helpers/zen_admin/application_helper.rb +80 -0
  10. data/app/javascript/controllers/application.js +9 -0
  11. data/app/javascript/controllers/bulk_actions_controller.js +55 -0
  12. data/app/javascript/controllers/clipboard_controller.js +27 -0
  13. data/app/javascript/controllers/index.js +5 -0
  14. data/app/javascript/controllers/layout_controller.js +48 -0
  15. data/app/javascript/controllers/menu_group_controller.js +40 -0
  16. data/app/javascript/controllers/modal_controller.js +31 -0
  17. data/app/javascript/controllers/toast_controller.js +14 -0
  18. data/app/javascript/controllers/tom_select_controller.js +35 -0
  19. data/app/javascript/zen_admin/application.js +12 -0
  20. data/app/jobs/zen_admin/application_job.rb +4 -0
  21. data/app/mailers/zen_admin/application_mailer.rb +6 -0
  22. data/app/models/zen_admin/application_record.rb +5 -0
  23. data/app/models/zen_admin/asset.rb +43 -0
  24. data/app/models/zen_admin/audit_log.rb +116 -0
  25. data/app/models/zen_admin/permission.rb +73 -0
  26. data/app/models/zen_admin/role.rb +45 -0
  27. data/app/models/zen_admin/trash_item.rb +98 -0
  28. data/app/models/zen_admin/user.rb +37 -0
  29. data/app/policies/zen_admin/application_policy.rb +53 -0
  30. data/app/policies/zen_admin/resource_policy.rb +48 -0
  31. data/app/views/layouts/zen_admin/_flash.html.erb +9 -0
  32. data/app/views/layouts/zen_admin/_sidebar.html.erb +115 -0
  33. data/app/views/layouts/zen_admin/application.html.erb +98 -0
  34. data/app/views/zen_admin/builtin/_copy_button.html.erb +9 -0
  35. data/app/views/zen_admin/builtin/_file_link.html.erb +22 -0
  36. data/app/views/zen_admin/dashboard/index.html.erb +27 -0
  37. data/app/views/zen_admin/sessions/new.html.erb +47 -0
  38. data/app/views/zen_admin/ui/resources/_form.html.erb +226 -0
  39. data/app/views/zen_admin/ui/resources/_row.html.erb +170 -0
  40. data/app/views/zen_admin/ui/resources/create.turbo_stream.erb +2 -0
  41. data/app/views/zen_admin/ui/resources/destroy.turbo_stream.erb +2 -0
  42. data/app/views/zen_admin/ui/resources/edit.html.erb +11 -0
  43. data/app/views/zen_admin/ui/resources/index.html.erb +285 -0
  44. data/app/views/zen_admin/ui/resources/new.html.erb +11 -0
  45. data/app/views/zen_admin/ui/resources/show.html.erb +133 -0
  46. data/app/views/zen_admin/ui/resources/update.turbo_stream.erb +2 -0
  47. data/config/importmap.rb +10 -0
  48. data/config/locales/en.yml +107 -0
  49. data/config/locales/zh-CN.yml +110 -0
  50. data/config/routes.rb +24 -0
  51. data/lib/generators/zen_admin/admin_user/admin_user_generator.rb +55 -0
  52. data/lib/generators/zen_admin/install/install_generator.rb +50 -0
  53. data/lib/generators/zen_admin/install/templates/asset.rb +46 -0
  54. data/lib/generators/zen_admin/install/templates/create_zen_admin_assets.rb.erb +9 -0
  55. data/lib/generators/zen_admin/install/templates/create_zen_admin_audit_logs.rb.erb +18 -0
  56. data/lib/generators/zen_admin/install/templates/create_zen_admin_rbac.rb.erb +57 -0
  57. data/lib/generators/zen_admin/install/templates/create_zen_admin_trash_items.rb.erb +13 -0
  58. data/lib/generators/zen_admin/install/templates/zen_admin.rb +17 -0
  59. data/lib/generators/zen_admin/install/templates/zh-CN.yml +15 -0
  60. data/lib/generators/zen_admin/model/model_generator.rb +65 -0
  61. data/lib/generators/zen_admin/model/templates/zen_admin_config.rb.erb +80 -0
  62. data/lib/generators/zen_admin/rbac_install/rbac_install_generator.rb +52 -0
  63. data/lib/generators/zen_admin/rbac_install/templates/create_zen_admin_rbac.rb.erb +42 -0
  64. data/lib/generators/zen_admin/rbac_install/templates/seeds.rb.erb +13 -0
  65. data/lib/tasks/zen_admin_tasks.rake +4 -0
  66. data/lib/zen_admin/authenticatable.rb +44 -0
  67. data/lib/zen_admin/builtin.rb +77 -0
  68. data/lib/zen_admin/configuration.rb +17 -0
  69. data/lib/zen_admin/core/field.rb +34 -0
  70. data/lib/zen_admin/core/filter.rb +16 -0
  71. data/lib/zen_admin/core/resource.rb +175 -0
  72. data/lib/zen_admin/core.rb +3 -0
  73. data/lib/zen_admin/engine.rb +67 -0
  74. data/lib/zen_admin/link_registerable.rb +11 -0
  75. data/lib/zen_admin/registerable.rb +17 -0
  76. data/lib/zen_admin/registry.rb +83 -0
  77. data/lib/zen_admin/schema/serializer.rb +15 -0
  78. data/lib/zen_admin/schema.rb +1 -0
  79. data/lib/zen_admin/version.rb +3 -0
  80. data/lib/zen_admin.rb +51 -0
  81. metadata +233 -0
@@ -0,0 +1,110 @@
1
+ zh-CN:
2
+ zen_admin:
3
+ ui:
4
+ search: "搜索"
5
+ show_limit: "显示"
6
+ items_per_page: "条"
7
+ no_data: "暂无数据。"
8
+ list_suffix: "列表"
9
+ actions: "操作"
10
+ confirm_delete: "确认删除吗?"
11
+ confirm_bulk_delete: "确认删除选中的 {count} 条数据吗?"
12
+ select_all: "全选"
13
+ close: "关闭"
14
+ save: "保存"
15
+ cancel: "取消"
16
+ errors: "错误!"
17
+ related_records: "相关记录"
18
+ no_related_records: "暂无相关记录。"
19
+ click_to_upload: "点击上传 %{field}"
20
+ change_image: "点击更换预览图"
21
+ multi_select_help: "按住 Ctrl (或 Command) 可选择多个"
22
+ actions:
23
+ new: "新增 %{resource}"
24
+ view: "查看"
25
+ edit: "编辑"
26
+ delete: "删除"
27
+ bulk_delete: "批量删除"
28
+ copy: "复制"
29
+ restore: "还原"
30
+ move_to_trash: "移至回收站"
31
+ messages:
32
+ created: "成功创建了 %{resource}。"
33
+ updated: "成功更新了 %{resource}。"
34
+ destroyed: "成功删除了 %{resource}。"
35
+ bulk_destroyed: "成功批量删除了 %{count} 条记录。"
36
+ restored: "成功还原了 %{resource}。"
37
+ moved_to_trash: "已将 %{resource} 移至回收站。"
38
+
39
+ # 内置核心资源定义
40
+ builtin:
41
+ assets: "文件资源库"
42
+ attachments: "系统自动附件"
43
+ attachment_info: "这里列出了系统中所有通过 ActiveStorage 自动关联的附件(如富文本插图等)。"
44
+
45
+ models:
46
+ # 映射 ActiveStorage 关联
47
+ "active_storage/attachment":
48
+ one: "系统自动附件"
49
+ other: "系统自动附件"
50
+ fields:
51
+ id: "预览"
52
+ record_type: "所属模型"
53
+ name: "字段名"
54
+ blob_filename: "原始文件名"
55
+ blob_id: "复制链接"
56
+ record: "来源对象"
57
+ blob: "原始文件"
58
+ # 映射内置资产模型
59
+ asset:
60
+ one: "文件资源库"
61
+ other: "文件资源库"
62
+ fields:
63
+ file: "预览"
64
+ name: "文件名称/备注"
65
+ id: "复制链接"
66
+ created_at: "上传时间"
67
+ user:
68
+ one: "系统用户"
69
+ other: "系统用户"
70
+ fields:
71
+ username: "用户名"
72
+ password: "密码"
73
+ roles: "角色"
74
+ created_at: "创建时间"
75
+ role:
76
+ one: "角色管理"
77
+ other: "角色管理"
78
+ fields:
79
+ name: "角色名称"
80
+ code: "标识符"
81
+ permissions: "拥有权限"
82
+ permission_ids: "权限分配"
83
+ permission:
84
+ one: "权限点"
85
+ other: "权限点"
86
+ fields:
87
+ name: "权限名称"
88
+ code: "标识符"
89
+ audit_log:
90
+ one: "操作审计"
91
+ other: "操作审计"
92
+ fields:
93
+ admin_username: "操作员"
94
+ resource_type: "资源类型"
95
+ resource_id: "ID"
96
+ action: "操作"
97
+ created_at: "时间"
98
+ changes_data: "数据变更"
99
+ ip_address: "IP地址"
100
+ trash_item:
101
+ one: "回收站记录"
102
+ other: "回收站记录"
103
+
104
+ views:
105
+ pagination:
106
+ first: "首页"
107
+ last: "末页"
108
+ previous: "上一页"
109
+ next: "下一页"
110
+ truncate: "..."
data/config/routes.rb ADDED
@@ -0,0 +1,24 @@
1
+ ZenAdmin::Engine.routes.draw do
2
+ next unless ZenAdmin.configuration.enable_ui
3
+
4
+ # 1. 静态路由优先级最高 (防止被作为资源名匹配)
5
+ get "login", to: "sessions#new", as: :login
6
+ post "login", to: "sessions#create"
7
+ delete "logout", to: "sessions#destroy", as: :logout
8
+ root to: "dashboard#index"
9
+
10
+ # 2. 动态资源路由 (直接挂载在 / 下)
11
+ # /admin/posts, /admin/posts/5, etc.
12
+ scope ":resource_name", module: "ui" do
13
+ post "bulk_action", to: "resources#bulk_action", as: :ui_resource_bulk_action
14
+ post ":id/member_action", to: "resources#member_action", as: :ui_resource_member_action
15
+ post ":id/restore", to: "resources#restore", as: :ui_resource_restore
16
+ delete "empty_trash", to: "resources#empty_trash", as: :ui_resource_empty_trash
17
+
18
+ resources :resources,
19
+ as: :ui_resource,
20
+ path: "",
21
+ only: [:index, :new, :create, :edit, :update, :show, :destroy],
22
+ param: :id
23
+ end
24
+ end
@@ -0,0 +1,55 @@
1
+ module ZenAdmin
2
+ module Generators
3
+ class AdminUserGenerator < Rails::Generators::Base
4
+ desc "创建 ZenAdmin 管理员账号"
5
+
6
+ def create_admin_user
7
+ username = ask("请输入用户名 [admin]:")
8
+ username = "admin" if username.blank?
9
+
10
+ # 检查用户是否已存在
11
+ if ZenAdmin::User.exists?(username: username)
12
+ say "错误: 用户 '#{username}' 已存在。", :red
13
+ return
14
+ end
15
+
16
+ password = ask_password("请输入密码:")
17
+
18
+ # 简单强度校验:长度小于 8 位
19
+ if password.length < 8
20
+ say "提示: 密码长度小于 8 位,安全性较低。", :yellow
21
+ unless yes?("确定要使用这个弱密码吗?(y/n)")
22
+ password = ask_password("请重新输入更强的密码:")
23
+ end
24
+ end
25
+
26
+ begin
27
+ user = ZenAdmin::User.new(username: username, password: password)
28
+
29
+ # 自动确保“超级管理员”角色存在
30
+ admin_role = ZenAdmin::Role.find_or_create_by!(code: "superadmin") do |r|
31
+ r.name = "超级管理员"
32
+ end
33
+
34
+ user.roles << admin_role
35
+ say "已分配超级管理员权限。", :green
36
+
37
+ if user.save
38
+ say "成功: 管理员 '#{username}' 已创建!", :green
39
+ else
40
+ say "保存失败: #{user.errors.full_messages.join(', ')}", :red
41
+ end
42
+ rescue => e
43
+ say "发生异常: #{e.message}", :red
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def ask_password(prompt)
50
+ # echo: false 隐藏输入,安全性更好
51
+ ask(prompt, echo: false)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,50 @@
1
+ require "rails/generators/active_record"
2
+
3
+ module ZenAdmin
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ include ActiveRecord::Generators::Migration
7
+ source_root File.expand_path("templates", __dir__)
8
+
9
+ desc "安装 ZenAdmin 基础配置(硬编码登录模式)"
10
+
11
+ def copy_initializer
12
+ template "zen_admin.rb", "config/initializers/zen_admin.rb"
13
+ end
14
+
15
+ def copy_migrations
16
+ migration_template "create_zen_admin_assets.rb.erb", "db/migrate/create_zen_admin_assets.rb"
17
+ migration_template "create_zen_admin_audit_logs.rb.erb", "db/migrate/create_zen_admin_audit_logs.rb"
18
+ migration_template "create_zen_admin_trash_items.rb.erb", "db/migrate/create_zen_admin_trash_items.rb"
19
+ end
20
+
21
+ def copy_models
22
+ template "asset.rb", "app/models/zen_admin/asset.rb"
23
+ end
24
+
25
+ def copy_locales
26
+ template "zh-CN.yml", "config/locales/zen_admin.zh-CN.yml"
27
+ end
28
+
29
+ def install_dependencies
30
+ say "正在安装 Action Text 和 Active Storage 依赖...", :yellow
31
+ rails_command "action_text:install"
32
+ # 注意: action_text:install 也会顺带安装 active_storage:install
33
+ end
34
+
35
+ def add_routes
36
+ route 'mount ZenAdmin::Engine => "/admin"'
37
+ end
38
+
39
+ def show_readme
40
+ say "\nZenAdmin 基础配置安装成功!", :green
41
+ say "你可以通过 config/initializers/zen_admin.rb 修改默认账号密码。", :yellow
42
+ say "接下来请运行: ", :yellow
43
+ say " bin/rails db:migrate", :white
44
+ say "直接访问 /admin 使用硬编码方式登录。", :white
45
+ say "\n如果你需要基于数据库的角色权限管理,请运行:", :yellow
46
+ say " bin/rails g zen_admin:rbac_install", :white
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,46 @@
1
+ module ZenAdmin
2
+ class Asset < ApplicationRecord
3
+ self.table_name = "zen_admin_assets"
4
+ has_one_attached :file
5
+
6
+ zen_admin do |resource|
7
+ resource.label :'zen_admin.builtin.assets', :'zen_admin.builtin.assets'
8
+ resource.menu label: :'zen_admin.builtin.assets', icon: "fas fa-images", position: 99
9
+ resource.enable_batch_actions
10
+ resource.batch_action :delete, label: I18n.t('zen_admin.actions.bulk_delete'), type: :danger, confirm: I18n.t('zen_admin.ui.confirm_delete') do |records|
11
+ records.destroy_all
12
+ end
13
+
14
+ resource.search do
15
+ field :name
16
+ end
17
+
18
+ resource.list do
19
+ field :file, label: "Preview"
20
+ field :name, label: "Name"
21
+ field :id, label: I18n.t('zen_admin.actions.copy') do |asset|
22
+ if asset.file.attached?
23
+ url = Rails.application.routes.url_helpers.rails_blob_url(asset.file, host: "localhost:3000") rescue "#"
24
+ render "zen_admin/builtin/copy_button", url: url
25
+ end
26
+ end
27
+ field :created_at, label: "Created At"
28
+ end
29
+
30
+ resource.form do
31
+ field :name, label: "Name/Note", required: true
32
+ field :file, label: "File", type: :file
33
+ end
34
+
35
+ resource.show do
36
+ field :name, label: "Name"
37
+ field :file, label: "Attachment Details" do |asset|
38
+ if asset.file.attached?
39
+ url = Rails.application.routes.url_helpers.rails_blob_url(asset.file, host: "localhost:3000") rescue ""
40
+ render "zen_admin/builtin/file_link", url: url
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,9 @@
1
+ class CreateZenAdminAssets < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :zen_admin_assets do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ class CreateZenAdminAuditLogs < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :zen_admin_audit_logs do |t|
4
+ t.string :admin_user_id
5
+ t.string :admin_username
6
+ t.string :resource_type
7
+ t.string :resource_id
8
+ t.string :action
9
+ t.text :note
10
+ t.json :changes_data
11
+ t.string :ip_address
12
+ t.string :user_agent
13
+ t.datetime :created_at
14
+ end
15
+ add_index :zen_admin_audit_logs, [:resource_type, :resource_id]
16
+ add_index :zen_admin_audit_logs, :admin_user_id
17
+ end
18
+ end
@@ -0,0 +1,57 @@
1
+ class CreateZenAdminRbac < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ # 1. 用户表
4
+ create_table :zen_admin_users do |t|
5
+ t.string :username, null: false
6
+ t.string :password_digest, null: false
7
+ t.timestamps
8
+ end
9
+ add_index :zen_admin_users, :username, unique: true
10
+
11
+ # 2. 角色表
12
+ create_table :zen_admin_roles do |t|
13
+ t.string :name, null: false
14
+ t.string :code, null: false
15
+ t.timestamps
16
+ end
17
+ add_index :zen_admin_roles, :name, unique: true
18
+ add_index :zen_admin_roles, :code, unique: true
19
+
20
+ # 3. 权限表
21
+ create_table :zen_admin_permissions do |t|
22
+ t.string :name, null: false
23
+ t.string :code, null: false
24
+ t.timestamps
25
+ end
26
+ add_index :zen_admin_permissions, :code, unique: true
27
+
28
+ # 4. 用户与角色的多对多中间表
29
+ create_table :zen_admin_users_roles, id: false do |t|
30
+ t.belongs_to :user, null: false, foreign_key: { to_table: :zen_admin_users }
31
+ t.belongs_to :role, null: false, foreign_key: { to_table: :zen_admin_roles }
32
+ end
33
+ add_index :zen_admin_users_roles, [:user_id, :role_id], unique: true
34
+
35
+ # 5. 角色与权限的多对多中间表
36
+ create_table :zen_admin_roles_permissions, id: false do |t|
37
+ t.belongs_to :role, null: false, foreign_key: { to_table: :zen_admin_roles }
38
+ t.belongs_to :permission, null: false, foreign_key: { to_table: :zen_admin_permissions }
39
+ end
40
+ add_index :zen_admin_roles_permissions, [:role_id, :permission_id], unique: true
41
+
42
+ # 6. 审计日志表
43
+ create_table :zen_admin_audit_logs do |t|
44
+ t.string :admin_user_id # 支持硬编码或数据库用户
45
+ t.string :admin_username
46
+ t.string :resource_type
47
+ t.string :resource_id
48
+ t.string :action
49
+ t.json :changes_data
50
+ t.string :ip_address
51
+ t.string :user_agent
52
+ t.datetime :created_at
53
+ end
54
+ add_index :zen_admin_audit_logs, [:resource_type, :resource_id]
55
+ add_index :zen_admin_audit_logs, :admin_user_id
56
+ end
57
+ end
@@ -0,0 +1,13 @@
1
+ class CreateZenAdminTrashItems < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :zen_admin_trash_items do |t|
4
+ t.string :resource_type, null: false
5
+ t.string :resource_id, null: false
6
+ t.string :resource_label
7
+ t.json :data
8
+ t.string :admin_username
9
+ t.datetime :created_at
10
+ end
11
+ add_index :zen_admin_trash_items, [:resource_type, :resource_id]
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ ZenAdmin.configure do |config|
2
+ # 是否开启管理后台 UI
3
+ config.enable_ui = true
4
+
5
+ # 后台访问路径
6
+ config.admin_path = "/admin"
7
+
8
+ # 设置显示时区
9
+ config.time_zone = "Beijing"
10
+
11
+ # 设置默认语言 (zh-CN, en)
12
+ config.default_locale = :"zh-CN"
13
+
14
+ # 默认初始账号(建议在通过指令创建真实用户后修改或删除)
15
+ config.username = "admin"
16
+ config.password = "password"
17
+ end
@@ -0,0 +1,15 @@
1
+ zh-CN:
2
+ zen_admin:
3
+ # 核心内置资源翻译
4
+ builtin:
5
+ assets: "文件资源库"
6
+ attachments: "系统自动附件"
7
+
8
+ # 宿主应用业务模型翻译 (示例)
9
+ models:
10
+ # post:
11
+ # one: "博客文章"
12
+ # other: "文章管理"
13
+ # fields:
14
+ # title: "文章标题"
15
+ # status: "发布状态"
@@ -0,0 +1,65 @@
1
+ require "rails/generators/active_record"
2
+
3
+ module ZenAdmin
4
+ module Generators
5
+ class ModelGenerator < Rails::Generators::NamedBase
6
+ argument :attributes, type: :array, default: [], banner: "field:type field:type"
7
+ source_root File.expand_path("templates", __dir__)
8
+
9
+ def create_model_if_missing
10
+ path = File.join("app/models", class_path, "#{file_name}.rb")
11
+ unless File.exist?(path)
12
+ say "Model #{class_name} not found. Generating it...", :yellow
13
+ generate "model", "#{class_name} #{attributes.map { |a| "#{a.name}:#{a.type}" }.join(' ')}"
14
+ end
15
+ end
16
+
17
+ def inject_zen_admin_config
18
+ path = File.join("app/models", class_path, "#{file_name}.rb")
19
+
20
+ if File.exist?(path)
21
+ @attrs = derived_attributes
22
+
23
+ # 渲染模板
24
+ template_path = File.expand_path("templates/zen_admin_config.rb.erb", __dir__)
25
+ config_content = ERB.new(File.read(template_path), trim_mode: '-').result(binding)
26
+
27
+ inject_into_class path, class_name do
28
+ config_content
29
+ end
30
+
31
+ say "Successfully integrated ZenAdmin DSL into #{class_name}", :green
32
+ else
33
+ say "Error: Model file #{path} not found.", :red
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ # 获取模型属性,用于自动填充 list/form
40
+ def derived_attributes
41
+ if attributes.any?
42
+ attributes
43
+ else
44
+ begin
45
+ # 尝试从数据库加载(如果模型已存在)
46
+ klass = class_name.safe_constantize
47
+ if klass && klass < ActiveRecord::Base
48
+ columns = klass.columns.reject { |c| %w[id created_at updated_at deleted_at].include?(c.name) }
49
+ columns.map { |c| Rails::Generators::GeneratedAttribute.new(c.name, c.type.to_s) }
50
+ else
51
+ []
52
+ end
53
+ rescue
54
+ []
55
+ end
56
+ end
57
+ end
58
+
59
+ # 内部绑定使用的变量
60
+ def attrs
61
+ @attrs || []
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,80 @@
1
+
2
+ # ZenAdmin 资源配置
3
+ zen_admin do |resource|
4
+ # 1. 基础信息配置
5
+ resource.label "<%= class_name %>", "<%= class_name.pluralize %>"
6
+ # group: 菜单分组名称,支持自动折叠
7
+ resource.menu label: "<%= class_name.pluralize.titleize %>", icon: "fas fa-circle", position: 10, visible: true, group: "应用管理"
8
+
9
+ # 2. 功能特性开关
10
+ resource.enable_batch_actions # 开启批量操作 (默认包含批量删除)
11
+ resource.exportable! # 开启 CSV 导出功能
12
+ # resource.soft_delete = true # 开启回收站 (默认开启,设为 false 则为物理删除)
13
+
14
+ # 3. 快捷页签 (Scopes)
15
+ # 静态页签示例 (支持 Ransack 查询语法: _eq, _cont, _gteq 等)
16
+ resource.scope :all, label: "全部", default: true
17
+ # resource.scope :recent, label: "最近一周", query: { created_at_gteq: 1.week.ago }
18
+
19
+ # 动态页签示例 (从数据库加载)
20
+ # resource.scope do
21
+ # Category.all.map { |cat| { name: "cat_#{cat.id}", label: cat.name, query: { category_id_eq: cat.id } } }
22
+ # end
23
+
24
+ # 4. 自定义批量操作 (Batch Actions)
25
+ # resource.batch_action :verify, label: "批量审核", type: :success, method: :bulk_verify_method
26
+ # resource.batch_action :archive, label: "批量归档", handler: ->(records) {
27
+ # records.update_all(archived: true)
28
+ # # 记录审计日志: zen_admin_audit(资源类, 动作名, note: 说明, changes: 数据)
29
+ # zen_admin_audit(<%= class_name %>, "archive", note: "批量归档操作", changes: { ids: records.ids })
30
+ # }
31
+
32
+ # 5. 单条记录操作 (Member Actions)
33
+ # resource.member_action :copy, label: "复制", icon: "fas fa-copy", type: :info, method: :copy_instance_method
34
+ # resource.member_action :highlight, label: "精选", handler: ->(record) { record.touch }
35
+
36
+ # 6. 列表页字段定义 (List View)
37
+ resource.list do
38
+ field :id, sortable: true
39
+ <% attrs.each do |a| -%>
40
+ field :<%= a.name %>, label: "<%= a.name.humanize %>"
41
+ <% end -%>
42
+ field :created_at, label: "创建时间", sortable: true
43
+ # 自定义渲染示例
44
+ # field :status, collection: [["草稿", "draft"], ["发布", "published"]] do |record, label|
45
+ # css = record.status == 'published' ? 'success' : 'secondary'
46
+ # content_tag :span, label, class: "badge bg-#{css}"
47
+ # end
48
+ end
49
+
50
+ # 7. 高级筛选面板 (Filters)
51
+ resource.filters do
52
+ <% attrs.select { |a| [:string, :text, :integer, :date, :datetime].include?(a.type.to_sym) }.each do |a| -%>
53
+ field :<%= a.name %>, label: "<%= a.name.humanize %>", type: :<%= a.type %>
54
+ <% end -%>
55
+ field :created_at, type: :date_range, label: "时间范围"
56
+ # 支持类型: :string, :select, :date_range
57
+ end
58
+
59
+ # 8. 表单页字段定义 (Form View)
60
+ resource.form do
61
+ <% attrs.each do |a| -%>
62
+ field :<%= a.name %>, label: "<%= a.name.humanize %>", type: :<%= a.type == "datetime" ? "date" : a.type %>
63
+ <% end -%>
64
+ # 常用类型参考:
65
+ # :string, :text, :password, :number, :email, :date, :datetime
66
+ # :file (ActiveStorage), :rich_text (ActionText)
67
+ # :select (单选), :multi_select (多选), :radio (单选组)
68
+ # 示例:
69
+ # field :author_id, type: :select, collection: -> { Author.all.map{|a| [a.name, a.id]} }
70
+ end
71
+
72
+ # 9. 详情页字段定义 (Show View - 默认自动发现所有字段)
73
+ # resource.show do
74
+ # field :id
75
+ # field :created_at
76
+ # field :cover_image do |record|
77
+ # image_tag url_for(record.cover_image) if record.cover_image.attached?
78
+ # end
79
+ # end
80
+ end
@@ -0,0 +1,52 @@
1
+ require "rails/generators/active_record"
2
+
3
+ module ZenAdmin
4
+ module Generators
5
+ class RbacInstallGenerator < Rails::Generators::Base
6
+ include ActiveRecord::Generators::Migration
7
+ source_root File.expand_path("templates", __dir__)
8
+
9
+ desc "安装 ZenAdmin RBAC 数据库支持"
10
+
11
+ def invoke_base_install
12
+ invoke "zen_admin:install"
13
+ end
14
+
15
+ def copy_migrations
16
+ migration_template "create_zen_admin_rbac.rb.erb", "db/migrate/create_zen_admin_rbac.rb"
17
+ end
18
+
19
+ def enable_rbac_config
20
+ path = "config/initializers/zen_admin.rb"
21
+ if File.exist?(path)
22
+ # 如果已经存在,则更新为 true
23
+ if File.read(path).include?("config.rbac_enable")
24
+ gsub_file path, /config\.rbac_enable\s*=\s*.*/, "config.rbac_enable = true"
25
+ else
26
+ # 插入在 configure 块的下一行
27
+ inject_into_file path, after: "ZenAdmin.configure do |config|\n" do
28
+ <<-RUBY
29
+ # 开启 RBAC 数据库验证模式
30
+ config.rbac_enable = true
31
+ RUBY
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def add_seeds
38
+ append_to_file "db/seeds.rb" do
39
+ ERB.new(File.read(File.expand_path("templates/seeds.rb.erb", __dir__))).result
40
+ end
41
+ end
42
+
43
+ def show_readme
44
+ say "\nZenAdmin RBAC 迁移文件已生成!", :green
45
+ say "接下来请运行: ", :yellow
46
+ say " bin/rails db:migrate", :white
47
+ say "然后创建管理员账号: ", :yellow
48
+ say " bin/rails g zen_admin:admin_user", :white
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,42 @@
1
+ class CreateZenAdminRbac < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ # 1. 用户表
4
+ create_table :zen_admin_users do |t|
5
+ t.string :username, null: false
6
+ t.string :password_digest, null: false
7
+ t.timestamps
8
+ end
9
+ add_index :zen_admin_users, :username, unique: true
10
+
11
+ # 2. 角色表
12
+ create_table :zen_admin_roles do |t|
13
+ t.string :name, null: false
14
+ t.string :code, null: false
15
+ t.timestamps
16
+ end
17
+ add_index :zen_admin_roles, :name, unique: true
18
+ add_index :zen_admin_roles, :code, unique: true
19
+
20
+ # 3. 权限表
21
+ create_table :zen_admin_permissions do |t|
22
+ t.string :name, null: false
23
+ t.string :code, null: false
24
+ t.timestamps
25
+ end
26
+ add_index :zen_admin_permissions, :code, unique: true
27
+
28
+ # 4. 用户与角色的多对多中间表
29
+ create_table :zen_admin_users_roles, id: false do |t|
30
+ t.belongs_to :user, null: false, foreign_key: { to_table: :zen_admin_users }
31
+ t.belongs_to :role, null: false, foreign_key: { to_table: :zen_admin_roles }
32
+ end
33
+ add_index :zen_admin_users_roles, [:user_id, :role_id], unique: true
34
+
35
+ # 5. 角色与权限的多对多中间表
36
+ create_table :zen_admin_roles_permissions, id: false do |t|
37
+ t.belongs_to :role, null: false, foreign_key: { to_table: :zen_admin_roles }
38
+ t.belongs_to :permission, null: false, foreign_key: { to_table: :zen_admin_permissions }
39
+ end
40
+ add_index :zen_admin_roles_permissions, [:role_id, :permission_id], unique: true
41
+ end
42
+ end
@@ -0,0 +1,13 @@
1
+ # ZenAdmin RBAC 初始数据
2
+ puts "正在初始化 ZenAdmin RBAC 数据..."
3
+
4
+ # 1. 创建基础权限 (可选,这里可以先空着让用户通过后台加)
5
+
6
+ # 2. 创建超级管理员角色
7
+ admin_role = ZenAdmin::Role.find_or_create_by!(code: "superadmin") do |r|
8
+ r.name = "超级管理员"
9
+ end
10
+
11
+ # 3. 如果有需要,可以给角色分配所有权限 (这里逻辑可以在后台手动操作,或写一个通配符逻辑)
12
+
13
+ puts "ZenAdmin RBAC 数据初始化完成!"