工单
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\ResponseTrait;
|
||||
use support\Request;
|
||||
use Shopwwi\WebmanFilesystem\Facade\Storage;
|
||||
|
||||
class UploadController
|
||||
{
|
||||
|
||||
use ResponseTrait;
|
||||
|
||||
public function upload(Request $request)
|
||||
{
|
||||
try {
|
||||
$scene = $request->input('scene', 'image');
|
||||
$file = $request->file('file');
|
||||
if ($file && $file->isValid()) {
|
||||
$pathUrl = '/uploads/'.$scene.'/'.date('Ymd').'/'.md5($file->getUploadName() . time()).'.'.$file->getUploadExtension();
|
||||
$fullPathUrl = public_path() . $pathUrl;
|
||||
$file->move($fullPathUrl);
|
||||
$data = [
|
||||
'domain' => getenv('MAIN_DOMAIN'),
|
||||
'file_url' => $pathUrl,
|
||||
'full_url' => getenv('MAIN_DOMAIN') . $pathUrl,
|
||||
'scene' => $scene,
|
||||
];
|
||||
return $this->success($data, 'upload success');
|
||||
}
|
||||
return $this->error('file not found');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 上传单文件附件
|
||||
public function uploadFile(Request $request)
|
||||
{
|
||||
try {
|
||||
$file = $request->file('file');
|
||||
|
||||
if (!$file || !$file->isValid()) {
|
||||
return $this->error('上传失败');
|
||||
}
|
||||
|
||||
$result = Storage::adapter('oss')
|
||||
->path('vehicle_album/'.date('Ymd'))
|
||||
->size(1024*1024*5)
|
||||
->upload($file);
|
||||
|
||||
$ossservice = new OssService();
|
||||
|
||||
$data = [
|
||||
'file_name' => $result->file_name,
|
||||
'file_url' => $ossservice->generatePrivateUrl($result->file_name)
|
||||
];
|
||||
|
||||
return $this->success($data);
|
||||
}catch (\Throwable $e){
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 上传单文件图片
|
||||
public function uploadImage(Request $request)
|
||||
{
|
||||
try {
|
||||
$file = $request->file('image');
|
||||
|
||||
if (!$file || !$file->isValid()) {
|
||||
return $this->error('上传失败');
|
||||
}
|
||||
|
||||
$result = Storage::adapter('oss')
|
||||
->path('vehicle_album/'.date('Ymd'))
|
||||
->size(1024*1024*5)
|
||||
->extYes(['image/jpeg','image/png'])
|
||||
->extNo(['image/gif'])
|
||||
->upload($file);
|
||||
|
||||
$ossservice = new OssService();
|
||||
|
||||
$data = [
|
||||
'image_name' => $result->file_name,
|
||||
'image_url' => $ossservice->generatePrivateUrl($result->file_name)
|
||||
];
|
||||
|
||||
return $this->success($data);
|
||||
}catch (\Throwable $e){
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function proxy(Request $request)
|
||||
{
|
||||
$filePath = $request->get('file'); // 原OSS文件路径
|
||||
try {
|
||||
// 生成签名URL
|
||||
$signedUrl = (new \app\common\service\OssService())->generatePrivateUrl($filePath);
|
||||
|
||||
// 获取图片数据并返回
|
||||
$imageData = file_get_contents($signedUrl);
|
||||
|
||||
// 根据文件类型设置Content-Type
|
||||
$mime = mime_content_type('data://application/octet-stream;base64,'.base64_encode($imageData));
|
||||
|
||||
return response($imageData, 200, [
|
||||
'Content-Type' => $mime,
|
||||
'Cache-Control' => 'public, max-age=600' // 客户端缓存10分钟
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return response('Image not found '.$e->getMessage(), 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use OSS\OssClient;
|
||||
use OSS\Core\OssException;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class OssService
|
||||
{
|
||||
private $accessKeyId;
|
||||
private $accessKeySecret;
|
||||
private $bucket;
|
||||
private $endpoint;
|
||||
private $ossClient;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->accessKeyId = getenv('OSS_ACCESSID');
|
||||
$this->accessKeySecret = getenv('OSS_ACCESSSECRET');
|
||||
$this->bucket = getenv('OSS_BUCKET');
|
||||
$this->endpoint = getenv('OSS_ENDPOINT');
|
||||
$this->ossClient = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传图片到 OSS
|
||||
* @param string $filePath 本地文件路径
|
||||
* @param string $objectKey OSS上存储的对象名称
|
||||
* @return string 图片的 URL
|
||||
*/
|
||||
public function uploadImage($filePath, $objectKey)
|
||||
{
|
||||
try {
|
||||
// 上传文件到 OSS
|
||||
$this->ossClient->uploadFile($this->bucket, $objectKey, $filePath);
|
||||
// 构造图片的私有 URL
|
||||
$url = $this->generatePrivateUrl($objectKey);
|
||||
return $url;
|
||||
} catch (OssException $e) {
|
||||
// 错误处理
|
||||
throw new \RuntimeException('OSS Error: ' . $e->getMessage());
|
||||
} catch (\Throwable $th) {
|
||||
// 错误处理
|
||||
throw new BusinessException('Error: ' . $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成图片的私有访问 URL
|
||||
* @param string $objectKey
|
||||
* @return string
|
||||
*/
|
||||
public function generatePrivateUrl($objectKey, $expireTime = 3600)
|
||||
{
|
||||
// 生成 OSS 私有 URL(有效期为 3600 秒)
|
||||
return $this->ossClient->signUrl($this->bucket, $objectKey, $expireTime);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace app\ticket\controller;
|
||||
|
||||
use app\ticket\service\TicketService;
|
||||
use support\Request;
|
||||
|
||||
class AttachmentController extends BaseController
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace app\ticket\controller;
|
||||
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
use support\exception\BusinessException;
|
||||
use app\common\traits\ResponseTrait;
|
||||
use think\Validate;
|
||||
|
||||
abstract class BaseController
|
||||
{
|
||||
use ResponseTrait;
|
||||
|
||||
protected mixed $validator = null;
|
||||
|
||||
/**
|
||||
* 验证数据
|
||||
*
|
||||
* @param Validate $validator 验证器实例
|
||||
* @param array $data 待验证的数据
|
||||
* @param string $scene 验证场景
|
||||
* @return array 验证后的数据
|
||||
* @throws BusinessException 验证失败时抛出业务异常
|
||||
*/
|
||||
public function validate(Validate $validator, array $data, string $scene = ''): array
|
||||
{
|
||||
// 如果指定了验证场景,并且验证器支持场景方法,则设置验证场景
|
||||
if ($scene && method_exists($validator, 'scene')) {
|
||||
$validator->scene($scene);
|
||||
}
|
||||
// 执行数据验证
|
||||
if (!$validator->check($data)) {
|
||||
// 验证失败,抛出业务异常,异常信息为验证器返回的错误信息
|
||||
throw new BusinessException($validator->getError());
|
||||
}
|
||||
// 验证成功,返回原始数据
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function page($result){
|
||||
$current = $result->currentPage();
|
||||
$total = $result->total();
|
||||
$size = $result->perPage();
|
||||
$result = $result->toArray();
|
||||
$result['current'] = $current;
|
||||
$result['total'] = $total;
|
||||
$result['size'] = $size;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace app\ticket\controller;
|
||||
|
||||
use app\ticket\service\TicketService;
|
||||
use support\Request;
|
||||
|
||||
class TicketController extends BaseController
|
||||
{
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$result = (new TicketService())->list($request->all());
|
||||
return $this->success($this->page($result));
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
public function add(Request $request)
|
||||
{
|
||||
try {
|
||||
$request->setPost('user_id', 1);
|
||||
|
||||
return (new TicketService())->add($request->all())
|
||||
? $this->success()
|
||||
: $this->error();
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage().' '.$th->getLine().' '.$th->getFile());
|
||||
}
|
||||
}
|
||||
|
||||
public function edit(Request $request)
|
||||
{
|
||||
try {
|
||||
$request->setPost('user_id', 1);
|
||||
$result = (new TicketService())->edit($request->all());
|
||||
return $result
|
||||
? $this->success($result)
|
||||
: $this->error();
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage().' '.$th->getLine().' '.$th->getFile());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace app\ticket\logic;
|
||||
|
||||
use app\common\model\UserTokenLog;
|
||||
use app\common\model\Systems;
|
||||
use app\common\model\User;
|
||||
use app\common\model\UserSn;
|
||||
use app\common\utils\Jwt;
|
||||
use app\ticket\model\Attachment;
|
||||
use app\ticket\model\Ticket;
|
||||
use support\Redis;
|
||||
use support\exception\BusinessException;
|
||||
use support\Log;
|
||||
|
||||
class AttachmentLogic
|
||||
{
|
||||
public function adds(array $data,int $ticket_id,int $user_id)
|
||||
{
|
||||
try {
|
||||
foreach ($data as $k=>$v){
|
||||
$v['ticket_id'] = $ticket_id;
|
||||
$v['user_id'] = $user_id;
|
||||
$res = Attachment::create($v);
|
||||
}
|
||||
return $res;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('工单创建失败', [
|
||||
'data' => $data,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
throw new BusinessException($e->getMessage().'工单创建失败,请稍后重试', 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function edit(array $data,int $ticket_id,int $user_id)
|
||||
{
|
||||
try {
|
||||
$attachmentsId = [];
|
||||
foreach ($data as $k=>$v){
|
||||
$v['ticket_id'] = $ticket_id;
|
||||
$v['user_id'] = $user_id;
|
||||
if(!empty($v['id'])){ //修改附件
|
||||
$attachmentId = $v['id'];
|
||||
$attachmentsId[] = $attachmentId;
|
||||
// $v_res = Attachment::update($attachmentId, $v);
|
||||
$v_res = Attachment::updateOrCreate(['id' => $v['id']],$v);
|
||||
if (!$v_res) {
|
||||
throw new BusinessException('附件保存失败');
|
||||
}
|
||||
} else { //新增附件
|
||||
unset($v['id']);
|
||||
$v_res = Attachment::create($v);
|
||||
if (!$v_res) {
|
||||
throw new BusinessException('附件创建失败');
|
||||
}
|
||||
$vId = $v_res->id;
|
||||
$attachmentsId[] = $vId;
|
||||
}
|
||||
}
|
||||
|
||||
//删除本次没有出现的附件
|
||||
$res = Attachment::whereNotIn('id', $attachmentsId)->where('ticket_id',$ticket_id)->delete();
|
||||
return $res;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('工单创建失败', [
|
||||
'data' => $data,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
throw new BusinessException($e->getMessage().'工单创建失败,请稍后重试', 500);
|
||||
}
|
||||
}
|
||||
|
||||
public static function generateSimpleTicketNo(): string
|
||||
{
|
||||
$date = date('Ymd'); // 日期
|
||||
$prefix = 'GD'; // 前缀
|
||||
$random = strtoupper(substr(md5(uniqid()), 0, 5)); // 5位随机字母数字
|
||||
|
||||
return $prefix . $date . '-' . $random; // 如 GD20240702-AB3X9Z
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace app\ticket\logic;
|
||||
|
||||
use app\common\model\UserTokenLog;
|
||||
use app\common\model\Systems;
|
||||
use app\common\model\User;
|
||||
use app\common\model\UserSn;
|
||||
use app\common\utils\Jwt;
|
||||
use app\ticket\model\Ticket;
|
||||
use support\Redis;
|
||||
use support\exception\BusinessException;
|
||||
use support\Log;
|
||||
|
||||
class TicketLogic
|
||||
{
|
||||
public function list($params)
|
||||
{
|
||||
$where = [];
|
||||
$size = $params['size'];
|
||||
$current = $params['current'];
|
||||
return Ticket::with('attachments')->where($where)->paginate($size, ['*'], 'page', $current);
|
||||
}
|
||||
public function add(array $data)
|
||||
{
|
||||
$data['status'] = 1;
|
||||
$data['code'] = self::generateSimpleTicketNo();
|
||||
try {
|
||||
return Ticket::create($data);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('工单创建失败', [
|
||||
'data' => $data,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
throw new BusinessException($e->getMessage().'工单创建失败,请稍后重试', 500);
|
||||
}
|
||||
}
|
||||
public function edit(array $data)
|
||||
{
|
||||
try {
|
||||
unset($data['code']);
|
||||
$ticket = Ticket::updateOrCreate(['id' => $data['id']],$data);
|
||||
return $ticket;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('工单编辑失败', [
|
||||
'data' => $data,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
throw new BusinessException($e->getMessage().'工单提取方法…失败,请稍后重试', 500);
|
||||
}
|
||||
}
|
||||
|
||||
public static function generateSimpleTicketNo(): string
|
||||
{
|
||||
$date = date('Ymd'); // 日期
|
||||
$prefix = 'GD'; // 前缀
|
||||
$random = strtoupper(substr(md5(uniqid()), 0, 5)); // 5位随机字母数字
|
||||
|
||||
return $prefix . $date . '-' . $random; // 如 GD20240702-AB3X9Z
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace app\ticket\model;
|
||||
|
||||
use app\common\model\Resource;
|
||||
use app\common\model\Role;
|
||||
use app\common\model\Systems;
|
||||
use support\Model;
|
||||
|
||||
/**
|
||||
* users 用户表
|
||||
* @property integer $id 用户ID(主键)
|
||||
* @property string $ticket_id 工单编号
|
||||
* @property string $user_id 分类id
|
||||
* @property string $original_name 内容
|
||||
* @property string $storage_path 排序
|
||||
* @property string $mime_type 状态
|
||||
* @property integer $file_size 创建人id
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class Attachment extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'ticket_attachment';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
protected $fillable = [
|
||||
'ticket_id',
|
||||
'user_id',
|
||||
'original_name',
|
||||
'storage_path',
|
||||
'mime_type',
|
||||
'file_size'
|
||||
];
|
||||
|
||||
public function ticket(){
|
||||
return $this->belongsTo(Ticket::class, 'ticket_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace app\ticket\model;
|
||||
|
||||
use app\common\model\Resource;
|
||||
use app\common\model\Role;
|
||||
use app\common\model\Systems;
|
||||
use support\Model;
|
||||
|
||||
/**
|
||||
* users 用户表
|
||||
* @property integer $id 用户ID(主键)
|
||||
* @property string $code 工单编号
|
||||
* @property string $categorie_id 分类id
|
||||
* @property string $content 内容
|
||||
* @property string $sort 排序
|
||||
* @property integer $status 状态
|
||||
* @property string $user_id 创建人id
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class Ticket extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'ticket';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
protected $dates = ['created_at', 'updated_at'];
|
||||
|
||||
protected $casts = [
|
||||
'updated_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'code',
|
||||
'categorie_id',
|
||||
'content',
|
||||
'sort',
|
||||
'status',
|
||||
'user_id'
|
||||
];
|
||||
|
||||
public function attachments(){
|
||||
return $this->hasMany(Attachment::class, 'ticket_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace app\ticket\service;
|
||||
|
||||
use app\ticket\logic\AttachmentLogic;
|
||||
use app\ticket\logic\TicketLogic;
|
||||
use app\ticket\model\Ticket;
|
||||
use support\Db;
|
||||
use support\exception\BusinessException;
|
||||
use support\Log;
|
||||
|
||||
class TicketService
|
||||
{
|
||||
public function list($params)
|
||||
{
|
||||
$res = (new TicketLogic())->list($params);
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function add(array $data)
|
||||
{
|
||||
try {
|
||||
$attachment = $data['attachment']??[];
|
||||
$logic = new TicketLogic();
|
||||
$result = $logic->add($data);
|
||||
if(!empty($attachment)){
|
||||
(new AttachmentLogic())->adds($attachment, $result->id, $data['user_id']);
|
||||
}
|
||||
return $result;
|
||||
} catch (\Throwable $e) {
|
||||
Db::rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function edit(array $data)
|
||||
{
|
||||
try {
|
||||
Db::beginTransaction();
|
||||
$attachment = $data['attachment']??[];
|
||||
$logic = new TicketLogic();
|
||||
$result = $logic->edit($data);
|
||||
|
||||
if(!empty($attachment)){
|
||||
(new AttachmentLogic())->edit($attachment, $result->id, $data['user_id']);
|
||||
}
|
||||
Db::commit();
|
||||
return $result;
|
||||
} catch (\Throwable $e) {
|
||||
Db::rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user