69 Commits

Author SHA1 Message Date
wolfcode
74c21d2397 Update public.css 2024-10-09 13:37:46 +08:00
wolfcode
f1d049fc0a Update logviewer.php 2024-10-09 11:12:27 +08:00
wolfcode
a6ec0f143a feat(log): 新增框架日志查看器,integrate log viewer and improve log management
- Add log viewer functionality using wolf-leo/phplogviewer package
- Implement log record feature in admin system
- Update log table to include log record button
- Configure default and common log modules in logviewer config

Signed-off-by: wolfcode <37436228+wolf-leo@users.noreply.github.com>
2024-10-09 10:02:42 +08:00
wolfcode
a1d4aa97d5 feat(log): 新增框架日志查看器,integrate log viewer and improve log management
- Add log viewer functionality using wolf-leo/phplogviewer package
- Implement log record feature in admin system
- Update log table to include log record button
- Configure default and common log modules in logviewer config

Signed-off-by: wolfcode <37436228+wolf-leo@users.noreply.github.com>
2024-10-09 09:51:25 +08:00
wolfcode
4b8e163454 feat(goods): optimize goods add and edit pages
- Adjust layout of goods add and edit forms for better readability- Enhance editor visibility on the right side of the page
- Increase dialog size for adding and editing goods to improve usability

Signed-off-by: wolfcode <37436228+wolf-leo@users.noreply.github.com>
2024-10-07 13:26:49 +08:00
wolfcode
c2762fa2ad feat(goods): optimize goods add and edit pages
- Adjust layout of goods add and edit forms for better readability- Enhance editor visibility on the right side of the page
- Increase dialog size for adding and editing goods to improve usability

Signed-off-by: wolfcode <37436228+wolf-leo@users.noreply.github.com>
2024-10-07 13:07:17 +08:00
wolfcode
de92299a4f Update README.md 2024-09-27 16:59:48 +08:00
wolfcode
a4782ad38e 🚀Layui v2.9.17 2024-09-25 10:05:01 +08:00
wolfcode
36038516e0 fix(SystemLog): limit response content in admin middleware
Implement a limitation on the amount of response content recorded in the system logs
to avoid excessively large entries. The response is now truncated to 3000 characters,
enhancing performance and readability while still capturing essential data.
2024-09-20 09:51:17 +08:00
wolfcode
aeb3b28184 fix(SystemLog): limit response content in admin middleware
Implement a limitation on the amount of response content recorded in the system logs
to avoid excessively large entries. The response is now truncated to 3000 characters,
enhancing performance and readability while still capturing essential data.
2024-09-20 09:49:26 +08:00
wolfcode
cb34bf1758 fix(log): allow text wrapping in table cells
Modified the log table's line style to enable 'word-break: break-all' property, which permits text to break and wrap within table cells. This adjustment addresses the issue
where long strings of text would overflow or extend beyond the cell's boundary, now
ensuring that all content remains neatly contained within the structure of the table.
2024-09-19 16:34:24 +08:00
wolfcode
84f0bdcc77 refactor(admin/middleware): update request type to app\Request
Change the type of the request parameter in middleware handle functions to use
app\Request instead of the plain $request. This update clarifies the expected
request object type for better type checking and autocompletion support.
2024-09-14 17:33:07 +08:00
wolfcode
ef40aa27b7 fix(goods): 添加属性显示与否演示 add visible check for stock button in admin mallImplement a conditional 'visible' attribute for the 'stock' button within the goods
management section of the admin mall interface, ensuring the button only appears
when the goods status is set to 1 (active). This change streamlines the UI by
hiding irrelevant options for inactive goods items.
2024-09-13 10:56:27 +08:00
wolfcode
e69fddd2f7 feat(table): 新增 visible 参数值控制属性显示与否 pass data param to buildOperatHtml for visibility logic
Pass the `data` parameter to the `buildOperatHtml` function to support dynamic visibility checks for table operations. This allows operation visibility to be conditionally determined
based on the provided data.
2024-09-13 10:51:11 +08:00
wolfcode
229c74fbea feat(admin): add DEBUG mode button to welcome page
Display the status of the DEBUG mode on the welcome page with a button that changes color
and text based on the value of `APP_DEBUG` environment variable. Include a grey badge
提示 to prompt users to switch off DEBUG mode in production environments.
2024-09-12 18:38:56 +08:00
wolfcode
336ca82729 feat(search-form): 新增默认关闭搜索表单自动补全功能 add autocomplete control and other improvements
- Add an attribute 'searchTableAutocomplete' to enable/disable form autocomplete.
- Set 'searchTableShow' attribute to control the visibility of the search form.
- Remove redundant form initialization code for a cleaner setup.
2024-09-11 16:46:09 +08:00
wolfcode
5b444f7fc1 fix(admin): remove version param from require.js to use cache
Removed the version parameter from the require.js src attribute to enable browser caching
of the script. This change will improve load times and performance by leveraging cached
versions of the script when users revisit the site.
2024-09-11 09:45:17 +08:00
wolfcode
7375b7cbf0 fix(admin): remove version param from require.js to use cache
Removed the version parameter from the require.js src attribute to enable browser caching
of the script. This change will improve load times and performance by leveraging cached
versions of the script when users revisit the site.
2024-09-11 09:43:44 +08:00
wolfcode
62a3d80fa3 fix(wangEditor): correctly access wangEditor instances
Correct the way wangEditor instances are accessed and stored in the window object. The previous
implementation using `eval` could lead to security risks and is removed in favor of direct
window property access. This change improves code security and reliability by eliminating `eval`
and clarifying the object property name construction.
2024-09-05 09:33:38 +08:00
wolfcode
ea733d0acb feat(admin): 新增 markdown 编辑器支持,integrate EasyMDE markdown editor for admin interface
Introduce the EasyMDE markdown editor into the admin interface, providing enhanced
markdown editing capabilities. This integration caters to users preferring a dedicated
markdown editor with additional features and a streamlined user experience.
2024-09-02 16:09:36 +08:00
wolfcode
857533704e fix(admin-controller): ensure page and limit are integers
Cast page and limit values to integers in AdminController's filter method to prevent
type-related errors. This change guarantees that these parameters are whole numbers,
which is essential for consistent database pagination and filtering operations.
2024-08-27 18:49:26 +08:00
wolfcode
af419ff25b feat(cache): set default cache prefix to 'EA8TP'
To prevent cache data residuals between different versions, the default cache prefix
has been changed from an empty string to 'EA8TP'. This ensures each version's cache
is distinctly separated.

BREAKING CHANGE: The cache prefix 'EA8TP' is now used by default. If your application
depends on the default cache prefix being empty, you will need to explicitly set the
prefix to an empty string.
2024-08-26 18:03:16 +08:00
wolfcode
dcbb944fbf 🚀 Layui v2.9.16 2024-08-26 10:39:44 +08:00
wolfcode
5081a21a0b fix(easy-admin): 表格 toolbar 支持元素传入
The renderToolbar function in easy-admin now checks if the provided data is an object before
attempting to iterate over it. This fix prevents errors when the data parameter is not an object,
ensuring that the function does not break down and correctly returns the provided data.
2024-08-23 17:20:19 +08:00
wolfcode
92c75e52ba feat(admin-view): update welcome page layout and information display
Admin welcome page has been redesigned to improve the layout and readability of displayed
information. Real-time statistics panels have been adjusted with new color schemes, and the
information presentation has been refined with appropriate heading sizes. Additionally, the
page now links to the layui documentation and includes a reminder about the open-source
nature of the framework.

- Redesign the overall layout of the welcome page.
- Refactor real-time statistics panels with updated styles and content.
- Improve the display of quick entry modules.
- Add links to layui documentation and policy reminders.
- Ensure consistent use of spaces and clean up the footer section.
2024-08-22 10:42:30 +08:00
wolfcode
2b7f57cc9f Update echarts.min.js 2024-08-22 10:25:55 +08:00
wolfcode
0708435d91 feat(switch): add 'is_show' to switch field optionsInclude 'is_show' as an option in the switchFields array to enable the use of a switch
component for toggling the visibility of fields in the admin panel's build form.
2024-08-21 14:15:07 +08:00
wolfcode
c3a6118387 fix(admin-config): ensure required JS loads on DOM ready; add error handling
Moved the RequireJS dynamic load of the controller-specific JavaScript to execute upon
the 'load' event of the window, guaranteeing that all required DOM elements are available
before the script execution begins. Also, added error handling to log any require failures
to the console for easier debugging.
2024-08-20 17:41:32 +08:00
wolfcode
d7dcfb95b6 fix(admin-config): ensure required JS loads on DOM ready; add error handling
Moved the RequireJS dynamic load of the controller-specific JavaScript to execute upon
the 'load' event of the window, guaranteeing that all required DOM elements are available
before the script execution begins. Also, added error handling to log any require failures
to the console for easier debugging.
2024-08-20 17:22:54 +08:00
wolfcode
55c4743417 🚀 更新CRUD/CRUD可视化操作,新增支持可视化命令行
Extend the CURD generation functionality to support command line operations, supplementing
the existing visual generation method. This update includes modifications to the admin interface, enabling the system to process both types of CURD generation commands effectively.
2024-08-20 09:40:34 +08:00
wolfcode
f56e3630b6 🚀 Layui v2.9.15 2024-08-20 09:39:31 +08:00
wolfcode
6dfdffeab9 feat(console): add CRUD support and update usage warning
Extend the console command configuration to include 'crud' alongside the existing 'curd'
command for better supporting CRUD operations in the application. Additionally, update the
user warning message to recommend using the visual generation features for CRUD functionality
within the system, indicating that further support for command-line CURD/CRUD will be phased out.Adjust the related fields handling in the Curd command class methods to use 'onlyField' for
consistency with the singular form of field manipulations, and ensure correct method parameter
names are reflected in the relation setup.
2024-08-16 11:32:13 +08:00
wolfcode
ed0e14cb32 fix(admin): use direct IP retrieval for system logs
Direct IP retrieval method has been updated to improve accuracy in the admin system log.
This change involves modifying the IP address retrieval logic from considering the
`HTTP_X_FORWARDED_FOR` header to directly using the `ip()` method, potentially enhancing
the security and reliability of IP logging.
2024-08-12 15:58:23 +08:00
wolfcode
772ffc6328 fix(admin): correct admin login page redirect
After the admin session expires, the system now correctly redirects to the specified admin login URL, addressing the issue where the redirect would
sometimes point to an incorrect path.
2024-08-12 13:57:33 +08:00
wolfcode
c9f65c838e Update Curd.php 2024-08-06 19:49:24 +08:00
wolfcode
7f3a3a85f3 CURD生成器:增强字段类型设置和模板调整
本次更新增强了CURD生成器的字段类型自定义功能,允许开发者通过Web界面设置特定字段的类型,例如忽略字段、下拉字段、单选字段、多选字段、图片字段、多选图片字段、日期字段、日期时间字段和编辑器字段。这些设置会直接影响生成的控制器、模型和视图文件,从而提供更高的灵活性和定制化能力。此外,还对代码模板进行了调整,引入了`$notes`变量来存储字段定义,简化了视图中的脚本处理,并优化了控制器和模型中的代码结构。这些改动旨在改善代码的可读性和可维护性,同时使CURD生成器的使用更加直观和便捷。

通过这次更新,我们希望进一步提升CURD生成器的实用性和用户体验,减少开发者在日常 CRUD操作中重复编写代码的工作量。相关的代码改动包括对`BuildCurd.php`文件的多处调整,以实现新的字段类型设置功能;对`CommonTool.php`的修改,以支持新的数组字符串处理逻辑;对`controller.code`、`curd_generate.js`、`curd_generate.php`、`index.code`和`index.html`等文件的修改,以确保生成的代码与新的设置逻辑兼容,并改善前端交互体验。
2024-07-31 14:47:24 +08:00
wolfcode
c5a091c732 移除Vue实例并优化配置项加载逻辑
删除了`config.js`中的Vue实例创建过程,简化了上传类型的数据绑定。通过直接操作`app.upload_type`来响应上传类型的变化。
2024-07-26 10:20:18 +08:00
wolfcode
4f184abb08 移除Vue实例并优化配置项加载逻辑
删除了`config.js`中的Vue实例创建过程,简化了上传类型的数据绑定。通过直接操作`app.upload_type`来响应上传类型的变化。
2024-07-26 10:08:09 +08:00
wolfcode
1365fd08a0 fix(system/config): correct upload button reference in admin background config
Update the data-upload attribute on the upload button in the admin background
configuration page to correctly reference 'admin_background' instead of
'site_ico', ensuring the button functions as intended when uploading a new
background image.
2024-07-26 09:38:54 +08:00
wolfcode
71aee61345 Merge remote-tracking branch 'origin/main' 2024-07-19 21:14:39 +08:00
wolfcode
efbf557cc0 fix(admin): ensure CheckAuth is enabled for route verification
Enable CheckAuth in the admin route configuration which was previously
commented out, ensuring that node permissions are validated as expected.
2024-07-19 21:14:28 +08:00
wolfcode
96d162d11f 切换编辑器类型时修正了common.php中编辑器样式的分配问题。
根据编辑器类型(ckeditor、wangEditor、ueditor),现在正确地分配了相应的HTML结构。
之前默认分配给wangEditor的div结构,在编辑器类型为ueditor时会出现问题,现在已将其修正为正确的script标签结构。
同时,也对ckeditor的textarea标签进行了样式修正。
2024-07-18 12:40:18 +08:00
wolfcode
27b718da3c fix(composer): update alibabacloud/client dependency to support PHP 8.1
The Alibaba Cloud client dependency has been updated to version 1.6.0 to add
PHP 8.1 compatibility. This change is reflected in the composer.json file under
the `require` section.

Additionally, the ordering of the `ext-mysqli` and `ext-pdo` dependencies has
been corrected for clarity and consistency.
2024-07-17 11:32:15 +08:00
wolfcode
e49b747f43 style: adjust width of search input in easy-admin
Set a fixed width for the search input field in the easy-admin plugin to
enhance the consistency and readability of the search section. The update
modifies the easy-admin.js and public.css files to enforce the new styling.
2024-07-16 16:02:19 +08:00
wolfcode
a2942e5589 feat(easy-admin): add laySearch support for search boxes in lists
Introduce the `laySearch` option to enable the search functionality on list
page search boxes. This improvement allows users to have a more intuitive
and interactive way of searching through the list data by providing a search
box with clear and concise feedback.

When `laySearch` is set to true, the corresponding search box will now
be equipped with the `lay-search` class which enhances the user interface
and experience.
2024-07-10 14:30:16 +08:00
wolfcode
f121d3c8b3 feat(easy-admin): add laySearch support for search boxes in lists
Introduce the `laySearch` option to enable the search functionality on list
page search boxes. This improvement allows users to have a more intuitive
and interactive way of searching through the lists by providing a search
input alongside the dropdown options.
2024-07-10 14:29:49 +08:00
wolfcode
a069704803 🚀 Layui v2.9.14 2024-07-10 14:20:48 +08:00
wolfcode
58db4f4277 fix(common): correct spelling of 'selectFields' in Curd.php
Fix misspelling of 'selectFields' option throughout Curd.php, ensuring consistency and
correctness in the command's configuration options.
2024-07-10 11:53:07 +08:00
wolfcode
332ededb3a update README.md 2024-07-10 11:19:01 +08:00
wolfcode
214b3e9f19 update README.md 2024-07-10 11:16:35 +08:00
wolfcode
6b97ca12de feat(admin): add table order sorting functionality
初始化表格排序,js排序操作传递到服务端
2024-07-08 14:57:18 +08:00
wolfcode
11aa723d75 fix(easy-admin): prevent js error when operat is not object
When the operat parameter passed to the easy-admin.js plugin is not an object,it previously caused a JavaScript error. This fix adds a check to ensure that operat is indeed an object before processing it, thus preventing the error.
2024-07-08 10:25:40 +08:00
wolfcode
df69c2aea4 refactor(admin-model): change MallGoods cate relation from BelongsTo to HasOne
The relationship between MallGoods and MallCate has been updated to reflect a HasOne
association rather than a BelongsTo. This change is reflected in the cate() method
of the MallGoods model, enhancing the flexibility of the model relationships.
2024-07-01 13:51:58 +08:00
wolfcode
5855a97255 Improve category selection in goods management - Simplify HTML structure and recommend a concise coding method for
category selection in both add and edit pages of the mall goods module.
- Modify the corresponding JS file to support the new category display format.
- Refactor controller code to assign categories using a more efficient method.
- Ensure consistent category data processing across all related views.

Note: This change updates the way categories are presented to the admin user,
enhancing usability and maintainability of the goods management system.
2024-06-20 10:23:27 +08:00
wolfcode
88035326a4 refactor(admin): change default editor from ueditor to wangEditor
Due to the recommendation for better performance and user experience,
the default editor in both configuration files and view templates has been
switched from ueditor to wangEditor. The code changes reflect this update by
marking ueditor as '(不建议使用)' (not recommended) and WangEditor as
'(推荐使用)' (recommended). Additionally, the relevant controller file has
been updated to ensure that the correct default editor is loaded based on
the new configuration setting.
2024-06-19 15:30:03 +08:00
wolfcode
df3571534c Adjust the editor_textarea function to allow $detail parameter as nullable
The function signature for `editor_textarea` in common.php has been updated
to accept `$detail` as a nullable string. This change allows the function to handle cases
where `$detail` might not be provided or could be null.

```php
-    function editor_textarea(string $detail, string $name = 'desc', string $placeholder = '请输入'): string
+ function editor_textarea(?string $detail, string $name = 'desc', string $placeholder = '请输入'): string
```
2024-06-18 17:36:23 +08:00
wolfcode
417a834593 feat(curd): 初始化下拉、单选、复选字段的后缀和字段类型定义
在BuildCurd.php中,新增了下拉字段的后缀定义及相关的字段类型数组初始化,同时对单选框和复选框的后缀及字段类型进行了初始化配置。这些改动将有助于更精确地识别和处理不同类型的表单字段。
2024-06-14 15:15:34 +08:00
wolfcode
070d9494e7 🚀 Layui V2.9.11 2024-06-07 13:38:33 +08:00
wolfcode
6dcd0c8d1f fix: 修复自动生成页面时获取表字段注释匹配失效 2024-06-07 11:35:46 +08:00
wolfcode
09beccc30b fix: 当修改后台路径时百度编辑器配置报错 2024-06-07 09:41:07 +08:00
wolfcode
41a444a49d Update LICENSE 2024-06-06 18:42:20 +08:00
wolfcode
1071c7e1d2 Update Ajax.php 2024-06-06 16:58:41 +08:00
wolfcode
8b1e9e3744 Update README.md 2024-05-23 17:38:40 +08:00
wolfcode
40256d3d4b Update welcome.html 2024-05-23 17:38:37 +08:00
wolfcode
4974ba7c79 🚀 Layui V2.9.10 2024-05-23 17:34:15 +08:00
wolfcode
9d61503ea6 Update Curd.php 2024-05-14 15:23:40 +08:00
wolfcode
2ec046de07 Update console.php 2024-05-14 13:33:30 +08:00
wolfcode
0c68f2c1ad Update session.php 2024-05-13 18:30:14 +08:00
wolfcode
a6fd81b0ed 🚀 202405重置版 2024-05-13 11:16:20 +08:00
259 changed files with 10807 additions and 3176 deletions

View File

@@ -1,24 +1,19 @@
APP_DEBUG=true
[APP]
DEFAULT_TIMEZONE=Asia/Shanghai
[DATABASE]
TYPE=mysql
HOSTNAME=127.0.0.1
DATABASE=easyadmin8
USERNAME=root
PASSWORD=root
HOSTPORT=3306
CHARSET=utf8mb4
DEBUG=true
PREFIX=ea8_
[LANG]
default_lang=zh-cn
DB_TYPE=mysql
DB_HOST=127.0.0.1
DB_NAME=easyadmin8
DB_USER=root
DB_PASS=root
DB_PORT=3306
DB_CHARSET=utf8mb4
DB_PREFIX=ea8_
# 后台配置项组
[EASYADMIN]
# 后台地址后缀名称
ADMIN=admin

27
.gitignore vendored
View File

@@ -1,21 +1,12 @@
/.idea
/.vscode
*.log
.env
config/install/lock/install.lock
/public/upload
/public/storage
/public/docs
runtime/admin
runtime/index
runtime/log
runtime/session
runtime/temp
runtime/cache
public/conf
public/WowOss.exe
app/index/controller/Test.php
composer.phar
app/test/
vendor
composer.lock
composer.lock
.DS_Store
Thumbs.db
/.idea
/.vscode
/vendor
/.settings
/.buildpath
/.project

66
CURD.md
View File

@@ -1,66 +0,0 @@
# CURD命令大全
`EasyAdmin8`框架以内置快速生成CURD的命令, 包括控制器、视图、模型、JS文件。能够使开发者效率得到进一步提升。
# 常用命令
```shell
# 生成ea8_test_goods表的CURD
php think curd -t test_goods
# 生成ea8_test_goods表的CURD, 文件冲突时强制覆盖
php think curd -t test_goods -f 1
# 删除ea8_test_goods表的CURD
php think curd -t test_goods -d 1
# 生成ea8_test_goods表的CURD, 控制器在目录demo下的Goods.php文件
php think curd -t test_goods -c demo/Goods
# 生成ea8_test_goods表的CURD, 模型在目录demo下的Goods.php文件
php think curd -t test_goods -m demo/Goods
# 生成ea8_test_goods表的CURD, 并关联ea8_test_cate表, 并设置外键为cate_id
php think curd -t test_goods -r test_cate --foreignKey=cate_id --primaryKey=id
# 生成ea8_test_goods表的CURD, 并关联ea8_test_cate表, 并设置只显示title,image两个字段
php think curd -t test_goods -r test_cate --foreignKey=cate_id --relationOnlyFileds=title,image
# 生成ea8_test_goods表的CURD, 并关联ea8_test_cate表, 并设置主表外键cate_id在表单的下拉选择显示的关联表的title字段
php think curd -t test_goods -r test_cate --foreignKey=cate_id --relationBindSelect=title
# 生成ea8_test_goods表的CURD, 并设置logo字段后缀为单图片
php think curd -t test_goods --imageFieldSuffix=logo
# 生成ea8_test_goods表的CURD, 并设置忽略remark, stock字段
php think curd -t test_goods --ignoreFields=remark --ignoreFields=stock
```
# 参数介绍
| 短参 | 长参 | 说明 |
| --- | --- |--- |
| -t | --table=VALUE | 主表名 |
| -c | --controllerFilename=VALUE | 控制器文件名 |
| -m | --modelFilename=VALUE | 主表模型文件名 |
| -f | --force=VALUE | 强制覆盖模式 |
| -d | --delete=VALUE | 删除模式 |
| | --checkboxFieldSuffix=VALUE | 复选框字段后缀 |
| | --radioFieldSuffix=VALUE | 单选框字段后缀 |
| | --imageFieldSuffix=VALUE | 单图片字段后缀 |
| | --imagesFieldSuffix=VALUE | 多图片字段后缀 |
| | --fileFieldSuffix=VALUE | 单文件字段后缀 |
| | --filesFieldSuffix=VALUE | 多文件字段后缀 |
| | --dateFieldSuffix=VALUE | 时间字段后缀 |
| | --switchFields=VALUE | 开关的字段 |
| | --selectFileds=VALUE | 下拉的字段 |
| | --editorFields=VALUE | 富文本的字段 |
| | --sortFields=VALUE | 排序的字段 |
| | --ignoreFields=VALUE | 忽略的字段 |
| -r | --relationTable=VALUE | 关联表名 |
| | --foreignKey=VALUE | 关联外键 |
| | --primaryKey=VALUE | 关联主键 |
| | --relationOnlyFileds=VALUE | 关联模型中只显示的字段 |
| | --relationBindSelect=VALUE | 关联模型中的字段用于主表外键的表单下拉选择 |
| | --relationModelFilename=VALUE | 关联模型文件名 |

View File

@@ -18,4 +18,4 @@ 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.
SOFTWARE.

View File

@@ -1 +0,0 @@
# EasyAdmin8

View File

@@ -1,3 +1,14 @@
<div align="center" dir="auto">
<img alt="log" src="/public/static/common/images/logo-8.png" />
<span><img src="https://img.shields.io/badge/php-%3E=8.0.0-brightgreen.svg?style=for-the-badge&logo=php&colorB=ff69b4" alt="php"></span>
<span><img src="https://img.shields.io/badge/mysql-%3E=5.7-brightgreen.svg?style=for-the-badge&logo=mysql&colorB=blue" alt="MySQL"></span>
<span><img src="https://img.shields.io/badge/thinkphp-%3E=8.0.0-brightgreen.svg?style=for-the-badge&logo=thinkphp" alt="ThinkPHP"></span>
<span><img src="https://img.shields.io/badge/layui-%3E=2.9.0-brightgreen.svg?style=for-the-badge&logo=layui&colorB=orange" alt="layui"></span>
<span><img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge&logo=license&colorB=purple" alt="License"></span>
</div>
## `EasyAdmin8`所有版本 (当前项目为`ThinkPHP`版本)
| | Github | Gitee |
@@ -20,6 +31,10 @@
>
>【如果不能访问,可以自行本地搭建预览或参考下方界面预览图】
## 大版本更新记录:
[更新记录](log.md)
## 安装教程
> EasyAdmin8 使用 Composer 来管理项目依赖。因此,在使用 EasyAdmin8 之前,请确保你的机器已经安装了 Composer。
@@ -80,7 +95,7 @@
* [EasyAdmin](http://easyadmin.99php.cn/docs)
* [Layui 2.8.x](https://layui.dev/docs/2.8/)
* [Layui 2.9.x](https://layui.dev/docs)
* [Layuimini](https://github.com/zhongshaofa/layuimini)

22
app/AppService.php Normal file
View File

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

View File

@@ -64,7 +64,7 @@ abstract class BaseController
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
protected function validate(array $data, string|array $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
@@ -72,7 +72,7 @@ abstract class BaseController
} else {
if (strpos($validate, '.')) {
// 支持场景
list($validate, $scene) = explode('.', $validate);
[$validate, $scene] = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();

View File

@@ -1,11 +1,8 @@
<?php
namespace app;
// 应用请求对象类
class Request extends \think\Request
{
protected $filter = ['htmlspecialchars'];
}

View File

@@ -1,33 +1,24 @@
<?php
return [
// 不需要验证登录的控制器
'no_login_controller' => [
'login',
],
// 不需要验证登录的节点
'no_login_node' => [
'login/index',
'login/out',
],
// 后台路径地址 默认 admin
'alias_name' => env('EASYADMIN.ADMIN'),
// 不需要验证权限的控制器
'no_auth_controller' => [
'no_auth_controller' => [
'ajax',
'login',
'index',
],
// 不需要验证权限的节点
'no_auth_node' => [
'no_auth_node' => [
'login/index',
'login/out',
],
//上传类型
'upload_types' => [
'upload_types' => [
'local' => '本地存储',
'oss' => '阿里云oss',
'cos' => '腾讯云cos',
@@ -35,9 +26,11 @@ return [
],
// 默认编辑器
'editor_types' => [
'ueditor' => '百度编辑器',
'editor_types' => [
'ueditor' => '百度编辑器(不建议使用)',
'ckeditor' => 'CK编辑器',
'wangEditor' => 'wangEditor',
'wangEditor' => 'wangEditor(推荐使用)',
'EasyMDE' => 'EasyMDE(markdown)',
],
];

View File

@@ -1,10 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | 应用设置
// +----------------------------------------------------------------------
use think\facade\Env;
return [
];

View File

@@ -1,10 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | 控制台配置
// +----------------------------------------------------------------------
return [
// 指令定义
'commands' => [
'alioss' => 'addons\alioss\command\Alioss',
],
];

View File

@@ -1,19 +1,28 @@
<?php
use app\admin\middleware\CheckInstall;
use app\admin\middleware\CheckLogin;
use app\admin\middleware\CheckAuth;
use app\admin\middleware\SystemLog;
// 你可以在这里继续写你需要的路由
// +----------------------------------------------------------------------
// | 路由设置
// | 这里只是路由的中间件
// | 至于为什么要把中间件配置写在这里呢??? Why???
// | 因为 ThinkPHP官方最新版本 已经不支持在中间件获取 controller 和 action 了
// +----------------------------------------------------------------------
return [
// 路由中间件
'middleware' => [
// // 后台视图初始化
// \app\admin\middleware\ViewInit::class,
// 检测用户是否登录
// \app\admin\middleware\CheckAdmin::class,
// 判断是否已经安装后台系统
CheckInstall::class,
// 检测是否登录
CheckLogin::class,
// 操作日志
SystemLog::class,
// 验证节点权限
CheckAuth::class,
],
];
];

View File

@@ -6,6 +6,7 @@ use app\admin\model\SystemUploadfile;
use app\admin\service\UploadService;
use app\common\controller\AdminController;
use app\common\service\MenuService;
use app\Request;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
@@ -25,28 +26,28 @@ class Ajax extends AdminController
*/
public function initAdmin(): Json
{
$cacheData = Cache::get('initAdmin_' . session('admin.id'));
$cacheData = Cache::get('initAdmin_' . $this->adminUid);
if (!empty($cacheData)) {
return json($cacheData);
}
$menuService = new MenuService(session('admin.id'));
$menuService = new MenuService($this->adminUid);
$data = [
'logoInfo' => [
'title' => sysconfig('site', 'logo_title'),
'image' => sysconfig('site', 'logo_image'),
'title' => sysConfig('site', 'logo_title'),
'image' => sysConfig('site', 'logo_image'),
'href' => __url('index/index'),
],
'homeInfo' => $menuService->getHomeInfo(),
'menuInfo' => $menuService->getMenuTree(),
];
Cache::tag('initAdmin')->set('initAdmin_' . session('admin.id'), $data);
Cache::tag('initAdmin')->set('initAdmin_' . $this->adminUid, $data);
return json($data);
}
/**
* 清理缓存接口
*/
public function clearCache()
public function clearCache(): void
{
Cache::clear();
$this->success('清理缓存成功');
@@ -54,17 +55,19 @@ class Ajax extends AdminController
/**
* 上传文件
* @param Request $request
* @return Json|null
*/
public function upload()
public function upload(Request $request): Json|null
{
$this->isDemo && $this->error('演示环境下不允许修改');
$this->checkPostRequest();
$type = $this->request->param('type', '');
$type = $request->param('type', '');
$data = [
'upload_type' => $this->request->post('upload_type'),
'file' => $this->request->file($type == 'editor' ? 'upload' : 'file'),
'upload_type' => $request->post('upload_type'),
'file' => $request->file($type == 'editor' ? 'upload' : 'file'),
];
$uploadConfig = sysconfig('upload');
$uploadConfig = sysConfig('upload');
empty($data['upload_type']) && $data['upload_type'] = $uploadConfig['upload_type'];
$rule = [
'upload_type|指定上传类型有误' => "in:{$uploadConfig['upload_allow_type']}",
@@ -81,30 +84,35 @@ class Ajax extends AdminController
if ($code == 0) {
$this->error($upload['data'] ?? '');
}else {
$type == 'editor' ? json(
[
'error' => ['message' => '上传成功', 'number' => 201,],
'fileName' => '',
'uploaded' => 1,
'url' => $upload['data']['url'] ?? '',
]
) : $this->success('上传成功', $upload['data'] ?? '');
if ($type == 'editor') {
return json(
[
'error' => ['message' => '上传成功', 'number' => 201,],
'fileName' => '',
'uploaded' => 1,
'url' => $upload['data']['url'] ?? '',
]
);
}else {
$this->success('上传成功', $upload['data'] ?? '');
}
}
}
/**
* 获取上传文件列表
* @param Request $request
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getUploadFiles(): Json
public function getUploadFiles(Request $request): Json
{
$get = $this->request->get();
$page = isset($get['page']) && !empty($get['page']) ? $get['page'] : 1;
$limit = isset($get['limit']) && !empty($get['limit']) ? $get['limit'] : 10;
$title = isset($get['title']) && !empty($get['title']) ? $get['title'] : null;
$get = $request->get();
$page = !empty($get['page']) ? $get['page'] : 1;
$limit = !empty($get['limit']) ? $get['limit'] : 10;
$title = !empty($get['title']) ? $get['title'] : null;
$this->model = new SystemUploadfile();
$count = $this->model
->where(function (Query $query) use ($title) {
@@ -117,7 +125,7 @@ class Ajax extends AdminController
})
->page($page, $limit)
->order($this->sort)
->select();
->select()->toArray();
$data = [
'code' => 0,
'msg' => '',
@@ -129,14 +137,15 @@ class Ajax extends AdminController
/**
* 百度编辑器上传
* @param Request $request
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function uploadUEditor(): Json
public function uploadUEditor(Request $request): Json
{
$uploadConfig = sysconfig('upload');
$uploadConfig = sysConfig('upload');
$upload_allow_size = $uploadConfig['upload_allow_size'];
$_upload_allow_ext = explode(',', $uploadConfig['upload_allow_ext']);
$upload_allow_ext = [];
@@ -171,8 +180,8 @@ class Ajax extends AdminController
"fileMaxSize" => $upload_allow_size,
"fileAllowFiles" => $upload_allow_ext,
];
$action = $this->request->param('action/s', '');
$file = $this->request->file('file');
$action = $request->param('action/s', '');
$file = $request->file('file');
$upload_type = $uploadConfig['upload_type'];
switch ($action) {
case 'image':

View File

@@ -5,27 +5,24 @@ namespace app\admin\controller;
use app\admin\model\SystemAdmin;
use app\admin\model\SystemQuick;
use app\common\controller\AdminController;
use app\Request;
use Exception;
use think\App;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;
use think\facade\Env;
class Index extends AdminController
{
/**
* 后台主页
* @param Request $request
* @return string
* @throws Exception
*/
public function index(): string
public function index(Request $request): string
{
return $this->fetch('', [
'admin' => session('admin'),
]);
return $this->fetch('', ['admin' => $request->adminUserInfo,]);
}
/**
@@ -50,20 +47,21 @@ class Index extends AdminController
/**
* 修改管理员信息
* @param Request $request
* @return string
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function editAdmin(): string
public function editAdmin(Request $request): string
{
$id = session('admin.id');
$id = $this->adminUid;
$row = (new SystemAdmin())
->withoutField('password')
->find($id);
empty($row) && $this->error('用户信息不存在');
if ($this->request->isPost()) {
$post = $this->request->post();
if ($request->isPost()) {
$post = $request->post();
$this->isDemo && $this->error('演示环境下不允许修改');
$rule = [];
$this->validate($post, $rule);
@@ -71,7 +69,7 @@ class Index extends AdminController
$save = $row
->allowField(['head_img', 'phone', 'remark', 'update_time'])
->save($post);
} catch (Exception $e) {
}catch (Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
@@ -82,22 +80,23 @@ class Index extends AdminController
/**
* 修改密码
* @param Request $request
* @return string
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function editPassword(): string
public function editPassword(Request $request): string
{
$id = session('admin.id');
$id = $this->adminUid;
$row = (new SystemAdmin())
->withoutField('password')
->find($id);
if (!$row) {
$this->error('用户信息不存在');
}
if ($this->request->isPost()) {
$post = $this->request->post();
if ($request->isPost()) {
$post = $request->post();
$this->isDemo && $this->error('演示环境下不允许修改');
$rule = [
'password|登录密码' => 'require',
@@ -110,14 +109,14 @@ class Index extends AdminController
try {
$save = $row->save([
'password' => password($post['password']),
]);
} catch (Exception $e) {
'password' => password($post['password']),
]);
}catch (Exception $e) {
$this->error('保存失败');
}
if ($save) {
$this->success('保存成功');
} else {
}else {
$this->error('保存失败');
}
}

View File

@@ -5,73 +5,70 @@ namespace app\admin\controller;
use app\admin\model\SystemAdmin;
use app\common\controller\AdminController;
use think\captcha\facade\Captcha;
use think\facade\Env;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use app\Request;
use think\Response;
/**
* Class Login
* @package app\admin\controller
*/
class Login extends AdminController
{
/**
* 初始化方法
*/
public function initialize()
protected bool $ignoreAuth = true;
public function initialize(): void
{
parent::initialize();
$action = $this->request->action();
if (!empty(session('admin')) && !in_array($action, ['out'])) {
$adminModuleName = config('app.admin_alias_name');
if (!empty($this->adminUid) && !in_array($action, ['out'])) {
$adminModuleName = config('admin.alias_name');
$this->success('已登录,无需再次登录', [], __url("@{$adminModuleName}"));
}
}
/**
* 用户登录
* @param Request $request
* @return string
* @throws \Exception
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function index(): string
public function index(Request $request): string
{
$captcha = Env::get('EASYADMIN.CAPTCHA', 1);
if ($this->request->isPost()) {
$post = $this->request->post();
$rule = [
'username|用户名' => 'require',
'password|密码' => 'require',
'keep_login|是否保持登录' => 'require',
];
$captcha == 1 && $rule['captcha|验证码'] = 'require|captcha';
$this->validate($post, $rule);
$admin = SystemAdmin::where(['username' => $post['username']])->find();
if (empty($admin)) {
$this->error('用户不存在');
}
if (password($post['password']) != $admin->password) {
$this->error('密码输入有误');
}
if ($admin->status == 0) {
$this->error('账号已被禁用');
}
$admin->login_num += 1;
$admin->save();
$admin = $admin->toArray();
unset($admin['password']);
$admin['expire_time'] = $post['keep_login'] == 1 ? true : time() + 7200;
session('admin', $admin);
$this->success('登录成功');
$captcha = env('EASYADMIN.CAPTCHA', 1);
if (!$request->isPost()) return $this->fetch('', compact('captcha'));
$post = $request->post();
$rule = [
'username|用户名' => 'require',
'password|密码' => 'require',
'keep_login|是否保持登录' => 'require',
];
$captcha == 1 && $rule['captcha|验证码'] = 'require|captcha';
$this->validate($post, $rule);
$admin = SystemAdmin::where(['username' => $post['username']])->find();
if (empty($admin)) {
$this->error('用户不存在');
}
$this->assign('captcha', $captcha);
$this->assign('demo', $this->isDemo);
return $this->fetch();
if (password($post['password']) != $admin->password) {
$this->error('密码输入有误');
}
if ($admin->status == 0) {
$this->error('账号已被禁用');
}
$admin->login_num += 1;
$admin->save();
$admin = $admin->toArray();
unset($admin['password']);
$admin['expire_time'] = $post['keep_login'] == 1 ? true : time() + 7200;
session('admin', $admin);
$this->success('登录成功');
}
/**
* 用户退出
*/
public function out()
public function out(): void
{
session('admin', null);
$this->success('退出登录成功');
@@ -83,6 +80,6 @@ class Login extends AdminController
*/
public function captcha(): Response
{
return Captcha::create();
return Captcha::instance()->create();
}
}

View File

@@ -3,7 +3,6 @@
namespace app\admin\controller\mall;
use app\admin\model\MallCate;
use app\admin\traits\Curd;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
@@ -17,8 +16,6 @@ use think\App;
class Cate extends AdminController
{
use Curd;
public function __construct(App $app)
{
parent::__construct($app);

View File

@@ -2,12 +2,15 @@
namespace app\admin\controller\mall;
use app\admin\model\MallCate;
use app\admin\model\MallGoods;
use app\admin\traits\Curd;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\Request;
use think\App;
use think\db\exception\DbException;
use think\response\Json;
/**
* Class Goods
@@ -17,36 +20,24 @@ use think\App;
class Goods extends AdminController
{
use Curd;
protected bool $relationSearch = true;
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new MallGoods();
$this->assign('cate', (new MallCate())->column('title', 'id'));
}
/**
* @NodeAnnotation(title="列表")
* @throws DbException
*/
public function index()
public function index(Request $request): Json|string
{
if ($this->request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
if ($request->isAjax()) {
if (input('selectFields')) return $this->selectList();
list($page, $limit, $where) = $this->buildTableParams();
$count = $this->model
->withJoin('cate', 'LEFT')
->where($where)
->count();
$list = $this->model
->withJoin('cate', 'LEFT')
->where($where)
->page($page, $limit)
->order($this->sort)
->select();
$count = $this->model->where($where)->count();
$list = $this->model->with(['cate'])->where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
$data = [
'code' => 0,
'msg' => '',
@@ -61,19 +52,19 @@ class Goods extends AdminController
/**
* @NodeAnnotation(title="入库")
*/
public function stock($id)
public function stock(Request $request, $id): string
{
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isPost()) {
$post = $this->request->post();
if ($request->isPost()) {
$post = $request->post();
$rule = [];
$this->validate($post, $rule);
try {
$post['total_stock'] = $row->total_stock + $post['stock'];
$post['stock'] = $row->stock + $post['stock'];
$save = $row->save($post);
} catch (\Exception $e) {
}catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');

View File

@@ -8,7 +8,10 @@ use app\common\constants\AdminConstant;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\Request;
use think\App;
use think\db\exception\DbException;
use think\response\Json;
/**
* Class Admin
@@ -18,8 +21,6 @@ use think\App;
class Admin extends AdminController
{
use \app\admin\traits\Curd;
protected array $sort = [
'sort' => 'desc',
'id' => 'desc',
@@ -34,10 +35,11 @@ class Admin extends AdminController
/**
* @NodeAnnotation(title="列表")
* @throws DbException
*/
public function index()
public function index(Request $request): Json|string
{
if ($this->request->isAjax()) {
if ($request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
@@ -50,7 +52,7 @@ class Admin extends AdminController
->where($where)
->page($page, $limit)
->order($this->sort)
->select();
->select()->toArray();
$data = [
'code' => 0,
'msg' => '',
@@ -65,11 +67,11 @@ class Admin extends AdminController
/**
* @NodeAnnotation(title="添加")
*/
public function add()
public function add(Request $request): string
{
if ($this->request->isPost()) {
$post = $this->request->post();
$authIds = $this->request->post('auth_ids', []);
if ($request->isPost()) {
$post = $request->post();
$authIds = $request->post('auth_ids', []);
$post['auth_ids'] = implode(',', array_keys($authIds));
$rule = [];
$this->validate($post, $rule);
@@ -77,7 +79,7 @@ class Admin extends AdminController
$post['password'] = password($post['password']);
try {
$save = $this->model->save($post);
} catch (\Exception $e) {
}catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
@@ -88,13 +90,13 @@ class Admin extends AdminController
/**
* @NodeAnnotation(title="编辑")
*/
public function edit($id)
public function edit(Request $request, $id = 0): string
{
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isPost()) {
$post = $this->request->post();
$authIds = $this->request->post('auth_ids', []);
if ($request->isPost()) {
$post = $request->post();
$authIds = $request->post('auth_ids', []);
$post['auth_ids'] = implode(',', array_keys($authIds));
$rule = [];
$this->validate($post, $rule);
@@ -104,7 +106,7 @@ class Admin extends AdminController
try {
$save = $row->save($post);
TriggerService::updateMenu($id);
} catch (\Exception $e) {
}catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
@@ -117,12 +119,12 @@ class Admin extends AdminController
/**
* @NodeAnnotation(title="编辑")
*/
public function password($id)
public function password(Request $request, $id): string
{
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isAjax()) {
$post = $this->request->post();
if ($request->isAjax()) {
$post = $request->post();
$rule = [
'password|登录密码' => 'require',
'password_again|确认密码' => 'require',
@@ -133,9 +135,9 @@ class Admin extends AdminController
}
try {
$save = $row->save([
'password' => password($post['password']),
]);
} catch (\Exception $e) {
'password' => password($post['password']),
]);
}catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
@@ -148,7 +150,7 @@ class Admin extends AdminController
/**
* @NodeAnnotation(title="删除")
*/
public function delete($id)
public function delete($id): void
{
$this->checkPostRequest();
$row = $this->model->whereIn('id', $id)->select();
@@ -161,7 +163,7 @@ class Admin extends AdminController
}
try {
$save = $row->delete();
} catch (\Exception $e) {
}catch (\Exception $e) {
$this->error('删除失败');
}
$save ? $this->success('删除成功') : $this->error('删除失败');
@@ -170,14 +172,14 @@ class Admin extends AdminController
/**
* @NodeAnnotation(title="属性修改")
*/
public function modify()
public function modify(Request $request): void
{
$this->checkPostRequest();
$post = $this->request->post();
$post = $request->post();
$rule = [
'id|ID' => 'require',
'id|ID' => 'require',
'field|字段' => 'require',
'value|值' => 'require',
'value|值' => 'require',
];
$this->validate($post, $rule);
if (!in_array($post['field'], $this->allowModifyFields)) {
@@ -190,9 +192,9 @@ class Admin extends AdminController
empty($row) && $this->error('数据不存在');
try {
$row->save([
$post['field'] => $post['value'],
]);
} catch (\Exception $e) {
$post['field'] => $post['value'],
]);
}catch (\Exception $e) {
$this->error($e->getMessage());
}
$this->success('保存成功');

View File

@@ -8,6 +8,7 @@ use app\admin\service\TriggerService;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\Request;
use think\App;
/**
@@ -18,8 +19,6 @@ use think\App;
class Auth extends AdminController
{
use \app\admin\traits\Curd;
protected array $sort = [
'sort' => 'desc',
'id' => 'desc',
@@ -34,11 +33,11 @@ class Auth extends AdminController
/**
* @NodeAnnotation(title="授权")
*/
public function authorize($id)
public function authorize(Request $request, $id): string
{
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isAjax()) {
if ($request->isAjax()) {
$list = $this->model->getAuthorizeNodeListByAdminId($id);
$this->success('获取成功', $list);
}
@@ -49,11 +48,11 @@ class Auth extends AdminController
/**
* @NodeAnnotation(title="授权保存")
*/
public function saveAuthorize()
public function saveAuthorize(Request $request): void
{
$this->checkPostRequest();
$id = $this->request->post('id');
$node = $this->request->post('node', "[]");
$id = $request->post('id');
$node = $request->post('node', "[]");
$node = json_decode($node, true);
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
@@ -71,7 +70,7 @@ class Auth extends AdminController
$authNode->saveAll($saveAll);
}
TriggerService::updateMenu();
} catch (\Exception $e) {
}catch (\Exception $e) {
$this->error('保存失败');
}
$this->success('保存成功');

View File

@@ -7,7 +7,10 @@ use app\admin\service\TriggerService;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\Request;
use think\App;
use think\facade\Cache;
use think\response\Json;
/**
* Class Config
@@ -28,7 +31,7 @@ class Config extends AdminController
/**
* @NodeAnnotation(title="列表")
*/
public function index()
public function index(Request $request): Json|string
{
return $this->fetch();
}
@@ -36,10 +39,10 @@ class Config extends AdminController
/**
* @NodeAnnotation(title="保存")
*/
public function save()
public function save(Request $request): void
{
$this->checkPostRequest();
$post = $this->request->post();
$post = $request->post();
$notAddFields = ['_token', 'file', 'group'];
try {
$group = $post['group'] ?? '';
@@ -53,7 +56,7 @@ class Config extends AdminController
if (in_array($key, $notAddFields)) continue;
if ($this->model->where('name', $key)->count()) {
$this->model->where('name', $key)->update(['value' => $val,]);
} else {
}else {
$this->model->create(
[
'name' => $key,
@@ -63,8 +66,8 @@ class Config extends AdminController
}
}
TriggerService::updateMenu();
TriggerService::updateSysconfig();
} catch (\Exception $e) {
TriggerService::updateSysConfig();
}catch (\Exception $e) {
$this->error('保存失败');
}
$this->success('保存成功');

View File

@@ -10,6 +10,7 @@ use app\admin\service\annotation\NodeAnnotation;
use app\Request;
use think\db\exception\PDOException;
use think\exception\FileException;
use think\facade\Console;
use think\facade\Db;
use think\helper\Str;
use think\response\Json;
@@ -23,7 +24,7 @@ class CurdGenerate extends AdminController
/**
* @NodeAnnotation(title="列表")
*/
public function index()
public function index(Request $request): Json|string
{
return $this->fetch();
}
@@ -35,11 +36,12 @@ class CurdGenerate extends AdminController
public function save(Request $request, string $type = ''): ?Json
{
if (!$request->isAjax()) $this->error();
$tb_prefix = $request->param('tb_prefix/s', '');
$tb_name = $request->param('tb_name/s', '');
if (empty($tb_name)) $this->error('参数错误');
switch ($type) {
case "search":
$tb_prefix = $request->param('tb_prefix/s', '');
$tb_name = $request->param('tb_name/s', '');
if (empty($tb_name)) $this->error('参数错误');
try {
$list = Db::query("SHOW FULL COLUMNS FROM {$tb_prefix}{$tb_name}");
$data = [];
@@ -59,10 +61,53 @@ class CurdGenerate extends AdminController
}
break;
case "add":
$force = $request->post('force/d', 0);
$tb_prefix = $request->param('tb_prefix/s', '');
$tb_name = $request->param('tb_name/s', '');
if (empty($tb_name)) $this->error('参数错误');
$tb_fields = $request->param('tb_fields');
$force = $request->post('force/d', 0);
try {
$build = (new BuildCurd())->setTablePrefix($tb_prefix)->setTable($tb_name);
$build->setForce($force); // 强制覆盖
// 新增字段类型
if ($tb_fields) {
foreach ($tb_fields as $tk => $tf) {
if (empty($tf)) continue;
$tf = array_values($tf);
switch ($tk) {
case 'ignore':
$build->setIgnoreFields($tf, true);
break;
case 'select':
$build->setSelectFields($tf, true);
break;
case 'radio':
$build->setRadioFieldSuffix($tf, true);
break;
case 'checkbox':
$build->setCheckboxFieldSuffix($tf, true);
break;
case 'image':
$build->setImageFieldSuffix($tf, true);
break;
case 'images':
$build->setImagesFieldSuffix($tf, true);
break;
case 'date':
$build->setDateFieldSuffix($tf, true);
break;
case 'datetime':
$build->setDatetimeFieldSuffix($tf, true);
break;
case 'editor':
$build->setEditorFields($tf, true);
break;
default:
break;
}
}
}
$build = $build->render();
$fileList = $build->getFileList();
if (empty($fileList)) $this->error('这里什么都没有');
@@ -74,7 +119,7 @@ class CurdGenerate extends AdminController
$_fileExp_last = array_slice($_fileExp, -2);
$_fileExp_last_0 = $_fileExp_last[0] . '.';
if ($_fileExp_last[0] == 'controller') $_fileExp_last_0 = '';
$link = '/' . env('EASYADMIN.ADMIN', 'admin') . '/' . $_fileExp_last_0 . Str::snake(explode('.php', end($_fileExp_last))[0] ?? '') . '/index';
$link = '/' . config('admin.alias_name') . '/' . $_fileExp_last_0 . Str::snake(explode('.php', end($_fileExp_last))[0] ?? '') . '/index';
}
$this->success('生成成功', compact('result', 'link'));
}catch (FileException $exception) {
@@ -82,6 +127,10 @@ class CurdGenerate extends AdminController
}
break;
case "delete":
$tb_prefix = $request->param('tb_prefix/s', '');
$tb_name = $request->param('tb_name/s', '');
if (empty($tb_name)) $this->error('参数错误');
try {
$build = (new BuildCurd())->setTablePrefix($tb_prefix)->setTable($tb_name);
$build = $build->render();
@@ -93,6 +142,19 @@ class CurdGenerate extends AdminController
return json(['code' => -1, 'msg' => $exception->getMessage()]);
}
break;
case 'console':
$command = $request->post('command', '');
if (empty($command)) $this->error('请输入命令');
$commandExp = explode(' ', $command);
try {
$output = Console::call('curd', [...$commandExp]);
}catch (\Throwable $exception) {
$this->error($exception->getMessage() . $exception->getLine());
}
if (empty($output)) $this->error('设置错误');
$this->success($output->fetch());
break;
default:
$this->error('参数错误');
break;

View File

@@ -4,15 +4,16 @@ namespace app\admin\controller\system;
use app\admin\model\SystemLog;
use app\admin\service\tool\CommonTool;
use app\admin\traits\Curd;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\Request;
use jianyan\excel\Excel;
use think\App;
use think\db\exception\DbException;
use think\db\exception\PDOException;
use think\facade\Db;
use think\response\Json;
/**
* @ControllerAnnotation(title="操作日志管理")
@@ -21,7 +22,6 @@ use think\facade\Db;
*/
class Log extends AdminController
{
use Curd;
public function __construct(App $app)
{
@@ -32,9 +32,9 @@ class Log extends AdminController
/**
* @NodeAnnotation(title="列表")
*/
public function index()
public function index(Request $request): Json|string
{
if ($this->request->isAjax()) {
if ($request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
@@ -44,7 +44,7 @@ class Log extends AdminController
try {
$count = $model->count();
$list = $model->page($page, $limit)->order($this->sort)->select();
} catch (PDOException|DbException $exception) {
}catch (PDOException|DbException $exception) {
$count = 0;
$list = [];
}
@@ -62,7 +62,7 @@ class Log extends AdminController
/**
* @NodeAnnotation(title="导出")
*/
public function export()
public function export(): bool
{
if (env('EASYADMIN.IS_DEMO', false)) {
$this->error('演示环境下不允许操作');
@@ -88,11 +88,19 @@ class Log extends AdminController
->order('id', 'desc')
->select()
->toArray();
} catch (PDOException|DbException $exception) {
}catch (PDOException|DbException $exception) {
$this->error($exception->getMessage());
}
$fileName = time();
return Excel::exportData($list, $header, $fileName, 'xlsx');
}
/**
* @NodeAnnotation(title="框架日志")
*/
public function record(): string
{
return (new \Wolfcode\PhpLogviewer\thinkphp\LogViewer())->fetch();
}
}

View File

@@ -5,12 +5,14 @@ namespace app\admin\controller\system;
use app\admin\model\SystemMenu;
use app\admin\model\SystemNode;
use app\admin\service\TriggerService;
use app\admin\traits\Curd;
use app\common\constants\MenuConstant;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\common\controller\AdminController;
use app\Request;
use think\App;
use think\db\exception\DbException;
use think\response\Json;
/**
* Class Menu
@@ -20,8 +22,6 @@ use think\App;
class Menu extends AdminController
{
use Curd;
protected array $sort = [
'sort' => 'desc',
'id' => 'asc',
@@ -35,15 +35,16 @@ class Menu extends AdminController
/**
* @NodeAnnotation(title="列表")
* @throws DbException
*/
public function index()
public function index(Request $request): Json|string
{
if ($this->request->isAjax()) {
if ($request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
$count = $this->model->count();
$list = $this->model->order($this->sort)->select();
$list = $this->model->order($this->sort)->select()->toArray();
$data = [
'code' => 0,
'msg' => '',
@@ -58,14 +59,15 @@ class Menu extends AdminController
/**
* @NodeAnnotation(title="添加")
*/
public function add($id = null)
public function add(Request $request): string
{
$id = $request->param('id');
$homeId = $this->model->where(['pid' => MenuConstant::HOME_PID,])->value('id');
if ($id == $homeId) {
$this->error('首页不能添加子菜单');
}
if ($this->request->isPost()) {
$post = $this->request->post();
if ($request->isPost()) {
$post = $request->post();
$rule = [
'pid|上级菜单' => 'require',
'title|菜单名称' => 'require',
@@ -74,13 +76,13 @@ class Menu extends AdminController
$this->validate($post, $rule);
try {
$save = $this->model->save($post);
} catch (\Exception $e) {
}catch (\Exception $e) {
$this->error('保存失败');
}
if ($save) {
TriggerService::updateMenu();
$this->success('保存成功');
} else {
}else {
$this->error('保存失败');
}
}
@@ -93,12 +95,12 @@ class Menu extends AdminController
/**
* @NodeAnnotation(title="编辑")
*/
public function edit($id)
public function edit(Request $request, $id = 0): string
{
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isPost()) {
$post = $this->request->post();
if ($request->isPost()) {
$post = $request->post();
$rule = [
'pid|上级菜单' => 'require',
'title|菜单名称' => 'require',
@@ -108,42 +110,42 @@ class Menu extends AdminController
if ($row->pid == MenuConstant::HOME_PID) $post['pid'] = MenuConstant::HOME_PID;
try {
$save = $row->save($post);
} catch (\Exception $e) {
}catch (\Exception $e) {
$this->error('保存失败');
}
if (!empty($save)) {
TriggerService::updateMenu();
$this->success('保存成功');
} else {
}else {
$this->error('保存失败');
}
}
$pidMenuList = $this->model->getPidMenuList();
$this->assign([
'id' => $id,
'pidMenuList' => $pidMenuList,
'row' => $row,
]);
'id' => $id,
'pidMenuList' => $pidMenuList,
'row' => $row,
]);
return $this->fetch();
}
/**
* @NodeAnnotation(title="删除")
*/
public function delete($id)
public function delete($id): void
{
$this->checkPostRequest();
$row = $this->model->whereIn('id', $id)->select();
empty($row) && $this->error('数据不存在');
try {
$save = $row->delete();
} catch (\Exception $e) {
}catch (\Exception $e) {
$this->error('删除失败');
}
if ($save) {
TriggerService::updateMenu();
$this->success('删除成功');
} else {
}else {
$this->error('删除失败');
}
}
@@ -151,14 +153,14 @@ class Menu extends AdminController
/**
* @NodeAnnotation(title="属性修改")
*/
public function modify()
public function modify(Request $request): void
{
$this->checkPostRequest();
$post = $this->request->post();
$post = $request->post();
$rule = [
'id|ID' => 'require',
'id|ID' => 'require',
'field|字段' => 'require',
'value|值' => 'require',
'value|值' => 'require',
];
$this->validate($post, $rule);
$row = $this->model->find($post['id']);
@@ -170,17 +172,17 @@ class Menu extends AdminController
}
$homeId = $this->model
->where([
'pid' => MenuConstant::HOME_PID,
])
'pid' => MenuConstant::HOME_PID,
])
->value('id');
if ($post['id'] == $homeId && $post['field'] == 'status') {
$this->error('首页状态不允许关闭');
}
try {
$row->save([
$post['field'] => $post['value'],
]);
} catch (\Exception $e) {
$post['field'] => $post['value'],
]);
}catch (\Exception $e) {
$this->error($e->getMessage());
}
TriggerService::updateMenu();
@@ -190,18 +192,18 @@ class Menu extends AdminController
/**
* @NodeAnnotation(title="添加菜单提示")
*/
public function getMenuTips()
public function getMenuTips(): Json
{
$node = input('get.keywords');
$list = SystemNode::whereLike('node', "%{$node}%")
->field('node,title')
->limit(10)
->select();
->select()->toArray();
return json([
'code' => 0,
'content' => $list,
'type' => 'success',
]);
'code' => 0,
'content' => $list,
'type' => 'success',
]);
}
}

View File

@@ -8,7 +8,10 @@ use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\admin\service\NodeService;
use app\Request;
use think\App;
use think\db\exception\DbException;
use think\response\Json;
/**
* @ControllerAnnotation(title="系统节点管理")
@@ -18,8 +21,6 @@ use think\App;
class Node extends AdminController
{
use \app\admin\traits\Curd;
public function __construct(App $app)
{
parent::__construct($app);
@@ -28,10 +29,11 @@ class Node extends AdminController
/**
* @NodeAnnotation(title="列表")
* @throws DbException
*/
public function index()
public function index(Request $request): Json|string
{
if ($this->request->isAjax()) {
if ($request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
@@ -86,7 +88,7 @@ class Node extends AdminController
}
$model->saveAll($nodeList);
TriggerService::updateNode();
} catch (\Exception $e) {
}catch (\Exception $e) {
$this->error('节点更新失败');
}
$this->success('节点更新成功');
@@ -107,7 +109,7 @@ class Node extends AdminController
!isset($formatNodeList[$vo['node']]) && $model->where('id', $vo['id'])->delete();
}
TriggerService::updateNode();
} catch (\Exception $e) {
}catch (\Exception $e) {
$this->error('节点更新失败');
}
$this->success('节点更新成功');

View File

@@ -17,8 +17,6 @@ use think\App;
class Quick extends AdminController
{
use \app\admin\traits\Curd;
protected array $sort = [
'sort' => 'desc',
'id' => 'desc',

View File

@@ -10,14 +10,11 @@ use think\App;
/**
* @ControllerAnnotation(title="上传文件管理")
* Class Uploadfile
* @package app\admin\controller\system
*/
class Uploadfile extends AdminController
{
use \app\admin\traits\Curd;
public function __construct(App $app)
{
parent::__construct($app);

View File

@@ -1,21 +0,0 @@
<?php
// 事件定义文件
return [
'bind' => [
],
'listen' => [
'AppInit' => [
\app\admin\listener\ViewInitListener::class,
],
'HttpRun' => [
\app\admin\listener\ViewInitListener::class,
],
'HttpEnd' => [],
'LogLevel' => [],
'LogWrite' => [],
],
'subscribe' => [
],
];

View File

@@ -1,23 +1,5 @@
<?php
// 全局中间件定义文件
return [
// Session初始化
\think\middleware\SessionInit::class,
// 系统操作日志
\app\admin\middleware\SystemLog::class,
// Csrf安全校验
\app\admin\middleware\CsrfMiddleware::class,
// 后台视图初始化
// \app\admin\middleware\ViewInit::class,
// 检测用户是否登录
// \app\admin\middleware\CheckAdmin::class,
// 检测是否已经安装程序
\app\admin\middleware\CheckInstall::class,
// ...
];

View File

@@ -1,57 +0,0 @@
<?php
namespace app\admin\middleware;
use app\common\service\AuthService;
use think\Request;
/**
* @deprecated 废弃新版TP不支持在中间件获取控制器相关信息
* 检测用户登录和节点权限
* Class CheckAdmin
* @package app\admin\middleware
*/
class CheckAdmin
{
use \app\common\traits\JumpTrait;
public function handle(Request $request, \Closure $next)
{
$adminConfig = config('admin');
$adminId = session('admin.id');
$expireTime = session('admin.expire_time');
/** @var AuthService $authService */
$authService = app(AuthService::class, ['adminId' => $adminId]);
$currentNode = $authService->getCurrentNode();
$currentController = parse_name($request->controller());
// 验证登录
if (!in_array($currentController, $adminConfig['no_login_controller']) &&
!in_array($currentNode, $adminConfig['no_login_node'])) {
empty($adminId) && $this->error('请先登录后台', [], __url('admin/login/index'));
// 判断是否登录过期
if ($expireTime !== true && time() > $expireTime) {
session('admin', null);
$this->error('登录已过期,请重新登录', [], __url('admin/login/index'));
}
}
// 验证权限
if (!in_array($currentController, $adminConfig['no_auth_controller']) &&
!in_array($currentNode, $adminConfig['no_auth_node'])) {
$check = $authService->checkNode($currentNode);
!$check && $this->error('无权限访问');
// 判断是否为演示环境
if(env('EASYADMIN.IS_DEMO', false) && $request->isPost()){
$this->error('演示环境下不允许修改');
}
}
return $next($request);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace app\admin\middleware;
use app\common\service\AuthService;
use app\common\traits\JumpTrait;
use app\Request;
use Closure;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
class CheckAuth
{
use JumpTrait;
/**
* @throws ModelNotFoundException
* @throws DbException
* @throws DataNotFoundException
*/
public function handle(Request $request, Closure $next)
{
$adminUserInfo = $request->adminUserInfo;
if (empty($adminUserInfo)) return $next($request);
$adminConfig = config('admin');
$adminId = $adminUserInfo['id'];
$authService = app(AuthService::class, ['adminId' => $adminId]);
$currentNode = $authService->getCurrentNode();
$currentController = parse_name($request->controller());
if (!in_array($currentController, $adminConfig['no_auth_controller']) && !in_array($currentNode, $adminConfig['no_auth_node'])) {
$check = $authService->checkNode($currentNode);
!$check && $this->error('无权限访问');
// 判断是否为演示环境
if (env('EASYADMIN.IS_DEMO', false) && $request->isPost()) {
if (!in_array($currentNode, ['system.log/record', ''])) $this->error('演示环境下不允许修改');
}
}
return $next($request);
}
}

View File

@@ -2,18 +2,18 @@
namespace app\admin\middleware;
use app\common\traits\JumpTrait;
use app\Request;
use Closure;
/**
* 检测是否安装成功
* 系统安装后可以在 config/route 中删除该中间件判定
*/
class CheckInstall
{
public function handle(Request $request, \Closure $next)
use JumpTrait;
public function handle(Request $request, Closure $next)
{
$controller = $request->controller();
if (!is_file(ROOT_PATH . 'config' . DS . 'install' . DS . 'lock' . DS . 'install.lock')) {
if (!is_file(root_path() . 'config' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'lock' . DIRECTORY_SEPARATOR . 'install.lock')) {
if ($controller != 'Install') return redirect('/install');
}
return $next($request);

View File

@@ -0,0 +1,47 @@
<?php
namespace app\admin\middleware;
use app\common\traits\JumpTrait;
use app\Request;
use Closure;
use ReflectionClass;
use ReflectionException;
class CheckLogin
{
use JumpTrait;
/**
* @throws ReflectionException
*/
public function handle(Request $request, Closure $next)
{
$controller = $request->controller();
if (empty($controller)) return $next($request);
if (str_contains($controller, '.')) $controller = str_replace('.', '\\', $controller);
$action = $request->action();
$controllerClass = 'app\\admin\\controller\\' . $controller;
$classObj = new ReflectionClass($controllerClass);
$properties = $classObj->getDefaultProperties();
$ignoreAuth = $properties['ignoreAuth'] ?? false;
$adminUserInfo = session('admin');
if (!$ignoreAuth) {
$noNeedCheck = $properties['noNeedCheck'] ?? [];
if (in_array($action, $noNeedCheck)) {
return $next($request);
}
if (empty($adminUserInfo)) {
return redirect(__url('login/index'));
}
// 判断是否登录过期
$expireTime = $adminUserInfo['expire_time'];
if ($expireTime !== true && time() > $expireTime) {
session('admin', null);
$this->error('登录已过期,请重新登录', [], __url(env('EASYADMIN.ADMIN') . '/login/index'));
}
}
$request->adminUserInfo = $adminUserInfo ?: [];
return $next($request);
}
}

View File

@@ -1,40 +0,0 @@
<?php
namespace app\admin\middleware;
use app\Request;
use CsrfVerify\drive\ThinkphpCache;
use CsrfVerify\entity\CsrfVerifyEntity;
use CsrfVerify\interfaces\CsrfVerifyInterface;
use think\facade\Session;
class CsrfMiddleware
{
use \app\common\traits\JumpTrait;
public function handle(Request $request, \Closure $next)
{
if (env('EASYADMIN.IS_CSRF', true)) {
if (in_array($request->method(), ['POST', 'DELETE'])) {
// 跨域校验
$refererUrl = $request->header('REFERER', null);
$refererInfo = parse_url($refererUrl);
$host = $request->host(true);
if (!isset($refererInfo['host']) || $refererInfo['host'] != $host) {
$this->error('当前请求不合法!');
}
// CSRF校验
// @todo 兼容CK编辑器上传功能
$ckCsrfToken = $request->post('ckCsrfToken');
$data = !empty($ckCsrfToken) ? ['__token__' => $ckCsrfToken] : [];
$check = $request->checkToken('__token__', $data);
if (!$check) {
$this->error('请求验证失败,请重新刷新页面!');
}
}
}
return $next($request);
}
}

View File

@@ -5,36 +5,31 @@ namespace app\admin\middleware;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\admin\service\SystemLogService;
use app\common\traits\JumpTrait;
use app\Request;
use app\admin\service\tool\CommonTool;
use Closure;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\DocParser;
/**
* 系统操作日志中间件
* Class SystemLog
* @package app\admin\middleware
*/
class SystemLog
{
use JumpTrait;
/**
* 敏感信息字段,日志记录时需要加密
* @var array
*/
protected $sensitiveParams = [
protected array $sensitiveParams = [
'password',
'password_again',
'phone',
'mobile',
];
public function handle(Request $request, \Closure $next)
public function handle(Request $request, Closure $next)
{
$params = $request->param();
if (isset($params['s'])) {
unset($params['s']);
}
if (isset($params['s'])) unset($params['s']);
foreach ($params as $key => $val) {
in_array($key, $this->sensitiveParams) && $params[$key] = "***********";
}
@@ -44,7 +39,7 @@ class SystemLog
if (env('APP_DEBUG')) {
trace(['url' => $url, 'method' => $method, 'params' => $params,], 'requestDebugInfo');
}
$response = $next($request);
if ($request->isAjax()) {
if (in_array($method, ['post', 'put', 'delete'])) {
$title = '';
@@ -66,9 +61,14 @@ class SystemLog
$nodeAnnotation = $reader->getMethodAnnotation($reflectionAction, NodeAnnotation::class);
$title = $controllerAnnotation->title . ' - ' . $nodeAnnotation->title;
}
} catch (\Throwable $exception) {
}catch (\Throwable $exception) {
}
$ip = CommonTool::getRealIp();
$ip = $request->ip();
// 限制记录的响应内容,避免过大
$_response = json_encode($response->getData(), JSON_UNESCAPED_UNICODE);
$_response = mb_substr($_response, 0, 3000, 'utf-8');
$data = [
'admin_id' => session('admin.id'),
'title' => $title,
@@ -76,13 +76,13 @@ class SystemLog
'method' => $method,
'ip' => $ip,
'content' => json_encode($params, JSON_UNESCAPED_UNICODE),
'useragent' => $_SERVER['HTTP_USER_AGENT'],
'response' => $_response,
'useragent' => $request->server('HTTP_USER_AGENT'),
'create_time' => time(),
];
SystemLogService::instance()->save($data);
}
}
return $next($request);
return $response;
}
}

View File

@@ -1,47 +0,0 @@
<?php
namespace app\admin\middleware;
use app\admin\service\ConfigService;
use app\common\constants\AdminConstant;
use think\App;
use think\facade\Request;
use think\facade\View;
/**
* @deprecated 废弃新版TP不支持在中间件获取控制器相关信息
* Class ViewInit
* @package app\admin\middleware
*/
class ViewInit
{
public function handle(\app\Request $request, \Closure $next)
{
list($thisModule, $thisController, $thisAction) = [app('http')->getName(), Request::controller(), $request->action()];
list($thisControllerArr, $jsPath) = [explode('.', $thisController), null];
foreach ($thisControllerArr as $vo) {
empty($jsPath) ? $jsPath = parse_name($vo) : $jsPath .= '/' . parse_name($vo);
}
$autoloadJs = file_exists(root_path('public')."static/{$thisModule}/js/{$jsPath}.js") ? true : false;
$thisControllerJsPath = "{$thisModule}/js/{$jsPath}.js";
$adminModuleName = config('app.admin_alias_name');
$isSuperAdmin = session('admin.id') == AdminConstant::SUPER_ADMIN_ID ? true : false;
$data = [
'adminModuleName' => $adminModuleName,
'thisController' => parse_name($thisController),
'thisAction' => $thisAction,
'thisRequest' => parse_name("{$thisModule}/{$thisController}/{$thisAction}"),
'thisControllerJsPath' => "{$thisControllerJsPath}",
'autoloadJs' => $autoloadJs,
'isSuperAdmin' => $isSuperAdmin,
'version' => env('APP_DEBUG') ? time() : ConfigService::getVersion(),
];
View::assign($data);
$request->adminModuleName = $adminModuleName;
return $next($request);
}
}

View File

@@ -2,8 +2,9 @@
namespace app\admin\model;
use app\common\model\TimeModel;
use think\model\relation\BelongsTo;
use think\model\relation\HasOne;
class MallGoods extends TimeModel
{
@@ -12,9 +13,18 @@ class MallGoods extends TimeModel
protected $deleteTime = 'delete_time';
public function cate()
// * +++++++++++++++++++++++++++
// | 以下两种写法适用于 with 关联
// * +++++++++++++++++++++++++
// public function cate(): BelongsTo
// {
// return $this->belongsTo('app\admin\model\MallCate', 'cate_id', 'id');
// }
public function cate(): HasOne
{
return $this->belongsTo('app\admin\model\MallCate', 'cate_id', 'id');
return $this->hasOne(MallCate::class, 'id', 'cate_id');
}
}

View File

@@ -11,7 +11,7 @@ class ConfigService
{
$version = cache('version');
if (empty($version)) {
$version = sysconfig('site', 'site_version');
$version = sysConfig('site', 'site_version');
cache('site_version', $version);
Cache::set('version', $version, 3600);
}

View File

@@ -15,29 +15,25 @@ use think\facade\Env;
class SystemLogService
{
/**
* 当前实例
* @var object
*/
protected static $instance;
protected static ?SystemLogService $instance = null;
/**
* 表前缀
* @var string
*/
protected $tablePrefix;
protected string $tablePrefix;
/**
* 表后缀
* @var string
*/
protected $tableSuffix;
protected string $tableSuffix;
/**
* 表名
* @var string
*/
protected $tableName;
protected string $tableName;
/**
* 构造方法
@@ -69,14 +65,14 @@ class SystemLogService
* @param $data
* @return bool|string
*/
public function save($data)
public function save($data): bool|string
{
Db::startTrans();
try {
$this->detectTable();
Db::table($this->tableName)->insert($data);
Db::table($this->tableName)->strict(false)->insert($data);
Db::commit();
} catch (\Exception $e) {
}catch (\Exception $e) {
Db::rollback();
return $e->getMessage();
}
@@ -119,7 +115,8 @@ CREATE TABLE `{$this->tableName}` (
`url` varchar(1500) NOT NULL DEFAULT '' COMMENT '操作页面',
`method` varchar(50) NOT NULL COMMENT '请求方法',
`title` varchar(100) DEFAULT '' COMMENT '日志标题',
`content` text NOT NULL COMMENT '内容',
`content` json NOT NULL COMMENT '请求数据',
`response` json DEFAULT NULL COMMENT '回调数据',
`ip` varchar(50) NOT NULL DEFAULT '' COMMENT 'IP',
`useragent` varchar(255) DEFAULT '' COMMENT 'User-Agent',
`create_time` int(10) DEFAULT NULL COMMENT '操作时间',

View File

@@ -41,9 +41,9 @@ class TriggerService
* 更新系统设置缓存
* @return bool
*/
public static function updateSysconfig()
public static function updateSysConfig(): bool
{
Cache::tag('sysconfig')->clear();
Cache::tag('sysConfig')->clear();
return true;
}

View File

@@ -2,12 +2,14 @@
namespace app\admin\service\auth;
use Doctrine\Common\Annotations\AnnotationException;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Doctrine\Common\Annotations\DocParser;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\admin\service\tool\CommonTool;
use ReflectionException;
/**
* 节点处理类
@@ -20,12 +22,12 @@ class Node
/**
* @var string 当前文件夹
*/
protected $basePath;
protected string $basePath;
/**
* @var string 命名空间前缀
*/
protected $baseNamespace;
protected string $baseNamespace;
/**
* 构造方法
@@ -33,7 +35,7 @@ class Node
* @param string $basePath 读取的文件夹
* @param string $baseNamespace 读取的命名空间前缀
*/
public function __construct($basePath, $baseNamespace)
public function __construct(string $basePath, string $baseNamespace)
{
$this->basePath = $basePath;
$this->baseNamespace = $baseNamespace;
@@ -43,8 +45,8 @@ class Node
/**
* 获取所有节点
* @return array
* @throws \Doctrine\Common\Annotations\AnnotationException
* @throws \ReflectionException
* @throws AnnotationException
* @throws ReflectionException
*/
public function getNodeList(): array
{
@@ -67,9 +69,9 @@ class Node
foreach ($methods as $method) {
// 读取NodeAnnotation的注解
$nodeAnnotation = $reader->getMethodAnnotation($method, NodeAnnotation::class);
if (!empty($nodeAnnotation) && !empty($nodeAnnotation->title)) {
$actionTitle = !empty($nodeAnnotation) && !empty($nodeAnnotation->title) ? $nodeAnnotation->title : null;
$actionAuth = !empty($nodeAnnotation) && !empty($nodeAnnotation->auth) ? $nodeAnnotation->auth : false;
if (!empty($nodeAnnotation)) {
$actionTitle = !empty($nodeAnnotation->title) ? $nodeAnnotation->title : null;
$actionAuth = !empty($nodeAnnotation->auth) ? $nodeAnnotation->auth : false;
$actionList[] = [
'node' => $controllerFormat . '/' . $method->name,
'title' => $actionTitle,
@@ -82,8 +84,8 @@ class Node
if (!empty($actionList)) {
// 读取Controller的注解
$controllerAnnotation = $reader->getClassAnnotation($reflectionClass, ControllerAnnotation::class);
$controllerTitle = !empty($controllerAnnotation) && !empty($controllerAnnotation->title) ? $controllerAnnotation->title : null;
$controllerAuth = !empty($controllerAnnotation) && !empty($controllerAnnotation->auth) ? $controllerAnnotation->auth : false;
$controllerTitle = !empty($controllerAnnotation->title) ? $controllerAnnotation->title : null;
$controllerAuth = !empty($controllerAnnotation->auth) ? $controllerAnnotation->auth : false;
$nodeList[] = [
'node' => $controllerFormat,
'title' => $controllerTitle,
@@ -102,7 +104,7 @@ class Node
* 获取所有控制器
* @return array
*/
public function getControllerList()
public function getControllerList(): array
{
return $this->readControllerFiles($this->basePath);
}
@@ -112,10 +114,10 @@ class Node
* @param $path
* @return array
*/
protected function readControllerFiles($path)
protected function readControllerFiles($path): array
{
list($list, $temp_list, $dirExplode) = [[], scandir($path), explode($this->basePath, $path)];
$middleDir = isset($dirExplode[1]) && !empty($dirExplode[1]) ? str_replace('/', '\\', substr($dirExplode[1], 1)) . "\\" : '';
$middleDir = !empty($dirExplode[1]) ? str_replace('/', '\\', substr($dirExplode[1], 1)) . "\\" : '';
foreach ($temp_list as $file) {
// 排除根目录和没有开启注解的模块
@@ -126,7 +128,7 @@ class Node
// 子文件夹,进行递归
$childFiles = $this->readControllerFiles($path . DIRECTORY_SEPARATOR . $file);
$list = array_merge($childFiles, $list);
} else {
}else {
// 判断是不是控制器
$fileExplodeArray = explode('.', $file);
if (count($fileExplodeArray) != 2 || end($fileExplodeArray) != 'php') {

View File

@@ -5,11 +5,11 @@ namespace app\admin\service\console;
class CliEcho
{
private $foreground_colors = [];
private array $foreground_colors = [];
private $background_colors = [];
private array $background_colors = [];
private static $foregroundColors = [
private static array $foregroundColors = [
'black' => '0;30',
'dark_gray' => '1;30',
'blue' => '0;34',
@@ -42,57 +42,57 @@ class CliEcho
public function __construct()
{
// Set up shell colors
$this->foreground_colors['black'] = '0;30';
$this->foreground_colors['dark_gray'] = '1;30';
$this->foreground_colors['blue'] = '0;34';
$this->foreground_colors['light_blue'] = '1;34';
$this->foreground_colors['green'] = '0;32';
$this->foreground_colors['light_green'] = '1;32';
$this->foreground_colors['cyan'] = '0;36';
$this->foreground_colors['light_cyan'] = '1;36';
$this->foreground_colors['red'] = '0;31';
$this->foreground_colors['light_red'] = '1;31';
$this->foreground_colors['purple'] = '0;35';
$this->foreground_colors['black'] = '0;30';
$this->foreground_colors['dark_gray'] = '1;30';
$this->foreground_colors['blue'] = '0;34';
$this->foreground_colors['light_blue'] = '1;34';
$this->foreground_colors['green'] = '0;32';
$this->foreground_colors['light_green'] = '1;32';
$this->foreground_colors['cyan'] = '0;36';
$this->foreground_colors['light_cyan'] = '1;36';
$this->foreground_colors['red'] = '0;31';
$this->foreground_colors['light_red'] = '1;31';
$this->foreground_colors['purple'] = '0;35';
$this->foreground_colors['light_purple'] = '1;35';
$this->foreground_colors['brown'] = '0;33';
$this->foreground_colors['yellow'] = '1;33';
$this->foreground_colors['light_gray'] = '0;37';
$this->foreground_colors['white'] = '1;37';
$this->background_colors['black'] = '40';
$this->background_colors['red'] = '41';
$this->background_colors['green'] = '42';
$this->background_colors['yellow'] = '43';
$this->background_colors['blue'] = '44';
$this->background_colors['magenta'] = '45';
$this->background_colors['cyan'] = '46';
$this->background_colors['light_gray'] = '47';
$this->foreground_colors['brown'] = '0;33';
$this->foreground_colors['yellow'] = '1;33';
$this->foreground_colors['light_gray'] = '0;37';
$this->foreground_colors['white'] = '1;37';
$this->background_colors['black'] = '40';
$this->background_colors['red'] = '41';
$this->background_colors['green'] = '42';
$this->background_colors['yellow'] = '43';
$this->background_colors['blue'] = '44';
$this->background_colors['magenta'] = '45';
$this->background_colors['cyan'] = '46';
$this->background_colors['light_gray'] = '47';
}
// Returns colored string
public function getColoredString($string, $foreground_color = null, $background_color = null, $new_line = false)
public function getColoredString($string, $foreground_color = null, $background_color = null, $new_line = false): string
{
$colored_string = '';
// Check if given foreground color found
if (isset($this->foreground_colors[$foreground_color])) {
$colored_string .= "\033[".$this->foreground_colors[$foreground_color].'m';
$colored_string .= "\033[" . $this->foreground_colors[$foreground_color] . 'm';
}
// Check if given background color found
if (isset($this->background_colors[$background_color])) {
$colored_string .= "\033[".$this->background_colors[$background_color].'m';
$colored_string .= "\033[" . $this->background_colors[$background_color] . 'm';
}
// Add string and end coloring
$colored_string .= $string."\033[0m";
return $new_line ? $colored_string.PHP_EOL : $colored_string;
$colored_string .= $string . "\033[0m";
return $new_line ? $colored_string . PHP_EOL : $colored_string;
}
// Returns all foreground color names
public function getForegroundColors()
public function getForegroundColors(): array
{
return array_keys($this->foreground_colors);
}
// Returns all background color names
public function getBackgroundColors()
public function getBackgroundColors(): array
{
return array_keys($this->background_colors);
}
@@ -100,25 +100,26 @@ class CliEcho
/**
* 获取带颜色的文字.
*
* @param string $string black|dark_gray|blue|light_blue|green|light_green|cyan|light_cyan|red|light_red|purple|brown|yellow|light_gray|white
* @param string $string black|dark_gray|blue|light_blue|green|light_green|cyan|light_cyan|red|light_red|purple|brown|yellow|light_gray|white
* @param string|null $foregroundColor 前景颜色 black|red|green|yellow|blue|magenta|cyan|light_gray
* @param string|null $backgroundColor 背景颜色 同$foregroundColor
*
* @return string
*/
public static function initColoredString(
$string,
$foregroundColor = null,
$backgroundColor = null
) {
string $string,
?string $foregroundColor = null,
?string $backgroundColor = null
): string
{
$coloredString = '';
if (isset(static::$foregroundColors[$foregroundColor])) {
$coloredString .= "\033[".static::$foregroundColors[$foregroundColor].'m';
$coloredString .= "\033[" . static::$foregroundColors[$foregroundColor] . 'm';
}
if (isset(static::$backgroundColors[$backgroundColor])) {
$coloredString .= "\033[".static::$backgroundColors[$backgroundColor].'m';
$coloredString .= "\033[" . static::$backgroundColors[$backgroundColor] . 'm';
}
$coloredString .= $string."\033[0m";
$coloredString .= $string . "\033[0m";
return $coloredString;
}
@@ -127,9 +128,9 @@ class CliEcho
*
* @param $msg
*/
public static function notice($msg)
public static function notice($msg): void
{
fwrite(STDOUT, self::initColoredString($msg, 'light_gray').PHP_EOL);
fwrite(STDOUT, self::initColoredString($msg, 'light_gray') . PHP_EOL);
}
/**
@@ -137,9 +138,9 @@ class CliEcho
*
* @param $msg
*/
public static function error($msg)
public static function error($msg): void
{
fwrite(STDERR, self::initColoredString($msg, 'white','red').PHP_EOL);
fwrite(STDERR, self::initColoredString($msg, 'white', 'red') . PHP_EOL);
}
/**
@@ -147,9 +148,9 @@ class CliEcho
*
* @param $msg
*/
public static function warn($msg)
public static function warn($msg): void
{
fwrite(STDOUT, self::initColoredString($msg, 'red','yellow').PHP_EOL);
fwrite(STDOUT, self::initColoredString($msg, 'red', 'yellow') . PHP_EOL);
}
/**
@@ -157,9 +158,9 @@ class CliEcho
*
* @param $msg
*/
public static function success($msg)
public static function success($msg): void
{
fwrite(STDOUT, self::initColoredString($msg, 'light_cyan').PHP_EOL);
fwrite(STDOUT, self::initColoredString($msg, 'light_cyan') . PHP_EOL);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -13,15 +13,16 @@ use think\App;
class {{controllerName}} extends AdminController
{
use \app\admin\traits\Curd;
private array $notes;
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new {{modelFilename}}();
{{selectList}}
$this->notes = $notes = $this->model->notes;
$this->assign(compact('notes'));
}
{{indexMethod}}
}

View File

@@ -9,16 +9,8 @@
return $this->selectList();
}
list($page, $limit, $where) = $this->buildTableParams();
$count = $this->model
{{relationIndexMethod}}
->where($where)
->count();
$list = $this->model
{{relationIndexMethod}}
->where($where)
->page($page, $limit)
->order($this->sort)
->select();
$count = $this->model{{relationIndexMethod}}->where($where)->count();
$list = $this->model{{relationIndexMethod}}->where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
$data = [
'code' => 0,
'msg' => '',

View File

@@ -13,7 +13,6 @@ class {{modelName}} extends TimeModel
protected $deleteTime = {{deleteTime}};
{{relationList}}
{{selectList}}
public array $notes = {{selectArrays}};
}

View File

@@ -11,7 +11,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
modify_url: '{{controllerUrl}}/modify',
};
var Controller = {
return {
index: function () {
ea.table.render({
@@ -30,5 +30,4 @@ define(["jquery", "easy-admin"], function ($, ea) {
ea.listen();
},
};
return Controller;
});

View File

@@ -6,6 +6,5 @@
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

View File

@@ -7,4 +7,8 @@
lay-filter="currentTable">
</table>
</div>
</div>
</div>
<script>
{{notesScript}}
</script>

View File

@@ -14,7 +14,7 @@ class CommonTool
{
$str = preg_replace_callback('/([-_]+([a-z]{1}))/i', function ($matches) {
return strtoupper($matches[2]);
}, $str);
}, $str);
return $str;
}
@@ -27,7 +27,7 @@ class CommonTool
{
$str = preg_replace_callback('/([A-Z]{1})/', function ($matches) {
return '_' . strtolower($matches[0]);
}, $str);
}, $str);
return $str;
}
@@ -45,11 +45,11 @@ class CommonTool
break;
}
}
} elseif (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
}elseif (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (isset($_SERVER['HTTP_CF_CONNECTING_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CF_CONNECTING_IP'])) {
}elseif (isset($_SERVER['HTTP_CF_CONNECTING_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CF_CONNECTING_IP'])) {
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
} elseif (isset($_SERVER['HTTP_X_REAL_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_X_REAL_IP'])) {
}elseif (isset($_SERVER['HTTP_X_REAL_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_X_REAL_IP'])) {
$ip = $_SERVER['HTTP_X_REAL_IP'];
}
return $ip;
@@ -70,7 +70,7 @@ class CommonTool
if (is_dir($path . DIRECTORY_SEPARATOR . $file)) {
$childFiles = self::readDirAllFiles($path . DIRECTORY_SEPARATOR . $file, $basePath);
$list = array_merge($childFiles, $list);
} else {
}else {
$filePath = $path . DIRECTORY_SEPARATOR . $file;
$fileName = str_replace($basePath . DIRECTORY_SEPARATOR, '', $filePath);
$list[$fileName] = $filePath;
@@ -95,4 +95,11 @@ class CommonTool
return $string;
}
public static function replaceArrayString(?string $arrayString): string
{
$arrayString = str_replace('array (', '[', $arrayString);
$arrayString = str_replace(')', ']', $arrayString);
return $arrayString;
}
}

View File

@@ -1,122 +0,0 @@
<?php
namespace app\admin\service\upload;
use think\facade\Filesystem;
use think\File;
/**
* 基类
* Class Base
* @package EasyAdmin\upload
*/
class FileBase
{
/**
* 上传配置
* @var array
*/
protected $uploadConfig;
/**
* 上传文件对象
* @var object
*/
protected $file;
/**
* 上传完成的文件路径
* @var string
*/
protected $completeFilePath;
/**
* 上传完成的文件的URL
* @var string
*/
protected $completeFileUrl;
/**
* 保存上传文件的数据表
* @var string
*/
protected $tableName;
/**
* 上传类型
* @var string
*/
protected $uploadType = 'local';
/**
* 设置上传方式
* @param $value
* @return $this
*/
public function setUploadType($value)
{
$this->uploadType = $value;
return $this;
}
/**
* 设置上传配置
* @param $value
* @return $this
*/
public function setUploadConfig($value)
{
$this->uploadConfig = $value;
return $this;
}
/**
* 设置上传配置
* @param $value
* @return $this
*/
public function setFile($value)
{
$this->file = $value;
return $this;
}
/**
* 设置保存文件数据表
* @param $value
* @return $this
*/
public function setTableName($value)
{
$this->tableName = $value;
return $this;
}
/**
* 保存文件
*/
public function save()
{
$this->completeFilePath = Filesystem::disk('public')->putFile('upload', $this->file, 'md5');
$this->completeFileUrl = request()->domain() . '/' . str_replace(DIRECTORY_SEPARATOR, '/', $this->completeFilePath);
}
/**
* 删除保存在本地的文件
* @return bool|string
*/
public function rmLocalSave()
{
try {
$rm = unlink($this->completeFilePath);
} catch (\Exception $e) {
return $e->getMessage();
}
return $rm;
}
}

View File

@@ -1,127 +0,0 @@
<?php
namespace app\admin\service\upload;
use app\admin\service\upload\driver\Alioss;
use app\admin\service\upload\driver\Qnoss;
use app\admin\service\upload\driver\Txcos;
use app\admin\service\upload\driver\Local;
use think\File;
/**
* 上传组件
* Class Uploadfile
* @package EasyAdmin\upload
*/
class Uploadfile
{
/**
* 当前实例对象
* @var object
*/
protected static $instance;
/**
* 上传方式
* @var string
*/
protected $uploadType = 'local';
/**
* 上传配置文件
* @var array
*/
protected $uploadConfig;
/**
* 需要上传的文件对象
* @var File
*/
protected $file;
/**
* 保存上传文件的数据表
* @var string
*/
protected $tableName = 'system_uploadfile';
/**
* 获取对象实例
* @return Uploadfile|object
*/
public static function instance()
{
if (is_null(self::$instance)) {
self::$instance = new static();
}
return self::$instance;
}
/**
* 设置上传对象
* @param $value
* @return $this
*/
public function setFile($value)
{
$this->file = $value;
return $this;
}
/**
* 设置上传文件
* @param $value
* @return $this
*/
public function setUploadConfig($value)
{
$this->uploadConfig = $value;
return $this;
}
/**
* 设置上传方式
* @param $value
* @return $this
*/
public function setUploadType($value)
{
$this->uploadType = $value;
return $this;
}
/**
* 设置保存数据表
* @param $value
* @return $this
*/
public function setTableName($value)
{
$this->tableName = $value;
return $this;
}
/**
* 保存文件
* @return array|void
*/
public function save()
{
$obj = null;
if ($this->uploadType == 'local') {
$obj = new Local();
} elseif ($this->uploadType == 'oss') {
$obj = new Alioss();
} elseif ($this->uploadType == 'cos') {
$obj = new Txcos();
}
$save = $obj->setUploadConfig($this->uploadConfig)
->setUploadType($this->uploadType)
->setTableName($this->tableName)
->setFile($this->file)
->save();
return $save;
}
}

View File

@@ -1,42 +0,0 @@
<?php
namespace app\admin\service\upload\driver;
use app\admin\service\upload\FileBase;
use app\admin\service\upload\trigger\SaveDb;
use app\admin\service\upload\driver\alioss\Oss;
/**
* 阿里云上传
* Class Alioss
* @package EasyAdmin\upload\driver
*/
class Alioss extends FileBase
{
/**
* 重写上传方法
* @return array|void
*/
public function save()
{
parent::save();
$upload = Oss::instance($this->uploadConfig)
->save($this->completeFilePath, $this->completeFilePath);
if ($upload['save'] == true) {
SaveDb::trigger($this->tableName, [
'upload_type' => $this->uploadType,
'original_name' => $this->file->getOriginalName(),
'mime_type' => $this->file->getOriginalMime(),
'file_ext' => strtolower($this->file->getOriginalExtension()),
'url' => $upload['url'],
'create_time' => time(),
]);
}
$this->rmLocalSave();
return $upload;
}
}

View File

@@ -1,45 +0,0 @@
<?php
namespace app\admin\service\upload\driver;
use app\admin\service\upload\FileBase;
use app\admin\service\upload\trigger\SaveDb;
/**
* 本地上传
* Class Local
* @package EasyAdmin\upload\driver
*/
class Local extends FileBase
{
/**
* 重写上传方法
* @return array|void
*/
public function save()
{
if (pathinfo($this->file->getOriginalName(), PATHINFO_EXTENSION) === 'php') {
return [
'save' => false,
'msg' => '上传文件中存在异常文件,请重新选择',
'url' => '',
];
}
parent::save();
SaveDb::trigger($this->tableName, [
'upload_type' => $this->uploadType,
'original_name' => $this->file->getOriginalName(),
'mime_type' => $this->file->getOriginalMime(),
'file_ext' => strtolower($this->file->getOriginalExtension()),
'url' => $this->completeFileUrl,
'create_time' => time(),
]);
return [
'save' => true,
'msg' => '上传成功',
'url' => $this->completeFileUrl,
];
}
}

View File

@@ -1,42 +0,0 @@
<?php
namespace app\admin\service\upload\driver;
use app\admin\service\upload\driver\qnoss\Oss;
use app\admin\service\upload\FileBase;
use app\admin\service\upload\trigger\SaveDb;
/**
* 七牛云上传
* Class Qnoss
* @package EasyAdmin\upload\driver
*/
class Qnoss extends FileBase
{
/**
* 重写上传方法
* @return array|void
*/
public function save()
{
parent::save();
$upload = Oss::instance($this->uploadConfig)
->save($this->completeFilePath, $this->completeFilePath);
if ($upload['save'] == true) {
SaveDb::trigger($this->tableName, [
'upload_type' => $this->uploadType,
'original_name' => $this->file->getOriginalName(),
'mime_type' => $this->file->getOriginalMime(),
'file_ext' => strtolower($this->file->getOriginalExtension()),
'url' => $upload['url'],
'create_time' => time(),
]);
}
$this->rmLocalSave();
return $upload;
}
}

View File

@@ -1,43 +0,0 @@
<?php
namespace app\admin\service\upload\driver;
use app\admin\service\upload\driver\txcos\Cos;
use app\admin\service\upload\FileBase;
use app\admin\service\upload\trigger\SaveDb;
/**
* 腾讯云上传
* Class Txcos
* @package EasyAdmin\upload\driver
*/
class Txcos extends FileBase
{
/**
* 重写上传方法
* @return array|void
*/
public function save()
{
parent::save();
$upload = Cos::instance($this->uploadConfig)
->save($this->completeFilePath, $this->completeFilePath);
if ($upload['save'] == true) {
SaveDb::trigger($this->tableName, [
'upload_type' => $this->uploadType,
'original_name' => $this->file->getOriginalName(),
'mime_type' => $this->file->getOriginalMime(),
'file_ext' => strtolower($this->file->getOriginalExtension()),
'url' => $upload['url'],
'create_time' => time(),
]);
}
$this->rmLocalSave();
return $upload;
}
}

View File

@@ -1,70 +0,0 @@
<?php
namespace app\admin\service\upload\driver\alioss;
use EasyAdmin\upload\interfaces\OssDriver;
use OSS\Core\OssException;
use OSS\OssClient;
class Oss implements OssDriver
{
protected static $instance;
protected $accessKeyId;
protected $accessKeySecret;
protected $endpoint;
protected $bucket;
protected $domain;
protected $ossClient;
protected function __construct($config)
{
$this->accessKeyId = $config['alioss_access_key_id'];
$this->accessKeySecret = $config['alioss_access_key_secret'];
$this->endpoint = $config['alioss_endpoint'];
$this->bucket = $config['alioss_bucket'];
$this->domain = $config['alioss_domain'];
$this->ossClient = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint);
return $this;
}
public static function instance($config)
{
if (is_null(self::$instance)) {
self::$instance = new static($config);
}
return self::$instance;
}
public function save($objectName,$filePath)
{
try {
$upload = $this->ossClient->uploadFile($this->bucket, $objectName, $filePath);
} catch (OssException $e) {
return [
'save' => false,
'msg' => $e->getMessage(),
];
}
if (!isset($upload['info']['url'])) {
return [
'save' => false,
'msg' => '保存失败',
];
}
return [
'save' => true,
'msg' => '上传成功',
'url' => $upload['info']['url'],
];
}
}

View File

@@ -1,64 +0,0 @@
<?php
namespace app\admin\service\upload\driver\qnoss;
use app\admin\service\upload\interfaces\OssDriver;
use Qiniu\Auth;
use Qiniu\Storage\UploadManager;
class Oss implements OssDriver
{
protected static $instance;
protected $accessKey;
protected $secretKey;
protected $bucket;
protected $domain;
protected $auth;
public function __construct($config)
{
$this->accessKey = $config['qnoss_access_key'];
$this->secretKey = $config['qnoss_secret_key'];
$this->bucket = $config['qnoss_bucket'];
$this->domain = $config['qnoss_domain'];
$this->auth = new Auth($this->accessKey, $this->secretKey);
return $this;
}
public static function instance($config)
{
if (is_null(self::$instance)) {
self::$instance = new static($config);
}
return self::$instance;
}
public function save($objectName, $filePath)
{
$token = $this->auth->uploadToken($this->bucket);
$uploadMgr = new UploadManager();
list($result, $error) = $uploadMgr->putFile($token, $objectName, $filePath);
if ($error !== null) {
return [
'save' => false,
'msg' => '保存失败',
];
} else {
return [
'save' => true,
'msg' => '上传成功',
'url' => $this->domain . '/' . $result['key'],
];
}
}
}

View File

@@ -1,12 +0,0 @@
<?php
namespace app\admin\service\upload\interfaces;
interface OssDriver
{
public function save($objectName,$filePath);
}

View File

@@ -1,31 +0,0 @@
<?php
namespace app\admin\service\upload\trigger;
use think\facade\Db;
/**
* 保存到数据库
* Class SaveDb
* @package EasyAdmin\upload\trigger
*/
class SaveDb
{
/**
* 保存上传文件
* @param $tableName
* @param $data
*/
public static function trigger($tableName, $data)
{
if (isset($data['original_name'])) {
$data['original_name'] = htmlspecialchars($data['original_name'], ENT_QUOTES);
}
Db::name($tableName)->save($data);
}
}

View File

@@ -4,8 +4,10 @@ namespace app\admin\traits;
use app\admin\service\annotation\NodeAnnotation;
use app\admin\service\tool\CommonTool;
use app\Request;
use jianyan\excel\Excel;
use think\facade\Db;
use think\response\Json;
/**
* 后台CURD复用
@@ -18,21 +20,15 @@ trait Curd
/**
* @NodeAnnotation(title="列表")
*/
public function index()
public function index(Request $request): Json|string
{
if ($this->request->isAjax()) {
if ($request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
list($page, $limit, $where) = $this->buildTableParams();
$count = $this->model
->where($where)
->count();
$list = $this->model
->where($where)
->page($page, $limit)
->order($this->sort)
->select();
$count = $this->model->where($where)->count();
$list = $this->model->where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
$data = [
'code' => 0,
'msg' => '',
@@ -47,18 +43,20 @@ trait Curd
/**
* @NodeAnnotation(title="添加")
*/
public function add()
public function add(Request $request): string
{
if ($this->request->isPost()) {
$post = $this->request->post();
if ($request->isPost()) {
$post = $request->post();
$rule = [];
$this->validate($post, $rule);
try {
$save = $this->model->save($post);
} catch (\Exception $e) {
$this->error('保存失败:' . $e->getMessage());
Db::transaction(function () use ($post, &$save) {
$save = $this->model->save($post);
});
}catch (\Exception $e) {
$this->error('新增失败:' . $e->getMessage());
}
$save ? $this->success('保存成功') : $this->error('保存失败');
$save ? $this->success('新增成功') : $this->error('新增失败');
}
return $this->fetch();
}
@@ -66,17 +64,19 @@ trait Curd
/**
* @NodeAnnotation(title="编辑")
*/
public function edit($id)
public function edit(Request $request, $id = 0): string
{
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isPost()) {
$post = $this->request->post();
if ($request->isPost()) {
$post = $request->post();
$rule = [];
$this->validate($post, $rule);
try {
$save = $row->save($post);
} catch (\Exception $e) {
Db::transaction(function () use ($post, $row, &$save) {
$save = $row->save($post);
});
}catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
@@ -88,14 +88,14 @@ trait Curd
/**
* @NodeAnnotation(title="删除")
*/
public function delete($id)
public function delete($id): void
{
$this->checkPostRequest();
$row = $this->model->whereIn('id', $id)->select();
$row->isEmpty() && $this->error('数据不存在');
try {
$save = $row->delete();
} catch (\Exception $e) {
}catch (\Exception $e) {
$this->error('删除失败');
}
$save ? $this->success('删除成功') : $this->error('删除失败');
@@ -134,10 +134,10 @@ trait Curd
/**
* @NodeAnnotation(title="属性修改")
*/
public function modify()
public function modify(Request $request): void
{
$this->checkPostRequest();
$post = $this->request->post();
$post = $request->post();
$rule = [
'id|ID' => 'require',
'field|字段' => 'require',
@@ -152,10 +152,12 @@ trait Curd
$this->error('该字段不允许修改:' . $post['field']);
}
try {
$row->save([
$post['field'] => $post['value'],
]);
} catch (\Exception $e) {
Db::transaction(function () use ($post, $row) {
$row->save([
$post['field'] => $post['value'],
]);
});
}catch (\Exception $e) {
$this->error($e->getMessage());
}
$this->success('保存成功');

View File

@@ -1,5 +1,5 @@
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/layuimini/layuimini.css?v={$version}" media="all">
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/layuimini/themes/default.css?v={$version}" media="all">
<link rel="stylesheet" href="/static/plugs/lay-module/layuimini/layuimini.css?v={$version}" media="all">
<link rel="stylesheet" href="/static/plugs/lay-module/layuimini/themes/default.css?v={$version}" media="all">
<style id="layuimini-bg-color"></style>
<div class="layui-layout-body layuimini-all">
<div class="layui-layout layui-layout-admin">

View File

@@ -1,67 +1,59 @@
<link rel="stylesheet" href="__STATIC__/admin/css/welcome.css?v={$version}" media="all">
<div class="layuimini-container">
<div class="layuimini-main">
<div class="layui-row layui-col-space15">
<div class="layui-col-md8">
<div class="layui-row layui-col-space15">
<div class="layui-col-md6">
<link rel="stylesheet" href="/static/admin/css/welcome.css?v={$version}" media="all">
<div class="layui-layout layui-padding-2">
<div class="layui-layout-admin">
<div class="layui-row layui-col-space10">
<div class="layui-col-md8 ">
<div class="layui-row layui-col-space10">
<div class="layui-col-md6 ">
<div class="layui-card">
<div class="layui-card-header"><i class="fa fa-warning icon"></i>数据统计</div>
<div class="layui-card-body">
<div class="welcome-module">
<div class="layui-row layui-col-space10">
<div class="layui-col-xs6">
<div class="panel layui-bg-number">
<div class="panel-body">
<div class="panel-title">
<span class="label pull-right layui-bg-blue">实时</span>
<div class="layui-panel">
<div class="layui-card-body">
<span class="layui-badge layui-bg-cyan pull-right ">实时</span>
<div class="panel-content">
<h5>用户统计</h5>
</div>
<div class="panel-content">
<h1 class="no-margins">1234</h1>
<small>当前分类总记录数</small>
<h1>1234</h1>
<h6>当前分类总记录数</h6>
</div>
</div>
</div>
</div>
<div class="layui-col-xs6">
<div class="panel layui-bg-number">
<div class="panel-body">
<div class="panel-title">
<span class="label pull-right layui-bg-cyan">实时</span>
<div class="layui-panel">
<div class="layui-card-body">
<span class="layui-badge layui-bg-purple pull-right ">实时</span>
<div class="panel-content">
<h5>商品统计</h5>
</div>
<div class="panel-content">
<h1 class="no-margins">1234</h1>
<small>当前分类总记录数</small>
<h1>1234</h1>
<h6>当前分类总记录数</h6>
</div>
</div>
</div>
</div>
<div class="layui-col-xs6">
<div class="panel layui-bg-number">
<div class="panel-body">
<div class="panel-title">
<span class="label pull-right layui-bg-orange">实时</span>
<div class="layui-panel">
<div class="layui-card-body ">
<span class="layui-badge layui-bg-orange pull-right ">实时</span>
<div class="panel-content">
<h5>浏览统计</h5>
</div>
<div class="panel-content">
<h1 class="no-margins">1234</h1>
<small>当前分类总记录数</small>
<h1>1234</h1>
<h6>当前分类总记录数</h6>
</div>
</div>
</div>
</div>
<div class="layui-col-xs6">
<div class="panel layui-bg-number">
<div class="panel-body">
<div class="panel-title">
<span class="label pull-right layui-bg-green">实时</span>
<h5>订单统计</h5>
</div>
<div class="layui-panel">
<div class="layui-card-body ">
<span class="layui-badge layui-bg-red pull-right ">实时</span>
<div class="panel-content">
<h1 class="no-margins">1234</h1>
<small>当前分类总记录数</small>
<h5>订单统计</h5>
<h1>1234</h1>
<h6>当前分类总记录数</h6>
</div>
</div>
</div>
@@ -71,12 +63,12 @@
</div>
</div>
</div>
<div class="layui-col-md6">
<div class="layui-col-md6 ">
<div class="layui-card">
<div class="layui-card-header"><i class="fa fa-credit-card icon icon-blue"></i>快捷入口</div>
<div class="layui-card-body">
<div class="welcome-module">
<div class="layui-row layui-col-space10 layuimini-qiuck">
<div class="layui-row layui-col-space10">
{foreach $quicks as $vo}
<div class="layui-col-xs3 layuimini-qiuck-module">
@@ -93,7 +85,7 @@
</div>
</div>
<div class="layui-col-md12">
<div class="layui-col-md12 ">
<div class="layui-card">
<div class="layui-card-header"><i class="fa fa-line-chart icon"></i>报表统计</div>
<div class="layui-card-body">
@@ -104,7 +96,7 @@
</div>
</div>
<div class="layui-col-md4">
<div class="layui-col-md4 ">
<div class="layui-card">
<div class="layui-card-header"><i class="fa fa-fire icon"></i>版本信息</div>
@@ -145,6 +137,15 @@
<button type="button" class="layui-btn layui-btn-xs layui-btn-primary" id="layui-version">-</button>
</td>
</tr>
<tr>
<td>DEBUG模式</td>
<td>
<button type="button" class="layui-btn layui-btn-xs {:env('APP_DEBUG')?'layui-btn-warm':'layui-bg-gray'}">
{:env('APP_DEBUG')?'开启中':'已关闭'}
</button>
<span class="layui-badge layui-bg-gray">建议线上环境关闭 APP_DEBUG</span>
</td>
</tr>
<tr>
<td>主要特色</td>
<td>
@@ -167,8 +168,8 @@
<tr>
<td>Github</td>
<td>
<a href="https://github.com/wolf-leo/easyAdmin8" target="_blank" style="text-decoration: none;">
<i class="layui-icon layui-icon-github" style="font-size: 25px; color: #333333;"></i>
<a href="https://github.com/wolf-leo/easyAdmin8" target="_blank">
<i class="layui-icon layui-icon-github layui-font-20 layui-font-cyan layui-text"></i>
</a>
</td>
</tr>
@@ -179,16 +180,18 @@
<div class="layui-card">
<div class="layui-card-header"><i class="fa fa-paper-plane-o icon"></i>作者心语</div>
<div class="layui-card-body layui-text layadmin-text">
<p>本模板基于layui2.8.x以及font-awesome-4.7.0进行实现。layui开发文档地址<a class="layui-btn layui-btn-xs layui-btn-danger" target="_blank" href="http://layui.dev/docs">layui文档</a></p>
<p class="layui-red">备注:此后台框架永久开源,但请勿进行出售或者上传到任何素材网站,否则将追究相应的责任。</p>
</div>
</div>
<div class="layui-card">
<div class="layui-card-header"><i class="fa fa-qq icon"></i>QQ交流群</div>
<div class="layui-card-body layui-text layadmin-text">
<img src="/static/common/images/EasyAdmin8-ThinkPHP.png">
<div class="layui-card-body layui-text">
<p class="layui-font-cyan">
本模板基于layui2.9.x以及font-awesome-4.7.0进行实现。
<a class="layui-btn layui-btn-xs layui-btn-danger" style="vertical-align: baseline;" target="_blank" href="http://layui.dev/docs">layui文档</a>
</p>
<hr>
<p class="layui-font-red">备注:此后台框架永久开源,但请勿进行出售或者上传到任何素材网站,否则将追究相应的责任。</p>
<hr>
<div class="layui-card-header"><i class="fa fa-qq icon"></i>QQ交流群</div>
<div class="layui-card-body">
<img src="/static/common/images/EasyAdmin8-ThinkPHP.png" width="145">
</div>
</div>
</div>

View File

@@ -2,7 +2,7 @@
<html>
<head>
<meta charset="utf-8">
<title>{:sysconfig('site','site_name')}</title>
<title>{:sysConfig('site','site_name')}</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
@@ -10,7 +10,7 @@
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<link rel="stylesheet" href="__STATIC__/admin/css/public.css?v={$version}" media="all">
<link rel="stylesheet" href="/static/admin/css/public.css?v={$version}" media="all">
<link rel="stylesheet" href="" id="layuicss-theme-dark" media="all">
<script>
window.CONFIG = {
@@ -25,10 +25,10 @@
EDITOR_TYPE: "{$adminEditor|default='ueditor'}",
};
</script>
<script src="__STATIC__/plugs/layui-v2.8.x/layui.js?v={$version}" charset="utf-8"></script>
<script src="__STATIC__/plugs/require-2.3.6/require.js?v={$version}" charset="utf-8"></script>
<script src="__STATIC__/config-admin.js?v={$version}" charset="utf-8"></script>
<script src="__STATIC__/common/js/admin.js?v={$version}" charset="utf-8"></script>
<script src="/static/plugs/layui-v2.x/layui.js" charset="utf-8"></script>
<script src="/static/plugs/require-2.3.6/require.js" charset="utf-8"></script>
<script src="/static/config-admin.js?v={$version}" charset="utf-8"></script>
<script src="/static/common/js/admin.js?v={$version}" charset="utf-8"></script>
{include file="layout/editor" /}
</head>
<body>

View File

@@ -1,20 +1,27 @@
{switch $adminEditor}
{case ckeditor}
<script src="__STATIC__/plugs/ckeditor4/ckeditor.js?v={$version}" charset="utf-8"></script>
<script src="/static/plugs/ckeditor4/ckeditor.js?v={$version}" charset="utf-8"></script>
{/case}
{case wangEditor}
<link rel="stylesheet" href="__STATIC__/plugs/wangEditor/dist/style.css?v={$version}">
<script src="__STATIC__/plugs/wangEditor/dist/index.js?v={$version}"></script>
<link rel="stylesheet" href="/static/plugs/wangEditor/dist/style.css?v={$version}">
<script src="/static/plugs/wangEditor/dist/index.js?v={$version}"></script>
{/case}
{case EasyMDE}
<link rel="stylesheet" href="/static/plugs/easymde/easymde.min.css?v={$version}">
<script src="/static/plugs/easymde/easymde.min.js?v={$version}"></script>
{/case}
{default /}
<script src="__STATIC__/plugs/ueditor/ueditor.config.js?v={$version}" charset="utf-8"></script>
<script src="__STATIC__/plugs/ueditor/ueditor.all.js?v={$version}" charset="utf-8"></script>
<script src="__STATIC__/plugs/ueditor/lang/zh-cn/zh-cn.js?v={$version}" charset="utf-8"></script>
<script src="__STATIC__/plugs/ueditor/third-party/codemirror/codemirror.js?v={$version}" charset="utf-8"></script>
<script src="__STATIC__/plugs/ueditor/third-party/zeroclipboard/zeroclipboard.js?v={$version}" charset="utf-8"></script>
<script src="/static/plugs/ueditor/ueditor.config.js?v={$version}" charset="utf-8"></script>
<script src="/static/plugs/ueditor/ueditor.all.js?v={$version}" charset="utf-8"></script>
<script src="/static/plugs/ueditor/lang/zh-cn/zh-cn.js?v={$version}" charset="utf-8"></script>
<script src="/static/plugs/ueditor/third-party/codemirror/codemirror.js?v={$version}" charset="utf-8"></script>
<script src="/static/plugs/ueditor/third-party/zeroclipboard/zeroclipboard.js?v={$version}" charset="utf-8"></script>
{/switch}

View File

@@ -1,14 +1,14 @@
<link rel="stylesheet" href="__STATIC__/admin/css/login.css?v={$version}" media="all">
<link rel="stylesheet" href="/static/admin/css/login.css?v={$version}" media="all">
<div class="container">
<div class="main-body">
<div class="login-main">
<div class="login-top">
<span>{:sysconfig('site','site_name')}</span>
<span>{:sysConfig('site','site_name')}</span>
<span class="bg1"></span>
<span class="bg2"></span>
</div>
<form class="layui-form login-bottom">
<div class="demo{if !$demo} layui-hide{/if}">用户名:admin 密码:123456</div>
<div class="demo {if !$isDemo}layui-hide{/if}">用户名:admin 密码:123456</div>
<div class="center">
<div class="item">
@@ -42,9 +42,9 @@
</div>
</div>
<div class="footer">
{:sysconfig('site','site_copyright')}<span class="padding-5">|</span><a target="_blank" href="http://www.miitbeian.gov.cn">{:sysconfig('site','site_beian')}</a>
{:sysConfig('site','site_copyright')}<span class="padding-5">|</span><a target="_blank" href="http://www.miitbeian.gov.cn">{:sysConfig('site','site_beian')}</a>
</div>
</div>
<script>
let backgroundUrl = "{:sysconfig('site','admin_background')}"
let backgroundUrl = "{:sysConfig('site','admin_background')}"
</script>

View File

@@ -1,84 +1,104 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">商品分类</label>
<div class="layui-input-block">
<select name="cate_id" lay-verify="required" data-select="{:url('mall.cate/index')}" data-fields="id,title">
</select>
</div>
</div>
<form id="app-form" class="layui-form layuimini-form layui-form-pane">
<div class="layui-form-item">
<label class="layui-form-label">商品标题</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入商品标题" value="">
</div>
</div>
<div class="layui-row">
<div class="layui-col-xl5 layui-col-lg5 layui-col-md5 layui-col-sm5 layui-col-xs5">
<!-- 可以使用该方式 推荐写法-->
<div class="layui-form-item">
<label class="layui-form-label">商品分类</label>
<div class="layui-input-block">
<select name="cate_id" lay-verify="required" data-select="{:url('mall.cate/index')}" data-fields="id,title">
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">商品LOGO</label>
<div class="layui-input-block layuimini-upload">
<input name="logo" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="logo" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_logo" data-upload-select="logo" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
<!--也可以使用该方式-->
<!-- <div class="layui-form-item">-->
<!-- <label class="layui-form-label">商品分类</label>-->
<!-- <div class="layui-input-block">-->
<!-- <select name="cate_id" lay-verify="required">-->
<!-- <option value="">请选择</option>-->
<!-- {volist name='cate' id='vo'}-->
<!-- <option value="{$key}">{$vo}</option>-->
<!-- {/volist}-->
<!-- </select>-->
<!-- </div>-->
<!-- </div>-->
<div class="layui-form-item">
<label class="layui-form-label">商品标题</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入商品标题" value="">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">商品LOGO</label>
<div class="layui-input-block layuimini-upload">
<input name="logo" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="logo" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_logo" data-upload-select="logo" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">商品图片</label>
<div class="layui-input-block layuimini-upload">
<input name="images" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传商品图片" value="">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="images" data-upload-number="more" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_images" data-upload-select="images" data-upload-number="more" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">市场价格</label>
<div class="layui-input-block">
<input type="text" name="market_price" class="layui-input" lay-verify="required" placeholder="请输入市场价格" value="0">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">折扣价格</label>
<div class="layui-input-block">
<input type="text" name="discount_price" class="layui-input" lay-verify="required" placeholder="请输入折扣价格" value="0">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">虚拟销量</label>
<div class="layui-input-block">
<input type="text" name="virtual_sales" class="layui-input" lay-verify="required" placeholder="请输入虚拟销量" value="0">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类排序</label>
<div class="layui-input-block">
<input type="number" name="sort" class="layui-input" placeholder="请输入分类排序" value="0">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息"></textarea>
</div>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">商品图片</label>
<div class="layui-input-block layuimini-upload">
<input name="images" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传商品图片" value="">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="images" data-upload-number="more" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_images" data-upload-select="images" data-upload-number="more" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
<div class="layui-col-xl7 layui-col-lg7 layui-col-md7 layui-col-sm7 layui-col-xs7">
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">商品描述</label>
<div class="layui-input-block">
{:editor_textarea('','describe')}
</div>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">市场价格</label>
<div class="layui-input-block">
<input type="text" name="market_price" class="layui-input" lay-verify="required" placeholder="请输入市场价格" value="0">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">折扣价格</label>
<div class="layui-input-block">
<input type="text" name="discount_price" class="layui-input" lay-verify="required" placeholder="请输入折扣价格" value="0">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">虚拟销量</label>
<div class="layui-input-block">
<input type="text" name="virtual_sales" class="layui-input" lay-verify="required" placeholder="请输入虚拟销量" value="0">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">商品描述</label>
<div class="layui-input-block">
{:editor_textarea('','describe')}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类排序</label>
<div class="layui-input-block">
<input type="number" name="sort" class="layui-input" placeholder="请输入分类排序" value="0">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息"></textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>

View File

@@ -1,85 +1,104 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<form id="app-form" class="layui-form layuimini-form layui-form-pane">
<div class="layui-form-item">
<label class="layui-form-label">商品分类</label>
<div class="layui-input-block">
<select name="cate_id" lay-verify="required" data-select="{:url('mall.cate/index')}" data-fields="id,title" data-value="{$row.cate_id|default=''}">
</select>
</div>
</div>
<div class="layui-row">
<div class="layui-col-xl5 layui-col-lg5 layui-col-md5 layui-col-sm5 layui-col-xs5">
<!-- 可以使用该方式 推荐写法-->
<div class="layui-form-item">
<label class="layui-form-label">商品分类</label>
<div class="layui-input-block">
<select name="cate_id" lay-verify="required" data-select="{:url('mall.cate/index')}" data-fields="id,title" data-value="{$row.cate_id|default=''}">
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">商品标题</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入商品标题" value="{$row.title|default=''}">
</div>
</div>
<!--也可以使用该方式-->
<!-- <div class="layui-form-item">-->
<!-- <label class="layui-form-label">商品分类</label>-->
<!-- <div class="layui-input-block">-->
<!-- <select name="cate_id" lay-verify="required">-->
<!-- <option value="">请选择</option>-->
<!-- {volist name='cate' id='vo'}-->
<!-- <option value="{$key}" {if $key==$row.cate_id}selected{/if}>{$vo}</option>-->
<!-- {/volist}-->
<!-- </select>-->
<!-- </div>-->
<!-- </div>-->
<div class="layui-form-item">
<label class="layui-form-label required">商品LOGO</label>
<div class="layui-input-block layuimini-upload">
<input name="logo" class="layui-input layui-col-xs6" lay-verify="required" placeholder="上传分类图片" value="{$row.logo|default=''}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="logo" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_logo" data-upload-select="logo" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
<div class="layui-form-item">
<label class="layui-form-label">商品标题</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="输入商品标题" value="{$row.title|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">商品LOGO</label>
<div class="layui-input-block layuimini-upload">
<input name="logo" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="{$row.logo|default=''}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="logo" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_logo" data-upload-select="logo" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">商品图片</label>
<div class="layui-input-block layuimini-upload">
<input name="images" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传商品图片" value="{$row.images|default=''}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="images" data-upload-number="more" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_images" data-upload-select="images" data-upload-number="more" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">市场价格</label>
<div class="layui-input-block">
<input type="text" name="market_price" class="layui-input" lay-verify="required" placeholder="请输入市场价格" value="{$row.market_price|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">折扣价格</label>
<div class="layui-input-block">
<input type="text" name="discount_price" class="layui-input" lay-verify="required" placeholder="请输入折扣价格" value="{$row.discount_price|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">虚拟销量</label>
<div class="layui-input-block">
<input type="text" name="virtual_sales" class="layui-input" lay-verify="required" placeholder="请输入虚拟销量" value="{$row.virtual_sales|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类排序</label>
<div class="layui-input-block">
<input type="number" name="sort" class="layui-input" placeholder="请输入分类排序" value="{$row.sort|default=''}">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息">{$row.remark|default=''}</textarea>
</div>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">商品图片</label>
<div class="layui-input-block layuimini-upload">
<input name="images" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传商品图片" value="{$row.images|default=''}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="images" data-upload-number="more" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_images" data-upload-select="images" data-upload-number="more" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
<div class="layui-col-xl7 layui-col-lg7 layui-col-md7 layui-col-sm7 layui-col-xs7">
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">商品描述</label>
<div class="layui-input-block">
{:editor_textarea($row["describe"],'describe')}
</div>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">市场价格</label>
<div class="layui-input-block">
<input type="text" name="market_price" class="layui-input" lay-verify="required" placeholder="请输入市场价格" value="{$row.market_price|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">折扣价格</label>
<div class="layui-input-block">
<input type="text" name="discount_price" class="layui-input" lay-verify="required" placeholder="请输入折扣价格" value="{$row.discount_price|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">虚拟销量</label>
<div class="layui-input-block">
<input type="text" name="virtual_sales" class="layui-input" lay-verify="required" placeholder="请输入虚拟销量" value="{$row.virtual_sales|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">商品描述</label>
<div class="layui-input-block">
{:editor_textarea($row["describe"],'describe')}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类排序</label>
<div class="layui-input-block">
<input type="number" name="sort" class="layui-input" placeholder="请输入分类排序" value="{$row.sort|default=''}">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息">{$row.remark|default=''}</textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>

View File

@@ -8,4 +8,7 @@
lay-filter="currentTable">
</table>
</div>
</div>
</div>
<script>
let cateSelects=JSON.parse('{$cate|json_encode=256|raw}')
</script>

View File

@@ -3,7 +3,7 @@
<div class="layui-form-item">
<label class="layui-form-label">LOGO标题</label>
<div class="layui-input-block">
<input type="text" name="logo_title" class="layui-input" lay-verify="required" placeholder="请输入LOGO标题" value="{:sysconfig('site','logo_title')}">
<input type="text" name="logo_title" class="layui-input" lay-verify="required" placeholder="请输入LOGO标题" value="{:sysConfig('site','logo_title')}">
<tip>填写站点名称。</tip>
</div>
</div>
@@ -11,7 +11,7 @@
<div class="layui-form-item">
<label class="layui-form-label">LOGO图标</label>
<div class="layui-input-block layuimini-upload">
<input name="logo_image" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传LOGO图标" value="{:sysconfig('site','logo_image')}">
<input name="logo_image" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传LOGO图标" value="{:sysConfig('site','logo_image')}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="logo_image" data-upload-number="one" data-upload-exts="ico|png|jpg|jpeg"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_logo_image" data-upload-select="logo_image" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>

View File

@@ -3,7 +3,7 @@
<div class="layui-form-item">
<label class="layui-form-label">站点名称</label>
<div class="layui-input-block">
<input type="text" name="site_name" class="layui-input" lay-verify="required" placeholder="请输入站点名称" value="{:sysconfig('site','site_name')}">
<input type="text" name="site_name" class="layui-input" lay-verify="required" placeholder="请输入站点名称" value="{:sysConfig('site','site_name')}">
<tip>填写站点名称。</tip>
</div>
</div>
@@ -11,7 +11,7 @@
<div class="layui-form-item">
<label class="layui-form-label">浏览器图标ico格式</label>
<div class="layui-input-block layuimini-upload">
<input name="site_ico" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传浏览器图标,ico类型" value="{:sysconfig('site','site_ico')}">
<input name="site_ico" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传浏览器图标,ico类型" value="{:sysConfig('site','site_ico')}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="site_ico" data-upload-number="one" data-upload-exts="ico"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_site_ico" data-upload-select="site_ico" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
@@ -22,9 +22,9 @@
<div class="layui-form-item">
<label class="layui-form-label">后台背景图</label>
<div class="layui-input-block layuimini-upload">
<input name="admin_background" class="layui-input layui-col-xs6" placeholder="不填默认#333333" value="{:sysconfig('site','admin_background')}">
<input name="admin_background" class="layui-input layui-col-xs6" placeholder="不填默认#333333" value="{:sysConfig('site','admin_background')}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="site_ico" data-upload-number="one" data-upload-exts="png|jpg|jpeg"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn" data-upload="admin_background" data-upload-number="one" data-upload-exts="png|jpg|jpeg"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_admin_background" data-upload-select="admin_background" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
@@ -33,7 +33,7 @@
<div class="layui-form-item">
<label class="layui-form-label">版本信息</label>
<div class="layui-input-block">
<input type="text" name="site_version" class="layui-input" lay-verify="required" placeholder="请输入版本信息" value="{:sysconfig('site','site_version')}">
<input type="text" name="site_version" class="layui-input" lay-verify="required" placeholder="请输入版本信息" value="{:sysConfig('site','site_version')}">
<tip>填写版本信息。</tip>
</div>
</div>
@@ -41,7 +41,7 @@
<div class="layui-form-item">
<label class="layui-form-label">备案信息</label>
<div class="layui-input-block">
<input type="text" name="site_beian" class="layui-input" lay-verify="required" placeholder="请输入备案信息" value="{:sysconfig('site','site_beian')}">
<input type="text" name="site_beian" class="layui-input" lay-verify="required" placeholder="请输入备案信息" value="{:sysConfig('site','site_beian')}">
<tip>填写备案信息。</tip>
</div>
</div>
@@ -49,7 +49,7 @@
<div class="layui-form-item">
<label class="layui-form-label">版权信息</label>
<div class="layui-input-block">
<input type="text" name="site_copyright" class="layui-input" lay-verify="required" placeholder="请输入版权信息" value="{:sysconfig('site','site_copyright')}">
<input type="text" name="site_copyright" class="layui-input" lay-verify="required" placeholder="请输入版权信息" value="{:sysConfig('site','site_copyright')}">
<tip>填写版权信息。</tip>
</div>
</div>
@@ -59,10 +59,10 @@
<label class="layui-form-label">默认编辑器</label>
<div class="layui-input-block">
{foreach $editor_types as $key=>$val}
<input type="radio" name="editor_type" lay-filter="editor_type" value="{$key}" title="{$val}" {if $key==sysconfig('site','editor_type')}checked=""{/if}>
<input type="radio" name="editor_type" lay-filter="editor_type" value="{$key}" title="{$val}" {if $key==sysConfig('site','editor_type')}checked=""{/if}>
{/foreach}
<br>
<tip>默认百度编辑器。</tip>
<tip>默认推荐编辑器。</tip>
</div>
</div>

View File

@@ -3,7 +3,7 @@
<label class="layui-form-label required">存储方式</label>
<div class="layui-input-block">
{foreach $upload_types as $key=>$val}
<input type="radio" v-model="upload_type" name="upload_type" lay-filter="upload_type" value="{$key}" title="{$val}" {if $key==sysconfig('upload','upload_type')}checked=""{/if}>
<input type="radio" v-model="upload_type" name="upload_type" lay-filter="upload_type" value="{$key}" title="{$val}" {if $key==sysConfig('upload','upload_type')}checked=""{/if}>
{/foreach}
</div>
</div>
@@ -11,7 +11,7 @@
<div class="layui-form-item">
<label class="layui-form-label required">允许类型</label>
<div class="layui-input-block">
<input type="text" name="upload_allow_ext" class="layui-input" lay-verify="required" lay-reqtext="请输入允许类型" placeholder="请输入允许类型" value="{:sysconfig('upload','upload_allow_ext')}">
<input type="text" name="upload_allow_ext" class="layui-input" lay-verify="required" lay-reqtext="请输入允许类型" placeholder="请输入允许类型" value="{:sysConfig('upload','upload_allow_ext')}">
<tip>英文逗号做分隔符。</tip>
</div>
</div>
@@ -19,111 +19,111 @@
<div class="layui-form-item">
<label class="layui-form-label required">允许大小</label>
<div class="layui-input-block">
<input type="text" name="upload_allow_size" class="layui-input" lay-verify="required" lay-reqtext="请输入允许上传大小" placeholder="请输入允许上传大小" value="{:sysconfig('upload','upload_allow_size')}">
<input type="text" name="upload_allow_size" class="layui-input" lay-verify="required" lay-reqtext="请输入允许上传大小" placeholder="请输入允许上传大小" value="{:sysConfig('upload','upload_allow_size')}">
<tip>设置允许上传大小。</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'oss'" v-cloak>
<div class="layui-form-item oss layui-hide upload_type">
<label class="layui-form-label required">公钥信息</label>
<div class="layui-input-block">
<input type="text" name="oss_access_key_id" class="layui-input" lay-verify="required" lay-reqtext="请输入公钥信息" placeholder="请输入公钥信息" value="{:sysconfig('upload','oss_access_key_id')}">
<input type="text" name="oss_access_key_id" class="layui-input" lay-verify="required" lay-reqtext="请输入公钥信息" placeholder="请输入公钥信息" value="{:sysConfig('upload','oss_access_key_id')}">
<tip>例子FSGGshu64642THSk</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'oss'" v-cloak>
<div class="layui-form-item oss layui-hide upload_type">
<label class="layui-form-label required">私钥信息</label>
<div class="layui-input-block">
<input type="text" name="oss_access_key_secret" class="layui-input" lay-verify="required" lay-reqtext="请输入私钥信息" placeholder="请输入私钥信息" value="{:sysconfig('upload','oss_access_key_secret')}">
<input type="text" name="oss_access_key_secret" class="layui-input" lay-verify="required" lay-reqtext="请输入私钥信息" placeholder="请输入私钥信息" value="{:sysConfig('upload','oss_access_key_secret')}">
<tip>例子5fsfPReYKkFSGGshu64642THSkmTInaIm</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'oss'" v-cloak>
<div class="layui-form-item oss layui-hide upload_type">
<label class="layui-form-label required">数据中心</label>
<div class="layui-input-block">
<input type="text" name="oss_endpoint" class="layui-input" lay-verify="required" lay-reqtext="请输入数据中心" placeholder="请输入数据中心" value="{:sysconfig('upload','oss_endpoint')}">
<input type="text" name="oss_endpoint" class="layui-input" lay-verify="required" lay-reqtext="请输入数据中心" placeholder="请输入数据中心" value="{:sysConfig('upload','oss_endpoint')}">
<tip>例子https://oss-cn-shenzhen.aliyuncs.com</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'oss'" v-cloak>
<div class="layui-form-item oss layui-hide upload_type">
<label class="layui-form-label required">空间名称</label>
<div class="layui-input-block">
<input type="text" name="oss_bucket" class="layui-input" lay-verify="required" lay-reqtext="请输入空间名称" placeholder="请输入空间名称" value="{:sysconfig('upload','oss_bucket')}">
<input type="text" name="oss_bucket" class="layui-input" lay-verify="required" lay-reqtext="请输入空间名称" placeholder="请输入空间名称" value="{:sysConfig('upload','oss_bucket')}">
<tip>例子easy-admin</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'oss'" v-cloak>
<div class="layui-form-item oss layui-hide upload_type">
<label class="layui-form-label required">访问域名</label>
<div class="layui-input-block">
<input type="text" name="oss_domain" class="layui-input" lay-verify="required" lay-reqtext="请输入访问域名" placeholder="请输入访问域名" value="{:sysconfig('upload','oss_domain')}">
<input type="text" name="oss_domain" class="layui-input" lay-verify="required" lay-reqtext="请输入访问域名" placeholder="请输入访问域名" value="{:sysConfig('upload','oss_domain')}">
<tip>例子easy-admin.oss-cn-shenzhen.aliyuncs.com</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'cos'" v-cloak>
<div class="layui-form-item cos layui-hide upload_type">
<label class="layui-form-label required">公钥信息</label>
<div class="layui-input-block">
<input type="text" name="cos_secret_id" class="layui-input" lay-verify="required" lay-reqtext="请输入公钥信息" placeholder="请输入公钥信息" value="{:sysconfig('upload','cos_secret_id')}">
<input type="text" name="cos_secret_id" class="layui-input" lay-verify="required" lay-reqtext="请输入公钥信息" placeholder="请输入公钥信息" value="{:sysConfig('upload','cos_secret_id')}">
<tip>例子AKIDta6OQCbALQGrCI6ngKwQffR3dfsfrwrfs</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'cos'" v-cloak>
<div class="layui-form-item cos layui-hide upload_type">
<label class="layui-form-label required">私钥信息</label>
<div class="layui-input-block">
<input type="text" name="cos_secret_key" class="layui-input" lay-verify="required" lay-reqtext="请输入私钥信息" placeholder="请输入私钥信息" value="{:sysconfig('upload','cos_secret_key')}">
<input type="text" name="cos_secret_key" class="layui-input" lay-verify="required" lay-reqtext="请输入私钥信息" placeholder="请输入私钥信息" value="{:sysConfig('upload','cos_secret_key')}">
<tip>例子VllEWYKtClAbpqfFdTqysXxGQM6dsfs</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'cos'" v-cloak>
<div class="layui-form-item cos layui-hide upload_type">
<label class="layui-form-label required">存储桶地域</label>
<div class="layui-input-block">
<input type="text" name="cos_region" class="layui-input" lay-verify="required" lay-reqtext="请输入存储桶地域" placeholder="请输入存储桶地域" value="{:sysconfig('upload','cos_region')}">
<input type="text" name="cos_region" class="layui-input" lay-verify="required" lay-reqtext="请输入存储桶地域" placeholder="请输入存储桶地域" value="{:sysConfig('upload','cos_region')}">
<tip>例子ap-guangzhou</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'cos'" v-cloak>
<div class="layui-form-item cos layui-hide upload_type">
<label class="layui-form-label required">存储桶名称</label>
<div class="layui-input-block">
<input type="text" name="cos_bucket" class="layui-input" lay-verify="required" lay-reqtext="请输入存储桶名称" placeholder="请输入存储桶名称" value="{:sysconfig('upload','cos_bucket')}">
<input type="text" name="cos_bucket" class="layui-input" lay-verify="required" lay-reqtext="请输入存储桶名称" placeholder="请输入存储桶名称" value="{:sysConfig('upload','cos_bucket')}">
<tip>例子easyadmin-1251997243</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'qnoss'" v-cloak>
<div class="layui-form-item qnoss layui-hide upload_type">
<label class="layui-form-label required">公钥信息</label>
<div class="layui-input-block">
<input type="text" name="qnoss_access_key" class="layui-input" lay-verify="required" lay-reqtext="请输入公钥信息" placeholder="请输入公钥信息" value="{:sysconfig('upload','qnoss_access_key')}">
<input type="text" name="qnoss_access_key" class="layui-input" lay-verify="required" lay-reqtext="请输入公钥信息" placeholder="请输入公钥信息" value="{:sysConfig('upload','qnoss_access_key')}">
<tip>例子v-lV3tXev7yyfsfa1jRc6_8rFOhFYGQvvjsAQxdrB</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'qnoss'" v-cloak>
<div class="layui-form-item qnoss layui-hide upload_type">
<label class="layui-form-label required">私钥信息</label>
<div class="layui-input-block">
<input type="text" name="qnoss_secret_key" class="layui-input" lay-verify="required" lay-reqtext="请输入私钥信息" placeholder="请输入私钥信息" value="{:sysconfig('upload','qnoss_secret_key')}">
<input type="text" name="qnoss_secret_key" class="layui-input" lay-verify="required" lay-reqtext="请输入私钥信息" placeholder="请输入私钥信息" value="{:sysConfig('upload','qnoss_secret_key')}">
<tip>例子XOhYRR9JNqxsWVEO-mHWB4193vfsfsQADuORaXzr</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'qnoss'" v-cloak>
<div class="layui-form-item qnoss layui-hide upload_type">
<label class="layui-form-label required">存储空间</label>
<div class="layui-input-block">
<input type="text" name="qnoss_bucket" class="layui-input" lay-verify="required" lay-reqtext="请输入存储桶地域" placeholder="请输入存储桶地域" value="{:sysconfig('upload','qnoss_bucket')}">
<input type="text" name="qnoss_bucket" class="layui-input" lay-verify="required" lay-reqtext="请输入存储桶地域" placeholder="请输入存储桶地域" value="{:sysConfig('upload','qnoss_bucket')}">
<tip>例子easyadmin</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'qnoss'" v-cloak>
<div class="layui-form-item qnoss layui-hide upload_type">
<label class="layui-form-label required">访问域名</label>
<div class="layui-input-block">
<input type="text" name="qnoss_domain" class="layui-input" lay-verify="required" lay-reqtext="请输入访问域名" placeholder="请输入访问域名" value="{:sysconfig('upload','qnoss_domain')}">
<input type="text" name="qnoss_domain" class="layui-input" lay-verify="required" lay-reqtext="请输入访问域名" placeholder="请输入访问域名" value="{:sysConfig('upload','qnoss_domain')}">
<tip>例子http://q0xqzappp.bkt.clouddn.com</tip>
</div>
</div>
@@ -136,5 +136,5 @@
</form>
<script>
var upload_type = "{:sysconfig('upload','upload_type')}";
var upload_type = "{:sysConfig('upload','upload_type')}";
</script>

View File

@@ -1,46 +1,119 @@
<style>
.table_fields .input_tag {
margin-bottom: 5px;
display: inline-flex;
}
</style>
<div class="layuimini-container">
<div class="layuimini-main" id="app">
<div class="layuimini-main">
<div class="layui-tab layui-tab-brief" lay-filter="docDemoTabBrief">
<div class="layui-tab" lay-filter="curd-hash">
<ul class="layui-tab-title">
<li class="layui-this" lay-id="1">视图生成</li>
<li lay-id="2">命令生成</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-tab layui-tab-brief" lay-filter="docDemoTabBrief">
<form id="app-form" class="layui-form layuimini-form">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">数据库表前缀</label>
<div class="layui-input-block">
<input type="text" name="tb_prefix" class="layui-input" placeholder="请输入" value="{:env('DATABASE.PREFIX','')}">
<tip>可为空,为空则不带前缀</tip>
<div class="layui-form-item">
<label class="layui-form-label">数据库表前缀</label>
<div class="layui-input-block">
<input type="text" name="tb_prefix" class="layui-input" placeholder="请输入" value="{:env('DB_PREFIX','')}">
<tip>可为空,为空则不带前缀</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">数据库表名字</label>
<div class="layui-input-block">
<input type="text" name="tb_name" class="layui-input" lay-verify="required" placeholder="请输入:例如 test_goods" value="">
<tip>数据库表名字 不包含数据库表前缀。</tip>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="button" class="layui-btn layui-btn-normal layui-btn-sm" lay-filter="search" lay-submit="system.CurdGenerate/save?type=search" data-refresh="false">查询</button>
</div>
</form>
</div>
<div class="tableShow layui-hide">
<blockquote class="layui-elem-quote layui-quote-nm">
数据表:<span class="table-text"></span>
</blockquote>
<div class="layui-card-body">
<fieldset class="layui-elem-field">
<legend class="layui-font-16">设置忽略字段</legend>
<div class="layui-field-box">
<div class="table_fields layui-form" data-name="ignore"></div>
</div>
</fieldset>
<fieldset class="layui-elem-field">
<legend class="layui-font-16">设置下拉字段</legend>
<div class="layui-field-box">
<div class="table_fields layui-form" data-name="select"></div>
</div>
</fieldset>
<fieldset class="layui-elem-field">
<legend class="layui-font-16">设置单选字段</legend>
<div class="layui-field-box">
<div class="table_fields layui-form" data-name="radio"></div>
</div>
</fieldset>
<fieldset class="layui-elem-field">
<legend class="layui-font-16">设置多选字段</legend>
<div class="layui-field-box">
<div class="table_fields layui-form" data-name="checkbox"></div>
</div>
</fieldset>
<fieldset class="layui-elem-field">
<legend class="layui-font-16">设置单选图片字段</legend>
<div class="layui-field-box">
<div class="table_fields layui-form" data-name="image"></div>
</div>
</fieldset>
<fieldset class="layui-elem-field">
<legend class="layui-font-16">设置多选图片字段</legend>
<div class="layui-field-box">
<div class="table_fields layui-form" data-name="images"></div>
</div>
</fieldset>
<fieldset class="layui-elem-field">
<legend class="layui-font-16">设置日期Y-m-d字段</legend>
<div class="layui-field-box">
<div class="table_fields layui-form" data-name="date"></div>
</div>
</fieldset>
<fieldset class="layui-elem-field">
<legend class="layui-font-16">设置日期时间Y-m-d H:i:s字段</legend>
<div class="layui-field-box">
<div class="table_fields layui-form" data-name="datetime"></div>
</div>
</fieldset>
<fieldset class="layui-elem-field">
<legend class="layui-font-16">设置编辑器字段</legend>
<div class="layui-field-box">
<div class="table_fields layui-form" data-name="editor"></div>
</div>
</fieldset>
</div>
<div class="layui-btn-container">
<form class="layui-form layuimini-form">
<button type="button" class="layui-btn layui-bg-cyan" lay-filter="add" lay-submit="system.CurdGenerate/save?type=add">自动生成CURD</button>
<button type="button" class="layui-btn layui-bg-red" lay-filter="delete" lay-submit="system.CurdGenerate/save?type=delete">删除CURD对应的文件</button>
</form>
<div class="file-list layui-elem-quote">还未生成任何文件</div>
</div>
<table id="currentTable" class="layui-table" lay-filter="currentTable"></table>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">数据库表名字</label>
<div class="layui-input-block">
<input type="text" name="tb_name" class="layui-input" lay-verify="required" placeholder="请输入:例如 test_goods" value="">
<tip>数据库表名字 不包含数据库表前缀。</tip>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="button" class="layui-btn layui-btn-normal layui-btn-sm" lay-filter="search" lay-submit="system.CurdGenerate/save?type=search" data-refresh="false">查询</button>
</div>
</form>
</div>
<div class="tableShow layui-hide">
<blockquote class="layui-elem-quote layui-quote-nm">
数据表:<span class="table-text"></span>
</blockquote>
<div class="layui-btn-container">
<form class="layui-form layuimini-form">
<button type="button" class="layui-btn layui-bg-cyan" lay-filter="add" lay-submit="system.CurdGenerate/save?type=add">自动生成CURD</button>
<button type="button" class="layui-btn layui-bg-red" lay-filter="delete" lay-submit="system.CurdGenerate/save?type=delete">删除CURD对应的文件</button>
</form>
<div class="file-list layui-elem-quote">还未生成任何文件</div>
<div class="layui-tab-item"></div>
</div>
<table id="currentTable" class="layui-table" lay-filter="currentTable"></table>
</div>
</div>
</div>

View File

@@ -1,6 +1,7 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
data-auth-record="{:auth('system.log/record')}"
lay-filter="currentTable">
</table>
</div>

View File

@@ -3,7 +3,7 @@
display: none;
}
</style>
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/autocomplete/autocomplete.css?v={$version}" media="all">
<link rel="stylesheet" href="/static/plugs/lay-module/autocomplete/autocomplete.css?v={$version}" media="all">
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">

View File

@@ -3,7 +3,7 @@
display: none;
}
</style>
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/autocomplete/autocomplete.css?v={$version}" media="all">
<link rel="stylesheet" href="/static/plugs/lay-module/autocomplete/autocomplete.css?v={$version}" media="all">
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">

View File

@@ -1,4 +1,4 @@
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/treetable-lay/treetable.css?v={$version}" media="all">
<link rel="stylesheet" href="/static/plugs/lay-module/treetable-lay/treetable.css?v={$version}" media="all">
<style>
.layui-btn:not(.layui-btn-lg ):not(.layui-btn-sm):not(.layui-btn-xs) {
height: 34px;

View File

@@ -3,7 +3,7 @@
display: none;
}
</style>
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/autocomplete/autocomplete.css?v={$version}" media="all">
<link rel="stylesheet" href="/static/plugs/lay-module/autocomplete/autocomplete.css?v={$version}" media="all">
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">

View File

@@ -3,7 +3,7 @@
display: none;
}
</style>
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/autocomplete/autocomplete.css?v={$version}" media="all">
<link rel="stylesheet" href="/static/plugs/lay-module/autocomplete/autocomplete.css?v={$version}" media="all">
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">

View File

@@ -9,6 +9,5 @@
</div>
</div>
<script>
let upload_types = '{$upload_types|json_encode|raw}'
upload_types = JSON.parse(upload_types)
let upload_types = JSON.parse('{$upload_types|json_encode=256|raw}')
</script>

View File

@@ -2,6 +2,9 @@
// 应用公共文件
use app\common\service\AuthService;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Cache;
if (!function_exists('__url')) {
@@ -14,7 +17,7 @@ if (!function_exists('__url')) {
* @param bool $domain
* @return string
*/
function __url(string $url = '', array $vars = [], $suffix = true, $domain = false)
function __url(string $url = '', array $vars = [], bool $suffix = true, bool $domain = false): string
{
return url($url, $vars, $suffix, $domain)->build();
}
@@ -24,11 +27,10 @@ if (!function_exists('password')) {
/**
* 密码加密算法
* @param $value 需要加密的值
* @param $type 加密类型默认为md5 md5, hash
* @return mixed
* @param $value
* @return string
*/
function password($value)
function password($value): string
{
$value = sha1('blog_') . md5($value) . md5('_encrypt') . sha1($value);
return sha1($value);
@@ -36,49 +38,27 @@ if (!function_exists('password')) {
}
if (!function_exists('xdebug')) {
/**
* debug调试
* @param string|array $data 打印信息
* @param string $type 类型
* @param string $suffix 文件后缀名
* @param bool $force
* @param null $file
* @deprecated 不建议使用建议直接使用框架自带的log组件
*/
function xdebug($data, $type = 'xdebug', $suffix = null, $force = false, $file = null)
{
!is_dir(runtime_path() . 'xdebug/') && mkdir(runtime_path() . 'xdebug/');
if (is_null($file)) {
$file = is_null($suffix) ? runtime_path() . 'xdebug/' . date('Ymd') . '.txt' : runtime_path() . 'xdebug/' . date('Ymd') . "_{$suffix}" . '.txt';
}
file_put_contents($file, "[" . date('Y-m-d H:i:s') . "] " . "========================= {$type} ===========================" . PHP_EOL, FILE_APPEND);
$str = ((is_string($data) ? $data : (is_array($data) || is_object($data))) ? print_r($data, true) : var_export($data, true)) . PHP_EOL;
$force ? file_put_contents($file, $str) : file_put_contents($file, $str, FILE_APPEND);
}
}
if (!function_exists('sysconfig')) {
if (!function_exists('sysConfig')) {
/**
* 获取系统配置信息
* @param $group
* @param null $name
* @return array|mixed
* @param $name
* @return mixed
*/
function sysconfig($group, $name = null)
function sysConfig($group, $name = null): mixed
{
$where = ['group' => $group];
$value = empty($name) ? Cache::get("sysconfig_{$group}") : Cache::get("sysconfig_{$group}_{$name}");
$value = empty($name) ? Cache::get("sysConfig_{$group}") : Cache::get("sysConfig_{$group}_{$name}");
if (empty($value)) {
if (!empty($name)) {
$where['name'] = $name;
$value = \app\admin\model\SystemConfig::where($where)->value('value');
Cache::tag('sysconfig')->set("sysconfig_{$group}_{$name}", $value, 3600);
} else {
Cache::tag('sysConfig')->set("sysConfig_{$group}_{$name}", $value, 3600);
}else {
$value = \app\admin\model\SystemConfig::where($where)->column('value', 'name');
Cache::tag('sysconfig')->set("sysconfig_{$group}", $value, 3600);
Cache::tag('sysConfig')->set("sysConfig_{$group}", $value, 3600);
}
}
return $value;
@@ -93,7 +73,7 @@ if (!function_exists('array_format_key')) {
* @param $key
* @return array
*/
function array_format_key($array, $key)
function array_format_key($array, $key): array
{
$newArray = [];
foreach ($array as $vo) {
@@ -110,30 +90,30 @@ if (!function_exists('auth')) {
* auth权限验证
* @param $node
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
function auth($node = null)
function auth($node = null): bool
{
$authService = new AuthService(session('admin.id'));
$check = $authService->checkNode($node);
return $check;
return $authService->checkNode($node);
}
/**
* @param string $detail
* @param string|null $detail
* @param string $name
* @param string $placeholder
* @return string
*/
function editor_textarea(string $detail, string $name = 'desc', string $placeholder = '请输入'): string
function editor_textarea(?string $detail, string $name = 'desc', string $placeholder = '请输入'): string
{
$editor_type = sysconfig('site', 'editor_type');
$editor_type = sysConfig('site', 'editor_type');
return match ($editor_type) {
'ckeditor' => "<textarea name='{$name}' rows='20' class='layui-textarea editor' placeholder='{$placeholder}'>{$detail}</textarea>",
'wangEditor' => "<div class='wangEditor_div'><textarea name='{$name}' rows='20' class='layui-textarea editor layui-hide'>{$detail}</textarea><div id='editor_toolbar_{$name}'></div><div id='editor_{$name}' style='height: 300px'></div></div>",
default => "<script type='text/plain' id='{$name}' name='{$name}' class='editor' data-content='{$detail}'></script>",
'ueditor' => "<script type='text/plain' id='{$name}' name='{$name}' class='editor' data-content='{$detail}'></script>",
'EasyMDE' => "<textarea id='{$name}' class='editor' name='{$name}'>{$detail}</textarea>",
default => "<div class='wangEditor_div'><textarea name='{$name}' rows='20' class='layui-textarea editor layui-hide'>{$detail}</textarea><div id='editor_toolbar_{$name}'></div><div id='editor_{$name}' style='height: 300px'></div></div>",
};
}
}

View File

@@ -27,7 +27,7 @@ class Curd extends Command
->addOption('filesFieldSuffix', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '多文件字段后缀', null)
->addOption('dateFieldSuffix', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '时间字段后缀', null)
->addOption('switchFields', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '开关的字段', null)
->addOption('selectFileds', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '下拉的字段', null)
->addOption('selectFields', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '下拉的字段', null)
->addOption('editorFields', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '富文本的字段', null)
->addOption('sortFields', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '排序的字段', null)
->addOption('ignoreFields', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '忽略的字段', null)
@@ -36,7 +36,7 @@ class Curd extends Command
->addOption('foreignKey', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '关联外键', null)
->addOption('primaryKey', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '关联主键', null)
->addOption('relationModelFilename', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '关联模型文件名', null)
->addOption('relationOnlyFileds', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '关联模型中只显示的字段', null)
->addOption('relationOnlyFields', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '关联模型中只显示的字段', null)
->addOption('relationBindSelect', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '关联模型中的字段用于主表外键的表单下拉选择', null)
#
->addOption('force', 'f', Option::VALUE_REQUIRED, '强制覆盖模式', 0)
@@ -59,7 +59,7 @@ class Curd extends Command
$filesFieldSuffix = $input->getOption('filesFieldSuffix');
$dateFieldSuffix = $input->getOption('dateFieldSuffix');
$switchFields = $input->getOption('switchFields');
$selectFileds = $input->getOption('selectFileds');
$selectFields = $input->getOption('selectFields');
$sortFields = $input->getOption('sortFields');
$ignoreFields = $input->getOption('ignoreFields');
@@ -67,7 +67,7 @@ class Curd extends Command
$foreignKey = $input->getOption('foreignKey');
$primaryKey = $input->getOption('primaryKey');
$relationModelFilename = $input->getOption('relationModelFilename');
$relationOnlyFileds = $input->getOption('relationOnlyFileds');
$relationOnlyFields = $input->getOption('relationOnlyFields');
$relationBindSelect = $input->getOption('relationBindSelect');
$force = $input->getOption('force');
@@ -80,13 +80,16 @@ class Curd extends Command
'foreignKey' => $foreignKey[$key] ?? null,
'primaryKey' => $primaryKey[$key] ?? null,
'modelFilename' => $relationModelFilename[$key] ?? null,
'onlyFileds' => isset($relationOnlyFileds[$key]) ? explode(",", $relationOnlyFileds[$key]) : [],
'onlyField' => isset($relationOnlyFields[$key]) ? explode(",", $relationOnlyFields[$key]) : [],
'relationBindSelect' => $relationBindSelect[$key] ?? null,
];
}
if (empty($table)) {
CliEcho::error('请设置主表');
if (PHP_SAPI == 'cli')
CliEcho::error('请设置主表');
else
$output->writeln('请设置主表');
return false;
}
@@ -106,12 +109,12 @@ class Curd extends Command
!empty($filesFieldSuffix) && $build = $build->setFilesFieldSuffix($filesFieldSuffix);
!empty($dateFieldSuffix) && $build = $build->setDateFieldSuffix($dateFieldSuffix);
!empty($switchFields) && $build = $build->setSwitchFields($switchFields);
!empty($selectFileds) && $build = $build->setSelectFileds($selectFileds);
!empty($selectFields) && $build = $build->setselectFields($selectFields);
!empty($sortFields) && $build = $build->setSortFields($sortFields);
!empty($ignoreFields) && $build = $build->setIgnoreFields($ignoreFields);
foreach ($relations as $relation) {
$build = $build->setRelation($relation['table'], $relation['foreignKey'], $relation['primaryKey'], $relation['modelFilename'], $relation['onlyFileds'], $relation['relationBindSelect']);
$build = $build->setRelation($relation['table'], $relation['foreignKey'], $relation['primaryKey'], $relation['modelFilename'], $relation['onlyField'], $relation['relationBindSelect']);
}
$build = $build->render();
@@ -120,41 +123,58 @@ class Curd extends Command
if (!$delete) {
$result = $build->create();
if ($force) {
if (PHP_SAPI == 'cli') {
$output->info(">>>>>>>>>>>>>>>");
foreach ($fileList as $key => $val) {
$output->info($key);
}
$output->info(">>>>>>>>>>>>>>>");
$output->info("确定强制生成上方所有文件? 如果文件存在会直接覆盖。 请输入 'yes' 按回车键继续操作: ");
$line = fgets(defined('STDIN') ? STDIN : fopen('php://stdin', 'r'));
if (trim($line) != 'yes') {
throw new Exception("取消文件CURD生成操作");
}
CliEcho::success('自动生成CURD成功');
}else {
$output->writeln('自动生成CURD成功');
}
}
}else {
if (PHP_SAPI == 'cli') {
$output->info(">>>>>>>>>>>>>>>");
foreach ($fileList as $key => $val) {
$output->info($key);
}
$output->info(">>>>>>>>>>>>>>>");
$output->info("确定强制生成上方所有文件? 如果文件存在会直接覆盖。 请输入 'yes' 按回车键继续操作: ");
$output->info("确定删除上方所有文件? 请输入 'yes' 按回车键继续操作: ");
$line = fgets(defined('STDIN') ? STDIN : fopen('php://stdin', 'r'));
if (trim($line) != 'yes') {
throw new Exception("取消文件CURD生成操作");
throw new Exception("取消删除文件操作");
}
$result = $build->delete();
CliEcho::success('>>>>>>>>>>>>>>>');
CliEcho::success('删除自动生成CURD文件成功');
CliEcho::success('>>>>>>>>>>>>>>>');
foreach ($result as $vo) {
CliEcho::success($vo);
}
}else {
$result = $build->delete();
$output->writeln('>>>>>>>>>>>>>>>');
$output->writeln('删除自动生成CURD文件成功');
$output->writeln('>>>>>>>>>>>>>>>');
foreach ($result as $vo) {
$output->writeln($vo);
}
}
CliEcho::success('自动生成CURD成功');
} else {
$output->info(">>>>>>>>>>>>>>>");
foreach ($fileList as $key => $val) {
$output->info($key);
}
$output->info(">>>>>>>>>>>>>>>");
$output->info("确定删除上方所有文件? 请输入 'yes' 按回车键继续操作: ");
$line = fgets(defined('STDIN') ? STDIN : fopen('php://stdin', 'r'));
if (trim($line) != 'yes') {
throw new Exception("取消删除文件操作");
}
$result = $build->delete();
CliEcho::success('>>>>>>>>>>>>>>>');
CliEcho::success('删除自动生成CURD文件成功');
}
CliEcho::success('>>>>>>>>>>>>>>>');
foreach ($result as $vo) {
CliEcho::success($vo);
}
} catch (\Exception $e) {
CliEcho::error($e->getMessage());
return false;
}catch (\Exception $e) {
if (PHP_SAPI == 'cli')
CliEcho::error($e->getMessage());
else
$output->writeln($e->getMessage());
}
return false;
}

View File

@@ -24,7 +24,7 @@ class OssStatic extends Command
$output->writeln("========正在上传静态资源到OSS上========" . date('Y-m-d H:i:s'));
$dir = root_path() . 'public' . DIRECTORY_SEPARATOR . 'static';
$list = CommonTool::readDirAllFiles($dir);
$uploadConfig = sysconfig('upload');
$uploadConfig = sysConfig('upload');
$uploadPrefix = config('app.oss_static_prefix', 'oss_static_prefix');
foreach ($list as $key => $val) {
list($objectName, $filePath) = [$uploadPrefix . DIRECTORY_SEPARATOR . $key, $val];

View File

@@ -3,25 +3,18 @@
namespace app\common\controller;
use app\admin\service\ConfigService;
use app\admin\traits\Curd;
use app\BaseController;
use app\common\constants\AdminConstant;
use app\common\service\AuthService;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Env;
use app\common\traits\JumpTrait;
use think\facade\View;
use think\helper\Str;
use think\response\Json;
/**
* Class AdminController
* @package app\common\controller
*/
class AdminController extends BaseController
{
use \app\common\traits\JumpTrait;
use Curd;
use JumpTrait;
/**
* 当前模型
@@ -81,39 +74,60 @@ class AdminController extends BaseController
*/
protected bool $isDemo = false;
/**
* @var int|string
*/
protected int|string $adminUid;
/**
* 初始化方法
*/
protected function initialize()
protected function initialize(): void
{
parent::initialize();
$this->layout && $this->app->view->engine()->layout($this->layout);
$this->isDemo = Env::get('EASYADMIN.IS_DEMO', false);
$this->adminUid = request()->adminUserInfo['id'] ?? 0;
$this->isDemo = env('EASYADMIN.IS_DEMO', false);
$this->setOrder();
$this->viewInit();
$this->checkAuth();
}
/**
* 初始化排序
* @return $this
*/
public function setOrder(): static
{
$tableOrder = $this->request->param('tableOrder/s', '');
if (!empty($tableOrder)) {
[$orderField, $orderType] = explode(' ', $tableOrder);
$this->sort = [$orderField => $orderType];
}
return $this;
}
/**
* 模板变量赋值
* @param string|array $name 模板变量
* @param mixed $value 变量值
* @return mixed
* @param array|string $name 模板变量
* @param mixed|null $value 变量值
*/
public function assign($name, $value = null): mixed
public function assign(array|string $name, mixed $value = null): void
{
return $this->app->view->assign($name, $value);
View::assign($name, $value);
}
/**
* 解析和获取模板内容 用于输出
* @param string $template
* @param array $vars
* @return mixed
* @param bool $layout 是否需要自动布局
* @return string
*/
public function fetch(string $template = '', array $vars = []): mixed
public function fetch(string $template = '', array $vars = [], bool $layout = true): string
{
return $this->app->view->fetch($template, $vars);
if ($layout) View::instance()->engine()->layout('/layout/default');
View::assign($vars);
return View::fetch($template);
}
/**
@@ -158,7 +172,7 @@ class AdminController extends BaseController
$excludes[$key] = $val;
continue;
}
$op = isset($ops[$key]) && !empty($ops[$key]) ? $ops[$key] : '%*%';
$op = !empty($ops[$key]) ? $ops[$key] : '%*%';
if ($this->relationSearch && count(explode('.', $key)) == 1) {
$key = "{$tableName}.{$key}";
}
@@ -185,7 +199,7 @@ class AdminController extends BaseController
$where[] = [$key, $op, "%{$val}"];
}
}
return [$page, $limit, $where, $excludes];
return [(int)$page, (int)$limit, $where, $excludes];
}
/**
@@ -195,17 +209,14 @@ class AdminController extends BaseController
public function selectList(): Json
{
$fields = input('selectFields');
$data = $this->model
->where($this->selectWhere)
->field($fields)
->select();
$data = $this->model->where($this->selectWhere)->field($fields)->select()->toArray();
$this->success(null, $data);
}
/**
* 初始化视图参数
*/
private function viewInit()
private function viewInit(): void
{
$request = app()->request;
list($thisModule, $thisController, $thisAction) = [app('http')->getName(), app()->request->controller(), $request->action()];
@@ -215,9 +226,10 @@ class AdminController extends BaseController
}
$autoloadJs = file_exists(root_path('public') . "static/{$thisModule}/js/{$jsPath}.js");
$thisControllerJsPath = "{$thisModule}/js/{$jsPath}.js";
$adminModuleName = config('app.admin_alias_name');
$isSuperAdmin = session('admin.id') == AdminConstant::SUPER_ADMIN_ID;
$adminModuleName = config('admin.alias_name');
$isSuperAdmin = $this->adminUid == AdminConstant::SUPER_ADMIN_ID;
$data = [
'isDemo' => $this->isDemo,
'adminModuleName' => $adminModuleName,
'thisController' => parse_name($thisController),
'thisAction' => $thisAction,
@@ -227,60 +239,16 @@ class AdminController extends BaseController
'isSuperAdmin' => $isSuperAdmin,
'version' => env('APP_DEBUG') ? time() : ConfigService::getVersion(),
'adminUploadUrl' => url('ajax/upload', [], false),
'adminEditor' => sysconfig('site', 'editor_type') ?: 'ueditor',
'adminEditor' => sysConfig('site', 'editor_type') ?: 'wangEditor',
];
View::assign($data);
}
/**
* 检测权限
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
private function checkAuth()
{
$adminConfig = config('admin');
$adminId = session('admin.id');
$expireTime = session('admin.expire_time');
/** @var AuthService $authService */
$authService = app(AuthService::class, ['adminId' => $adminId]);
$currentNode = $authService->getCurrentNode();
$currentController = parse_name(app()->request->controller());
// 验证登录
if (
!in_array($currentController, $adminConfig['no_login_controller'])
&& !in_array($currentNode, $adminConfig['no_login_node'])) {
empty($adminId) && $this->error('请先登录后台', [], __url('admin/login/index'));
// 判断是否登录过期
if ($expireTime !== true && time() > $expireTime) {
session('admin', null);
$this->error('登录已过期,请重新登录', [], __url('admin/login/index'));
}
}
// 验证权限
if (
!in_array($currentController, $adminConfig['no_auth_controller'])
&& !in_array($currentNode, $adminConfig['no_auth_node'])) {
$check = $authService->checkNode($currentNode);
!$check && $this->error('无权限访问');
// 判断是否为演示环境
if (env('EASYADMIN.IS_DEMO', false) && app()->request->isPost()) {
$this->error('演示环境下不允许修改');
}
}
}
/**
* 严格校验接口是否为POST请求
*/
protected function checkPostRequest()
protected function checkPostRequest(): void
{
if (!$this->request->isPost()) {
$this->error("当前请求不合法!");

View File

@@ -1,59 +1,161 @@
{__NOLAYOUT__}<!DOCTYPE html>
<html>
<!DOCTYPE html>
<html lang="">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>跳转提示</title>
<style type="text/css">
*{box-sizing:border-box;margin:0;padding:0;font-family:Lantinghei SC,Open Sans,Arial,Hiragino Sans GB,Microsoft YaHei,"微软雅黑",STHeiti,WenQuanYi Micro Hei,SimSun,sans-serif;-webkit-font-smoothing:antialiased}
body{padding:70px 0;background:#edf1f4;font-weight:400;font-size:1pc;-webkit-text-size-adjust:none;color:#333}
a{outline:0;color:#3498db;text-decoration:none;cursor:pointer}
.system-message{margin:20px 5%;padding:40px 20px;background:#fff;box-shadow:1px 1px 1px hsla(0,0%,39%,.1);text-align:center}
.system-message h1{margin:0;margin-bottom:9pt;color:#444;font-weight:400;font-size:40px}
.system-message .jump,.system-message .image{margin:20px 0;padding:0;padding:10px 0;font-weight:400}
.system-message .jump{font-size:14px}
.system-message .jump a{color:#333}
.system-message p{font-size:9pt;line-height:20px}
.system-message .btn{display:inline-block;margin-right:10px;width:138px;height:2pc;border:1px solid #44a0e8;border-radius:30px;color:#44a0e8;text-align:center;font-size:1pc;line-height:2pc;margin-bottom:5px;}
.success .btn{border-color:#69bf4e;color:#69bf4e}
.error .btn{border-color:#ff8992;color:#ff8992}
.info .btn{border-color:#3498db;color:#3498db}
.copyright p{width:100%;color:#919191;text-align:center;font-size:10px}
.system-message .btn-grey{border-color:#bbb;color:#bbb}
.clearfix:after{clear:both;display:block;visibility:hidden;height:0;content:"."}
@media (max-width:768px){body {padding:20px 0;}}
@media (max-width:480px){.system-message h1{font-size:30px;}}
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: Lantinghei SC, Open Sans, Arial, Hiragino Sans GB, Microsoft YaHei, "微软雅黑", STHeiti, WenQuanYi Micro Hei, SimSun, sans-serif;
-webkit-font-smoothing: antialiased
}
body {
padding: 70px 0;
background: #edf1f4;
font-weight: 400;
font-size: 1pc;
-webkit-text-size-adjust: none;
color: #333
}
a {
outline: 0;
color: #3498db;
text-decoration: none;
cursor: pointer
}
.system-message {
margin: 20px 5%;
padding: 40px 20px;
background: #fff;
box-shadow: 1px 1px 1px hsla(0, 0%, 39%, .1);
text-align: center
}
.system-message h1 {
margin: 0;
margin-bottom: 9pt;
color: #444;
font-weight: 400;
font-size: 40px
}
.system-message .jump, .system-message .image {
margin: 20px 0;
padding: 0;
padding: 10px 0;
font-weight: 400
}
.system-message .jump {
font-size: 14px
}
.system-message .jump a {
color: #333
}
.system-message p {
font-size: 9pt;
line-height: 20px
}
.system-message .btn {
display: inline-block;
margin-right: 10px;
width: 138px;
height: 2pc;
border: 1px solid #44a0e8;
border-radius: 30px;
color: #44a0e8;
text-align: center;
font-size: 1pc;
line-height: 2pc;
margin-bottom: 5px;
}
.success .btn {
border-color: #69bf4e;
color: #69bf4e
}
.error .btn {
border-color: #ff8992;
color: #ff8992
}
.info .btn {
border-color: #3498db;
color: #3498db
}
.copyright p {
width: 100%;
color: #919191;
text-align: center;
font-size: 10px
}
.system-message .btn-grey {
border-color: #bbb;
color: #bbb
}
.clearfix:after {
clear: both;
display: block;
visibility: hidden;
height: 0;
content: "."
}
@media (max-width: 768px) {
body {
padding: 20px 0;
}
}
@media (max-width: 480px) {
.system-message h1 {
font-size: 30px;
}
}
</style>
</head>
<body>
<?php
$codeText = $code == 1 ? 'success' : ($code == 0 ? 'error' : 'info');
?>
<div class="system-message {$codeText}">
<div class="image">
<img src="/static/common/images/{$codeText}.svg" alt="" width="150" />
</div>
<h1><?php echo(strip_tags($msg));?></h1>
<p class="jump">
页面将在 <span id="wait"><?php echo($wait);?></span> 秒后自动跳转
</p>
<p class="clearfix">
<a href="#" onClick="javascript :history.back(-1);" class="btn btn-grey">返回上一页</a>
<a id="href" href="{$url}" class="btn btn-primary">立即跳转</a>
</p>
<div class="system-message {$codeText}">
<div class="image">
<img src="/static/common/images/{$codeText}.svg" alt="" width="150"/>
</div>
<script type="text/javascript">
(function(){
var wait = document.getElementById('wait'),
href = document.getElementById('href').href;
var interval = setInterval(function(){
var time = --wait.innerHTML;
if(time <= 0) {
location.href = href;
clearInterval(interval);
};
}, 1000);
})();
</script>
<h1><?php echo(strip_tags($msg));?></h1>
<p class="jump">
页面将在 <span id="wait"><?php echo($wait);?></span> 秒后自动跳转
</p>
<p class="clearfix">
<a href="#" onClick="history.back(-1);" class="btn btn-grey">返回上一页</a>
<a id="href" href="{$url}" class="btn btn-primary">立即跳转</a>
</p>
</div>
<script type="text/javascript">
(function () {
var wait = document.getElementById('wait'),
href = document.getElementById('href').href;
var interval = setInterval(function () {
var time = --wait.innerHTML;
if (time <= 0) {
location.href = href;
clearInterval(interval);
}
}, 1000);
})();
</script>
</body>
</html>

View File

@@ -15,22 +15,20 @@ trait JumpTrait
/**
* 操作成功跳转的快捷方法
* @access protected
* @param mixed $msg 提示信息
* @param mixed $data 返回的数据
* @param string $url 跳转的 URL 地址
* @param int $wait 跳转等待时间
* @param array $header 发送的 Header 信息
* @param string|null $msg 提示信息
* @param mixed|string $data 返回的数据
* @param string|null $url 跳转的 URL 地址
* @param int $wait 跳转等待时间
* @param array $header 发送的 Header 信息
* @return void
* @throws HttpResponseException
*/
protected function success($msg = '', $data = '', $url = null, $wait = 3, array $header = [])
protected function success(?string $msg = null, mixed $data = '', ?string $url = null, int $wait = 3, array $header = []): void
{
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)->__toString();
if (is_null($url)) {
$url = app()->request->server('HTTP_REFERER');
}elseif ($url) {
$url = (strpos($url, '://') || str_starts_with($url, '/')) ? $url : app('route')->buildUrl($url)->__toString();
}
$result = [
'code' => 1,
'msg' => $msg,
@@ -42,8 +40,8 @@ trait JumpTrait
$type = $this->getResponseType();
if ($type == 'html') {
$response = view(app('config')->get('app.dispatch_success_tmpl'), $result);
} elseif ($type == 'json') {
$response = view(config('app.dispatch_success_tmpl'), $result);
}else {
$response = json($result);
}
throw new HttpResponseException($response);
@@ -52,20 +50,19 @@ trait JumpTrait
/**
* 操作错误跳转的快捷方法
* @access protected
* @param mixed $msg 提示信息
* @param mixed $data 返回的数据
* @param string $url 跳转的 URL 地址
* @param int $wait 跳转等待时间
* @param array $header 发送的 Header 信息
* @param string|null $msg 提示信息
* @param mixed $data 返回的数据
* @param string|null $url 跳转的 URL 地址
* @param int $wait 跳转等待时间
* @param array $header 发送的 Header 信息
* @return void
* @throws HttpResponseException
*/
protected function error($msg = '', $data = '', $url = null, $wait = 3, array $header = [])
protected function error(?string $msg = null, mixed $data = '', ?string $url = null, int $wait = 3, array $header = []): void
{
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();
}elseif ($url) {
$url = (strpos($url, '://') || str_starts_with($url, '/')) ? $url : app('route')->buildUrl($url)->__toString();
}
$type = $this->getResponseType();
@@ -78,8 +75,8 @@ trait JumpTrait
'__token__' => request()->buildToken('__token__'),
];
if ($type == 'html') {
$response = view(app('config')->get('app.dispatch_error_tmpl'), $result);
} elseif ($type == 'json') {
$response = view(config('app.dispatch_error_tmpl'), $result);
}else {
$response = json($result);
}
throw new HttpResponseException($response);
@@ -88,15 +85,14 @@ trait JumpTrait
/**
* 返回封装后的 API 数据到客户端
* @access protected
* @param mixed $data 要返回的数据
* @param int $code 返回的 code
* @param mixed $msg 提示信息
* @param string $type 返回数据格式
* @param array $header 发送的 Header 信息
* @param mixed $data 要返回的数据
* @param int $code 返回的 code
* @param string|null $msg 提示信息
* @param string $type 返回数据格式
* @param array $header 发送的 Header 信息
* @return void
* @throws HttpResponseException
*/
protected function result($data, $code = 0, $msg = '', $type = '', array $header = [])
protected function result(mixed $data, int $code = 0, ?string $msg = '', string $type = '', array $header = []): void
{
$result = [
'code' => $code,
@@ -106,27 +102,19 @@ trait JumpTrait
];
$type = $type ?: $this->getResponseType();
$response = Response::create($result, $type)->header($header);
throw new HttpResponseException($response);
}
/**
* URL 重定向
* @access protected
* @param string $url 跳转的 URL 表达式
* @param array|int $params 其它 URL 参数
* @param int $code http code
* @param array $with 隐式传参
* @param string $url 跳转的 URL 表达式
* @param int $code http code
* @return void
* @throws HttpResponseException
*/
protected function redirect($url = [], $params = [], $code = 302)
protected function redirect(string $url = '', int $code = 302): void
{
if (is_integer($params)) {
$code = $params;
$params = [];
}
$response = Response::create($url, 'redirect', $code);
throw new HttpResponseException($response);
}
@@ -136,7 +124,7 @@ trait JumpTrait
* @access protected
* @return string
*/
protected function getResponseType()
protected function getResponseType(): string
{
return (request()->isJson() || request()->isAjax() || request()->isPost()) ? 'json' : 'html';
}

View File

@@ -18,17 +18,19 @@ class Install extends BaseController
$installPath = config_path() . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR;
$errorInfo = null;
if (is_file($installPath . 'lock' . DIRECTORY_SEPARATOR . 'install.lock')) {
// 如果你已经成功安装了后台系统 并且不想再次出现安装界面,可以把下面跳转注释取消
// $this->redirect('/');
$isInstall = true;
$errorInfo = '已安装系统,如需重新安装请删除文件:/config/install/lock/install.lock或者删除 /install 路由';
} elseif (version_compare(phpversion(), '8.0.0', '<')) {
}elseif (version_compare(phpversion(), '8.0.0', '<')) {
$errorInfo = 'PHP版本不能小于8.0.0';
} elseif (!extension_loaded("PDO")) {
}elseif (!extension_loaded("PDO")) {
$errorInfo = '当前未开启PDO无法进行安装';
}
if (!$request->isAjax()) {
$currentHost = '://';
$result = compact('errorInfo', 'currentHost', 'isInstall');
return view('', $result);
return view('index/install/index', $result);
}
if ($errorInfo) $this->error($errorInfo);
$charset = 'utf8mb4';
@@ -53,9 +55,9 @@ class Install extends BaseController
}
if (strlen($adminUrl) < 2) {
$validateError = '后台的地址不能小于2位数';
} elseif (strlen($password) < 5) {
}elseif (strlen($password) < 5) {
$validateError = '管理员密码不能小于5位数';
} elseif (strlen($username) < 4) {
}elseif (strlen($username) < 4) {
$validateError = '管理员账号不能小于4位数';
}
if (!empty($validateError)) $this->error($validateError);
@@ -110,7 +112,7 @@ class Install extends BaseController
!is_dir($installPath) && @mkdir($installPath);
!is_dir($installPath . 'lock' . DIRECTORY_SEPARATOR) && @mkdir($installPath . 'lock' . DIRECTORY_SEPARATOR);
@file_put_contents($installPath . 'lock' . DIRECTORY_SEPARATOR . 'install.lock', date('Y-m-d H:i:s'));
} catch (\Exception|\PDOException|\Throwable $e) {
}catch (\Exception|\PDOException|\Throwable $e) {
$this->error("系统安装失败:" . $e->getMessage());
}
return true;
@@ -160,7 +162,7 @@ class Install extends BaseController
$con = mysqli_connect($config['host'] ?? '127.0.0.1', $config['username'] ?? 'root', $config['password'] ?? '', null, $config['port'] ?? '');
mysqli_query($con, "CREATE DATABASE IF NOT EXISTS `{$database}` DEFAULT CHARACTER SET {$config['charset']} COLLATE=utf8mb4_general_ci");
mysqli_close($con);
} catch (\Throwable $e) {
}catch (\Throwable $e) {
return false;
}
return true;
@@ -170,12 +172,12 @@ class Install extends BaseController
{
try {
$check = Db::query("SELECT * FROM information_schema.schemata WHERE schema_name='{$database}'");
} catch (\Throwable $exception) {
}catch (\Throwable $exception) {
$check = false;
}
if (empty($check)) {
return false;
} else {
}else {
return true;
}
}
@@ -191,7 +193,7 @@ class Install extends BaseController
if (version_compare($_version, '5.7.0', '<')) {
$this->error('mysql版本最低要求 5.7.x');
}
} catch (\mysqli_sql_exception $e) {
}catch (\mysqli_sql_exception $e) {
$this->error($e->getMessage());
}
return true;

View File

@@ -6,5 +6,5 @@ return [
// 多语言加载
// \think\middleware\LoadLangPack::class,
// Session初始化
\think\middleware\SessionInit::class
\think\middleware\SessionInit::class
];

View File

@@ -1,7 +1,9 @@
<?php
declare (strict_types=1);
use app\AppService;
// 系统服务定义文件
// 服务在完成全局初始化之后执行
return [
0 => 'think\\captcha\\CaptchaService',
1 => 'think\\app\\Service',
];
AppService::class,
];

View File

@@ -1,58 +1,63 @@
{
"name": "wolfcode/easyadmin8",
"url": "https://github.com/wolf-leo/EasyAdmin8",
"description": "基于ThinkPHP8.0和Layui的快速开发的后台管理系统。",
"type": "project",
"keywords": [
"thinkphp",
"easyadmin",
"admin"
],
"homepage": "https://easyadmin8.top/",
"license": "MIT",
"authors": [
{
"name": "wolfcode"
}
],
"require": {
"php": ">=8.0.0",
"topthink/framework": "8.0.3",
"topthink/think-orm": "^3.0",
"topthink/think-multi-app": "^1.0",
"topthink/think-view": "^2.0",
"topthink/think-captcha": "^3.0",
"topthink/think-filesystem": "^2.0",
"aliyuncs/oss-sdk-php": "^2.6",
"qcloud/cos-sdk-v5": "^2.6",
"alibabacloud/client": "^1.5",
"jianyan74/php-excel": "^1.0.2",
"doctrine/annotations": "^1.13",
"phpoffice/phpspreadsheet": "^1.28",
"myclabs/php-enum": "^1.8",
"ext-json": "*",
"qiniu/php-sdk": "v7.11.0"
},
"require-dev": {
"symfony/var-dumper": "^4.2",
"eaglewu/swoole-ide-helper": "dev-master"
},
"autoload": {
"psr-4": {
"app\\": "app"
"name": "topthink/think",
"description": "the new thinkphp framework",
"type": "project",
"keywords": [
"framework",
"thinkphp",
"ORM"
],
"homepage": "https://www.thinkphp.cn/",
"license": "Apache-2.0",
"authors": [
{
"name": "liu21st",
"email": "liu21st@gmail.com"
},
{
"name": "yunwuxin",
"email": "448901948@qq.com"
}
],
"require": {
"php": ">=8.0.0",
"topthink/framework": "^8.0",
"topthink/think-orm": "^3.0",
"topthink/think-multi-app": "^1.0",
"topthink/think-view": "^2.0",
"topthink/think-captcha": "^3.0",
"topthink/think-filesystem": "^2.0",
"aliyuncs/oss-sdk-php": "^2.6",
"qcloud/cos-sdk-v5": "^2.6",
"jianyan74/php-excel": "^1.0.2",
"doctrine/annotations": "^1.13",
"phpoffice/phpspreadsheet": "^1.28",
"myclabs/php-enum": "^1.8",
"ext-json": "*",
"qiniu/php-sdk": "v7.11.0",
"ext-mysqli": "*",
"ext-pdo": "*",
"wolf-leo/phplogviewer": "^0.05.0"
},
"psr-0": {
"": "extend/"
"require-dev": {
"symfony/var-dumper": ">=4.2",
"topthink/think-trace": "^1.0"
},
"autoload": {
"psr-4": {
"app\\": "app"
},
"psr-0": {
"": "extend/"
}
},
"config": {
"preferred-install": "dist"
},
"scripts": {
"post-autoload-dump": [
"@php think service:discover",
"@php think vendor:publish"
]
}
},
"config": {
"preferred-install": "dist",
"secure-http": false
},
"scripts": {
"post-autoload-dump": [
"@php think service:discover",
"@php think vendor:publish"
]
}
}

View File

@@ -1,14 +0,0 @@
<?php
return [
// 自动加载,插件命令行模式下必须
'autoload' => true,
// 默认插件入口路径
'path' => 'addons',
// 默认方法
'default_action' => 'index',
];

View File

@@ -7,35 +7,32 @@ use think\facade\Env;
return [
// 应用地址
'app_host' => Env::get('APP.HOST', ''),
'app_host' => env('APP_HOST', ''),
// 应用的命名空间
'app_namespace' => '',
// 是否启用路由
'with_route' => true,
// 是否启用事件
'with_event' => true,
// 开启应用快速访问
'app_express' => true,
// 默认应用
'default_app' => 'index',
// 默认时区
'default_timezone' => 'Asia/Shanghai',
// 应用映射(自动多应用模式有效)
'app_map' => [
Env::get('EASYADMIN.ADMIN', 'admin') => 'admin',
],
// 后台别名
'admin_alias_name' => Env::get('EASYADMIN.ADMIN', 'admin'),
// 域名绑定(自动多应用模式有效)
'domain_bind' => [],
// 禁止URL访问的应用列表自动多应用模式有效
'deny_app_list' => ['common'],
// 异常页面的模板文件
'exception_tmpl' => Env::get('APP_DEBUG') == 1 ? app()->getThinkPath() . 'tpl/think_exception.tpl' : app()->getBasePath() . 'common' . DIRECTORY_SEPARATOR . 'tpl' . DIRECTORY_SEPARATOR . 'think_exception.tpl',
// 跳转页面的成功模板文件
'dispatch_success_tmpl' => app()->getBasePath() . 'common' . DIRECTORY_SEPARATOR . 'tpl' . DIRECTORY_SEPARATOR . 'dispatch_jump.tpl',
// 跳转页面的失败模板文件
'dispatch_error_tmpl' => app()->getBasePath() . 'common' . DIRECTORY_SEPARATOR . 'tpl' . DIRECTORY_SEPARATOR . 'dispatch_jump.tpl',
// 错误显示信息,非调试模式有效
'error_message' => '页面错误!请稍后再试~',
// 显示错误信息

View File

@@ -1,14 +1,11 @@
<?php
use think\facade\Env;
// +----------------------------------------------------------------------
// | 缓存设置
// +----------------------------------------------------------------------
return [
// 默认缓存驱动
'default' => Env::get('CACHE.DRIVER', 'file'),
'default' => 'file',
// 缓存连接方式配置
'stores' => [
@@ -18,7 +15,7 @@ return [
// 缓存保存目录
'path' => '',
// 缓存前缀
'prefix' => '',
'prefix' => 'EA8TP', // 主要是为了区分不同版本安装后数据的残留
// 缓存有效期 0表示永久缓存
'expire' => 0,
// 缓存标签前缀

View File

@@ -7,7 +7,7 @@ return [
//验证码位数
'length' => 4,
// 验证码字符集合
'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY',
'codeSet' => '1234567890',
// 验证码过期时间
'expire' => 1800,
// 是否使用中文验证码
@@ -17,7 +17,7 @@ return [
// 是否使用背景图
'useImgBg' => false,
//验证码字符大小
'fontSize' => 50,
'fontSize' => 25,
// 是否使用混淆曲线
'useCurve' => true,
//是否添加杂点

View File

@@ -3,10 +3,12 @@
// | 控制台配置
// +----------------------------------------------------------------------
return [
// 指令定义
'commands' => [
'curd' => 'app\common\command\Curd',
'node' => 'app\common\command\Node',
'OssStatic' => 'app\common\command\OssStatic',
'curd' => 'app\common\command\Curd',
'crud' => 'app\common\command\Curd',
'node' => 'app\common\command\Node',
],
];

View File

@@ -15,4 +15,6 @@ return [
'httponly' => false,
// 是否使用 setcookie
'setcookie' => true,
// samesite 设置,支持 'strict' 'lax'
'samesite' => '',
];

View File

@@ -1,10 +1,8 @@
<?php
use think\facade\Env;
return [
// 默认使用的数据库连接配置
'default' => Env::get('DATABASE.DRIVER', 'mysql'),
'default' => env('DB_DRIVER', 'mysql'),
// 自定义时间查询规则
'time_query_rule' => [],
@@ -17,46 +15,47 @@ return [
// 时间字段取出后的默认时间格式
'datetime_format' => 'Y-m-d H:i:s',
// 时间字段配置 配置格式create_time,update_time
'datetime_field' => '',
// 数据库连接配置信息
'connections' => [
'mysql' => [
// 数据库类型
'type' => Env::get('DATABASE.TYPE', 'mysql'),
'type' => env('DB_TYPE', 'mysql'),
// 服务器地址
'hostname' => Env::get('DATABASE.HOSTNAME', '127.0.0.1'),
'hostname' => env('DB_HOST', '127.0.0.1'),
// 数据库名
'database' => Env::get('DATABASE.DATABASE', 'easyadmin8'),
'database' => env('DB_NAME', ''),
// 用户名
'username' => Env::get('DATABASE.USERNAME', 'root'),
'username' => env('DB_USER', 'root'),
// 密码
'password' => Env::get('DATABASE.PASSWORD', 'root'),
'password' => env('DB_PASS', ''),
// 端口
'hostport' => Env::get('DATABASE.HOSTPORT', '3306'),
'hostport' => env('DB_PORT', '3306'),
// 数据库连接参数
'params' => [],
'params' => [],
// 数据库编码默认采用utf8
'charset' => Env::get('DATABASE.CHARSET', 'utf8'),
'charset' => env('DB_CHARSET', 'utf8'),
// 数据库表前缀
'prefix' => Env::get('DATABASE.PREFIX', 'ea8_'),
'prefix' => env('DB_PREFIX', ''),
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
'fields_strict' => true,
// 是否需要断线重连
'break_reconnect' => false,
'break_reconnect' => false,
// 监听SQL
'trigger_sql' => true,
'trigger_sql' => env('APP_DEBUG', true),
// 开启字段缓存
'fields_cache' => false,
// 字段缓存路径
'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR,
'fields_cache' => false,
],
// 更多的数据库配置信息

View File

@@ -1,10 +1,8 @@
<?php
use think\facade\Env;
return [
// 默认磁盘
'default' => Env::get('FILESYSTEM.DRIVER', 'local'),
'default' => 'local',
// 磁盘列表
'disks' => [
'local' => [
@@ -15,7 +13,7 @@ return [
// 磁盘类型
'type' => 'local',
// 磁盘路径
'root' => app()->getRootPath() . 'public',
'root' => app()->getRootPath() . 'public/storage',
// 磁盘路径对应的外部URL路径
'url' => '/storage',
// 可见性

2
config/install/lock/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
install.lock
!.gitignore

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