# 🚀 插件开发完整指南
> 本指南提供了完整的插件开发、页面集成和导航结构的详细说明,帮助开发者快速创建功能丰富的插件。
## 📋 目录
- [系统概述](#系统概述)
- [快速开始](#快速开始)
- [插件结构](#插件结构)
- [导航系统](#导航系统)
- [页面开发](#页面开发)
- [AJAX处理](#ajax处理)
- [数据库操作](#数据库操作)
- [钩子系统](#钩子系统)
- [示例插件](#示例插件)
- [最佳实践](#最佳实践)
- [故障排除](#故障排除)
---
## 🎯 系统概述
本插件系统提供了完整的页面功能集成方案,支持:
- ✅ **智能导航集成** - 自动在用户中心生成导航菜单
- ✅ **灵活页面路由** - 支持多页面插件和单页面插件
- ✅ **统一AJAX处理** - 标准化的请求处理机制
- ✅ **数据库集成** - 完整的数据持久化支持
- ✅ **钩子系统** - 与系统事件深度集成
- ✅ **权限控制** - 完善的用户权限管理
### 核心文件
| 文件 | 功能 |
|------|------|
| `user/plugin_page.php` | 插件页面路由系统 |
| `user/plugin_ajax.php` | 插件AJAX请求处理器 |
| `user/index.php` | 用户中心主页(增强导航) |
| `admin/plugin.php` | 插件管理后台 |
| `includes/PluginManager.php` | 插件管理器 |
---
## 🚀 快速开始
### 1. 创建插件目录
```bash
mkdir plugin/my_plugin
cd plugin/my_plugin
```
### 2. 创建基本文件
```
plugin/my_plugin/
├── config.json # 插件配置
├── index.php # 插件主文件
├── ajax.php # AJAX处理
└── pages/ # 用户页面
└── index.php # 主页面
```
### 3. 配置文件示例
```json
{
"name": "我的插件",
"identifier": "my_plugin",
"version": "1.0.0",
"author": "开发者",
"description": "插件描述",
"icon": "layui-icon-component",
"user_pages": [
{
"action": "index",
"title": "主页面",
"icon": "layui-icon-home"
}
]
}
```
### 4. 扫描并启用
1. 访问 `admin/plugin.php`
2. 点击"扫描插件"
3. 启用您的插件
4. 在用户中心查看效果
---
## 📁 插件结构
### 标准目录结构
```
plugin/your_plugin/
├── config.json # 📄 插件配置文件
├── index.php # 🔧 插件主文件(钩子处理)
├── ajax.php # 🌐 AJAX请求处理
├── pages/ # 📱 用户页面目录
│ ├── index.php # 🏠 主页面
│ ├── feature1.php # ⚙️ 功能页面1
│ └── feature2.php # ⚙️ 功能页面2
├── assets/ # 🎨 静态资源(可选)
│ ├── css/
│ ├── js/
│ └── images/
└── README.md # 📖 插件说明(可选)
```
### 配置文件详解 (config.json)
```json
{
"name": "插件显示名称",
"identifier": "plugin_unique_id",
"version": "1.0.0",
"author": "作者名称",
"description": "插件功能描述",
"icon": "layui-icon-component",
"user_pages": [
{
"action": "index",
"title": "主页面",
"icon": "layui-icon-home"
},
{
"action": "settings",
"title": "设置",
"icon": "layui-icon-set"
}
],
"config": [
{
"name": "enable_feature",
"title": "启用功能",
"type": "switch",
"default": "1",
"tips": "是否启用此功能"
},
{
"name": "api_key",
"title": "API密钥",
"type": "input",
"default": "",
"tips": "请输入API密钥"
}
]
}
```
**字段说明:**
| 字段 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `name` | string | ✅ | 插件显示名称 |
| `identifier` | string | ✅ | 插件唯一标识符 |
| `version` | string | ✅ | 插件版本号 |
| `author` | string | ❌ | 作者信息 |
| `description` | string | ❌ | 插件描述 |
| `icon` | string | ❌ | 插件图标(LayUI图标类名) |
| `user_pages` | array | ❌ | 用户页面配置 |
| `config` | array | ❌ | 插件配置项 |
---
## 🧭 导航系统
### 导航生成规则
插件导航系统支持一级导航和二级导航的灵活组合:
#### 🔹 情况1:有 index + 子页面
**配置:**
```json
{
"name": "个人工具箱",
"icon": "layui-icon-util",
"user_pages": [
{
"action": "index",
"title": "工具箱",
"icon": "layui-icon-util"
},
{
"action": "qrcode",
"title": "二维码生成"
},
{
"action": "password",
"title": "密码生成器"
}
]
}
```
**生成效果:**
```
📁 个人工具箱 ▼
├─ 主页面 ← index页面
├─ 二维码生成 ← 子功能
└─ 密码生成器 ← 子功能
```
#### 🔹 情况2:只有 index 页面
**配置:**
```json
{
"user_pages": [
{
"action": "index",
"title": "工具箱",
"icon": "layui-icon-util"
}
]
}
```
**生成效果:**
```
📁 工具箱 ← 简单一级导航
```
#### 🔹 情况3:无 index,多页面
**配置:**
```json
{
"name": "用户中心工具",
"icon": "layui-icon-user",
"user_pages": [
{
"action": "profile",
"title": "个人资料管理"
},
{
"action": "security",
"title": "安全设置"
}
]
}
```
**生成效果:**
```
📁 用户中心工具 ▼ ← 使用插件名
├─ 个人资料管理
└─ 安全设置
```
#### 🔹 情况4:无 index,单页面
**配置:**
```json
{
"name": "文件管理",
"user_pages": [
{
"action": "upload",
"title": "文件上传"
}
]
}
```
**生成效果:**
```
📁 文件管理 ← 直接访问功能
```
### 导航配置最佳实践
#### 1. **工具箱类插件**(推荐有 index)
```json
{
"name": "实用工具箱",
"icon": "layui-icon-util",
"user_pages": [
{
"action": "index",
"title": "工具箱",
"icon": "layui-icon-util"
},
{
"action": "qrcode",
"title": "二维码生成"
},
{
"action": "password",
"title": "密码生成器"
}
]
}
```
#### 2. **功能模块类插件**(可以没有 index)
```json
{
"name": "账户管理",
"icon": "layui-icon-user",
"user_pages": [
{
"action": "profile",
"title": "个人资料"
},
{
"action": "security",
"title": "安全设置"
}
]
}
```
#### 3. **单功能插件**(简单导航)
```json
{
"name": "文件上传",
"icon": "layui-icon-upload",
"user_pages": [
{
"action": "upload",
"title": "文件上传",
"icon": "layui-icon-upload"
}
]
}
```
---
## 📱 页面开发
### 页面模板
创建 `pages/xxx.php` 文件:
```php
<?php
/**
* 插件页面模板
*/
if(!defined('IN_CRONLITE')) exit('Access Denied');
// 可用变量:
// $plugin_config - 插件配置数组
// $plugin_info - 插件信息数组
// $title - 页面标题
// $userrow - 当前用户信息
// $conf - 系统配置
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><?=$title?> - <?=$conf['title']?></title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="../../assets/libs/layui/css/layui.css">
<style>
.plugin-container {
padding: 15px;
}
.feature-card {
margin-bottom: 15px;
}
.stats-item {
text-align: center;
padding: 20px;
}
</style>
</head>
<body>
<div class="layui-fluid plugin-container">
<!-- 页面头部 -->
<div class="layui-card">
<div class="layui-card-header">
<i class="layui-icon layui-icon-component"></i>
<?=$title?>
</div>
<div class="layui-card-body">
<!-- 主要内容区域 -->
<div class="layui-row layui-col-space15">
<div class="layui-col-md8">
<!-- 功能区域 -->
<div class="layui-card feature-card">
<div class="layui-card-header">功能操作</div>
<div class="layui-card-body">
<form class="layui-form" lay-filter="pluginForm">
<div class="layui-form-item">
<label class="layui-form-label">输入内容</label>
<div class="layui-input-block">
<input type="text" name="content" placeholder="请输入内容" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="submit" class="layui-btn" lay-submit lay-filter="submit">
<i class="layui-icon layui-icon-ok"></i> 执行操作
</button>
</div>
</div>
</form>
</div>
</div>
<!-- 结果显示区域 -->
<div class="layui-card">
<div class="layui-card-header">操作结果</div>
<div class="layui-card-body" id="resultArea">
<div class="layui-text">
<p>操作结果将在这里显示...</p>
</div>
</div>
</div>
</div>
<div class="layui-col-md4">
<!-- 侧边栏 -->
<div class="layui-card">
<div class="layui-card-header">使用统计</div>
<div class="layui-card-body">
<div class="stats-item">
<div class="layui-text">
<h3 id="todayCount">0</h3>
<p>今日使用</p>
</div>
</div>
<div class="stats-item">
<div class="layui-text">
<h3 id="totalCount">0</h3>
<p>总计使用</p>
</div>
</div>
</div>
</div>
<!-- 帮助信息 -->
<div class="layui-card">
<div class="layui-card-header">使用说明</div>
<div class="layui-card-body">
<div class="layui-text">
<p>1. 在输入框中输入内容</p>
<p>2. 点击执行操作按钮</p>
<p>3. 查看操作结果</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="../../assets/libs/layui/layui.js"></script>
<script>
layui.use(['form', 'layer'], function(){
var form = layui.form;
var layer = layui.layer;
// 加载统计数据
loadStats();
// 表单提交
form.on('submit(submit)', function(data){
var loadIndex = layer.load(2);
$.ajax({
type: 'POST',
url: '../plugin_ajax.php',
data: {
plugin: '<?=$plugin_info['identifier']?>',
action: 'process_content',
content: data.field.content
},
dataType: 'json',
success: function(res) {
layer.close(loadIndex);
if(res.code == 0) {
$('#resultArea').html('<div class="layui-text"><p>' + res.data + '</p></div>');
layer.msg('操作成功!', {icon: 1});
loadStats(); // 重新加载统计
} else {
layer.msg(res.msg, {icon: 2});
}
},
error: function() {
layer.close(loadIndex);
layer.msg('请求失败,请重试!', {icon: 2});
}
});
return false;
});
// 加载统计数据
function loadStats() {
$.ajax({
type: 'POST',
url: '../plugin_ajax.php',
data: {
plugin: '<?=$plugin_info['identifier']?>',
action: 'get_stats'
},
dataType: 'json',
success: function(res) {
if(res.code == 0) {
$('#todayCount').text(res.data.today || 0);
$('#totalCount').text(res.data.total || 0);
}
}
});
}
});
</script>
</body>
</html>
```
### 页面开发要点
1. **安全检查**:页面开头必须检查 `IN_CRONLITE` 常量
2. **响应式设计**:使用 LayUI 的栅格系统适配不同屏幕
3. **用户体验**:提供加载提示、操作反馈和错误处理
4. **数据交互**:通过 AJAX 与后端交互,避免页面刷新
---
## 🌐 AJAX处理
### AJAX处理文件 (ajax.php)
```php
<?php
/**
* 插件AJAX处理
*/
if(!defined('IN_CRONLITE')) exit('Access Denied');
$action = $GLOBALS['plugin_action'];
$plugin_config = $GLOBALS['plugin_config'];
$plugin_info = $GLOBALS['plugin_info'];
switch($action) {
case 'process_content':
// 处理内容
$content = daddslashes($_POST['content']);
if(empty($content)) {
json_format(['code' => '-1', 'msg' => '内容不能为空!']);
}
// 记录使用统计
recordUsage('process_content');
// 处理业务逻辑
$result = processContent($content);
json_format([
'code' => 0,
'msg' => '处理成功',
'data' => $result
]);
break;
case 'get_stats':
// 获取使用统计
$stats = getUsageStats();
json_format([
'code' => 0,
'data' => $stats
]);
break;
default:
json_format(['code' => '-1', 'msg' => '未知操作!']);
break;
}
/**
* 处理内容的业务逻辑
*/
function processContent($content) {
// 这里实现具体的业务逻辑
return "处理结果:" . $content;
}
/**
* 记录使用统计
*/
function recordUsage($action) {
global $DB, $dbconfig, $userrow, $date;
$tableName = $dbconfig['dbqz'] . '_plugin_stats';
$userId = $userrow['id'];
$today = date('Y-m-d');
// 确保统计表存在
createStatsTable();
try {
// 检查今天是否已有记录
$existing = $DB->getRow("SELECT id, use_count FROM `{$tableName}` WHERE user_id='{$userId}' AND action='{$action}' AND use_date='{$today}'");
if($existing) {
// 更新使用次数
$newCount = $existing['use_count'] + 1;
$DB->update($tableName, [
'use_count' => $newCount,
'updated_at' => $date
], ['id' => $existing['id']]);
} else {
// 插入新记录
$data = [
'user_id' => $userId,
'action' => $action,
'use_date' => $today,
'use_count' => 1,
'created_at' => $date,
'updated_at' => $date
];
$DB->insert($tableName, $data);
}
} catch(Exception $e) {
// 忽略统计错误,不影响主功能
error_log("recordUsage error: " . $e->getMessage());
}
}
/**
* 获取使用统计
*/
function getUsageStats() {
global $DB, $dbconfig, $userrow;
$tableName = $dbconfig['dbqz'] . '_plugin_stats';
$userId = $userrow['id'];
$today = date('Y-m-d');
try {
// 今日使用次数
$todayCount = $DB->getColumn("SELECT SUM(use_count) FROM `{$tableName}` WHERE user_id='{$userId}' AND use_date='{$today}'") ?: 0;
// 总使用次数
$totalCount = $DB->getColumn("SELECT SUM(use_count) FROM `{$tableName}` WHERE user_id='{$userId}'") ?: 0;
return [
'today' => $todayCount,
'total' => $totalCount
];
} catch(Exception $e) {
return ['today' => 0, 'total' => 0];
}
}
/**
* 创建统计表
*/
function createStatsTable() {
global $DB, $dbconfig;
$tableName = $dbconfig['dbqz'] . '_plugin_stats';
try {
$DB->exec("CREATE TABLE IF NOT EXISTS `{$tableName}` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`action` varchar(50) NOT NULL,
`use_date` date NOT NULL,
`use_count` int(11) DEFAULT 1,
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_usage` (`user_id`, `action`, `use_date`),
KEY `idx_user_date` (`user_id`, `use_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='插件使用统计表'");
} catch(Exception $e) {
error_log("createStatsTable error: " . $e->getMessage());
}
}
?>
```
### AJAX请求规范
#### 前端请求格式
```javascript
$.ajax({
type: 'POST',
url: '../plugin_ajax.php',
data: {
plugin: 'plugin_identifier', // 插件标识符
action: 'action_name', // 操作名称
// 其他参数...
},
dataType: 'json',
success: function(data) {
if(data.code == 0) {
// 成功处理
} else {
// 错误处理
}
}
});
```
#### 后端响应格式
```php
// 成功响应
json_format([
'code' => 0,
'msg' => '操作成功',
'data' => $result
]);
// 错误响应
json_format([
'code' => '-1',
'msg' => '错误信息'
]);
```
---
## 🗄️ 数据库操作
### 创建插件数据表
```php
/**
* 在插件主文件 index.php 中创建表
*/
function createPluginTables() {
global $DB, $dbconfig;
$tableName = $dbconfig['dbqz'] . '_my_plugin_data';
$sql = "CREATE TABLE IF NOT EXISTS `{$tableName}` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`title` varchar(255) NOT NULL,
`content` text,
`status` tinyint(1) DEFAULT 1,
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='我的插件数据表'";
try {
$DB->exec($sql);
return true;
} catch(Exception $e) {
error_log("创建表失败: " . $e->getMessage());
return false;
}
}
```
### 标准数据库操作
```php
// 插入数据
$data = [
'user_id' => $userrow['id'],
'title' => $title,
'content' => $content,
'created_at' => $date
];
$result = $DB->insert($tableName, $data);
// 更新数据
$updateData = [
'title' => $newTitle,
'updated_at' => $date
];
$result = $DB->update($tableName, $updateData, ['id' => $id]);
// 查询数据
$item = $DB->getRow("SELECT * FROM `{$tableName}` WHERE id='{$id}' AND user_id='{$userId}'");
// 删除数据
$result = $DB->delete($tableName, "id='{$id}' AND user_id='{$userId}'");
// 分页查询
$page = intval($_POST['page']) ?: 1;
$limit = 10;
$offset = ($page - 1) * $limit;
$count = $DB->getColumn("SELECT COUNT(*) FROM `{$tableName}` WHERE user_id='{$userId}'");
$list = $DB->query("SELECT * FROM `{$tableName}` WHERE user_id='{$userId}' ORDER BY id DESC LIMIT {$offset},{$limit}");
```
---
## 🔗 钩子系统
### 插件主文件 (index.php)
```php
<?php
/**
* 插件主文件 - 钩子处理
*/
if(!defined('IN_CRONLITE')) exit('Access Denied');
/**
* 插件初始化
*/
function my_plugin_init() {
// 创建数据表
createPluginTables();
// 注册钩子
add_hook('user_login', 'my_plugin_user_login');
add_hook('page_visit', 'my_plugin_page_visit');
}
/**
* 用户登录钩子
*/
function my_plugin_user_login($userInfo) {
// 记录用户登录
recordUserLogin($userInfo);
return true;
}
/**
* 页面访问钩子
*/
function my_plugin_page_visit($pageInfo) {
// 记录页面访问
recordPageVisit($pageInfo);
return true;
}
/**
* 插件卸载清理
*/
function my_plugin_uninstall() {
global $DB, $dbconfig;
// 删除插件数据表
$tableName = $dbconfig['dbqz'] . '_my_plugin_data';
$DB->exec("DROP TABLE IF EXISTS `{$tableName}`");
return true;
}
// 插件初始化
my_plugin_init();
?>
```
### 可用钩子事件
| 钩子名称 | 触发时机 | 参数 |
|----------|----------|------|
| `user_login` | 用户登录成功 | 用户信息数组 |
| `user_register` | 用户注册成功 | 用户信息数组 |
| `page_visit` | 页面访问 | 页面信息数组 |
| `order_create` | 订单创建 | 订单信息数组 |
| `payment_success` | 支付成功 | 支付信息数组 |
---
## 📚 示例插件
### 个人工具箱插件
我们提供了一个完整的示例插件"个人工具箱",包含:
#### 功能特性
- 🏠 **工具箱主页** - 工具概览和使用统计
- 🔗 **二维码生成器** - 支持文本、网址、WiFi、联系人等
- 🔐 **密码生成器** - 可自定义长度、字符类型、强度分析
- 📊 **使用统计** - 记录和展示使用数据
- ⚙️ **配置管理** - 灵活的插件配置选项
#### 目录结构
```
plugin/user_toolbox/
├── config.json # 插件配置
├── index.php # 主文件
├── ajax.php # AJAX处理
└── pages/ # 页面文件
├── index.php # 主页面
├── qrcode.php # 二维码生成
└── password.php # 密码生成器
```
#### 核心代码片段
**二维码生成功能:**
```php
case 'generate_qrcode':
$text = daddslashes($_POST['text']);
$size = intval($_POST['size']) ?: 200;
if(empty($text)) {
json_format(['code' => '-1', 'msg' => '内容不能为空!']);
}
// 生成二维码
$qrcode = generateQRCode($text, $size);
// 记录使用统计
recordToolUsage('qrcode');
json_format([
'code' => 0,
'msg' => '生成成功',
'data' => $qrcode
]);
break;
```
**密码生成功能:**
```php
case 'generate_password':
$length = intval($_POST['length']) ?: 12;
$includeNumbers = $_POST['numbers'] == '1';
$includeSymbols = $_POST['symbols'] == '1';
$password = generateSecurePassword($length, $includeNumbers, $includeSymbols);
$strength = analyzePasswordStrength($password);
recordToolUsage('password');
json_format([
'code' => 0,
'data' => [
'password' => $password,
'strength' => $strength
]
]);
break;
```
---
## 💡 最佳实践
### 1. 安全性
#### 输入验证
```php
// 过滤用户输入
$content = daddslashes($_POST['content']);
$id = intval($_POST['id']);
// 验证用户权限
if($islogins != 1) {
loginsmsg('请登录后再操作!');
}
// 检查数据所有权
$item = $DB->getRow("SELECT * FROM `{$tableName}` WHERE id='{$id}' AND user_id='{$userrow['id']}'");
if(!$item) {
json_format(['code' => '-1', 'msg' => '数据不存在或无权限!']);
}
```
#### 文件安全
```php
// 页面文件开头
if(!defined('IN_CRONLITE')) exit('Access Denied');
// 文件上传验证
$allowedTypes = ['jpg', 'png', 'gif'];
$fileExt = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
if(!in_array($fileExt, $allowedTypes)) {
json_format(['code' => '-1', 'msg' => '不支持的文件类型!']);
}
```
### 2. 性能优化
#### 数据库优化
```php
// 使用索引
$sql = "CREATE INDEX idx_user_date ON `{$tableName}` (user_id, created_at)";
// 分页查询
$limit = min(intval($_POST['limit']) ?: 10, 100); // 限制最大查询数量
// 缓存查询结果
$cacheKey = "plugin_data_{$userId}_{$page}";
$result = cache_get($cacheKey);
if(!$result) {
$result = $DB->query($sql);
cache_set($cacheKey, $result, 300); // 缓存5分钟
}
```
#### 前端优化
```javascript
// 防抖处理
var searchTimer;
$('#searchInput').on('input', function() {
clearTimeout(searchTimer);
searchTimer = setTimeout(function() {
performSearch();
}, 500);
});
// 加载状态管理
var isLoading = false;
function loadData() {
if(isLoading) return;
isLoading = true;
$.ajax({
// ...
complete: function() {
isLoading = false;
}
});
}
```
### 3. 用户体验
#### 操作反馈
```javascript
// 成功提示
layer.msg('操作成功!', {icon: 1, time: 2000});
// 错误提示
layer.msg('操作失败:' + res.msg, {icon: 2, time: 3000});
// 加载提示
var loadIndex = layer.load(2, {shade: [0.3, '#000']});
// 操作完成后
layer.close(loadIndex);
// 确认对话框
layer.confirm('确定要删除这条记录吗?', {icon: 3}, function(index) {
// 执行删除操作
layer.close(index);
});
```
#### 响应式设计
```css
/* 移动端适配 */
@media screen and (max-width: 768px) {
.layui-col-md4 {
margin-top: 15px;
}
.plugin-container {
padding: 10px;
}
.layui-card {
margin-bottom: 10px;
}
}
```
### 4. 代码规范
#### 命名规范
```php
// 函数命名:小写+下划线
function generate_qr_code($text, $size) {}
// 变量命名:小写+下划线
$user_id = $userrow['id'];
$table_name = $dbconfig['dbqz'] . '_plugin_data';
// 常量命名:大写+下划线
define('PLUGIN_VERSION', '1.0.0');
```
#### 注释规范
```php
/**
* 生成二维码
* @param string $text 二维码内容
* @param int $size 二维码尺寸
* @return string 二维码图片base64编码
*/
function generateQRCode($text, $size = 200) {
// 实现代码...
}
```
---
## 🔧 故障排除
### 常见问题
#### 1. 插件页面不显示
**可能原因:**
- 插件未启用
- `config.json` 配置错误
- 页面文件不存在
- 权限问题
**解决方法:**
```bash
# 检查插件状态
SELECT * FROM fenfa_plugins WHERE identifier='your_plugin';
# 检查文件权限
ls -la plugin/your_plugin/
# 检查配置文件
cat plugin/your_plugin/config.json | python -m json.tool
```
#### 2. AJAX请求失败
**可能原因:**
- `ajax.php` 文件不存在
- 请求参数错误
- 权限验证失败
- 数据库连接问题
**调试方法:**
```javascript
// 在浏览器控制台查看请求详情
$.ajax({
// ...
error: function(xhr, status, error) {
console.log('Status:', status);
console.log('Error:', error);
console.log('Response:', xhr.responseText);
}
});
```
#### 3. 数据库操作错误
**可能原因:**
- 表名前缀错误
- SQL语法错误
- 字段类型不匹配
- 权限不足
**调试方法:**
```php
// 开启错误日志
try {
$result = $DB->insert($tableName, $data);
} catch(Exception $e) {
error_log("Database error: " . $e->getMessage());
json_format(['code' => '-1', 'msg' => '数据库操作失败']);
}
```
#### 4. 导航不显示
**检查清单:**
- [ ] 插件已启用
- [ ] `user_pages` 配置正确
- [ ] 页面文件存在
- [ ] 用户已登录
- [ ] 浏览器缓存已清除
### 调试工具
#### 1. 插件测试页面
访问 `admin/test_plugin_system.php` 进行系统诊断
#### 2. 数据库测试脚本
```php
// plugin/your_plugin/test_db.php
<?php
include("../../includes/common.php");
echo "<h3>数据库连接测试</h3>";
try {
$tableName = $dbconfig['dbqz'] . '_test';
$DB->exec("CREATE TABLE IF NOT EXISTS `{$tableName}` (id int PRIMARY KEY)");
echo "✅ 数据库连接正常<br>";
$DB->exec("DROP TABLE `{$tableName}`");
echo "✅ 表操作正常<br>";
} catch(Exception $e) {
echo "❌ 数据库错误: " . $e->getMessage() . "<br>";
}
?>
```
#### 3. 日志查看
```bash
# 查看错误日志
tail -f /var/log/php_errors.log
# 查看访问日志
tail -f /var/log/nginx/access.log
```
---
## 📖 总结
通过本指南,您已经掌握了:
- ✅ **插件系统架构** - 了解核心文件和工作原理
- ✅ **导航系统设计** - 灵活的一级/二级导航结构
- ✅ **页面开发技巧** - 响应式设计和用户体验优化
- ✅ **AJAX处理规范** - 标准化的请求响应机制
- ✅ **数据库操作** - 安全高效的数据持久化
- ✅ **钩子系统集成** - 与系统事件深度集成
- ✅ **安全最佳实践** - 输入验证和权限控制
- ✅ **性能优化技巧** - 数据库和前端优化方案
现在您可以开始创建功能丰富、用户友好的插件了!
### 快速开始检查清单
- [ ] 创建插件目录和基本文件
- [ ] 编写 `config.json` 配置文件
- [ ] 创建页面文件和AJAX处理
- [ ] 在管理后台扫描并启用插件
- [ ] 在用户中心测试功能
- [ ] 优化用户体验和性能
### 获取帮助
如果在开发过程中遇到问题:
1. 📖 **查阅文档** - 仔细阅读本指南相关章节
2. 🔍 **检查示例** - 参考"个人工具箱"插件代码
3. 🧪 **使用调试工具** - 运行测试脚本诊断问题
4. 📝 **查看日志** - 检查错误日志获取详细信息
祝您开发愉快!🎉