You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
279 lines
9.0 KiB
279 lines
9.0 KiB
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | Niucloud-admin 企业快速开发的多应用管理平台
|
|
// +----------------------------------------------------------------------
|
|
|
|
namespace app\service\api\student;
|
|
|
|
use app\model\physical_test\PhysicalTest;
|
|
use app\model\customer_resources\CustomerResources;
|
|
use app\model\student\Student;
|
|
use core\base\BaseService;
|
|
use core\exception\CommonException;
|
|
|
|
/**
|
|
* 体测数据服务类
|
|
*/
|
|
class PhysicalTestService extends BaseService
|
|
{
|
|
/**
|
|
* 获取学员体测记录列表
|
|
* @param array $data
|
|
* @return array
|
|
*/
|
|
public function getPhysicalTestList($data)
|
|
{
|
|
$studentId = $data['student_id'];
|
|
|
|
$page = $data['page'] ?? 1;
|
|
$limit = $data['limit'] ?? 20;
|
|
|
|
$list = (new PhysicalTest())
|
|
->where('student_id', $studentId)
|
|
->field('id,student_id,height,weight,physical_test_report,created_at,updated_at')
|
|
->order('created_at desc')
|
|
->page($page, $limit)
|
|
->select()
|
|
->toArray();
|
|
|
|
// 处理数据
|
|
foreach ($list as &$item) {
|
|
$item['test_date'] = date('Y-m-d', strtotime($item['created_at']));
|
|
$item['height_text'] = $item['height'] . 'cm';
|
|
$item['weight_text'] = $item['weight'] . 'kg';
|
|
|
|
// 处理体测报告PDF文件
|
|
$item['has_report'] = !empty($item['physical_test_report']);
|
|
$item['report_files'] = [];
|
|
|
|
if ($item['physical_test_report']) {
|
|
$files = explode(',', $item['physical_test_report']);
|
|
foreach ($files as $file) {
|
|
if ($file) {
|
|
$item['report_files'][] = [
|
|
'name' => '体测报告',
|
|
'url' => get_image_url($file),
|
|
'path' => $file
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$total = (new PhysicalTest())->where('student_id', $studentId)->count();
|
|
|
|
return [
|
|
'list' => $list,
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'limit' => $limit,
|
|
'pages' => ceil($total / $limit)
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取体测详情
|
|
* @param int $testId
|
|
* @return array
|
|
*/
|
|
public function getPhysicalTestDetail($testId)
|
|
{
|
|
$physicalTest = (new PhysicalTest())->where('id', $testId)->find();
|
|
|
|
if (!$physicalTest) {
|
|
throw new CommonException('体测记录不存在');
|
|
}
|
|
|
|
$data = $physicalTest->toArray();
|
|
|
|
// 格式化数据
|
|
$data['test_date'] = date('Y-m-d', strtotime($data['created_at']));
|
|
$data['height_text'] = $data['height'] . 'cm';
|
|
$data['weight_text'] = $data['weight'] . 'kg';
|
|
|
|
// 处理各项体测指标
|
|
$indicators = [
|
|
'seated_forward_bend' => ['name' => '坐位体前屈', 'unit' => 'cm'],
|
|
'sit_ups' => ['name' => '仰卧卷腹', 'unit' => '次'],
|
|
'push_ups' => ['name' => '九十度仰卧撑', 'unit' => '次'],
|
|
'flamingo_balance' => ['name' => '火烈鸟平衡测试', 'unit' => 's'],
|
|
'thirty_sec_jump' => ['name' => '三十秒双脚连续跳', 'unit' => '次'],
|
|
'standing_long_jump' => ['name' => '立定跳远', 'unit' => 'cm'],
|
|
'agility_run' => ['name' => '4乘10m灵敏折返跑', 'unit' => 's'],
|
|
'balance_beam' => ['name' => '走平衡木', 'unit' => 's'],
|
|
'tennis_throw' => ['name' => '网球掷远', 'unit' => 'm'],
|
|
'ten_meter_shuttle_run' => ['name' => '十米往返跑', 'unit' => 's']
|
|
];
|
|
|
|
$data['indicators'] = [];
|
|
foreach ($indicators as $key => $info) {
|
|
if ($data[$key] !== null && $data[$key] !== '') {
|
|
$data['indicators'][] = [
|
|
'name' => $info['name'],
|
|
'value' => $data[$key],
|
|
'unit' => $info['unit'],
|
|
'value_text' => $data[$key] . $info['unit']
|
|
];
|
|
}
|
|
}
|
|
|
|
// 处理体测报告文件
|
|
$data['report_files'] = [];
|
|
if ($data['physical_test_report']) {
|
|
$files = explode(',', $data['physical_test_report']);
|
|
foreach ($files as $file) {
|
|
if ($file) {
|
|
$data['report_files'][] = [
|
|
'name' => '体测报告',
|
|
'url' => get_image_url($file),
|
|
'path' => $file,
|
|
'type' => 'pdf'
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* 获取体测趋势数据(身高体重变化)
|
|
* @param array $data
|
|
* @return array
|
|
*/
|
|
public function getPhysicalTestTrend($data)
|
|
{
|
|
$studentId = $data['student_id'];
|
|
$months = $data['months'] ?? 12;
|
|
|
|
// 获取指定月份内的体测数据
|
|
$startDate = date('Y-m-d', strtotime("-{$months} months"));
|
|
|
|
$trendData = (new PhysicalTest())
|
|
->where('student_id', $studentId)
|
|
->where('created_at', '>=', $startDate)
|
|
->field('height,weight,created_at')
|
|
->order('created_at asc')
|
|
->select()
|
|
->toArray();
|
|
|
|
$heightData = [];
|
|
$weightData = [];
|
|
$dates = [];
|
|
|
|
foreach ($trendData as $item) {
|
|
$date = date('Y-m', strtotime($item['created_at']));
|
|
$dates[] = $date;
|
|
$heightData[] = [
|
|
'date' => $date,
|
|
'value' => (float)$item['height']
|
|
];
|
|
$weightData[] = [
|
|
'date' => $date,
|
|
'value' => (float)$item['weight']
|
|
];
|
|
}
|
|
|
|
// 计算增长情况
|
|
$heightGrowth = 0;
|
|
$weightGrowth = 0;
|
|
|
|
if (count($heightData) >= 2) {
|
|
$heightGrowth = end($heightData)['value'] - $heightData[0]['value'];
|
|
$weightGrowth = end($weightData)['value'] - $weightData[0]['value'];
|
|
}
|
|
|
|
return [
|
|
'height_data' => $heightData,
|
|
'weight_data' => $weightData,
|
|
'dates' => array_unique($dates),
|
|
'growth' => [
|
|
'height' => round($heightGrowth, 1),
|
|
'weight' => round($weightGrowth, 1),
|
|
'height_text' => ($heightGrowth >= 0 ? '+' : '') . round($heightGrowth, 1) . 'cm',
|
|
'weight_text' => ($weightGrowth >= 0 ? '+' : '') . round($weightGrowth, 1) . 'kg'
|
|
],
|
|
'data_count' => count($trendData),
|
|
'months' => $months
|
|
];
|
|
}
|
|
|
|
/**
|
|
* PDF转图片分享
|
|
* @param int $testId
|
|
* @return array
|
|
*/
|
|
public function convertPdfToImage($testId)
|
|
{
|
|
$physicalTest = (new PhysicalTest())->where('id', $testId)->find();
|
|
|
|
if (!$physicalTest) {
|
|
throw new CommonException('体测记录不存在');
|
|
}
|
|
|
|
|
|
// 本地保存路径
|
|
$saveDir = public_path() . "/upload/pdf_images/";
|
|
if (!is_dir($saveDir)) {
|
|
mkdir($saveDir, 0777, true);
|
|
}
|
|
|
|
// 下载远程 PDF 到本地临时文件
|
|
$pdfPath = $saveDir . uniqid() . ".pdf";
|
|
|
|
file_put_contents($pdfPath, file_get_contents($physicalTest['physical_test_report']));
|
|
|
|
// 获取第一个PDF文件
|
|
// $files = explode('/upload', $physicalTest['physical_test_report']);
|
|
// $pdfFile = '/upload'.trim($files[0]);
|
|
|
|
if (!$pdfPath) {
|
|
throw new CommonException('PDF文件路径无效');
|
|
}
|
|
|
|
|
|
if (!file_exists($pdfPath)) {
|
|
throw new CommonException('PDF文件不存在');
|
|
}
|
|
|
|
try {
|
|
// 使用Imagick将PDF转换为图片
|
|
if (!extension_loaded('imagick')) {
|
|
throw new CommonException('系统不支持PDF转图片功能');
|
|
}
|
|
|
|
$imagick = new \Imagick();
|
|
$imagick->setResolution(150, 150);
|
|
$imagick->readImage($pdfPath . '[0]'); // 只转换第一页
|
|
$imagick->setImageFormat('jpeg');
|
|
$imagick->setImageCompressionQuality(85);
|
|
|
|
// 生成图片文件名
|
|
$imageName = 'physical_test_' . $testId . '_' . time() . '.jpg';
|
|
$imagePath = 'uploads/share/' . date('Y/m/d') . '/' . $imageName;
|
|
$fullImagePath = public_path() . $imagePath;
|
|
|
|
// 确保目录存在
|
|
$dir = dirname($fullImagePath);
|
|
if (!is_dir($dir)) {
|
|
mkdir($dir, 0755, true);
|
|
}
|
|
|
|
// 保存图片
|
|
$imagick->writeImage($fullImagePath);
|
|
$imagick->clear();
|
|
$imagick->destroy();
|
|
|
|
return [
|
|
'image_url' => get_image_url($imagePath),
|
|
'image_path' => $imagePath,
|
|
'pdf_url' => get_image_url($pdfPath),
|
|
'message' => 'PDF转换为图片成功,可以分享给朋友了'
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
throw new CommonException('PDF转图片失败:' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
}
|
|
|