首页 / 应用软件 / 详细教程,为网站开发活动报名与电子票务管理工具

详细教程,为网站开发活动报名与电子票务管理工具

详细教程:为网站开发活动报名与电子票务管理工具——通过WordPress代码二次开发实现常用互联网小工具功能

引言:为什么需要自定义活动报名与电子票务系统

在当今数字化时代,活动组织者面临着管理参与者、票务销售和活动执行的复杂挑战。虽然市场上有许多现成的活动管理解决方案,但它们往往缺乏灵活性、定制性,或者价格昂贵。对于许多中小型组织、社区团体或个人活动策划者来说,一个能够完全控制、成本可控且功能定制的解决方案显得尤为重要。

WordPress作为全球最流行的内容管理系统,拥有强大的扩展性和灵活性。通过代码二次开发,我们可以在WordPress平台上构建一个功能完善、符合特定需求的活动报名与电子票务管理工具。本教程将详细指导您如何从零开始,通过WordPress代码二次开发实现这一目标。

第一部分:准备工作与环境搭建

1.1 开发环境配置

在开始开发之前,我们需要搭建一个合适的开发环境:

  1. 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel等工具搭建本地WordPress环境
  2. 代码编辑器:选择Visual Studio Code、PHPStorm或Sublime Text等专业编辑器
  3. 版本控制:初始化Git仓库,便于代码管理和版本控制
  4. 浏览器开发者工具:熟悉Chrome或Firefox的开发者工具,用于调试前端代码

1.2 WordPress安装与基础配置

  1. 下载最新版WordPress并安装到本地环境
  2. 配置数据库连接信息
  3. 设置管理员账户和网站基本信息
  4. 安装必要的开发插件:

    • Query Monitor:用于调试数据库查询和性能
    • Show Current Template:显示当前使用的模板文件
    • Advanced Custom Fields:用于创建自定义字段(可选)

1.3 创建自定义插件结构

为了避免主题更新导致功能丢失,我们将创建一个独立插件来实现所有功能。在wp-content/plugins/目录下创建新文件夹event-ticket-manager,并创建以下基础文件结构:

event-ticket-manager/
├── event-ticket-manager.php      # 主插件文件
├── includes/                     # 核心功能文件目录
│   ├── class-database.php        # 数据库操作类
│   ├── class-event.php           # 活动管理类
│   ├── class-ticket.php          # 票务管理类
│   ├── class-payment.php         # 支付处理类
│   └── class-email.php           # 邮件通知类
├── admin/                        # 后台管理文件
│   ├── css/                      # 后台样式
│   ├── js/                       # 后台脚本
│   └── pages/                    # 后台页面
├── public/                       # 前端文件
│   ├── css/                      # 前端样式
│   ├── js/                       # 前端脚本
│   └── templates/                # 前端模板
├── assets/                       # 静态资源
└── vendor/                       # 第三方库(如果需要)

第二部分:数据库设计与数据模型

2.1 设计数据库表结构

活动报名与电子票务系统需要多个数据表来存储不同类型的信息。我们将在插件激活时创建这些表:

// includes/class-database.php
class ETM_Database {
    
    public function create_tables() {
        global $wpdb;
        
        $charset_collate = $wpdb->get_charset_collate();
        
        // 活动表
        $events_table = $wpdb->prefix . 'etm_events';
        $events_sql = "CREATE TABLE IF NOT EXISTS $events_table (
            id int(11) NOT NULL AUTO_INCREMENT,
            title varchar(255) NOT NULL,
            description text,
            start_date datetime NOT NULL,
            end_date datetime NOT NULL,
            location varchar(500),
            max_participants int(11) DEFAULT 0,
            current_participants int(11) DEFAULT 0,
            status varchar(50) DEFAULT 'draft',
            created_at datetime DEFAULT CURRENT_TIMESTAMP,
            updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY (id)
        ) $charset_collate;";
        
        // 票务类型表
        $ticket_types_table = $wpdb->prefix . 'etm_ticket_types';
        $ticket_types_sql = "CREATE TABLE IF NOT EXISTS $ticket_types_table (
            id int(11) NOT NULL AUTO_INCREMENT,
            event_id int(11) NOT NULL,
            name varchar(255) NOT NULL,
            description text,
            price decimal(10,2) DEFAULT 0.00,
            quantity int(11) NOT NULL,
            sold int(11) DEFAULT 0,
            sale_start datetime,
            sale_end datetime,
            status varchar(50) DEFAULT 'active',
            PRIMARY KEY (id),
            FOREIGN KEY (event_id) REFERENCES $events_table(id) ON DELETE CASCADE
        ) $charset_collate;";
        
        // 订单表
        $orders_table = $wpdb->prefix . 'etm_orders';
        $orders_sql = "CREATE TABLE IF NOT EXISTS $orders_table (
            id int(11) NOT NULL AUTO_INCREMENT,
            order_number varchar(100) NOT NULL UNIQUE,
            event_id int(11) NOT NULL,
            customer_name varchar(255) NOT NULL,
            customer_email varchar(255) NOT NULL,
            customer_phone varchar(50),
            total_amount decimal(10,2) NOT NULL,
            payment_status varchar(50) DEFAULT 'pending',
            payment_method varchar(100),
            payment_id varchar(255),
            order_status varchar(50) DEFAULT 'pending',
            created_at datetime DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            FOREIGN KEY (event_id) REFERENCES $events_table(id)
        ) $charset_collate;";
        
        // 订单详情表
        $order_items_table = $wpdb->prefix . 'etm_order_items';
        $order_items_sql = "CREATE TABLE IF NOT EXISTS $order_items_table (
            id int(11) NOT NULL AUTO_INCREMENT,
            order_id int(11) NOT NULL,
            ticket_type_id int(11) NOT NULL,
            quantity int(11) NOT NULL,
            unit_price decimal(10,2) NOT NULL,
            subtotal decimal(10,2) NOT NULL,
            ticket_code varchar(100) NOT NULL UNIQUE,
            checked_in tinyint(1) DEFAULT 0,
            checked_in_at datetime,
            PRIMARY KEY (id),
            FOREIGN KEY (order_id) REFERENCES $orders_table(id) ON DELETE CASCADE,
            FOREIGN KEY (ticket_type_id) REFERENCES $ticket_types_table(id)
        ) $charset_collate;";
        
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($events_sql);
        dbDelta($ticket_types_sql);
        dbDelta($orders_sql);
        dbDelta($order_items_sql);
    }
}

2.2 实现数据模型类

为每个主要实体创建对应的PHP类,封装数据库操作:

// includes/class-event.php
class ETM_Event {
    
    private $db;
    private $table_name;
    
    public function __construct() {
        global $wpdb;
        $this->db = $wpdb;
        $this->table_name = $wpdb->prefix . 'etm_events';
    }
    
    public function create($data) {
        $defaults = array(
            'status' => 'draft',
            'current_participants' => 0,
            'created_at' => current_time('mysql'),
            'updated_at' => current_time('mysql')
        );
        
        $data = wp_parse_args($data, $defaults);
        
        $result = $this->db->insert(
            $this->table_name,
            $data
        );
        
        if ($result) {
            return $this->db->insert_id;
        }
        
        return false;
    }
    
    public function get($id) {
        $query = $this->db->prepare(
            "SELECT * FROM $this->table_name WHERE id = %d",
            $id
        );
        
        return $this->db->get_row($query);
    }
    
    public function update($id, $data) {
        $data['updated_at'] = current_time('mysql');
        
        $where = array('id' => $id);
        
        return $this->db->update(
            $this->table_name,
            $data,
            $where
        );
    }
    
    public function delete($id) {
        return $this->db->delete(
            $this->table_name,
            array('id' => $id)
        );
    }
    
    public function get_all($args = array()) {
        $defaults = array(
            'status' => 'publish',
            'orderby' => 'start_date',
            'order' => 'ASC',
            'limit' => 10,
            'offset' => 0
        );
        
        $args = wp_parse_args($args, $defaults);
        
        $where = array();
        
        if (!empty($args['status'])) {
            $where[] = $this->db->prepare("status = %s", $args['status']);
        }
        
        if (!empty($args['search'])) {
            $where[] = $this->db->prepare("(title LIKE %s OR description LIKE %s)", 
                '%' . $args['search'] . '%',
                '%' . $args['search'] . '%'
            );
        }
        
        $where_clause = '';
        if (!empty($where)) {
            $where_clause = 'WHERE ' . implode(' AND ', $where);
        }
        
        $orderby = esc_sql($args['orderby']);
        $order = esc_sql($args['order']);
        
        $query = "SELECT * FROM $this->table_name 
                  $where_clause 
                  ORDER BY $orderby $order 
                  LIMIT %d OFFSET %d";
        
        $query = $this->db->prepare(
            $query,
            $args['limit'],
            $args['offset']
        );
        
        return $this->db->get_results($query);
    }
    
    public function get_upcoming($limit = 5) {
        $current_time = current_time('mysql');
        
        $query = $this->db->prepare(
            "SELECT * FROM $this->table_name 
             WHERE status = 'publish' 
             AND start_date > %s 
             ORDER BY start_date ASC 
             LIMIT %d",
            $current_time,
            $limit
        );
        
        return $this->db->get_results($query);
    }
}

第三部分:后台管理界面开发

3.1 创建管理菜单和页面

在WordPress后台添加自定义管理菜单,用于管理活动、票务和订单:

// admin/class-admin-menu.php
class ETM_Admin_Menu {
    
    public function __construct() {
        add_action('admin_menu', array($this, 'add_admin_menus'));
        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
    }
    
    public function add_admin_menus() {
        // 主菜单
        add_menu_page(
            '活动票务管理',
            '活动票务',
            'manage_options',
            'etm-events',
            array($this, 'render_events_page'),
            'dashicons-tickets-alt',
            30
        );
        
        // 子菜单
        add_submenu_page(
            'etm-events',
            '活动管理',
            '所有活动',
            'manage_options',
            'etm-events',
            array($this, 'render_events_page')
        );
        
        add_submenu_page(
            'etm-events',
            '添加新活动',
            '添加活动',
            'manage_options',
            'etm-add-event',
            array($this, 'render_add_event_page')
        );
        
        add_submenu_page(
            'etm-events',
            '票务类型',
            '票务类型',
            'manage_options',
            'etm-ticket-types',
            array($this, 'render_ticket_types_page')
        );
        
        add_submenu_page(
            'etm-events',
            '订单管理',
            '订单',
            'manage_options',
            'etm-orders',
            array($this, 'render_orders_page')
        );
        
        add_submenu_page(
            'etm-events',
            '签到管理',
            '签到',
            'manage_options',
            'etm-checkin',
            array($this, 'render_checkin_page')
        );
        
        add_submenu_page(
            'etm-events',
            '报表统计',
            '报表',
            'manage_options',
            'etm-reports',
            array($this, 'render_reports_page')
        );
        
        add_submenu_page(
            'etm-events',
            '系统设置',
            '设置',
            'manage_options',
            'etm-settings',
            array($this, 'render_settings_page')
        );
    }
    
    public function enqueue_admin_scripts($hook) {
        // 只在插件页面加载脚本和样式
        if (strpos($hook, 'etm-') === false) {
            return;
        }
        
        wp_enqueue_style(
            'etm-admin-style',
            plugins_url('admin/css/admin-style.css', dirname(__FILE__)),
            array(),
            '1.0.0'
        );
        
        wp_enqueue_script(
            'etm-admin-script',
            plugins_url('admin/js/admin-script.js', dirname(__FILE__)),
            array('jquery', 'jquery-ui-datepicker'),
            '1.0.0',
            true
        );
        
        // 本地化脚本,传递数据到JavaScript
        wp_localize_script('etm-admin-script', 'etm_admin', array(
            'ajax_url' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('etm_admin_nonce'),
            'confirm_delete' => '确定要删除这个项目吗?此操作不可撤销。'
        ));
        
        // 加载jQuery UI日期选择器样式
        wp_enqueue_style('jquery-ui-style', 'https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css');
    }
    
    public function render_events_page() {
        include plugin_dir_path(__FILE__) . 'pages/events.php';
    }
    
    public function render_add_event_page() {
        include plugin_dir_path(__FILE__) . 'pages/add-event.php';
    }
    
    // 其他页面渲染方法...
}

3.2 实现活动管理界面

创建活动列表和编辑界面:

// admin/pages/events.php
<div class="wrap etm-admin-wrap">
    <h1 class="wp-heading-inline">活动管理</h1>
    <a href="<?php echo admin_url('admin.php?page=etm-add-event'); ?>" class="page-title-action">添加新活动</a>
    
    <hr class="wp-header-end">
    
    <div class="etm-admin-container">
        <div class="etm-admin-header">
            <div class="tablenav top">
                <div class="alignleft actions">
                    <select name="filter_status" id="filter-status">
                        <option value="">所有状态</option>
                        <option value="draft">草稿</option>
                        <option value="publish">已发布</option>
                        <option value="cancelled">已取消</option>
                        <option value="completed">已结束</option>
                    </select>
                    <input type="text" name="search" id="event-search" placeholder="搜索活动..." value="<?php echo isset($_GET['s']) ? esc_attr($_GET['s']) : ''; ?>">
                    <button type="button" class="button" id="search-events">搜索</button>
                </div>
                <div class="tablenav-pages">
                    <span class="displaying-num"><?php echo $total_events; ?> 个活动</span>
                    <span class="pagination-links">
                        <?php echo $pagination; ?>
                    </span>
                </div>
            </div>
        </div>
        
        <table class="wp-list-table widefat fixed striped">
            <thead>
                <tr>
                    <th scope="col" class="column-primary">活动名称</th>
                    <th scope="col">日期</th>
                    <th scope="col">地点</th>
                    <th scope="col">参与人数</th>
                    <th scope="col">状态</th>
                    <th scope="col">操作</th>
                </tr>
            </thead>
            <tbody>
                <?php if (!empty($events)) : ?>
                    <?php foreach ($events as $event) : ?>
                        <tr>
                            <td class="column-primary">
                                <strong><?php echo esc_html($event->title); ?></strong>
                                <div class="row-actions">
                                    <span class="edit">
                                        <a href="<?php echo admin_url('admin.php?page=etm-add-event&id=' . $event->id); ?>">编辑</a> |
                                    </span>
                                    <span class="view">
                                        <a href="<?php echo get_permalink($event->post_id); ?>" target="_blank">查看</a> |
                                    </span>
                                    <span class="duplicate">
                                        <a href="#" class="duplicate-event" data-id="<?php echo $event->id; ?>">复制</a> |
                                    </span>
                                    <span class="trash">
                                        <a href="#" class="delete-event" data-id="<?php echo $event->id; ?>">删除</a>
                                    </span>
                                </div>
                                <button type="button" class="toggle-row">
                                    <span class="screen-reader-text">显示详情</span>
                                </button>
                            </td>
                            <td>
                                <?php 
                                $start_date = date_i18n('Y年m月d日 H:i', strtotime($event->start_date));
                                $end_date = date_i18n('Y年m月d日 H:i', strtotime($event->end_date));
                                echo $start_date . '<br>至<br>' . $end_date;
                                ?>
                            </td>
                            <td><?php echo esc_html($event->location); ?></td>
                            <td>

<?php echo $event->max_participants > 0 ? $event->max_participants : '不限'; ?>

                        </td>
                        <td>
                            <span class="event-status status-<?php echo esc_attr($event->status); ?>">
                                <?php 
                                $status_labels = array(
                                    'draft' => '草稿',
                                    'publish' => '已发布',
                                    'cancelled' => '已取消',
                                    'completed' => '已结束'
                                );
                                echo isset($status_labels[$event->status]) ? $status_labels[$event->status] : $event->status;
                                ?>
                            </span>
                        </td>
                        <td>
                            <div class="action-buttons">
                                <a href="<?php echo admin_url('admin.php?page=etm-ticket-types&event_id=' . $event->id); ?>" class="button button-small">管理票务</a>
                                <a href="<?php echo admin_url('admin.php?page=etm-orders&event_id=' . $event->id); ?>" class="button button-small">查看订单</a>
                                <?php if ($event->status == 'publish') : ?>
                                    <a href="#" class="button button-small button-primary copy-registration-link" data-link="<?php echo home_url('/event-registration/?event_id=' . $event->id); ?>">复制报名链接</a>
                                <?php endif; ?>
                            </div>
                        </td>
                    </tr>
                <?php endforeach; ?>
            <?php else : ?>
                <tr>
                    <td colspan="6" class="no-items">暂无活动,<a href="<?php echo admin_url('admin.php?page=etm-add-event'); ?>">创建第一个活动</a></td>
                </tr>
            <?php endif; ?>
        </tbody>
    </table>
</div>

</div>


## 第四部分:前端报名与票务购买功能

### 4.1 创建前端报名页面模板

// public/templates/registration-form.php
<div class="etm-registration-container">

<div class="etm-registration-header">
    <h1><?php echo esc_html($event->title); ?></h1>
    <div class="event-meta">
        <div class="meta-item">
            <span class="dashicons dashicons-calendar"></span>
            <span class="meta-label">时间:</span>
            <span class="meta-value"><?php echo date_i18n('Y年m月d日 H:i', strtotime($event->start_date)); ?> - <?php echo date_i18n('Y年m月d日 H:i', strtotime($event->end_date)); ?></span>
        </div>
        <div class="meta-item">
            <span class="dashicons dashicons-location"></span>
            <span class="meta-label">地点:</span>
            <span class="meta-value"><?php echo esc_html($event->location); ?></span>
        </div>
        <div class="meta-item">
            <span class="dashicons dashicons-groups"></span>
            <span class="meta-label">已报名:</span>
            <span class="meta-value"><?php echo $event->current_participants; ?>/<?php echo $event->max_participants > 0 ? $event->max_participants : '不限'; ?></span>
        </div>
    </div>
</div>

<?php if ($event->status !== 'publish') : ?>
    <div class="etm-alert etm-alert-warning">
        此活动当前不可报名。
    </div>
<?php elseif ($event->max_participants > 0 && $event->current_participants >= $event->max_participants) : ?>
    <div class="etm-alert etm-alert-warning">
        抱歉,此活动报名人数已满。
    </div>
<?php else : ?>
    <div class="etm-registration-content">
        <div class="etm-event-description">
            <h2>活动介绍</h2>
            <div class="description-content">
                <?php echo wpautop($event->description); ?>
            </div>
        </div>
        
        <div class="etm-registration-form-wrapper">
            <h2>报名信息</h2>
            
            <form id="etm-registration-form" method="post" action="<?php echo admin_url('admin-ajax.php'); ?>">
                <?php wp_nonce_field('etm_registration_nonce', 'registration_nonce'); ?>
                <input type="hidden" name="action" value="etm_process_registration">
                <input type="hidden" name="event_id" value="<?php echo $event->id; ?>">
                
                <div class="form-section">
                    <h3>选择票种</h3>
                    <div class="ticket-selection">
                        <?php if (!empty($ticket_types)) : ?>
                            <?php foreach ($ticket_types as $ticket) : ?>
                                <?php if ($ticket->status == 'active' && $ticket->sold < $ticket->quantity) : ?>
                                    <div class="ticket-option">
                                        <div class="ticket-header">
                                            <input type="radio" 
                                                   name="ticket_type_id" 
                                                   id="ticket_<?php echo $ticket->id; ?>" 
                                                   value="<?php echo $ticket->id; ?>" 
                                                   data-price="<?php echo $ticket->price; ?>"
                                                   required>
                                            <label for="ticket_<?php echo $ticket->id; ?>">
                                                <span class="ticket-name"><?php echo esc_html($ticket->name); ?></span>
                                                <span class="ticket-price">
                                                    <?php if ($ticket->price > 0) : ?>
                                                        ¥<?php echo number_format($ticket->price, 2); ?>
                                                    <?php else : ?>
                                                        免费
                                                    <?php endif; ?>
                                                </span>
                                            </label>
                                        </div>
                                        <div class="ticket-details">
                                            <p><?php echo esc_html($ticket->description); ?></p>
                                            <div class="ticket-meta">
                                                <span class="available">剩余:<?php echo $ticket->quantity - $ticket->sold; ?>张</span>
                                                <?php if ($ticket->sale_start && $ticket->sale_end) : ?>
                                                    <span class="sale-period">
                                                        销售时间:<?php echo date_i18n('m月d日 H:i', strtotime($ticket->sale_start)); ?> - <?php echo date_i18n('m月d日 H:i', strtotime($ticket->sale_end)); ?>
                                                    </span>
                                                <?php endif; ?>
                                            </div>
                                        </div>
                                    </div>
                                <?php endif; ?>
                            <?php endforeach; ?>
                        <?php else : ?>
                            <p class="no-tickets">暂无可用票种</p>
                        <?php endif; ?>
                    </div>
                </div>
                
                <div class="form-section">
                    <h3>购票数量</h3>
                    <div class="quantity-selection">
                        <div class="quantity-control">
                            <button type="button" class="quantity-minus" disabled>-</button>
                            <input type="number" 
                                   name="ticket_quantity" 
                                   id="ticket_quantity" 
                                   value="1" 
                                   min="1" 
                                   max="10" 
                                   class="quantity-input">
                            <button type="button" class="quantity-plus">+</button>
                        </div>
                        <div class="quantity-note">
                            <p>每人最多可购买10张票</p>
                        </div>
                    </div>
                </div>
                
                <div class="form-section">
                    <h3>填写个人信息</h3>
                    <div class="personal-info">
                        <div class="form-row">
                            <div class="form-group">
                                <label for="customer_name">姓名 <span class="required">*</span></label>
                                <input type="text" 
                                       id="customer_name" 
                                       name="customer_name" 
                                       required 
                                       placeholder="请输入真实姓名">
                            </div>
                            <div class="form-group">
                                <label for="customer_email">邮箱 <span class="required">*</span></label>
                                <input type="email" 
                                       id="customer_email" 
                                       name="customer_email" 
                                       required 
                                       placeholder="用于接收电子票和通知">
                            </div>
                        </div>
                        <div class="form-row">
                            <div class="form-group">
                                <label for="customer_phone">手机号 <span class="required">*</span></label>
                                <input type="tel" 
                                       id="customer_phone" 
                                       name="customer_phone" 
                                       required 
                                       placeholder="用于活动通知">
                            </div>
                            <div class="form-group">
                                <label for="customer_company">公司/机构</label>
                                <input type="text" 
                                       id="customer_company" 
                                       name="customer_company" 
                                       placeholder="选填">
                            </div>
                        </div>
                        <div class="form-row">
                            <div class="form-group full-width">
                                <label for="special_requirements">特殊需求</label>
                                <textarea id="special_requirements" 
                                          name="special_requirements" 
                                          rows="3" 
                                          placeholder="如有饮食禁忌、特殊需求等请在此说明"></textarea>
                            </div>
                        </div>
                    </div>
                </div>
                
                <div class="form-section">
                    <h3>订单总览</h3>
                    <div class="order-summary">
                        <div class="summary-row">
                            <span class="summary-label">票种:</span>
                            <span class="summary-value" id="summary_ticket_name">请选择票种</span>
                        </div>
                        <div class="summary-row">
                            <span class="summary-label">单价:</span>
                            <span class="summary-value" id="summary_ticket_price">¥0.00</span>
                        </div>
                        <div class="summary-row">
                            <span class="summary-label">数量:</span>
                            <span class="summary-value" id="summary_quantity">1</span>
                        </div>
                        <div class="summary-row total">
                            <span class="summary-label">总计:</span>
                            <span class="summary-value" id="summary_total">¥0.00</span>
                        </div>
                    </div>
                </div>
                
                <div class="form-section">
                    <div class="form-submit">
                        <button type="submit" class="etm-submit-button" id="submit-registration">
                            <span class="button-text">提交报名</span>
                            <span class="loading-spinner" style="display:none;"></span>
                        </button>
                        <p class="form-notice">点击提交即表示您同意我们的<a href="<?php echo get_privacy_policy_url(); ?>" target="_blank">隐私政策</a>和<a href="<?php echo home_url('/terms'); ?>" target="_blank">服务条款</a></p>
                    </div>
                </div>
            </form>
        </div>
    </div>
<?php endif; ?>

</div>

<script>
jQuery(document).ready(function($) {

// 更新订单总览
function updateOrderSummary() {
    var selectedTicket = $('input[name="ticket_type_id"]:checked');
    var quantity = parseInt($('#ticket_quantity').val());
    
    if (selectedTicket.length > 0) {
        var ticketName = selectedTicket.siblings('label').find('.ticket-name').text();
        var ticketPrice = parseFloat(selectedTicket.data('price'));
        var total = ticketPrice * quantity;
        
        $('#summary_ticket_name').text(ticketName);
        $('#summary_ticket_price').text('¥' + ticketPrice.toFixed(2));
        $('#summary_quantity').text(quantity);
        $('#summary_total').text('¥' + total.toFixed(2));
    }
}

// 票种选择事件
$('input[name="ticket_type_id"]').on('change', updateOrderSummary);

// 数量控制
$('.quantity-minus').on('click', function() {
    var input = $('#ticket_quantity');
    var currentVal = parseInt(input.val());
    if (currentVal > 1) {
        input.val(currentVal - 1);
        updateOrderSummary();
    }
    updateQuantityButtons();
});

$('.quantity-plus').on('click', function() {
    var input = $('#ticket_quantity');
    var currentVal = parseInt(input.val());
    var maxVal = parseInt(input.attr('max'));
    if (currentVal < maxVal) {
        input.val(currentVal + 1);
        updateOrderSummary();
    }
    updateQuantityButtons();
});

$('#ticket_quantity').on('change', function() {
    var val = parseInt($(this).val());
    var maxVal = parseInt($(this).attr('max'));
    var minVal = parseInt($(this).attr('min'));
    
    if (val > maxVal) val = maxVal;
    if (val < minVal) val = minVal;
    
    $(this).val(val);
    updateOrderSummary();
    updateQuantityButtons();
});

function updateQuantityButtons() {
    var currentVal = parseInt($('#ticket_quantity').val());
    var maxVal = parseInt($('#ticket_quantity').attr('max'));
    var minVal = parseInt($('#ticket_quantity').attr('min'));
    
    $('.quantity-minus').prop('disabled', currentVal <= minVal);
    $('.quantity-plus').prop('disabled', currentVal >= maxVal);
}

// 表单提交
$('#etm-registration-form').on('submit', function(e) {
    e.preventDefault();
    
    var form = $(this);
    var submitButton = $('#submit-registration');
    var buttonText = submitButton.find('.button-text');
    var spinner = submitButton.find('.loading-spinner');
    
    // 验证表单
    if (!form[0].checkValidity()) {
        form[0].reportValidity();
        return;
    }
    
    // 显示加载状态
    buttonText.text('处理中...');
    spinner.show();
    submitButton.prop('disabled', true);
    
    // 发送AJAX请求
    $.ajax({
        url: form.attr('action'),
        type: 'POST',
        data: form.serialize(),
        dataType: 'json',
        success: function(response) {
            if (response.success) {
                // 跳转到支付页面或成功页面
                if (response.data.payment_required) {
                    window.location.href = response.data.payment_url;
                } else {
                    window.location.href = response.data.success_url;
                }
            } else {
                // 显示错误信息
                alert(response.data.message || '提交失败,请重试');
                buttonText.text('提交报名');
                spinner.hide();
                submitButton.prop('disabled', false);
            }
        },
        error: function() {
            alert('网络错误,请重试');
            buttonText.text('提交报名');
            spinner.hide();
            submitButton.prop('disabled', false);
        }
    });
});

// 初始化
updateQuantityButtons();
$('input[name="ticket_type_id"]:first').prop('checked', true).trigger('change');

});
</script>


### 4.2 实现AJAX表单处理

// includes/class-ajax-handler.php
class ETM_Ajax_Handler {


public function __construct() {
    // 前端AJAX处理
    add_action('wp_ajax_etm_process_registration', array($this, 'process_registration'));
    add_action('wp_ajax_nopriv_etm_process_registration', array($this, 'process_registration'));
    
    // 后台AJAX处理
    add_action('wp_ajax_etm_admin_actions', array($this, 'handle_admin_actions'));
}

public function process_registration() {
    // 验证nonce
    if (!isset($_POST['registration_nonce']) || 
        !wp_verify_nonce($_POST['registration_nonce'], 'etm_registration_nonce')) {
        wp_send_json_error(array('message' => '安全验证失败'));
    }
    
    // 验证必填字段
    $required_fields = array(
        'event_id',
        'ticket_type_id',
        'ticket_quantity',
        'customer_name',
        'customer_email',
        'customer_phone'
    );
    
    foreach ($required_fields as $field) {
        if (empty($_POST[$field])) {
            wp_send_json_error(array('message' => '请填写所有必填字段'));
        }
    }
    
    $event_id = intval($_POST['event_id']);
    $ticket_type_id = intval($_POST['ticket_type_id']);
    $quantity = intval($_POST['ticket_quantity']);
    
    // 验证活动状态
    $event_model = new ETM_Event();
    $event = $event_model->get($event_id);
    
    if (!$event || $event->status !== 'publish') {
        wp_send_json_error(array('message' => '活动不可用'));
    }
    
    // 验证票种
    $ticket_model = new ETM_Ticket();
    $ticket_type = $ticket_model->get_type($ticket_type_id);
    
    if (!$ticket_type || $ticket_type->event_id != $event_id) {
        wp_send_json_error(array('message' => '票种无效'));
    }
    
    if ($ticket_type->status !== 'active') {
        wp_send_json_error(array('message' => '该票种已停售'));
    }
    
    // 检查库存
    if ($ticket_type->sold + $quantity > $ticket_type->quantity) {
        wp_send_json_error(array('message' => '票数不足,仅剩' . ($ticket_type->quantity - $ticket_type->sold) . '张'));
    }
    
    // 检查活动人数限制
    if ($event->max_participants > 0 && 
        $event->current_participants + $quantity > $event->max_participants) {
        wp_send_json_error(array('
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5128.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部