初始化项目:添加后端代码、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
+250
View File
@@ -0,0 +1,250 @@
<?php
namespace app\common\library\share;
/**
* 分享链接
*/
class Links
{
/**
* 获取分享链接
* @param $type
* @param $params
* @return void
*/
public static function getLink($type,$params = []){
$link = self::getMobilePath();
switch ($type){
case 'goods':
$link .= '/pages/course/detail/detail';
break;
case 'physical':
$link .= '/pages/app/physical/detail/detail';
break;
case 'course':
$link .= '/pages/course/detail/detail';
break;
case 'coupon':
$link .= '/pages/app/coupon/receive/receive';
break;
case 'exercises':
$link .= '/pages/app/exam/detail/detail';
break;
case 'test':
$link .= '/pages/app/test/detail/detail';
break;
case 'vipcard':
$link .= '/pages/app/vip/center/center';
break;
case 'activity':
$link .= '/pages/app/activity/detail/detail';
break;
case 'order':
$link .= '/pages/order/detail/detail';
break;
case 'channels_share_link':
$link .= '/pages/app/channels/sharer/invite/invite';
break;
case 'activity_signin':
$link .= '/pages/app/activity/sign/sign';
break;
case 'page':
$link .= '/'.$params['path'];
break;
}
$link .= '?'. self::parseParams($type,$params);
return $link;
}
/**
* 获取小程序link
* @return void
*/
public static function getMpLink($type,$params){
$link = '';
switch ($type){
case 'goods':
$link = 'pages/course/detail/detail';
break;
case 'physical':
$link .= 'pages/app/physical/detail/detail';
break;
case 'course':
$link = 'pages/course/detail/detail';
break;
case 'exercises':
$link = 'pages/app/exam/detail/detail';
break;
case 'test':
$link = 'pages/app/test/detail/detail';
break;
case 'coupon':
$link = 'pages/app/coupon/receive/receive';
break;
case 'order':
$link = 'pages/order/detail/detail';
break;
case 'vipcard':
$link .= 'pages/app/vip/center/center';
break;
case 'channels_share_link':
$link .= 'pages/app/channels/sharer/invite/invite';
break;
case 'activity':
$link = 'pages/app/activity/detail/detail';
break;
case 'activity_signin':
$link = 'pages/app/activity/sign/sign';
break;
case 'page':
$link .= $params['path'];
break;
}
return ['link'=>$link,'params'=>self::parseParams($type,$params)];
}
/**
* 将params参数转为get参数
* @param $type
* @param $params
* @return string
*/
public static function parseParams($type,$params){
$fields = [
'goods'=>[
'id'=>'goods_id'
],
'course'=>[
'id'=>'id'
],
'physical'=>[
'id'=>'id'
],
'page'=>[
'id'=>'id'
],
'exercises'=>[
'id'=>'id'
],
'test'=>[
'id'=>'id'
],
'activity'=>[
'id'=>'id'
],
'channels_share_link'=>[
'code'=>'code'
],
'activity_signin'=>[
'id'=>'id'
],
'coupon'=>[
'id'=>'id'
],
'order'=>[
'order_no'=>'order_no'
]
];
$data = [];
$fields[$type]['share'] = 'share_id';
foreach ($fields[$type] as $index => $item){
if(isset($params[$item])){
$data[$index] = $params[$item];
}
}
return http_build_query($data);
}
/**
* 获取分享参数
* @param $type
* @param $val
* @return array
*/
public static function getShareParams($type,$val,$userId=0){
switch ($type){
case 'goods':
$params = [
'goods_id'=>$val
];
break;
case 'physical':
$params = [
'id'=>$val
];
break;
case 'exercises':
$params = [
'id'=>$val
];
break;
case 'test':
$params = [
'id'=>$val
];
break;
case 'coupon':
$params = [
'id'=>$val
];
break;
case 'activity':
$params = [
'id'=>$val
];
break;
case 'channels_share_link':
$params = [
'code'=>$val
];
break;
case 'activity_signin':
$params = [
'id'=>$val
];
break;
case 'order':
$params = [
'order_no'=>$val
];
break;
case 'page':
$params = [
'path'=>$val
];
break;
}
if($userId){
$params['share_id'] = $userId;
}
return $params;
}
/**
* 获取移动端链接
* @return string
*/
public static function getMobilePath(){
global $_W;
return $_W['siteroot'].'/index.php?i='.$_W['uniacid'].'&route=#';
}
}
+308
View File
@@ -0,0 +1,308 @@
<?php
namespace app\common\library\share;
/**
* 分享海报
*/
class Poster
{
//海报元素最小变局
protected static $minPadding = 0.9;
//海报基准宽度
protected static $basicWidth = 1024;
/**
* 创建海报
* @param $nickName 昵称
* @param $avatar 头像
* @param $qrCode 二维码
* @param $themes 风格 blue balck steel
* @return false|string
*/
public static function mkPoster($nickName,$avatar,$qrCode,$themes='blue') {
$bgPath = MODULE_ROOT.'/public/assets/poster/'.$themes.'.jpg';
$fontPath = MODULE_ROOT."/public/assets/poster/font/ding/DingTalk_JinBuTi_Regular.ttf";
$posterItems = self::getPosterItems($themes,$nickName,$avatar,$qrCode);
//用户信息
//这是要插入到图片的文字
if ($bgPath) {
if (is_file($bgPath)) {
//创建画布
$bgCanvas = imagecreatefromstring(file_get_contents($bgPath));
$bgW = imagesx($bgCanvas);
$contrastSize =$bgW /self::$basicWidth ;
foreach ($posterItems as $item){
if($item['attr']['x'] < (1-self::$minPadding) * $bgW){
$item['attr']['x'] = (1-self::$minPadding) * $bgW;
}
$sizeFields = ['x','y','w','h','size'];
foreach ($item['attr'] as $key => $option){
if(in_array($key,$sizeFields)){
$item['attr'][$key] = $option * $contrastSize;
}
}
switch ($item['type']){
case 'text':
$fontBox = imagettfbbox($item['attr']['size'], 0, $fontPath, $item['attr']['text']);
$newText = self::handleTextAlign($bgW,$fontBox[2],$item['attr']['text']);
if($newText != $item['attr']['text']){
$item['attr']['text'] = $newText;
$fontBox = imagettfbbox($item['attr']['size'], 0, $fontPath, $item['attr']['text']);
}
if(isset($item['align']) && $item['align']=='center'){
$item['attr']['x'] = ceil(($bgW - $fontBox[2])/2);
}
$color = ImageColorAllocate($bgCanvas, $item['attr']['color'][0],$item['attr']['color'][1],$item['attr']['color'][2]);
imagettftext($bgCanvas, $item['attr']['size'], $item['attr']['angle'], $item['attr']['x'], $item['attr']['y'], $color,$fontPath, $item['attr']['text']);
break;
case 'image':
if(isset($item['align']) && $item['align']=='center'){
$item['attr']['x'] = ceil(($bgW - $item['attr']['w'])/2);
}
imagecopyresampled($bgCanvas, $item['attr']['src_image'], $item['attr']['x'], $item['attr']['y'], 0, 0, $item['attr']['w'], $item['attr']['h'], imagesx($item['attr']['src_image']), imagesy($item['attr']['src_image']));
break;
}
}
ob_start();
imagepng($bgCanvas);
$imgSrc = base64_encode(ob_get_contents());
ob_end_clean();
//生成图片
return $imgSrc;
}
}
return false;
}
/**
* 处理规定宽度内自动换行(imagettftext
* @return void
*/
private static function handleTextAlign($bgW,$txtW,$text)
{
$minBgWidth = $bgW * self::$minPadding;
if($txtW <= $minBgWidth){
return $text;
}
$maxLineWordsLength = ceil(mb_strlen($text) * ($minBgWidth/ $txtW));
$string = '';
foreach (mb_str_split($text) as $index => $t){
$string .= $t;
if($index > 0 && ($index % $maxLineWordsLength) == 0){
$string .= "\n";
}
}
return $string;
}
/**
* 获取海报元素
* @param $bgType 海报背景类型
* @param $nickName 昵称
* @param $avatar 头像
* @param $qrCode 二维码
* @return array|array[]
*/
public static function getPosterItems($bgType,$nickName,$avatar,$qrCode){
$items = [
'nickname'=>[
'type'=>'text',
'align'=>'center',
'attr'=>[
'size'=>36,//字体大小
'x'=>480,//x轴
'y'=>380,//y轴
'text'=>$nickName,//内容
'angle'=>0,//角度,
'color'=>[255,255,255]//字体颜色rgb
]
],
'recommend'=>[
'type'=>'text',
'align'=>'center',
'attr'=>[
'size'=>26,//字体大小
'x'=>360,//x轴
'y'=>430,//y轴
'text'=>'向你推荐优质知识店铺',//内容
'angle'=>0,//角度,
'color'=>[255,255,255]//字体颜色rgb
]
],
'tip'=>[
'type'=>'text',
'align'=>'center',
'attr'=>[
'size'=>20,//字体大小
'x'=>400,//x轴
'y'=>1010,//y轴
'text'=>'长按识别,查看好课',//内容
'angle'=>0,//角度,
'color'=>[0,0,0]//字体颜色rgb
]
],
'other'=>[
'type'=>'text',
'align'=>'center',
'attr'=>[
'size'=>30,//字体大小
'x'=>400,//x轴
'y'=>1210,//y轴
'text'=>'不可错过的精品课程',//内容
'angle'=>0,//角度,
'color'=>[255,255,255]//字体颜色rgb
]
],
'other1'=>[
'type'=>'text',
'align'=>'center',
'attr'=>[
'size'=>35,//字体大小
'x'=>400,//x轴
'y'=>1280,//y轴
'text'=>'邀请你和我一起成长',//内容
'angle'=>0,//角度,
'color'=>[255,255,255]//字体颜色rgb
]
],
'avatar'=>[
'type'=>'image',
'align'=>'center',
'attr'=>[
'x'=>440,//x轴
'y'=>140,//y轴
'w'=>160,//宽度
'h'=>160,//高度
'src_image'=>'',//图像资源
]
],
'qrcode'=>[
'type'=>'image',
'align'=>'center',
'attr'=>[
'x'=>400,//x轴
'y'=>730,//y轴
'w'=>240,//宽度
'h'=>240,//高度
'src_image'=>'',//图像资源
]
]
];
if($bgType=='steel'){
$items['other1']['attr']['color'] = [209,141,56];
$items['other']['attr']['color'] = [209,141,56];
$items['tip']['attr']['color'] = [255,255,255];
$items['qrcode']['attr']['y'] -= 160;
$items['tip']['attr']['y'] -= 160;
$items['other']['attr']['y'] -= 240;
$items['other1']['attr']['y'] -= 240;
}
if($bgType=='black'){
$items['qrcode']['attr']['y'] -= 100;
$items['tip']['attr']['y'] -= 100;
$items['tip']['attr']['color'] = [255,255,255];
$items['other']['attr']['y'] -= 100;
$items['other1']['attr']['y'] -= 100;
}
$items['qrcode']['attr']['src_image'] = imagecreatefromstring($qrCode);
$items['avatar']['attr']['src_image'] = imagecreatefromstring(self::convertToCircleFromData($avatar));
return $items;
}
/**
* 图片转圆形
* @param $imageData 二进制图片数据
* @return false|string
*/
public static function convertToCircleFromData($imageData) {
// 创建内存中的图像资源
$image = imagecreatefromstring($imageData);
if (!$image) {
return $imageData;
}
// 获取图像的宽度和高度
$width = imagesx($image);
$height = imagesy($image);
// 创建一个新的透明图像
$mask = imagecreatetruecolor($width, $height);
imagesavealpha($mask, true);
$transparent = imagecolorallocatealpha($mask, 0, 0, 0, 127);
imagefill($mask, 0, 0, $transparent);
// 绘制圆形
$centerX = $width / 2;
$centerY = $height / 2;
$radius = min($width, $height) / 2;
imagefilledellipse($mask, $centerX, $centerY, $radius * 2, $radius * 2, imagecolorallocate($mask, 255, 255, 255));
// 创建一个新的透明图像来存储最终结果
$output = imagecreatetruecolor($width, $height);
imagesavealpha($output, true);
imagefill($output, 0, 0, $transparent);
// 应用遮罩到原始图像
for ($x = 0; $x < $width; $x++) {
for ($y = 0; $y < $height; $y++) {
$maskColor = imagecolorat($mask, $x, $y);
$alpha = 127 - ($maskColor >> 24);
if ($alpha > 0) {
$imageColor = imagecolorat($image, $x, $y);
$r = ($imageColor >> 16) & 0xFF;
$g = ($imageColor >> 8) & 0xFF;
$b = $imageColor & 0xFF;
$newColor = imagecolorallocatealpha($output, $r, $g, $b, 127 - $alpha);
imagesetpixel($output, $x, $y, $newColor);
}
}
}
// 保存处理后的图像到内存
ob_start();
imagepng($output);
$result = ob_get_clean();
// 释放图像资源
imagedestroy($image);
imagedestroy($mask);
imagedestroy($output);
return $result;
}
}
@@ -0,0 +1,197 @@
<?php
namespace app\common\library\share;
use think\Loader;
Loader::import('PhpQrcode.phpqrcode',EXTEND_PATH,'.php');
/**
* 二维码
*/
class Qrsharecode
{
/**
* 生成二维码
* @param $src
* @return void
*/
public static function mkQrcode($src){
$qrcodeLib = new \QRcode();
ob_start();
$errorLevel = 'H';
$size = 4;
$qrcodeLib::png($src,false,$errorLevel,$size);
$imgSrc = base64_encode(ob_get_contents());
ob_end_clean();
return $imgSrc;
}
/**
* 生成小程序码
* @param $src
* @return void
*/
public static function mkMpCode($page,$scene){
$wechat = new \app\common\library\Wechat('wxMiniProgram');
try{
$pageParams = [
'page' => $page,
'width'=>100
];
if($scene){
$pageParams['scene'] = $scene;
}
$code = $wechat->getApp()->app_code->getUnlimit('scene-value', $pageParams);
}catch (\Exception $e){
return false;
}
if(!$code || !is_object($code)){
return false;
}
$random = rand(1,9999);
$path = MODULE_ROOT."/public/uploads/poster/".$random.".png";
$filename = $code->saveAs(MODULE_ROOT."/public/uploads/poster/",$random. ".png");
if($filename){
$data = base64_encode(file_get_contents($path));
unlink($path);
return $data;
}
return false;
}
/**
* 生成抖音小程序码
* @param $src
* @return void
*/
public static function mkDouyinMpCode($page,$scene){
$dyMiniProgramConfig = \app\common\model\config\System::getConfig('dyMiniProgram');
$result = \douyin\Byte::init([
'app_id'=>$dyMiniProgramConfig['appid'],
'secret'=>$dyMiniProgramConfig['secret'],
])->qrcode($page.'?'.$scene);
if(!$result ||( is_array($result) && isset($result['errcode']))){
return base64_encode(file_get_contents(MODULE_ROOT.'/public/assets/image/avatar.png'));
}
try{
$random = rand(1,9999);
$path = MODULE_ROOT."/public/uploads/poster/".$random.".png";
file_put_contents($path, $result, true);
$data = base64_encode(file_get_contents($path));
unlink($path);
return $data;
}catch (\Exception $e){
return base64_encode(file_get_contents(MODULE_ROOT.'/public/assets/image/avatar.png'));
}
// $random = rand(1,9999);
// $path = MODULE_ROOT."/public/uploads/poster/".$random.".png";
// file_put_contents($path, $result, true);
// $data = base64_encode(file_get_contents($path));
// unlink($path);
// return $data;
}
/**
* 获取小程序码
* @param $type
* @param $val
* @return false|null
*/
public static function getMpCode($type,$val=0,$platform = 'wechat'){
switch ($type){
case 'course':
$type = 'goods';
$params = [
'goods_id'=>$val
];
break;
case 'evaluation':
case 'exercises':
$type = 'exercises';
$params = [
'id'=>$val
];
break;
case 'test':
$type = 'test';
$params = [
'id'=>$val
];
break;
case 'coupon':
$type = 'coupon';
$params = [
'id'=>$val
];
break;
case 'page':
$params = [
'id'=>$val,
'path'=>'pages/index/index'
];
break;
case 'group':
$type = 'page';
$params = [
'id'=>$val,
'path'=>'pages/course/group/group'
];
break;
case 'vipcard':
$type = 'page';
$params = [
'id'=>$val,
'path'=>'pages/app/vip/center/center'
];
break;
case 'activity':
$type = 'activity';
$params = [
'id'=>$val,
'path'=>'pages/app/activity/detail/detail'
];
break;
case 'physical':
$type = 'physical';
$params = [
'id'=>$val,
'path'=>'pages/app/physical/detail/detail'
];
break;
case 'index':
$type = 'page';
$params = [
'path'=>'pages/index/index'
];
break;
}
$data = \app\common\library\share\Links::getMpLink($type,$params);
if($platform == 'wechat'){
$qrCode = self::mkMpCode($data['link'],$data['params']);
}else{
$qrCode = self::mkDouyinMpCode($data['link'],$data['params']);
}
return $qrCode;
}
}