开发指南:打造网站内嵌的在线问卷调查与可视化数据分析报告
摘要
在当今数据驱动的互联网时代,网站内嵌的在线问卷调查与可视化数据分析功能已成为企业与用户互动、收集反馈、优化产品的重要工具。本文详细介绍了如何通过WordPress程序的代码二次开发,实现这一常用互联网小工具功能。我们将从需求分析、技术选型、开发流程到最终部署,全面解析打造专业级问卷调查与数据分析系统的全过程。
一、需求分析与功能规划
1.1 市场需求背景
随着互联网技术的普及,数据收集与分析已成为企业决策的重要依据。传统问卷调查方式存在诸多局限性,如数据整理繁琐、分析效率低下、可视化程度不足等。而网站内嵌的在线问卷调查系统能够实时收集用户反馈,结合可视化数据分析报告,为企业提供直观、高效的数据洞察工具。
1.2 核心功能需求
一个完整的网站内嵌问卷调查与数据分析系统应包含以下核心功能:
- 问卷创建与管理:支持多种题型(单选、多选、文本、评分等),可自定义问卷样式
- 响应式设计:适配各种设备,确保移动端用户体验
- 数据收集与存储:安全高效地收集和存储用户提交的数据
- 实时数据分析:对收集的数据进行实时统计分析
- 可视化报告:将分析结果以图表形式直观展示
- 数据导出:支持将数据导出为Excel、CSV等格式
- 权限管理:不同用户角色拥有不同的数据访问和操作权限
- 集成能力:能够与WordPress用户系统、邮件系统等无缝集成
1.3 技术可行性分析
WordPress作为全球最流行的内容管理系统,拥有强大的扩展性和丰富的API接口,通过二次开发完全可以实现上述功能需求。其优势包括:
- 成熟的用户管理系统
- 丰富的插件生态和开发文档
- 灵活的数据库结构
- 强大的主题定制能力
- 活跃的开发者社区
二、技术架构设计
2.1 系统架构概览
我们将采用分层架构设计,确保系统的可扩展性和可维护性:
┌─────────────────────────────────────────┐
│ 用户界面层 (UI Layer) │
├─────────────────────────────────────────┤
│ 业务逻辑层 (Logic Layer) │
├─────────────────────────────────────────┤
│ 数据访问层 (Data Layer) │
├─────────────────────────────────────────┤
│ WordPress核心系统 │
└─────────────────────────────────────────┘
2.2 数据库设计
在WordPress默认数据库结构基础上,我们需要新增以下数据表:
- 问卷表 (wp_surveys):存储问卷基本信息
- 问题表 (wp_survey_questions):存储问卷中的各个问题
- 选项表 (wp_survey_options):存储选择题的选项
- 回答表 (wp_survey_responses):存储用户提交的回答
- 报告表 (wp_survey_reports):存储生成的分析报告
2.3 技术栈选择
- 后端:PHP 7.4+,WordPress REST API,MySQL 5.7+
- 前端:HTML5,CSS3,JavaScript (ES6+),Chart.js/D3.js(数据可视化)
- 开发框架:基于WordPress插件架构开发
- 第三方库:jQuery(兼容性),Bootstrap(响应式布局),PHPSpreadsheet(数据导出)
三、开发环境搭建与配置
3.1 本地开发环境配置
- 安装本地服务器环境:推荐使用XAMPP、MAMP或Local by Flywheel
- 安装WordPress:下载最新版WordPress并完成基本配置
- 创建插件目录:在
wp-content/plugins/目录下创建survey-analytics-tool文件夹 - 配置开发工具:安装代码编辑器(如VS Code),配置Git版本控制
3.2 插件基础结构
创建插件主文件survey-analytics-tool.php:
<?php
/**
* Plugin Name: 问卷调查与数据分析工具
* Plugin URI: https://yourwebsite.com/
* Description: 网站内嵌的在线问卷调查与可视化数据分析报告系统
* Version: 1.0.0
* Author: 开发者名称
* License: GPL v2 or later
* Text Domain: survey-analytics-tool
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('SAT_VERSION', '1.0.0');
define('SAT_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('SAT_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
require_once SAT_PLUGIN_DIR . 'includes/class-survey-analytics-tool.php';
// 实例化主类
function sat_init() {
$plugin = new Survey_Analytics_Tool();
$plugin->run();
}
add_action('plugins_loaded', 'sat_init');
3.3 数据库表创建
创建数据库表安装脚本:
// 在includes/class-install.php中
class SAT_Install {
public static function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// 问卷表
$surveys_table = $wpdb->prefix . 'surveys';
$sql1 = "CREATE TABLE IF NOT EXISTS $surveys_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
title varchar(255) NOT NULL,
description text,
status varchar(20) DEFAULT 'draft',
created_by bigint(20) NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
settings text,
PRIMARY KEY (id)
) $charset_collate;";
// 问题表
$questions_table = $wpdb->prefix . 'survey_questions';
$sql2 = "CREATE TABLE IF NOT EXISTS $questions_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
survey_id mediumint(9) NOT NULL,
question_text text NOT NULL,
question_type varchar(50) NOT NULL,
is_required tinyint(1) DEFAULT 0,
sort_order int(11) DEFAULT 0,
options text,
PRIMARY KEY (id),
KEY survey_id (survey_id)
) $charset_collate;";
// 更多表创建语句...
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql1);
dbDelta($sql2);
// 执行其他表的创建...
}
}
四、核心功能模块开发
4.1 问卷创建与管理模块
4.1.1 后台管理界面
创建问卷管理后台页面:
// 在admin/class-admin-survey.php中
class SAT_Admin_Survey {
public function add_admin_menu() {
add_menu_page(
'问卷调查管理',
'问卷调查',
'manage_options',
'survey-analytics',
array($this, 'render_survey_list'),
'dashicons-feedback',
30
);
add_submenu_page(
'survey-analytics',
'创建新问卷',
'创建问卷',
'manage_options',
'survey-analytics-new',
array($this, 'render_survey_editor')
);
}
public function render_survey_list() {
// 显示问卷列表
include SAT_PLUGIN_DIR . 'admin/views/survey-list.php';
}
public function render_survey_editor() {
// 显示问卷编辑器
include SAT_PLUGIN_DIR . 'admin/views/survey-editor.php';
}
}
4.1.2 问卷编辑器前端实现
创建交互式问卷编辑器:
<!-- admin/views/survey-editor.php -->
<div class="wrap">
<h1>问卷编辑器</h1>
<div id="survey-builder">
<!-- 问卷基本信息 -->
<div class="survey-basic-info">
<input type="text" id="survey-title" placeholder="问卷标题">
<textarea id="survey-description" placeholder="问卷描述"></textarea>
</div>
<!-- 问题列表 -->
<div id="questions-container">
<!-- 问题将通过JavaScript动态添加 -->
</div>
<!-- 添加问题按钮 -->
<button id="add-question" class="button button-primary">添加问题</button>
<!-- 保存问卷 -->
<button id="save-survey" class="button button-primary">保存问卷</button>
</div>
</div>
<script>
// 问题类型模板
const questionTemplates = {
'single_choice': `
<div class="question-item" data-type="single_choice">
<div class="question-header">
<input type="text" class="question-text" placeholder="请输入问题">
<select class="question-required">
<option value="0">非必填</option>
<option value="1">必填</option>
</select>
<button class="remove-question">删除</button>
</div>
<div class="options-container">
<div class="option-item">
<input type="radio" disabled>
<input type="text" class="option-text" placeholder="选项文本">
<button class="remove-option">删除</button>
</div>
</div>
<button class="add-option">添加选项</button>
</div>
`,
// 其他问题类型模板...
};
// 初始化问卷编辑器
jQuery(document).ready(function($) {
// 添加问题
$('#add-question').on('click', function() {
const questionType = 'single_choice'; // 默认单选,实际中可以让用户选择
$('#questions-container').append(questionTemplates[questionType]);
});
// 保存问卷
$('#save-survey').on('click', function() {
const surveyData = {
title: $('#survey-title').val(),
description: $('#survey-description').val(),
questions: []
};
// 收集所有问题数据
$('.question-item').each(function() {
const question = {
text: $(this).find('.question-text').val(),
type: $(this).data('type'),
required: $(this).find('.question-required').val(),
options: []
};
// 收集选项数据
$(this).find('.option-item').each(function() {
question.options.push($(this).find('.option-text').val());
});
surveyData.questions.push(question);
});
// 发送到服务器保存
$.ajax({
url: sat_ajax.ajax_url,
type: 'POST',
data: {
action: 'save_survey',
nonce: sat_ajax.nonce,
survey: surveyData
},
success: function(response) {
if (response.success) {
alert('问卷保存成功!');
} else {
alert('保存失败:' + response.data.message);
}
}
});
});
});
</script>
4.2 前端问卷展示与数据收集
4.2.1 创建短代码显示问卷
// 在includes/class-shortcodes.php中
class SAT_Shortcodes {
public function register_shortcodes() {
add_shortcode('survey', array($this, 'render_survey'));
}
public function render_survey($atts) {
$atts = shortcode_atts(array(
'id' => 0,
'title' => '问卷调查'
), $atts);
$survey_id = intval($atts['id']);
if (!$survey_id) {
return '<p>请指定有效的问卷ID</p>';
}
// 获取问卷数据
$survey = $this->get_survey_data($survey_id);
if (!$survey) {
return '<p>问卷不存在或已删除</p>';
}
// 渲染问卷HTML
ob_start();
include SAT_PLUGIN_DIR . 'public/views/survey-form.php';
return ob_get_clean();
}
private function get_survey_data($survey_id) {
global $wpdb;
$table = $wpdb->prefix . 'surveys';
$survey = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table WHERE id = %d AND status = 'published'",
$survey_id
));
if ($survey) {
// 获取问题数据
$questions_table = $wpdb->prefix . 'survey_questions';
$survey->questions = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $questions_table WHERE survey_id = %d ORDER BY sort_order ASC",
$survey_id
));
// 解析问题选项
foreach ($survey->questions as &$question) {
if ($question->options) {
$question->options = maybe_unserialize($question->options);
}
}
}
return $survey;
}
}
4.2.2 问卷表单前端实现
<!-- public/views/survey-form.php -->
<div class="sat-survey-container" data-survey-id="<?php echo $survey->id; ?>">
<h2 class="survey-title"><?php echo esc_html($survey->title); ?></h2>
<?php if ($survey->description): ?>
<div class="survey-description">
<?php echo wp_kses_post($survey->description); ?>
</div>
<?php endif; ?>
<form id="sat-survey-form-<?php echo $survey->id; ?>" class="sat-survey-form">
<?php foreach ($survey->questions as $index => $question): ?>
<div class="survey-question" data-question-id="<?php echo $question->id; ?>">
<div class="question-text">
<label>
<?php echo ($index + 1) . '. ' . esc_html($question->question_text); ?>
<?php if ($question->is_required): ?>
<span class="required">*</span>
<?php endif; ?>
</label>
</div>
<div class="question-input">
<?php switch($question->question_type):
case 'single_choice': ?>
<?php foreach ($question->options as $option_index => $option): ?>
<div class="option-item">
<input type="radio"
id="q<?php echo $question->id; ?>_o<?php echo $option_index; ?>"
name="question_<?php echo $question->id; ?>"
value="<?php echo esc_attr($option); ?>"
<?php echo $question->is_required ? 'required' : ''; ?>>
<label for="q<?php echo $question->id; ?>_o<?php echo $option_index; ?>">
<?php echo esc_html($option); ?>
</label>
</div>
<?php endforeach; ?>
<?php break;
case 'multiple_choice': ?>
<!-- 多选实现 -->
<?php break;
case 'text': ?>
<textarea name="question_<?php echo $question->id; ?>"
<?php echo $question->is_required ? 'required' : ''; ?>
rows="3"></textarea>
<?php break;
case 'rating': ?>
<!-- 评分题实现 -->
<?php break;
endswitch; ?>
</div>
</div>
<?php endforeach; ?>
<div class="survey-submit">
<button type="submit" class="submit-button">提交问卷</button>
</div>
</form>
<div id="survey-thankyou" style="display:none;">
<p>感谢您参与本次问卷调查!</p>
</div>
</div>
<script>
jQuery(document).ready(function($) {
$('#sat-survey-form-<?php echo $survey->id; ?>').on('submit', function(e) {
e.preventDefault();
const formData = $(this).serializeArray();
const surveyId = $(this).closest('.sat-survey-container').data('survey-id');
// 添加survey_id到数据中
formData.push({name: 'survey_id', value: surveyId});
$.ajax({
url: sat_public.ajax_url,
type: 'POST',
data: {
action: 'submit_survey',
nonce: sat_public.nonce,
form_data: formData
},
success: function(response) {
if (response.success) {
// 显示感谢信息
$('#sat-survey-form-<?php echo $survey->id; ?>').hide();
$('#survey-thankyou').show();
} else {
alert('提交失败:' + response.data.message);
}
}
});
});
});
</script>
4.3 数据存储与处理模块
4.3.1 数据提交处理
// 在includes/class-data-handler.php中
class SAT_Data_Handler {
public function handle_survey_submission() {
// 验证nonce
if (!wp_verify_nonce($_POST['nonce'], 'sat_public_nonce')) {
wp_die('安全验证失败');
}
$survey_id = intval($_POST['survey_id']);
$form_data = $_POST['form_data'];
// 验证问卷是否存在且处于发布状态
$survey = $this->validate_survey($survey_id);
if (!$survey) {
wp_send_json_error(array('message' => '问卷不存在或已关闭'));
}
// 处理表单数据
$processed_data = array();
foreach ($form_data as $item) {
if (strpos($item['name'], 'question_') === 0) {
$question_id = str_replace('question_', '', $item['name']);
$processed_data[$question_id] = $item['value'];
}
4.3.2 数据验证与存储
// 验证必填问题
foreach ($survey->questions as $question) {
if ($question->is_required && empty($processed_data[$question->id])) {
wp_send_json_error(array(
'message' => '请填写所有必填问题',
'question_id' => $question->id
));
}
}
// 存储回答数据
$response_id = $this->store_response($survey_id, $processed_data);
if ($response_id) {
// 触发数据收集完成钩子
do_action('sat_survey_completed', $survey_id, $response_id, $processed_data);
wp_send_json_success(array(
'message' => '提交成功',
'response_id' => $response_id
));
} else {
wp_send_json_error(array('message' => '数据存储失败'));
}
}
private function store_response($survey_id, $data) {
global $wpdb;
// 插入主回答记录
$responses_table = $wpdb->prefix . 'survey_responses';
$wpdb->insert(
$responses_table,
array(
'survey_id' => $survey_id,
'user_id' => get_current_user_id(),
'ip_address' => $this->get_client_ip(),
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'created_at' => current_time('mysql')
),
array('%d', '%d', '%s', '%s', '%s')
);
$response_id = $wpdb->insert_id;
if (!$response_id) {
return false;
}
// 存储每个问题的回答
$answers_table = $wpdb->prefix . 'survey_answers';
foreach ($data as $question_id => $answer_value) {
$wpdb->insert(
$answers_table,
array(
'response_id' => $response_id,
'question_id' => $question_id,
'answer_value' => is_array($answer_value) ? serialize($answer_value) : $answer_value,
'created_at' => current_time('mysql')
),
array('%d', '%d', '%s', '%s')
);
}
return $response_id;
}
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;
}
}
4.4 数据分析与统计模块
4.4.1 数据统计功能
// 在includes/class-analytics.php中
class SAT_Analytics {
public function get_survey_statistics($survey_id) {
global $wpdb;
$statistics = array(
'basic' => $this->get_basic_stats($survey_id),
'questions' => array(),
'trends' => $this->get_response_trends($survey_id)
);
// 获取所有问题
$questions_table = $wpdb->prefix . 'survey_questions';
$questions = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $questions_table WHERE survey_id = %d ORDER BY sort_order ASC",
$survey_id
));
// 为每个问题生成统计
foreach ($questions as $question) {
$statistics['questions'][$question->id] = $this->analyze_question($question);
}
return $statistics;
}
private function get_basic_stats($survey_id) {
global $wpdb;
$responses_table = $wpdb->prefix . 'survey_responses';
// 总回答数
$total_responses = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $responses_table WHERE survey_id = %d",
$survey_id
));
// 今日回答数
$today_responses = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $responses_table
WHERE survey_id = %d AND DATE(created_at) = CURDATE()",
$survey_id
));
// 平均完成时间(如果有记录时间的话)
$avg_completion_time = null;
return array(
'total_responses' => (int)$total_responses,
'today_responses' => (int)$today_responses,
'completion_rate' => $this->calculate_completion_rate($survey_id),
'avg_completion_time' => $avg_completion_time
);
}
private function analyze_question($question) {
global $wpdb;
$answers_table = $wpdb->prefix . 'survey_answers';
$responses_table = $wpdb->prefix . 'survey_responses';
$analysis = array(
'question_id' => $question->id,
'question_text' => $question->question_text,
'question_type' => $question->question_type,
'total_answers' => 0,
'data' => array()
);
switch ($question->question_type) {
case 'single_choice':
case 'multiple_choice':
$analysis = $this->analyze_choice_question($question, $analysis);
break;
case 'rating':
$analysis = $this->analyze_rating_question($question, $analysis);
break;
case 'text':
$analysis = $this->analyze_text_question($question, $analysis);
break;
}
return $analysis;
}
private function analyze_choice_question($question, $analysis) {
global $wpdb;
$answers_table = $wpdb->prefix . 'survey_answers';
$options = maybe_unserialize($question->options);
// 获取每个选项的选择次数
$option_counts = array();
foreach ($options as $index => $option) {
$count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $answers_table
WHERE question_id = %d AND answer_value LIKE %s",
$question->id,
'%' . $wpdb->esc_like($option) . '%'
));
$option_counts[$option] = (int)$count;
}
// 计算百分比
$total = array_sum($option_counts);
$analysis['total_answers'] = $total;
foreach ($option_counts as $option => $count) {
$percentage = $total > 0 ? round(($count / $total) * 100, 2) : 0;
$analysis['data'][] = array(
'option' => $option,
'count' => $count,
'percentage' => $percentage
);
}
return $analysis;
}
private function get_response_trends($survey_id) {
global $wpdb;
$responses_table = $wpdb->prefix . 'survey_responses';
// 获取最近30天的回答趋势
$trends = $wpdb->get_results($wpdb->prepare(
"SELECT DATE(created_at) as date, COUNT(*) as count
FROM $responses_table
WHERE survey_id = %d AND created_at >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
GROUP BY DATE(created_at)
ORDER BY date ASC",
$survey_id
));
return $trends;
}
}
4.5 可视化报告生成模块
4.5.1 图表生成与展示
<!-- admin/views/analytics-dashboard.php -->
<div class="wrap">
<h1>问卷数据分析报告</h1>
<div class="sat-analytics-dashboard">
<!-- 基本统计 -->
<div class="basic-stats">
<div class="stat-card">
<h3>总回答数</h3>
<div class="stat-value" id="total-responses">0</div>
</div>
<div class="stat-card">
<h3>今日回答</h3>
<div class="stat-value" id="today-responses">0</div>
</div>
<div class="stat-card">
<h3>完成率</h3>
<div class="stat-value" id="completion-rate">0%</div>
</div>
</div>
<!-- 回答趋势图 -->
<div class="chart-container">
<h3>回答趋势</h3>
<canvas id="response-trend-chart" width="800" height="300"></canvas>
</div>
<!-- 问题分析 -->
<div id="question-analytics">
<!-- 每个问题的分析将通过JavaScript动态加载 -->
</div>
<!-- 数据导出 -->
<div class="export-options">
<button id="export-csv" class="button">导出CSV</button>
<button id="export-excel" class="button">导出Excel</button>
<button id="export-pdf" class="button">导出PDF报告</button>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
jQuery(document).ready(function($) {
const surveyId = <?php echo $survey_id; ?>;
// 加载统计数据
function loadAnalytics() {
$.ajax({
url: sat_admin.ajax_url,
type: 'GET',
data: {
action: 'get_survey_analytics',
survey_id: surveyId,
nonce: sat_admin.nonce
},
success: function(response) {
if (response.success) {
renderAnalytics(response.data);
}
}
});
}
function renderAnalytics(data) {
// 更新基本统计
$('#total-responses').text(data.basic.total_responses);
$('#today-responses').text(data.basic.today_responses);
$('#completion-rate').text(data.basic.completion_rate + '%');
// 渲染趋势图
renderTrendChart(data.trends);
// 渲染问题分析
renderQuestionAnalytics(data.questions);
}
function renderTrendChart(trends) {
const dates = trends.map(item => item.date);
const counts = trends.map(item => parseInt(item.count));
const ctx = document.getElementById('response-trend-chart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: dates,
datasets: [{
label: '回答数量',
data: counts,
borderColor: 'rgb(75, 192, 192)',
tension: 0.1,
fill: true,
backgroundColor: 'rgba(75, 192, 192, 0.2)'
}]
},
options: {
responsive: true,
plugins: {
legend: {
position: 'top',
},
title: {
display: true,
text: '回答趋势图'
}
}
}
});
}
function renderQuestionAnalytics(questions) {
const container = $('#question-analytics');
container.empty();
Object.values(questions).forEach(question => {
const questionHtml = `
<div class="question-analysis" data-question-id="${question.question_id}">
<h4>${question.question_text}</h4>
<div class="chart-container">
<canvas id="chart-${question.question_id}" width="400" height="200"></canvas>
</div>
<div class="analysis-table">
<table>
<thead>
<tr>
<th>选项</th>
<th>数量</th>
<th>百分比</th>
</tr>
</thead>
<tbody>
${question.data.map(item => `
<tr>
<td>${item.option}</td>
<td>${item.count}</td>
<td>${item.percentage}%</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
</div>
`;
container.append(questionHtml);
// 为每个问题渲染图表
renderQuestionChart(question);
});
}
function renderQuestionChart(question) {
const ctx = document.getElementById(`chart-${question.question_id}`).getContext('2d');
const labels = question.data.map(item => item.option);
const data = question.data.map(item => item.count);
const backgroundColors = generateColors(data.length);
new Chart(ctx, {
type: question.question_type === 'rating' ? 'bar' : 'pie',
data: {
labels: labels,
datasets: [{
data: data,
backgroundColor: backgroundColors,
borderWidth: 1
}]
},
options: {
responsive: true,
plugins: {
legend: {
position: 'right',
},
title: {
display: true,
text: question.question_text.substring(0, 50) + '...'
}
}
}
});
}
function generateColors(count) {
const colors = [];
for (let i = 0; i < count; i++) {
const hue = (i * 360 / count) % 360;
colors.push(`hsl(${hue}, 70%, 60%)`);
}
return colors;
}
// 初始化加载
loadAnalytics();
// 设置自动刷新
setInterval(loadAnalytics, 300000); // 每5分钟刷新一次
});
</script>
4.5.2 数据导出功能
// 在includes/class-export.php中
class SAT_Export {
public function export_csv($survey_id) {
global $wpdb;
// 获取问卷数据
$survey = $this->get_survey_with_responses($survey_id);
if (!$survey) {
return false;
}
// 设置CSV头部
$filename = 'survey_' . $survey_id . '_' . date('Ymd_His') . '.csv';
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $filename . '"');
$output = fopen('php://output', 'w');
// 写入标题行
$headers = array('回答ID', '提交时间', '用户ID', 'IP地址');
foreach ($survey->questions as $question) {
$headers[] = $question->question_text;
}
fputcsv($output, $headers);
// 写入数据行
foreach ($survey->responses as $response) {
$row = array(
$response->id,
$response->created_at,
$response->user_id,
$response->ip_address
);
foreach ($survey->questions as $question) {
$answer = $this->find_answer($response->answers, $question->id);
$row[] = $answer ? $answer->answer_value : '';
}
fputcsv($output, $row);
}
fclose($output);
exit;
}
public function export_pdf_report($survey_id) {
// 使用TCPDF或DomPDF生成PDF报告
require_once SAT_PLUGIN_DIR . 'vendor/autoload.php';
$analytics = SAT_Analytics::get_survey_statistics($survey_id);
$survey = $this->get_survey_data($survey_id);
// 创建PDF
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
// 设置文档信息
$pdf->SetCreator('Survey Analytics Tool');
$pdf->SetAuthor('WordPress');
$pdf->SetTitle('问卷分析报告 - ' . $survey->title);
// 添加页面
$pdf->AddPage();
// 添加标题
$pdf->SetFont('stsongstdlight', 'B', 16);
$pdf->Cell(0, 10, $survey->title, 0, 1, 'C');
// 添加基本统计
$pdf->SetFont('stsongstdlight', '', 12);
$pdf->Ln(10);
$pdf->Cell(0, 10, '基本统计:', 0, 1);
$pdf->Cell(0, 10, '总回答数: ' . $analytics['basic']['total_responses'], 0, 1);
$pdf->Cell(0, 10, '今日回答: ' . $analytics['basic']['today_responses'], 0, 1);
// 添加问题分析
foreach ($analytics['questions'] as $question) {
$pdf->AddPage();
$pdf->SetFont('stsongstdlight', 'B', 14);
$pdf->Cell(0, 10, $question['question_text'], 0, 1);
$pdf->SetFont('stsongstdlight', '', 12);
// 添加图表或表格...
}
// 输出PDF
