文章目录[隐藏]
WordPress高级教程:开发集成在线问卷调查与自动报告生成器
引言:WordPress作为企业级应用开发平台
WordPress早已超越了简单的博客系统范畴,成为全球最受欢迎的内容管理系统(CMS),驱动着超过40%的网站。其强大的插件架构、丰富的API接口和庞大的开发者社区,使得WordPress能够胜任各种复杂的企业级应用开发。本教程将深入探讨如何通过WordPress代码二次开发,实现一个集在线问卷调查与自动报告生成器于一体的高级功能模块。
在当今数据驱动的商业环境中,问卷调查和数据分析工具已成为企业决策的重要支撑。传统上,企业可能需要购买昂贵的专业调查工具或委托定制开发,而通过WordPress二次开发,我们可以以更低的成本、更高的集成度实现这一功能,同时充分利用WordPress的用户管理、权限控制和内容展示能力。
系统架构设计
功能需求分析
在开始开发之前,我们需要明确系统的核心需求:
-
问卷调查功能:
- 支持多种题型(单选、多选、文本输入、评分等)
- 问题逻辑跳转
- 问卷分页与进度保存
- 响应式设计,适配移动设备
-
报告生成功能:
- 基于问卷结果的自动分析
- 可视化图表生成
- 可定制的报告模板
- 多种格式导出(PDF、Word、HTML)
-
管理功能:
- 问卷创建与管理界面
- 数据收集与统计分析
- 用户权限与访问控制
- 报告模板管理
技术架构设计
我们将采用分层架构设计,确保系统的可维护性和扩展性:
- 数据层:使用WordPress自定义数据表存储问卷、回答和报告数据
- 业务逻辑层:处理问卷逻辑、数据分析和报告生成
- 表示层:前端界面和用户交互
- 集成层:与WordPress核心功能(用户、权限、主题)的集成
数据库设计与实现
自定义数据表设计
虽然WordPress提供了自定义文章类型(CPT)和元数据存储机制,但对于问卷调查这种结构化数据,我们建议创建专门的数据表以提高查询效率。
-- 问卷主表
CREATE TABLE wp_surveys (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
status ENUM('draft', 'published', 'closed') DEFAULT 'draft',
created_by INT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
settings TEXT, -- JSON格式存储问卷设置
FOREIGN KEY (created_by) REFERENCES wp_users(ID)
);
-- 问题表
CREATE TABLE wp_survey_questions (
id INT AUTO_INCREMENT PRIMARY KEY,
survey_id INT NOT NULL,
question_text TEXT NOT NULL,
question_type ENUM('single_choice', 'multiple_choice', 'text', 'rating', 'matrix') NOT NULL,
options TEXT, -- JSON格式存储选项
is_required BOOLEAN DEFAULT FALSE,
sort_order INT DEFAULT 0,
logic_rules TEXT, -- JSON格式存储逻辑跳转规则
FOREIGN KEY (survey_id) REFERENCES wp_surveys(id) ON DELETE CASCADE
);
-- 回答表
CREATE TABLE wp_survey_responses (
id INT AUTO_INCREMENT PRIMARY KEY,
survey_id INT NOT NULL,
user_id INT,
session_id VARCHAR(100),
started_at DATETIME,
completed_at DATETIME,
ip_address VARCHAR(45),
user_agent TEXT,
FOREIGN KEY (survey_id) REFERENCES wp_surveys(id),
FOREIGN KEY (user_id) REFERENCES wp_users(ID)
);
-- 答案详情表
CREATE TABLE wp_survey_answers (
id INT AUTO_INCREMENT PRIMARY KEY,
response_id INT NOT NULL,
question_id INT NOT NULL,
answer_value TEXT,
FOREIGN KEY (response_id) REFERENCES wp_survey_responses(id) ON DELETE CASCADE,
FOREIGN KEY (question_id) REFERENCES wp_survey_questions(id)
);
-- 报告表
CREATE TABLE wp_survey_reports (
id INT AUTO_INCREMENT PRIMARY KEY,
survey_id INT NOT NULL,
title VARCHAR(255) NOT NULL,
report_type ENUM('summary', 'individual', 'comparative') NOT NULL,
template_id INT,
generated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
content LONGTEXT, -- 报告内容,可以是HTML或序列化数据
file_path VARCHAR(500), -- 导出文件路径
FOREIGN KEY (survey_id) REFERENCES wp_surveys(id)
);
数据库操作类封装
为了与WordPress数据库操作保持一致,我们创建一个专门的数据库操作类:
<?php
/**
* 问卷调查数据库操作类
*/
class Survey_DB {
private $wpdb;
private $charset_collate;
public function __construct() {
global $wpdb;
$this->wpdb = $wpdb;
$this->charset_collate = $wpdb->get_charset_collate();
}
/**
* 创建数据表
*/
public function create_tables() {
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
// 问卷主表
$sql = "CREATE TABLE {$this->wpdb->prefix}surveys (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
status ENUM('draft', 'published', 'closed') DEFAULT 'draft',
created_by INT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
settings TEXT,
FOREIGN KEY (created_by) REFERENCES {$this->wpdb->prefix}users(ID)
) {$this->charset_collate};";
dbDelta($sql);
// 其他表的创建代码类似...
}
/**
* 获取问卷列表
*/
public function get_surveys($args = array()) {
$defaults = array(
'status' => 'published',
'per_page' => 10,
'page' => 1,
'orderby' => 'created_at',
'order' => 'DESC'
);
$args = wp_parse_args($args, $defaults);
$offset = ($args['page'] - 1) * $args['per_page'];
$sql = $this->wpdb->prepare(
"SELECT * FROM {$this->wpdb->prefix}surveys
WHERE status = %s
ORDER BY {$args['orderby']} {$args['order']}
LIMIT %d OFFSET %d",
$args['status'],
$args['per_page'],
$offset
);
return $this->wpdb->get_results($sql);
}
/**
* 保存问卷回答
*/
public function save_response($survey_id, $user_id, $answers) {
// 开启事务
$this->wpdb->query('START TRANSACTION');
try {
// 保存回答主记录
$response_data = array(
'survey_id' => $survey_id,
'user_id' => $user_id,
'completed_at' => current_time('mysql'),
'ip_address' => $this->get_client_ip(),
'user_agent' => $_SERVER['HTTP_USER_AGENT']
);
$this->wpdb->insert(
"{$this->wpdb->prefix}survey_responses",
$response_data
);
$response_id = $this->wpdb->insert_id;
// 保存每个问题的答案
foreach ($answers as $question_id => $answer) {
$answer_data = array(
'response_id' => $response_id,
'question_id' => $question_id,
'answer_value' => is_array($answer) ? json_encode($answer) : $answer
);
$this->wpdb->insert(
"{$this->wpdb->prefix}survey_answers",
$answer_data
);
}
// 提交事务
$this->wpdb->query('COMMIT');
return $response_id;
} catch (Exception $e) {
// 回滚事务
$this->wpdb->query('ROLLBACK');
return false;
}
}
/**
* 获取客户端IP
*/
private function get_client_ip() {
$ipaddress = '';
if (isset($_SERVER['HTTP_CLIENT_IP']))
$ipaddress = $_SERVER['HTTP_CLIENT_IP'];
else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
$ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
else if(isset($_SERVER['HTTP_X_FORWARDED']))
$ipaddress = $_SERVER['HTTP_X_FORWARDED'];
else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
else if(isset($_SERVER['HTTP_FORWARDED']))
$ipaddress = $_SERVER['HTTP_FORWARDED'];
else if(isset($_SERVER['REMOTE_ADDR']))
$ipaddress = $_SERVER['REMOTE_ADDR'];
else
$ipaddress = 'UNKNOWN';
return $ipaddress;
}
}
?>
问卷创建与管理模块
后台管理界面开发
我们将创建一个完整的后台管理界面,用于问卷的创建、编辑和管理:
<?php
/**
* 问卷调查管理类
*/
class Survey_Admin {
private $db;
public function __construct() {
$this->db = new Survey_DB();
// 添加管理菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 注册管理页面脚本
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
}
/**
* 添加管理菜单
*/
public function add_admin_menu() {
// 主菜单
add_menu_page(
'问卷调查管理',
'问卷调查',
'manage_options',
'survey-manager',
array($this, 'render_main_page'),
'dashicons-feedback',
30
);
// 子菜单
add_submenu_page(
'survey-manager',
'所有问卷',
'所有问卷',
'manage_options',
'survey-manager',
array($this, 'render_main_page')
);
add_submenu_page(
'survey-manager',
'新建问卷',
'新建问卷',
'manage_options',
'survey-new',
array($this, 'render_new_survey_page')
);
add_submenu_page(
'survey-manager',
'报告生成',
'报告生成',
'manage_options',
'survey-reports',
array($this, 'render_reports_page')
);
add_submenu_page(
'survey-manager',
'设置',
'设置',
'manage_options',
'survey-settings',
array($this, 'render_settings_page')
);
}
/**
* 渲染主页面
*/
public function render_main_page() {
// 获取问卷列表
$surveys = $this->db->get_surveys();
// 加载模板
include SURVEY_PLUGIN_DIR . 'templates/admin/survey-list.php';
}
/**
* 渲染新建问卷页面
*/
public function render_new_survey_page() {
// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_survey'])) {
$this->save_survey($_POST);
}
// 加载模板
include SURVEY_PLUGIN_DIR . 'templates/admin/survey-editor.php';
}
/**
* 保存问卷
*/
private function save_survey($data) {
// 验证和清理数据
$survey_data = array(
'title' => sanitize_text_field($data['title']),
'description' => wp_kses_post($data['description']),
'status' => sanitize_text_field($data['status']),
'created_by' => get_current_user_id(),
'settings' => json_encode(array(
'require_login' => isset($data['require_login']) ? 1 : 0,
'limit_responses' => isset($data['limit_responses']) ? intval($data['limit_responses']) : 0,
'show_progress' => isset($data['show_progress']) ? 1 : 0,
'randomize_questions' => isset($data['randomize_questions']) ? 1 : 0
))
);
// 保存到数据库
global $wpdb;
if (isset($data['survey_id']) && $data['survey_id']) {
// 更新现有问卷
$wpdb->update(
"{$wpdb->prefix}surveys",
$survey_data,
array('id' => intval($data['survey_id']))
);
$survey_id = $data['survey_id'];
} else {
// 创建新问卷
$wpdb->insert(
"{$wpdb->prefix}surveys",
$survey_data
);
$survey_id = $wpdb->insert_id;
}
// 保存问题
if (isset($data['questions']) && is_array($data['questions'])) {
$this->save_questions($survey_id, $data['questions']);
}
// 重定向到编辑页面
wp_redirect(admin_url('admin.php?page=survey-new&survey_id=' . $survey_id . '&saved=1'));
exit;
}
/**
* 注册管理页面脚本
*/
public function enqueue_admin_scripts($hook) {
// 只在我们的管理页面加载脚本
if (strpos($hook, 'survey-') === false) {
return;
}
// 加载Vue.js用于动态界面
wp_enqueue_script('vue', 'https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js', array(), '2.6.14');
// 加载Element UI组件库
wp_enqueue_style('element-ui', 'https://unpkg.com/element-ui/lib/theme-chalk/index.css');
wp_enqueue_script('element-ui', 'https://unpkg.com/element-ui/lib/index.js', array('vue'), '2.15.6');
// 加载自定义脚本
wp_enqueue_script(
'survey-admin',
SURVEY_PLUGIN_URL . 'assets/js/admin.js',
array('vue', 'element-ui', 'jquery'),
'1.0.0',
true
);
// 加载自定义样式
wp_enqueue_style(
'survey-admin',
SURVEY_PLUGIN_URL . 'assets/css/admin.css',
array('element-ui'),
'1.0.0'
);
// 传递数据到JavaScript
wp_localize_script('survey-admin', 'survey_admin_data', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('survey_admin_nonce')
));
}
}
?>
问卷编辑器前端实现
使用Vue.js和Element UI创建动态问卷编辑器:
// assets/js/admin.js
(function($) {
'use strict';
// 创建Vue应用
new Vue({
el: '#survey-editor',
data: {
survey: {
title: '',
description: '',
status: 'draft',
settings: {
require_login: false,
limit_responses: 0,
show_progress: true,
randomize_questions: false
}
},
questions: [],
questionTypes: [
{ value: 'single_choice', label: '单选题' },
{ value: 'multiple_choice', label: '多选题' },
{ value: 'text', label: '文本题' },
{ value: 'rating', label: '评分题' },
{ value: 'matrix', label: '矩阵题' }
],
activeQuestionIndex: 0
},
methods: {
// 添加新问题
addQuestion: function(type) {
const newQuestion = {
id: Date.now(), // 临时ID
question_text: '',
question_type: type,
options: type === 'rating' ?
[{value: 1, label: '1'}, {value: 2, label: '2'}, {value: 3, label: '3'}, {value: 4, label: '4'}, {value: 5, label: '5'}] :
type === 'single_choice' || type === 'multiple_choice' ?
[{value: 'option1', label: '选项1'}, {value: 'option2', label: '选项2'}] :
[],
is_required: false,
sort_order: this.questions.length,
logic_rules: []
};
this.questions.push(newQuestion);
this.activeQuestionIndex = this.questions.length - 1;
},
// 删除问题
removeQuestion: function(index) {
this.questions.splice(index, 1);
if (this.activeQuestionIndex >= index && this.activeQuestionIndex > 0) {
this.activeQuestionIndex--;
}
},
// 上移问题
moveQuestionUp: function(index) {
if (index > 0) {
const temp = this.questions[index];
this.$set(this.questions, index, this.questions[index - 1]);
this.$set(this.questions, index - 1, temp);
this.activeQuestionIndex = index - 1;
}
},
// 下移问题
moveQuestionDown: function(index) {
if (index < this.questions.length - 1) {
const temp = this.questions[index];
this.$set(this.questions, index, this.questions[index + 1]);
this.activeQuestionIndex = index + 1;
}
},
// 添加选项
addOption: function(questionIndex) {
if (!this.questions[questionIndex].options) {
this.$set(this.questions[questionIndex], 'options', []);
}
const optionCount = this.questions[questionIndex].options.length + 1;
this.questions[questionIndex].options.push({
value: 'option' + optionCount,
label: '选项' + optionCount
});
},
// 删除选项
removeOption: function(questionIndex, optionIndex) {
this.questions[questionIndex].options.splice(optionIndex, 1);
},
// 保存问卷
saveSurvey: function() {
const formData = new FormData();
formData.append('action', 'save_survey');
formData.append('nonce', survey_admin_data.nonce);
formData.append('survey', JSON.stringify(this.survey));
formData.append('questions', JSON.stringify(this.questions));
$.ajax({
url: survey_admin_data.ajax_url,
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
if (response.success) {
this.$message.success('问卷保存成功');
if (response.data.redirect) {
window.location.href = response.data.redirect;
}
} else {
this.$message.error('保存失败:' + response.data.message);
}
}.bind(this),
error: function() {
this.$message.error('网络错误,请重试');
}.bind(this)
});
},
// 预览问卷
previewSurvey: function() {
// 在新窗口打开预览
const previewUrl = survey_admin_data.site_url + '?survey_preview=' + (this.survey.id || 'new');
window.open(previewUrl, '_blank');
}
},
mounted: function() {
// 如果有现有问卷数据,加载它
if (window.surveyData) {
this.survey = window.surveyData.survey;
this.questions = window.surveyData.questions;
}
}
});
})(jQuery);
前端问卷展示与交互
短代码系统实现
为了让用户能够轻松地在文章或页面中插入问卷,我们实现一个短代码系统:
<?php
/**
* 问卷调查短代码类
*/
class Survey_Shortcode {
private $db;
public function __construct() {
$this->db = new Survey_DB();
// 注册短代码
add_shortcode('survey', array($this, 'render_survey'));
// 注册AJAX处理
add_action('wp_ajax_submit_survey', array($this, 'handle_survey_submission'));
add_action('wp_ajax_nopriv_submit_survey', array($this, 'handle_survey_submission'));
}
/**
* 渲染问卷短代码
*/
public function render_survey($atts) {
$atts = shortcode_atts(array(
'id' => 0,
'title' => '',
'width' => '100%',
'height' => 'auto'
), $atts, 'survey');
$survey_id = intval($atts['id']);
if (!$survey_id) {
return '<div class="survey-error">请指定问卷ID</div>';
}
// 获取问卷数据
global $wpdb;
$survey = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}surveys WHERE id = %d AND status = 'published'",
$survey_id
));
if (!$survey) {
return '<div class="survey-error">问卷不存在或未发布</div>';
}
// 检查访问权限
$settings = json_decode($survey->settings, true);
if ($settings['require_login'] && !is_user_logged_in()) {
return '<div class="survey-login-required">请先登录后再填写问卷</div>';
}
// 检查回答限制
if ($settings['limit_responses'] > 0) {
$response_count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$wpdb->prefix}survey_responses WHERE survey_id = %d",
$survey_id
));
if ($response_count >= $settings['limit_responses']) {
return '<div class="survey-closed">本问卷已收集足够数据,感谢参与</div>';
}
}
// 获取问题列表
$questions = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}survey_questions
WHERE survey_id = %d
ORDER BY sort_order ASC",
$survey_id
));
// 解析问题选项
foreach ($questions as &$question) {
if ($question->options) {
$question->options = json_decode($question->options, true);
}
if ($question->logic_rules) {
$question->logic_rules = json_decode($question->logic_rules, true);
}
}
// 生成唯一会话ID
$session_id = $this->generate_session_id();
// 输出问卷HTML
ob_start();
include SURVEY_PLUGIN_DIR . 'templates/frontend/survey-form.php';
return ob_get_clean();
}
/**
* 处理问卷提交
*/
public function handle_survey_submission() {
// 验证nonce
if (!check_ajax_referer('survey_submission', 'nonce', false)) {
wp_die(json_encode(array(
'success' => false,
'message' => '安全验证失败'
)));
}
$survey_id = intval($_POST['survey_id']);
$answers = $_POST['answers'];
$session_id = sanitize_text_field($_POST['session_id']);
// 验证问卷是否存在且开放
global $wpdb;
$survey = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}surveys WHERE id = %d AND status = 'published'",
$survey_id
));
if (!$survey) {
wp_die(json_encode(array(
'success' => false,
'message' => '问卷不存在'
)));
}
// 检查是否已经提交过
$settings = json_decode($survey->settings, true);
if ($settings['prevent_duplicate']) {
$user_id = get_current_user_id();
$check_field = $user_id ? 'user_id' : 'session_id';
$check_value = $user_id ? $user_id : $session_id;
$existing = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$wpdb->prefix}survey_responses
WHERE survey_id = %d AND {$check_field} = %s",
$survey_id,
$check_value
));
if ($existing > 0) {
wp_die(json_encode(array(
'success' => false,
'message' => '您已经提交过本问卷'
)));
}
}
// 保存回答
$user_id = get_current_user_id();
$response_id = $this->db->save_response($survey_id, $user_id, $answers);
if ($response_id) {
// 触发完成动作
do_action('survey_completed', $survey_id, $response_id, $user_id);
wp_die(json_encode(array(
'success' => true,
'message' => '提交成功',
'response_id' => $response_id
)));
} else {
wp_die(json_encode(array(
'success' => false,
'message' => '提交失败,请重试'
)));
}
}
/**
* 生成会话ID
*/
private function generate_session_id() {
if (isset($_COOKIE['survey_session_id'])) {
return $_COOKIE['survey_session_id'];
}
$session_id = wp_generate_uuid4();
setcookie('survey_session_id', $session_id, time() + 3600 * 24 * 30, '/');
return $session_id;
}
}
?>
前端问卷样式与交互
/* assets/css/frontend.css */
.survey-container {
max-width: 800px;
margin: 0 auto;
padding: 30px;
background: #fff;
border-radius: 10px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
.survey-header {
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 2px solid #f0f0f0;
}
.survey-title {
font-size: 28px;
font-weight: 600;
color: #333;
margin-bottom: 10px;
}
.survey-description {
font-size: 16px;
color: #666;
line-height: 1.6;
}
.survey-progress {
margin-bottom: 30px;
}
.progress-bar {
height: 8px;
background: #f0f0f0;
border-radius: 4px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #4CAF50, #8BC34A);
transition: width 0.3s ease;
}
.progress-text {
text-align: right;
font-size: 14px;
color: #666;
margin-top: 5px;
}
.survey-questions {
margin-bottom: 40px;
}
.question-item {
margin-bottom: 30px;
padding: 25px;
background: #f9f9f9;
border-radius: 8px;
border-left: 4px solid #4CAF50;
transition: all 0.3s ease;
}
.question-item.required {
border-left-color: #F44336;
}
.question-item.required .question-text::after {
content: " *";
color: #F44336;
}
.question-text {
font-size: 18px;
font-weight: 500;
color: #333;
margin-bottom: 20px;
line-height: 1.5;
}
.question-hint {
font-size: 14px;
color: #888;
margin-top: 5px;
font-style: italic;
}
.options-container {
display: flex;
flex-direction: column;
gap: 12px;
}
.option-item {
display: flex;
align-items: center;
padding: 12px 15px;
background: #fff;
border: 2px solid #e0e0e0;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s ease;
}
.option-item:hover {
border-color: #4CAF50;
background: #f8fff8;
}
.option-item.selected {
border-color: #4CAF50;
background: #f0f9f0;
}
.option-radio, .option-checkbox {
margin-right: 12px;
width: 20px;
height: 20px;
}
.option-label {
font-size: 16px;
color: #333;
flex: 1;
}
.text-input {
width: 100%;
padding: 12px 15px;
font-size: 16px;
border: 2px solid #e0e0e0;
border-radius: 6px;
transition: border-color 0.2s ease;
}
.text-input:focus {
outline: none;
border-color: #4CAF50;
}
.rating-container {
display: flex;
gap: 10px;
justify-content: center;
}
.rating-star {
font-size: 32px;
color: #ddd;
cursor: pointer;
transition: color 0.2s ease;
}
.rating-star.active {
color: #FFC107;
}
.rating-star:hover {
color: #FFC107;
}
.matrix-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.matrix-table th, .matrix-table td {
padding: 12px;
text-align: center;
border: 1px solid #e0e0e0;
}
.matrix-table th {
background: #f5f5f5;
font-weight: 500;
}
.matrix-option {
display: inline-block;
margin: 0 5px;
}
.survey-navigation {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 30px;
border-top: 2px solid #f0f0f0;
}
.nav-button {
padding: 12px 30px;
font-size: 16px;
font-weight: 500;
border: none;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s ease;
}
.nav-button.prev {
background: #f5f5f5;
color: #666;
}
.nav-button.prev:hover {
background: #e0e0e0;
}
.nav-button.next {
background: #4CAF50;
color: white;
}
.nav-button.next:hover {
background: #45a049;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3);
}
.nav-button.submit {
background: #2196F3;
color: white;
}
.nav-button.submit:hover {
background: #1976D2;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);
}
.survey-footer {
margin-top: 30px;
text-align: center;
font-size: 14px;
color: #888;
}
/* 响应式设计 */
@media (max-width: 768px) {
.survey-container {
padding: 20px;
margin: 10px;
}
.survey-title {
font-size: 24px;
}
.question-item {
padding: 20px;
}
.question-text {
font-size: 16px;
}
.nav-button {
padding: 10px 20px;
font-size: 14px;
}
.matrix-table {
font-size: 14px;
}
.matrix-table th, .matrix-table td {
padding: 8px;
}
}
/* 动画效果 */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.question-item {
animation: fadeIn 0.5s ease forwards;
}
.question-item:nth-child(odd) {
animation-delay: 0.1s;
}
.question-item:nth-child(even) {
animation-delay: 0.2s;
}
数据统计与分析模块
数据可视化组件
<?php
/**
* 数据统计与分析类
*/
class Survey_Analytics {
private $db;
public function __construct() {
$this->db = new Survey_DB();
// 注册AJAX端点
add_action('wp_ajax_get_survey_stats', array($this, 'get_survey_statistics'));
}
/**
* 获取问卷统计数据
*/
public function get_survey_statistics($survey_id) {
global $wpdb;
$stats = array(
'summary' => array(),
'questions' => array(),
'demographics' => array(),
'timeline' => array()
);
// 基础统计
$stats['summary'] = array(
'total_responses' => $this->get_total_responses($survey_id),
'completion_rate' => $this->get_completion_rate($survey_id),
'average_time' => $this->get_average_completion_time($survey_id),
'daily_average' => $this->get_daily_average($survey_id)
);
// 问题分析
$questions = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}survey_questions WHERE survey_id = %d ORDER BY sort_order",
$survey_id
));
foreach ($questions as $question) {
$question_stats = $this->analyze_question($question->id, $question->question_type);
$stats['questions'][] = array(
'id' => $question->id,
'text' => $question->question_text,
'type' => $question->question_type,
'stats' => $question_stats
);
}
// 用户画像(如果收集了用户信息)
$stats['demographics'] = $this->analyze_demographics($survey_id);
// 时间线数据
$stats['timeline'] = $this->get_response_timeline($survey_id);
return $stats;
}
/**
* 分析单个问题
*/
private function analyze_question($question_id, $question_type) {
global $wpdb;
$stats = array();
switch ($question_type) {
case 'single_choice':
case 'multiple_choice':
// 获取选项统计
$answers = $wpdb->get_results($wpdb->prepare(
"SELECT answer_value, COUNT(*) as count
