文章目录[隐藏]
实战教程:在WordPress网站中添加在线个人记账与预算规划管理小程序
摘要
本教程将详细介绍如何通过WordPress代码二次开发,在您的网站上添加一个功能完整的在线个人记账与预算规划管理小程序。我们将从零开始,逐步构建一个包含收入支出记录、预算管理、数据可视化等核心功能的实用工具,帮助您的网站访客更好地管理个人财务。
目录
- 项目概述与准备工作
- WordPress开发环境搭建
- 数据库设计与表结构创建
- 用户界面设计与前端开发
- 后端API与数据处理逻辑
- 预算规划功能实现
- 数据可视化与报表生成
- 安全性与数据保护
- 性能优化与部署
- 功能扩展与维护建议
1. 项目概述与准备工作
1.1 项目目标
本项目的目标是在WordPress网站中集成一个完整的个人财务管理工具,使访客能够:
- 记录日常收入和支出
- 设置和管理预算
- 查看财务数据可视化报表
- 获得支出分类分析
- 导出财务数据
1.2 技术栈选择
- 前端:HTML5, CSS3, JavaScript (使用jQuery简化开发)
- 后端:PHP (WordPress原生支持)
- 数据库:MySQL (通过WordPress数据库操作类)
- 图表库:Chart.js (轻量级、响应式图表)
- UI框架:Bootstrap 5 (快速构建响应式界面)
1.3 准备工作
- 确保您拥有一个已安装的WordPress网站
- 具备基本的PHP、JavaScript和MySQL知识
- 准备一个代码编辑器(如VS Code、Sublime Text等)
- 备份您的WordPress网站,以防开发过程中出现问题
2. WordPress开发环境搭建
2.1 创建插件目录结构
在WordPress的wp-content/plugins/目录下创建一个新文件夹personal-finance-manager,并建立以下结构:
personal-finance-manager/
├── personal-finance-manager.php # 主插件文件
├── includes/
│ ├── class-database.php # 数据库操作类
│ ├── class-shortcodes.php # 短代码处理类
│ ├── class-api.php # API处理类
│ └── class-charts.php # 图表生成类
├── assets/
│ ├── css/
│ │ └── style.css # 样式文件
│ ├── js/
│ │ └── script.js # 前端脚本
│ └── lib/
│ └── chart.min.js # Chart.js库
├── templates/
│ ├── dashboard.php # 主仪表板模板
│ ├── add-transaction.php # 添加交易模板
│ └── budget.php # 预算管理模板
└── languages/ # 国际化文件目录
2.2 创建主插件文件
在personal-finance-manager.php中添加以下代码:
<?php
/**
* Plugin Name: 个人记账与预算规划管理
* Plugin URI: https://yourwebsite.com/
* Description: 在WordPress网站中添加在线个人记账与预算规划管理功能
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
* Text Domain: personal-finance-manager
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('PFM_VERSION', '1.0.0');
define('PFM_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('PFM_PLUGIN_URL', plugin_dir_url(__FILE__));
// 加载必要文件
require_once PFM_PLUGIN_DIR . 'includes/class-database.php';
require_once PFM_PLUGIN_DIR . 'includes/class-shortcodes.php';
require_once PFM_PLUGIN_DIR . 'includes/class-api.php';
require_once PFM_PLUGIN_DIR . 'includes/class-charts.php';
// 初始化插件
class Personal_Finance_Manager {
private static $instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->init_hooks();
}
private function init_hooks() {
// 激活/停用钩子
register_activation_hook(__FILE__, array($this, 'activate'));
register_deactivation_hook(__FILE__, array($this, 'deactivate'));
// 初始化
add_action('init', array($this, 'init'));
// 加载脚本和样式
add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
// 初始化短代码
$shortcodes = new PFM_Shortcodes();
$shortcodes->init();
}
public function activate() {
// 创建数据库表
PFM_Database::create_tables();
// 设置默认选项
update_option('pfm_version', PFM_VERSION);
}
public function deactivate() {
// 清理临时数据
// 注意:这里不删除用户数据,仅清理临时选项
delete_option('pfm_temp_data');
}
public function init() {
// 加载文本域
load_plugin_textdomain('personal-finance-manager', false, dirname(plugin_basename(__FILE__)) . '/languages');
}
public function enqueue_scripts() {
// 仅在有需要的页面加载
if (is_page('personal-finance') || has_shortcode(get_post()->post_content, 'personal_finance')) {
// 加载CSS
wp_enqueue_style('pfm-bootstrap', 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css');
wp_enqueue_style('pfm-style', PFM_PLUGIN_URL . 'assets/css/style.css', array(), PFM_VERSION);
// 加载JavaScript
wp_enqueue_script('jquery');
wp_enqueue_script('pfm-bootstrap', 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js', array('jquery'), '5.1.3', true);
wp_enqueue_script('pfm-chartjs', PFM_PLUGIN_URL . 'assets/lib/chart.min.js', array(), '3.7.0', true);
wp_enqueue_script('pfm-script', PFM_PLUGIN_URL . 'assets/js/script.js', array('jquery', 'pfm-chartjs'), PFM_VERSION, true);
// 传递数据到前端
wp_localize_script('pfm-script', 'pfm_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('pfm_nonce'),
'user_id' => get_current_user_id()
));
}
}
}
// 启动插件
Personal_Finance_Manager::get_instance();
3. 数据库设计与表结构创建
3.1 数据库表设计
我们需要创建三个主要表来存储财务数据:
- 交易记录表:存储收入和支出记录
- 预算表:存储用户设置的预算
- 分类表:存储收入和支出的分类
3.2 数据库操作类实现
在includes/class-database.php中添加以下代码:
<?php
class PFM_Database {
private static $table_prefix;
public static function init() {
global $wpdb;
self::$table_prefix = $wpdb->prefix . 'pfm_';
}
public static function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
self::$table_prefix = $wpdb->prefix . 'pfm_';
// 交易记录表
$transactions_table = self::$table_prefix . 'transactions';
$sql_transactions = "CREATE TABLE IF NOT EXISTS $transactions_table (
id INT(11) NOT NULL AUTO_INCREMENT,
user_id INT(11) NOT NULL,
type ENUM('income', 'expense') NOT NULL,
category_id INT(11) NOT NULL,
amount DECIMAL(10,2) NOT NULL,
description TEXT,
transaction_date DATE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX user_id (user_id),
INDEX transaction_date (transaction_date)
) $charset_collate;";
// 预算表
$budgets_table = self::$table_prefix . 'budgets';
$sql_budgets = "CREATE TABLE IF NOT EXISTS $budgets_table (
id INT(11) NOT NULL AUTO_INCREMENT,
user_id INT(11) NOT NULL,
category_id INT(11) NOT NULL,
amount DECIMAL(10,2) NOT NULL,
period ENUM('daily', 'weekly', 'monthly', 'yearly') DEFAULT 'monthly',
start_date DATE NOT NULL,
end_date DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX user_id (user_id)
) $charset_collate;";
// 分类表
$categories_table = self::$table_prefix . 'categories';
$sql_categories = "CREATE TABLE IF NOT EXISTS $categories_table (
id INT(11) NOT NULL AUTO_INCREMENT,
user_id INT(11) DEFAULT 0,
name VARCHAR(100) NOT NULL,
type ENUM('income', 'expense') NOT NULL,
color VARCHAR(7) DEFAULT '#007bff',
icon VARCHAR(50) DEFAULT 'fas fa-tag',
is_default TINYINT(1) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX user_id (user_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql_transactions);
dbDelta($sql_budgets);
dbDelta($sql_categories);
// 插入默认分类
self::insert_default_categories();
}
private static function insert_default_categories() {
global $wpdb;
$categories_table = self::$table_prefix . 'categories';
$default_categories = array(
// 收入分类
array('name' => '工资', 'type' => 'income', 'color' => '#28a745', 'icon' => 'fas fa-money-check-alt', 'is_default' => 1),
array('name' => '投资', 'type' => 'income', 'color' => '#20c997', 'icon' => 'fas fa-chart-line', 'is_default' => 1),
array('name' => '兼职', 'type' => 'income', 'color' => '#17a2b8', 'icon' => 'fas fa-briefcase', 'is_default' => 1),
array('name' => '其他收入', 'type' => 'income', 'color' => '#6c757d', 'icon' => 'fas fa-coins', 'is_default' => 1),
// 支出分类
array('name' => '餐饮', 'type' => 'expense', 'color' => '#dc3545', 'icon' => 'fas fa-utensils', 'is_default' => 1),
array('name' => '交通', 'type' => 'expense', 'color' => '#fd7e14', 'icon' => 'fas fa-car', 'is_default' => 1),
array('name' => '购物', 'type' => 'expense', 'color' => '#6f42c1', 'icon' => 'fas fa-shopping-cart', 'is_default' => 1),
array('name' => '住房', 'type' => 'expense', 'color' => '#e83e8c', 'icon' => 'fas fa-home', 'is_default' => 1),
array('name' => '娱乐', 'type' => 'expense', 'color' => '#20c997', 'icon' => 'fas fa-gamepad', 'is_default' => 1),
array('name' => '医疗', 'type' => 'expense', 'color' => '#007bff', 'icon' => 'fas fa-heartbeat', 'is_default' => 1),
array('name' => '教育', 'type' => 'expense', 'color' => '#17a2b8', 'icon' => 'fas fa-graduation-cap', 'is_default' => 1),
array('name' => '其他支出', 'type' => 'expense', 'color' => '#6c757d', 'icon' => 'fas fa-tags', 'is_default' => 1),
);
foreach ($default_categories as $category) {
$wpdb->insert(
$categories_table,
$category,
array('%s', '%s', '%s', '%s', '%d')
);
}
}
// 获取用户交易记录
public static function get_transactions($user_id, $limit = 50, $offset = 0, $filters = array()) {
global $wpdb;
$transactions_table = self::$table_prefix . 'transactions';
$categories_table = self::$table_prefix . 'categories';
$where_clause = "WHERE t.user_id = %d";
$where_values = array($user_id);
// 应用过滤器
if (!empty($filters['type'])) {
$where_clause .= " AND t.type = %s";
$where_values[] = $filters['type'];
}
if (!empty($filters['category_id'])) {
$where_clause .= " AND t.category_id = %d";
$where_values[] = $filters['category_id'];
}
if (!empty($filters['start_date'])) {
$where_clause .= " AND t.transaction_date >= %s";
$where_values[] = $filters['start_date'];
}
if (!empty($filters['end_date'])) {
$where_clause .= " AND t.transaction_date <= %s";
$where_values[] = $filters['end_date'];
}
$query = $wpdb->prepare(
"SELECT t.*, c.name as category_name, c.color as category_color, c.icon as category_icon
FROM $transactions_table t
LEFT JOIN $categories_table c ON t.category_id = c.id
$where_clause
ORDER BY t.transaction_date DESC, t.created_at DESC
LIMIT %d OFFSET %d",
array_merge($where_values, array($limit, $offset))
);
return $wpdb->get_results($query);
}
// 添加交易记录
public static function add_transaction($data) {
global $wpdb;
$transactions_table = self::$table_prefix . 'transactions';
$result = $wpdb->insert(
$transactions_table,
$data,
array('%d', '%s', '%d', '%f', '%s', '%s')
);
return $result ? $wpdb->insert_id : false;
}
// 获取用户预算
public static function get_budgets($user_id, $period = 'monthly', $date = null) {
global $wpdb;
if (!$date) {
$date = date('Y-m-d');
}
$budgets_table = self::$table_prefix . 'budgets';
$categories_table = self::$table_prefix . 'categories';
$query = $wpdb->prepare(
"SELECT b.*, c.name as category_name, c.type as category_type
FROM $budgets_table b
LEFT JOIN $categories_table c ON b.category_id = c.id
WHERE b.user_id = %d
AND b.period = %s
AND (b.end_date IS NULL OR b.end_date >= %s)
ORDER BY b.start_date DESC",
array($user_id, $period, $date)
);
return $wpdb->get_results($query);
}
// 更多数据库操作方法...
}
PFM_Database::init();
4. 用户界面设计与前端开发
4.1 创建短代码类
在includes/class-shortcodes.php中添加以下代码:
<?php
class PFM_Shortcodes {
public function init() {
add_shortcode('personal_finance', array($this, 'render_main_dashboard'));
add_shortcode('add_transaction', array($this, 'render_add_transaction'));
add_shortcode('budget_planner', array($this, 'render_budget_planner'));
}
public function render_main_dashboard($atts) {
// 检查用户是否登录
if (!is_user_logged_in()) {
return $this->render_login_prompt();
}
// 获取模板
ob_start();
include PFM_PLUGIN_DIR . 'templates/dashboard.php';
return ob_get_clean();
}
public function render_add_transaction($atts) {
if (!is_user_logged_in()) {
return $this->render_login_prompt();
}
ob_start();
include PFM_PLUGIN_DIR . 'templates/add-transaction.php';
return ob_get_clean();
}
public function render_budget_planner($atts) {
if (!is_user_logged_in()) {
return $this->render_login_prompt();
}
ob_start();
include PFM_PLUGIN_DIR . 'templates/budget.php';
return ob_get_clean();
}
private function render_login_prompt() {
get_permalink() . '">登录以使用个人记账功能。</div>';
}
}
### 4.2 主仪表板模板
在`templates/dashboard.php`中添加以下代码:
<div class="personal-finance-dashboard">
<div class="container-fluid">
<div class="row mb-4">
<div class="col-12">
<h1 class="h3 mb-0">个人财务管理中心</h1>
<p class="text-muted">管理您的收入、支出和预算</p>
</div>
</div>
<!-- 快速统计卡片 -->
<div class="row mb-4">
<div class="col-md-3 mb-3">
<div class="card border-left-primary shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
本月收入</div>
<div class="h5 mb-0 font-weight-bold text-gray-800" id="current-month-income">¥0.00</div>
</div>
<div class="col-auto">
<i class="fas fa-money-bill-wave fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card border-left-danger shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-danger text-uppercase mb-1">
本月支出</div>
<div class="h5 mb-0 font-weight-bold text-gray-800" id="current-month-expense">¥0.00</div>
</div>
<div class="col-auto">
<i class="fas fa-shopping-cart fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card border-left-success shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">
本月结余</div>
<div class="h5 mb-0 font-weight-bold text-gray-800" id="current-month-balance">¥0.00</div>
</div>
<div class="col-auto">
<i class="fas fa-piggy-bank fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card border-left-warning shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
预算使用率</div>
<div class="h5 mb-0 font-weight-bold text-gray-800" id="budget-usage">0%</div>
</div>
<div class="col-auto">
<i class="fas fa-chart-pie fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 主要内容和图表 -->
<div class="row">
<!-- 左侧:图表区域 -->
<div class="col-lg-8 mb-4">
<div class="card shadow mb-4">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">月度收支趋势</h6>
<div class="dropdown no-arrow">
<select class="form-control form-control-sm" id="chart-period">
<option value="3">最近3个月</option>
<option value="6" selected>最近6个月</option>
<option value="12">最近12个月</option>
</select>
</div>
</div>
<div class="card-body">
<div class="chart-area">
<canvas id="monthlyTrendChart"></canvas>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6 mb-4">
<div class="card shadow">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">支出分类</h6>
</div>
<div class="card-body">
<div class="chart-pie pt-4">
<canvas id="expenseCategoryChart"></canvas>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card shadow">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">预算执行情况</h6>
</div>
<div class="card-body">
<div id="budget-progress-container">
<!-- 预算进度条将通过JS动态生成 -->
<div class="text-center py-4">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">加载中...</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 右侧:快速操作和最近交易 -->
<div class="col-lg-4 mb-4">
<!-- 快速操作 -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">快速操作</h6>
</div>
<div class="card-body">
<div class="d-grid gap-2">
<button class="btn btn-primary" id="btn-add-income">
<i class="fas fa-plus-circle me-2"></i>添加收入
</button>
<button class="btn btn-danger" id="btn-add-expense">
<i class="fas fa-minus-circle me-2"></i>添加支出
</button>
<button class="btn btn-success" id="btn-manage-budget">
<i class="fas fa-chart-line me-2"></i>管理预算
</button>
<button class="btn btn-info" id="btn-export-data">
<i class="fas fa-download me-2"></i>导出数据
</button>
</div>
</div>
</div>
<!-- 最近交易 -->
<div class="card shadow">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">最近交易</h6>
<a href="#" class="btn btn-sm btn-outline-primary" id="btn-view-all">查看全部</a>
</div>
<div class="card-body">
<div id="recent-transactions">
<!-- 最近交易列表将通过JS动态加载 -->
<div class="text-center py-4">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">加载中...</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 添加交易模态框 -->
<div class="modal fade" id="addTransactionModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="transactionModalTitle">添加交易</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="transaction-form">
<div class="mb-3">
<label for="transaction-type" class="form-label">交易类型</label>
<div class="btn-group w-100" role="group">
<input type="radio" class="btn-check" name="transaction-type" id="type-income" value="income" autocomplete="off" checked>
<label class="btn btn-outline-success" for="type-income">收入</label>
<input type="radio" class="btn-check" name="transaction-type" id="type-expense" value="expense" autocomplete="off">
<label class="btn btn-outline-danger" for="type-expense">支出</label>
</div>
</div>
<div class="mb-3">
<label for="transaction-amount" class="form-label">金额</label>
<div class="input-group">
<span class="input-group-text">¥</span>
<input type="number" class="form-control" id="transaction-amount" step="0.01" min="0.01" required>
</div>
</div>
<div class="mb-3">
<label for="transaction-category" class="form-label">分类</label>
<select class="form-select" id="transaction-category" required>
<!-- 分类选项将通过JS动态加载 -->
<option value="">请选择分类</option>
</select>
</div>
<div class="mb-3">
<label for="transaction-date" class="form-label">日期</label>
<input type="date" class="form-control" id="transaction-date" value="<?php echo date('Y-m-d'); ?>" required>
</div>
<div class="mb-3">
<label for="transaction-description" class="form-label">描述</label>
<textarea class="form-control" id="transaction-description" rows="2" placeholder="请输入交易描述(可选)"></textarea>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary" id="btn-save-transaction">保存交易</button>
</div>
</form>
</div>
</div>
</div>
</div>
---
## 5. 后端API与数据处理逻辑
### 5.1 API处理类
在`includes/class-api.php`中添加以下代码:
<?php
class PFM_API {
public function init() {
// 注册AJAX处理函数
add_action('wp_ajax_pfm_add_transaction', array($this, 'add_transaction'));
add_action('wp_ajax_nopriv_pfm_add_transaction', array($this, 'require_login'));
add_action('wp_ajax_pfm_get_transactions', array($this, 'get_transactions'));
add_action('wp_ajax_nopriv_pfm_get_transactions', array($this, 'require_login'));
add_action('wp_ajax_pfm_get_statistics', array($this, 'get_statistics'));
add_action('wp_ajax_nopriv_pfm_get_statistics', array($this, 'require_login'));
add_action('wp_ajax_pfm_get_categories', array($this, 'get_categories'));
add_action('wp_ajax_nopriv_pfm_get_categories', array($this, 'require_login'));
add_action('wp_ajax_pfm_add_budget', array($this, 'add_budget'));
add_action('wp_ajax_nopriv_pfm_add_budget', array($this, 'require_login'));
add_action('wp_ajax_pfm_get_budgets', array($this, 'get_budgets'));
add_action('wp_ajax_nopriv_pfm_get_budgets', array($this, 'require_login'));
add_action('wp_ajax_pfm_export_data', array($this, 'export_data'));
add_action('wp_ajax_nopriv_pfm_export_data', array($this, 'require_login'));
}
private function verify_nonce() {
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'pfm_nonce')) {
wp_send_json_error(array('message' => '安全验证失败'));
}
}
public function require_login() {
wp_send_json_error(array('message' => '请先登录'));
}
// 添加交易记录
public function add_transaction() {
$this->verify_nonce();
$user_id = get_current_user_id();
if (!$user_id) {
wp_send_json_error(array('message' => '用户未登录'));
}
// 验证数据
$type = sanitize_text_field($_POST['type']);
$category_id = intval($_POST['category_id']);
$amount = floatval($_POST['amount']);
$description = sanitize_textarea_field($_POST['description']);
$transaction_date = sanitize_text_field($_POST['transaction_date']);
if (!in_array($type, array('income', 'expense'))) {
wp_send_json_error(array('message' => '无效的交易类型'));
}
if ($amount <= 0) {
wp_send_json_error(array('message' => '金额必须大于0'));
}
if (empty($transaction_date)) {
$transaction_date = date('Y-m-d');
}
// 保存到数据库
$data = array(
'user_id' => $user_id,
'type' => $type,
'category_id' => $category_id,
'amount' => $amount,
'description' => $description,
'transaction_date' => $transaction_date
);
$transaction_id = PFM_Database::add_transaction($data);
if ($transaction_id) {
wp_send_json_success(array(
'message' => '交易记录添加成功',
'transaction_id' => $transaction_id
));
} else {
wp_send_json_error(array('message' => '添加交易记录失败'));
}
}
// 获取交易记录
public function get_transactions() {
$this->verify_nonce();
$user_id = get_current_user_id();
if (!$user_id) {
wp_send_json_error(array('message' => '用户未登录'));
}
$limit = isset($_POST['limit']) ? intval($_POST['limit']) : 50;
$offset = isset($_POST['offset']) ? intval($_POST['offset']) : 0;
$filters = array();
if (isset($_POST['type'])) {
$filters['type'] = sanitize_text_field($_POST['type']);
}
if (isset($_POST['category_id'])) {
$filters['category_id'] = intval($_POST['category_id']);
}
if (isset($_POST['start_date'])) {
$filters['start_date'] = sanitize_text_field($_POST['start_date']);
}
if (isset($_POST['end_date'])) {
$filters['end_date'] = sanitize_text_field($_POST['end_date']);
}
$transactions = PFM_Database::get_transactions($user_id, $limit, $offset, $filters);
// 格式化数据
$formatted_transactions = array();
foreach ($transactions as $transaction) {
$formatted_transactions[] = array(
'id' => $transaction->id,
'type' => $transaction->type,
'type_text' => $transaction->type == 'income' ? '收入' : '支出',
'amount' => number_format($transaction->amount, 2),
'amount_raw' => $transaction->amount,
'category_name' => $transaction->category_name,
'category_color' => $transaction->category_color,
'description' => $transaction->description,
'date' => date('Y-m-d', strtotime($transaction->transaction_date)),
'date_formatted' => date('m月d日', strtotime($transaction->transaction_date)),
'created_at' => $transaction->created_at
);
}
wp_send_json_success(array(
'transactions' => $formatted_transactions,
'count' => count($formatted_transactions)
));
}
// 获取统计数据
public function get_statistics() {
$this->verify_nonce();
$user_id = get_current_user_id();
if (!$user_id) {
wp_send_json_error(array('message' => '用户未登录'));
}
global $wpdb;
$table_prefix = $wpdb->prefix . 'pfm_';
$transactions_table = $table_prefix . 'transactions';
// 获取当前月份
$current_month = date('Y-m');
// 本月收入
$monthly_income = $wpdb->get_var($wpdb->prepare(
"SELECT SUM(amount) FROM $transactions_table
WHERE user_id = %d
AND type = 'income'
AND DATE_FORMAT(transaction_date, '%%Y-%%m') = %s",
$user_id, $current_month
));
// 本月支出
$monthly_expense = $wpdb->get_var($wpdb->prepare(
"SELECT SUM(amount) FROM $transactions_table
WHERE user_id = %d
AND type = 'expense'
AND DATE_FORMAT(transaction_date, '%%Y-%%m') = %s",
$user_id, $current_month
));
// 月度趋势数据(最近6个月)
$months = array();
$income_trend = array();
$expense_trend = array();
