Browse Source

骏飞微信小程序API 1.0.0版本

master
ahbmz 4 years ago
commit
05bc5e4a94
  1. 870
      .editorconfig
  2. 30
      .env
  3. 5
      .gitignore
  4. 42
      .travis.yml
  5. 21
      LICENSE
  6. 80
      README.md
  7. 66
      addons/test/Plugin.php
  8. 57
      addons/test/config.php
  9. 15
      addons/test/controller/Index.php
  10. 14
      addons/test/view/index_info.html
  11. 1
      app/.htaccess
  12. 22
      app/AppService.php
  13. 58
      app/ExceptionHandle.php
  14. 8
      app/Request.php
  15. 272
      app/admin/common.php
  16. 14
      app/admin/config/app.php
  17. 23
      app/admin/config/builder.php
  18. 20
      app/admin/config/filesystem.php
  19. 9
      app/admin/config/view.php
  20. 47
      app/admin/controller/Ad.php
  21. 47
      app/admin/controller/AdType.php
  22. 230
      app/admin/controller/Admin.php
  23. 69
      app/admin/controller/AdminLog.php
  24. 47
      app/admin/controller/Article.php
  25. 134
      app/admin/controller/AuthGroup.php
  26. 165
      app/admin/controller/AuthRule.php
  27. 476
      app/admin/controller/Base.php
  28. 457
      app/admin/controller/Cate.php
  29. 241
      app/admin/controller/Config.php
  30. 313
      app/admin/controller/Database.php
  31. 47
      app/admin/controller/Debris.php
  32. 82
      app/admin/controller/Demo.php
  33. 47
      app/admin/controller/Dictionary.php
  34. 47
      app/admin/controller/DictionaryType.php
  35. 47
      app/admin/controller/Download.php
  36. 799
      app/admin/controller/Field.php
  37. 47
      app/admin/controller/FieldGroup.php
  38. 251
      app/admin/controller/Index.php
  39. 47
      app/admin/controller/Link.php
  40. 66
      app/admin/controller/Login.php
  41. 47
      app/admin/controller/Message.php
  42. 419
      app/admin/controller/Module.php
  43. 47
      app/admin/controller/Page.php
  44. 47
      app/admin/controller/Picture.php
  45. 374
      app/admin/controller/Plugin.php
  46. 47
      app/admin/controller/Product.php
  47. 47
      app/admin/controller/System.php
  48. 47
      app/admin/controller/Team.php
  49. 417
      app/admin/controller/Template.php
  50. 815
      app/admin/controller/Upload.php
  51. 47
      app/admin/controller/Users.php
  52. 47
      app/admin/controller/UsersType.php
  53. 21
      app/admin/event.php
  54. 12
      app/admin/facade/ThinkAddons.php
  55. 14
      app/admin/listener/AdminLogin.php
  56. 157
      app/admin/middleware/Admin.php
  57. 68
      app/admin/model/Base.php
  58. 502
      app/admin/service/ThinkAddons.php
  59. 52
      app/admin/validate/Ad.php
  60. 44
      app/admin/validate/AdType.php
  61. 55
      app/admin/validate/Admin.php
  62. 43
      app/admin/validate/AdminLog.php
  63. 55
      app/admin/validate/Article.php
  64. 41
      app/admin/validate/AuthGroup.php
  65. 45
      app/admin/validate/AuthRule.php
  66. 85
      app/admin/validate/Cate.php
  67. 57
      app/admin/validate/Debris.php
  68. 56
      app/admin/validate/Dictionary.php
  69. 49
      app/admin/validate/DictionaryType.php
  70. 55
      app/admin/validate/Download.php
  71. 61
      app/admin/validate/Field.php
  72. 49
      app/admin/validate/FieldGroup.php
  73. 47
      app/admin/validate/Link.php
  74. 50
      app/admin/validate/Message.php
  75. 63
      app/admin/validate/Module.php
  76. 49
      app/admin/validate/Page.php
  77. 55
      app/admin/validate/Picture.php
  78. 55
      app/admin/validate/Product.php
  79. 46
      app/admin/validate/System.php
  80. 61
      app/admin/validate/Team.php
  81. 75
      app/admin/validate/Users.php
  82. 46
      app/admin/validate/UsersType.php
  83. 15
      app/api/apidoc.json
  84. 19
      app/api/config/app.php
  85. 117
      app/api/controller/Base.php
  86. 155
      app/api/controller/Content.php
  87. 233
      app/api/controller/User.php
  88. 81
      app/api/middleware/Api.php
  89. 130
      app/api/service/JwtAuth.php
  90. 108
      app/command/Admin.php
  91. 953
      app/common.php
  92. 1290
      app/common/builder/FormBuilder.php
  93. 1290
      app/common/builder/MakeBuilder.php
  94. 715
      app/common/builder/TableBuilder.php
  95. 47
      app/common/builder/build/Controller.php
  96. 38
      app/common/builder/build/Model.php
  97. 33
      app/common/builder/build/Validate.php
  98. 12
      app/common/facade/Cms.php
  99. 12
      app/common/facade/MakeBuilder.php
  100. 12
      app/common/facade/User.php

870
.editorconfig

@ -0,0 +1,870 @@
[*]
charset = utf-8
end_of_line = crlf
indent_size = 4
indent_style = space
insert_final_newline = false
max_line_length = 120
tab_width = 4
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = false
ij_smart_tabs = false
ij_visual_guides = none
ij_wrap_on_typing = false
[*.blade.php]
ij_blade_keep_indents_on_empty_lines = false
[*.css]
ij_css_align_closing_brace_with_properties = false
ij_css_blank_lines_around_nested_selector = 1
ij_css_blank_lines_between_blocks = 1
ij_css_brace_placement = end_of_line
ij_css_enforce_quotes_on_format = false
ij_css_hex_color_long_format = false
ij_css_hex_color_lower_case = false
ij_css_hex_color_short_format = false
ij_css_hex_color_upper_case = false
ij_css_keep_blank_lines_in_code = 2
ij_css_keep_indents_on_empty_lines = false
ij_css_keep_single_line_blocks = false
ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_css_space_after_colon = true
ij_css_space_before_opening_brace = true
ij_css_use_double_quotes = true
ij_css_value_alignment = do_not_align
[*.feature]
indent_size = 2
ij_gherkin_keep_indents_on_empty_lines = false
[*.haml]
indent_size = 2
ij_haml_keep_indents_on_empty_lines = false
[*.less]
indent_size = 2
ij_less_align_closing_brace_with_properties = false
ij_less_blank_lines_around_nested_selector = 1
ij_less_blank_lines_between_blocks = 1
ij_less_brace_placement = 0
ij_less_enforce_quotes_on_format = false
ij_less_hex_color_long_format = false
ij_less_hex_color_lower_case = false
ij_less_hex_color_short_format = false
ij_less_hex_color_upper_case = false
ij_less_keep_blank_lines_in_code = 2
ij_less_keep_indents_on_empty_lines = false
ij_less_keep_single_line_blocks = false
ij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_less_space_after_colon = true
ij_less_space_before_opening_brace = true
ij_less_use_double_quotes = true
ij_less_value_alignment = 0
[*.sass]
indent_size = 2
ij_sass_align_closing_brace_with_properties = false
ij_sass_blank_lines_around_nested_selector = 1
ij_sass_blank_lines_between_blocks = 1
ij_sass_brace_placement = 0
ij_sass_enforce_quotes_on_format = false
ij_sass_hex_color_long_format = false
ij_sass_hex_color_lower_case = false
ij_sass_hex_color_short_format = false
ij_sass_hex_color_upper_case = false
ij_sass_keep_blank_lines_in_code = 2
ij_sass_keep_indents_on_empty_lines = false
ij_sass_keep_single_line_blocks = false
ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_sass_space_after_colon = true
ij_sass_space_before_opening_brace = true
ij_sass_use_double_quotes = true
ij_sass_value_alignment = 0
[*.scss]
indent_size = 2
ij_scss_align_closing_brace_with_properties = false
ij_scss_blank_lines_around_nested_selector = 1
ij_scss_blank_lines_between_blocks = 1
ij_scss_brace_placement = 0
ij_scss_enforce_quotes_on_format = false
ij_scss_hex_color_long_format = false
ij_scss_hex_color_lower_case = false
ij_scss_hex_color_short_format = false
ij_scss_hex_color_upper_case = false
ij_scss_keep_blank_lines_in_code = 2
ij_scss_keep_indents_on_empty_lines = false
ij_scss_keep_single_line_blocks = false
ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_scss_space_after_colon = true
ij_scss_space_before_opening_brace = true
ij_scss_use_double_quotes = true
ij_scss_value_alignment = 0
[*.twig]
ij_twig_keep_indents_on_empty_lines = false
ij_twig_spaces_inside_comments_delimiters = true
ij_twig_spaces_inside_delimiters = true
ij_twig_spaces_inside_variable_delimiters = true
[*.vue]
indent_size = 2
tab_width = 2
ij_continuation_indent_size = 4
ij_vue_indent_children_of_top_level = template
ij_vue_interpolation_new_line_after_start_delimiter = true
ij_vue_interpolation_new_line_before_end_delimiter = true
ij_vue_interpolation_wrap = off
ij_vue_keep_indents_on_empty_lines = false
ij_vue_spaces_within_interpolation_expressions = true
ij_vue_uniform_indent = true
[.editorconfig]
ij_editorconfig_align_group_field_declarations = false
ij_editorconfig_space_after_colon = false
ij_editorconfig_space_after_comma = true
ij_editorconfig_space_before_colon = false
ij_editorconfig_space_before_comma = false
ij_editorconfig_spaces_around_assignment_operators = true
[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul,phpunit.xml.dist}]
ij_xml_align_attributes = true
ij_xml_align_text = false
ij_xml_attribute_wrap = normal
ij_xml_block_comment_at_first_column = true
ij_xml_keep_blank_lines = 2
ij_xml_keep_indents_on_empty_lines = false
ij_xml_keep_line_breaks = true
ij_xml_keep_line_breaks_in_text = true
ij_xml_keep_whitespaces = false
ij_xml_keep_whitespaces_around_cdata = preserve
ij_xml_keep_whitespaces_inside_cdata = false
ij_xml_line_comment_at_first_column = true
ij_xml_space_after_tag_name = false
ij_xml_space_around_equals_in_attribute = false
ij_xml_space_inside_empty_tag = false
ij_xml_text_wrap = normal
[{*.ats,*.ts}]
ij_continuation_indent_size = 4
ij_typescript_align_imports = false
ij_typescript_align_multiline_array_initializer_expression = false
ij_typescript_align_multiline_binary_operation = false
ij_typescript_align_multiline_chained_methods = false
ij_typescript_align_multiline_extends_list = false
ij_typescript_align_multiline_for = true
ij_typescript_align_multiline_parameters = true
ij_typescript_align_multiline_parameters_in_calls = false
ij_typescript_align_multiline_ternary_operation = false
ij_typescript_align_object_properties = 0
ij_typescript_align_union_types = false
ij_typescript_align_var_statements = 0
ij_typescript_array_initializer_new_line_after_left_brace = false
ij_typescript_array_initializer_right_brace_on_new_line = false
ij_typescript_array_initializer_wrap = off
ij_typescript_assignment_wrap = off
ij_typescript_binary_operation_sign_on_next_line = false
ij_typescript_binary_operation_wrap = off
ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
ij_typescript_blank_lines_after_imports = 1
ij_typescript_blank_lines_around_class = 1
ij_typescript_blank_lines_around_field = 0
ij_typescript_blank_lines_around_field_in_interface = 0
ij_typescript_blank_lines_around_function = 1
ij_typescript_blank_lines_around_method = 1
ij_typescript_blank_lines_around_method_in_interface = 1
ij_typescript_block_brace_style = end_of_line
ij_typescript_call_parameters_new_line_after_left_paren = false
ij_typescript_call_parameters_right_paren_on_new_line = false
ij_typescript_call_parameters_wrap = off
ij_typescript_catch_on_new_line = false
ij_typescript_chained_call_dot_on_new_line = true
ij_typescript_class_brace_style = end_of_line
ij_typescript_comma_on_new_line = false
ij_typescript_do_while_brace_force = never
ij_typescript_else_on_new_line = false
ij_typescript_enforce_trailing_comma = keep
ij_typescript_extends_keyword_wrap = off
ij_typescript_extends_list_wrap = off
ij_typescript_field_prefix = _
ij_typescript_file_name_style = relaxed
ij_typescript_finally_on_new_line = false
ij_typescript_for_brace_force = never
ij_typescript_for_statement_new_line_after_left_paren = false
ij_typescript_for_statement_right_paren_on_new_line = false
ij_typescript_for_statement_wrap = off
ij_typescript_force_quote_style = false
ij_typescript_force_semicolon_style = false
ij_typescript_function_expression_brace_style = end_of_line
ij_typescript_if_brace_force = never
ij_typescript_import_merge_members = global
ij_typescript_import_prefer_absolute_path = global
ij_typescript_import_sort_members = true
ij_typescript_import_sort_module_name = false
ij_typescript_import_use_node_resolution = true
ij_typescript_imports_wrap = on_every_item
ij_typescript_indent_case_from_switch = true
ij_typescript_indent_chained_calls = true
ij_typescript_indent_package_children = 0
ij_typescript_jsdoc_include_types = false
ij_typescript_jsx_attribute_value = braces
ij_typescript_keep_blank_lines_in_code = 2
ij_typescript_keep_first_column_comment = true
ij_typescript_keep_indents_on_empty_lines = false
ij_typescript_keep_line_breaks = true
ij_typescript_keep_simple_blocks_in_one_line = false
ij_typescript_keep_simple_methods_in_one_line = false
ij_typescript_line_comment_add_space = true
ij_typescript_line_comment_at_first_column = false
ij_typescript_method_brace_style = end_of_line
ij_typescript_method_call_chain_wrap = off
ij_typescript_method_parameters_new_line_after_left_paren = false
ij_typescript_method_parameters_right_paren_on_new_line = false
ij_typescript_method_parameters_wrap = off
ij_typescript_object_literal_wrap = on_every_item
ij_typescript_parentheses_expression_new_line_after_left_paren = false
ij_typescript_parentheses_expression_right_paren_on_new_line = false
ij_typescript_place_assignment_sign_on_next_line = false
ij_typescript_prefer_as_type_cast = false
ij_typescript_prefer_explicit_types_function_expression_returns = false
ij_typescript_prefer_explicit_types_function_returns = false
ij_typescript_prefer_explicit_types_vars_fields = false
ij_typescript_prefer_parameters_wrap = false
ij_typescript_reformat_c_style_comments = false
ij_typescript_space_after_colon = true
ij_typescript_space_after_comma = true
ij_typescript_space_after_dots_in_rest_parameter = false
ij_typescript_space_after_generator_mult = true
ij_typescript_space_after_property_colon = true
ij_typescript_space_after_quest = true
ij_typescript_space_after_type_colon = true
ij_typescript_space_after_unary_not = false
ij_typescript_space_before_async_arrow_lparen = true
ij_typescript_space_before_catch_keyword = true
ij_typescript_space_before_catch_left_brace = true
ij_typescript_space_before_catch_parentheses = true
ij_typescript_space_before_class_lbrace = true
ij_typescript_space_before_class_left_brace = true
ij_typescript_space_before_colon = true
ij_typescript_space_before_comma = false
ij_typescript_space_before_do_left_brace = true
ij_typescript_space_before_else_keyword = true
ij_typescript_space_before_else_left_brace = true
ij_typescript_space_before_finally_keyword = true
ij_typescript_space_before_finally_left_brace = true
ij_typescript_space_before_for_left_brace = true
ij_typescript_space_before_for_parentheses = true
ij_typescript_space_before_for_semicolon = false
ij_typescript_space_before_function_left_parenth = true
ij_typescript_space_before_generator_mult = false
ij_typescript_space_before_if_left_brace = true
ij_typescript_space_before_if_parentheses = true
ij_typescript_space_before_method_call_parentheses = false
ij_typescript_space_before_method_left_brace = true
ij_typescript_space_before_method_parentheses = false
ij_typescript_space_before_property_colon = false
ij_typescript_space_before_quest = true
ij_typescript_space_before_switch_left_brace = true
ij_typescript_space_before_switch_parentheses = true
ij_typescript_space_before_try_left_brace = true
ij_typescript_space_before_type_colon = false
ij_typescript_space_before_unary_not = false
ij_typescript_space_before_while_keyword = true
ij_typescript_space_before_while_left_brace = true
ij_typescript_space_before_while_parentheses = true
ij_typescript_spaces_around_additive_operators = true
ij_typescript_spaces_around_arrow_function_operator = true
ij_typescript_spaces_around_assignment_operators = true
ij_typescript_spaces_around_bitwise_operators = true
ij_typescript_spaces_around_equality_operators = true
ij_typescript_spaces_around_logical_operators = true
ij_typescript_spaces_around_multiplicative_operators = true
ij_typescript_spaces_around_relational_operators = true
ij_typescript_spaces_around_shift_operators = true
ij_typescript_spaces_around_unary_operator = false
ij_typescript_spaces_within_array_initializer_brackets = false
ij_typescript_spaces_within_brackets = false
ij_typescript_spaces_within_catch_parentheses = false
ij_typescript_spaces_within_for_parentheses = false
ij_typescript_spaces_within_if_parentheses = false
ij_typescript_spaces_within_imports = false
ij_typescript_spaces_within_interpolation_expressions = false
ij_typescript_spaces_within_method_call_parentheses = false
ij_typescript_spaces_within_method_parentheses = false
ij_typescript_spaces_within_object_literal_braces = false
ij_typescript_spaces_within_object_type_braces = true
ij_typescript_spaces_within_parentheses = false
ij_typescript_spaces_within_switch_parentheses = false
ij_typescript_spaces_within_type_assertion = false
ij_typescript_spaces_within_union_types = true
ij_typescript_spaces_within_while_parentheses = false
ij_typescript_special_else_if_treatment = true
ij_typescript_ternary_operation_signs_on_next_line = false
ij_typescript_ternary_operation_wrap = off
ij_typescript_union_types_wrap = on_every_item
ij_typescript_use_chained_calls_group_indents = false
ij_typescript_use_double_quotes = true
ij_typescript_use_explicit_js_extension = global
ij_typescript_use_path_mapping = always
ij_typescript_use_public_modifier = false
ij_typescript_use_semicolon_after_statement = true
ij_typescript_var_declaration_wrap = normal
ij_typescript_while_brace_force = never
ij_typescript_while_on_new_line = false
ij_typescript_wrap_comments = false
[{*.bash,*.sh,*.zsh}]
indent_size = 2
tab_width = 2
ij_shell_binary_ops_start_line = false
ij_shell_keep_column_alignment_padding = false
ij_shell_minify_program = false
ij_shell_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false
ij_shell_use_unix_line_separator = true
[{*.cjs,*.js}]
ij_continuation_indent_size = 4
ij_javascript_align_imports = false
ij_javascript_align_multiline_array_initializer_expression = false
ij_javascript_align_multiline_binary_operation = false
ij_javascript_align_multiline_chained_methods = false
ij_javascript_align_multiline_extends_list = false
ij_javascript_align_multiline_for = true
ij_javascript_align_multiline_parameters = true
ij_javascript_align_multiline_parameters_in_calls = false
ij_javascript_align_multiline_ternary_operation = false
ij_javascript_align_object_properties = 0
ij_javascript_align_union_types = false
ij_javascript_align_var_statements = 0
ij_javascript_array_initializer_new_line_after_left_brace = false
ij_javascript_array_initializer_right_brace_on_new_line = false
ij_javascript_array_initializer_wrap = off
ij_javascript_assignment_wrap = off
ij_javascript_binary_operation_sign_on_next_line = false
ij_javascript_binary_operation_wrap = off
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
ij_javascript_blank_lines_after_imports = 1
ij_javascript_blank_lines_around_class = 1
ij_javascript_blank_lines_around_field = 0
ij_javascript_blank_lines_around_function = 1
ij_javascript_blank_lines_around_method = 1
ij_javascript_block_brace_style = end_of_line
ij_javascript_call_parameters_new_line_after_left_paren = false
ij_javascript_call_parameters_right_paren_on_new_line = false
ij_javascript_call_parameters_wrap = off
ij_javascript_catch_on_new_line = false
ij_javascript_chained_call_dot_on_new_line = true
ij_javascript_class_brace_style = end_of_line
ij_javascript_comma_on_new_line = false
ij_javascript_do_while_brace_force = never
ij_javascript_else_on_new_line = false
ij_javascript_enforce_trailing_comma = keep
ij_javascript_extends_keyword_wrap = off
ij_javascript_extends_list_wrap = off
ij_javascript_field_prefix = _
ij_javascript_file_name_style = relaxed
ij_javascript_finally_on_new_line = false
ij_javascript_for_brace_force = never
ij_javascript_for_statement_new_line_after_left_paren = false
ij_javascript_for_statement_right_paren_on_new_line = false
ij_javascript_for_statement_wrap = off
ij_javascript_force_quote_style = false
ij_javascript_force_semicolon_style = false
ij_javascript_function_expression_brace_style = end_of_line
ij_javascript_if_brace_force = never
ij_javascript_import_merge_members = global
ij_javascript_import_prefer_absolute_path = global
ij_javascript_import_sort_members = true
ij_javascript_import_sort_module_name = false
ij_javascript_import_use_node_resolution = true
ij_javascript_imports_wrap = on_every_item
ij_javascript_indent_case_from_switch = true
ij_javascript_indent_chained_calls = true
ij_javascript_indent_package_children = 0
ij_javascript_jsx_attribute_value = braces
ij_javascript_keep_blank_lines_in_code = 2
ij_javascript_keep_first_column_comment = true
ij_javascript_keep_indents_on_empty_lines = false
ij_javascript_keep_line_breaks = true
ij_javascript_keep_simple_blocks_in_one_line = false
ij_javascript_keep_simple_methods_in_one_line = false
ij_javascript_line_comment_add_space = true
ij_javascript_line_comment_at_first_column = false
ij_javascript_method_brace_style = end_of_line
ij_javascript_method_call_chain_wrap = off
ij_javascript_method_parameters_new_line_after_left_paren = false
ij_javascript_method_parameters_right_paren_on_new_line = false
ij_javascript_method_parameters_wrap = off
ij_javascript_object_literal_wrap = on_every_item
ij_javascript_parentheses_expression_new_line_after_left_paren = false
ij_javascript_parentheses_expression_right_paren_on_new_line = false
ij_javascript_place_assignment_sign_on_next_line = false
ij_javascript_prefer_as_type_cast = false
ij_javascript_prefer_explicit_types_function_expression_returns = false
ij_javascript_prefer_explicit_types_function_returns = false
ij_javascript_prefer_explicit_types_vars_fields = false
ij_javascript_prefer_parameters_wrap = false
ij_javascript_reformat_c_style_comments = false
ij_javascript_space_after_colon = true
ij_javascript_space_after_comma = true
ij_javascript_space_after_dots_in_rest_parameter = false
ij_javascript_space_after_generator_mult = true
ij_javascript_space_after_property_colon = true
ij_javascript_space_after_quest = true
ij_javascript_space_after_type_colon = true
ij_javascript_space_after_unary_not = false
ij_javascript_space_before_async_arrow_lparen = true
ij_javascript_space_before_catch_keyword = true
ij_javascript_space_before_catch_left_brace = true
ij_javascript_space_before_catch_parentheses = true
ij_javascript_space_before_class_lbrace = true
ij_javascript_space_before_class_left_brace = true
ij_javascript_space_before_colon = true
ij_javascript_space_before_comma = false
ij_javascript_space_before_do_left_brace = true
ij_javascript_space_before_else_keyword = true
ij_javascript_space_before_else_left_brace = true
ij_javascript_space_before_finally_keyword = true
ij_javascript_space_before_finally_left_brace = true
ij_javascript_space_before_for_left_brace = true
ij_javascript_space_before_for_parentheses = true
ij_javascript_space_before_for_semicolon = false
ij_javascript_space_before_function_left_parenth = true
ij_javascript_space_before_generator_mult = false
ij_javascript_space_before_if_left_brace = true
ij_javascript_space_before_if_parentheses = true
ij_javascript_space_before_method_call_parentheses = false
ij_javascript_space_before_method_left_brace = true
ij_javascript_space_before_method_parentheses = false
ij_javascript_space_before_property_colon = false
ij_javascript_space_before_quest = true
ij_javascript_space_before_switch_left_brace = true
ij_javascript_space_before_switch_parentheses = true
ij_javascript_space_before_try_left_brace = true
ij_javascript_space_before_type_colon = false
ij_javascript_space_before_unary_not = false
ij_javascript_space_before_while_keyword = true
ij_javascript_space_before_while_left_brace = true
ij_javascript_space_before_while_parentheses = true
ij_javascript_spaces_around_additive_operators = true
ij_javascript_spaces_around_arrow_function_operator = true
ij_javascript_spaces_around_assignment_operators = true
ij_javascript_spaces_around_bitwise_operators = true
ij_javascript_spaces_around_equality_operators = true
ij_javascript_spaces_around_logical_operators = true
ij_javascript_spaces_around_multiplicative_operators = true
ij_javascript_spaces_around_relational_operators = true
ij_javascript_spaces_around_shift_operators = true
ij_javascript_spaces_around_unary_operator = false
ij_javascript_spaces_within_array_initializer_brackets = false
ij_javascript_spaces_within_brackets = false
ij_javascript_spaces_within_catch_parentheses = false
ij_javascript_spaces_within_for_parentheses = false
ij_javascript_spaces_within_if_parentheses = false
ij_javascript_spaces_within_imports = false
ij_javascript_spaces_within_interpolation_expressions = false
ij_javascript_spaces_within_method_call_parentheses = false
ij_javascript_spaces_within_method_parentheses = false
ij_javascript_spaces_within_object_literal_braces = false
ij_javascript_spaces_within_object_type_braces = true
ij_javascript_spaces_within_parentheses = false
ij_javascript_spaces_within_switch_parentheses = false
ij_javascript_spaces_within_type_assertion = false
ij_javascript_spaces_within_union_types = true
ij_javascript_spaces_within_while_parentheses = false
ij_javascript_special_else_if_treatment = true
ij_javascript_ternary_operation_signs_on_next_line = false
ij_javascript_ternary_operation_wrap = off
ij_javascript_union_types_wrap = on_every_item
ij_javascript_use_chained_calls_group_indents = false
ij_javascript_use_double_quotes = true
ij_javascript_use_explicit_js_extension = global
ij_javascript_use_path_mapping = always
ij_javascript_use_public_modifier = false
ij_javascript_use_semicolon_after_statement = true
ij_javascript_var_declaration_wrap = normal
ij_javascript_while_brace_force = never
ij_javascript_while_on_new_line = false
ij_javascript_wrap_comments = false
[{*.cjsx,*.coffee}]
indent_size = 2
tab_width = 2
ij_continuation_indent_size = 2
ij_coffeescript_align_function_body = false
ij_coffeescript_align_imports = false
ij_coffeescript_align_multiline_array_initializer_expression = true
ij_coffeescript_align_multiline_parameters = true
ij_coffeescript_align_multiline_parameters_in_calls = false
ij_coffeescript_align_object_properties = 0
ij_coffeescript_align_union_types = false
ij_coffeescript_align_var_statements = 0
ij_coffeescript_array_initializer_new_line_after_left_brace = false
ij_coffeescript_array_initializer_right_brace_on_new_line = false
ij_coffeescript_array_initializer_wrap = normal
ij_coffeescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
ij_coffeescript_blank_lines_around_function = 1
ij_coffeescript_call_parameters_new_line_after_left_paren = false
ij_coffeescript_call_parameters_right_paren_on_new_line = false
ij_coffeescript_call_parameters_wrap = normal
ij_coffeescript_chained_call_dot_on_new_line = true
ij_coffeescript_comma_on_new_line = false
ij_coffeescript_enforce_trailing_comma = keep
ij_coffeescript_field_prefix = _
ij_coffeescript_file_name_style = relaxed
ij_coffeescript_force_quote_style = false
ij_coffeescript_force_semicolon_style = false
ij_coffeescript_function_expression_brace_style = end_of_line
ij_coffeescript_import_merge_members = global
ij_coffeescript_import_prefer_absolute_path = global
ij_coffeescript_import_sort_members = true
ij_coffeescript_import_sort_module_name = false
ij_coffeescript_import_use_node_resolution = true
ij_coffeescript_imports_wrap = on_every_item
ij_coffeescript_indent_chained_calls = true
ij_coffeescript_indent_package_children = 0
ij_coffeescript_jsx_attribute_value = braces
ij_coffeescript_keep_blank_lines_in_code = 2
ij_coffeescript_keep_first_column_comment = true
ij_coffeescript_keep_indents_on_empty_lines = false
ij_coffeescript_keep_line_breaks = true
ij_coffeescript_keep_simple_methods_in_one_line = false
ij_coffeescript_method_parameters_new_line_after_left_paren = false
ij_coffeescript_method_parameters_right_paren_on_new_line = false
ij_coffeescript_method_parameters_wrap = off
ij_coffeescript_object_literal_wrap = on_every_item
ij_coffeescript_prefer_as_type_cast = false
ij_coffeescript_prefer_explicit_types_function_expression_returns = false
ij_coffeescript_prefer_explicit_types_function_returns = false
ij_coffeescript_prefer_explicit_types_vars_fields = false
ij_coffeescript_reformat_c_style_comments = false
ij_coffeescript_space_after_comma = true
ij_coffeescript_space_after_dots_in_rest_parameter = false
ij_coffeescript_space_after_generator_mult = true
ij_coffeescript_space_after_property_colon = true
ij_coffeescript_space_after_type_colon = true
ij_coffeescript_space_after_unary_not = false
ij_coffeescript_space_before_async_arrow_lparen = true
ij_coffeescript_space_before_class_lbrace = true
ij_coffeescript_space_before_comma = false
ij_coffeescript_space_before_function_left_parenth = true
ij_coffeescript_space_before_generator_mult = false
ij_coffeescript_space_before_property_colon = false
ij_coffeescript_space_before_type_colon = false
ij_coffeescript_space_before_unary_not = false
ij_coffeescript_spaces_around_additive_operators = true
ij_coffeescript_spaces_around_arrow_function_operator = true
ij_coffeescript_spaces_around_assignment_operators = true
ij_coffeescript_spaces_around_bitwise_operators = true
ij_coffeescript_spaces_around_equality_operators = true
ij_coffeescript_spaces_around_logical_operators = true
ij_coffeescript_spaces_around_multiplicative_operators = true
ij_coffeescript_spaces_around_relational_operators = true
ij_coffeescript_spaces_around_shift_operators = true
ij_coffeescript_spaces_around_unary_operator = false
ij_coffeescript_spaces_within_array_initializer_braces = false
ij_coffeescript_spaces_within_array_initializer_brackets = false
ij_coffeescript_spaces_within_imports = false
ij_coffeescript_spaces_within_index_brackets = false
ij_coffeescript_spaces_within_interpolation_expressions = false
ij_coffeescript_spaces_within_method_call_parentheses = false
ij_coffeescript_spaces_within_method_parentheses = false
ij_coffeescript_spaces_within_object_braces = false
ij_coffeescript_spaces_within_object_literal_braces = false
ij_coffeescript_spaces_within_object_type_braces = true
ij_coffeescript_spaces_within_range_brackets = false
ij_coffeescript_spaces_within_type_assertion = false
ij_coffeescript_spaces_within_union_types = true
ij_coffeescript_union_types_wrap = on_every_item
ij_coffeescript_use_chained_calls_group_indents = false
ij_coffeescript_use_double_quotes = true
ij_coffeescript_use_explicit_js_extension = global
ij_coffeescript_use_path_mapping = always
ij_coffeescript_use_public_modifier = false
ij_coffeescript_use_semicolon_after_statement = false
ij_coffeescript_var_declaration_wrap = normal
[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}]
ij_continuation_indent_size = 4
ij_php_align_assignments = true
ij_php_align_class_constants = true
ij_php_align_group_field_declarations = true
ij_php_align_inline_comments = true
ij_php_align_key_value_pairs = true
ij_php_align_multiline_array_initializer_expression = false
ij_php_align_multiline_binary_operation = false
ij_php_align_multiline_chained_methods = false
ij_php_align_multiline_extends_list = false
ij_php_align_multiline_for = true
ij_php_align_multiline_parameters = true
ij_php_align_multiline_parameters_in_calls = false
ij_php_align_multiline_ternary_operation = false
ij_php_align_phpdoc_comments = true
ij_php_align_phpdoc_param_names = true
ij_php_anonymous_brace_style = end_of_line
ij_php_api_weight = 28
ij_php_array_initializer_new_line_after_left_brace = false
ij_php_array_initializer_right_brace_on_new_line = false
ij_php_array_initializer_wrap = off
ij_php_assignment_wrap = off
ij_php_attributes_wrap = off
ij_php_author_weight = 28
ij_php_binary_operation_sign_on_next_line = false
ij_php_binary_operation_wrap = off
ij_php_blank_lines_after_class_header = 0
ij_php_blank_lines_after_function = 1
ij_php_blank_lines_after_imports = 1
ij_php_blank_lines_after_opening_tag = 0
ij_php_blank_lines_after_package = 0
ij_php_blank_lines_around_class = 1
ij_php_blank_lines_around_constants = 0
ij_php_blank_lines_around_field = 0
ij_php_blank_lines_around_method = 1
ij_php_blank_lines_before_class_end = 0
ij_php_blank_lines_before_imports = 1
ij_php_blank_lines_before_method_body = 0
ij_php_blank_lines_before_package = 1
ij_php_blank_lines_before_return_statement = 0
ij_php_blank_lines_between_imports = 0
ij_php_block_brace_style = end_of_line
ij_php_call_parameters_new_line_after_left_paren = false
ij_php_call_parameters_right_paren_on_new_line = false
ij_php_call_parameters_wrap = off
ij_php_catch_on_new_line = false
ij_php_category_weight = 28
ij_php_class_brace_style = next_line
ij_php_comma_after_last_array_element = false
ij_php_concat_spaces = true
ij_php_copyright_weight = 28
ij_php_deprecated_weight = 28
ij_php_do_while_brace_force = never
ij_php_else_if_style = as_is
ij_php_else_on_new_line = false
ij_php_example_weight = 28
ij_php_extends_keyword_wrap = off
ij_php_extends_list_wrap = off
ij_php_fields_default_visibility = private
ij_php_filesource_weight = 28
ij_php_finally_on_new_line = false
ij_php_for_brace_force = never
ij_php_for_statement_new_line_after_left_paren = false
ij_php_for_statement_right_paren_on_new_line = false
ij_php_for_statement_wrap = off
ij_php_force_short_declaration_array_style = false
ij_php_getters_setters_naming_style = camel_case
ij_php_getters_setters_order_style = getters_first
ij_php_global_weight = 28
ij_php_group_use_wrap = on_every_item
ij_php_if_brace_force = never
ij_php_if_lparen_on_next_line = false
ij_php_if_rparen_on_next_line = false
ij_php_ignore_weight = 28
ij_php_import_sorting = alphabetic
ij_php_indent_break_from_case = true
ij_php_indent_case_from_switch = true
ij_php_indent_code_in_php_tags = false
ij_php_internal_weight = 28
ij_php_keep_blank_lines_after_lbrace = 2
ij_php_keep_blank_lines_before_right_brace = 2
ij_php_keep_blank_lines_in_code = 2
ij_php_keep_blank_lines_in_declarations = 2
ij_php_keep_control_statement_in_one_line = true
ij_php_keep_first_column_comment = true
ij_php_keep_indents_on_empty_lines = false
ij_php_keep_line_breaks = true
ij_php_keep_rparen_and_lbrace_on_one_line = false
ij_php_keep_simple_classes_in_one_line = false
ij_php_keep_simple_methods_in_one_line = false
ij_php_lambda_brace_style = end_of_line
ij_php_license_weight = 28
ij_php_line_comment_add_space = false
ij_php_line_comment_at_first_column = true
ij_php_link_weight = 28
ij_php_lower_case_boolean_const = false
ij_php_lower_case_keywords = true
ij_php_lower_case_null_const = false
ij_php_method_brace_style = next_line
ij_php_method_call_chain_wrap = off
ij_php_method_parameters_new_line_after_left_paren = false
ij_php_method_parameters_right_paren_on_new_line = false
ij_php_method_parameters_wrap = off
ij_php_method_weight = 28
ij_php_modifier_list_wrap = false
ij_php_multiline_chained_calls_semicolon_on_new_line = false
ij_php_namespace_brace_style = 1
ij_php_new_line_after_php_opening_tag = false
ij_php_null_type_position = in_the_end
ij_php_package_weight = 28
ij_php_param_weight = 0
ij_php_parameters_attributes_wrap = off
ij_php_parentheses_expression_new_line_after_left_paren = false
ij_php_parentheses_expression_right_paren_on_new_line = false
ij_php_phpdoc_blank_line_before_tags = false
ij_php_phpdoc_blank_lines_around_parameters = false
ij_php_phpdoc_keep_blank_lines = true
ij_php_phpdoc_param_spaces_between_name_and_description = 1
ij_php_phpdoc_param_spaces_between_tag_and_type = 1
ij_php_phpdoc_param_spaces_between_type_and_name = 1
ij_php_phpdoc_use_fqcn = false
ij_php_phpdoc_wrap_long_lines = false
ij_php_place_assignment_sign_on_next_line = false
ij_php_place_parens_for_constructor = 0
ij_php_property_read_weight = 28
ij_php_property_weight = 28
ij_php_property_write_weight = 28
ij_php_return_type_on_new_line = false
ij_php_return_weight = 1
ij_php_see_weight = 28
ij_php_since_weight = 28
ij_php_sort_phpdoc_elements = true
ij_php_space_after_colon = true
ij_php_space_after_colon_in_named_argument = true
ij_php_space_after_colon_in_return_type = true
ij_php_space_after_comma = true
ij_php_space_after_for_semicolon = true
ij_php_space_after_quest = true
ij_php_space_after_type_cast = false
ij_php_space_after_unary_not = false
ij_php_space_before_array_initializer_left_brace = false
ij_php_space_before_catch_keyword = true
ij_php_space_before_catch_left_brace = true
ij_php_space_before_catch_parentheses = true
ij_php_space_before_class_left_brace = true
ij_php_space_before_closure_left_parenthesis = true
ij_php_space_before_colon = true
ij_php_space_before_colon_in_named_argument = false
ij_php_space_before_colon_in_return_type = false
ij_php_space_before_comma = false
ij_php_space_before_do_left_brace = true
ij_php_space_before_else_keyword = true
ij_php_space_before_else_left_brace = true
ij_php_space_before_finally_keyword = true
ij_php_space_before_finally_left_brace = true
ij_php_space_before_for_left_brace = true
ij_php_space_before_for_parentheses = true
ij_php_space_before_for_semicolon = false
ij_php_space_before_if_left_brace = true
ij_php_space_before_if_parentheses = true
ij_php_space_before_method_call_parentheses = false
ij_php_space_before_method_left_brace = true
ij_php_space_before_method_parentheses = false
ij_php_space_before_quest = true
ij_php_space_before_short_closure_left_parenthesis = false
ij_php_space_before_switch_left_brace = true
ij_php_space_before_switch_parentheses = true
ij_php_space_before_try_left_brace = true
ij_php_space_before_unary_not = false
ij_php_space_before_while_keyword = true
ij_php_space_before_while_left_brace = true
ij_php_space_before_while_parentheses = true
ij_php_space_between_ternary_quest_and_colon = false
ij_php_spaces_around_additive_operators = true
ij_php_spaces_around_arrow = false
ij_php_spaces_around_assignment_in_declare = false
ij_php_spaces_around_assignment_operators = true
ij_php_spaces_around_bitwise_operators = true
ij_php_spaces_around_equality_operators = true
ij_php_spaces_around_logical_operators = true
ij_php_spaces_around_multiplicative_operators = true
ij_php_spaces_around_null_coalesce_operator = true
ij_php_spaces_around_relational_operators = true
ij_php_spaces_around_shift_operators = true
ij_php_spaces_around_unary_operator = false
ij_php_spaces_around_var_within_brackets = false
ij_php_spaces_within_array_initializer_braces = false
ij_php_spaces_within_brackets = false
ij_php_spaces_within_catch_parentheses = false
ij_php_spaces_within_for_parentheses = false
ij_php_spaces_within_if_parentheses = false
ij_php_spaces_within_method_call_parentheses = false
ij_php_spaces_within_method_parentheses = false
ij_php_spaces_within_parentheses = false
ij_php_spaces_within_short_echo_tags = true
ij_php_spaces_within_switch_parentheses = false
ij_php_spaces_within_while_parentheses = false
ij_php_special_else_if_treatment = false
ij_php_subpackage_weight = 28
ij_php_ternary_operation_signs_on_next_line = false
ij_php_ternary_operation_wrap = off
ij_php_throws_weight = 2
ij_php_todo_weight = 28
ij_php_unknown_tag_weight = 28
ij_php_upper_case_boolean_const = false
ij_php_upper_case_null_const = false
ij_php_uses_weight = 28
ij_php_var_weight = 28
ij_php_variable_naming_style = mixed
ij_php_version_weight = 28
ij_php_while_brace_force = never
ij_php_while_on_new_line = false
[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,composer.lock,jest.config}]
indent_size = 2
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}]
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
ij_html_align_attributes = true
ij_html_align_text = false
ij_html_attribute_wrap = normal
ij_html_block_comment_at_first_column = true
ij_html_do_not_align_children_of_min_lines = 0
ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p
ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot
ij_html_enforce_quotes = false
ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var
ij_html_keep_blank_lines = 2
ij_html_keep_indents_on_empty_lines = false
ij_html_keep_line_breaks = true
ij_html_keep_line_breaks_in_text = true
ij_html_keep_whitespaces = false
ij_html_keep_whitespaces_inside = span,pre,textarea
ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never
ij_html_quote_style = double
ij_html_remove_new_line_before_tags = br
ij_html_space_after_tag_name = false
ij_html_space_around_equality_in_attribute = false
ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal
ij_html_uniform_ident = false
[{*.markdown,*.md}]
ij_markdown_force_one_space_after_blockquote_symbol = true
ij_markdown_force_one_space_after_header_symbol = true
ij_markdown_force_one_space_after_list_bullet = true
ij_markdown_force_one_space_between_words = true
ij_markdown_keep_indents_on_empty_lines = false
ij_markdown_max_lines_around_block_elements = 1
ij_markdown_max_lines_around_header = 1
ij_markdown_max_lines_between_paragraphs = 1
ij_markdown_min_lines_around_block_elements = 1
ij_markdown_min_lines_around_header = 1
ij_markdown_min_lines_between_paragraphs = 1
[{*.yaml,*.yml}]
indent_size = 2
ij_yaml_align_values_properties = do_not_align
ij_yaml_autoinsert_sequence_marker = true
ij_yaml_block_mapping_on_new_line = false
ij_yaml_indent_sequence_value = true
ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true
ij_yaml_sequence_on_new_line = false
ij_yaml_space_before_colon = false
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true

30
.env

@ -0,0 +1,30 @@
# 应用调试模式(true=开启;false=关闭)
APP_DEBUG = true
[APP]
DEFAULT_TIMEZONE = Asia/Shanghai
[DATABASE]
TYPE = mysql
HOSTNAME = 127.0.0.1
DATABASE = api_junfei_iiixo
USERNAME = root
PASSWORD = root
HOSTPORT = 3306
CHARSET = utf8mb4
DEBUG = true
PREFIX = tp_
[LANG]
# 默认语言
default_lang = zh-cn
[BUILDER]
# 后台添加/编辑等页启用layer弹层加载(true=启用;false=不启用)
LAYER_OPEN = true
[ROUTE]
# 开启请求缓存(true=自动缓存;false=关闭缓存)
REQUEST_CACHE_KEY = false
# 请求缓存有效期(秒)
REQUEST_CACHE_EXPIRE = 3600

5
.gitignore

@ -0,0 +1,5 @@
/.idea
/.vscode
*.log
/runtime
/vendor

42
.travis.yml

@ -0,0 +1,42 @@
sudo: false
language: php
branches:
only:
- stable
cache:
directories:
- $HOME/.composer/cache
before_install:
- composer self-update
install:
- composer install --no-dev --no-interaction --ignore-platform-reqs
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip .
- composer require --update-no-dev --no-interaction "topthink/think-image:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0"
- composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0"
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip .
script:
- php think unit
deploy:
provider: releases
api_key:
secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=
file:
- ThinkPHP_Core.zip
- ThinkPHP_Full.zip
skip_cleanup: true
on:
tags: true

21
LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 若水印象
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

80
README.md

@ -0,0 +1,80 @@
## SIYUCMS V6.1 快速开发内容管理系统
[![star](https://gitee.com/ruoshuiyx/tp6/badge/star.svg?theme=dark)](https://gitee.com/ruoshuiyx/tp6/stargazers)
[![fork](https://gitee.com/ruoshuiyx/tp6/badge/fork.svg?theme=gray)](https://gitee.com/ruoshuiyx/tp6/members)
![PHP Version](https://img.shields.io/badge/php-%3E%3D7.2-orange)
[![License](https://img.shields.io/badge/license-MIT-brightgreen)](https://gitee.com/ruoshuiyx/tp6/blob/master/LICENSE)
SIYUCMS 基于 ThinkPHP6.0 + AdminLTE 开发,简单 / 易用 / 响应式 / 低门槛。
系统内置了表单构建器和表格构建器,配合后台模块管理和字段管理能快速方便的构建Web应用程序。
## 安装使用
> 下载SIYUCMS完整包解压到你本地(建议采用git方式拉取,或宝塔一键部署)
> 将你的站点绑定到public目录(强烈建议绑定到public目录)
> 将文件夹中siyucms.sql还原到你自己项目的数据库中(需自行创建数据库)
> 修改.env 中数据库配置信息(调试模式也是在这个文件中进行打开和关闭)
> 访问后台并登录查看是否正常,后台目录为http://www.yourwebsite.com/admin (如无法访问请尝试隐藏index.php https://www.kancloud.cn/ruoshuiyx/siyucms/1032705)
> 默认后台用户名:admin 密码:admin
## 在线体验
- 用户名:test 密码:123456
- 陆续收到一些捐赠、授权和打赏,谢谢各位小伙伴的支持。
演示地址:
[https://v6.siyucms.com/admin](https://v6.siyucms.com/admin)
文档地址:[https://www.kancloud.cn/ruoshuiyx/siyucms/](https://www.kancloud.cn/ruoshuiyx/siyucms/)
## 演示图
<table>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-b4b04b9033593ade89b42a20c7dbc4cdbd1.JPEG"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-f3d19bd061ed7046fb1d648ee4daaba3ab9.JPEG"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-1145a21c76fdc552d80010e299431c0a857.JPEG"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-96e50291450aed07bcd37362cc9d84e80a9.JPEG"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-cc975637268ec7c56f8f53d47ba4c8f53ca.JPEG"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-0fae3534357c5f4fe38c38520b38ec28e7a.JPEG"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-37dfb84b8a047cb5dd8b3153e7bfc688f4e.JPEG"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-b4b0d3c405f86527555b86c2f7a94bd2bbf.JPEG"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-7f917fb75032f0eedd7ab4b8944cdf55b6c.JPEG"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-afe8a9ec02ecb9299c30be835fea4fbee42.JPEG"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-b28d0574a8984e016ecab0d54d8c5ae43d5.JPEG"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-1fb975c7931d5f946054b6ab5ffe1ff190f.JPEG"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-b6a8f7507b23b414b61bef796ab213f2b78.JPEG"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-7f9fb85d0727aa87b717d95ef0e6f7e30d1.JPEG"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-bc84053e8b6250e57d42f3c0b03980a799d.JPEG"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-85a769ccbb17fb074053296094e3e3e4ac9.JPEG"/></td>
</tr>
</table>
## 交流群
QQ群:
[883855822](https://qm.qq.com/cgi-bin/qm/qr?k=yPFJoUxXBYhHoGxh5lLSp3mpAdgw1v8x&jump_from=webapi)
## 版权信息
请尊重SIYUCMS开发者的劳动成果,SIYUCMS提供免费使用,但未授权前请保留前台 Powered by SIYUCMS ,并不得修改后台版权信息。

66
addons/test/Plugin.php

@ -0,0 +1,66 @@
<?php
// 注意命名空间规范
namespace addons\test;
use think\Addons;
/**
* 插件测试
* 注意名字不可以修改,只能为Plugin
*/
class Plugin extends Addons
{
// 该插件的基础信息,系统优先获取info.ini中的配置信息
public $info = [
'name' => 'test', // 插件标识
'title' => '插件测试', // 插件名称
'description' => 'thinkph6插件测试', // 插件简介
'status' => 0, // 状态[1 启用,0 禁用]
'install' => 0, // 是否已安装[1 已安装,0 未安装]
'author' => 'SIYUCMS', // 作者
'version' => '1.0', // 版本
];
// 插件的安装 [添加文件、执行sql等]
public function install()
{
return true;
}
// 插件的卸载 [移除文件、执行sql等]
public function uninstall()
{
return true;
}
/**
* 实现的testhook钩子方法
* @param $param 调用钩子时候的参数信息
* @return false|mixed|string
*
* 用法:
* 模版中调用:<div>{:hook('testhook', ['id'=>1])}</div>
* PHP中调用:hook('testhook', ['id'=>1]);
*/
public function testhook($param)
{
// 当前插件的基础信息,系统优先获取info.ini中的配置信息
$info = $this->getInfo();
// 插件禁用后不再进行任何输出
if($info['status'] == 0){
return false;
}
// 当前插件的配置信息,配置信息存在当前目录的config.php文件中
$config = $this->getConfig();
// 打印调用钩子时候的参数信息和当前参加的配置信息
dump($param, $info, $config);
// 可以返回模板,模板文件默认读取的为插件目录中的文件。模板名不能为空!
return $this->fetch('info');
}
}

57
addons/test/config.php

@ -0,0 +1,57 @@
<?php
return array (
'field_1' =>
array (
'title' => '文本框:',
'type' => 'text',
'options' =>
array (
),
'value' => '文本框的值',
),
'field_2' =>
array (
'title' => '文本域:',
'type' => 'textarea',
'options' =>
array (
),
'value' => '文本域的值',
),
'field_3' =>
array (
'title' => '单选:',
'type' => 'radio',
'options' =>
array (
1 => '是',
0 => '否',
),
'value' => '0',
),
'field_4' =>
array (
'title' => '多选:',
'type' => 'checkbox',
'options' =>
array (
1 => '选项1',
2 => '选项2',
3 => '选项3',
),
'value' => '1,2',
),
'field_5' =>
array (
'title' => '下拉:',
'type' => 'select',
'options' =>
array (
1 => '选项1',
2 => '选项2',
3 => '选项3',
),
'value' => '1',
),
);

15
addons/test/controller/Index.php

@ -0,0 +1,15 @@
<?php
namespace addons\test\controller;
class Index
{
public function link()
{
echo 'hello link';
}
public function test()
{
echo 'hello test';
}
}

14
addons/test/view/index_info.html

@ -0,0 +1,14 @@
<h1>hello tpl</h1>
如果插件中需要有链接或提交数据的业务,可以在插件中创建controller业务文件,
要访问插件中的controller时使用addons_url生成url链接。<br>
<hr>
如:
<a href="{:addons_url('Index/test')}">Index test</a><br>
格式为:
test为插件名,Index为controller中的类名[多级控制器可以用.分割],test同时也为controller中的方法命<br>
<a href="{:addons_url('test://Index/link')}">Index link</a><br>
格式为:
test为插件名,Index为controller中的类名[多级控制器可以用.分割],link为controller中的方法

1
app/.htaccess

@ -0,0 +1 @@
deny from all

22
app/AppService.php

@ -0,0 +1,22 @@
<?php
declare (strict_types = 1);
namespace app;
use think\Service;
/**
* 应用服务类
*/
class AppService extends Service
{
public function register()
{
// 服务注册
}
public function boot()
{
// 服务启动
}
}

58
app/ExceptionHandle.php

@ -0,0 +1,58 @@
<?php
namespace app;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Response;
use Throwable;
/**
* 应用异常处理类
*/
class ExceptionHandle extends Handle
{
/**
* 不需要记录信息(日志)的异常类列表
* @var array
*/
protected $ignoreReport = [
HttpException::class,
HttpResponseException::class,
ModelNotFoundException::class,
DataNotFoundException::class,
ValidateException::class,
];
/**
* 记录异常信息(包括日志或者其它方式记录)
*
* @access public
* @param Throwable $exception
* @return void
*/
public function report(Throwable $exception): void
{
// 使用内置的方式记录异常日志
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @access public
* @param \think\Request $request
* @param Throwable $e
* @return Response
*/
public function render($request, Throwable $e): Response
{
// 添加自定义异常处理机制
// 其他错误交给系统处理
return parent::render($request, $e);
}
}

8
app/Request.php

@ -0,0 +1,8 @@
<?php
namespace app;
// 应用请求对象类
class Request extends \think\Request
{
}

272
app/admin/common.php

@ -0,0 +1,272 @@
<?php
/**
* 生成页码跳转
* @param int $page_size 每页显示的数量
* @return string
*/
function page_size($page_size = 0, $total = 0)
{
$str = '<select class="form-control page_size">';
for ($i = 10; $i <= 100; $i += 10) {
$selected = $page_size == $i ? 'selected' : '';
$str .= '<option value="' . $i . '" ' . $selected . ' >' . $i . ' 条/页</option>';
}
$str .= '</select>';
if ($total > 0) {
$str .= '<span class="form-control page_total">总共 ' . $total . ' 条记录</span>';
}
return $str;
}
/**
* 空数据提示
* @param int $num
* @return string
*/
function empty_list($num = 10)
{
$empty = "<tr><td colspan='" . $num . "' align='center'>暂无数据</td></tr>";
return $empty;
}
/**
* 权限设置选中状态
* @param $cate 栏目
* @param int $pid 父ID
* @param $rules 规则
* @return array
*/
function auth($cate, $pid, $rules)
{
$arr = array();
$rulesArr = explode(',', $rules);
foreach ($cate as $v) {
if ($v['pid'] == $pid) {
if (in_array($v['id'], $rulesArr)) {
$v['checked'] = true;
}
$v['open'] = true;
$arr[] = $v;
$arr = array_merge($arr, auth($cate, $v['id'], $rules));
}
}
return $arr;
}
/**
* PHP格式化字节大小
* @param number $size 字节数
* @param string $delimiter 数字和单位分隔符
* @return string 格式化后的带单位的大小
*/
function format_bytes($size, $delimiter = '')
{
$units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
for ($i = 0; $size >= 1024 && $i < 5; $i++) $size /= 1024;
return round($size, 2) . $delimiter . $units[$i];
}
/**
* 获取目录里的文件,不包括下级文件夹
* @param string $dir 路径
* @return array
*/
function get_dir($dir)
{
$file = @ scandir($dir);
foreach ($file as $key) {
if ($key != ".." && $key != ".") {
$files[] = $key;
}
}
return $files;
}
/**
* 获取文件夹中的文件,含目录
* @param $path
* @param string $exts
* @param array $list
* @return array
*/
function dir_list($path, $exts = '', $list = array())
{
$path = dir_path($path);
$files = glob($path . '*');
foreach ($files as $v) {
$fileext = fileext($v);
if (!$exts || preg_match("/\.($exts)/i", $v)) {
$list[] = $v;
if (is_dir($v)) {
$list = dir_list($v, $exts, $list);
}
}
}
return $list;
}
/**
* 补齐目录后的/
* @param $path 目录
* @return string
*/
function dir_path($path)
{
$path = str_replace('\\', '/', $path);
if (substr($path, -1) != '/') $path = $path . '/';
return $path;
}
/**
* 查找文件后缀
* @param $filename 文件名称
* @return string 后缀名称(如:html)
*/
function fileext($filename)
{
return strtolower(trim(substr(strrchr($filename, '.'), 1, 10)));
}
/**
* 删除目录及文件
* @param $dir
* @return bool
*/
function dir_delete($dir)
{
$dir = dir_path($dir);
if (!is_dir($dir)) return FALSE;
$list = glob($dir . '*');
foreach ($list as $v) {
is_dir($v) ? dir_delete($v) : @unlink($v);
}
return @rmdir($dir);
}
/**
* 生成不同的编辑器(目前只支持ckeditor)
* @param string $name 字段名称
* @param string $conetnt 内容
* @param string $editor 编辑器
* @param string $height 高度
* @param string $width 宽度
* @return string
*/
function make_editor($name, $conetnt = '', $editor = '', $height = '400px', $width = '')
{
$result = '<textarea name="' . $name . '" id="' . $name . '">' . $conetnt . '</textarea><script>CKEDITOR.replace(\'' . $name . '\', { height: \'' . $height . '\', width: \'' . $width . '\' });</script>';
return $result;
}
/***
* 日期筛选格式化
* @param $dateran
* @return array
*/
function get_dateran($dateran)
{
if ($dateran) {
$dateran = explode(" 至 ", $dateran);
}
if (is_array($dateran) && count($dateran) == 2) {
$dateran[0] = strtotime($dateran[0]);
$dateran[1] = strtotime($dateran[1]) + 24 * 60 * 60 - 1;
}
return $dateran;
}
/**
* 根据数组中某个字段重新分组
* @param {dataArr:需要分组的数据;keyStr:分组依据}
* @return: array
*/
function array_group(array $dataArr, string $keyStr): array
{
$newArr = [];
foreach ($dataArr as $k => $val) {
$newArr[$val[$keyStr]][] = $val;
}
return $newArr;
}
/***
* 格式化面包导航(用户后台面包导航)
* @param $data
* @return array
*/
function format_bread_crumb($data)
{
$result = array();
if (!empty($data)) {
$data = array_reverse($data);
if (count($data) == 4) {
//非常规 添加或修改
$result['right'] = $data[1];
$result['left'][0] = $data[1]['title'];
//查看是添加还是修改
$result['left'][1] = $data[2]['title'] . '-' . str_replace('操作-', '', $data[3]['title']);
} else if (count($data) == 3) {
//常规 添加或修改
$result['right'] = $data[1];
$result['left'][0] = $data[1]['title'];
//查看是添加还是修改
$result['left'][1] = str_replace('操作-', '', $data[2]['title']);
} else if (count($data) == 2) {
//常规 列表
$result['right'] = $data[1];
$result['left'][0] = $data[1]['title'];
$result['left'][1] = '列表';
} else {
//单独定义
$result['right'] = $data[0];
$result['left'][0] = $data[0]['title'];
$result['left'][1] = '';
}
}
// 内容管理重构数组
$controller = \think\facade\Request::controller();
$module = \app\common\model\Module::where('model_name', $controller)->find();
if ($module && $module->table_type == 1) {
// 判断当前方法是添加、修改、列表
$action = \think\facade\Request::action();
if ($action == 'add') {
$action = '添加';
} else if ($action == 'edit') {
$action = '修改';
} else {
$action = '列表';
}
// 内容管理
$cateId = \think\facade\Request::param('cate_id');
if (empty($cateId)) {
$model = '\app\common\model\\' . $module->model_name;
if ($module['pk'] && \think\facade\Request::param('id')) {
$cateId = $model::where($module['pk'], \think\facade\Request::param('id'))->value('cate_id');
}
}
// 调用当前栏目名称
if ($cateId) {
$cateName = \app\common\model\Cate::where('id', $cateId)->value('cate_name');
if ($module->is_single) {
$url = 'edit?id=' . \think\facade\Request::param('id');
} else {
$url = 'index?cate_id=' . $cateId;
}
$result['right'] = [
'url' => $url,
'title' => $cateName,
'icon' => '',
];
$result['left'][0] = $cateName;
$result['left'][1] = $action;
}
}
return $result;
}

14
app/admin/config/app.php

@ -0,0 +1,14 @@
<?php
// +----------------------------------------------------------------------
// | 应用设置
// +----------------------------------------------------------------------
return [
// 默认分页显示数量
'page_size' => 10,
// 版本信息
'siyu_version' => '6.1.7',
// 默认跳转页面对应的模板文件
'dispatch_success_tmpl' => app()->getBasePath() . 'common' . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR . 'dispatch_jump.tpl',
'dispatch_error_tmpl' => app()->getBasePath() . 'common' . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR . 'dispatch_jump.tpl',
];

23
app/admin/config/builder.php

@ -0,0 +1,23 @@
<?php
// +----------------------------------------------------------------------
// | 构建器设置
// +----------------------------------------------------------------------
return [
// CMS模块添加字段时是否需要自动增加栏目ID等字段
'add_cate_id' => true,
// select2 插件是否启用ajax分页
'select2_ajax' => true,
// 添加/编辑等页启用layer弹层加载
'layer_open' => env('builder.layer_open', true),
// 不可生成的模块[内置模块][模型名称]
'un_make_module' => [
'Field', // 字段
'Module', // 模型
'AuthGroup', // 角色组
'Admin', // 管理员
'AuthRule', // 菜单规则
'AdminLog', // 管理员日志
'Cate', // 栏目管理
],
];

20
app/admin/config/filesystem.php

@ -0,0 +1,20 @@
<?php
use think\facade\Env;
return [
'default' => Env::get('filesystem.driver', 'local'),
'disks' => [
'local' => [
'type' => 'local',
'root' => app()->getRuntimePath() . 'storage',
],
'public' => [
'type' => 'local',
'root' => app()->getRootPath() . 'public',
'url' => '',
'visibility' => 'public',
],
// 更多的磁盘配置信息
],
];

9
app/admin/config/view.php

@ -0,0 +1,9 @@
<?php
// +----------------------------------------------------------------------
// | 模板设置
// +----------------------------------------------------------------------
return [
// 开启模板布局
'layout_on' => true,
];

47
app/admin/controller/Ad.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 广告管理控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Ad extends Base
{
// 验证器
protected $validate = 'Ad';
// 当前主表
protected $tableName = 'ad';
// 当前主模型
protected $modelName = 'Ad';
}

47
app/admin/controller/AdType.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 广告分组控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class AdType extends Base
{
// 验证器
protected $validate = 'AdType';
// 当前主表
protected $tableName = 'ad_type';
// 当前主模型
protected $modelName = 'AdType';
}

230
app/admin/controller/Admin.php

@ -0,0 +1,230 @@
<?php
/**
* +----------------------------------------------------------------------
* | 管理员列表控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/02/03
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
use think\facade\Session;
class Admin extends Base
{
// 验证器
protected $validate = 'Admin';
// 当前主表
protected $tableName = 'admin';
// 当前主模型
protected $modelName = 'Admin';
// 列表
public function index(){
// 获取主键
$pk = MakeBuilder::getPrimarykey($this->tableName);
// 获取列表数据
$columns = MakeBuilder::getListColumns($this->tableName);
// 插入`角色组`字段到第1个元素
array_splice($columns, 1, 0, [['group_name','角色组','text','',[],'','false']]);
// 获取搜索数据
$search = MakeBuilder::getListSearch($this->tableName);
// 获取当前模块信息
$model = '\app\common\model\\' . $this->modelName;
$module = \app\common\model\Module::where('table_name', $this->tableName)->find();
// 搜索
if (Request::param('getList') == 1) {
$where = MakeBuilder::getListWhere($this->tableName);
$orderByColumn = Request::param('orderByColumn') ?? $pk;
$isAsc = Request::param('isAsc') ?? 'desc';
return $model::getList($where, $this->pageSize, [$orderByColumn => $isAsc]);
}
// 构建页面
return TableBuilder::getInstance()
->setUniqueId($pk) // 设置主键
->addColumns($columns) // 添加列表字段数据
->setSearch($search) // 添加头部搜索
->addColumn('right_button', '操作', 'btn') // 启用右侧操作列
->addRightButtons($module->right_button) // 设置右侧操作列
->addTopButtons($module->top_button) // 设置顶部按钮组
->fetch();
}
// 添加
public function add()
{
// 获取字段信息
$columns = MakeBuilder::getAddColumns($this->tableName);
// 获取分组后的字段信息
$groups = MakeBuilder::getAddGroups($this->modelName, $this->tableName, $columns);
// 构建页面
$builder = FormBuilder::getInstance();
$builder->addSelect('group_id', '角色组', '', $this->getAuthGroupOptions(), '', '', '', '', true);
$groups ? $builder->addGroup($groups) : $builder->addFormItems($columns);
return $builder->fetch();
}
// 添加保存
public function addPost()
{
if (Request::isPost()) {
$data = MakeBuilder::changeFormData(Request::except(['file'], 'post'), $this->tableName);
$data['group_id'] = Request::param('group_id');
// 单独校验并去除角色组
if (empty($data['group_id'])) {
$this->error('请选择角色组');
} else {
$groupId = $data['group_id'];
unset($data['group_id']);
}
//单独验证密码
if (empty($data['password'])) {
$this->error('密码不能为空');
}
$result = $this->validate($data, $this->validate);
$data['login_time'] = time();
$data['login_ip'] = Request::ip();
if (true !== $result) {
// 验证失败 输出错误信息
$this->error($result);
} else {
$model = '\app\common\model\\' . $this->modelName;
$result = $model::create($data);
\app\common\model\AuthGroupAccess::create([
'uid' => $result->id,
'group_id' => $groupId
]);
$this->success('添加成功', 'index');
}
}
}
// 修改
public function edit(string $id)
{
$model = '\app\common\model\\' . $this->modelName;
$info = $model::edit($id)->toArray();
// 获取字段信息
$columns = MakeBuilder::getAddColumns($this->tableName, $info);
// 获取分组后的字段信息
$groups = MakeBuilder::getAddGroups($this->modelName, $this->tableName, $columns);
// 获取当前管理员的分组
$groupId = \app\common\model\AuthGroupAccess::where('uid', $info['id'])
->value('group_id');
// 构建页面
$builder = FormBuilder::getInstance();
$builder->addSelect('group_id', '角色组', '', $this->getAuthGroupOptions(), $groupId, '', '', '', true);
$groups ? $builder->addGroup($groups) : $builder->addFormItems($columns);
return $builder->fetch();
}
// 修改保存
public function editPost()
{
if (Request::isPost()) {
$data = MakeBuilder::changeFormData(Request::except(['file'], 'post'), $this->tableName);
$data['group_id'] = Request::param('group_id');
if (!$data['group_id']) {
$this->error('请选择角色组!');
}
if (Session::get('admin.group_id') != 1) {
// 非管理员组不可修改他人信息
if (Session::get('admin.id') != $data['id']) {
$this->error('非管理员组人员不可修改他人信息!', 'index');
}
// 非管理员组不可修改角色组
if (Session::get('admin.group_id') != $data['group_id']) {
$this->error('非管理员组人员不可修改所属角色组!', 'index');
}
}
$where['id'] = $data['id'];
$group_id = $data['group_id'];
unset($data['group_id']);
$result = $this->validate($data,'Admin');
if (true !== $result) {
$this->error($result);
}
\app\common\model\Admin::update($data, $where);
\app\common\model\AuthGroupAccess::update([
'group_id' => $group_id
], ['uid'=>$data['id']]);
$this->success('修改成功!', 'index');
}
}
// 删除
public function del(string $id)
{
if (Request::isPost()) {
if ($id == 1) {
return json(['error' => 1, 'msg' => '超级管理员不可删除!']);
}
if (strpos($id, ',') !== false) {
return $this->selectDel($id);
}
$model = '\app\common\model\\' . $this->modelName;
return $model::del($id);
}
}
// 批量删除
public function selectDel(string $id){
if (Request::isPost()) {
$ids = explode(',',$id);
if (in_array(1, $ids)) {
return json(['error' => 1, 'msg' => '超级管理员不可删除!']);
}
$model = '\app\common\model\\' . $this->modelName;
return $model::selectDel($id);
}
}
//===========================
// 获取角色分组信息
private function getAuthGroupOptions()
{
// 获取角色组
$authGroup = \app\common\model\AuthGroup::where('status', '=', 1)
->select()
->toArray();
$groupOptions = [];
foreach ($authGroup as $k => $v) {
$groupOptions[$v['id']] = $v['title'];
}
return $groupOptions;
}
}

69
app/admin/controller/AdminLog.php

@ -0,0 +1,69 @@
<?php
/**
* +----------------------------------------------------------------------
* | 管理员日志控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/02/03
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class AdminLog extends Base
{
// 验证器
protected $validate = 'AdminLog';
// 当前主表
protected $tableName = 'admin_log';
// 当前主模型
protected $modelName = 'AdminLog';
// 修改
public function edit(string $id)
{
$model = '\app\common\model\\' . $this->modelName;
$info = $model::edit($id)->toArray();
// 获取字段信息
$columns = MakeBuilder::getAddColumns($this->tableName, $info);
// 获取分组后的字段信息
$groups = MakeBuilder::getAddGroups($this->modelName, $this->tableName, $columns);
// 隐藏<显示全部>按钮
$hideShowAll = MakeBuilder::getHideShowAll($this->tableName);
// 构建页面
$builder = FormBuilder::getInstance();
if ($hideShowAll) {
$builder->hideShowAll();
}
$builder->hideBtn(['submit','back']);
$groups ? $builder->addGroup($groups) : $builder->addFormItems($columns);
return $builder->fetch();
}
}

47
app/admin/controller/Article.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 文章模块控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Article extends Base
{
// 验证器
protected $validate = 'Article';
// 当前主表
protected $tableName = 'article';
// 当前主模型
protected $modelName = 'Article';
}

134
app/admin/controller/AuthGroup.php

@ -0,0 +1,134 @@
<?php
/**
* +----------------------------------------------------------------------
* | 角色组管理控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/02/02
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
use think\facade\View;
class AuthGroup extends Base
{
// 验证器
protected $validate = 'AuthGroup';
// 当前主表
protected $tableName = 'auth_group';
// 当前主模型
protected $modelName = 'AuthGroup';
// 列表
public function index()
{
// 获取主键
$pk = MakeBuilder::getPrimarykey($this->tableName);
// 获取列表数据
$columns = MakeBuilder::getListColumns($this->tableName);
// 获取搜索数据
$search = MakeBuilder::getListSearch($this->tableName);
// 获取当前模块信息
$model = '\app\common\model\\' . $this->modelName;
$module = \app\common\model\Module::where('table_name', $this->tableName)->find();
// 搜索
if (Request::param('getList') == 1) {
$where = MakeBuilder::getListWhere($this->tableName);
$orderByColumn = Request::param('orderByColumn') ?? $pk;
$isAsc = Request::param('isAsc') ?? 'desc';
return $model::getList($where, $this->pageSize, [$orderByColumn => $isAsc]);
}
// 检测单页模式
$isSingle = MakeBuilder::checkSingle($this->modelName);
if ($isSingle) {
return $this->jump($isSingle);
}
// 获取新增地址
$addUlr = MakeBuilder::getAddUrl($this->tableName);
// 构建页面
return TableBuilder::getInstance()
->setUniqueId($pk) // 设置主键
->addColumns($columns) // 添加列表字段数据
->setSearch($search) // 添加头部搜索
->addColumn('right_button', '操作', 'btn') // 启用右侧操作列
->addRightButton('info', [
'title' => '权限',
'icon' => 'far fa-check-square',
'class' => 'btn btn-warning btn-xs confirm',
'href' => url('access', ['id' => '__id__'])
]) // 添加额外按钮
->addRightButtons($module->right_button) // 设置右侧操作列
->addTopButtons($module->top_button) // 设置顶部按钮组
->setAddUrl($addUlr) // 设置新增地址
->fetch();
}
//===================================
// 权限
public function access(string $id)
{
// 获取菜单规则
$authRule = \app\common\model\AuthRule::field('id, pid, title')
->order('sort asc')
->select()
->toArray();
// 获取当前组权限并格式化
$rules = \app\common\model\AuthGroup::where('id', $id)->value('rules');
$list = auth($authRule, 0, $rules);
$list[] = array(
"id" => 0,
"pid" => 0,
"title" => "全部",
"open" => true
);
$view = [
'list' => $list
];
View::assign($view);
return View::fetch('auth/group_access');
}
// 权限保存
public function accessPost()
{
$rules = Request::post('rules');
if (empty($rules)) {
return json(['msg' => '请选择权限!', 'error' => 1]);
}
$data = Request::post();
$where['id'] = $data['id'];
if (\app\common\model\AuthGroup::update($data, $where)) {
return json(['msg' => '修改成功!', 'url' => url('index')->__toString(), 'error' => 0]);
} else {
return json(['msg' => '修改失败', 'error' => 1]);
}
}
}

165
app/admin/controller/AuthRule.php

@ -0,0 +1,165 @@
<?php
/**
* +----------------------------------------------------------------------
* | 菜单规则控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/02/03
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class AuthRule extends Base
{
// 验证器
protected $validate = 'AuthRule';
// 当前主表
protected $tableName = 'auth_rule';
// 当前主模型
protected $modelName = 'AuthRule';
// 列表
public function index()
{
// 获取主键
$pk = MakeBuilder::getPrimarykey($this->tableName);
// 获取列表数据
$columns = MakeBuilder::getListColumns($this->tableName);
// 获取搜索数据
$search = MakeBuilder::getListSearch($this->tableName);
// 获取当前模块信息
$model = '\app\common\model\\' . $this->modelName;
$module = \app\common\model\Module::where('table_name', $this->tableName)->find();
// 搜索
if (Request::param('getList') == 1) {
$where = MakeBuilder::getListWhere($this->tableName);
$orderByColumn = Request::param('orderByColumn') ?? $pk;
$isAsc = Request::param('isAsc') ?? 'desc';
return $model::getList($where, $this->pageSize, [$orderByColumn => $isAsc]);
}
// 检测单页模式
$isSingle = MakeBuilder::checkSingle($this->modelName);
if ($isSingle) {
return $this->jump($isSingle);
}
// 获取新增地址
$addUlr = MakeBuilder::getAddUrl($this->tableName);
// 构建页面
return TableBuilder::getInstance()
->setUniqueId($pk) // 设置主键
->addColumns($columns) // 添加列表字段数据
->setSearch($search) // 添加头部搜索
->addColumn('right_button', '操作', 'btn') // 启用右侧操作列
->addRightButton('info', [ // 添加额外按钮
'title' => '添加',
'icon' => 'fa fa-plus',
'class' => 'btn btn-success btn-xs',
'href' => url('add', ['pid' => '__id__'])
])
->addRightButtons($module->right_button) // 设置右侧操作列
->addTopButtons($module->top_button) // 设置顶部按钮组
->setAddUrl($addUlr) // 设置新增地址
->addTopButton('default', [
'title' => '展开/折叠',
'icon' => 'fas fa-exchange-alt',
'class' => 'btn btn-info treeStatus',
'href' => '',
'onclick' => '$.operate.treeStatus()'
]) // 自定义按钮
->setPagination('false') // 关闭分页显示
->setParentIdField('pid') // 设置列表树父id
->fetch();
}
// 添加
public function add(string $pid = '')
{
// 获取字段信息
$columns = MakeBuilder::getAddColumns($this->tableName);
// 获取父ID数据
foreach ($columns as $k => $v) {
if ($v[1] == 'pid') {
$model = '\app\common\model\\' . $this->modelName;
$pidOptions = $model::getPidOptions();
// 设置父ID选项
$columns[$k][4] = $pidOptions;
// 设置父ID默认值
if ($pid) {
$columns[$k][5] = $pid;
}
}
}
// 获取分组后的字段信息
$groups = MakeBuilder::getAddGroups($this->modelName, $this->tableName, $columns);
// 隐藏<显示全部>按钮
$hideShowAll = MakeBuilder::getHideShowAll($this->tableName);
// 构建页面
$builder = FormBuilder::getInstance();
if ($hideShowAll) {
$builder->hideShowAll();
}
$groups ? $builder->addGroup($groups) : $builder->addFormItems($columns);
return $builder->fetch();
}
// 修改
public function edit(string $id)
{
$model = '\app\common\model\\' . $this->modelName;
$info = $model::edit($id)->toArray();
// 获取字段信息
$columns = MakeBuilder::getAddColumns($this->tableName, $info);
// 获取父ID数据
foreach ($columns as $k => $v) {
if ($v[1] == 'pid') {
$model = '\app\common\model\\' . $this->modelName;
$pidOptions = $model::getPidOptions();
$columns[$k][4] = $pidOptions;
}
}
// 获取分组后的字段信息
$groups = MakeBuilder::getAddGroups($this->modelName, $this->tableName, $columns);
// 隐藏<显示全部>按钮
$hideShowAll = MakeBuilder::getHideShowAll($this->tableName);
// 构建页面
$builder = FormBuilder::getInstance();
if ($hideShowAll) {
$builder->hideShowAll();
}
$groups ? $builder->addGroup($groups) : $builder->addFormItems($columns);
return $builder->fetch();
}
}

476
app/admin/controller/Base.php

@ -0,0 +1,476 @@
<?php
/**
* +----------------------------------------------------------------------
* | 基础控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/03/08
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
declare (strict_types=1);
namespace app\admin\controller;
// 引入框架内置类
use think\App;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\facade\Config;
use think\facade\Request;
use think\facade\View;
use think\Response;
use think\Validate;
// 引入表格和表单构建器
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
use app\common\facade\MakeBuilder;
/**
* 控制器基础类
*/
abstract class Base
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中间件
* @var array
*/
protected $middleware = ['app\admin\middleware\Admin'];
/**
* 分页数量
* @var string
*/
protected $pageSize = '';
/**
* 系统设置
* @var array
*/
protected $system = [];
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{
// 每页显示数据量
$this->pageSize = (int)Request::param('pageSize', Config::get('app.page_size'));
// 左侧菜单
$menus = \app\admin\model\Base::getMenus();
View::assign(['menus' => $menus]);
// 面包导航
$auth = new \Auth();
$breadCrumb = $auth->getBreadCrumb();
$breadCrumb = format_bread_crumb($breadCrumb);
View::assign(['breadCrumb' => $breadCrumb]);
// 内容管理,获取栏目列表
if (class_exists('\app\common\model\Cate')) {
$cates = \app\common\model\Cate::getList();
}
View::assign(['cates' => unlimitedForLayer($cates['data'] ?? [])]);
// index应用地址
$domainBind = Config::get('app.domain_bind');
if ($domainBind) {
$domainBindKey = array_search('index', $domainBind);
$domainBindKey = $domainBindKey == '*' ? 'www.' : ($domainBindKey ? $domainBindKey . '.' : '');
$indexUrl = Request::scheme() . '://' . $domainBindKey . Request::rootDomain() . '/';
}
View::assign(['indexUrl' => $indexUrl ?? '/']);
// 查询系统设置
$system = \app\common\model\System::find(1);
$this->system = $system;
View::assign(['system' => $system]);
// pjax单页面模式
if (Request::has('_pjax')) {
View::assign(['pjax' => true]);
} else {
View::assign(['pjax' => false]);
}
// iframe多标签模式
if ($system['display_mode'] == 1) {
if ($this->request->controller() == 'Index' && $this->request->action() == 'index') {
View::assign(['iframe' => false]);
} else {
View::assign(['iframe' => true]);
}
} else {
View::assign(['iframe' => false]);
}
// layer open
if (Request::has('_layer')) {
View::assign(['layer' => true]);
} else {
View::assign(['layer' => false]);
}
}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
list($validate, $scene) = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
//是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
$result = $v->failException(false)->check($data);
if (true !== $result) {
return $v->getError();
} else {
return $result;
}
}
/**
* 操作错误跳转
* @param mixed $msg 提示信息
* @param string $url 跳转的URL地址
* @param mixed $data 返回的数据
* @param integer $wait 跳转等待时间
* @param array $header 发送的Header信息
* @return void
*/
protected function error($msg = '', string $url = null, $data = '', int $wait = 3, array $header = []): Response
{
if (is_null($url)) {
$url = request()->isAjax() ? '' : 'javascript:history.back(-1);';
} elseif ($url) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : app('route')->buildUrl($url)->__toString();
}
$result = [
'code' => 0,
'msg' => $msg,
'data' => $data,
'url' => $url,
'wait' => $wait,
];
$type = (request()->isJson() || request()->isAjax()) ? 'json' : 'html';
if ($type == 'html') {
$response = view(app('config')->get('app.dispatch_error_tmpl'), $result);
} else if ($type == 'json') {
$response = json($result);
}
throw new HttpResponseException($response);
}
/**
* 返回封装后的API数据到客户端
* @param mixed $data 要返回的数据
* @param integer $code 返回的code
* @param mixed $msg 提示信息
* @param string $type 返回数据格式
* @param array $header 发送的Header信息
* @return Response
*/
protected function result($data, int $code = 0, $msg = '', string $type = '', array $header = []): Response
{
$result = [
'code' => $code,
'msg' => $msg,
'time' => time(),
'data' => $data,
];
$type = $type ?: 'json';
$response = Response::create($result, $type)->header($header);
throw new HttpResponseException($response);
}
/**
* 操作成功跳转
* @param mixed $msg 提示信息
* @param string $url 跳转的URL地址
* @param mixed $data 返回的数据
* @param integer $wait 跳转等待时间
* @param array $header 发送的Header信息
* @return void
*/
protected function success($msg = '', string $url = null, $data = '', int $wait = 3, array $header = []): Response
{
if (is_null($url) && isset($_SERVER["HTTP_REFERER"])) {
$url = $_SERVER["HTTP_REFERER"];
} elseif ($url) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : app('route')->buildUrl($url, get_back_url())->__toString();
}
$result = [
'code' => 1,
'msg' => $msg,
'data' => $data,
'url' => $url,
'wait' => $wait,
];
$type = (request()->isJson() || request()->isAjax()) ? 'json' : 'html';
if ($type == 'html') {
$response = view(app('config')->get('app.dispatch_success_tmpl'), $result);
} else if ($type == 'json') {
$response = json($result);
}
throw new HttpResponseException($response);
}
/**
* 跳转页
* @param string $url
* @return Response
*/
protected function jump(string $url = '')
{
if ($this->request->isPjax()) {
return response('<span style="display: none">loading...</span>', 200, ['X-PJAX-URL' => $url]);
} else {
return redirect($url);
}
}
// 列表
public function index()
{
// 获取主键
$pk = MakeBuilder::getPrimarykey($this->tableName);
// 获取列表数据
$columns = MakeBuilder::getListColumns($this->tableName);
// 获取搜索数据
$search = MakeBuilder::getListSearch($this->tableName);
// 获取当前模块信息
$model = '\app\common\model\\' . $this->modelName;
$module = \app\common\model\Module::where('table_name', $this->tableName)->find();
// 搜索
if (Request::param('getList') == 1) {
$where = MakeBuilder::getListWhere($this->tableName);
$orderByColumn = Request::param('orderByColumn') ?? $pk;
$isAsc = Request::param('isAsc') ?? 'desc';
return $model::getList($where, $this->pageSize, [$orderByColumn => $isAsc]);
}
// 检测单页模式
$isSingle = MakeBuilder::checkSingle($this->modelName);
if ($isSingle) {
return $this->jump($isSingle);
}
// 获取新增地址
$addUlr = MakeBuilder::getAddUrl($this->tableName);
// 构建页面
return TableBuilder::getInstance()
->setUniqueId($pk) // 设置主键
->addColumns($columns) // 添加列表字段数据
->setSearch($search) // 添加头部搜索
->addColumn('right_button', '操作', 'btn') // 启用右侧操作列
->addRightButtons($module->right_button) // 设置右侧操作列
->addTopButtons($module->top_button) // 设置顶部按钮组
->setAddUrl($addUlr) // 设置新增地址
->fetch();
}
// 添加
public function add()
{
// 获取字段信息
$columns = MakeBuilder::getAddColumns($this->tableName);
// 获取分组后的字段信息
$groups = MakeBuilder::getAddGroups($this->modelName, $this->tableName, $columns);
// 隐藏<显示全部>按钮
$hideShowAll = MakeBuilder::getHideShowAll($this->tableName);
// 构建页面
$builder = FormBuilder::getInstance();
if ($hideShowAll) {
$builder->hideShowAll();
}
$groups ? $builder->addGroup($groups) : $builder->addFormItems($columns);
return $builder->fetch();
}
// 添加保存
public function addPost()
{
if (Request::isPost()) {
$data = MakeBuilder::changeFormData(Request::except(['file'], 'post'), $this->tableName);
$result = $this->validate($data, $this->validate);
if (true !== $result) {
// 验证失败 输出错误信息
$this->error($result);
} else {
$model = '\app\common\model\\' . $this->modelName;
$result = $model::addPost($data);
if ($result['error']) {
$this->error($result['msg']);
} else {
$this->success($result['msg'], 'index');
}
}
}
}
// 修改
public function edit(string $id)
{
$model = '\app\common\model\\' . $this->modelName;
$info = $model::edit($id)->toArray();
// 获取字段信息
$columns = MakeBuilder::getAddColumns($this->tableName, $info);
// 获取分组后的字段信息
$groups = MakeBuilder::getAddGroups($this->modelName, $this->tableName, $columns);
// 隐藏<显示全部>按钮
$hideShowAll = MakeBuilder::getHideShowAll($this->tableName);
// 构建页面
$builder = FormBuilder::getInstance();
if ($hideShowAll) {
$builder->hideShowAll();
}
$groups ? $builder->addGroup($groups) : $builder->addFormItems($columns);
return $builder->fetch();
}
// 修改保存
public function editPost()
{
if (Request::isPost()) {
$data = MakeBuilder::changeFormData(Request::except(['file'], 'post'), $this->tableName);
$result = $this->validate($data, $this->validate);
if (true !== $result) {
// 验证失败 输出错误信息
$this->error($result);
} else {
$model = '\app\common\model\\' . $this->modelName;
$result = $model::editPost($data);
if ($result['error']) {
$this->error($result['msg']);
} else {
$this->success($result['msg'], 'index');
}
}
}
}
// 删除
public function del(string $id)
{
if (Request::isPost()) {
if (strpos($id, ',') !== false) {
return $this->selectDel($id);
}
$model = '\app\common\model\\' . $this->modelName;
return $model::del($id);
}
}
// 批量删除
public function selectDel(string $id)
{
if (Request::isPost()) {
$model = '\app\common\model\\' . $this->modelName;
return $model::selectDel($id);
}
}
// 排序
public function sort()
{
if (Request::isPost()) {
$data = Request::post();
$model = '\app\common\model\\' . $this->modelName;
return $model::sort($data);
}
}
// 状态变更
public function state(string $id)
{
if (Request::isPost()) {
$model = '\app\common\model\\' . $this->modelName;
return $model::state($id);
}
}
// 导出
public function export()
{
\app\common\model\Base::export($this->tableName, $this->modelName);
}
}

457
app/admin/controller/Cate.php

@ -0,0 +1,457 @@
<?php
/**
* +----------------------------------------------------------------------
* | 栏目管理控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/02/05
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Cate extends Base
{
// 验证器
protected $validate = 'Cate';
// 当前主表
protected $tableName = 'cate';
// 当前主模型
protected $modelName = 'Cate';
// 列表
public function index(){
// 获取主键
$pk = MakeBuilder::getPrimarykey($this->tableName);
// 获取列表数据
$columns = MakeBuilder::getListColumns($this->tableName);
// 获取搜索数据
$search = MakeBuilder::getListSearch($this->tableName);
// 获取当前模块信息
$model = '\app\common\model\\' . $this->modelName;
$module = \app\common\model\Module::where('table_name', $this->tableName)->find();
// 检测单页模式
$isSingle = MakeBuilder::checkSingle($this->modelName);
if ($isSingle) {
return redirect($isSingle);
}
// 搜索
if (Request::param('getList') == 1) {
return $model::getList();
}
// 构建页面
return TableBuilder::getInstance()
->setUniqueId($pk) // 设置主键
->addColumns($columns) // 添加列表字段数据
->setSearch($search) // 添加头部搜索
->addColumn('right_button', '操作', 'btn') // 启用右侧操作列
->addRightButton('info', [ // 添加额外按钮
'title' => '添加',
'icon' => 'fa fa-plus',
'class' => 'btn btn-success btn-xs',
'href' => url('add', ['parentId' => '__id__'])
])
->addRightButtons($module->right_button) // 设置右侧操作列
->addTopButtons($module->top_button) // 设置顶部按钮组
->addTopButton('default', [
'title' => '展开/折叠',
'icon' => 'fas fa-exchange-alt',
'class' => 'btn btn-info treeStatus',
'href' => '',
'onclick' => '$.operate.treeStatus()'
]) // 自定义按钮
->addTopButton('default', [
'title' => '批量新增',
'icon' => 'fa fa-plus',
'class' => 'btn btn-success',
'href' => '',
'onclick' => '$.operate.batchAdd(\'' . url('batchAdd') . '\')'
]) // 自定义按钮
->setPagination('false') // 关闭分页显示
->setParentIdField('parent_id') // 设置列表树父id
->fetch();
}
// 添加
public function add(string $parentId = '')
{
// 获取字段信息
$columns = MakeBuilder::getAddColumns($this->tableName);
// 重置`所属模块`和`上级栏目`的选项
foreach ($columns as $k => $coloumn) {
if ($coloumn[1] == 'module_id') {
$columns[$k][4] = $this->getModuleIds();
}
if ($coloumn[1] == 'parent_id') {
$model = '\app\common\model\\' . $this->modelName;
$pidOptions = $model::getPidOptions();
$columns[$k][4] = $pidOptions;
// 设置父ID默认值
if ($parentId) {
$columns[$k][5] = $parentId;
}
}
}
// 获取分组后的字段信息
$groups = MakeBuilder::getAddGroups($this->modelName, $this->tableName, $columns);
// 构建页面
$builder = FormBuilder::getInstance();
$groups ? $builder->addGroup($groups) : $builder->addFormItems($columns);
return $builder->fetch();
}
// 添加保存
public function addPost()
{
if (Request::isPost()) {
$data = MakeBuilder::changeFormData(Request::except(['file'], 'post'), $this->tableName);
$result = $this->validate($data, $this->validate);
if (true !== $result) {
// 验证失败 输出错误信息
$this->error($result);
} else {
$model = '\app\common\model\\' . $this->modelName;
$result = $model::addPost($data);
if ($result['error']) {
$this->error($result['msg']);
} else {
$this->singleCateInit($data);
$this->success($result['msg'], 'index');
}
}
}
}
// 修改
public function edit(string $id)
{
$model = '\app\common\model\\' . $this->modelName;
$info = $model::edit($id)->toArray();
// 获取字段信息
$columns = MakeBuilder::getAddColumns($this->tableName, $info);
// 重置`所属模块`和`上级栏目`的选项
foreach ($columns as $k => $coloumn) {
if ($coloumn[1] == 'module_id') {
$columns[$k][4] = $this->getModuleIds();
}
if ($coloumn[1] == 'parent_id') {
$model = '\app\common\model\\' . $this->modelName;
$pidOptions = $model::getPidOptions();
$columns[$k][4] = $pidOptions;
// 设置父ID默认值
if ($info['parent_id']) {
$columns[$k][5] = $info['parent_id'];
}
}
}
// 获取分组后的字段信息
$groups = MakeBuilder::getAddGroups($this->modelName, $this->tableName, $columns);
// 构建页面
$builder = FormBuilder::getInstance();
$groups ? $builder->addGroup($groups) : $builder->addFormItems($columns);
return $builder->fetch();
}
// 修改保存
public function editPost()
{
if (Request::isPost()) {
$data = MakeBuilder::changeFormData(Request::except(['file'], 'post'), $this->tableName);
if ($data['id'] == $data['parent_id']) {
$this->error('上级栏目不可以为当前栏目');
}
$result = $this->validate($data, $this->validate);
if (true !== $result) {
// 验证失败 输出错误信息
$this->error($result);
} else {
$model = '\app\common\model\\' . $this->modelName;
$result = $model::editPost($data);
if ($result['error']) {
$this->error($result['msg']);
} else {
$this->success($result['msg'], 'index');
}
}
}
}
// 删除
public function del(string $id)
{
if (Request::isPost()) {
// 删除子分类
$this->delChildsCate($id);
if (strpos($id, ',') !== false) {
return $this->selectDel($id);
}
$model = '\app\common\model\\' . $this->modelName;
return $model::del($id);
}
}
// 批量添加
public function batchAdd()
{
// 额外CSS
$css = '<style>
.form_builder .form-group{margin-bottom: 0}
.form_builder .col-form-label{padding-right: 5px;}
.form_builder .form-control{padding-left: 0.5rem; padding-right: 0.5rem}
.form_builder .js_cates_content .col-form-label{display: none}
.form_builder .js_cates button{display: none}
.form_builder .js_cates_content button{margin-top: 4px}
</style>';
// 额外js
$js = '<script type="text/javascript">
// 增加一行
$(document).on("click", \'.js_add_row\', function () {
var html = $(\'.js_cates\').html();
$(\'.js_cates_content\').append(html);
})
// 刪除一行
$(document).on("click", \'.js_del_row\', function () {
$(this).parent().parent().remove();
})
</script>';
// 添加按钮
$html = '<div class="row dd_input_group"><button type="button" class="btn btn-success btn-sm js_add_row"><i class="fa fa-plus"></i> 增加一行</button></div>';
// 所属模块
$modules = $this->getModuleIds();
$modulesStr = '';
foreach ($modules as $k => $v) {
$modulesStr .= '<option value="' . $k . '">' . $v . '</option>';
}
$html .= '<div class="js_cates">
<div class="row dd_input_group">
<div class="col-2">
<div class="form-group">
<label class="col-form-label is-required">所属模块</label>
<select class="form-control" name="module_id[]"><option value="">请选择</option>' . $modulesStr . '</select>
</div>
</div>';
// 上级栏目
$model = '\app\common\model\\' . $this->modelName;
$pidOptions = $model::getPidOptions();
$pidOptionsStr = '';
foreach ($pidOptions as $k => $v) {
$pidOptionsStr .= '<option value="' . $k . '">' . $v . '</option>';
}
$html .= '<div class="col-2">
<div class="form-group">
<label class="col-form-label">上级栏目</label>
<select class="form-control" name="parent_id[]"><option value="">请选择</option>' . $pidOptionsStr . '</select>
</div>
</div>';
// 栏目名称
$html .= '<div class="col-2">
<div class="form-group">
<label class="col-form-label is-required">栏目名称</label>
<input class="form-control" type="text" name="cate_name[]" placeholder="请输入栏目名称">
</div>
</div>';
// 英文名称
$html .= '<div class="col-2">
<div class="form-group">
<label class="col-form-label">英文名称</label>
<input class="form-control" type="text" name="en_name[]" placeholder="请输入英文名称">
</div>
</div>';
// 栏目目录
$html .= '<div class="col-2">
<div class="form-group">
<label class="col-form-label">栏目目录</label>
<input class="form-control" type="text" name="cate_folder[]" placeholder="请输入栏目目录">
</div>
</div>';
// 排序
$html .= '<div class="col-1">
<div class="form-group">
<label class="col-form-label is-required">排序</label>
<input class="form-control" type="number" name="sort[]" value="50" step="1">
</div>
</div>';
// 删除行
$html .= '<div class="col-1">
<button type="button" class="btn btn-success btn-sm js_del_row"><i class="fa fa-times"></i></button>
</div>';
$html .= '</div></div><div class="js_cates_content"></div>';
// 构建页面
$builder = FormBuilder::getInstance();
$builder->setExtraCss($css)
->setExtraJs($js)
->addHtml($html);
return $builder->fetch();
}
// 批量添加保存
public function batchAddPost()
{
if (Request::isPost()) {
$data = Request::except(['file'], 'post');
if ($data) {
$dataNew = [];
for ($i = 0; $i < count($data['module_id']); $i++) {
if (empty($data['module_id'][$i]) || empty($data['cate_name'][$i]) || empty($data['sort'][$i])) {
$this->error('所属模块、栏目名称和排序不可为空');
}
$dataNew[] = [
'module_id' => $data['module_id'][$i],
'parent_id' => $data['parent_id'][$i],
'cate_name' => $data['cate_name'][$i],
'en_name' => $data['en_name'][$i],
'cate_folder' => $data['cate_folder'][$i],
'sort' => $data['sort'][$i],
'status' => 1,
'summary' => '',
];
}
foreach ($dataNew as $k => $v) {
$result = $this->validate($v, $this->validate);
if (true !== $result) {
// 验证失败 输出错误信息
$this->error($result);
} else {
$model = '\app\common\model\\' . $this->modelName;
$result = $model::addPost($v);
if ($result['error']) {
$this->error($result['msg']);
} else {
$this->singleCateInit($v);
}
}
}
$this->success($result['msg'], 'index');
}
}
}
// =====================
// 获取CMS模块
private function getModuleIds()
{
$modules = \app\common\model\Module::where('table_type', 1)
->field('id,module_name')
->select()
->toArray();
$result = [];
foreach ($modules as &$module) {
$result[$module['id']] = $module['module_name'];
}
return $result;
}
/**
* 删除分类时删除子分类和子分类的数据
* @param string $id
* @throws \Exception
*/
private function delChildsCate(string $id)
{
// 多选时重新调用
if (strpos($id, ',') !== false) {
$idArr = explode(',', $id);
foreach ($idArr as $k => $v) {
$this->delChildsCate($v);
}
}
// 查找当前分类的所有子分类
$cate = \app\common\model\Cate::select()->toArray();
$ids = getChildsId($cate, $id);
foreach ($ids as $k => $v) {
// 删除一个分类的内容
$this->delCateContent($v['id'], $v['module_id']);
// 删除一个分类
\app\common\model\Cate::where('id', '=', $v['id'])->delete();
}
// 查找当前分类信息并尝试删除
$cateOn = \app\common\model\Cate::find($id);
if ($cateOn) {
// 删除一个分类的内容
$this->delCateContent($cateOn['id'], $cateOn['module_id']);
}
}
/**
* 删除某个分类的内容
* @param string $cateId
* @param string $moduleId
* @return bool
*/
private function delCateContent(string $cateId, string $moduleId)
{
$module = \app\common\model\Module::find($moduleId);
if ($module) {
$model = '\app\common\model\\' . $module->model_name;
return $model::where('cate_id', $cateId)->delete();
} else {
return false;
}
}
/**
* 单页模块栏目新增时初始化操作
* @param array $data
* @return bool
*/
private function singleCateInit(array $data = [])
{
if ($data['module_id'] == '18') {
$cate = \app\common\model\Cate::order('id', 'desc')->limit(1)->select()->toArray();
if (count($cate) > 0) {
$data = [
'sort' => 50,
'status' => 1,
'cate_id' => $cate[0]['id'],
'title' => $cate[0]['cate_name'],
'content' => '',
];
\app\common\model\Page::create($data);
return true;
}
}
return false;
}
}

241
app/admin/controller/Config.php

@ -0,0 +1,241 @@
<?php
/**
* +----------------------------------------------------------------------
* | 配置信息控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/01/21
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\builder\FormBuilder;
// 引入阿里云SDK
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
class Config extends Base
{
// 邮件配置
public function email(){
$smtp = \app\common\model\Config::where('inc_type','=','smtp')
->select();
$info = convert_arr_kv($smtp,'name','value');
return FormBuilder::getInstance()
->addText('smtp_server', '服务器')
->addText('smtp_port', 'SMTP端口')
->addText('email_id', '发件人')
->addText('smtp_user', '发件邮箱')
->addPassword('smtp_pwd', '身份验证码')
->addText('regis_smtp_enable', '标题')
->addText('test_eamil', '测试邮箱')
->addEditor('test_eamil_info', '测试邮件内容', '', '', '100')
->setFormData($info)
->setFormUrl(url('emailPost'))
->hideBtn('back')
->addBtn('<button type="button" id="test_email" class="btn btn-flat btn-info ">测试发送</button>')
->setExtraHtml($this->getEmailExtraHtml(), 'content_bottom')
->setPageTips('<div style="line-height: 32px;float: left">系统采用SMTP方式发送邮件</div>', 'success', 'search')
->hideShowAll()
->fetch();
}
// 邮件配置保存
public function emailPost()
{
if (Request::isPost()) {
$data = Request::post();
foreach ($data as $k => $v) {
$result = \app\common\model\Config::where([['name', '=', $k], ['inc_type', '=', 'smtp']])->find();
if ($k == 'smtp_pwd') {
if (!empty($v)) {
$result->value = $v;
}
} else {
$result->value = $v;
}
$result->save();
}
$this->success('修改成功', 'email');
}
}
// 测试邮件发送
public function emailSend(){
$sender = Request::param('email');
//检查是否邮箱格式
if (!is_email($sender)) {
return json(['error' => 1, 'msg' => '测试邮箱码格式有误']);
}
$data = \app\common\model\Config::where('inc_type','smtp')
->select();
$config = convert_arr_kv($data,'name','value');
$content = $config['test_eamil_info'];
//所有项目必须填写
if (empty($config['smtp_server']) || empty($config['smtp_port']) || empty($config['smtp_user']) || empty($config['smtp_pwd'])) {
return json(['error' => 1, 'msg' => '请完善邮件配置信息!']);
}
$send = send_email($sender, '测试邮件',$content);
if ($send) {
return ['error' => 0, 'msg' => '邮件发送成功!'];
} else {
return ['error' => 1, 'msg' => '邮件发送失败!'];
}
}
// 获取邮件配置额外HTML
private function getEmailExtraHtml()
{
$str = '<script type="text/javascript">
$("#test_email").click(function () {
var url = "' . url('emailSend') . '";
var email = $("input[name=\'test_eamil\']").val();
$.modal.confirm(\'确定要发送吗?如有修改请先提交保存!\', function () {
$.post(url,{email:email},function(result){
if(result.error == 0){
$.modal.alertSuccess(result.msg);
}else{
$.modal.alertError(result.msg);
}
},\'json\');
})
})
</script>
';
return $str;
}
// ==========================================
// 短信配置
public function sms(){
$smtp = \app\common\model\Config::where('inc_type','=','sms')
->select();
$info = convert_arr_kv($smtp,'name','value');
return FormBuilder::getInstance()
->addText('accessKeyId', 'AccessKey ID', '
<a href="https://help.aliyun.com/document_detail/53045.html" target="_blank">【创建】</a>
<a href="https://usercenter.console.aliyun.com/#/manage/ak" target="_blank">【查看】</a>')
->addText('accessKeySecret', '密钥secret')
->addText('signName', '签名名称', '
<a href="https://help.aliyun.com/document_detail/108072.html" target="_blank">【签名简介】</a>
<a href="https://dysms.console.aliyun.com/dysms.htm#/domestic/text/sign" target="_blank">【查看签名】</a>')
->addText('templateCode', '模版CODE', '
<a href="https://dysms.console.aliyun.com/dysms.htm#/domestic/text/template" target="_blank">【查看模版】</a>')
->addText('test_mobile', '测试手机')
->setFormData($info)
->setFormUrl(url('smsPost'))
->hideBtn('back')
->addBtn('<button type="button" id="test_sms" class="btn btn-flat btn-info ">测试发送</button>')
->setExtraHtml($this->getSmsExtraHtml(), 'content_bottom')
->setPageTips('<div style="line-height: 32px;float: left">系统采用阿里云短信服务发送短信 <a class="btn btn-flat btn-primary m-r-10" href="https://help.aliyun.com/document_detail/101346.html" target="_blank">查看错误码</a><a class="btn btn-flat btn-primary" href="https://help.aliyun.com/document_detail/59210.html" target="_blank">使用指引</a></div>', 'success', 'search')
->hideShowAll()
->fetch();
}
// 短信配置保存
public function smsPost()
{
if (Request::isPost()) {
$data = Request::post();
foreach ($data as $k => $v) {
\app\common\model\Config::where([
['name', '=', $k], ['inc_type', '=', 'sms']
])
->update(['value' => $v]);
}
$this->success('保存成功', 'sms');
}
}
// 测试短信发送
public function smsSend()
{
$data = \app\common\model\Config::where('inc_type', 'sms')->select();
$config = convert_arr_kv($data, 'name', 'value');
// 生成验证码
$code = json_encode(['code' => rand(1000, 9999)]);
// 新版发送
AlibabaCloud::accessKeyClient($config['accessKeyId'], $config['accessKeySecret'])
->regionId('cn-hangzhou')
->asDefaultClient();
try {
$result = AlibabaCloud::rpc()
->product('Dysmsapi')
// ->scheme('https') // https | http
->version('2017-05-25')
->action('SendSms')
->method('POST')
->host('dysmsapi.aliyuncs.com')
->options([
'query' => [
'RegionId' => "cn-hangzhou",
'PhoneNumbers' => $config['test_mobile'],
'SignName' => $config['signName'],
'TemplateCode' => $config['templateCode'],
'TemplateParam' => $code,
],
])
->request();
$resultArr = $result->toArray();
if ($resultArr['Code'] == 'OK') {
return json(['error' => 0, 'msg' => '发送成功']);
} else {
return json(['error' => 1, 'msg' => $resultArr['Message']]);
}
} catch (ClientException $e) {
return json(['error' => 1, 'msg' => $e->getErrorMessage()]);
} catch (ServerException $e) {
return json(['error' => 1, 'msg' => $e->getErrorMessage()]);
}
}
// 获取短信配置额外HTML
private function getSmsExtraHtml(){
$str = '<script type="text/javascript">
$("#test_sms").click(function () {
var url = "' . url('smsSend') . '";
var mobile = $("input[name=\'mobile\']").val();
$.modal.confirm(\'确定要发送吗?如有修改请先提交保存!\', function () {
$.post(url,{mobile:mobile},function(result){
if(result.error == 0){
$.modal.alertSuccess(result.msg);
}else{
$.modal.alertError(result.msg);
}
},\'json\');
})
})
</script>
';
return $str;
}
}

313
app/admin/controller/Database.php

@ -0,0 +1,313 @@
<?php
/**
* +----------------------------------------------------------------------
* | 数据库备份控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/01/31
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
use think\facade\Request;
use \tp5er\Backup;
// 引入表格构建器
use app\common\builder\TableBuilder;
class Database extends Base
{
protected $db = '', $datadir;
function initialize(){
parent::initialize();
$this->config=array(
'path' => './Data/', // 数据库备份路径
'part' => 20971520, // 数据库备份卷大小
'compress' => 0, // 数据库备份文件是否启用压缩 0不压缩 1 压缩
'level' => 9 // 数据库备份文件压缩级别 1普通 4 一般 9最高
);
$this->db = new Backup($this->config);
}
// 数据列表
public function database()
{
// 设置主键
$pk = 'name';
// 字段信息
$columns = [
['name' , '数据表'],
['engine', '存储引擎'],
//['version', '版本'],
['row_format', '行格式'],
['rows', '行数', '', '', '', '', 'true'],
//['avg_row_length', '平均每行包括的字节数'],
['data_size', '字节数', '', '', '', '', 'true'],
['data_length', '数据量'],
//['max_data_length', '可容纳的最大数据量'],
//['index_length', '索引占用磁盘的空间大小'],
//['data_free', '已经分配,但目前没有使用的空间'],
//['auto_increment', 'auto_increment'],
['comment', '额外信息'],
['create_time', '创建时间'],
['update_time', '更新时间'],
//['check_time', '最后一次检查表的时间'],
//['collation', '表的默认字符集和字符排序规则'],
//['checksum', '整个表的实时校验和'],
//['create_options', '创建表时指定的其他选项'],
];
// 数据信息
$list = $this->db->dataList();
// 计算总大小
$total = 0;
foreach ($list as $k => $v) {
$total += $v['data_length'];
$list[$k]['data_size'] = $v['data_length'];
$list[$k]['data_length'] = format_bytes($v['data_length']);
}
// 提示信息
$pageTips = '数据库中共有 ' . count($list) . ' 张表,共计 ' . format_bytes($total);
// 可搜索的字段
$search = [
['text', 'name', '数据表', 'LIKE'],
];
// 搜索
if (Request::param('getList') == 1) {
// 排序规则
$orderByColumn = Request::param('orderByColumn') ?? $pk;
$isAsc = Request::param('isAsc') ?? 'desc';
$isAsc = $isAsc == 'desc' ? SORT_DESC : SORT_ASC;
// 排序处理
$date = array_column($list, $orderByColumn);
array_multisort($date, $isAsc, $list);
if (Request::param('name')) {
foreach ($list as $k => $v) {
if (strpos($v['name'], Request::param('name')) == false) {
unset($list[$k]);
}
}
}
// 渲染输出
$result = [
'total' => count($list),
'per_page' => 1000,
'current_page' => 1,
'last_page' => 1,
'data' => $list,
];
return $result;
}
// 构建页面
return TableBuilder::getInstance()
->setUniqueId($pk) // 设置主键
->addColumns($columns) // 添加列表字段数据
->setSearch($search) // 添加头部搜索
->setPageTips($pageTips, 'warning') // 提示信息
->setPagination('false') // 关闭分页显示
->addTopButtons([
'backup' => [
'title' => '备份',
'icon' => 'fa fa-server',
'class' => 'btn btn-success multiple disabled',
'href' => '',
'target' => '',
'onclick' => '$.operate.database(\''.url('backup').'\' , \'备份\')',
],
'optimize' => [
'title' => '优化',
'icon' => 'fa fa-medkit',
'class' => 'btn btn-primary multiple disabled',
'href' => '',
'target' => '',
'onclick' => '$.operate.database(\''.url('optimize').'\', \'优化\')',
],
'repair' => [
'title' => '修复',
'icon' => 'fa fa-user-md',
'class' => 'btn btn-warning multiple disabled',
'href' => '',
'target' => '',
'onclick' => '$.operate.database(\''.url('repair').'\', \'修复\')',
],
])
->fetch();
}
// 备份
public function backup()
{
$tables = Request::param('id');
if (!empty($tables)) {
$tables = explode(',', $tables);
foreach ($tables as $table) {
$this->db->setFile()->backup($table, 0);
}
return json(['error' => 0, 'msg' => '备份成功!']);
} else {
return json(['error' => 1, 'msg' => '请选择要备份的表!']);
}
}
// 优化
public function optimize() {
$tables = Request::param('id');
if (empty($tables)) {
return json(['error'=>1,'msg'=>'请选择要优化的表!']);
}
$tables = explode(',',$tables);
if ($this->db->optimize($tables)) {
return json(['error'=>0, 'msg'=>'数据表优化成功!']);
} else {
return json(['error'=>1, 'msg'=>'数据表优化出错请重试!']);
}
}
// 修复
public function repair() {
$tables = Request::param('id');
if (empty($tables)) {
return json(['error'=>1,'msg'=>'请选择要修复的表!']);
}
$tables = explode(',',$tables);
if ($this->db->repair($tables)) {
return json(['error'=>0, 'msg'=>'数据表修复成功!']);
} else {
return json(['error'=>1, 'msg'=>'数据表修复出错请重试!']);
}
}
// ===========================
// 还原
public function restore()
{
$list = $this->db->fileList();
$total = 0;
$listNew = [];
foreach ($list as $k => $v) {
$total += $v['size_num'];
$listNew[] = $list[$k];
}
$list = $listNew;
array_multisort(array_column($list, 'time'), SORT_DESC, $list);
// 设置主键
$pk = 'time';
// 字段信息
$columns = [
['time', '编号',],
['name', '文件名称'],
['part', '分卷'],
['size', '文件大小'],
['compress', '分隔符'],
['addtime', '创建时间', '', '', '', '', 'true'],
];
// 可搜索的字段
$search = [
// ['text', 'name', '文件名称', 'LIKE'],
];
// 提示信息
$pageTips = '备份文件列表中共有 ' . count($list) . ' 个文件,共计 ' . format_bytes($total);
// 搜索
if (Request::param('getList') == 1) {
// 排序规则
$orderByColumn = Request::param('orderByColumn') ?? $pk;
$isAsc = Request::param('isAsc') ?? 'desc';
$isAsc = $isAsc == 'desc' ? SORT_DESC : SORT_ASC;
// 排序处理
$date = array_column($list, $orderByColumn);
array_multisort($date, $isAsc, $list);
if (Request::param('name')) {
foreach ($list as $k => $v) {
if (strpos($v['name'], Request::param('name')) == false) {
unset($list[$k]);
}
}
}
// 渲染输出
$result = [
'total' => count($list),
'per_page' => 1000,
'current_page' => 1,
'last_page' => 1,
'data' => $list,
];
return $result;
}
// 构建页面
return TableBuilder::getInstance()
->setUniqueId($pk)// 设置主键
->addColumns($columns)// 添加列表字段数据
->setSearch($search)// 添加头部搜索
->setPageTips($pageTips, 'warning')// 提示信息
->setPagination('false')// 关闭分页显示
->addColumn('right_button', '操作', 'btn')
->addTopButtons('del')
->addRightButton('info', [
'title' => '恢复',
'icon' => 'fa fa-exclamation-triangle',
'class' => 'btn btn-flat btn-warning btn-xs confirm',
'href' => url('import', ['id' => '__time__'])
]) // 添加额外按钮
->addRightButton('info', [
'title' => '下载',
'icon' => 'fa fa-download',
'target'=> '_blank',
'class' => 'btn btn-flat btn-success btn-xs confirm',
'href' => url('downFile', ['id' => '__time__'])
]) // 添加额外按钮
->addRightButton('delete')
->fetch();
}
// 执行还原数据库操作
public function import(string $id)
{
$list = $this->db->getFile('timeverif', $id);
$this->db->setFile($list)->import(1);
return json(['error' => 0, 'msg' => '还原成功!']);
}
// 下载
public function downFile(string $id)
{
$this->db->downloadFile($id);
}
// 删除sql文件
public function del(string $id)
{
if (Request::isPost()) {
if (strpos($id, ',') !== false) {
$idArr = explode(',', $id);
foreach ($idArr as $k => $v) {
$this->db->delFile($v);
}
return json(['error' => 0, 'msg' => "删除成功!"]);
}
if ($this->db->delFile($id)) {
return json(['error' => 0, 'msg' => "删除成功!"]);
} else {
return json(['error' => 1, 'msg' => "备份文件删除失败,请检查文件权限!"]);
}
}
}
}

47
app/admin/controller/Debris.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 碎片管理控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Debris extends Base
{
// 验证器
protected $validate = 'Debris';
// 当前主表
protected $tableName = 'debris';
// 当前主模型
protected $modelName = 'Debris';
}

82
app/admin/controller/Demo.php

@ -0,0 +1,82 @@
<?php
/**
* +----------------------------------------------------------------------
* | 演示控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/02/09
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
use think\facade\Request;
use think\facade\View;
class Demo extends Base
{
// 按钮
public function button()
{
return View::fetch();
}
// 图标
public function icons()
{
return View::fetch();
}
// 常规
public function general()
{
return View::fetch();
}
// 模态框
public function modals()
{
return View::fetch();
}
// 时间轴
public function timeline()
{
return View::fetch();
}
// 弹层
public function layer()
{
return View::fetch();
}
// layer表单
public function layerForm()
{
return View::fetch();
}
// 模拟提交
public function addPost()
{
$this->success('提交成功', 'layer');
}
}

47
app/admin/controller/Dictionary.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 字典数据控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Dictionary extends Base
{
// 验证器
protected $validate = 'Dictionary';
// 当前主表
protected $tableName = 'dictionary';
// 当前主模型
protected $modelName = 'Dictionary';
}

47
app/admin/controller/DictionaryType.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 字典类型控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class DictionaryType extends Base
{
// 验证器
protected $validate = 'DictionaryType';
// 当前主表
protected $tableName = 'dictionary_type';
// 当前主模型
protected $modelName = 'DictionaryType';
}

47
app/admin/controller/Download.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 下载模块控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Download extends Base
{
// 验证器
protected $validate = 'Download';
// 当前主表
protected $tableName = 'download';
// 当前主模型
protected $modelName = 'Download';
}

799
app/admin/controller/Field.php

@ -0,0 +1,799 @@
<?php
/**
* +----------------------------------------------------------------------
* | 字段控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/01/21
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
use think\facade\Config;
use think\facade\Db;
use think\facade\Request;
use think\facade\View;
// 引入构建器
use app\common\builder\TableBuilder;
use app\common\facade\MakeBuilder;
class Field extends Base
{
// 验证器
protected $validate = 'field';
// 当前主表
protected $tableName = 'field';
// 当前主模型
protected $modelName = 'Field';
// 列表
public function index()
{
// 获取主键
$pk = MakeBuilder::getPrimarykey($this->tableName);
// 获取列表数据
$columns = MakeBuilder::getListColumns($this->tableName);
// 获取搜索数据
$search = MakeBuilder::getListSearch($this->tableName);
// 搜索
if (Request::param('getList') == 1) {
$where = MakeBuilder::getListWhere($this->tableName);
$orderByColumn = Request::param('orderByColumn') ?? $pk;
$isAsc = Request::param('isAsc') ?? 'desc';
$model = '\app\common\model\\' . $this->modelName;
return $model::getList($where, $this->pageSize, [$orderByColumn => $isAsc]);
}
// 构建页面
return TableBuilder::getInstance()
->setUniqueId($pk) // 设置主键
->addColumns($columns) // 添加列表字段数据
->setSearch($search) // 添加头部搜索
->addColumn('right_button', '操作', 'btn') // 启用右侧操作列
->addRightButtons(['edit', 'delete']) // 设置右侧操作列
->addTopButtons(['add', 'edit', 'del']) // 设置顶部按钮组
->setExtraJs($this->getIndexExtraJs()) // 设置额外JS
->fetch();
}
/**
* 添加
* @param int $moduleId 模块(表)ID
* @return string
*/
public function add(int $moduleId = 0)
{
// 获取所有模块
$modules = \app\common\model\Module::field('id,module_name,table_name,table_comment')
->select();
// 获取所有字典类型
$dictTypes = \app\common\model\DictionaryType::field('id,dict_name, remark')
->where('status', 1)
->order('sort asc, id desc')
->select();
$view = [
'module_id' => $moduleId,
'info' => null,
'fieldInfo' => null,
'modules' => $modules,
'dictTypes' => $dictTypes,
'groups' => [],
];
View::assign($view);
return View::fetch();
}
/**
* 添加/修改时字段变更后重新加载配置信息
* @param int $moduleId 模块(表)ID
* @param string $type 类型
* @param string $field 字段(编辑字段时需传递该参数)
* @return string
*/
public function changeType(int $moduleId, string $type, string $field = '')
{
if (Request::isPost()) {
if (Request::param('isajax')) {
// 调用字段设置模版
View::assign(Request::param());
// 传递field说明是编辑字段,编辑字段需要调取当前字段的配置信息
if (!empty($field)) {
$fieldInfo = \app\common\model\Field::where('module_id', $moduleId)
->where('field', '=', $field)
->find();
$fieldInfo['setup'] = string2array($fieldInfo['setup']);
} else {
$fieldInfo = null;
}
$view = [
'fieldInfo' => $fieldInfo,
];
View::assign($view);
return View::fetch('changeType');
}
}
}
// 添加保存
public function addPost()
{
if (Request::isPost()) {
$data = MakeBuilder::changeFormData(Request::except(['file'], 'post'), $this->tableName);
// 验证数据
$result = $this->validate($data, 'field');
if (true !== $result) {
$this->error($result);
}
// 查询字段是否已录入
$hasIn = \app\common\model\Field::where('field', $data['field'])
->where('module_id', $data['module_id'])
->count();
if ($hasIn) {
$this->error('该模块中已存在字段' . $data['field']);
}
// 查询字段是否已在表中存在
$name = \app\common\model\Module::where('id', '=', $data['module_id'])->value('table_name');
$tablename = Config::get('database.connections.mysql.prefix') . $name;
if ($this->_iset_field($tablename, $data['field'])) {
//$this->error($tablename . '表已存在[' . $data['field'] . ']字段');
} else {
// 获取字段sql
$addfieldsql = $this->get_tablesql($data, 'add');
}
if (isset($data['setup'])) {
$data['setup'] = array2string($data['setup']);
}
$model = Db::name('field');
if ($model->insert($data) !== false) {
// 数据库已存在字段时不再执行字段操作
if (isset($addfieldsql) && !empty($addfieldsql)) {
if (is_array($addfieldsql)) {
foreach ($addfieldsql as $sql) {
try {
Db::execute($sql);
} catch (\Exception $e) {
$this->error($e->getMessage() . '<br><br>[SQL]: ' . $sql);
}
}
} else {
try {
Db::execute($addfieldsql);
} catch (\Exception $e) {
$this->error($e->getMessage() . '<br><br>[SQL]: ' . $addfieldsql);
}
}
}
$this->success('添加成功!', url('index', array('module_id' => $data['module_id'])));
} else {
$this->error('添加失败!');
}
}
}
// 修改
public function edit(string $id)
{
// 获取所有模块
$modules = \app\common\model\Module::field('id,module_name,table_name,table_comment')
->select()->toArray();
// 获取所有字典类型
$dictTypes = \app\common\model\DictionaryType::field('id,dict_name, remark')
->order('sort asc, id desc')
->select();
// 获取所有字段分组
$groups = \app\common\model\FieldGroup::order('sort asc,id desc')
->select()
->toArray();
// 格式化字段分组中的分组名称,避免重复展示
foreach ($groups as $k => $v) {
foreach ($modules as $kk => $vv) {
if ($vv['id'] == $v['module_id']) {
$v['group_name'] = $vv['module_name'] . ' - ' . $v['group_name'];
break;
}
}
$groups[$k]['group_name'] = $v['group_name'];
}
$fieldInfo = \app\common\model\Field::where('id', '=', $id)->find();
if ($fieldInfo['setup']) {
$fieldInfo['setup'] = string2array($fieldInfo['setup']);
}
$view = [
'module_id' => $fieldInfo['module_id'],
'info' => $fieldInfo,
'modules' => $modules,
'dictTypes' => $dictTypes,
'groups' => $groups,
];
View::assign($view);
return View::fetch('add');
}
// 修改保存
public function editPost()
{
if (Request::isPost()) {
$data = MakeBuilder::changeFormData(Request::except(['old_field']), $this->tableName);
$oldfield = Request::param('old_field');
// 验证数据
$result = $this->validate($data, 'field');
if (true !== $result) {
$this->error($result);
}
$data['is_list'] = $data['is_list'] ?? 0;
$data['is_add'] = $data['is_add'] ?? 0;
$data['is_edit'] = $data['is_edit'] ?? 0;
$data['is_search'] = $data['is_search'] ?? 0;
$data['is_sort'] = $data['is_sort'] ?? 0;
// 查询字段是否已在表中存在
if (strpos($data['field'], '.') === false) {
$name = \app\common\model\Module::where('id', '=', $data['module_id'])->value('table_name');
$tablename = Config::get('database.connections.mysql.prefix') . $name;
// 新的字段已被存在于表中
if ($this->_iset_field($tablename, $data['field']) && $oldfield != $data['field']) {
$this->error($tablename . '表已存在[' . $data['field'] . ']字段');
}
// 旧的字段不存在于表中
if ($this->_iset_field($tablename, $oldfield) == false) {
$this->error($tablename . '表不存在[' . $oldfield . ']字段');
}
}
$editfieldsql = $this->get_tablesql(Request::post(), 'edit');
if (array_key_exists("setup", $data) && $data['setup']) {
$data['setup'] = array2string($data['setup']);
}
$model = Db::name('field');
if (false !== $model->update($data)) {
if (Request::param('execute_sql', 0) == 1 && !empty($editfieldsql)) {
if (is_array($editfieldsql)) {
foreach ($editfieldsql as $sql) {
try {
Db::execute($sql);
} catch (\Exception $e) {
$this->error($e->getMessage() . '<br><br>[SQL]: ' . $sql);
}
}
} else {
try {
Db::execute($editfieldsql);
} catch (\Exception $e) {
$this->error($e->getMessage() . '<br><br>[SQL]: ' . $editfieldsql);
}
}
}
$this->success('修改成功!', 'index');
} else {
$this->error('修改失败!');
}
}
}
// 状态变更
public function state(string $id, string $field = '')
{
if (Request::isPost()) {
// 其他字段变更
if ($field) {
$alowField = ['is_add', 'is_edit', 'is_list', 'is_search', 'is_sort', 'required'];
if (in_array($field, $alowField)) {
$model = '\app\common\model\\' . $this->modelName;
$info = $model::find($id);
$value = $info[$field] == 1 ? 0 : 1;
$info[$field] = $value;
$info->save();
return json(['error' => 0, 'msg' => '修改成功!']);
}
}
$model = '\app\common\model\\' . $this->modelName;
return $model::state($id);
}
}
// 删除
public function del(string $id)
{
if (Request::isPost()) {
if (strpos($id, ',') !== false) {
return $this->selectDel($id);
}
$r = Db::name('field')->find($id);
if ($r) {
//删除字段表中的记录
Db::name('field')->delete($id);
}
$moduleId = $r['module_id'];
$field = $r['field'];
$prefix = Config::get('database.connections.mysql.prefix');
$name = Db::name('module')
->where('id', '=', $moduleId)
->value('table_name');
$tableName = $prefix . $name;
//实际查询表中是否有该字段
if ($this->_iset_field($tableName, $field)) {
Db::execute("ALTER TABLE `{$tableName}` DROP `$field`");
}
return json(['error' => 0, 'msg' => '删除成功!']);
}
}
// 批量删除
public function selectDel(string $id)
{
$ids = explode(',', $id);
foreach ($ids as $k => $v) {
$r = Db::name('field')->find($v);
if ($r) {
// 删除字段表中的记录
Db::name('field')->delete($r['id']);
}
$moduleId = $r['module_id'];
$field = $r['field'];
$prefix = Config::get('database.connections.mysql.prefix');
$name = Db::name('module')
->where('id', '=', $moduleId)
->value('table_name');
$tableName = $prefix . $name;
// 实际查询表中是否有该字段
if ($this->_iset_field($tableName, $field)) {
Db::execute("ALTER TABLE `{$tableName}` DROP `$field`");
}
}
return json(['error' => 0, 'msg' => '删除成功!']);
}
//============================================
/**
* 获取要执行的sql
* @param array $info 字段信息
* @param string $do 操作类型[add/edit]
* @return array|string
*/
protected function get_tablesql(array $info, string $do = 'add')
{
$comment = $info['name'];
$type = $info['type'];
if (isset($info['setup']['fieldtype'])) {
$fieldtype = strtoupper($info['setup']['fieldtype']);
}
$moduleid = $info['module_id'];
$default = $info['setup']['default'] ?? '';
$field = $info['field'];
// 字段包含.时不创建字段
if (strpos($field, '.') !== false) {
return '';
}
$module = \app\common\model\Module::find($moduleid);
$name = $module->table_name;
$pk = $module->pk ?: 'id';
$tablename = Config::get('database.connections.mysql.prefix') . $name;
$maxlength = intval($info['maxlength']);
$minlength = intval($info['minlength']);
$numbertype = $info['setup']['numbertype'] ?? '1'; // 是否包含负数
if ($do == 'add') {
$do = ' ADD ';
} else {
$oldfield = $info['old_field'];
$do = " CHANGE `" . $oldfield . "` ";
}
// text,textarea,radio,checkbox,date,time,datetime,daterange,tag,number,password,select,select2,image,images,file,files,editor,hidden,color
switch ($type) {
case 'text':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
case 'textarea':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
case 'radio':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
$default = $default !== '' ? intval($default) : 0;
if (!$maxlength) {
$maxlength = 10;
}
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) " . ($numbertype == 1 ? 'UNSIGNED' : '') . " NOT NULL DEFAULT '$default' COMMENT '$comment'";
}
break;
case 'checkbox':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
if (!$maxlength) {
$maxlength = 10;
}
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) " . ($numbertype == 1 ? 'UNSIGNED' : '') . " NOT NULL DEFAULT '$default' COMMENT '$comment'";
}
break;
case 'date':
$fieldtype = $fieldtype ?? 'INT';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
if (!$maxlength) {
$maxlength = 10;
}
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) " . ($numbertype == 1 ? 'UNSIGNED' : '') . " NOT NULL DEFAULT '$default' COMMENT '$comment'";
}
break;
case 'time':
$fieldtype = $fieldtype ?? 'INT';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
if (!$maxlength) {
$maxlength = 10;
}
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) " . ($numbertype == 1 ? 'UNSIGNED' : '') . " NOT NULL DEFAULT '$default' COMMENT '$comment'";
}
break;
case 'datetime':
$fieldtype = $fieldtype ?? 'INT';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
if (!$maxlength) {
$maxlength = 10;
}
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) " . ($numbertype == 1 ? 'UNSIGNED' : '') . " NOT NULL DEFAULT '$default' COMMENT '$comment'";
}
break;
case 'daterange':
if (!$maxlength) {
$maxlength = 50;
}
$maxlength = min($maxlength, 255);
$fieldtype = $fieldtype ?? 'VARCHAR';
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
break;
case 'tag':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
case 'number':
$fieldtype = $fieldtype ?? 'INT';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
$default = $default !== '' ? intval($default) : 0;
if (!$maxlength) {
$maxlength = 10;
}
if ($fieldtype == 'FLOAT' || $fieldtype == 'DECIMAL' || $fieldtype == 'DOUBLE') {
$point = isset($info['setup']['point']) && $info['setup']['point'] !== '' ? $info['setup']['point'] : '0';
$maxlength = $maxlength . ',' . $point;
}
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) " . ($numbertype == 1 ? 'UNSIGNED' : '') . " NOT NULL DEFAULT {$default} COMMENT '$comment'";
}
break;
case 'password':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
case 'select':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} elseif ($fieldtype == 'INT' || $fieldtype == 'TINYINT') {
$default = $default !== '' ? intval($default) : 0;
if (!$maxlength) {
$maxlength = $fieldtype == 'INT' ? 10 : 4;
}
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) " . ($numbertype == 1 ? 'UNSIGNED' : '') . " NOT NULL DEFAULT {$default} COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
case 'select2':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} elseif ($fieldtype == 'INT' || $fieldtype == 'TINYINT') {
$default = $default !== '' ? intval($default) : 0;
if (!$maxlength) {
$maxlength = $fieldtype == 'INT' ? 10 : 4;
}
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) " . ($numbertype == 1 ? 'UNSIGNED' : '') . " NOT NULL DEFAULT {$default} COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
case 'linkage':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} elseif ($fieldtype == 'INT' || $fieldtype == 'TINYINT') {
$default = $default !== '' ? intval($default) : 0;
if (!$maxlength) {
$maxlength = $fieldtype == 'INT' ? 10 : 4;
}
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) " . ($numbertype == 1 ? 'UNSIGNED' : '') . " NOT NULL DEFAULT {$default} COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
case 'image':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 80;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
case 'images':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
case 'file':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 80;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
case 'files':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
case 'editor':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
case 'hidden':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 255;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
if (!$maxlength) {
$maxlength = 10;
}
// 主键字段自增
if ($pk == $field) {
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) " . ($numbertype == 1 ? 'UNSIGNED' : '') . " NOT NULL AUTO_INCREMENT COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) " . ($numbertype == 1 ? 'UNSIGNED' : '') . " NOT NULL DEFAULT '$default' COMMENT '$comment'";
}
}
break;
case 'color':
$fieldtype = $fieldtype ?? 'VARCHAR';
if ($fieldtype == 'VARCHAR' || $fieldtype == 'CHAR') {
if (!$maxlength) {
$maxlength = 10;
}
$maxlength = min($maxlength, 255);
$sql = "ALTER TABLE `$tablename` $do `$field` $fieldtype( $maxlength ) NOT NULL DEFAULT '$default' COMMENT '$comment'";
} else {
$sql = "ALTER TABLE `$tablename` $do `$field` TEXT NULL COMMENT '$comment'";
}
break;
}
return $sql;
}
/**
* 判断表中是否存在所选字段
* @param $table 表全称
* @param $field 字段名称
* @return mixed
*/
protected function _iset_field($table, $field)
{
$fields = Db::getTableFields($table);
if (array_search($field, $fields) === false) {
return false;
} else {
return true;
}
}
// 列表页额外JS
private function getIndexExtraJs()
{
$url = url('state');
$js = '<script type="text/javascript">
$(document).ready(function() {
//避免pjax重复加载js导致事件重复绑定
if (typeof (fieldIndexExtraJs) != "undefined") {
return;
}
$(document).on("click", \'.js_is_add\', function () {
var id = $(this).parent(\'tr\').data(\'uniqueid\');
if(id){
$.operate.submit(\'' . $url . '\', "post", "json", {"id": id,"field": \'is_add\'});
}
})
$(document).on("click", \'.js_is_edit\', function () {
var id = $(this).parent(\'tr\').data(\'uniqueid\');
if(id){
$.operate.submit(\'' . $url . '\', "post", "json", {"id": id,"field": \'is_edit\'});
}
})
$(document).on("click", \'.js_is_list\', function () {
var id = $(this).parent(\'tr\').data(\'uniqueid\');
if(id){
$.operate.submit(\'' . $url . '\', "post", "json", {"id": id,"field": \'is_list\'});
}
})
$(document).on("click", \'.js_is_search\', function () {
var id = $(this).parent(\'tr\').data(\'uniqueid\');
if(id){
$.operate.submit(\'' . $url . '\', "post", "json", {"id": id,"field": \'is_search\'});
}
})
$(document).on("click", \'.js_is_sort\', function () {
var id = $(this).parent(\'tr\').data(\'uniqueid\');
if(id){
$.operate.submit(\'' . $url . '\', "post", "json", {"id": id,"field": \'is_sort\'});
}
})
$(document).on("click", \'.js_required\', function () {
var id = $(this).parent(\'tr\').data(\'uniqueid\');
if(id){
$.operate.submit(\'' . $url . '\', "post", "json", {"id": id,"field": \'required\'});
}
})
fieldIndexExtraJs = true;
})
</script>';
return $js;
}
}

47
app/admin/controller/FieldGroup.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 字段分组控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class FieldGroup extends Base
{
// 验证器
protected $validate = 'FieldGroup';
// 当前主表
protected $tableName = 'field_group';
// 当前主模型
protected $modelName = 'FieldGroup';
}

251
app/admin/controller/Index.php

@ -0,0 +1,251 @@
<?php
/**
* +----------------------------------------------------------------------
* | 首页控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | QQ: 407593529
* '::::::::::::' | DATETIME: 2019/04/03
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
use think\facade\App;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Db;
use think\facade\Request;
use think\facade\View;
class Index extends Base
{
// 首页
public function index()
{
// 系统信息
$mysqlVersion = Db::query('SELECT VERSION() AS ver');
$config = [
'url' => $_SERVER['HTTP_HOST'],
'document_root' => $_SERVER['DOCUMENT_ROOT'],
'server_os' => PHP_OS,
'server_port' => $_SERVER['SERVER_PORT'],
'server_ip' => isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '',
'server_soft' => $_SERVER['SERVER_SOFTWARE'],
'php_version' => PHP_VERSION,
'mysql_version' => $mysqlVersion[0]['ver'],
'max_upload_size' => ini_get('upload_max_filesize'),
'version' => App::version(),
'siyu_version' => Config::get('app.siyu_version'),
];
// 查找一周内注册用户信息
$user = \app\common\model\Users::where('create_time', '>', time() - 60 * 60 * 24 * 7)->count();
// 查找待处理留言信息
if (class_exists('\app\common\model\Message')) {
$message = \app\common\model\Message::where('status', '0')->count();
}
// 查找是否有在线留言的模型id
$messageModuleId = \app\common\model\Module::where('table_name', 'message')->value('id');
$messageCatUrl = url('Message/index');
if ($messageModuleId) {
// 查询留言模块第一个栏目ID
$messageCatId = \app\common\model\Cate::where('module_id', $messageModuleId)->value('id');
if (!is_null($messageCatId)) {
// 生成URL
$messageCatUrl = url('Message/index', ['cate_id' => $messageCatId]);
}
}
$view = [
'config' => $config,
'user' => $user,
'message' => $message ?? 0,
'messageCatUrl' => $messageCatUrl,
'indexTips' => $this->getIndexTips(),
];
View::assign($view);
return View::fetch();
}
// 清除缓存
public function clear()
{
$path = App::getRootPath() . 'runtime';
if ($this->_deleteDir($path)) {
$result['msg'] = '清除缓存成功!';
$result['error'] = 0;
} else {
$result['msg'] = '清除缓存失败!';
$result['error'] = 1;
}
$result['url'] = (string)url('login/index');
return json($result);
}
/**
* 预览
* @param string $module 模型名称
* @param string $id 文章id
* @return \think\response\Redirect
*/
public function preview(string $module, string $id)
{
// 查询当前模块信息
$model = '\app\common\model\\' . $module;
$info = $model::find($id);
if ($info) {
// 查询所在栏目信息
$cate = \app\common\model\Cate::find($info['cate_id']);
if ($cate->module->getData('model_name') == 'Page') {
if ($cate['cate_folder']) {
$url = $cate['cate_folder'] . '.' . Config::get('route.url_html_suffix');
} else {
$url = $module . Config::get('route.pathinfo_depr') . 'index.' . Config::get('route.url_html_suffix') . '?cate=' . $cate['id'];
}
} else {
if ($cate['cate_folder']) {
$url = $cate['cate_folder'] . Config::get('route.pathinfo_depr') . $id . '.' . Config::get('route.url_html_suffix');
} else {
$url = $module . Config::get('route.pathinfo_depr') . 'info.' . Config::get('route.url_html_suffix') . '?cate=' . $cate['id'] . '&id=' . $id;
}
}
if (isset($url) && !empty($url)) {
// 检测是否开启了域名绑定
$domainBind = Config::get('app.domain_bind');
if ($domainBind) {
$domainBindKey = array_search('index', $domainBind);
$domainBindKey = $domainBindKey == '*' ? 'www.' : ($domainBindKey ? $domainBindKey . '.' : '');
$url = Request::scheme() . '://' . $domainBindKey . Request::rootDomain() . '/' . $url;
} else {
$url = '/index/' . $url;
}
}
}
return redirect($url);
}
/**
* select 2 ajax分页获取数据
* @param int $id 字段id
* @param string $keyWord 搜索词
* @param string $rows 显示数量
* @param string $value 默认值
* @return array
*/
public function select2(int $id, string $keyWord = '', string $rows = '10', string $value = '')
{
// 字段信息
$field = \app\common\model\Field::find($id);
if (is_null($field) || empty($field['relation_model']) || empty($field['relation_field'])) {
return [];
}
$model = '\app\common\model\\' . $field['relation_model'];
// 获取主键
$pk = \app\common\model\Module::where('model_name', $field['relation_model'])->value('pk') ?? 'id';
// 默认值
if ($value) {
$valueText = $model::where($pk, $value)->value($field['relation_field']);
if ($valueText) {
return [
'key' => $value,
'value' => $valueText
];
}
}
// 搜索条件
$where = [];
if ($keyWord) {
$where[] = [$field['relation_field'], 'LIKE', '%' . $keyWord . '%'];
}
$list = $model::field($pk . ',' . $field['relation_field'])
->where($where)
->order($pk . ' desc')
->paginate([
'query' => Request::get(),
'list_rows' => $rows,
]);
foreach ($list as $k => $v) {
$v['text'] = $v[$field['relation_field']];
}
return $list;
}
/**
* ajax获取多级联动数据
* @param string $model 模型名称
* @param string $key 关联模型的主键
* @param string $keyValue 要展示的字段
* @param int $pid 父ID
* @param string $pidFieldName 关联模型的父级id字段名
* @return array
*/
public function linkage(string $model, string $key, string $keyValue, int $pid = 0, string $pidFieldName = 'pid')
{
$list = getLinkageData($model, $pid, $pidFieldName);
$result = [];
foreach ($list as $v) {
$result[] = [
'key' => $v[$key],
'value' => $v[$keyValue],
];
}
return [
'code' => 1,
'list' => $result
];
}
// 执行删除
private function _deleteDir($R)
{
Cache::clear();
$handle = opendir($R);
while (($item = readdir($handle)) !== false) {
// log目录不可以删除
if ($item != '.' && $item != '..' && $item != 'log') {
if (is_dir($R . DIRECTORY_SEPARATOR . $item)) {
$this->_deleteDir($R . DIRECTORY_SEPARATOR . $item);
} else {
if ($item != '.gitignore') {
if (!unlink($R . DIRECTORY_SEPARATOR . $item)) {
return false;
}
}
}
}
}
closedir($handle);
return true;
//return rmdir($R); // 删除空的目录
}
// 检查提示信息
private function getIndexTips()
{
$password = \app\common\model\Admin::where('id', session('admin.id'))->value('password');
if ($password == md5('admin')) {
return '<h6 class="mb-0"><i class="icon fas fa-fw fa-exclamation-triangle"></i> 请尽快修改后台初始密码!</h6>';
}
return '';
}
}

47
app/admin/controller/Link.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 友情链接控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Link extends Base
{
// 验证器
protected $validate = 'Link';
// 当前主表
protected $tableName = 'link';
// 当前主模型
protected $modelName = 'Link';
}

66
app/admin/controller/Login.php

@ -0,0 +1,66 @@
<?php
/**
* +----------------------------------------------------------------------
* | 后台登录控制制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | QQ: 407593529
* '::::::::::::' | DATETIME: 2019/04/03
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
use think\captcha\facade\Captcha;
use think\facade\Request;
use think\facade\Session;
use think\facade\View;
class Login
{
// 登录页面
public function index()
{
// 已登录自动跳转
if (Session::has('admin')) {
return redirect((string)url('Index/index'));
}
// 查找系统设置
$system = \app\common\model\System::find(1);
$view['mobile'] = Request::isMobile();
$view['system'] = $system;
View::assign($view);
return View::fetch();
}
// 校验登录
public function checkLogin(){
return \app\common\model\Admin::checkLogin();
}
// 验证码
public function captcha(){
return Captcha::create();
}
// 退出登录
public function logout(){
Session::delete('admin');
return redirect('index');
}
}

47
app/admin/controller/Message.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 留言模块控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Message extends Base
{
// 验证器
protected $validate = 'Message';
// 当前主表
protected $tableName = 'message';
// 当前主模型
protected $modelName = 'Message';
}

419
app/admin/controller/Module.php

@ -0,0 +1,419 @@
<?php
/**
* +----------------------------------------------------------------------
* | 模块管理控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/04/16
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Db;
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Module extends Base
{
// 验证器
protected $validate = 'Module';
// 当前主表
protected $tableName = 'module';
// 当前主模型
protected $modelName = 'Module';
// 列表
public function index()
{
// 获取主键
$pk = MakeBuilder::getPrimarykey($this->tableName);
// 获取列表数据
$columns = MakeBuilder::getListColumns($this->tableName);
// 获取搜索数据
$search = MakeBuilder::getListSearch($this->tableName);
// 搜索
if (Request::param('getList') == 1) {
$where = MakeBuilder::getListWhere($this->tableName);
$orderByColumn = Request::param('orderByColumn') ?? $pk;
$isAsc = Request::param('isAsc') ?? 'desc';
$model = '\app\common\model\\' . $this->modelName;
return $model::getList($where, $this->pageSize, [$orderByColumn => $isAsc]);
}
// 构建页面
return TableBuilder::getInstance()
->setUniqueId($pk) // 设置主键
->addColumns($columns) // 添加列表字段数据
->setSearch($search) // 添加头部搜索
->addColumn('right_button', '操作', 'btn') // 启用右侧操作列
->addRightButtons(['edit', 'delete']) // 设置右侧操作列
->addTopButtons(['add', 'edit', 'del', 'export', 'build']) // 设置顶部按钮组
->addTopButton(
'default', [
'title' => '生成菜单规则',
'icon' => 'fa fa-bars',
'class' => 'btn btn-danger single disabled',
'href' => '',
'onclick' => '$.operate.makeRule(\'' . url('makeRule') . '\')'
]
) // 自定义按钮
->fetch();
}
// 添加
public function add()
{
// 获取字段信息
$columns = MakeBuilder::getAddColumns($this->tableName);
// 提示信息
$pageTips = '1、没有表时会创建表和字段并插入至字段管理中;<br>2、已有表时会检测必要字段后插入至字段管理中;<br>3、已有表需包含的字段:主键、create_time、update_time、[sort 勾选排序字段时]、[status 勾选状态字段时]、[cate_id, hits, keywords, description, template, url 表类型为CMS时];';
// 构建页面
return FormBuilder::getInstance()
->addFormItems($columns)
->setPageTips($pageTips, 'warning') // 提示信息
->setExtraJs($this->getAddExtraJs()) // 设置额外JS
->fetch();
}
// 添加保存
public function addPost()
{
if (Request::isPost()) {
$data = MakeBuilder::changeFormData(Request::except(['file'], 'post'), $this->tableName);
$result = $this->validate($data, $this->validate);
if (true !== $result) {
// 验证失败 输出错误信息
$this->error($result);
} else {
$model = '\app\common\model\\' . $this->modelName;
// 唯一判断
$count = $model::where('table_name', $data['table_name'])->count();
if ($count) {
$this->error('表名称 [' . $data['table_name'] . '] 已存在');
}
$result = $model::addPost($data);
if ($result['error']) {
$this->error($result['msg']);
} else {
$makeTable = \app\common\model\Module::makeTable($data['table_name']);
if ($makeTable === true) {
$this->success($result['msg'], 'index');
} else {
// 删除刚插入的数据
$model::where('table_name', $data['table_name'])->delete();
$this->error($makeTable);
}
}
}
}
}
// 修改
public function edit(string $id)
{
$model = '\app\common\model\\' . $this->modelName;
$info = $model::edit($id)->toArray();
// 获取字段信息
$columns = MakeBuilder::getAddColumns($this->tableName, $info);
// 提示信息
$pageTips = '1、主键发生变动时会更改数据库中的表结构,字段管理中的主键字段也会相应改变;<br>2、表名称发生变动时会更改数据库中的表名称,需要重新进行代码生成和菜单生成;';
// 构建页面
return FormBuilder::getInstance()
->addFormItems($columns)
->setPageTips($pageTips, 'warning') // 提示信息
->setExtraJs($this->getEditExtraJs()) // 设置额外JS
->fetch();
}
// 修改保存
public function editPost()
{
if (Request::isPost()) {
$data = MakeBuilder::changeFormData(Request::except(['file'], 'post'), $this->tableName);
$result = $this->validate($data, $this->validate);
if (true !== $result) {
// 验证失败 输出错误信息
$this->error($result);
} else {
// 尝试修改表名称和主键
$result = \app\common\model\Module::changeTable($data);
if ($result !== true) {
$this->error($result);
}
// 修改表记录信息
$model = '\app\common\model\\' . $this->modelName;
$result = $model::editPost($data);
if ($result['error']) {
$this->error($result['msg']);
} else {
$this->success($result['msg'], 'index');
}
}
}
}
// 删除
public function del(string $id)
{
if (Request::isPost()) {
// 当有栏目使用该模块时不可删除
if ($this->checkCate($id) == false) {
return ['error' => 1, 'msg' => '删除失败,请先删除已使用该模块的栏目'];
}
// 模块删除的同时删除字段管理中对应的数据
$this->delModuleField($id);
// 是否清空表[不删除]
// 是否删除模型、控制器、验证器文件[不删除]
if (strpos($id, ',') !== false) {
return $this->selectDel($id);
}
$model = '\app\common\model\\' . $this->modelName;
return $model::del($id);
}
}
// 批量删除
public function selectDel(string $id)
{
if (Request::isPost()) {
$model = '\app\common\model\\' . $this->modelName;
return $model::selectDel($id);
}
}
// ==========================
// 检查表信息
public function checkTale(string $table_name = '')
{
if ($table_name) {
try {
// 获取模型名称
$modelName = '';
$tableNameArr = explode('_', $table_name);
foreach ($tableNameArr as $v) {
$modelName .= ucfirst($v);
}
// 获取完整表名称
$tableName = \think\facade\Config::get('database.connections.mysql.prefix') . $table_name;
// 获取表全部字段
$fields = Db::getTableFields($tableName);
// 从数据库中获取表字段信息
$sql = "SELECT * FROM `information_schema`.`columns` WHERE TABLE_SCHEMA = :table_schema AND table_name = :table_name "
. "ORDER BY ORDINAL_POSITION";
$columnList = Db::query($sql, ['table_schema' => \think\facade\Config::get('database.connections.mysql.database'), 'table_name' => $tableName]);
$priKey = '';
foreach ($columnList as $v) {
if ($v['COLUMN_KEY'] == 'PRI') {
$priKey = $v['COLUMN_NAME'];
break;
}
}
if (!$priKey) {
return json(['error' => 1, 'msg' => '请设置 [' . $tableName . '] 表的主键']);
}
// 获取表基础信息
$tableInfo = Db::query("SHOW TABLE STATUS LIKE '{$tableName}'");
$tableInfo = $tableInfo[0];
// 获取表类型
$tableType = '2';
if (in_array('cate_id', $fields) && in_array('hits', $fields) && in_array('keywords', $fields) && in_array('description', $fields) && in_array('template', $fields) && in_array('url', $fields)) {
$tableType = '1';
}
// 自动时间戳
if (in_array('create_time', $fields) && in_array('update_time', $fields)) {
$autoTimestamp = '1';
}
// 返回信息
$data = [
'module_name' => $tableInfo['Comment'] ?: $table_name, // 模块名称
'model_name' => $modelName, // 模型名称
'table_comment' => $tableInfo['Comment'], // 表注释
'pk' => $priKey, // 主键
'table_type' => $tableType, // 表类型
'is_sort' => in_array('sort', $fields) ? '1' : '0', // 排序字段
'is_status' => in_array('status', $fields) ? '1' : '0', // 状态字段
'remark' => $tableInfo['Comment'], // 备注
'auto_timestamp' => $autoTimestamp ?? '0', // 自动写入时间戳
'add_param' => $addParam ?? '', // 添加参数
];
return json(['error' => 0, 'msg' => '数据表已存在,系统已自动补全其他字段', 'data' => $data]);
} catch (\Exception $e) {
return json(['error' => 2, 'msg' => $e->getMessage()]);
}
}
}
// 生成代码
public function build(string $id, string $file = '')
{
return MakeBuilder::makeModule($id, $file);
}
// 生成菜单
public function makeRule(string $id)
{
return MakeBuilder::makeRule($id);
}
/**
* 删除模块时判断是否已有栏目在应用[兼容多选和单选]
* @param $id 模块id
* @return bool false 不可删除,true 可删除
*/
private function checkCate(string $id)
{
strpos($id, ',') !== false ? $op = 'in' : $op = '=';
$count = \app\common\model\Cate::where('module_id', $op, $id)->count();
if ($count) {
return false;
}
return true;
}
/**
* 删除模型时删除当前模型的所有字段数据[兼容多选和单选]
* @param string $id
* @return bool
* @throws \Exception
*/
private function delModuleField(string $id)
{
strpos($id, ',') !== false ? $op = 'in' : $op = '=';
return \app\common\model\Field::where('module_id', $op, $id)->delete();
}
// 添加页额外JS
private function getAddExtraJs()
{
$js = '<script type="text/javascript">
$(function () {
// 添加默认隐藏预览按钮
$("input[name=\'right_button[]\']").each(function(){
var value = $(this).val();
if(value == \'preview\'){
$(this).parent(\'.dd_radio_lable\').hide();
}
});
// 切换表类型时显示/隐藏预览按钮,设置添加参数
$("select[name=\'table_type\']").change(function(){
var value = $(this).val();
if(value == \'1\'){
$("input[name=\'right_button[]\']").each(function(){
if($(this).val() == \'preview\'){
$(this).attr("checked",true);
$(this).parent(\'.dd_radio_lable\').show();
}
});
$("input[name=\'add_param\']").val(\'cate_id\');
} else {
$("input[name=\'right_button[]\']").each(function(){
if($(this).val() == \'preview\'){
$(this).attr("checked",false);
$(this).parent(\'.dd_radio_lable\').hide();
}
});
$("input[name=\'add_param\']").val(\'\');
}
})
// 表名称添加完时尝试补充其他信息
$("input[name=\'table_name\']").change(function(){
var config = {
url: \'checkTale\',
dataType: \'json\',
data: {table_name:$("input[name=\'table_name\']").val()},
success: function(result) {
if(result.error == 1){
toastr.success(result.msg);
} else if(result.error == 0) {
$("input[name=\'module_name\']").val(result.data.module_name);
$("input[name=\'model_name\']").val(result.data.model_name);
$("input[name=\'table_comment\']").val(result.data.table_comment);
$("input[name=\'pk\']").val(result.data.pk);
$("select[name=\'table_type\']").val(result.data.table_type);
if(result.data.is_sort == \'1\'){
$("#is_sort1").attr(\'checked\', \'checked\');
} else {
$("#is_sort2").attr(\'checked\', \'checked\');
}
if(result.data.is_status == \'1\'){
$("#is_status1").attr(\'checked\', \'checked\');
} else {
$("#is_status2").attr(\'checked\', \'checked\');
}
$("textarea[name=\'remark\']").text(result.data.remark);
toastr.success(result.msg);
}
}
};
$.ajax(config)
})
})
</script>';
return $js;
}
// 编辑页额外JS
private function getEditExtraJs()
{
$js = '<script type="text/javascript">
$(function () {
// 添加默认隐藏预览按钮
if($("select[name=\'table_type\']").val() != "1"){
$("input[name=\'right_button[]\']").each(function(){
var value = $(this).val();
if(value == \'preview\'){
$(this).parent(\'.dd_radio_lable\').hide();
}
});
}
// 切换表类型为CMS时显示预览按钮
$("select[name=\'table_type\']").change(function(){
var value = $(this).val();
if(value == \'1\'){
$("input[name=\'right_button[]\']").each(function(){
if($(this).val() == \'preview\'){
//$(this).attr("checked",true);
$(this).parent(\'.dd_radio_lable\').show();
}
});
} else {
$("input[name=\'right_button[]\']").each(function(){
if($(this).val() == \'preview\'){
$(this).attr("checked",false);
$(this).parent(\'.dd_radio_lable\').hide();
}
});
}
})
})
</script>';
return $js;
}
}

47
app/admin/controller/Page.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 单页模块控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Page extends Base
{
// 验证器
protected $validate = 'Page';
// 当前主表
protected $tableName = 'page';
// 当前主模型
protected $modelName = 'Page';
}

47
app/admin/controller/Picture.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 图片模块控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Picture extends Base
{
// 验证器
protected $validate = 'Picture';
// 当前主表
protected $tableName = 'picture';
// 当前主模型
protected $modelName = 'Picture';
}

374
app/admin/controller/Plugin.php

@ -0,0 +1,374 @@
<?php
/**
* +----------------------------------------------------------------------
* | 插件管理控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | QQ: 407593529
* '::::::::::::' | DATETIME: 2020/03/11
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
use think\facade\Request;
use think\facade\View;
// 表单和表格构建器
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
// 插件服务
use app\admin\facade\ThinkAddons;
class Plugin extends Base
{
// 列表
public function index()
{
// 搜索
if (Request::param('getList') == 1) {
// 获取插件列表
$list = ThinkAddons::localAddons();
// 渲染输出
$result = [
'total' => count($list),
'per_page' => 1000,
'current_page' => 1,
'last_page' => 1,
'data' => $list,
];
return $result;
}
return TableBuilder::getInstance()
->addColumns([ // 批量添加列
['name', '编号'],
['title', '插件名称'],
['description', '插件介绍'],
['status', '状态(启用/禁用)', 'status', '0',[
['0' => '禁用'],
['1' => '启用']
]],
['author', '作者'],
['version', '版本'],
['button', '操作', 'text']
])
->setUniqueId('name')
//->addRightButton('edit', ['title' => '配置'])
->setEditUrl(url('config', ['name' => '__id__']))
->setExtraJs($this->makeExtraJs())
->fetch();
}
// 插件配置信息预览
public function config(string $name)
{
$config = ThinkAddons::config($name);
// 如果插件自带配置模版的话加载插件自带的,否则调用表单构建器
$file = app()->getRootPath() . 'addons' . DIRECTORY_SEPARATOR . $name . DIRECTORY_SEPARATOR . 'config.html';
if (file_exists($file)) {
View::assign([
'config' => $config
]);
return View::fetch($file);
} else {
// 获取字段数据
$columns = $this->makeAddColumns($config);
// 判断是否分组
$group = ThinkAddons::checkConfigGroup($config);
// 构建页面
$builder = FormBuilder::getInstance();
$builder->setFormUrl(url('configSave'))
->addHidden('id', $name);
$group ? $builder->addGroup($columns) : $builder->addFormItems($columns);
return $builder->fetch();
}
}
// 插件配置信息保存
public function configSave()
{
if (Request::isPost()) {
$result = ThinkAddons::configPost(Request::except(['file'], 'post'));
if ($result['code'] == 1) {
$this->success($result['msg'], 'index');
} else {
$this->error($result['msg']);
}
}
}
// 更改插件状态 [启用/禁用]
public function state(string $id)
{
return ThinkAddons::state($id);
}
// 安装插件
public function install(string $id)
{
return ThinkAddons::install($id);
}
// 卸载插件
public function uninstall(string $id)
{
return ThinkAddons::uninstall($id);
}
// =========================================
// 生成表单信息
private function makeAddColumns(array $config)
{
// 判断是否开启了分组
if (ThinkAddons::checkConfigGroup($config) === false) {
// 未开启分组
return $this->makeAddColumnsArr($config);
} else {
$columns = [];
// 开启分组
foreach ($config as $k => $v) {
$columns[$k] = $this->makeAddColumnsArr($v);
}
return $columns;
}
}
// 生成表单返回数组
private function makeAddColumnsArr(array $config)
{
$columns = [];
foreach ($config as $k => $field) {
// 初始化
$field['name'] = $field['name'] ?? $field['title'];
$field['field'] = $k;
$field['tips'] = $field['tips'] ?? '';
$field['required'] = $field['required'] ?? 0;
$field['group'] = $field['group'] ?? '';
if (!isset($field['setup'])) {
$field['setup'] = [
'default' => $field['value'] ?? '',
'extra_attr' => $field['extra_attr'] ?? '',
'extra_attr' => $field['extra_attr'] ?? '',
'extra_class' => $field['extra_class'] ?? '',
'placeholder' => $field['placeholder'] ?? '',
];
}
if ($field['type'] == 'text') {
$columns[] = [
$field['type'], // 类型
$field['field'], // 字段名称
$field['name'], // 字段别名
$field['tips'], // 提示信息
$field['setup']['default'], // 默认值
$field['group'], // 标签组,可以在文本框前后添加按钮或者文字
$field['setup']['extra_attr'], // 额外属性
$field['setup']['extra_class'],// 额外CSS
$field['setup']['placeholder'],// 占位符
$field['required'], // 是否必填
];
}
elseif ($field['type'] == 'textarea' || $field['type'] == 'password') {
$columns[] = [
$field['type'], // 类型
$field['field'], // 字段名称
$field['name'], // 字段别名
$field['tips'], // 提示信息
$field['setup']['default'], // 默认值
$field['setup']['extra_attr'], // 额外属性
$field['setup']['extra_class'] ?? '', // 额外CSS
$field['setup']['placeholder'] ?? '', // 占位符
$field['required'], // 是否必填
];
}
elseif ($field['type'] == 'radio' || $field['type'] == 'checkbox') {
$columns[] = [
$field['type'], // 类型
$field['field'], // 字段名称
$field['name'], // 字段别名
$field['tips'], // 提示信息
$field['options'], // 选项(数组)
$field['setup']['default'], // 默认值
$field['setup']['extra_attr'], // 额外属性 extra_attr
'', // 额外CSS extra_class
$field['required'], // 是否必填
];
}
elseif ($field['type'] == 'select' || $field['type'] == 'select2' ) {
$columns[] = [
$field['type'], // 类型
$field['field'], // 字段名称
$field['name'], // 字段别名
$field['tips'], // 提示信息
$field['options'], // 选项(数组)
$field['setup']['default'], // 默认值
$field['setup']['extra_attr'], // 额外属性
$field['setup']['extra_class'] ?? '', // 额外CSS
$field['setup']['placeholder'] ?? '', // 占位符
$field['required'], // 是否必填
];
}
elseif ($field['type'] == 'number') {
$columns[] = [
$field['type'], // 类型
$field['field'], // 字段名称
$field['name'], // 字段别名
$field['tips'], // 提示信息
$field['setup']['default'], // 默认值
'', // 最小值
'', // 最大值
$field['setup']['step'], // 步进值
$field['setup']['extra_attr'], // 额外属性
$field['setup']['extra_class'], // 额外CSS
$field['setup']['placeholder'] ?? '', // 占位符
$field['required'], // 是否必填
];
}
elseif ($field['type'] == 'hidden') {
$columns[] = [
$field['type'], // 类型
$field['field'], // 字段名称
$field['setup']['default'] ?? '', // 默认值
$field['setup']['extra_attr'] ?? '', // 额外属性 extra_attr
];
}
elseif ($field['type'] == 'date' || $field['type'] == 'time' || $field['type'] == 'datetime') {
// 使用每个字段设定的格式
if ($field['type'] == 'time') {
$field['setup']['format'] = str_replace("HH", "h", $field['setup']['format']);
$field['setup']['format'] = str_replace("mm", "i", $field['setup']['format']);
$field['setup']['format'] = str_replace("ss", "s", $field['setup']['format']);
$format = $field['setup']['format'] ?? 'H:i:s';
} else {
$field['setup']['format'] = str_replace("yyyy", "Y", $field['setup']['format']);
$field['setup']['format'] = str_replace("mm", "m", $field['setup']['format']);
$field['setup']['format'] = str_replace("dd", "d", $field['setup']['format']);
$field['setup']['format'] = str_replace("hh", "h", $field['setup']['format']);
$field['setup']['format'] = str_replace("ii", "i", $field['setup']['format']);
$field['setup']['format'] = str_replace("ss", "s", $field['setup']['format']);
$format = $field['setup']['format'] ?? 'Y-m-d H:i:s';
}
$field['setup']['default'] = $field['setup']['default'] > 0 ? date($format, $field['setup']['default']) : '';
$columns[] = [
$field['type'], // 类型
$field['field'], // 字段名称
$field['name'], // 字段别名
$field['tips'], // 提示信息
$field['setup']['default'], // 默认值
$field['setup']['format'], // 日期格式
$field['setup']['extra_attr'], // 额外属性 extra_attr
'', // 额外CSS extra_class
$field['setup']['placeholder'],// 占位符
$field['required'], // 是否必填
];
}
elseif ($field['type'] == 'daterange') {
$columns[] = [
$field['type'], // 类型
$field['field'], // 字段名称
$field['name'], // 字段别名
$field['tips'], // 提示信息
$field['setup']['default'], // 默认值
$field['setup']['format'], // 日期格式
$field['setup']['extra_attr'] ?? '', // 额外属性
$field['setup']['extra_class'] ?? '', // 额外CSS
$field['required'], // 是否必填
];
}
elseif ($field['type'] == 'tag') {
$columns[] = [
$field['type'], // 类型
$field['field'], // 字段名称
$field['name'], // 字段别名
$field['tips'], // 提示信息
$field['setup']['default'], // 默认值
$field['setup']['extra_attr'] ?? '', // 额外属性
$field['setup']['extra_class'] ?? '', // 额外CSS
$field['required'], // 是否必填
];
}
elseif ($field['type'] == 'image' || $field['type'] == 'images' || $field['type'] == 'file' || $field['type'] == 'files') {
$columns[] = [
$field['type'], // 类型
$field['field'], // 字段名称
$field['name'], // 字段别名
$field['tips'], // 提示信息
$field['setup']['default'], // 默认值
$field['setup']['size'], // 限制大小(单位kb)
$field['setup']['ext'], // 文件后缀
$field['setup']['extra_attr'] ?? '', // 额外属性
$field['setup']['extra_class'] ?? '', // 额外CSS
$field['setup']['placeholder'] ?? '', // 占位符
$field['required'], // 是否必填
];
}
elseif ($field['type'] == 'editor') {
$columns[] = [
$field['type'], // 类型
$field['field'], // 字段名称
$field['name'], // 字段别名
$field['tips'], // 提示信息
$field['setup']['default'], // 默认值
$field['setup']['heidht'] ?? 0, // 高度
$field['setup']['extra_attr'] ?? '', // 额外属性
$field['setup']['extra_class'] ?? '', // 额外CSS
$field['required'], // 是否必填
];
}
elseif ($field['type'] == 'color') {
$columns[] = [
$field['type'], // 类型
$field['field'], // 字段名称
$field['name'], // 字段别名
$field['tips'], // 提示信息
$field['setup']['default'], // 默认值
$field['setup']['extra_attr'] ?? '', // 额外属性
$field['setup']['extra_class'] ?? '', // 额外CSS
$field['setup']['placeholder'] ?? '', // 占位符
$field['required'], // 是否必填
];
}
}
return $columns;
}
// 生成列表页额外JS
private function makeExtraJs()
{
$js = '<script type="text/javascript">
// 安装
$.operate.pluginInstall = function(id) {
var url = \''.url('install').'\';
$.modal.confirm("确认要安装?", function () {
var data = {"id": id};
$.operate.submit(url, "post", "json", data);
});
}
// 卸载
$.operate.pluginUninstall = function(id) {
var url = \''.url('uninstall').'\';
$.modal.confirm("确认要卸载?", function () {
var data = {"id": id};
$.operate.submit(url, "post", "json", data);
});
}
</script>';
return $js;
}
}

47
app/admin/controller/Product.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 产品模块控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Product extends Base
{
// 验证器
protected $validate = 'Product';
// 当前主表
protected $tableName = 'product';
// 当前主模型
protected $modelName = 'Product';
}

47
app/admin/controller/System.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 系统设置控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class System extends Base
{
// 验证器
protected $validate = 'System';
// 当前主表
protected $tableName = 'system';
// 当前主模型
protected $modelName = 'System';
}

47
app/admin/controller/Team.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 团队模块控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Team extends Base
{
// 验证器
protected $validate = 'Team';
// 当前主表
protected $tableName = 'team';
// 当前主模型
protected $modelName = 'Team';
}

417
app/admin/controller/Template.php

@ -0,0 +1,417 @@
<?php
/**
* +----------------------------------------------------------------------
* | 模板控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | QQ: 407593529
* '::::::::::::' | DATETIME: 2019/03/06
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
use think\facade\Request;
use think\facade\View;
// 引入表格和表单构建器
use app\common\builder\TableBuilder;
use app\common\builder\FormBuilder;
class Template extends Base
{
protected $public, $template_path, $template_html, $template_css, $template_js, $template_img, $upload_path;
// 默认开启备份功能
protected $templateOpening = true;
function initialize()
{
parent::initialize();
// 查找所有系统设置表数据
$system = \app\common\model\System::find(1);
$this->public = '/template/' .
$system['template'] .
'/' .
'index' .
'/';
$this->template_path =
'.' . $this->public;
$this->template_html = $system['html'];
$this->template_css = 'css';
$this->template_js = 'js';
$this->template_img = 'img';
$initialize = [
'html' => $this->template_html, // 自定义html目录
'css' => $this->template_css, // 自定义css目录
'js' => $this->template_js, // 自定义js目录
'img' => $this->template_img, // 自定义媒体文件目录
];
View::assign($initialize);
// 查找是否开启了模板修改备份功能
$this->templateOpening = $system['template_opening'];
}
// 列表
public function index(string $type = 'html')
{
if ($type == 'html') {
$path = $this->template_path . $this->template_html . DIRECTORY_SEPARATOR;
} else {
$path = $this->template_path . $type . DIRECTORY_SEPARATOR;
}
// 设置主键
$pk = 'id';
// 字段信息
$columns = [
['id', '文件名称'],
['filepath', '目录'],
['filesize', '文件大小'],
['filemtime', '更新时间', '', '', '', '', 'true'],
['ext', '后缀'],
];
$files = dir_list($path, $type);
$list = [];
foreach ($files as $key => $file) {
$filename = basename($file);
//$list[$key]['value'] = substr($filename, 0, strrpos($filename, '.'));
$list[$key]['id'] = $filename;
$list[$key]['filepath'] = $file;
$list[$key]['filesize'] = format_bytes(filesize($file));
$list[$key]['filemtime'] = date('Y-m-d H:i:s', filemtime($file));
$list[$key]['ext'] = strtolower(substr($filename, strrpos($filename, '.') - strlen($filename)));
}
// 搜索
if (Request::param('getList') == 1) {
// 排序规则
$orderByColumn = Request::param('orderByColumn') ?? $pk;
$isAsc = Request::param('isAsc') ?? 'desc';
$isAsc = $isAsc == 'desc' ? SORT_DESC : SORT_ASC;
// 排序处理
$date = array_column($list, $orderByColumn);
array_multisort($date, $isAsc, $list);
// 渲染输出
$result = [
'total' => count($list),
'per_page' => 1000,
'current_page' => 1,
'last_page' => 1,
'data' => $list,
];
return $result;
}
// 获取头部切换按钮
$pageTips = $this->getPageTips($type);
// 构建页面
return TableBuilder::getInstance()
->setUniqueId($pk) // 设置主键
->addColumns($columns) // 添加列表字段数据
->setPageTips($pageTips, 'success', 'search') // 提示信息
->setPagination('false') // 关闭分页显示
->addColumn('right_button', '操作', 'btn')
->addRightButton('edit', ['href' => (string)url('edit', ['id' => '__id__', 'type' => $type])])
->addRightButton('delete')
->addTopButtons(['add', 'edit', 'del']) // 设置顶部按钮组
->setEditUrl((string)url('edit', ['id' => '__id__', 'type' => $type]))
->setDelUrl((string)url('del', ['id' => '__id__', 'type' => $type]))
->setDataUrl(url('index', ['getList' => '1', 'type' => $type]))
->fetch();
}
// 添加
public function add()
{
// 默认文件类型
$type = Request::param('type', 'html');
// 文件类型数组
$fileType = ['html' => 'HTML', 'css' => 'CSS', 'js' => 'JS'];
// 构建页面
return FormBuilder::getInstance()
->addFormItems([
['text', 'filename', '文件名称', '不需要输入文件后缀,如 style.css 请填写style', '', [], '', '', '', true],
['radio', 'type', '文件类型', '', $fileType, $type, '', '', true],
['code', 'content', '内容', '', '', '', '', '', false, $type],
])
->fetch();
}
// 添加保存
public function addPost()
{
if (Request::isPost()) {
$filename = $this->checkFilename(Request::post('filename'));
$type = $this->checkFiletype(Request::param('type', 'html'));
if (empty($filename)) {
$this->error('文件名称不可以为空');
}
if ($type == 'html') {
$path = $this->template_path . $this->template_html . '/';
} else {
$path = $this->template_path . $type . '/';
}
$file = $path . $filename . '.' . $type;
if (file_exists($file)) {
$this->error('文件已经存在!');
} else {
try {
file_put_contents($file, stripslashes(input('post.content')));
} catch (\Exception $e) {
$this->error($e->getMessage());
}
$this->success('添加成功!', url('index', ['type' => $type]));
}
}
}
// 修改
public function edit(string $id)
{
$id = $this->checkFilename($id);
// 默认文件类型
$type = $this->checkFiletype(Request::param('type', 'html'));
// 文件类型数组
$fileType = ['html' => 'HTML', 'css' => 'CSS', 'js' => 'JS'];
if ($type == 'html') {
$path = $this->template_path . $this->template_html . '/';
} else {
$path = $this->template_path . $type . '/';
}
$file = $path . $id;
if (file_exists($file)) {
$file = iconv('gb2312', 'utf-8', $file);
$content = file_get_contents($file);
$info = [
'filename' => $id,
'file' => $file,
'content' => $content,
'type' => $type
];
} else {
$this->error('文件不存在!');
}
// 构建页面
return FormBuilder::getInstance()
->addFormItems([
['text', 'filename', '文件名称', '不需要输入文件后缀,如 style.css 请填写style', $info['filename'], [], 'readonly', '', '', true],
['radio', 'type', '文件类型', '', $fileType, $info['type'], '', '', true],
['code', 'content', '内容', '', $info['content'], '', '', '', false, $type],
['hidden', 'file', $info['file']]
])
->fetch();
}
// 修改保存
public function editPost()
{
if (Request::isPost()) {
$filename = $this->checkFilename(Request::post('filename'));
$type = $this->checkFiletype(Request::param('type', 'html'));
if (empty($filename)) {
$this->error('文件名称不可以为空');
}
if ($type == 'html') {
$path = $this->template_path . $this->template_html . '/';
} else {
$path = $this->template_path . $type . '/';
}
$file = $path . $filename;
if (file_exists($file)) {
// 判断是否有写入权限
if (!is_writable($file)) {
$this->error('无写入权限!');
}
// 备份文件(防止出错)
if ($this->templateOpening) {
// 设置备份文件名
$newFile = $path . str_replace('.', '_back-' . date("Y-m-d_H-i-s") . '.', $filename);
// 执行复制操作
copy($file, $newFile);
}
if (false !== file_put_contents($file, stripslashes(input('content')))) {
$this->success('修改成功!', url('index', ['type' => $type]));
} else {
$this->error('修改失败!');
}
} else {
$this->error('文件不存在!');
}
}
}
// 删除
public function del(string $id, string $type = 'html')
{
$id = $this->checkFilename($id);
$type = $this->checkFiletype($type);
if (strpos($id, ',') !== false) {
return $this->selectDel($id, $type);
}
//删除文件
if ($type == 'html') {
$path = $this->template_path . $this->template_html . '/';
} else {
$path = $this->template_path . $type . '/';
}
$file = $path . $id;
if (file_exists($file)) {
unlink($file);
return ['error' => 0, 'msg' => '删除成功!'];
} else {
return ['error' => 1, 'msg' => '删除失败!'];
}
}
// 批量删除
public function selectDel(string $id, string $type = 'html')
{
$type = $this->checkFiletype($type);
if (Request::isPost()) {
$ids = explode(',', $id);
if ($type == 'html') {
$path = $this->template_path . $this->template_html . '/';
} else {
$path = $this->template_path . $type . '/';
}
foreach ($ids as $k => $v) {
$v = $this->checkFilename($v);
//删除文件
$file = $path . $v;
if (file_exists($file)) {
unlink($file);
}
}
return ['error' => 0, 'msg' => '删除成功!'];
}
}
// 媒体文件
public function img()
{
$path = $this->template_path . $this->template_img . '/' . Request::param('folder');
$folder = Request::param('folder', '');
$uppath = explode('/', Request::param('folder'));
$leve = count($uppath) - 1;
unset($uppath[$leve]);
if ($leve > 1) {
unset($uppath[$leve - 1]);
$uppath = implode('/', $uppath) . '/';
} else {
$uppath = '';
}
$files = glob($path . '*');
$folders = $templates = array();
foreach ($files as $key => $file) {
$filename = basename($file);
if (is_dir($file)) {
$folders[$key]['filename'] = $filename;
$folders[$key]['filepath'] = $file;
$folders[$key]['ext'] = 'folder';
} else {
$templates[$key]['filename'] = $filename;
$templates[$key]['filepath'] = ltrim($file, '.');
$templates[$key]['ext'] = strtolower(substr($filename, strrpos($filename, '.') - strlen($filename) + 1));
if (!in_array($templates[$key]['ext'], array('gif', 'jpg', 'png', 'bmp'))) {
$templates[$key]['ico'] = 1;
}
}
}
$view = [
'folder' => $folder,
'leve' => $leve,
'uppath' => $uppath,
'path' => $path, //路径
'folders' => $folders, //文件夹
'files' => $templates, //文件
'type' => $this->template_img, //当前显示的类型
];
View::assign($view);
return View::fetch();
}
// 媒体文件删除
public function imgDel()
{
$folder = str_replace("..", "", Request::param('folder'));
$path = $this->template_path . $this->template_img . '/' . $folder;
$file = $path . $this->checkFilename(Request::post('filename'));
if (file_exists($file)) {
is_dir($file) ? dir_delete($file) : unlink($file);
return json(['error' => 0, 'msg' => '删除成功!']);
} else {
return json(['error' => 1, 'msg' => '文件不存在!']);
}
}
/**
* 获取头部切换按钮
* @param string $type
* @return string
*/
private function getPageTips(string $type)
{
$html = $type == 'html' ? 'btn-info' : 'btn-primary';
$css = $type == 'css' ? 'btn-info' : 'btn-primary';
$js = $type == 'js' ? 'btn-info' : 'btn-primary';
$img = $type == 'img' ? 'btn-info' : 'btn-primary';
$link = [
'html' => url('index', ['type' => 'html']),
'css' => url('index', ['type' => 'css']),
'js' => url('index', ['type' => 'js']),
'img' => url('img', ['type' => 'img']),
];
$pageTips = '
<a class="btn btn-flat m-r-5 ' . $html . '" href="' . $link['html'] . '">html</a>
<a class="btn btn-flat m-r-5 ' . $css . '" href="' . $link['css'] . '">css</a>
<a class="btn btn-flat m-r-5 ' . $js . '" href="' . $link['js'] . '">js</a>
<a class="btn btn-flat m-r-5 ' . $img . '" href="' . $link['img'] . '">媒体文件</a>
';
return $pageTips;
}
// 过滤文件名
private function checkFilename(string $fileName)
{
$fileName = str_replace("/", "", $fileName);
$fileName = str_replace("..", "", $fileName);
$fileName = str_ireplace(".php", ".html", $fileName);
$fileName = str_ireplace(".asp", ".html", $fileName);
return $fileName;
}
// 过滤文件类型
private function checkFiletype(string $fileType)
{
$arr = ['html', 'css', 'js'];
if (!in_array(strtolower($fileType), $arr)) {
return 'html';
} else {
return $fileType;
}
}
}

815
app/admin/controller/Upload.php

@ -0,0 +1,815 @@
<?php
/**
* +----------------------------------------------------------------------
* | 上传控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | QQ: 407593529
* '::::::::::::' | DATETIME: 2019/04/03
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
use think\App;
use think\facade\Request;
class Upload extends Base
{
// 上传方式 [chunk 大文件分片上传, tp 沿用TP上传]
private $uploadType = "";
// 上传验证规则
protected $uploadValidate = [];
// 构造方法
public function __construct(App $app)
{
parent::__construct($app);
// 默认上传方式
$this->uploadType = "chunk";
// 验证规则
$this->uploadValidate = [
'file' => $this->uploadVal()
];
}
// 上传文件
public function index()
{
if (Request::param('from') == 'ckeditor') {
// 获取上传文件表单字段名
$fileKey = array_keys(request()->file());
$path = [];
for ($i = 0; $i < count($fileKey); $i++) {
// 获取表单上传文件并执行上传操作
$uploadFile = $this->uploadFile($fileKey[$i]);
if ($uploadFile['code'] == 1) {
$path[] = $uploadFile['url'];
} else {
$path = [];
$error = $uploadFile['msg'];
}
}
if ($path) {
$result['uploaded'] = true;
// 分辨是否截图上传,截图上传只能上传一个,非截图上传可以上传多个
if (Request::param('responseType') == 'json') {
$result["url"] = $path[0];
} else {
$result["url"] = $path;
}
return json($result);
} else {
// 上传失败
$result['uploaded'] = false;
$result['url'] = '';
$result['message'] = $error;
return json($result);
}
} else if ((Request::param('from') == 'ueditor')) {
return $this->ueIndex();
} else {
if ($this->uploadType == 'tp') {
// webupload [file是webloader固定写入的隐藏文本名称]
return json($this->uploadFile('file'));
} else {
return json($this->bigUpload());
}
}
}
// 上传验证规则
private function uploadVal()
{
$file = [];
if (Request::param('upload_type') == 'file' || Request::param('action') == 'upload_video' | Request::param('action') == 'upload_file') {
// 文件限制
if ($this->system['upload_file_ext']) {
$file['fileExt'] = $this->removeExt($this->system['upload_file_ext']);
} else {
$file['fileExt'] = 'rar,zip,avi,rmvb,3gp,flv,mp3,mp4,txt,doc,xls,ppt,pdf,xls,docx,xlsx,doc';
}
// 限制文件大小(单位b)
if ($this->system['upload_file_size']) {
$file['fileSize'] = $this->system['upload_file_size'] * 1024;
}
} else {
// 图片限制
if ($this->system['upload_image_ext']) {
$file['fileExt'] = $this->removeExt($this->system['upload_image_ext']);
} else {
$file['fileExt'] = 'jpg,png,gif,jpeg';
}
// 限制图片大小(单位b)
if ($this->system['upload_image_size']) {
$file['fileSize'] = $this->system['upload_image_size'] * 1024;
}
}
return $file;
}
// tp上传文件
private function uploadFile(string $fileName)
{
$file = request()->file($fileName);
try {
validate($this->uploadValidate)
->check(['file' => $file]);
$savename = \think\facade\Filesystem::disk('public')->putFile('uploads', $file);
// windows系统中路径反斜杠处理
$savename = '/' . str_replace('\\', '/', $savename);
// 上传驱动
$savename = $this->uploadDriver($savename);
if (is_array($savename)) {
return [
'code' => 0,
'msg' => $savename['msg'],
'url' => '',
];
}
return [
'code' => 1,
'msg' => '上传成功',
'url' => $savename
];
} catch (\Exception $e) { // think\exception\ValidateException 取消验证异常捕获
return [
'code' => 0,
'msg' => 'ERROR:' . $e->getMessage(),
'url' => ''
];
}
}
// 大文件切片上传
private function bigUpload()
{
// 验证
$file = request()->file('file');
try {
validate($this->uploadValidate)
->check(['file' => $file]);
} catch (\Exception $e) { // think\exception\ValidateException 取消验证异常捕获
return [
'code' => 0,
'msg' => 'ERROR:' . $e->getMessage(),
'url' => ''
];
}
// Make sure file is not cached (as it happens for example on iOS devices)
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
// 跨域支持
// header("Access-Control-Allow-Origin: *");
// other CORS headers if any...
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
exit; // finish preflight CORS requests here
}
if (!empty($_REQUEST['debug'])) {
$random = rand(0, intval($_REQUEST['debug']));
if ($random === 0) {
header("HTTP/1.0 500 Internal Server Error");
exit;
}
}
// 页面执行时间不限制
@set_time_limit(5 * 60);
// Uncomment this one to fake upload time
// usleep(5000);
// Settings
// $targetDir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload";
// 设置临时上传目录
$targetDir = public_path() . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'temp';
// 设置上传目录
$uploadDir = public_path() . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . date('Ymd');
// 上传完后清空临时目录
$cleanupTargetDir = true;
// 临时文件期限
$maxFileAge = 5 * 3600;
// 创建临时目录
if (!file_exists($targetDir)) {
@mkdir($targetDir);
}
// 创建上传目录
if (!file_exists($uploadDir)) {
@mkdir($uploadDir);
}
// 获取上传文件名称
$fileName = $file->getOriginalName();
$oldName = $fileName;
$fileName = iconv('UTF-8', 'gb2312', $fileName);
// 临时上传完整目录信息
$filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName;
// 定义命名规则
$pathInfo = pathinfo($fileName);
// md5
$fileName = md5(time() . $pathInfo['basename']) . '.' . $pathInfo['extension'];
// 正式上传完整目录信息
$uploadPath = $uploadDir . DIRECTORY_SEPARATOR . $fileName;
// Chunking might be enabled
$chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
$chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 1;
// 清空临时目录
if ($cleanupTargetDir) {
if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
return [
'code' => 0,
'msg' => 'Failed to open temp directory.',
'url' => ''
];
}
while (($file = readdir($dir)) !== false) {
$tmpfilePath = $targetDir . DIRECTORY_SEPARATOR . $file;
// 如果临时文件是当前文件,则转到下一个
if ($tmpfilePath == "{$filePath}_{$chunk}.part" || $tmpfilePath == "{$filePath}_{$chunk}.parttmp") {
continue;
}
// 如果临时文件早于最大使用期限并且不是当前文件,则将其删除
if (preg_match('/\.(part|parttmp)$/', $file) && (@filemtime($tmpfilePath) < time() - $maxFileAge)) {
@unlink($tmpfilePath);
}
}
closedir($dir);
}
// 打开临时文件
if (!$out = @fopen("{$filePath}_{$chunk}.parttmp", "wb")) {
return [
'code' => 0,
'msg' => 'Failed to open output stream.',
'url' => ''
];
}
if (!empty($_FILES)) {
if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
return [
'code' => 0,
'msg' => 'Failed to move uploaded file.',
'url' => ''
];
}
// 读取二进制输入流并将其附加到临时文件
if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
return [
'code' => 0,
'msg' => 'Failed to open input stream.',
'url' => ''
];
}
} else {
if (!$in = @fopen("php://input", "rb")) {
return [
'code' => 0,
'msg' => 'Failed to open input stream.',
'url' => ''
];
}
}
while ($buff = fread($in, 4096)) {
fwrite($out, $buff);
}
@fclose($out);
@fclose($in);
rename("{$filePath}_{$chunk}.parttmp", "{$filePath}_{$chunk}.part");
$index = 0;
$done = true;
for ($index = 0; $index < $chunks; $index++) {
if (!file_exists("{$filePath}_{$index}.part")) {
$done = false;
break;
}
}
if ($done) {
if (!$out = @fopen($uploadPath, "wb")) {
return [
'code' => 0,
'msg' => 'Failed to open output stream.',
'url' => ''
];
}
if (flock($out, LOCK_EX)) {
for ($index = 0; $index < $chunks; $index++) {
if (!$in = @fopen("{$filePath}_{$index}.part", "rb")) {
break;
}
while ($buff = fread($in, 4096)) {
fwrite($out, $buff);
}
@fclose($in);
@unlink("{$filePath}_{$index}.part");
}
flock($out, LOCK_UN);
}
@fclose($out);
// 输出
// 移除public目录
$uploadPath = str_replace(public_path() . DIRECTORY_SEPARATOR, '', $uploadPath);
// windows系统中路径反斜杠处理
$uploadPath = '/' . str_replace('\\', '/', $uploadPath);
// 上传驱动
$uploadPath = $this->uploadDriver($uploadPath);
if (is_array($uploadPath)) {
return [
'code' => 0,
'msg' => $uploadPath['msg'],
'url' => '',
];
}
return [
'code' => 1,
'msg' => '上传完毕',
'url' => $uploadPath,
'title' => $_FILES["file"]['name'],
'original' => $_FILES["file"]['name'],
'state' => 'SUCCESS',
];
/*$response = [
'success'=>true,
'oldName'=>$oldName,
'filePaht'=>$uploadPath,
'fileSize'=>$data['size'],
'fileSuffixes'=>$pathInfo['extension'],
'file_id'=>$data['id'],
];
die(json_encode($response));*/
}
// Return Success JSON-RPC response
die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}');
}
// 移除上传危险后缀
private function removeExt(string $ext = '')
{
$ext = strtolower($ext);
if (strpos($ext, 'php') !== false) {
$ext = str_ireplace("php", "", $ext);
return $this->removeExt($ext);
}
if (strpos($ext, 'asp') !== false) {
$ext = str_ireplace("asp", "", $ext);
return $this->removeExt($ext);
}
return $ext;
}
// 上传驱动
private function uploadDriver(string $fineName = '')
{
if ($fineName) {
$uploadDriver = \app\common\model\System::where('id', 1)->value('upload_driver');
if ($uploadDriver == '1') {
return $fineName;
} else if ($uploadDriver == '2') {
// 阿里云
$urlArr = hook('aliyunOssHook', ['url' => $fineName]);
$urlArr = json_decode($urlArr, true);
if (isset($urlArr['error']) && $urlArr['error'] == 0) {
return $urlArr['data'];
} else {
return $urlArr;
}
} else if ($uploadDriver == '3') {
// 七牛云
$urlArr = hook('qiniuOssHook', ['url' => $fineName]);
$urlArr = json_decode($urlArr, true);
if (isset($urlArr['error']) && $urlArr['error'] == 0) {
return $urlArr['data'];
} else {
return $urlArr;
}
}
}
}
// ===================================Ueditor===================================
// 配置信息,部分信息会重新赋值,仅做参考
private $ueConfig = [
/* 上传图片配置项 */
"imageActionName" => "upload_image", /* 执行上传图片的action名称 */
"imageFieldName" => "file", /* 提交的图片表单名称 */
"imageMaxSize" => 10485760, /* 上传大小限制,单位B 102400=100KB, 512000=500KB,1048576=1M */
"imageAllowFiles" => [".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp"], /* 上传图片格式显示 */
"imageCompressEnable" => true, /* 是否压缩图片,默认是true */
"imageCompressBorder" => 1600, /* 图片压缩最长边限制 */
"imageInsertAlign" => "none", /* 插入的图片浮动方式 */
"imageUrlPrefix" => "", /* 图片访问路径前缀 */
"imagePathFormat" => "",
/* 截图工具上传 */
"snapscreenActionName" => "upload_image", /* 执行上传截图的action名称 */
"snapscreenPathFormat" => "", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"snapscreenUrlPrefix" => "", /* 图片访问路径前缀 */
"snapscreenInsertAlign" => "none", /* 插入的图片浮动方式 */
/* 抓取远程图片配置 */
"catcherLocalDomain" => ["127.0.0.1", "localhost", "img.baidu.com"],
"catcherActionName" => "catch_image", /* 执行抓取远程图片的action名称 */
"catcherFieldName" => "file", /* 提交的图片列表表单名称 */
"catcherPathFormat" => "", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"catcherUrlPrefix" => "", /* 图片访问路径前缀 */
"catcherMaxSize" => 10485760, /* 上传大小限制,单位B 102400=100KB, 512000=500KB,1048576=1M */
"catcherAllowFiles" => [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 抓取图片格式显示 */
/* 上传视频配置 */
"videoActionName" => "upload_video", /* 执行上传视频的action名称 */
"videoFieldName" => "file", /* 提交的视频表单名称 */
"videoPathFormat" => "./upload/ueditor/video/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"videoUrlPrefix" => "", /* 视频访问路径前缀 */
"videoMaxSize" => 104857600, /* 上传大小限制,单位B,默认100MB */
"videoAllowFiles" => [
".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"
], /* 上传视频格式显示 */
/* 上传文件配置 */
"fileActionName" => "upload_file", /* controller里,执行上传视频的action名称 */
"fileFieldName" => "file", /* 提交的文件表单名称 */
"filePathFormat" => "", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"fileUrlPrefix" => "", /* 文件访问路径前缀 */
"fileMaxSize" => 51200000, /* 上传大小限制,单位B,默认50MB */
"fileAllowFiles" => [
".png", ".jpg", ".jpeg", ".gif", ".bmp",
".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml",
], /* 上传文件格式显示 */
/* 列出指定目录下的图片 */
"imageManagerActionName" => "list_image", /* 执行图片管理的action名称 */
"imageManagerListPath" => "", /* 指定要列出图片的目录 */
"imageManagerListSize" => 20, /* 每次列出文件数量 */
"imageManagerUrlPrefix" => "", /* 图片访问路径前缀 */
"imageManagerInsertAlign" => "none", /* 插入的图片浮动方式 */
"imageManagerAllowFiles" => [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 列出的文件类型 */
/* 列出指定目录下的文件 */
"fileManagerActionName" => "list_file", /* 执行文件管理的action名称 */
"fileManagerListPath" => "", /* 指定要列出文件的目录 */
"fileManagerUrlPrefix" => "", /* 文件访问路径前缀 */
"fileManagerListSize" => 20, /* 每次列出文件数量 */
"fileManagerAllowFiles" => [
".png", ".jpg", ".jpeg", ".gif", ".bmp",
".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml",
], /* 列出的文件类型 */
];
// 针对ueditor的请求链接进行分发
private function ueIndex()
{
$action = Request::param('action', '');
switch ($action) {
case 'config':
return json($this->ueConfig);
break;
/* 上传图片 */
case 'upload_image':
return json($this->bigUpload());
break;
/* 上传视频 */
case 'upload_video':
return json($this->bigUpload());
break;
/* 上传文件 */
case 'upload_file':
return json($this->bigUpload());
break;
/* 列出图片 */
case 'list_image':
$allowFiles = $this->system['upload_image_ext'];
$listSize = $this->ueConfig['imageManagerListSize'];
$path = public_path() . 'uploads';
$get = Request::param();
$result = $this->fileList($allowFiles, $listSize, $path, $get);
break;
/* 列出文件 */
case 'list_file':
$allowFiles = $this->system['upload_file_ext'];
$listSize = $this->ueConfig['imageManagerListSize'];
$path = public_path() . 'uploads';
$get = Request::param();
$result = $this->fileList($allowFiles, $listSize, $path, $get);
break;
/* 抓取远程文件 */
case 'catch_image':
$config = [
"maxSize" => $this->system['upload_image_size'],
"allowFiles" => $this->system['upload_image_ext'] ? explode(',', $this->system['upload_image_ext']) : [],
"oriName" => "remote.png",
];
/* 抓取远程图片 */
$list = [];
$failList = []; //错误的列表
$source = Request::param('file');
if (empty($source)) {
return $this->error('参数错误');
}
foreach ($source as $imgUrl) {
$remoteResult = $this->saveRemote($config, $imgUrl);
if (is_array($remoteResult) && $remoteResult['code'] == 1) {
array_push($list, [
"state" => $remoteResult["state"],
"url" => $remoteResult["url"],
"size" => $remoteResult["size"],
"title" => htmlspecialchars($remoteResult["title"]),
"original" => htmlspecialchars($remoteResult["original"]),
"source" => htmlspecialchars($imgUrl),
]);
} else {
array_push($failList, [
"state" => 'ERROR',
"source" => htmlspecialchars($imgUrl),
]);
}
}
$result = [
'state' => count($list) ? 'SUCCESS' : 'ERROR',
'list' => $list,
'fail_list' => $failList,
];
break;
default:
return $this->error('请求地址出错');
break;
}
return json($result);
}
/**
* 文件列表
* @param string $allowFiles 指定的文件后缀
* @param int $listSize 列表分页数量
* @param string $path 文件目录
* @param array $get ['size'=>xxx,'start'=>xxx]
* @return array
*/
private function fileList($allowFiles, $listSize, $path, $get)
{
$dirname = $path;
$allowFiles = substr(str_replace(",", "|", $allowFiles), 0);
/* 获取参数 */
$size = isset($get['size']) ? htmlspecialchars($get['size']) : $listSize;
$start = isset($get['start']) ? htmlspecialchars($get['start']) : 0;
$end = $start + $size;
/* 获取文件列表 */
$files = $this->getFiles($dirname, $allowFiles);
if (!count($files)) {
return [
"code" => 0,
"state" => "no match file",
"list" => [],
"start" => $start,
"total" => count($files),
];
}
/* 获取指定范围的列表 */
$len = count($files);
for ($i = min($end, $len) - 1, $list = array(); $i < $len && $i >= 0 && $i >= $start; $i--) {
$list[] = $files[$i];
}
/* 返回数据 */
$result = [
"code" => 1,
"state" => "SUCCESS",
"list" => $list,
"start" => $start,
"total" => count($files),
];
return $result;
}
/**
* 遍历获取目录下的指定类型的文件
* @param string $path 文件路径
* @param string $allowFiles 指定的文件后缀,以|分隔的文本
* @param array $files 文件数组
* @return array
*/
private function getFiles($path, $allowFiles, &$files = array())
{
if (!is_dir($path)) {
return [];
}
if (substr($path, strlen($path) - 1) != '/') {
$path .= '/';
}
$handle = opendir($path);
while (false !== ($file = readdir($handle))) {
if ($file != '.' && $file != '..') {
$path2 = $path . $file;
if (is_dir($path2)) {
$this->getFiles($path2, $allowFiles, $files);
} else {
if (preg_match("/\.(" . $allowFiles . ")$/i", $file)) {
$files[] = array(
'url' => preg_replace('/(.*)upload/i', '/upload', $path2),
'mtime' => filemtime($path2),
);
}
}
}
}
return $files;
}
/**
* 拉取远程图片
* @return mixed
*/
private function saveRemote($config, $fieldName)
{
$imgUrl = htmlspecialchars($fieldName);
$imgUrl = str_replace("&amp;", "&", $imgUrl);
// http开头验证
if (strpos($imgUrl, "http") !== 0) {
return [
'code' => 0,
'msg' => '链接不是http|https链接',
'url' => '',
];
}
// 获取请求头并检测死链
$heads = get_headers($imgUrl, true);
if (!(stristr($heads[0], "200") && stristr($heads[0], "OK"))) {
return [
'code' => 0,
'msg' => '链接不可用',
'url' => '',
];
}
// 格式验证(扩展名验证和Content-Type验证)
$fileType = strtolower(strrchr(strrchr($imgUrl, '/'), '.'));
$fileType = ltrim($fileType, '.');
// img链接后缀可能为空,Content-Type须为image
if ((!empty($fileType) && !in_array($fileType, $config['allowFiles'])) || stristr($heads['Content-Type'], "image") === -1) {
return [
'code' => 0,
'msg' => '链接contentType不正确',
'url' => '',
];
}
// 解析出域名作为http_referer
$urlArr = explode('/', $imgUrl);
$protocol = str_replace(':', '', $urlArr[0]);
$httpReferer = $protocol . ':' . '//' . $urlArr[2];
// 打开输出缓冲区并获取远程图片
ob_start();
$context = stream_context_create([
'http' => array(
//'header' => "Referer:$httpReferer", //突破防盗链,不可用
'user_agent' => 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36', //突破防盗链
'follow_location' => false, // don't follow redirects
),
]);
$res = false;
$message = '';
try {
$res = readfile($imgUrl, false, $context);
} catch (\Exception $e) {
$message = $e->getMessage();
}
$img = ob_get_contents();
ob_end_clean();
if ($res === false) {
return [
'code' => 0,
'msg' => $message,
'url' => '',
];
}
preg_match("/[\/]([^\/]*)[\.]?[^\.\/]*$/", $imgUrl, $fileName);
$dirname = public_path() . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . date('Ymd') . DIRECTORY_SEPARATOR;
$file['oriName'] = $fileName ? $fileName[1] : "";
$file['filesize'] = strlen($img);
$file['ext'] = strtolower(strrchr($config['oriName'], '.'));
$file['name'] = uniqid() . $file['ext'];
$file['fullName'] = $dirname . $file['name'];
$fullName = $file['fullName'];
// 检查文件大小是否超出限制
if ($config["maxSize"] > 0 && $file['filesize'] >= $config["maxSize"] * 1024) {
return [
'code' => 0,
'msg' => '文件大小超出网站限制',
'url' => '',
];
}
// 创建目录失败
if (!file_exists($dirname) && !mkdir($dirname, 0777, true)) {
return [
'code' => 0,
'msg' => '目录创建失败',
'url' => '',
];
} else if (!is_writeable($dirname)) {
return [
'code' => 0,
'msg' => '目录没有写权限',
'url' => '',
];
}
// 移动文件
if (!(file_put_contents($fullName, $img) && file_exists($fullName))) {
return [
'code' => 0,
'msg' => '写入文件内容错误',
'url' => '',
];
}
// 移动成功
$data = array(
'code' => 1,
'state' => 'SUCCESS',
'url' => '/uploads/' . date('Ymd') . '/' . $file['name'],
'title' => $file['name'],
'original' => $file['oriName'],
'type' => $file['ext'],
'size' => $file['filesize'],
);
return $data;
}
}

47
app/admin/controller/Users.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 会员管理控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class Users extends Base
{
// 验证器
protected $validate = 'Users';
// 当前主表
protected $tableName = 'users';
// 当前主模型
protected $modelName = 'Users';
}

47
app/admin/controller/UsersType.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 会员分组控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class UsersType extends Base
{
// 验证器
protected $validate = 'UsersType';
// 当前主表
protected $tableName = 'users_type';
// 当前主模型
protected $modelName = 'UsersType';
}

21
app/admin/event.php

@ -0,0 +1,21 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// 事件定义文件
return [
'bind' => [
// 更多事件绑定
],
'listen' => [
'AdminLogin' => ['app\admin\listener\AdminLogin'],
// 更多事件监听
],
];

12
app/admin/facade/ThinkAddons.php

@ -0,0 +1,12 @@
<?php
namespace app\admin\facade;
use think\Facade;
class ThinkAddons extends Facade
{
protected static function getFacadeClass()
{
return 'app\admin\service\ThinkAddons';
}
}

14
app/admin/listener/AdminLogin.php

@ -0,0 +1,14 @@
<?php
namespace app\admin\listener;
use app\common\model\AdminLog;
class AdminLogin
{
public function handle($admin)
{
// 事件监听处理
AdminLog::record();
}
}

157
app/admin/middleware/Admin.php

@ -0,0 +1,157 @@
<?php
/**
* +----------------------------------------------------------------------
* | 后台中间件
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/03/08
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\middleware;
use think\facade\Session;
use think\facade\Request;
use think\Response;
use think\exception\HttpResponseException;
class Admin
{
public function handle($request, \Closure $next)
{
// 获取当前用户
$admin_id = Session::get('admin.id');
if (empty($admin_id)) {
return redirect((string)url('Login/index'));
}
// 定义方法白名单
$allow = [
'Index/index', // 首页
'Index/clear', // 清除缓存
'Index/preview', // 预览
'Index/select2', // ajax select2
'Upload/index', // 上传文件
'Login/index', // 登录页面
'Login/checkLogin', // 校验登录
'Login/captcha', // 登录验证码
'Login/logout', // 退出登录
];
// 查询所有不验证的方法并放入白名单
$authOpen = \app\common\model\AuthRule::where('auth_open', '=', '0')
->select();
$authRole = \app\common\model\AuthRule::select();
$authOpens = [];
foreach ($authOpen as $k => $v) {
// 转换方法名为小写
$ruleName = explode('/', $v['name']);
if ($ruleName[1]) {
$ruleName[1] = strtolower($ruleName[1]);
}
// 转换控制器首字母大写
$ruleName = trim(implode('/', $ruleName));
$authOpens[] = ucfirst($ruleName);
// 查询所有下级权限
$ids = getChildsRule($authRole, $v['id']);
foreach ($ids as $kk => $vv) {
// 转换方法名为小写
$ruleName = explode('/', $vv['name']);
if ($ruleName[1]) {
$ruleName[1] = strtolower($ruleName[1]);
}
// 转换控制器首字母大写
$ruleName = trim(implode('/', $ruleName));
$authOpens[] = ucfirst($ruleName);
}
}
$allow = array_merge($allow, $authOpens);
// 查找当前控制器和方法,控制器首字母大写,方法名首字母小写 如:Index/index
$route = Request::controller() . '/' . lcfirst(Request::action());
// 权限认证
if (!in_array($route, $allow)) {
if ($admin_id != 1) {
//开始认证
$auth = new \Auth();
$result = $auth->check($route, $admin_id);
if (!$result) {
$this->error('您无此操作权限!');
}
}
}
// 进行操作日志的记录
\app\common\model\AdminLog::record();
// 当url中有ref=tab时表示刷新当前页(用于后台tab模式刷新)
if (Request::get("ref") == 'tab') {
// 去除url中ref参数
$url = preg_replace_callback("/([\?|&]+)ref=tab(&?)/i", function ($matches) {
return $matches[2] == '&' ? $matches[1] : '';
}, Request::url());
// 重定向隐式传值使用的是Session闪存数据隐式传值,并且仅在下一次请求有效,再次访问重定向地址的时候无效
return redirect('Index/index')->with('referer', $url);
}
// 中间件handle方法的返回值必须是一个Response对象。
return $next($request);
}
/**
* 操作错误跳转
* @param mixed $msg 提示信息
* @param string $url 跳转的URL地址
* @param mixed $data 返回的数据
* @param integer $wait 跳转等待时间
* @param array $header 发送的Header信息
* @return void
*/
protected function error($msg = '', string $url = null, $data = '', int $wait = 3, array $header = []): Response
{
if (is_null($url)) {
$url = request()->isAjax() ? '' : 'javascript:history.back(-1);';
} elseif ($url) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : app('route')->buildUrl($url);
}
$result = [
'code' => 0,
'msg' => $msg,
'data' => $data,
'url' => $url,
'wait' => $wait,
];
$type = (request()->isJson() || request()->isAjax()) ? 'json' : 'html';
// 所有form返回的都必须是json,所有A链接返回的都必须是Html
$type = request()->isGet() ? 'html' : $type;
if ($type == 'html') {
$response = view(app('config')->get('app.dispatch_error_tmpl'), $result);
} else if ($type == 'json') {
$response = json($result);
}
throw new HttpResponseException($response);
}
}

68
app/admin/model/Base.php

@ -0,0 +1,68 @@
<?php
namespace app\admin\model;
use think\facade\Session;
use think\Model;
class Base extends Model
{
// 获取左侧主菜单
public static function getMenus()
{
$authRule = \app\common\model\AuthRule::where('status', 1)
->order('sort asc')
->select()
->toArray();
$menus = [];
// 查找一级
foreach ($authRule as $key => $val) {
$authRule[$key]['href'] = (string)url($val['name']);
if ($val['pid'] == 0) {
if (Session::get('admin.id') != 1) {
if (in_array($val['id'], Session::get('admin.rules', []))) {
$menus[] = $val;
}
} else {
$menus[] = $val;
}
}
}
// 查找二级
foreach ($menus as $k => $v) {
$menus[$k]['children'] = [];
foreach ($authRule as $kk => $vv) {
if ($v['id'] == $vv['pid']) {
if (Session::get('admin.id') != 1) {
if (in_array($vv['id'], Session::get('admin.rules'))) {
$menus[$k]['children'][] = $vv;
}
} else {
$menus[$k]['children'][] = $vv;
}
}
}
}
// 查找三级
foreach ($menus as $k => $v) {
if ($v['children']) {
// 循环二级
foreach ($v['children'] as $kk => $vv) {
$menus[$k]['children'][$kk]['children'] = [];
foreach ($authRule as $kkk => $vvv) {
if ($vv['id'] == $vvv['pid']) {
if (Session::get('admin.id') != 1) {
if (in_array($vvv['id'], Session::get('admin.rules'))) {
$menus[$k]['children'][$kk]['children'][] = $vvv;
}
} else {
$menus[$k]['children'][$kk]['children'][] = $vvv;
}
}
}
}
}
}
return $menus;
}
}

502
app/admin/service/ThinkAddons.php

@ -0,0 +1,502 @@
<?php
/**
* +----------------------------------------------------------------------
* | 插件服务类
* +----------------------------------------------------------------------
* test // 插件名称
* ├── app // 此文件夹中所有文件会覆盖到根目录的/app文件夹
* ├── public // 此文件夹中所有文件会覆盖到根目录的/public文件夹
* ├── controller // 此文件夹为插件控制器目录
* ├── model // 此文件夹为插件模型目录
* ├── view // 此文件夹为插件视图目录
* ├── Plugin.php // 此文件为插件核心安装卸载控制器,必需存在,且名称不可以变动
* ├── config.php // 插件配置文件,后台插件管理中配置中读取和保存的就是这个文件,必须存在,且名称不可以变动
* ├── config.html // 插件配置模板文件,优先获取此文件,不存在则调用表单构建器[可选]
* ├── LICENSE // 版权文件
* ├── info.ini // 插件信息文件,用于保存插件基本信息,不存在则读取Plugin中的配置
* └── install.sql // 插件数据库安装文件,此文件仅在插件安装时会进行导入,如重复安装可能会导致报错
*/
namespace app\admin\service;
use think\Facade;
use think\facade\Config;
use think\facade\Db;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
class ThinkAddons
{
// 插件目录
protected $addonsPath = '';
// 插件安装需要复制的文件夹
protected $copyDirs = [];
// 构造方法
public function __construct()
{
$this->addonsPath = app()->getRootPath() . 'addons';
$this->copyDirs = [
'app', // 此文件夹中所有文件会覆盖到根目录的/app文件夹
'public', // 此文件夹中所有文件会覆盖到根目录的/public文件夹
];
}
// 获得本地插件列表 [目前只获取本地插件,后期会扩展为获取线上插件]
public function localAddons()
{
$plugins = scandir($this->addonsPath);
$list = [];
foreach ($plugins as $name) {
if ($name === '.' or $name === '..')
continue;
if (is_file($this->addonsPath . DIRECTORY_SEPARATOR . $name))
continue;
$addonDir = $this->addonsPath . DIRECTORY_SEPARATOR . $name . DIRECTORY_SEPARATOR;
if (!is_dir($addonDir))
continue;
$object = $this->getInstance($name);
if ($object) {
// 获取插件基础信息
$info = $object->getInfo();
// 增加右侧按钮组
$str = '';
if ($info['install'] == 1) {
// 已安装,增加配置按钮
$str .= '<a class="btn btn-primary btn-xs" href="javascript:void(0)" onclick="$.operate.edit(\''.$name.'\')"><i class="fa fa-edit"></i> 配置</a> ';
$str .= '<a class="btn btn-danger btn-xs confirm" href="javascript:void(0)" onclick="$.operate.pluginUninstall(\'' . $name . '\')"><i class="fa fa-edit"></i> 卸载</a> ';
} else {
// 未安装,增加安装按钮
$str = '<a class="btn btn-primary btn-xs" href="javascript:void(0)" onclick="$.operate.pluginInstall(\'' . $name . '\')"><i class="fa fa-edit"></i> 安装</a>';
}
$info['button'] = $str;
$list[] = $info;
}
}
return $list;
}
// 获取插件信息
public function config(string $name)
{
$check = $this->check($name);
if ($check !== true) {
return [
'code' => 0,
'msg' => $check
];
}
return $this->getConfig($name);
}
// 保存插件信息
public function configPost(array $data = [])
{
$check = $this->check($data['id']);
if ($check !== true) {
return [
'code' => 0,
'msg' => $check
];
}
// 实例化插件
$object = $this->getInstance($data['id']);
if ($object) {
// 获取插件配置信息
$config = $this->getConfig($data['id']);
// 判断是否分组
$group = $this->checkConfigGroup($config);
if ($data) {
if ($group) {
// 开启分组
foreach ($config as $k => $v) {
foreach ($v as $kk => $vv) {
if (isset($data[$kk])) {
$value = is_array($data[$kk]) ? implode(',', $data[$kk]) : ($data[$kk] ?? $vv['value']);
$config[$k][$kk]['value'] = $value;
}
}
}
} else {
// 未开启分组
foreach ($config as $k => $v) {
if (isset($data[$k])) {
$value = is_array($data[$k]) ? implode(',', $data[$k]) : ($data[$k] ?? $v['value']);
$config[$k]['value'] = $value;
}
}
}
}
// 更新配置文件
$result = $this->setPluginConfig($data['id'], $config);
if ($result['code'] == 1) {
return [
'code' => 1,
'msg' => '保存成功!'
];
} else {
return [
'code' => 0,
'msg' => $result['msg']
];
}
} else {
return [
'code' => 0,
'msg' => '插件实例化失败'
];
}
}
// 启用插件或禁用插件
public function state(string $name)
{
$check = $this->check($name);
if ($check !== true) {
return [
'code' => 0,
'msg' => $check
];
}
// 实例化插件
$object = $this->getInstance($name);
// 获取插件基础信息
$info = $object->getInfo();
if (!$info) {
return [
'code' => 0,
'msg' => '未找到该插件的信息'
];
} else {
// 请先安装
if ($info['install'] != 1) {
return [
'code' => 0,
'msg' => '请先安装该插件',
];
} else {
return $this->changeStatus($name);
}
}
}
// 安装插件
public function install(string $name)
{
// 实例化插件
$object = $this->getInstance($name);
// 获取插件基础信息
$info = $object->getInfo();
if (false !== $object->install()) {
$info['status'] = 1;
$info['install'] = 1;
try {
// 更新或创建插件的ini文件
$result = $this->setPluginIni($name, $info);
if ($result['code'] == 0) {
return [
'code' => 1,
'msg' => $result['msg'],
];
}
// 复制文件
$this->copyDir($name);
// 导入SQL
$this->importsql($name);
} catch (\Exception $e) {
return [
'code' => 0,
'msg' => '安装失败:' . $e->getMessage(),
];
}
} else {
return [
'code' => 0,
'msg' => '插件实例化失败',
];
}
return [
'code' => 1,
'msg' => '插件安装成功',
];
}
// 卸载插件
public function uninstall(string $name)
{
// 实例化插件
$object = $this->getInstance($name);
// 获取插件基础信息
$info = $object->getInfo();
if (false !== $object->uninstall()) {
$info['status'] = 0;
$info['install'] = 0;
// 更新或创建插件的ini文件
$result = $this->setPluginIni($name, $info);
if ($result['code'] == 0) {
return [
'code' => 0,
'msg' => $result['msg'],
];
} else {
return [
'code' => 1,
'msg' => '插件卸载成功',
];
}
} else {
return [
'code' => 0,
'msg' => '插件实例化失败',
];
}
}
// 启用/禁用插件
public function changeStatus(string $name)
{
// 实例化插件
$object = $this->getInstance($name);
// 获取插件基础信息
$info = $object->getInfo();
if (false !== $object->install()) {
$info['status'] = $info['status'] == 1 ? 0 : 1;
try {
// 更新或创建插件的ini文件
$result = $this->setPluginIni($name, $info);
if ($result['code'] == 0) {
return [
'code' => 1,
'msg' => $result['msg'],
];
}
} catch (\Exception $e) {
return [
'code' => 0,
'msg' => '状态变动失败:' . $e->getMessage(),
];
}
} else {
return [
'code' => 0,
'msg' => '插件实例化失败',
];
}
return [
'code' => 1,
'msg' => '状态变动成功',
];
}
// 判断插件配置文件是否进行了分组
public function checkConfigGroup(array $config)
{
// 空配置信息
if (!$config) {
return false;
}
// 获取第一个元素
$arrayShift = array_shift($config);
if (array_key_exists('title', $arrayShift) && array_key_exists('type', $arrayShift)) {
// 未开启分组
return false;
} else {
// 开启分组
return true;
}
}
// ===========================================
// 验证插件是否完整
private function check(string $name)
{
if (!is_dir($this->addonsPath . DIRECTORY_SEPARATOR . $name)) {
return '未发现该插件,请先下载并放入到addons目录中';
}
return true;
}
// 获取插件实例
private function getInstance(string $file)
{
$class = "\\addons\\{$file}\\Plugin";
if (class_exists($class)) {
// 容器类的工作由think\Container类完成,但大多数情况我们只需要通过app助手函数或者think\App类即可容器操作
return app($class);
}
return false;
}
// 获取完整配置列表[config.php]
private function getConfig(string $name)
{
$file = app()->getRootPath() . 'addons' . DIRECTORY_SEPARATOR . $name . DIRECTORY_SEPARATOR . 'config.php';
if (file_exists($file)) {
return include $file;
} else {
return false;
}
}
/**
* 更新插件的配置文件
* @param string $name 插件名
* @param array $array
* @return boolean
* @throws Exception
*/
private function setPluginConfig(string $name, array $array = [])
{
$file = $this->addonsPath . DIRECTORY_SEPARATOR . $name . DIRECTORY_SEPARATOR . 'config.php';
if (!$this->checkFileWritable($file)) {
return [
'code' => 0,
'msg' => '文件没有写入权限',
];
}
if ($handle = fopen($file, 'w')) {
fwrite($handle, "<?php\n\n" . "return " . var_export($array, TRUE) . ";\n");
fclose($handle);
} else {
return [
'code' => 0,
'msg' => '文件没有写入权限',
];
}
return [
'code' => 1,
'msg' => '文件写入完毕',
];
}
/**
* 更新插件的ini文件
* @param string $name 插件名
* @param array $array
* @return boolean
* @throws Exception
*/
private function setPluginIni(string $name, array $array = [])
{
$file = $this->addonsPath . DIRECTORY_SEPARATOR . $name . DIRECTORY_SEPARATOR . 'info.ini';
if (!$this->checkFileWritable($file)) {
return [
'code' => 0,
'msg' => '文件没有写入权限',
];
}
// 拼接要写入的数据
$str = '';
foreach ($array as $k => $v) {
$str .= $k . " = " . $v . "\n";
}
if ($handle = fopen($file, 'w')) {
fwrite($handle, $str);
fclose($handle);
} else {
return [
'code' => 0,
'msg' => '文件没有写入权限',
];
}
return [
'code' => 1,
'msg' => '文件写入完毕',
];
}
/**
* 判断文件或目录是否可写
* @param string $file 文件或目录
* @return bool
*/
private function checkFileWritable(string $file)
{
if (is_dir($file)) {
// 判断目录是否可写
return is_writable($file);
} elseif (file_exists($file)) {
// 文件存在则判断文件是否可写
return is_writable($file);
} else {
// 文件不存在则判断当前目录是否可写
$file = pathinfo($file, PATHINFO_DIRNAME);
return is_writable($file);
}
}
// 导入SQL
private function importsql(string $name)
{
$sqlFile = $this->addonsPath . DIRECTORY_SEPARATOR . $name . DIRECTORY_SEPARATOR . 'install.sql';
if (is_file($sqlFile)) {
$lines = file($sqlFile);
$templine = '';
foreach ($lines as $line) {
if (substr($line, 0, 2) == '--' || $line == '' || substr($line, 0, 2) == '/*')
continue;
$templine .= $line;
if (substr(trim($line), -1, 1) == ';') {
// 不区分大小写替换前缀
$templine = str_ireplace('__PREFIX__', Config::get('database.connections.mysql.prefix'), $templine);
// 忽略数据库中已经存在的数据
$templine = str_ireplace('INSERT INTO ', 'INSERT IGNORE INTO ', $templine);
try {
Db::execute($templine);
} catch (\PDOException $e) {
//$e->getMessage();
}
$templine = '';
}
}
}
return true;
}
// 安装时复制文件
private function copyDir(string $name)
{
$addonDir = $this->addonsPath . DIRECTORY_SEPARATOR . $name . DIRECTORY_SEPARATOR;
foreach ($this->copyDirs as $k => $dir) {
if (is_dir($addonDir . $dir)) {
$this->copydirs($addonDir . $dir, app()->getRootPath() . $dir);
}
}
}
/**
* 复制文件夹到另一个文件夹
* @param string $source 源文件夹
* @param string $dest 目标文件夹
*/
private function copydirs($source, $dest)
{
if (!is_dir($dest)) {
mkdir($dest, 0755, true);
}
foreach (
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
) as $item
) {
if ($item->isDir()) {
$sontDir = $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName();
if (!is_dir($sontDir)) {
mkdir($sontDir, 0755, true);
}
} else {
copy($item, $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
}
}
}
}

52
app/admin/validate/Ad.php

@ -0,0 +1,52 @@
<?php
/**
* +----------------------------------------------------------------------
* | 广告管理验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Ad extends Validate
{
protected $rule = [
'sort|排序' => [
'require' => 'require',
'max' => '8',
'number' => 'number',
],
'status|状态' => [
'require' => 'require',
'max' => '1',
],
'type_id|广告位' => [
'require' => 'require',
],
'name|广告名称' => [
'require' => 'require',
],
'description|备注' => [
'max' => '250',
]
];
}

44
app/admin/validate/AdType.php

@ -0,0 +1,44 @@
<?php
/**
* +----------------------------------------------------------------------
* | 广告分组验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class AdType extends Validate
{
protected $rule = [
'name|分组名称' => [
'require' => 'require',
],
'sort|排序' => [
'require' => 'require',
'number' => 'number',
],
'status|状态' => [
'require' => 'require',
]
];
}

55
app/admin/validate/Admin.php

@ -0,0 +1,55 @@
<?php
/**
* +----------------------------------------------------------------------
* | 管理员列表验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/02/03
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Admin extends Validate
{
protected $rule = [
'status|状态' => [
'require' => 'require',
'max' => '1',
],
'username|用户名' => [
'require' => 'require',
'max' => '25',
'min' => '4',
],
'password|密码' => [
'max' => '50',
'min' => '5',
],
'nickname|昵称' => [
'require' => 'require',
'max' => '25',
'min' => '4',
],
'image|头像' => [
'require' => 'require',
]
];
}

43
app/admin/validate/AdminLog.php

@ -0,0 +1,43 @@
<?php
/**
* +----------------------------------------------------------------------
* | 管理员日志验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/02/03
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class AdminLog extends Validate
{
protected $rule = [
'admin_id|管理员' => [
'max' => '8',
],
'title|日志标题' => [
'max' => '100',
],
'ip|操作IP' => [
'max' => '20',
]
];
}

55
app/admin/validate/Article.php

@ -0,0 +1,55 @@
<?php
/**
* +----------------------------------------------------------------------
* | 文章模块验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Article extends Validate
{
protected $rule = [
'sort|排序' => [
'require' => 'require',
'max' => '8',
'number' => 'number',
],
'status|状态' => [
'require' => 'require',
'max' => '1',
],
'cate_id|栏目' => [
'require' => 'require',
],
'title|标题' => [
'require' => 'require',
],
'hits|点击次数' => [
'number' => 'number',
],
'template|模板' => [
'max' => '30',
]
];
}

41
app/admin/validate/AuthGroup.php

@ -0,0 +1,41 @@
<?php
/**
* +----------------------------------------------------------------------
* | 角色组管理验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/02/02
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class AuthGroup extends Validate
{
protected $rule = [
'status|状态' => [
'require' => 'require',
'max' => '1',
],
'title|角色组' => [
'require' => 'require',
]
];
}

45
app/admin/validate/AuthRule.php

@ -0,0 +1,45 @@
<?php
/**
* +----------------------------------------------------------------------
* | 菜单规则验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/02/03
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class AuthRule extends Validate
{
protected $rule = [
'status|菜单状态' => [
'require' => 'require',
'max' => '1',
],
'name|控制器/方法' => [
'require' => 'require',
'unique' => 'auth_rule', // 唯一
],
'title|权限名称' => [
'require' => 'require',
]
];
}

85
app/admin/validate/Cate.php

@ -0,0 +1,85 @@
<?php
/**
* +----------------------------------------------------------------------
* | 栏目管理验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2020/02/05
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Cate extends Validate
{
protected $rule = [
'sort|排序' => [
'require' => 'require',
'max' => '8',
'number' => 'number',
],
'status|状态' => [
'require' => 'require',
'max' => '1',
],
'cate_name|栏目名称' => [
'require' => 'require',
'max' => '255',
],
'en_name|英文名称' => [
'max' => '255',
],
'cate_folder|栏目目录' => [
'max' => '255',
'unique' => 'cate'
],
'module_id|所属模块' => [
'require' => 'require',
],
'url|外部链接' => [
'max' => '255',
],
'image|栏目图片' => [
'max' => '255',
],
'ico_image|ICO图片' => [
'max' => '255',
],
'title|SEO标题' => [
'max' => '255',
],
'keywords|SEO关键字' => [
'max' => '255',
],
'description|SEO描述' => [
'max' => '255',
],
'template_list|列表模板' => [
'max' => '255',
],
'template_show|详情模版' => [
'max' => '255',
],
'page_size|分页条数' => [
'max' => '5',
'number' => 'number',
]
];
}

57
app/admin/validate/Debris.php

@ -0,0 +1,57 @@
<?php
/**
* +----------------------------------------------------------------------
* | 碎片管理验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Debris extends Validate
{
protected $rule = [
'sort|排序' => [
'require' => 'require',
'max' => '8',
'number' => 'number',
],
'status|状态' => [
'require' => 'require',
'max' => '1',
],
'title|碎片标题' => [
'require' => 'require',
'max' => '255',
],
'name|调用名称' => [
'require' => 'require',
'max' => '255',
],
'url|链接地址' => [
'max' => '255',
],
'description|描述' => [
'max' => '255',
]
];
}

56
app/admin/validate/Dictionary.php

@ -0,0 +1,56 @@
<?php
/**
* +----------------------------------------------------------------------
* | 字典数据验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Dictionary extends Validate
{
protected $rule = [
'dict_label|字典标签' => [
'require' => 'require',
'max' => '100',
],
'dict_value|字典键值' => [
'require' => 'require',
],
'dict_type|字典类型' => [
'require' => 'require',
'max' => '5',
],
'remark|备注' => [
'max' => '200',
],
'sort|排序' => [
'require' => 'require',
'max' => '5',
'number' => 'number',
],
'status|状态' => [
'require' => 'require',
]
];
}

49
app/admin/validate/DictionaryType.php

@ -0,0 +1,49 @@
<?php
/**
* +----------------------------------------------------------------------
* | 字典类型验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class DictionaryType extends Validate
{
protected $rule = [
'dict_name|字典名称' => [
'require' => 'require',
'max' => '100',
],
'status|状态' => [
'require' => 'require',
],
'remark|备注' => [
'max' => '200',
],
'sort|排序' => [
'require' => 'require',
'max' => '5',
'number' => 'number',
]
];
}

55
app/admin/validate/Download.php

@ -0,0 +1,55 @@
<?php
/**
* +----------------------------------------------------------------------
* | 下载模块验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Download extends Validate
{
protected $rule = [
'sort|排序' => [
'require' => 'require',
'max' => '8',
'number' => 'number',
],
'status|状态' => [
'require' => 'require',
'max' => '1',
],
'cate_id|栏目' => [
'require' => 'require',
],
'title|标题' => [
'require' => 'require',
],
'hits|点击次数' => [
'number' => 'number',
],
'template|模板' => [
'max' => '30',
]
];
}

61
app/admin/validate/Field.php

@ -0,0 +1,61 @@
<?php
/**
* +----------------------------------------------------------------------
* | 字段管理验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2019/05/25
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Field extends Validate
{
protected $rule = [
'module_id|所属模块' => [
'require' => 'require',
'max' => '3',
],
'type|字段类型' => [
'require' => 'require',
'max' => '40',
],
'field|字段名' => [
'require' => 'require',
'max' => '40',
],
'name|别名' => [
'require' => 'require',
'max' => '30',
],
'minlength|字符长度' => [
'max' => '10',
],
'maxlength|字符长度' => [
'max' => '10',
],
'sort|排序' => [
'require' => 'require',
'number' => 'number',
'max' => '10',
]
];
}

49
app/admin/validate/FieldGroup.php

@ -0,0 +1,49 @@
<?php
/**
* +----------------------------------------------------------------------
* | 字段分组验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class FieldGroup extends Validate
{
protected $rule = [
'module_id|所属模块' => [
'require' => 'require',
'max' => '5',
],
'group_name|分组名称' => [
'require' => 'require',
],
'status|状态' => [
'require' => 'require',
],
'sort|排序' => [
'require' => 'require',
'max' => '5',
'number' => 'number',
]
];
}

47
app/admin/validate/Link.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | 友情链接验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Link extends Validate
{
protected $rule = [
'name|网站名称' => [
'require' => 'require',
],
'url|网站地址' => [
'require' => 'require',
],
'sort|排序' => [
'require' => 'require',
'number' => 'number',
],
'status|状态' => [
'require' => 'require',
]
];
}

50
app/admin/validate/Message.php

@ -0,0 +1,50 @@
<?php
/**
* +----------------------------------------------------------------------
* | 留言模块验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Message extends Validate
{
protected $rule = [
'title|标题' => [
'require' => 'require',
],
'cate_id|栏目' => [
'require' => 'require',
],
'status|状态' => [
'require' => 'require',
'max' => '1',
],
'name|姓名' => [
'max' => '255',
],
'phone|电话' => [
'max' => '255',
]
];
}

63
app/admin/validate/Module.php

@ -0,0 +1,63 @@
<?php
/**
* +----------------------------------------------------------------------
* | 模块管理验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2019/05/25
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Module extends Validate
{
protected $rule = [
'module_name|模块名称' => [
'require' => 'require',
'max' => '100',
],
'table_name|表名称' => [
'require' => 'require',
'max' => '50',
],
'model_name|模型名称' => [
'require' => 'require',
'max' => '50',
],
'table_comment|表注释' => [
'max' => '200',
],
'table_type|表类型' => [
'require' => 'require',
'max' => '10',
],
'pk|主键' => [
'require' => 'require',
'max' => '50',
],
'sort|排序' => [
'require' => 'require',
'number' => 'number',
'max' => '3',
]
];
}

49
app/admin/validate/Page.php

@ -0,0 +1,49 @@
<?php
/**
* +----------------------------------------------------------------------
* | 单页模块验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Page extends Validate
{
protected $rule = [
'status|状态' => [
'require' => 'require',
'max' => '1',
],
'sort|排序' => [
'require' => 'require',
'max' => '8',
'number' => 'number',
],
'cate_id|栏目' => [
'require' => 'require',
],
'title|标题' => [
'max' => '255',
]
];
}

55
app/admin/validate/Picture.php

@ -0,0 +1,55 @@
<?php
/**
* +----------------------------------------------------------------------
* | 图片模块验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Picture extends Validate
{
protected $rule = [
'sort|排序' => [
'require' => 'require',
'max' => '8',
'number' => 'number',
],
'status|状态' => [
'require' => 'require',
'max' => '1',
],
'cate_id|栏目' => [
'require' => 'require',
],
'title|标题' => [
'require' => 'require',
],
'hits|点击次数' => [
'number' => 'number',
],
'template|模板' => [
'max' => '30',
]
];
}

55
app/admin/validate/Product.php

@ -0,0 +1,55 @@
<?php
/**
* +----------------------------------------------------------------------
* | 产品模块验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Product extends Validate
{
protected $rule = [
'sort|排序' => [
'require' => 'require',
'max' => '8',
'number' => 'number',
],
'status|状态' => [
'require' => 'require',
'max' => '1',
],
'cate_id|栏目' => [
'require' => 'require',
],
'title|标题' => [
'require' => 'require',
],
'hits|点击次数' => [
'number' => 'number',
],
'template|模板' => [
'max' => '30',
]
];
}

46
app/admin/validate/System.php

@ -0,0 +1,46 @@
<?php
/**
* +----------------------------------------------------------------------
* | 系统设置验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class System extends Validate
{
protected $rule = [
'copyright|版权信息' => [
'max' => '255',
],
'upload_driver|上传驱动' => [
'require' => 'require',
],
'upload_file_size|文件限制' => [
'max' => '50',
],
'upload_image_size|图片限制' => [
'max' => '50',
]
];
}

61
app/admin/validate/Team.php

@ -0,0 +1,61 @@
<?php
/**
* +----------------------------------------------------------------------
* | 团队模块验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Team extends Validate
{
protected $rule = [
'sort|排序' => [
'require' => 'require',
'max' => '8',
'number' => 'number',
],
'status|状态' => [
'require' => 'require',
'max' => '1',
],
'cate_id|栏目' => [
'require' => 'require',
],
'title|标题' => [
'require' => 'require',
],
'hits|点击次数' => [
'number' => 'number',
],
'template|模板' => [
'max' => '30',
],
'area|区域' => [
'max' => '4',
],
'sex|性别' => [
'max' => '4',
]
];
}

75
app/admin/validate/Users.php

@ -0,0 +1,75 @@
<?php
/**
* +----------------------------------------------------------------------
* | 会员管理验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class Users extends Validate
{
protected $rule = [
'email|邮箱' => [
'require' => 'require',
'max' => '100',
],
'password|密码' => [
'max' => '100',
],
'sex|性别' => [
'require' => 'require',
'max' => '1',
],
'last_login_time|最后登录时间' => [
'max' => '10',
],
'last_login_ip|最后登录IP' => [
'max' => '15',
],
'qq|QQ' => [
'max' => '20',
],
'mobile|手机' => [
'max' => '20',
],
'mobile_validated|手机验证' => [
'require' => 'require',
'max' => '3',
],
'email_validated|邮箱验证' => [
'require' => 'require',
'max' => '3',
],
'type_id|所属分组' => [
'require' => 'require',
'max' => '3',
],
'status|状态' => [
'require' => 'require',
],
'create_ip|注册IP' => [
'max' => '15',
]
];
}

46
app/admin/validate/UsersType.php

@ -0,0 +1,46 @@
<?php
/**
* +----------------------------------------------------------------------
* | 会员分组验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | DATETIME: 2021/06/23
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class UsersType extends Validate
{
protected $rule = [
'name|分组名称' => [
'require' => 'require',
'max' => '100',
],
'sort|排序' => [
'require' => 'require',
'max' => '5',
'number' => 'number',
],
'status|状态' => [
'require' => 'require',
]
];
}

15
app/api/apidoc.json

@ -0,0 +1,15 @@
{
"name": "SIYUCMS",
"version": "6.0.0",
"description": "api接口",
"title": "SIYUCMS V6 API接口",
"url": "http://api.junfei.iiixo.com/api",
"header": {
"title": "SIYUCMS",
"filename": ""
},
"template": {
"withCompare": true,
"withGenerator": false
}
}

19
app/api/config/app.php

@ -0,0 +1,19 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// +----------------------------------------------------------------------
// | 应用设置
// +----------------------------------------------------------------------
return [
// 默认分页显示数量
'page_size' => 10,
];

117
app/api/controller/Base.php

@ -0,0 +1,117 @@
<?php
/**
* +----------------------------------------------------------------------
* | api基础控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | QQ: 407593529
* '::::::::::::' | DATETIME: 2019/07/18
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
declare (strict_types = 1);
namespace app\api\controller;
use think\App;
use think\facade\Config;
use think\facade\Request;
use think\Response;
use think\Validate;
use think\exception\HttpResponseException;
/**
* 控制器基础类
*/
abstract class Base
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中间件
* @var array
*/
protected $middleware = [];
/**
* 分页数量
* @var string
*/
protected $pageSize = '';
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{
//每页显示数据量
$this->pageSize = Request::param('page_size', Config::get('app.page_size'));
}
/**
* 返回封装后的API数据到客户端
* @param mixed $data 要返回的数据
* @param integer $code 返回的code
* @param mixed $msg 提示信息
* @param string $type 返回数据格式
* @param array $header 发送的Header信息
* @return Response
*/
protected function result($data, int $code = 0, $msg = '', string $type = '', array $header = []): Response
{
$result = [
'code' => $code,
'msg' => $msg,
'time' => time(),
'data' => $data,
];
$type = $type ?: 'json';
$response = Response::create($result, $type)->header($header);
throw new HttpResponseException($response);
}
}

155
app/api/controller/Content.php

@ -0,0 +1,155 @@
<?php
/**
* +----------------------------------------------------------------------
* | 用户中心控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | QQ: 407593529
* '::::::::::::' | DATETIME: 2019/07/19
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\api\controller;
use app\api\service\JwtAuth;
use app\common\model\Product;
use app\common\model\Users;
use think\facade\Db;
use think\facade\Request;
class Content extends Base
{
/**
* 控制器中间件 [登录、注册 不需要鉴权]
* @var array
*/
protected $middleware = [
'app\api\middleware\Api' => ['except' => ['login', 'index', 'about', 'cate', 'product', 'detail_product', 'register']],
];
/**
* @api {post} /Content/index 01 首页api
* @apiGroup Content
* @apiVersion 1.0.0
* @apiDescription 首页接口,返回 广告列表(最新6条),产品数据(最大4条)
* @apiSuccessExample {json} 成功示例
* {"code":1,"msg":"","time":1660034733,"data":{"ad":[{"id":1,"create_time":1580378718,"update_time":1580378718,"sort":1,"status":1,"type_id":1,"name":"banner_1 ","image":"\/uploads\/20181225\/b671c6f234a72c2e6560c63ddd9dc0ff.jpg","thumb":"\/uploads\/20181225\/b671c6f234a72c2e6560c63ddd9dc0ff.jpg","url":"","description":"banner_1"},{"id":2,"create_time":1580378773,"update_time":1583585682,"sort":2,"status":1,"type_id":1,"name":"banner_2","image":"\/uploads\/20181225\/25670f5712b4acfb61c5d2a1bce79225.jpg","thumb":"\/uploads\/20181225\/25670f5712b4acfb61c5d2a1bce79225.jpg","url":"","description":"banner_2"}],"yinshidapeng":[{"id":1,"create_time":1581076523,"update_time":1581076523,"sort":50,"status":1,"cate_id":9,"title":"一本书","author":"管理员","source":"本站","content":"","summary":"","image":"\/uploads\/20181224\/065928f94ebe13ab1fbdc09cdd28a18b.jpg","images":"","download":"","tags":"书本","hits":0,"keywords":"","description":"","template":"","url":"","view_auth":0},{"id":2,"create_time":1581076563,"update_time":1581076563,"sort":50,"status":1,"cate_id":9,"title":"一支笔","author":"管理员","source":"本站","content":"","summary":"","image":"\/uploads\/20181224\/f05f564a79e650d566251152fa4fa75e.jpg","images":"","download":"","tags":"笔","hits":0,"keywords":"","description":"","template":"","url":"","view_auth":0},{"id":5,"create_time":1581076652,"update_time":1581076652,"sort":50,"status":1,"cate_id":9,"title":"笔记本","author":"管理员","source":"本站","content":"","summary":"","image":"\/uploads\/20181224\/d42552c77b14805f6d48e00b7a38f2e8.jpg","images":"","download":"","tags":"","hits":0,"keywords":"","description":"","template":"","url":"","view_auth":0},{"id":7,"create_time":1581076718,"update_time":1581076718,"sort":50,"status":1,"cate_id":9,"title":"铅笔盒","author":"管理员","source":"本站","content":"","summary":"","image":"\/uploads\/20181224\/c89c7634f5bcd3b60884da427bc0b384.jpg","images":"","download":"","tags":"","hits":0,"keywords":"","description":"","template":"","url":"","view_auth":0}],"shijingpianchang":[{"id":4,"create_time":1581076620,"update_time":1660025639,"sort":50,"status":1,"cate_id":10,"title":"背包","author":"管理员","source":"本站","content":"","summary":"","image":"\/uploads\/20181224\/8852280b4dc3365af4855c779e4239c6.jpg","images":"[]","download":"","tags":"","hits":0,"keywords":"","description":"","template":"","url":"","view_auth":0},{"id":6,"create_time":1581076690,"update_time":1660025634,"sort":50,"status":1,"cate_id":10,"title":"一支笔","author":"管理员","source":"本站","content":"","summary":"","image":"\/uploads\/20181224\/d42552c77b14805f6d48e00b7a38f2e8.jpg","images":"[]","download":"","tags":"笔","hits":0,"keywords":"","description":"","template":"","url":"","view_auth":0}],"peitaosheshi":[{"id":3,"create_time":1581076594,"update_time":1660025645,"sort":50,"status":1,"cate_id":14,"title":"一支铅笔","author":"管理员","source":"本站","content":"","summary":"","image":"\/uploads\/20181224\/d5e07bd3fdd9f3cbb0bdc798ccdba178.jpg","images":"[]","download":"","tags":"笔","hits":2,"keywords":"","description":"","template":"","url":"","view_auth":0}]}}
* @apiErrorExample {json} 失败示例
* {"code":0,"msg":"数据异常,请稍后操作","time":1563525638,"data":[]}
*/
public function index()
{
//广告
$_data['ad'] = Db::name('ad')->where('status', 1)->order('sort DESC,create_time DESC')->limit(6)->select();
//三个产品分类
$_data['yinshidapeng'] = Db::name('product')->where('cate_id', 9)
->order('sort DESC,create_time DESC')->limit(4)->select();
$_data['shijingpianchang'] = Db::name('product')->where('cate_id', 10)
->order('sort DESC,create_time DESC')->limit(4)->select();
$_data['peitaosheshi'] = Db::name('product')->where('cate_id', 14)
->order('sort DESC,create_time DESC')->limit(4)->select();
return $this->result($_data, 1, '');
}
/**
* @api {get} /Content/about 02 关于我们
* @apiGroup Content
* @apiVersion 1.0.0
* @apiDescription 关于我们内容详情接口,返回实体内容
* @apiSuccessExample {json} 成功示例
* {"code":1,"msg":"","time":1660034052,"data":{"content":"<p>ThinkPHP是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简代码的同时,更注重易用性。遵循<code>Apache2<\/code>开源许可协议发布,意味着你可以免费使用ThinkPHP,甚至允许把你基于ThinkPHP开发的应用开源或商业产品发布\/销售。<\/p>\n\n<p>ThinkPHP<code>6.0<\/code>基于精简核心和统一用法两大原则在<code>5.1<\/code>的基础上对底层架构做了进一步的优化改进,并更加规范化。由于引入了一些新特性,ThinkPHP<code>6.0<\/code>运行环境要求<code>PHP7.1+<\/code>,不支持<code>5.1<\/code>的无缝升级(官方给出了升级指导用于项目的升级参考)。<\/p>\n"}}
* @apiErrorExample {json} 失败示例
* {"code":0,"msg":"数据异常,请稍后操作","time":1563525638,"data":[]}
*/
public function about()
{
//联系我们
$_data = Db::name('page')->where('id', 1)->field('content')->find();
$_data['map'] = Db::name('page')->where('id', 1)->field('content')->find();
return $this->result($_data, 1, '');
}
/**
* @api {get} /Content/cate 03 获取产品栏目
* @apiGroup Content
* @apiVersion 1.0.0
* @apiDescription 产品栏目列表接口
* @apiSuccessExample {json} 成功示例
* {"code":1,"msg":"","time":1660034279,"data":[{"id":9,"sort":41,"status":1,"cate_name":"影视大棚","en_name":"","parent_id":8},{"id":10,"sort":42,"status":1,"cate_name":"实景片场","en_name":"","parent_id":8},{"id":14,"sort":50,"status":1,"cate_name":"配套设施","en_name":"","parent_id":8}]}
* @apiErrorExample {json} 失败示例
* {"code":0,"msg":"数据异常,请稍后操作","time":1563525638,"data":[]}
*/
public function cate()
{
//获取产品栏目
$_data = Db::name('cate')->where('parent_id', 8)
->where('status',1)
->field('id,sort,status,cate_name,en_name,parent_id')
->select();
return $this->result($_data, 1, '');
}
/**
* @api {get} /Content/product/cate_id/{cate_id}/page/{page}/limit/{limit} 04 产品列表
* @apiGroup Content
* @apiVersion 1.0.0
* @apiDescription 产品列表接口,返回某个栏目下所有的产品列表,可分页
* @apiParam (请求参数:) {int} cate_id 栏目id 必填
* @apiParam (请求参数:) {int} page 当前页数
* @apiParam (请求参数:) {int} limit 每页数量 默认10
* @apiSuccessExample {json} 成功示例
* {"code":1,"msg":"","time":1660034442,"data":[{"id":1,"image":"\/uploads\/20181224\/065928f94ebe13ab1fbdc09cdd28a18b.jpg","cate_id":9,"title":"一本书"},{"id":2,"image":"\/uploads\/20181224\/f05f564a79e650d566251152fa4fa75e.jpg","cate_id":9,"title":"一支笔"}]}
* @apiErrorExample {json} 失败示例
* {"code":0,"msg":"数据异常,请稍后操作","time":1563525638,"data":[]}
*/
public function product(int $cate_id, int $page = 1, int $limit = 2)
{
//获取所有产品栏目内容
$_db = Db::name('product');
$_data = $_db->where('cate_id', $cate_id)->field('id,image,cate_id,title')
->where('status',1)
->page($page, $limit)->select();
return $this->result($_data, 1, '');
}
/**
* @api {get} /Content/product/id/{id} 05 产品详情
* @apiGroup Content
* @apiVersion 1.0.0
* @apiDescription 产品详情以及相关推荐接口,返回产品详情以及相关推荐数据
* @apiParam (请求参数:) {int} id 产品id 必填
* @apiSuccessExample {json} 成功示例
* {"code":1,"msg":"","time":1660034541,"data":{"detail":{"id":8,"title":"钢笔","create_time":1581076758,"source":"本站","cate_id":9,"content":"","summary":""},"postion":[{"id":8,"title":"钢笔","image":"\/uploads\/20181224\/f05f564a79e650d566251152fa4fa75e.jpg"},{"id":7,"title":"铅笔盒","image":"\/uploads\/20181224\/c89c7634f5bcd3b60884da427bc0b384.jpg"},{"id":6,"title":"一支笔","image":"\/uploads\/20181224\/d42552c77b14805f6d48e00b7a38f2e8.jpg"},{"id":5,"title":"笔记本","image":"\/uploads\/20181224\/d42552c77b14805f6d48e00b7a38f2e8.jpg"}]}}
* @apiErrorExample {json} 失败示例
* {"code":0,"msg":"数据异常,请稍后操作","time":1563525638,"data":[]}
*/
public function detail_product(int $id)
{
$_db = Db::name('product');
$_data['detail'] = $_db->field('id,title,create_time,source,cate_id,content,summary')
->where('status',1)
->find($id);
$_data['postion'] = Db::name('product')->field('id,title,image')->limit(4)
->order('sort DESC,create_time DESC')->select();
return $this->result($_data, 1, '');
}
}

233
app/api/controller/User.php

@ -0,0 +1,233 @@
<?php
/**
* +----------------------------------------------------------------------
* | 用户中心控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | QQ: 407593529
* '::::::::::::' | DATETIME: 2019/07/19
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\api\controller;
use app\api\service\JwtAuth;
use app\common\model\Users;
use think\facade\Db;
use think\facade\Request;
class User extends Base
{
/**
* 控制器中间件 [登录、注册 不需要鉴权]
* @var array
*/
protected $middleware = [
'app\api\middleware\Api' => ['except' => ['login', 'register']],
];
/**
* @api {post} /User/login 01、会员登录
* @apiGroup User
* @apiVersion 6.0.0
* @apiDescription 系统登录接口,返回 token 用于操作需验证身份的接口
* @apiParam (请求参数:) {string} username 登录用户名
* @apiParam (请求参数:) {string} password 登录密码
* @apiParam (响应字段:) {string} token Token
* @apiSuccessExample {json} 成功示例
* {"code":1,"msg":"登录成功","time":1563525780,"data":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhcGkuc2l5dWNtcy5jb20iLCJhdWQiOiJzaXl1Y21zX2FwcCIsImlhdCI6MTU2MzUyNTc4MCwiZXhwIjoxNTYzNTI5MzgwLCJ1aWQiOjEzfQ.prQbqT00DEUbvsA5M14HpNoUqm31aj2JEaWD7ilqXjw"}}
* @apiErrorExample {json} 失败示例
* {"code":0,"msg":"帐号或密码错误","time":1563525638,"data":[]}
*/
public function login(string $username, string $password)
{
// 校验用户名密码
$user = Users::where('email|mobile', $username)
->where('password', md5($password))
->find();
if (empty($user)) {
$this->result([], 0, '帐号或密码错误');
} else {
if ($user['status'] == 1) {
//获取jwt的句柄
$jwtAuth = JwtAuth::getInstance();
$token = $jwtAuth->setUid($user['id'])->encode()->getToken();
//更新信息
Users::where('id', $user['id'])
->update(['last_login_time' => time(), 'last_login_ip' => Request::ip()]);
$this->result(['token' => $token], 1, '登录成功');
} else {
$this->result([], 0, '用户已被禁用');
}
}
}
/**
* @api {post} /User/register 02、会员注册
* @apiGroup User
* @apiVersion 6.0.0
* @apiDescription 系统注册接口,返回是否成功的提示,需再次登录
* @apiParam (请求参数:) {string} email 邮箱
* @apiParam (请求参数:) {string} password 密码
* @apiSuccessExample {json} 成功示例
* {"code":1,"msg":"注册成功","time":1563526721,"data":[]}
* @apiErrorExample {json} 失败示例
* {"code":0,"msg":"邮箱已被注册","time":1563526693,"data":[]}
*/
public function register(string $email, string $password){
// 密码长度不能低于6位
if (strlen($password) < 6) {
$this->result([], 0, '密码长度不能低于6位');
}
// 邮箱合法性判断
if (!is_email($email)) {
$this->result([], 0, '邮箱格式错误');
}
// 防止重复
$id = Db::name('users')->where('email|mobile', '=', $email)->find();
if ($id) {
$this->result([], 0, '邮箱已被注册');
}
// 注册入库
$data = [];
$data['email'] = $email;
$data['password'] = md5($password);
$data['last_login_time'] = $data['create_time'] = time();
$data['create_ip'] = $data['last_login_ip'] = Request::ip();
$data['status'] = 1;
$data['type_id'] = 1;
$data['sex'] = Request::post('sex') ? Request::post('sex') : 0;
$id = Db::name('users')->insertGetId($data);
if ($id) {
$this->result([], 1, '注册成功');
} else {
$this->result([], 0, '注册失败');
}
}
/**
* @api {post} /User/index 03、会员中心首页
* @apiGroup User
* @apiVersion 6.0.0
* @apiDescription 会员中心首页,返回用户个人信息
* @apiParam (请求参数:) {string} token Token
* @apiSuccessExample {json} 响应数据样例
* {"code":1,"msg":"","time":1563517637,"data":{"id":13,"email":"test110@qq.com","password":"e10adc3949ba59abbe56e057f20f883e","sex":1,"last_login_time":1563517503,"last_login_ip":"127.0.0.1","qq":"123455","mobile":"","mobile_validated":0,"email_validated":0,"type_id":1,"status":1,"create_ip":"127.0.0.1","update_time":1563507130,"create_time":1563503991,"type_name":"注册会员"}}
*/
public function index()
{
$user = Db::name('users')
->alias('u')
->leftJoin('users_type ut', 'u.type_id = ut.id')
->field('u.*,ut.name as type_name')
->where('u.id', $this->getUid())
->find();
return $this->result($user, 1, '');
}
/**
* @api {post} /User/editPwd 04、修改密码
* @apiGroup User
* @apiVersion 6.0.0
* @apiDescription 修改会员密码,返回成功或失败提示
* @apiParam (请求参数:) {string} token Token
* @apiParam (请求参数:) {string} oldPassword 原密码
* @apiParam (请求参数:) {string} newPassword 新密码
* @apiSuccessExample {json} 成功示例
* {"code":1,"msg":"密码修改成功","time":1563527107,"data":[]}
* @apiErrorExample {json} 失败示例
* {"code":0,"msg":"token已过期","time":1563527082,"data":[]}
*/
public function editPwd(string $oldPassword, string $newPassword){
// 密码长度不能低于6位
if (strlen($newPassword) < 6) {
$this->result([], 0, '密码长度不能低于6位');
}
// 查看原密码是否正确
$user = Users::where('id', $this->getUid())
->where('password', md5($oldPassword))
->find();
if (!$user) {
$this->result([], 0, '原密码输入有误');
}
//更新信息
$user = Users::find($this->getUid());
$user->password = md5($newPassword);
$user->save();
$this->result([], 1, '密码修改成功');
}
/**
* @api {post} /User/editInfo 05、修改信息
* @apiGroup User
* @apiVersion 6.0.0
* @apiDescription 修改用户信息,返回成功或失败提示
* @apiParam (请求参数:) {string} token Token
* @apiParam (请求参数:) {string} sex 性别 [1男/0女]
* @apiParam (请求参数:) {string} qq qq
* @apiParam (请求参数:) {string} mobile 手机号
* @apiSuccessExample {json} 成功示例
* {"code":0,"msg":"修改成功","time":1563507660,"data":[]}
* @apiErrorExample {json} 失败示例
* {"code":0,"msg":"token已过期","time":1563527082,"data":[]}
*/
public function editInfo(){
$data['sex'] = trim(Request::param("sex"));
$data['qq'] = trim(Request::param("qq"));
$data['mobile'] = trim(Request::param("mobile"));
if ($data['mobile']) {
// 不可和其他用户的一致
$id = Users::
where('mobile', $data['mobile'])
->where('id', '<>', $this->getUid())
->find();
if ($id) {
$this->result([], 0, '手机号已存在');
}
}
// 更新信息
Users::where('id', $this->getUid())
->update($data);
$this->result([], 0, '修改成功');
}
/**
* 获取用户id
* @return mixed
*/
protected function getUid(){
$jwtAuth = JwtAuth::getInstance();
return $jwtAuth->getUid();
}
}

81
app/api/middleware/Api.php

@ -0,0 +1,81 @@
<?php
/**
* +----------------------------------------------------------------------
* | Api中间件
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | QQ: 407593529
* '::::::::::::' | DATETIME: 2019/07/18
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\api\middleware;
use app\api\service\JwtAuth;
use think\facade\Request;
use think\Response;
use think\exception\HttpResponseException;
class Api
{
public function handle($request, \Closure $next)
{
$token = Request::header('token');
if ($token) {
if (count(explode('.', $token)) <> 3) {
$this->result([], 0, 'token格式错误');
}
$jwtAuth = JwtAuth::getInstance();
$jwtAuth->setToken($token);
if ($jwtAuth->validate() && $jwtAuth->verify()) {
return $next($request);
} else {
$this->result([], 0, 'token已过期');
}
} else {
$this->result([], 0, 'token不能为空');
}
return $next($request);
}
/**
* 返回封装后的API数据到客户端
* @param mixed $data 要返回的数据
* @param integer $code 返回的code
* @param mixed $msg 提示信息
* @param string $type 返回数据格式
* @param array $header 发送的Header信息
* @return Response
*/
protected function result($data, int $code = 0, $msg = '', string $type = '', array $header = []): Response
{
$result = [
'code' => $code,
'msg' => $msg,
'time' => time(),
'data' => $data,
];
$type = $type ?: 'json';
$response = Response::create($result, $type)->header($header);
throw new HttpResponseException($response);
}
}

130
app/api/service/JwtAuth.php

@ -0,0 +1,130 @@
<?php
namespace app\api\service;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\ValidationData;
/**
* 单例 一次请求中所有出现jwt的地方都是一个用户
* Class JwtAuth
* @package app\api\service
*/
class JwtAuth
{
// jwt token
private $token;
// jwt 过期时间
private $expTime = 3600;
// claim iss
private $iss = 'api.siyucms.com';
// claim aud
private $aud = 'siyucms_app';
// claim uid
private $uid;
// secrect
private $secrect = '1faASDF3';
// decode token
private $decodeToken;
// 单例模式JwtAuth句柄
private static $instance;
// 获取JwtAuth的句柄
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
// 私有化构造函数
private function __construct()
{
}
// 私有化clone函数
private function __clone()
{
// TODO: Implement __clone() method.
}
// 获取token
public function getToken()
{
return (string)$this->token;
}
// 设置token
public function setToken($token)
{
$this->token = $token;
return $this;
}
// 设置uid
public function setUid($uid)
{
$this->uid = $uid;
return $this;
}
// 获取uid
public function getUid()
{
return $this->uid;
}
// 编码jwt token
public function encode()
{
$time = time();
$this->token = (new Builder())->setHeader('alg', 'HS256')
->setIssuer($this->iss)
->setAudience($this->aud)
->setIssuedAt($time)
->setExpiration($time + $this->expTime)
->set('uid', $this->uid)
->sign(new Sha256(), $this->secrect)
->getToken();
return $this;
}
public function decode()
{
if (!$this->decodeToken) {
$this->decodeToken = (new Parser())->parse((string)$this->token); // Parses from a string
$this->uid = $this->decodeToken->getClaim('uid');
}
return $this->decodeToken;
}
// validate
public function validate()
{
$data = new ValidationData(); // It will use the current time to validate (iat, nbf and exp)
$data->setIssuer($this->iss);
$data->setAudience($this->aud);
$data->setId($this->uid);
return $this->decode()->validate($data);
}
// verify token
public function verify()
{
$signer = new Sha256();
return $this->decode()->verify($signer, $this->secrect);
}
}

108
app/command/Admin.php

@ -0,0 +1,108 @@
<?php
declare (strict_types=1);
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
class Admin extends Command
{
/**
* 精简列表
* ====文件和目录====
* public/template/ 前台模板目录
* public/uploads/ 前台上传文件目录
* app/api 前台api应用文件
* app/index 前台index应用文件
* app/mobile 前台mobile应用文件
* ====删除的模块====
* link,ad_type,ad,debris,page,article,cate,picture,product,download,team,message
* 1、删除字段管理中的数据[field表,根据 module_id删除]
* 2、删除菜单规则表中的数据[auth_rule表,根据 model_name 删除]
* 3、删除模块表中的数据
* 4、删除模块的控制器、模型、验证器[根据 model_name 删除]
* 5、删除模块对应的表
*/
protected function configure()
{
// 指令配置
$this->setName('admin')
->setDescription('精简文件和数据库');
}
protected function execute(Input $input, Output $output)
{
try {
$rootPath = app()->getRootPath();
$this->dirDelete($rootPath . 'public' . DIRECTORY_SEPARATOR . 'template' . DIRECTORY_SEPARATOR);
$this->dirDelete($rootPath . 'public' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR, false);
$this->dirDelete($rootPath . 'app' . DIRECTORY_SEPARATOR . 'api' . DIRECTORY_SEPARATOR);
$this->dirDelete($rootPath . 'app' . DIRECTORY_SEPARATOR . 'index' . DIRECTORY_SEPARATOR);
$this->dirDelete($rootPath . 'app' . DIRECTORY_SEPARATOR . 'mobile' . DIRECTORY_SEPARATOR);
$tableName = ['link', 'ad_type', 'ad', 'debris', 'page', 'article', 'cate', 'picture', 'product', 'download', 'team', 'message'];
$module = \app\common\model\Module::where('table_name', 'in', $tableName)->select();
if ($module) {
$module = $module->toArray();
$prefix = \think\facade\Config::get('database.connections.mysql.prefix');
foreach ($module as $k => $v) {
\app\common\model\Field::where('module_id', $v['id'])->delete();
\app\common\model\AuthRule::where('name', $v['model_name'])->whereOr('name', 'like', $v['model_name'] . '/%')->delete();
\app\common\model\Module::where('table_name', 'in', $tableName)->delete();
$this->dirDelete($rootPath . 'app' . DIRECTORY_SEPARATOR . 'admin' . DIRECTORY_SEPARATOR . 'controller' . DIRECTORY_SEPARATOR . $v['model_name'] . '.php');
$this->dirDelete($rootPath . 'app' . DIRECTORY_SEPARATOR . 'common' . DIRECTORY_SEPARATOR . 'model' . DIRECTORY_SEPARATOR . $v['model_name'] . '.php');
$this->dirDelete($rootPath . 'app' . DIRECTORY_SEPARATOR . 'admin' . DIRECTORY_SEPARATOR . 'validate' . DIRECTORY_SEPARATOR . $v['model_name'] . '.php');
$sql = 'DROP TABLE IF EXISTS `' . $prefix . $v['table_name'] . '`';
\think\facade\Db::query($sql);
}
}
// 指令输出
$output->writeln('END');
} catch (\Exception $e) {
// 指令输出
$output->writeln('ERROR:' . $e->getMessage());
}
}
/**
* 删除目录及文件
* @param string $path 要删除的目录
* @param bool $delSelf 是否删除当前目录
* @return bool
*/
private function dirDelete(string $path, bool $delSelf = true)
{
// 如果是目录则继续
if (is_dir($path)) {
// 扫描一个文件夹内的所有文件夹和文件并返回数组
$p = scandir($path);
foreach ($p as $val) {
// 排除目录中的.和..
if ($val != "." && $val != "..") {
// 如果是目录则递归子目录,继续操作
if (is_dir($path . $val)) {
// 子目录中操作删除文件夹和文件
$this->dirDelete($path . $val . DIRECTORY_SEPARATOR);
// 目录清空后删除空文件夹
@rmdir($path . $val . DIRECTORY_SEPARATOR);
} else {
// 如果是文件直接删除
unlink($path . $val);
}
}
}
if ($delSelf) {
// 刪除空文件夾
@rmdir($path);
}
} else if (is_file($path)) {
// 如果是文件直接删除
unlink($path);
}
}
}

953
app/common.php

@ -0,0 +1,953 @@
<?php
// 应用公共文件
// 获取列表链接地址
function getUrl($v)
{
// 判断是否外部链接
if (trim($v['url']) == '') {
// 判断是否跳转到下级栏目
if ($v['is_next'] == 1) {
$is_next = \app\common\model\Cate::with(['module'])
->where('parent_id', $v['id'])
->order('sort asc,id desc')
->find();
if ($is_next) {
$v['url'] = getUrl($is_next);
}
} else {
if ($v['cate_folder']) {
$v['url'] = (string)\think\facade\Route::buildUrl($v['cate_folder'] . '/index')->domain('');
} else {
if (isset($v['module']['model_name']) && !empty($v['module']['model_name'])) {
$moduleName = $v['module']['model_name'];
} else {
$moduleId = $v['module']['id'] ?? $v['module_id'];
$moduleName = \app\common\model\Module::where('id', $moduleId)
->value('model_name');
}
$v['url'] = (string)\think\facade\Route::buildUrl($moduleName . '/index', ['cate' => $v['id']])->domain('');
}
}
}
return $v['url'];
}
// 获取详情URL
function getShowUrl($v)
{
if ($v) {
if (isset($v['url']) && !empty($v['url'])) {
return $v['url'];
}
if (isset($v['cate_id']) && !empty($v['cate_id'])) {
if (isset($v['cate'])) {
$cate = $v['cate'];
} else {
$cate = \app\common\model\Cate::field('id,cate_folder,module_id')
->where('id', $v['cate_id'])
->find();
}
if ($cate['cate_folder']) {
$url = (string)\think\facade\Route::buildUrl($cate['cate_folder'] . '/info', ['id' => $v['id']])->domain('');
} else {
if (isset($v['cate']['module'])) {
$modelName = $v['cate']['module']['model_name'];
} else {
$modelName = \app\common\model\Module::where('id', $cate['module_id'])
->value('model_name');
}
$url = (string)\think\facade\Route::buildUrl($modelName . '/info', ['cate' => $cate['id'], 'id' => $v['id']])->domain('');
}
}
}
return $url ?? '';
}
/***
* 处理数据(把列表中需要处理的字段转换成数组和对应的值,用于自定义标签文件中)
* @param $list 列表
* @param $moduleId 模型ID
* @return array
*/
function changeFields($list, $moduleId)
{
// 根据模型ID查询字段信息
$fields = \app\common\model\Field::with(['module', 'dictionaryType'])->where('module_id', '=', $moduleId)
->select()
->toArray();
$optionsArr = [];
foreach ($fields as $k => $v) {
$options = \app\common\facade\MakeBuilder::getFieldOptions($v);
$optionsArr[$v['field']] = $options;
}
foreach ($list as $k => $v) {
$url = getShowUrl($v);
$list[$k] = changeField($v, $moduleId, $optionsArr);
$info[$k] = $list[$k]; // 定义中间变量防止报错
$info[$k]['url'] = $url;
}
return $info ?? [];
}
/***
* 处理数据(用于详情页中数据转换)
* @param $info 内容详情
* @param $moduleid 模型ID
* @param $optionsArr 选项信息
* @return array
*/
function changeField($info, $moduleId, $optionsArr)
{
$fields = \app\common\model\Field::with(['module', 'dictionaryType'])->where('module_id', '=', $moduleId)
->select()
->toArray();
foreach ($fields as $k => $v) {
// select等需要获取数据的字段
if ($optionsArr) {
$options = $optionsArr[$v['field']];
} else {
$options = \app\common\facade\MakeBuilder::getFieldOptions($v);
}
if (isset($info[$v['field']])) {
if ($v['type'] == 'text') {
// 忽略
} elseif ($v['type'] == 'textarea' || $v['type'] == 'password') {
// 忽略
} elseif ($v['type'] == 'radio' || $v['type'] == 'checkbox') {
$info[$v['field'] . '_array'] = \app\common\facade\Cms::changeOptionsValue($options, $info[$v['field']], true);
$info[$v['field']] = \app\common\facade\Cms::changeOptionsValue($options, $info[$v['field']], false);
} elseif ($v['type'] == 'select' || $v['type'] == 'select2') {
if ($v['field'] !== 'cate_id') {
$info[$v['field'] . '_array'] = \app\common\facade\Cms::changeOptionsValue($options, $info[$v['field']], true);
$info[$v['field']] = \app\common\facade\Cms::changeOptionsValue($options, $info[$v['field']], false);
}
} elseif ($v['type'] == 'number') {
} elseif ($v['type'] == 'hidden') {
} elseif ($v['type'] == 'date' || $v['type'] == 'time' || $v['type'] == 'datetime') {
} elseif ($v['type'] == 'daterange') {
} elseif ($v['type'] == 'tag') {
if (!empty($info[$v['field']])) {
$tags = explode(',', $info[$v['field']]);
foreach ($tags as $k => $tag) {
$tags[$k] = [
'name' => $tag,
'url' => \think\facade\Route::buildUrl('index/tag', ['module' => $moduleId, 't' => $tag])->__toString(),
];
}
$info[$v['field']] = $tags;
}
} elseif ($v['type'] == 'images' || $v['type'] == 'files') {
$info[$v['field']] = json_decode($info[$v['field']], true);
} elseif ($v['type'] == 'editor') {
} elseif ($v['type'] == 'color') {
}
}
}
return $info;
}
/**
* 邮件发送
* @param $to 接收人
* @param string $subject 邮件标题
* @param string $content 邮件内容(html模板渲染后的内容)
* @throws Exception
* @throws phpmailerException
*/
function send_email($to, $subject = '', $content = '')
{
$mail = new PHPMailer\PHPMailer\PHPMailer();
$arr = \think\facade\Db::name('config')
->where('inc_type', 'smtp')
->select();
$config = convert_arr_kv($arr, 'name', 'value');
$mail->CharSet = 'UTF-8'; //设定邮件编码,默认ISO-8859-1,如果发中文此项必须设置,否则乱码
$mail->isSMTP();
$mail->SMTPDebug = 0;
//调试输出格式
//$mail->Debugoutput = 'html';
//smtp服务器
$mail->Host = $config['smtp_server'];
//端口 - likely to be 25, 465 or 587
$mail->Port = $config['smtp_port'];
if ($mail->Port == '465') {
$mail->SMTPSecure = 'ssl';
}// 使用安全协议
//Whether to use SMTP authentication
$mail->SMTPAuth = true;
//发送邮箱
$mail->Username = $config['smtp_user'];
//密码
$mail->Password = $config['smtp_pwd'];
//Set who the message is to be sent from
$mail->setFrom($config['smtp_user'], $config['email_id']);
//回复地址
//$mail->addReplyTo('replyto@example.com', 'First Last');
//接收邮件方
if (is_array($to)) {
foreach ($to as $v) {
$mail->addAddress($v);
}
} else {
$mail->addAddress($to);
}
$mail->isHTML(true);// send as HTML
//标题
$mail->Subject = $subject;
//HTML内容转换
$mail->msgHTML($content);
return $mail->send();
}
/**
* 验证输入的邮件地址是否合法
* @param $user_email 邮箱
* @return bool
*/
function is_email($user_email)
{
$chars = "/^([a-z0-9+_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,6}\$/i";
if (strpos($user_email, '@') !== false && strpos($user_email, '.') !== false) {
if (preg_match($chars, $user_email)) {
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* 验证输入的手机号码是否合法
* @param $mobile_phone 手机号
* @return bool
*/
function is_mobile_phone($mobile_phone)
{
$chars = "/^13[0-9]{1}[0-9]{8}$|15[0-9]{1}[0-9]{8}$|18[0-9]{1}[0-9]{8}$|17[0-9]{1}[0-9]{8}$/";
if (preg_match($chars, $mobile_phone)) {
return true;
}
return false;
}
/**
* 过滤数组元素前后空格 (支持多维数组)
* @param $array 要过滤的数组
* @return array|string
*/
function trim_array_element($array)
{
if (!is_array($array))
return trim($array);
return array_map('trim_array_element', $array);
}
/**
* 将数据库中查出的列表以指定的 值作为数组的键名,并以另一个值作为键值
* @param $arr
* @param $key_name
* @return array
*/
function convert_arr_kv($arr, $key_name, $value)
{
$arr2 = array();
foreach ($arr as $key => $val) {
$arr2[$val[$key_name]] = $val[$value];
}
return $arr2;
}
function string2array($info)
{
if ($info == '') return array();
eval("\$r = $info;");
return $r;
}
function array2string($info)
{
//删除空格,某些情况下字段的设置会出现换行和空格的情况
if (is_array($info)) {
if (array_key_exists('options', $info)) {
$info['options'] = trim($info['options']);
}
}
if ($info == '') return '';
if (!is_array($info)) {
//删除反斜杠
$string = stripslashes($info);
}
foreach ($info as $key => $val) {
$string[$key] = stripslashes($val);
}
$setup = var_export($string, TRUE);
return $setup;
}
/**
* 文本域中换行标签输出
* @param $info 内容
* @return mixed
*/
function textareaBr($info)
{
$info = str_replace("\r\n", "<br />", $info);
$info = str_replace("\n", "<br />", $info);
$info = str_replace("\r", "<br />", $info);
return $info;
}
/**
* 无限分类-栏目
* @param $cate
* @param string $lefthtml
* @param int $pid
* @param int $lvl
* @return array
*/
function tree_cate($cate, $leftHtml = '|— ', $pid = 0, $lvl = 0)
{
$arr = array();
foreach ($cate as $v) {
if ($v['parent_id'] == $pid) {
$v['lvl'] = $lvl + 1;
$v['left_html'] = str_repeat($leftHtml, $lvl);
$v['l_cate_name'] = $v['left_html'] . $v['cate_name'];
$arr[] = $v;
$arr = array_merge($arr, tree_cate($cate, $leftHtml, $v['id'], $lvl + 1));
}
}
return $arr;
}
/**
* 组合多维数组
* @param $cate
* @param string $name
* @param int $pid
* @return array
*/
function unlimitedForLayer($cate, $name = 'sub', $pid = 0)
{
$arr = array();
foreach ($cate as $v) {
if ($v['parent_id'] == $pid) {
$v[$name] = unlimitedForLayer($cate, $name, $v['id']);
$v['url'] = getUrl($v);
$arr[] = $v;
}
}
return $arr;
}
/**
* 传递一个父级分类ID返回当前子分类
* @param $cate
* @param $pid
* @return array
*/
function getChildsOn($cate, $pid)
{
$arr = array();
foreach ($cate as $v) {
if ($v['parent_id'] == $pid) {
$v['sub'] = getChilds($cate, $v['id']);
$v['url'] = getUrl($v);
$arr[] = $v;
}
}
return $arr;
}
/**
* 传递一个父级分类ID返回所有子分类
* @param $cate
* @param $pid
* @return array
*/
function getChilds($cate, $pid)
{
$arr = array();
foreach ($cate as $v) {
if ($v['parent_id'] == $pid) {
$v['url'] = getUrl($v);
$arr[] = $v;
$arr = array_merge($arr, getChilds($cate, $v['id']));
}
}
return $arr;
}
/**
* 传递一个父级分类ID返回所有子分类ID
* @param $cate
* @param $pid
* @return array
*/
function getChildsId($cate, $pid)
{
$arr = [];
foreach ($cate as $v) {
if ($v['parent_id'] == $pid) {
$arr[] = $v;
$arr = array_merge($arr, getChildsId($cate, $v['id']));
}
}
return $arr;
}
/**
* 格式化分类数组为字符串
* @param $ids
* @param string $pid
* @return string
*/
function getChildsIdStr($ids, $pid = '')
{
$result = '';
foreach ($ids as $k => $v) {
$result .= $v['id'] . ',';
}
if ($pid) {
$result = $pid . ',' . $result;
}
$result = rtrim($result, ',');
return $result;
}
/**
* 传递一个子分类ID返回所有的父级分类[前台栏目]
* @param $cate
* @param $id
* @return array
*/
function getParents($cate, $id)
{
$arr = array();
foreach ($cate as $v) {
if ($v['id'] == $id) {
$arr[] = $v;
$arr = array_merge(getParents($cate, $v['parent_id']), $arr);
}
}
return $arr;
}
/**
* 查找一个分类id的顶级分类id
* @param $id
* @return string
*/
function getTopId($id)
{
$cate = \app\common\model\Cate::field('id,parent_id')->select()->toArray();
$cateArr = [];
if ($cate) {
foreach ($cate as $k => $v) {
$cateArr[$v['id']] = $v['parent_id'] ?: "0";
}
}
while ($cateArr[$id]) {
$id = $cateArr[$id];
}
return $id;
}
/**
* 获取文件目录列表
* @param string $pathname 路径
* @param integer $fileFlag 文件列表 0所有文件列表,1只读文件夹,2是只读文件(不包含文件夹)
* @param string $pathname 路径
* @return array
*/
function get_file_folder_List($pathname, $fileFlag = 0, $pattern = '*')
{
$fileArray = array();
$pathname = rtrim($pathname, '/') . '/';
$list = glob($pathname . $pattern);
foreach ($list as $i => $file) {
switch ($fileFlag) {
case 0:
$fileArray[] = basename($file);
break;
case 1:
if (is_dir($file)) {
$fileArray[] = basename($file);
}
break;
case 2:
if (is_file($file)) {
$fileArray[] = basename($file);
}
break;
default:
break;
}
}
if (empty($fileArray)) $fileArray = NULL;
return $fileArray;
}
/**
* 获取所有模版
* @return mixed
*/
function getTemplate()
{
// 查找所有系统设置表数据
$system = \app\common\model\System::find(1);
$path = './template/' . $system['template'] . '/index/' . $system['html'] . '/';
$tpl['list'] = get_file_folder_List($path, 2, '*_list*');
$tpl['show'] = get_file_folder_List($path, 2, '*_show*');
return $tpl;
}
/**
* 传递一个父级分类ID返回所有子分类
* @param $cate
* @param $pid
* @return array
*/
function getChildsRule($rules, $pid)
{
$arr = [];
foreach ($rules as $v) {
if ($v['pid'] == $pid) {
$arr[] = $v;
$arr = array_merge($arr, getChildsRule($rules, $v['id']));
}
}
return $arr;
}
/***
* 对象转数组
* @param $object
* @return array
*/
function object2array($object)
{
$array = array();
if (is_object($object)) {
foreach ($object as $key => $value) {
$array[$key] = $value;
}
} else {
$array = $object;
}
return $array;
}
/***
* 获取当前栏目ID
* @return mixed
*/
function getCateId()
{
if (\think\facade\Request::has('cate')) {
$result = (int)\think\facade\Request::param('cate');
} else {
$cateFolder = get_cate_folder();
if ($cateFolder) {
$result = \app\common\model\Cate::where('cate_folder', '=', $cateFolder)->value('id');
}
}
return $result ?? '';
}
/**
* 改变前台字典数据标签取得的数据
* @param array $list
* @return array
*/
function changeDict(array $list, string $field, string $all = "全部")
{
$get = \think\facade\Request::except(['page'], 'get');
foreach ($list as $k => $v) {
$url = $get;
$url[$field] = $v['dict_value'];
$list[$k]['url'] = (string)url(get_cate_folder() . '/' . \think\facade\Request::action(), $url);
$param = \think\facade\Request::param('', '', 'htmlspecialchars');
// 高亮显示
$list[$k]['current'] = 0;
if (!empty($param)) {
foreach ($param as $kk => $vv) {
if ($kk == $field) {
if (strpos($vv, '|') !== false) {
// 多选
$paramArr = explode("|", $vv);
foreach ($paramArr as $kkk => $vvv) {
if ($vvv == $v['dict_value']) {
$list[$k]['current'] = 1;
break;
}
}
} else {
// 单选
if ($vv == $v['dict_value']) {
$list[$k]['current'] = 1;
}
}
}
}
}
$list[$k]['param'] = $param;
}
// 添加[全部]字段在第一位
if (isset($get[$field])) {
unset($get[$field]);
} else {
$hover = 1;
}
$url = (string)url(get_cate_folder() . '/' . \think\facade\Request::action(), $get);
$all = [
'dict_label' => $all,
'dict_value' => 0,
'url' => $url,
'current' => $hover ?? 0,
];
array_unshift($list, $all);
return $list;
}
/**
* 改变模版标签中分类字段传递
* @param string $field 需要分类查询的字段,通过,分割或|分割
* @return string
*/
function getSearchField(string $field)
{
$sql = '';
if ($field) {
$field = str_replace('|', ',', $field);
$fieldArr = explode(',', $field);
foreach ($fieldArr as $k => $v) {
if (!empty($v)) {
// 查询浏览器参数是否包含此参数
if (\think\facade\Request::has($v, 'get')) {
$str = \think\facade\Request::get($v, '', ['strip_tags', 'htmlspecialchars']);
if (strpos($str, '|') !== false) {
$sql = ' AND (';
$strArr = explode("|", $str);
foreach ($strArr as &$strAr) {
// 检测是否存在
$dictCount = \app\common\model\Dictionary::where('dict_value', $strAr)->count();
if ($dictCount) {
$sql .= ' FIND_IN_SET(\'' . $strAr . '\', ' . $v . ') OR';
}
}
// 去除最后一个or
$sql = substr($sql, 0, strlen($sql) - 2);
$sql .= ') ';
} else {
// 检测是否存在
$dictCount = \app\common\model\Dictionary::where('dict_value', $str)->count();
if ($dictCount) {
$sql .= ' AND FIND_IN_SET(\'' . $str . '\', ' . $v . ') ';
} else {
// 常规搜索
$sql .= ' AND ' . $v . ' LIKE "%' . $str . '%" ';
}
}
}
}
}
}
return $sql;
}
/**
* 无限分类-权限
* @param $cate 栏目
* @param string $lefthtml 分隔符
* @param int $pid 父ID
* @param int $lvl 层级
* @return array
*/
function tree($cate, $lefthtml = '|— ', $pid = 0, $lvl = 0)
{
$arr = array();
foreach ($cate as $v) {
if ($v['pid'] == $pid) {
$v['lvl'] = $lvl + 1;
$v['lefthtml'] = str_repeat($lefthtml, $lvl);
$v['ltitle'] = $v['lefthtml'] . $v['title'];
$arr[] = $v;
$arr = array_merge($arr, tree($cate, $lefthtml, $v['id'], $lvl + 1));
}
}
return $arr;
}
/**
* 无限分类-权限
* @param $cate 栏目
* @param string $lefthtml 分隔符
* @param int $pid 父ID
* @param int $lvl 层级
* @return array
*/
function tree_three($cate, $lefthtml = '|— ', $pid = 0, $lvl = 0)
{
$arr = array();
foreach ($cate as $v) {
$keys = array_keys($v);
if (end($v) == $pid) {
$v['lvl'] = $lvl + 1;
$v['lefthtml'] = str_repeat($lefthtml, $lvl);
$v[$keys[1]] = $v['lefthtml'] . $v[$keys[1]];
$arr[] = $v;
$arr = array_merge($arr, tree_three($cate, $lefthtml, $v[$keys[0]], $lvl + 1));
}
}
return $arr;
}
/**
* 标签云数据处理
* @param $list
* @return array
*/
function get_tagcloud($list, $moduleId, $limit = 10)
{
$result = [];
if ($list) {
foreach ($list as $k => $v) {
if ($v['tags']) {
$arr = explode(',', $v['tags']);
foreach ($arr as $ar) {
if (!empty($ar)) {
$result[] = $ar;
}
}
}
}
}
if ($result) {
$arr = array_count_values($result); // 统计数组中所有的值出现的次数
// 降序排序
arsort($arr);
$arr = array_slice($arr, 0, $limit);// 截取前N条数据
$result = [];
foreach ($arr as $k => $v) {
$result[] = [
'name' => $k,
'count' => $v,
'url' => \think\facade\Route::buildUrl('index/tag', ['module' => $moduleId, 't' => $k])->__toString(),
];
}
}
return $result;
}
/**
* 获取前一页地址中设置的返回url
* @return array
*/
function get_back_url()
{
if (isset($_SERVER["HTTP_REFERER"]) && !empty($_SERVER["HTTP_REFERER"])) {
$queryStr = explode('?', $_SERVER["HTTP_REFERER"]);
if (count($queryStr) == 2) {
parse_str($queryStr[1], $queryArr);
if (isset($queryArr['back_url']) && !empty($queryArr['back_url'])) {
$backUrl = explode("&", urldecode($queryArr['back_url']));
foreach ($backUrl as $k => $v) {
$v = explode("=", $v);
if (isset($v[1]) && !empty($v[1])) {
$backArr[$v[0]] = $v[1];
}
}
}
}
}
return $backArr ?? [];
}
/**
* 转换moment格式为php可用格式[废弃]
* @param $format
* @return string
*/
function convert_moment_format_to_php(string $format = '')
{
$replacements = [
'DD' => 'd',
'ddd' => 'D',
'D' => 'j',
'dddd' => 'l',
'E' => 'N',
'o' => 'S',
'e' => 'w',
'DDD' => 'z',
'W' => 'W',
'MMMM' => 'F',
'MM' => 'm',
'MMM' => 'M',
'M' => 'n',
'YYYY' => 'Y',
'YY' => 'y',
'a' => 'a',
'A' => 'A',
'h' => 'g',
'H' => 'G',
'hh' => 'h',
'HH' => 'H',
'mm' => 'i',
'ss' => 's',
'SSS' => 'u',
'zz' => 'e',
'X' => 'U',
];
$phpFormat = strtr($format, $replacements);
return $phpFormat;
}
/**
* 转换php格式为moment可用格式
* @param $format
* @return string
*/
function convert_php_to_moment_format(string $format = '')
{
$replacements = [
'd' => 'DD',
'D' => 'ddd',
'j' => 'D',
'l' => 'dddd',
'N' => 'E',
'S' => 'o',
'w' => 'e',
'z' => 'DDD',
'W' => 'W',
'F' => 'MMMM',
'm' => 'MM',
'M' => 'MMM',
'n' => 'M',
't' => '', // no equivalent
'L' => '', // no equivalent
'o' => 'YYYY',
'Y' => 'YYYY',
'y' => 'YY',
'a' => 'a',
'A' => 'A',
'B' => '', // no equivalent
'g' => 'h',
'G' => 'H',
'h' => 'hh',
'H' => 'HH',
'i' => 'mm',
's' => 'ss',
'u' => 'SSS',
'e' => 'zz', // deprecated since version 1.6.0 of moment.js
'I' => '', // no equivalent
'O' => '', // no equivalent
'P' => '', // no equivalent
'T' => '', // no equivalent
'Z' => '', // no equivalent
'c' => '', // no equivalent
'r' => '', // no equivalent
'U' => 'X',
];
$momentFormat = strtr($format, $replacements);
return $momentFormat;
}
/**
* 根据url获取栏目目录
*/
function get_cate_folder()
{
//return \think\facade\Request::controller(); // 控制器的方式无法使用'-','_','/'连接符
$careFolder = \think\facade\Request::rule()->getRule(); // 获取当前路由规则
$careFolder = str_replace('<id>', '', $careFolder); // 移除路由规则多余的字符
$careFolder = trim($careFolder, '/'); // 移除两侧的/
return $careFolder;
}
/**
* 根据父ID获取下级联动数据
* @param string $modelName 模型名称
* @param int $pid 父ID
* @param string $pidFieldName 父ID字段名
* @return array
*/
function getLinkageData(string $modelName, int $pid = 0, string $pidFieldName = 'pid')
{
$model = '\app\common\model\\' . $modelName;
if (class_exists($model)) {
return $model:: where($pidFieldName, $pid)->select()->toArray();
}
return [];
}
/**
* 根据末级ID获取父级联动数据
* @param string $modelName 模型名称
* @param string $id 主键值
* @param string $idFieldName 主键字段名
* @param string $nameFieldName name字段名
* @param string $pidFieldName pid字段名
* @param int $level 级别
*/
function getLinkageAllData(string $modelName, $id = '', $idFieldName = 'id', $nameFieldName = 'name', $pidFieldName = 'pid', $level = 1)
{
$model = '\app\common\model\\' . $modelName;
// 获取当前数据的父ID
$pidFielValue = $model:: where($idFieldName, $id)->value($pidFieldName);
// 当前级别的数据
$resultKey[$level] = $pidFielValue;
$resultData[$level] = getLinkageData($modelName, (int)$pidFielValue, $pidFieldName);
if ($pidFielValue != 0) {
$data = getLinkageAllData($modelName, $pidFielValue, $idFieldName, $nameFieldName, $pidFieldName, $level + 1);
$resultKey = $resultKey + $data['key']; // 后面一个数组,加入到前面一个数组中,键名相同时,不会被覆盖
$resultData = $resultData + $data['data'];
}
$result['key'] = $resultKey;
$result['data'] = $resultData;
return $result;
}
/**
* 根据末级ID获取每级的联动数据
* @param string $modelName 模型名称
* @param string $id 主键值
* @param string $idFieldName 主键字段名
* @param string $nameFieldName name字段名
* @param string $pidFieldName pid字段名
* @param array $result 数据
*/
function getLinkageListData(string $modelName, $id = '', $idFieldName = 'id', $nameFieldName = 'name', $pidFieldName = 'pid', $result = [])
{
$model = '\app\common\model\\' . $modelName;
// 查找当前层的数据
$data = $model:: where($idFieldName, $id)->field([$idFieldName, $nameFieldName, $pidFieldName])->find();
if ($data) {
$result[] = $data->toArray();
if ($data->{$pidFieldName}) {
return getLinkageListData($modelName, $data->{$pidFieldName}, $idFieldName, $nameFieldName, $pidFieldName, $result);
}
}
return $result;
}

1290
app/common/builder/FormBuilder.php

File diff suppressed because it is too large

1290
app/common/builder/MakeBuilder.php

File diff suppressed because it is too large

715
app/common/builder/TableBuilder.php

@ -0,0 +1,715 @@
<?php
/**
* +----------------------------------------------------------------------
* | 表格快速构造器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: siyu
* ::::::::::: | EMAIL: 407593529@qq.com
* ..:::::::::::' | QQ: 407593529
* '::::::::::::' | DATETIME: 2019/08/05
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\common\builder;
use think\facade\Request;
use think\facade\View;
class TableBuilder
{
/**
* @var array 列名
*/
private $_field_name = [];
/**
* @var string 模板路径(默认使用系统内置路径,无需设置)
*/
private $_template = '';
/**
* @var array 模板变量
*/
private $_vars = [
'page_title' => '', // 页面标题
'page_tips' => '', // 页面提示
'page_tips_top' => '', // 页面提示[top]
'page_tips_search' => '', // 页面提示[search]
'page_tips_bottom' => '', // 页面提示[bottom]
'page_size' => '', // 每页显示的行数
'tips_type' => '', // 页面提示类型
'extra_js' => '', // 额外JS代码
'extra_css' => '', // 额外CSS代码
'extra_html' => '', // 额外HTML代码
'columns' => [], // 表格列集合
'right_buttons' => [], // 表格右侧按钮
'top_buttons' => [], // 顶部栏按钮组[toolbar]
'unique_id' => 'id', // 表格主键名称(默认为id,如表主键不为id必须设置主键)
'data_url' => '', // 表格数据源
'add_url' => '', // 默认的新增地址
'edit_url' => '', // 默认的修改地址
'del_url' => '', // 默认的删除地址
'export_url' => '', // 默认的导出地址
'sort_url' => '', // 默认的排序地址
'search' => [], // 搜索参数
'pagination' => 'true', // 是否进行分页
'parent_id_field' => '', // 列表树模式需传递父id
'empty_tips' => '没有找到匹配的记录', // 空数据提示信息
'hide_checkbox' => false, // 是否隐藏第一列多选[待完善]
'layer_open' => true, // 添加/编辑等页启用layer弹层加载
'fixed_left' => 0, // 左侧固定列数
'fixed_right' => 1, // 右侧固定列数
];
/**
* @var 单例模式句柄
*/
private static $instance;
/**
* 获取句柄
* @return FormBuilder
*/
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* 私有化构造函数
*/
private function __construct()
{
// 初始化
$this->initialize();
}
/**
* 初始化
*/
protected function initialize()
{
// 每页显示的行数
$this->_vars['page_size'] = \think\facade\Config::get('app.page_size', '10');
// layer弹层
$this->_vars['layer_open'] = \think\facade\Config::get('builder.layer_open', false);
// 设置默认模版
$this->_template = 'table_builder/layout';
// 设置默认URL
$this->_vars['data_url'] = Request::baseUrl() . '?getList=1';
$this->_vars['add_url'] = url('add');
$this->_vars['edit_url'] = url('edit', ['id' => '__id__']);
$this->_vars['del_url'] = url('del');
$this->_vars['export_url'] = url('export');
$this->_vars['sort_url'] = url('sort');
}
/**
* 私有化clone函数
*/
private function __clone()
{
// TODO: Implement __clone() method.
}
/**
* 渲染模版
* @param string $template 模板文件名
* @return string
* @throws \Exception
*/
public function fetch(string $template = '')
{
// 单独设置模板
if ($template != '') {
$this->_template = $template;
}
View::assign($this->_vars);
return View::fetch($this->_template);
}
/**
* 设置表格主键
* @param string $key 主键名称
* @return $this
*/
public function setUniqueId($key = '')
{
if ($key != '') {
$this->_vars['unique_id'] = $key;
}
return $this;
}
/**
* 设置页面标题
* @param string $title 页面标题
* @return $this
*/
public function setPageTitle($title = '')
{
if ($title != '') {
$this->_vars['page_title'] = trim($title);
}
return $this;
}
/**
* 设置表单页提示信息
* @param string $tips 提示信息
* @param string $type 提示类型:danger,info,warning,success
* @param string $pos 提示位置:top,search,bottom
* @return $this
*/
public function setPageTips($tips = '', $type = 'info', $pos = 'top')
{
if ($tips != '') {
$this->_vars['page_tips_' . $pos] = $tips;
$this->_vars['tips_type'] = trim($type);
}
return $this;
}
/**
* 设置额外JS代码
* @param string $extra_js 额外JS代码
* @return $this
*/
public function setExtraJs($extra_js = '')
{
if ($extra_js != '') {
$this->_vars['extra_js'] = $extra_js;
}
return $this;
}
/**
* 设置额外CSS代码
* @param string $extra_css 额外CSS代码
* @return $this
*/
public function setExtraCss($extra_css = '')
{
if ($extra_css != '') {
$this->_vars['extra_css'] = $extra_css;
}
return $this;
}
/**
* 设置额外HTML代码
* @param string $extra_html 额外HTML代码
* @param string $pos 位置 [top和bottom]
* @return $this
*/
public function setExtraHtml($extra_html = '', $pos = '')
{
if ($extra_html != '') {
$pos != '' && $pos = '_' . $pos;
$this->_vars['extra_html' . $pos] = $extra_html;
}
return $this;
}
/**
* 添加一列
* @param string $name 字段名称
* @param string $title 字段别名
* @param string $type 单元格类型
* @param string $default 默认值
* @param string $param 额外参数
* @param string $class css类名
* @param string $sortable 是否排序
* @param int $with 列宽
* @return $this
*/
public function addColumn($name = '', $title = '', $type = '', $default = '', $param = '', $class = '', $sortable = 'false', $width = 0)
{
$column = [
'name' => $name, // 字段名称
'title' => $title, // 字段别名
'type' => $type, // 单元格类型
'default' => $default, // 默认值
'param' => $param, // 额外参数
'class' => $class, // css类名
'sortable' => $sortable, // 是否排序
'width' => $width, // 列宽
];
$this->_vars['columns'][] = $column;
$this->_field_name[$name] = $title;
return $this;
}
/**
* 一次性添加多列
* @param array $columns 数据列
* @return $this
*/
public function addColumns($columns = [])
{
if (!empty($columns)) {
foreach ($columns as $column) {
call_user_func_array([$this, 'addColumn'], $column);
}
}
return $this;
}
/**
* 设置是否显示分页
* @param string $value 是否显示分页 true|false
* @return $this
*/
public function setPagination($value = '')
{
if ($value != '') {
$this->_vars['pagination'] = $value;
}
return $this;
}
/**
* 设置列表树父ID
* @param string $value 字段
* @return $this
*/
public function setParentIdField($value = '')
{
if ($value != '') {
$this->_vars['parent_id_field'] = $value;
}
return $this;
}
/**
* 设置空数据提示信息
* @param string $value 字段
* @return $this
*/
public function setEmptyTips($value = '')
{
if ($value != '') {
$this->_vars['empty_tips'] = $value;
}
return $this;
}
/**
* 设置每页显示的行数
* @param string $value 数量
* @return $this
*/
public function setPageSize($value = '')
{
if ($value != '') {
$this->_vars['page_size'] = $value;
}
return $this;
}
/**
* 隐藏第一列多选框(默认显示,多选列多用于批量删除等操作)
* @return $this
*/
public function hideCheckbox()
{
$this->_vars['hide_checkbox'] = true;
return $this;
}
/**
* 添加一个右侧按钮
* @param string $type 按钮类型:edit/delete/default
* @param array $attribute 按钮属性
* @param array $extra 扩展参数(待用)
* @return $this
*/
public function addRightButton($type = '', $attribute = [])
{
switch ($type) {
// 预览按钮
case 'preview':
// 默认属性
$btn_attribute = [
'type' => 'preview',
'title' => '预览',
'icon' => 'fa fa-eye',
'class' => 'btn btn-success btn-xs',
'href' => url('index/preview', ['module' => Request::controller(), 'id' => '__id__']),
'target' => '_blank'
];
break;
// 编辑按钮
case 'edit':
// 默认属性
$btn_attribute = [
'type' => 'edit',
'title' => '编辑',
'icon' => 'fa fa-edit',
'class' => 'btn btn-primary btn-xs',
];
break;
// 删除按钮(不可恢复)
case 'delete':
// 默认属性
$btn_attribute = [
'type' => 'delete',
'title' => '删除',
'icon' => 'far fa-trash-alt',
'class' => 'btn btn-danger btn-xs confirm',
];
break;
// 自定义按钮
default:
// 默认属性
$btn_attribute = [
'title' => '自定义按钮',
'icon' => 'fa fa-smile-o',
'class' => 'btn btn-flat btn-default btn-xs',
'href' => 'javascript:void(0);'
];
break;
}
// 合并自定义属性
if ($attribute && is_array($attribute)) {
$btn_attribute = array_merge($btn_attribute, $attribute);
}
$this->_vars['right_buttons'][] = $btn_attribute;
return $this;
}
/**
* 添加多个右侧按钮
* @param array|string $buttons 按钮类型
* 例如:
* $builder->addRightButtons('edit');
* $builder->addRightButtons('edit,delete');
* $builder->addRightButtons(['edit', 'delete']);
* $builder->addRightButtons(['edit' => ['title' => '查看'], 'delete']);
* @return $this
*/
public function addRightButtons($buttons = [])
{
if (!empty($buttons)) {
$buttons = is_array($buttons) ? $buttons : explode(',', $buttons);
foreach ($buttons as $key => $value) {
if (is_numeric($key)) {
$this->addRightButton($value);
} else {
$this->addRightButton(trim($key), $value);
}
}
}
return $this;
}
/**
* 设置表格URL
* @param string $url url地址
* @return $this
*/
public function setDataUrl($url = '')
{
if ($url != '') {
$this->_vars['data_url'] = $url;
}
return $this;
}
/**
* 设置表格默认的新增地址
* @param string $url url地址
* @return $this
*/
public function setAddUrl($url = '')
{
if ($url != '') {
$this->_vars['add_url'] = $url;
}
return $this;
}
/**
* 设置表格默认的修改地址
* @param string $url url地址
* @return $this
*/
public function setEditUrl($url = '')
{
if ($url != '') {
$this->_vars['edit_url'] = $url;
}
return $this;
}
/**
* 设置表格默认的删除地址
* @param string $url url地址
* @return $this
*/
public function setDelUrl($url = '')
{
if ($url != '') {
$this->_vars['del_url'] = $url;
}
return $this;
}
/**
* 设置表格默认的导出地址
* @param string $url url地址
* @return $this
*/
public function setExportUrl($url = '')
{
if ($url != '') {
$this->_vars['export_url'] = $url;
}
return $this;
}
/**
* 设置表格默认的更改排序地址
* @param string $url url地址
* @return $this
*/
public function setSortUrl($url = '')
{
if ($url != '') {
$this->_vars['sort_url'] = $url;
}
return $this;
}
/**
* 设置搜索参数
* @param array $items
* @return $this
* 第一个参数:类型
* 第二个参数:字段名称
* 第三个参数:字段别名
* 第四个参数:匹配方式(默认为'=',也可以是'<>,>,>=,<<=,LIKE'等等)
* 第五个参数:默认值
* 第六个参数:额外参数(不同类型,用途不同)
*/
public function setSearch($items = [])
{
if (!empty($items)) {
foreach ($items as &$item) {
$item['type'] = $item[0] ?? ''; // 字段类型
$item['name'] = $item[1] ?? ''; // 字段名称
$item['title'] = $item[2] ?? ''; // 字段别名
$item['option'] = $item[3] ?? '='; // 匹配方式
$item['default'] = $item[4] ?? ''; // 默认值
$item['param'] = $item[5] ?? []; // 额外参数
$item['data_source'] = $item[6] ?? 0; // 数据源 [0 字段本身, 1 系统字典, 2 模型数据]
$item['relation_model'] = $item[7] ?? ''; // 模型关联
$item['relation_field'] = $item[8] ?? ''; // 关联字段
$item['field_id'] = $item[9] ?? 0; // 字段编号
}
$this->_vars['search'] = $items;
}
return $this;
}
/**
* 添加一个顶部按钮
* @param string $type 按钮类型:add/edit/del/export/build/default
* @param array $attribute 按钮属性
* @return $this
*/
public function addTopButton($type = '', $attribute = [])
{
switch ($type) {
// 新增按钮
case 'add':
// 默认属性
$btn_attribute = [
'title' => '新增',
'icon' => 'fa fa-plus',
'class' => 'btn btn-success',
'href' => '',
'onclick' => '$.operate.add()',
];
break;
// 修改按钮
case 'edit':
// 默认属性
$btn_attribute = [
'title' => '修改',
'icon' => 'fa fa-edit',
'class' => 'btn btn-primary single disabled',
'href' => '',
'onclick' => '$.operate.edit()',
];
break;
// 删除按钮
case 'del':
// 默认属性
$btn_attribute = [
'title' => '删除',
'icon' => 'fa fa-times',
'class' => 'btn btn-danger multiple disabled',
'href' => '',
'onclick' => '$.operate.removeAll()'
];
break;
// 导出按钮
case 'export':
// 默认属性
$btn_attribute = [
'title' => '导出',
'icon' => 'fa fa-download',
'class' => 'btn btn-warning',
'href' => '',
'onclick' => '$.table.export()'
];
break;
// 生成按钮
case 'build':
// 默认属性
$btn_attribute = [
'title' => '代码生成',
'icon' => 'fa fa-code',
'class' => 'btn btn-info single disabled',
'href' => '',
'onclick' => '$.operate.build(\'\', \'' . url('module/build') . '\')',
'group' => [
'class' => 'btn-info single disabled', // 下拉分组组样式
'menus' => [ // 下拉分组数据(内容同按钮一样)
[
'title' => '生成验证器',
'icon' => '',
'class' => 'btn btn-info',
'href' => '',
'onclick' => '$.operate.build(\'\', \'' . url('module/build', ['file' => 'validate']) . '\')',
],
[
'title' => '生成模型',
'icon' => '',
'class' => 'btn btn-info',
'href' => '',
'onclick' => '$.operate.build(\'\', \'' . url('module/build', ['file' => 'model']) . '\')',
],
[
'title' => '生成控制器',
'icon' => '',
'class' => 'btn btn-info',
'href' => '',
'onclick' => '$.operate.build(\'\', \'' . url('module/build', ['file' => 'controller']) . '\')',
],
],
]
];
break;
// 自定义按钮
default:
// 默认属性
$btn_attribute = [
'title' => '自定义',
'icon' => 'fa fa-lightbulb',
'class' => 'btn btn-default',
'href' => '',
'onclick' => ''
];
break;
}
// 合并自定义属性
if ($attribute && is_array($attribute)) {
$btn_attribute = array_merge($btn_attribute, $attribute);
}
$this->_vars['top_buttons'][] = $btn_attribute;
return $this;
}
/**
* 一次性添加多个顶部按钮
* @param array|string $buttons 按钮组
* 例如:
* addTopButtons('add')
* addTopButtons('add, edit, del')
* addTopButtons(['add', 'del'])
* addTopButtons(['add' => ['title' => '增加'], 'del'])
* @return $this
*/
public function addTopButtons($buttons = [])
{
if (!empty($buttons)) {
$buttons = is_array($buttons) ? $buttons : explode(',', $buttons);
foreach ($buttons as $key => $value) {
if (is_numeric($key)) {
// key为数字则直接添加一个按钮
$this->addTopButton($value);
} else {
// key不为数字则需设置属性,去除前后空格
$this->addTopButton(trim($key), $value);
}
}
}
return $this;
}
/**
* 设置是否在添加/编辑等页启用layer弹层加载
* @param string $value 是否启用layer true|false
* @return $this
*/
public function setLayerOpen($value = true)
{
$this->_vars['layer_open'] = $value;
return $this;
}
/**
* 设置左侧固定列数
* @param string $value 列数
* @return $this
*/
public function setFixedLeft($value = 1)
{
$this->_vars['fixed_left'] = $value;
return $this;
}
/**
* 设置右侧固定列数
* @param string $value 列数
* @return $this
*/
public function setFixedRight($value = 1)
{
$this->_vars['fixed_right'] = $value;
return $this;
}
}

47
app/common/builder/build/Controller.php

@ -0,0 +1,47 @@
<?php
/**
* +----------------------------------------------------------------------
* | {$comment}控制器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: {$author}
* ::::::::::: | EMAIL: {$email}
* ..:::::::::::' | DATETIME: {$dateTime}
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\controller;
// 引入框架内置类
use think\facade\Request;
// 引入表格和表单构建器
use app\common\facade\MakeBuilder;
use app\common\builder\FormBuilder;
use app\common\builder\TableBuilder;
class {$modelName} extends Base
{
// 验证器
protected $validate = '{$validate}';
// 当前主表
protected $tableName = '{$tableName}';
// 当前主模型
protected $modelName = '{$modelName}';
}

38
app/common/builder/build/Model.php

@ -0,0 +1,38 @@
<?php
/**
* +----------------------------------------------------------------------
* | {$comment}模型
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: {$author}
* ::::::::::: | EMAIL: {$email}
* ..:::::::::::' | DATETIME: {$dateTime}
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\common\model;
class {$modelName} extends Base
{
// 定义时间戳字段名
protected $createTime = 'create_time';
protected $updateTime = 'update_time';
{$modulePk}
{$moduleTable}
{$relations}
}

33
app/common/builder/build/Validate.php

@ -0,0 +1,33 @@
<?php
/**
* +----------------------------------------------------------------------
* | {$comment}验证器
* +----------------------------------------------------------------------
* .::::.
* .::::::::. | AUTHOR: {$author}
* ::::::::::: | EMAIL: {$email}
* ..:::::::::::' | DATETIME: {$dateTime}
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
* +----------------------------------------------------------------------
*/
namespace app\admin\validate;
use think\Validate;
class {$modelName} extends Validate
{
{$rules}
}

12
app/common/facade/Cms.php

@ -0,0 +1,12 @@
<?php
namespace app\common\facade;
use think\Facade;
class Cms extends Facade
{
protected static function getFacadeClass()
{
return 'app\common\service\Cms';
}
}

12
app/common/facade/MakeBuilder.php

@ -0,0 +1,12 @@
<?php
namespace app\common\facade;
use think\Facade;
class MakeBuilder extends Facade
{
protected static function getFacadeClass()
{
return 'app\common\builder\MakeBuilder';
}
}

12
app/common/facade/User.php

@ -0,0 +1,12 @@
<?php
namespace app\common\facade;
use think\Facade;
class User extends Facade
{
protected static function getFacadeClass()
{
return 'app\common\service\User';
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save