初始化项目:添加后端代码、ThinkPHP框架、前端资源

This commit is contained in:
amb
2026-09-03 12:42:39 +08:00
commit 482bece22e
3726 changed files with 416708 additions and 0 deletions
@@ -0,0 +1,713 @@
<?php
namespace app\admin\controller\data;
use app\common\controller\Backend;
use think\Db;
use PHPExcel_IOFactory;
/**
* 专栏数据
* @icon fa fa-circle-o
*/
class Column extends Backend
{
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\data\Study();
$this->courseModel = new \app\admin\model\course\Course();
$this->userModel = new \app\admin\model\User();
$this->timeModel = new \app\admin\model\data\Time();
$this->columnBindModel = new \app\admin\model\course\ColumnBind;
$this->subscriptionModel = new \app\common\model\user\Subscription();
}
/**
* 课程概况
* @return void
*/
public function total(){
$this->request->filter(['strip_tags', 'trim']);
$columnId = input('column_id', 0);
// 1. 获取专栏下的所有课程ID
$courseIds = $this->columnBindModel
->with(['course'])
->where(['course.status' => 1, 'column_id' => $columnId,'course_id'=>['<>',0]])
->column('course.id');
// 2. 学员总数 (student_total)
// 这里我们假设 $this->subscriptionModel 是用来获取订阅/报名该专栏的用户
$studentTotal = $this->subscriptionModel->where(['course_id' => $columnId])->count();
// 3. 小节总数 (section_total)
// 如果你的“小节总数”实际上是“课程数”,请使用下面这行:
$totalCourseCount = count($courseIds);
if (empty($courseIds)) {
return $this->success("获取成功", [
'student_total' => $studentTotal,
'section_total' => $totalCourseCount,
'participate_count' => 0,
'participate_rate' => 0.00,
'finish_count' => 0,
'finish_rate' => 0.00,
]);
}
// 构造基础查询条件
$baseWhere = [
's.uniacid' => UNIACID,
's.course_id' => ['in', $courseIds],
's.column_id'=>$columnId
];
// 4. 参与人数 (participate_count)
// 定义:至少学习了一个小节的去重用户数
$participateCount = $this->model
->setUniacid(false)
->alias('s')
->where($baseWhere)
->count('DISTINCT s.user_id');
// 5. 完成人数 (finish_count)
// 子查询:计算每个用户完成了多少门课
// 这里的逻辑是:一个用户在一门课中只要有一个小节标记为 finish=1,就认为他完成了这门课
$finishedCoursesSubquery = $this->model
->setUniacid(false)
->alias('s')
->field('s.user_id, COUNT(DISTINCT s.course_id) as finished_course_count')
->where($baseWhere)
->where('s.finish', 1)
->group('s.user_id')
->buildSql();
// 主查询:筛选出完成课程数等于总课程数的用户
$finishCount = $this->model
->setUniacid(false)
->table("($finishedCoursesSubquery) AS user_finish_stats")
->where('user_finish_stats.finished_course_count', $totalCourseCount)
->count();
// 6. 参与率 (participate_rate)
$participateRate = $studentTotal > 0 && $participateCount
? floatval(($participateCount / $studentTotal))
: 0.00;
// 7. 完成率 (finish_rate)
$finishRate = $studentTotal > 0 && $finishCount
? floatval(($finishCount / $studentTotal))
: 0.00;
// 组织最终结果
$result = [
'student_total' => $studentTotal,
'section_total' => $totalCourseCount,
'participate_count' => $participateCount,
'participate_rate' => round($participateRate, 2),
'finish_count' => $finishCount,
'finish_rate' => round($finishRate, 2),
];
return $this->success("获取成功", $result);
}
/**
* 章节概括
* @return void
*/
public function userdetail(){
$this->request->filter(['strip_tags', 'trim']);
$columnId = input('column_id/d', 0);
$userId = input('user_id/d', 0);
if (!$columnId || !$userId) {
return $this->error("缺少必要参数");
}
// 1. 获取专栏所有课程
$courseIds = $this->columnBindModel
->with(['course'])
->where(['course.status' => 1, 'column_id' => $columnId,'course_id'=>['<>',0]])
->column('course.id');
if(!$courseIds){
return $this->success("获取成功", []);
}
$studyList = $this->courseModel
->alias('course')
->join($this->model->getTable()." study", "study.course_id = course.id AND study.user_id = {$userId} AND study.column_id = {$columnId} AND study.uniacid = " . UNIACID, 'LEFT')
->where([
'course.id' => ['in', $courseIds]
])
->field([
'course.id as course_id',
'course.name as course_name',
'course.cover as course_cover',
'course.type as course_type',
'COUNT(study.id) AS record_count',
'SUM(study.total_time) AS total_time_sec',
'MAX(study.media_progress) AS media_progress_sec',
'MIN(study.start_time) AS first_study_time',
'MAX(study.end_time) AS last_study_time',
'SUM(CASE WHEN study.finish = 1 THEN 1 ELSE 0 END) AS finish_count'
])
->group('course.id')
->order('total_time_sec','desc')
->select();
foreach ($studyList as $cid => $row) {
$row['course'] = [
'id' => $row['course_id'],
'name' => $row['course_name'],
'cover' => $row['course_cover'],
'type' => $row['course_type'],
];
// 参与状态
if ($row['finish_count'] > 0) {
$row['status'] = '已完成';
} elseif ($row['record_count'] > 0) {
$row['status'] = '进行中';
}
// 时长(秒→分钟)
$row['total_minutes'] = intval($row['total_time_sec']);
// 观看进度
$row['progress_minutes'] = intval($row['media_progress_sec']);
// 时间格式
$row['first_study_time'] = $row['first_study_time'] ? date('Y-m-d H:i:s', $row['first_study_time']) : '-';
$row['last_study_time'] = $row['last_study_time'] ? date('Y-m-d H:i:s', $row['last_study_time']) : '-';
$result[] = $row;
}
return $this->success("获取成功", $result);
}
/**
* 章节概括
* @return void
*/
public function course(){
$this->request->filter(['strip_tags','trim']);
$columnId = input('column_id/d', 0);
if (!$columnId) {
return $this->error("缺少必要参数");
}
// 1. 获取专栏内所有课程
$courses = $this->courseModel
->alias('c')
->join($this->columnBindModel->getTable()." cb", "cb.course_id = c.id AND cb.column_id = {$columnId}", 'LEFT')
->where(['c.status' => 1,'cb.course_id'=>['<>',0]])
->field('c.id,c.name,c.cover,c.type')
->group('cb.course_id')
->select();
if (!$courses) {
return $this->success("获取成功", ['total' => 0, 'rows' => []]);
}
$courseIds = array_column($courses, 'id');
// 2. 统计每门课程参与人数和完成人数
$studyStats = $this->model
->alias('s')
->where(['s.column_id' => $columnId, 's.uniacid' => UNIACID])
->whereIn('s.course_id', $courseIds)
->field([
's.course_id',
'COUNT(DISTINCT s.user_id) AS participate_user_count',
'SUM(CASE WHEN s.finish = 1 THEN 1 ELSE 0 END) AS finish_user_count'
])
->group('s.course_id')
->select();
// 3. 建立课程ID映射
$statsMap = [];
foreach ($studyStats as $stat) {
$statsMap[$stat['course_id']] = $stat;
}
// 4. 计算专栏总用户数(用于参与率)
$totalUserCount = $this->subscriptionModel
->where(['course_id' => $columnId])
->count();
// 5. 构造结果
$result = [];
foreach ($courses as $course) {
$cid = $course['id'];
$participate = isset($statsMap[$cid]) ? (int)$statsMap[$cid]['participate_user_count'] : 0;
$finish = isset($statsMap[$cid]) ? (int)$statsMap[$cid]['finish_user_count'] : 0;
$result[] = [
'course' => [
'id' => $course['id'],
'name' => $course['name'],
'cover' => $course['cover'],
'type' => $course['type'],
],
'participate_user_count' => $participate,
'participate_rate' => $totalUserCount > 0 && $participate ? number_format($participate / $totalUserCount * 100, 2) . '%' : '0%',
'finish_user_count' => $finish,
'finish_rate' => $participate > 0 && $totalUserCount ? number_format($finish / $totalUserCount * 100, 2) . '%' : '0%',
];
}
return $this->success("获取成功", ['total' => count($result), 'rows' => $result]);
}
protected $exportCourseIndex = 0;
public function courseDownload(){
$this->request->filter(['strip_tags','trim']);
$columnId = input('column_id/d', 0);
if (!$columnId) {
return $this->error("缺少必要参数");
}
// 1. 获取专栏内所有课程
$courses = $this->courseModel
->alias('c')
->join($this->columnBindModel->getTable()." cb", "cb.course_id = c.id AND cb.column_id = {$columnId}", 'LEFT')
->where(['c.status' => 1,'cb.course_id'=>['<>',0]])
->field('c.id,c.name')
->group('cb.course_id')
->select();
if (!$courses) {
return $this->error("未获取到相关课程");
}
$courseIds = array_column($courses, 'id');
// 2. 统计每门课程参与人数和完成人数
$studyStats = $this->model
->alias('s')
->where(['s.column_id' => $columnId, 's.uniacid' => UNIACID])
->whereIn('s.course_id', $courseIds)
->field([
's.course_id',
'COUNT(DISTINCT s.user_id) AS participate_user_count',
'SUM(CASE WHEN s.finish = 1 THEN 1 ELSE 0 END) AS finish_user_count'
])
->group('s.course_id')
->select();
// 3. 建立课程ID映射
$statsMap = [];
foreach ($studyStats as $stat) {
$statsMap[$stat['course_id']] = $stat;
}
// 4. 计算专栏总用户数(用于参与率)
$totalUserCount = $this->subscriptionModel
->where(['course_id' => $columnId])
->count();
$excelTitle = '小节概况【'.date('Y-m-d h:i',time()).'】';
$objPHPExcel = new \PHPExcel();
//设置Excel属性
$objPHPExcel->getProperties()
->setTitle($excelTitle); //设置标题
$objPHPExcel->getActiveSheet()->setCellValue('A1', '课程');//可以指定位置
$objPHPExcel->getActiveSheet()->setCellValue('B1', '参与人数');//可以指定位置
$objPHPExcel->getActiveSheet()->setCellValue('C1', '参与率');
$objPHPExcel->getActiveSheet()->setCellValue('D1', '完成人数');
$objPHPExcel->getActiveSheet()->setCellValue('E1', '完成率');
foreach ($courses as $course) {
$cid = $course['id'];
$participate = isset($statsMap[$cid]) ? (int)$statsMap[$cid]['participate_user_count'] : 0;
$finish = isset($statsMap[$cid]) ? (int)$statsMap[$cid]['finish_user_count'] : 0;
$objPHPExcel->getActiveSheet()->setCellValue('A'.(2 + $this->exportCourseIndex), $course['name']);
$objPHPExcel->getActiveSheet()->setCellValue('B'.(2 + $this->exportCourseIndex), $participate);
$objPHPExcel->getActiveSheet()->setCellValue('C'.(2 + $this->exportCourseIndex), ($totalUserCount > 0 && $participate? number_format($participate / $totalUserCount * 100, 2) . '%' : '0%'));
$objPHPExcel->getActiveSheet()->setCellValue('D'.(2 + $this->exportCourseIndex), $finish);
$objPHPExcel->getActiveSheet()->setCellValue('E'.(2 + $this->exportCourseIndex), ($participate > 0 && $finish ? number_format($finish / $totalUserCount * 100, 2) . '%' : '0%'));
$this->exportCourseIndex++;
}
//设置字体
$objPHPExcel->getActiveSheet()->getStyle('A1:E1')->getFont()->setBold(true)->getColor()->setARGB(\PHPExcel_Style_Color::COLOR_BLACK);
//设置水平居中
$objPHPExcel->getActiveSheet()->getStyle('A1:E1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
//设置背景颜色
$objPHPExcel->getActiveSheet()->getStyle('A1:E1')->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setARGB('D9FFC125');
$objPHPExcel->getActiveSheet()->getColumnDimension('A')->setWidth(20);
$objPHPExcel->getActiveSheet()->getColumnDimension('B')->setWidth(15);
$objPHPExcel->getActiveSheet()->getColumnDimension('C')->setWidth(15);
$objPHPExcel->getActiveSheet()->getColumnDimension('D')->setWidth(18);
$objPHPExcel->getActiveSheet()->getColumnDimension('E')->setWidth(18);
//激活当前表
$objPHPExcel->setActiveSheetIndex(0);
ob_end_clean();//清除缓冲区,避免乱码
//弹出提示下载文件
header('pragma:public');
header("Content-Disposition:attachment;filename={$excelTitle}.xlsx");
header('Cache-Control: max-age=0');
$objWriter = PHPExcel_IOFactory:: createWriter($objPHPExcel, 'Excel2007');
$objWriter->save( 'php://output');
}
/**
* 学员详情(包含未参与学习的用户)
*/
public function user()
{
$this->request->filter(['strip_tags', 'trim']);
$columnId = input('column_id/d', 0);
if (!$columnId) {
return $this->error("缺少必要参数");
}
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
// 1. 复用工具方法:获取订阅学员列表(带分页)
$subscriptionResult = $this->getSubscriptionUsers($columnId, $limit);
$userList = $subscriptionResult['userList'];
$pagination = $subscriptionResult['pagination'];
if (empty($userList)) {
return $this->success("获取成功", [
"total" => 0,
"rows" => [],
"total_section_count" => 0
]);
}
// 2. 复用工具方法:获取学员学习统计数据
$statResult = $this->getUserStudyStats($columnId, $userList);
$map = $statResult['map'];
$hasStudyUserIds = $statResult['hasStudyUserIds'];
$totalSectionCount = $statResult['totalSectionCount'];
// 3. 复用工具方法:组装学员详情数据
$rows = $this->assembleUserDetailData($userList, $map, $hasStudyUserIds, $totalSectionCount);
// 4. 自定义排序(当前方法特有逻辑)
usort($rows, function($a, $b) use ($sort, $order) {
if ($a['sort_flag'] != $b['sort_flag']) {
return $b['sort_flag'] - $a['sort_flag'];
}
if (empty($sort)) {
return 0;
}
$fieldA = $a[$sort] ?? 0;
$fieldB = $b[$sort] ?? 0;
if (in_array($sort, ['first_study_time', 'last_study_time'])) {
$fieldA = $fieldA != '-' ? strtotime($fieldA) : 0;
$fieldB = $fieldB != '-' ? strtotime($fieldB) : 0;
}
return $order == 'desc' ? $fieldB - $fieldA : $fieldA - $fieldB;
});
return $this->success("获取成功", [
"total" => $pagination->total(),
"rows" => $rows,
"total_section_count" => $totalSectionCount
]);
}
/**
* 学员详情导出
*/
public function userDownload()
{
$this->request->filter(['strip_tags', 'trim']);
$columnId = input('column_id/d', 0);
if (!$columnId) {
return $this->error("缺少必要参数:column_id");
}
// 1. 复用工具方法:获取订阅学员列表(无分页)
$subscriptionResult = $this->getSubscriptionUsers($columnId, 0);
$userList = $subscriptionResult['userList'];
if (empty($userList)) {
return $this->error("无学员数据可导出");
}
// 2. 复用工具方法:获取学员学习统计数据
$statResult = $this->getUserStudyStats($columnId, $userList);
$map = $statResult['map'];
$totalSectionCount = $statResult['totalSectionCount'];
// 3. 组装导出数据(当前方法特有逻辑)
$exportData = $this->assembleExportData($userList, $map, $totalSectionCount);
// 4. 排序(导出特有排序:participated_count降序)
usort($exportData, function($a, $b) {
return $b['participated_count'] - $a['participated_count'];
});
// 5. 执行导出(Excel逻辑不变)
$this->exportExcel($exportData);
}
/**
* 工具方法:获取专栏订阅学员列表
* @param int $columnId 专栏ID
* @param int $limit 分页条数(0表示无分页)
* @return array ['userList' => 学员列表, 'pagination' => 分页对象(无分页时为null)]
*/
private function getSubscriptionUsers(int $columnId, int $limit = 0)
{
$result = [
'userList' => [],
'pagination' => null
];
// 构建查询
$query = $this->subscriptionModel
->with(['user', 'mobileuser'])
->distinct(true)
->where(['course_id' => $columnId])
->group('subscription.id');
// 分页/无分页处理
if ($limit > 0) {
$pagination = $query->paginate($limit);
$result['pagination'] = $pagination;
$list = $pagination->items();
} else {
$list = $query->select();
}
// 整理学员数据(user/mobileuser统一格式)
if ($list) {
foreach ($list as &$row) {
if ($row->user->id) {
$row->getRelation('user')->visible(\app\admin\model\User::$listShowField);
$row->user->user_id = $row->user->id;
$result['userList'][] = $row->user;
continue;
}
if ($row->mobileuser->id) {
$row->getRelation('mobileuser')->visible(\app\admin\model\User::$listShowField);
$row->mobileuser->user_id = $row->mobileuser->id;
$result['userList'][] = $row->mobileuser;
continue;
}
}
}
return $result;
}
/**
* 工具方法:获取学员学习统计数据
* @param int $columnId 专栏ID
* @param array $userList 学员列表(含user_id
* @return array ['map' => 学习数据映射, 'hasStudyUserIds' => 有学习记录的用户ID, 'totalSectionCount' => 专栏总课程数]
*/
private function getUserStudyStats(int $columnId, array $userList)
{
$userIds = array_column($userList, "user_id");
// 统计学习数据
$studyStats = $this->model
->alias("s")
->where([
"s.column_id" => $columnId,
"s.uniacid" => UNIACID
])
->whereIn("s.user_id", $userIds)
->field([
's.user_id',
'COUNT(s.id) AS participated_count',
'SUM(CASE WHEN s.finish = 1 THEN 1 ELSE 0 END) AS finished_count',
'SUM(s.total_time) AS total_study_time_minutes',
'MIN(s.start_time) AS first_study_time',
'MAX(s.end_time) AS last_study_time',
])
->group("s.user_id")
->select();
// 构建映射和有学习记录的用户ID列表
$map = [];
$hasStudyUserIds = [];
foreach ($studyStats as $row) {
$map[$row['user_id']] = $row;
$hasStudyUserIds[] = $row['user_id'];
}
// 获取专栏总课程数
$courseIds = $this->columnBindModel
->where(['status' => 1, 'column_id' => $columnId])
->column('course_id');
$totalSectionCount = count($courseIds);
return [
'map' => $map,
'hasStudyUserIds' => $hasStudyUserIds,
'totalSectionCount' => $totalSectionCount
];
}
/**
* 工具方法:组装学员详情页数据(带排序标识)
* @param array $userList 学员列表
* @param array $map 学习数据映射
* @param array $hasStudyUserIds 有学习记录的用户ID
* @param int $totalSectionCount 专栏总课程数
* @return array 组装后的详情数据
*/
private function assembleUserDetailData(array $userList, array $map, array $hasStudyUserIds, int $totalSectionCount)
{
$rows = [];
foreach ($userList as $user) {
$uid = $user["user_id"];
$stat = $map[$uid] ?? [
"participated_count" => 0,
"finished_count" => 0,
"first_study_time" => null,
"last_study_time" => null,
"total_study_time_minutes" => 0,
];
$participated = intval($stat["participated_count"]);
$finished = intval($stat["finished_count"]);
$rows[] = [
"sort_flag" => in_array($uid, $hasStudyUserIds) ? 1 : 0,
"user" => [
"id" => $uid,
"username" => $user["username"],
"nickname" => $user["nickname"],
"avatar" => $user["avatar"],
],
"participated_count" => $participated,
"finished_count" => $finished,
"participated_rate" => $totalSectionCount && $participated ? number_format($participated / $totalSectionCount * 100, 2) . "%" : "0%",
"completion_rate" => $totalSectionCount && $finished ? number_format($finished / $totalSectionCount * 100, 2) . "%" : "0%",
"study_status" => $participated == 0 ? "未参与" : ($finished >= $totalSectionCount ? "已完成" : "进行中"),
"first_study_time" => $stat["first_study_time"] ? date("Y-m-d H:i:s", $stat["first_study_time"]) : "-",
"last_study_time" => $stat["last_study_time"] ? date("Y-m-d H:i:s", $stat["last_study_time"]) : "-",
"total_study_time_minutes" => intval($stat["total_study_time_minutes"]),
];
}
return $rows;
}
/**
* 工具方法:组装导出数据
* @param array $userList 学员列表
* @param array $map 学习数据映射
* @param int $totalSectionCount 专栏总课程数
* @return array 导出格式数据
*/
private function assembleExportData(array $userList, array $map, int $totalSectionCount)
{
$exportData = [];
foreach ($userList as $user) {
$uid = $user["user_id"];
$stat = $map[$uid] ?? [
"participated_count" => 0,
"finished_count" => 0,
"first_study_time" => null,
"last_study_time" => null,
"total_study_time_minutes" => 0,
];
$participated = intval($stat["participated_count"]);
$finished = intval($stat["finished_count"]);
$exportData[] = [
'username' => $user["username"] ?? "未知用户",
'study_status' => $participated == 0 ? "未参与" : ($finished >= $totalSectionCount ? "已完成" : "进行中"),
'participated_count' => $participated,
'participated_rate' => $totalSectionCount && $participated ? number_format($participated / $totalSectionCount * 100, 2) . "%" : "0%",
'finished_count' => $finished,
'completion_rate' => $totalSectionCount && $finished ? number_format($finished / $totalSectionCount * 100, 2) . "%" : "0%",
'first_study_time' => $stat["first_study_time"] ? date("Y-m-d H:i:s", $stat["first_study_time"]) : "-",
'last_study_time' => $stat["last_study_time"] ? date("Y-m-d H:i:s", $stat["last_study_time"]) : "-",
'total_study_time' => number_format((float)$stat["total_study_time_minutes"] / 60, 1) . " 分钟",
];
}
return $exportData;
}
/**
* 工具方法:Excel导出执行
* @param array $exportData 导出数据
*/
private function exportExcel(array $exportData)
{
$excelTitle = '学员详情【' . date('Y-m-d H:i', time()) . '】';
$objPHPExcel = new \PHPExcel();
// 设置Excel属性和表头
$objPHPExcel->getProperties()->setTitle($excelTitle);
$headers = [
'A1' => '学员用户名', 'B1' => '课程参与状态', 'C1' => '小节参与数',
'D1' => '小节参与率', 'E1' => '小节完成数', 'F1' => '小节完成率',
'G1' => '首次学习时间', 'H1' => '最后学习时间', 'I1' => '学习时长(分钟)'
];
foreach ($headers as $cell => $title) {
$objPHPExcel->getActiveSheet()->setCellValue($cell, $title);
}
// 填充数据
$startRow = 2;
foreach ($exportData as $data) {
$objPHPExcel->getActiveSheet()
->setCellValue('A' . $startRow, $data['username'])
->setCellValue('B' . $startRow, $data['study_status'])
->setCellValue('C' . $startRow, $data['participated_count'])
->setCellValue('D' . $startRow, $data['participated_rate'])
->setCellValue('E' . $startRow, $data['finished_count'])
->setCellValue('F' . $startRow, $data['completion_rate'])
->setCellValue('G' . $startRow, $data['first_study_time'])
->setCellValue('H' . $startRow, $data['last_study_time'])
->setCellValue('I' . $startRow, $data['total_study_time']);
$startRow++;
}
// 设置样式
$objPHPExcel->getActiveSheet()->getStyle('A1:I1')->getFont()->setBold(true)->getColor()->setARGB(\PHPExcel_Style_Color::COLOR_BLACK);
$objPHPExcel->getActiveSheet()->getStyle('A1:I1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
$objPHPExcel->getActiveSheet()->getStyle('A1:I1')->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setARGB('D9FFC125');
$columnWidths = ['A' => 20, 'B' => 15, 'C' => 15, 'D' => 18, 'E' => 18, 'F' => 18, 'G' => 20, 'H' => 20, 'I' => 16];
foreach ($columnWidths as $column => $width) {
$objPHPExcel->getActiveSheet()->getColumnDimension($column)->setWidth($width);
}
// 导出响应
$objPHPExcel->setActiveSheetIndex(0);
ob_end_clean();
header('pragma:public');
header("Content-Disposition:attachment;filename={$excelTitle}.xlsx");
header('Cache-Control: max-age=0');
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save('php://output');
}
// 原有的导出索引属性(当前已无需使用,可删除)
// protected $exportUserIndex = 0;
}