From 6f82d5ff72b03dd86c8122a9e2b766d49d639622 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Wed, 2 Jul 2025 17:12:38 +0800 Subject: [PATCH 01/20] =?UTF-8?q?=E5=B7=A5=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/controller/UploadController.php | 117 ++++++ app/common/service/OssService.php | 59 +++ .../controller/AttachmentController.php | 11 + app/ticket/controller/BaseController.php | 51 +++ app/ticket/controller/TicketController.php | 46 +++ app/ticket/logic/AttachmentLogic.php | 82 ++++ app/ticket/logic/TicketLogic.php | 61 +++ app/ticket/model/Attachment.php | 66 +++ app/ticket/model/Ticket.php | 73 ++++ app/ticket/service/TicketService.php | 54 +++ composer.json | 4 +- composer.lock | 377 +++++++++++++++++- config/plugin/shopwwi/filesystem/app.php | 116 ++++++ config/route.php | 11 +- 14 files changed, 1125 insertions(+), 3 deletions(-) create mode 100644 app/common/controller/UploadController.php create mode 100644 app/common/service/OssService.php create mode 100644 app/ticket/controller/AttachmentController.php create mode 100644 app/ticket/controller/BaseController.php create mode 100644 app/ticket/controller/TicketController.php create mode 100644 app/ticket/logic/AttachmentLogic.php create mode 100644 app/ticket/logic/TicketLogic.php create mode 100644 app/ticket/model/Attachment.php create mode 100644 app/ticket/model/Ticket.php create mode 100644 app/ticket/service/TicketService.php create mode 100644 config/plugin/shopwwi/filesystem/app.php diff --git a/app/common/controller/UploadController.php b/app/common/controller/UploadController.php new file mode 100644 index 0000000..c01f084 --- /dev/null +++ b/app/common/controller/UploadController.php @@ -0,0 +1,117 @@ +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); + } + } +} \ No newline at end of file diff --git a/app/common/service/OssService.php b/app/common/service/OssService.php new file mode 100644 index 0000000..4d75b1f --- /dev/null +++ b/app/common/service/OssService.php @@ -0,0 +1,59 @@ +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); + } +} \ No newline at end of file diff --git a/app/ticket/controller/AttachmentController.php b/app/ticket/controller/AttachmentController.php new file mode 100644 index 0000000..94e1724 --- /dev/null +++ b/app/ticket/controller/AttachmentController.php @@ -0,0 +1,11 @@ +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; + } +} \ No newline at end of file diff --git a/app/ticket/controller/TicketController.php b/app/ticket/controller/TicketController.php new file mode 100644 index 0000000..ff3defa --- /dev/null +++ b/app/ticket/controller/TicketController.php @@ -0,0 +1,46 @@ +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()); + } + } + +} diff --git a/app/ticket/logic/AttachmentLogic.php b/app/ticket/logic/AttachmentLogic.php new file mode 100644 index 0000000..ad3f52d --- /dev/null +++ b/app/ticket/logic/AttachmentLogic.php @@ -0,0 +1,82 @@ +$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 + } +} \ No newline at end of file diff --git a/app/ticket/logic/TicketLogic.php b/app/ticket/logic/TicketLogic.php new file mode 100644 index 0000000..0037879 --- /dev/null +++ b/app/ticket/logic/TicketLogic.php @@ -0,0 +1,61 @@ +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 + } +} \ No newline at end of file diff --git a/app/ticket/model/Attachment.php b/app/ticket/model/Attachment.php new file mode 100644 index 0000000..b29af53 --- /dev/null +++ b/app/ticket/model/Attachment.php @@ -0,0 +1,66 @@ +belongsTo(Ticket::class, 'ticket_id', 'id'); + } +} diff --git a/app/ticket/model/Ticket.php b/app/ticket/model/Ticket.php new file mode 100644 index 0000000..0327a87 --- /dev/null +++ b/app/ticket/model/Ticket.php @@ -0,0 +1,73 @@ + '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'); + } +} diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php new file mode 100644 index 0000000..650e163 --- /dev/null +++ b/app/ticket/service/TicketService.php @@ -0,0 +1,54 @@ +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; + } + } +} diff --git a/composer.json b/composer.json index 9e2dd39..20cf41f 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,9 @@ "vlucas/phpdotenv": "^5.6", "firebase/php-jwt": "^6.11", "league/oauth2-server": "^9.2", - "topthink/think-validate": "^3.0" + "topthink/think-validate": "^3.0", + "shopwwi/webman-filesystem": "1.1", + "shopwwi/filesystem-oss": "^1.0" }, "suggest": { "ext-event": "For better performance. " diff --git a/composer.lock b/composer.lock index e10e796..d34c290 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,59 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "eecf8b50860214e48bdcb8407fd40e14", + "content-hash": "7421030f864dacf31b06378e1045d034", "packages": [ + { + "name": "aliyuncs/oss-sdk-php", + "version": "v2.7.2", + "source": { + "type": "git", + "url": "https://github.com/aliyun/aliyun-oss-php-sdk.git", + "reference": "483dd0b8bff5d47f0e4ffc99f6077a295c5ccbb5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aliyun/aliyun-oss-php-sdk/zipball/483dd0b8bff5d47f0e4ffc99f6077a295c5ccbb5", + "reference": "483dd0b8bff5d47f0e4ffc99f6077a295c5ccbb5", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "php-coveralls/php-coveralls": "*", + "phpunit/phpunit": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "OSS\\": "src/OSS" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aliyuncs", + "homepage": "http://www.aliyun.com" + } + ], + "description": "Aliyun OSS SDK for PHP", + "homepage": "http://www.aliyun.com/product/oss/", + "support": { + "issues": "https://github.com/aliyun/aliyun-oss-php-sdk/issues", + "source": "https://github.com/aliyun/aliyun-oss-php-sdk/tree/v2.7.2" + }, + "time": "2024-10-28T10:41:12+00:00" + }, { "name": "brick/math", "version": "0.13.1", @@ -1997,6 +2048,212 @@ }, "time": "2024-09-04T16:06:53+00:00" }, + { + "name": "league/flysystem", + "version": "3.29.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "0adc0d9a51852e170e0028a60bd271726626d3f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/0adc0d9a51852e170e0028a60bd271726626d3f0", + "reference": "0adc0d9a51852e170e0028a60bd271726626d3f0", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "league/flysystem-local": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "conflict": { + "async-aws/core": "<1.19.0", + "async-aws/s3": "<1.14.0", + "aws/aws-sdk-php": "3.209.31 || 3.210.0", + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1", + "phpseclib/phpseclib": "3.0.15", + "symfony/http-client": "<5.2" + }, + "require-dev": { + "async-aws/s3": "^1.5 || ^2.0", + "async-aws/simple-s3": "^1.1 || ^2.0", + "aws/aws-sdk-php": "^3.295.10", + "composer/semver": "^3.0", + "ext-fileinfo": "*", + "ext-ftp": "*", + "ext-mongodb": "^1.3", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.5", + "google/cloud-storage": "^1.23", + "guzzlehttp/psr7": "^2.6", + "microsoft/azure-storage-blob": "^1.1", + "mongodb/mongodb": "^1.2", + "phpseclib/phpseclib": "^3.0.36", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.11|^10.0", + "sabre/dav": "^4.6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "File storage abstraction for PHP", + "keywords": [ + "WebDAV", + "aws", + "cloud", + "file", + "files", + "filesystem", + "filesystems", + "ftp", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/3.29.0" + }, + "time": "2024-09-29T11:59:11+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.29.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/e0e8d52ce4b2ed154148453d321e97c8e931bd27", + "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-fileinfo": "*", + "league/flysystem": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Local\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Local filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "file", + "files", + "filesystem", + "local" + ], + "support": { + "source": "https://github.com/thephpleague/flysystem-local/tree/3.29.0" + }, + "time": "2024-08-09T21:24:39+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.15.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301", + "reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.15.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2024-01-28T23:22:08+00:00" + }, { "name": "league/oauth2-server", "version": "9.2.0", @@ -3267,6 +3524,124 @@ }, "time": "2019-03-08T08:55:37+00:00" }, + { + "name": "shopwwi/filesystem-oss", + "version": "v1.0.3", + "source": { + "type": "git", + "url": "https://github.com/shopwwi/filesystem-oss.git", + "reference": "85cb385d1a5d11ca3c22bc485a7b18c588fe7645" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/shopwwi/filesystem-oss/zipball/85cb385d1a5d11ca3c22bc485a7b18c588fe7645", + "reference": "85cb385d1a5d11ca3c22bc485a7b18c588fe7645", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "aliyuncs/oss-sdk-php": "^2.4", + "league/flysystem": "^2.1|^3.0", + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Shopwwi\\FilesystemOss\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tycoon Song", + "email": "8988354@qq.com" + } + ], + "description": "AliYun OSS adapter for flysystem V2. aliyuncs/oss-sdk-php ~2.4", + "homepage": "https://github.com/phcent/filesystem-oss", + "keywords": [ + "Flysystem", + "aliyun-oss", + "flysystem-aliyun-oss" + ], + "support": { + "issues": "https://github.com/shopwwi/filesystem-oss/issues", + "source": "https://github.com/shopwwi/filesystem-oss/tree/v1.0.3" + }, + "time": "2022-10-01T03:00:18+00:00" + }, + { + "name": "shopwwi/webman-filesystem", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/shopwwi/webman-filesystem.git", + "reference": "26ac82515d3787943573c50d1a6f0ca339f0d3d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/shopwwi/webman-filesystem/zipball/26ac82515d3787943573c50d1a6f0ca339f0d3d4", + "reference": "26ac82515d3787943573c50d1a6f0ca339f0d3d4", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "league/flysystem": "^2.3|^3.0", + "php": ">=7.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Shopwwi\\WebmanFilesystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tycoon Song", + "email": "8988354@qq.com" + } + ], + "description": "Flysystem V2 adapter for the webman", + "keywords": [ + "cos", + "filesystem", + "oss", + "qiniu", + "webman" + ], + "support": { + "issues": "https://github.com/shopwwi/webman-filesystem/issues", + "source": "https://github.com/shopwwi/webman-filesystem/tree/v1.1.0" + }, + "time": "2024-01-21T08:03:36+00:00" + }, { "name": "symfony/cache", "version": "v7.3.0", diff --git a/config/plugin/shopwwi/filesystem/app.php b/config/plugin/shopwwi/filesystem/app.php new file mode 100644 index 0000000..f1c74b7 --- /dev/null +++ b/config/plugin/shopwwi/filesystem/app.php @@ -0,0 +1,116 @@ + true, + 'default' => 'local', + 'max_size' => 1024 * 1024 * 10, //单个文件大小10M + 'ext_yes' => [], //允许上传文件类型 为空则为允许所有 + 'ext_no' => [], // 不允许上传文件类型 为空则不限制 + 'storage' => [ + 'public' => [ + 'driver' => \Shopwwi\WebmanFilesystem\Adapter\LocalAdapterFactory::class, + 'root' => public_path(), + 'url' => '//127.0.0.1:8787' // 静态文件访问域名 + ], + 'local' => [ + 'driver' => \Shopwwi\WebmanFilesystem\Adapter\LocalAdapterFactory::class, + 'root' => runtime_path(), + 'url' => '//127.0.0.1:8787' // 静态文件访问域名 + ], + 'ftp' => [ + 'driver' => \Shopwwi\WebmanFilesystem\Adapter\FtpAdapterFactory::class, + 'host' => 'ftp.example.com', + 'username' => 'username', + 'password' => 'password', + 'url' => '' // 静态文件访问域名 + // 'port' => 21, + // 'root' => '/path/to/root', + // 'passive' => true, + // 'ssl' => true, + // 'timeout' => 30, + // 'ignorePassiveAddress' => false, + // 'timestampsOnUnixListingsEnabled' => true, + ], + 'memory' => [ + 'driver' => \Shopwwi\WebmanFilesystem\Adapter\MemoryAdapterFactory::class, + ], + 's3' => [ + 'driver' => \Shopwwi\WebmanFilesystem\Adapter\S3AdapterFactory::class, + 'credentials' => [ + 'key' => 'S3_KEY', + 'secret' => 'S3_SECRET', + ], + 'region' => 'S3_REGION', + 'version' => 'latest', + 'bucket_endpoint' => false, + 'use_path_style_endpoint' => false, + 'endpoint' => 'S3_ENDPOINT', + 'bucket_name' => 'S3_BUCKET', + 'url' => '' // 静态文件访问域名 + ], + 'minio' => [ + 'driver' => \Shopwwi\WebmanFilesystem\Adapter\S3AdapterFactory::class, + 'credentials' => [ + 'key' => 'S3_KEY', + 'secret' => 'S3_SECRET', + ], + 'region' => 'S3_REGION', + 'version' => 'latest', + 'bucket_endpoint' => false, + 'use_path_style_endpoint' => true, + 'endpoint' => 'S3_ENDPOINT', + 'bucket_name' => 'S3_BUCKET', + 'url' => '' // 静态文件访问域名 + ], + 'oss' => [ + 'driver' => \Shopwwi\WebmanFilesystem\Adapter\AliyunOssAdapterFactory::class, + 'accessId' => getenv('OSS_ACCESSID'), + 'accessSecret' => getenv('OSS_ACCESSSECRET'), + 'bucket' => getenv('OSS_BUCKET'), + 'endpoint' => getenv('OSS_ENDPOINT'), + 'url' => getenv('OSS_STATIC_URL'), // 静态文件访问域名 + // 'timeout' => 3600, + // 'connectTimeout' => 10, + // 'isCName' => false, + // 'token' => null, + // 'proxy' => null, + ], + 'qiniu' => [ + 'driver' => \Shopwwi\WebmanFilesystem\Adapter\QiniuAdapterFactory::class, + 'accessKey' => 'QINIU_ACCESS_KEY', + 'secretKey' => 'QINIU_SECRET_KEY', + 'bucket' => 'QINIU_BUCKET', + 'domain' => 'QINBIU_DOMAIN', + 'url' => '' // 静态文件访问域名 + ], + 'cos' => [ + 'driver' => \Shopwwi\WebmanFilesystem\Adapter\CosAdapterFactory::class, + 'region' => 'COS_REGION', + 'app_id' => 'COS_APPID', + 'secret_id' => 'COS_SECRET_ID', + 'secret_key' => 'COS_SECRET_KEY', + // 可选,如果 bucket 为私有访问请打开此项 + // 'signed_url' => false, + 'bucket' => 'COS_BUCKET', + 'read_from_cdn' => false, + 'url' => '' // 静态文件访问域名 + // 'timeout' => 60, + // 'connect_timeout' => 60, + // 'cdn' => '', + // 'scheme' => 'https', + ], + ], +]; \ No newline at end of file diff --git a/config/route.php b/config/route.php index 8870d47..fc12662 100644 --- a/config/route.php +++ b/config/route.php @@ -31,4 +31,13 @@ Route::group('/common', function () { Route::post('/login', [app\common\controller\AuthController::class, 'login']); Route::post('/register', [app\common\controller\AuthController::class, 'register']); }); -}); \ No newline at end of file +}); + + +Route::group('/ticket', function () { + Route::post('/ticket/add', [app\ticket\controller\TicketController::class, 'add']); + Route::post('/ticket/edit', [app\ticket\controller\TicketController::class, 'edit']); + Route::get('/ticket/list', [app\ticket\controller\TicketController::class, 'index']); + Route::post('/upload', [app\common\controller\UploadController::class, 'uploadFile']); +}); + From 9d7957d506caed71c0965b781bb515605552251c Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 3 Jul 2025 10:41:55 +0800 Subject: [PATCH 02/20] =?UTF-8?q?=E8=B7=A8=E5=9F=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/middleware/AccessControl.php | 26 ++++++++++++++++++++++++++ config/middleware.php | 6 +++++- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 app/middleware/AccessControl.php diff --git a/app/middleware/AccessControl.php b/app/middleware/AccessControl.php new file mode 100644 index 0000000..2a93d79 --- /dev/null +++ b/app/middleware/AccessControl.php @@ -0,0 +1,26 @@ +method() == 'OPTIONS' ? response('') : $handler($request); + + // 给响应添加跨域相关的http头 + $response->withHeaders([ + 'Access-Control-Allow-Credentials' => 'true', + 'Access-Control-Allow-Origin' => $request->header('origin', '*'), + 'Access-Control-Allow-Methods' => $request->header('access-control-request-method', '*'), + 'Access-Control-Allow-Headers' => $request->header('access-control-request-headers', '*'), + ]); + + return $response; + } +} \ No newline at end of file diff --git a/config/middleware.php b/config/middleware.php index 8e964ed..01e8367 100644 --- a/config/middleware.php +++ b/config/middleware.php @@ -12,4 +12,8 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ -return []; \ No newline at end of file +return [ + '' => [ + app\middleware\AccessControl::class + ], +]; \ No newline at end of file From 6ef45714454bb7a1dff3c2773459a3f7d0528cbb Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 3 Jul 2025 11:19:51 +0800 Subject: [PATCH 03/20] 1 --- app/ticket/controller/TicketController.php | 2 ++ config/route.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/ticket/controller/TicketController.php b/app/ticket/controller/TicketController.php index ff3defa..ad9f192 100644 --- a/app/ticket/controller/TicketController.php +++ b/app/ticket/controller/TicketController.php @@ -3,6 +3,7 @@ namespace app\ticket\controller; use app\ticket\service\TicketService; +use support\Log; use support\Request; class TicketController extends BaseController @@ -11,6 +12,7 @@ class TicketController extends BaseController public function index(Request $request) { try { + log::info('param',$request->all()); $result = (new TicketService())->list($request->all()); return $this->success($this->page($result)); } catch (\Throwable $e) { diff --git a/config/route.php b/config/route.php index fc12662..8d1c4a1 100644 --- a/config/route.php +++ b/config/route.php @@ -37,7 +37,7 @@ Route::group('/common', function () { Route::group('/ticket', function () { Route::post('/ticket/add', [app\ticket\controller\TicketController::class, 'add']); Route::post('/ticket/edit', [app\ticket\controller\TicketController::class, 'edit']); - Route::get('/ticket/list', [app\ticket\controller\TicketController::class, 'index']); + Route::any('/ticket/list', [app\ticket\controller\TicketController::class, 'index']); Route::post('/upload', [app\common\controller\UploadController::class, 'uploadFile']); }); From 78447737ea8a857fc3b943820662d6fcf508ede3 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 3 Jul 2025 11:23:39 +0800 Subject: [PATCH 04/20] =?UTF-8?q?=E8=AF=B7=E6=B1=82=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/controller/TicketController.php | 2 -- config/route.php | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/ticket/controller/TicketController.php b/app/ticket/controller/TicketController.php index ad9f192..ff3defa 100644 --- a/app/ticket/controller/TicketController.php +++ b/app/ticket/controller/TicketController.php @@ -3,7 +3,6 @@ namespace app\ticket\controller; use app\ticket\service\TicketService; -use support\Log; use support\Request; class TicketController extends BaseController @@ -12,7 +11,6 @@ class TicketController extends BaseController public function index(Request $request) { try { - log::info('param',$request->all()); $result = (new TicketService())->list($request->all()); return $this->success($this->page($result)); } catch (\Throwable $e) { diff --git a/config/route.php b/config/route.php index 8d1c4a1..a1b8c64 100644 --- a/config/route.php +++ b/config/route.php @@ -35,9 +35,9 @@ Route::group('/common', function () { Route::group('/ticket', function () { - Route::post('/ticket/add', [app\ticket\controller\TicketController::class, 'add']); - Route::post('/ticket/edit', [app\ticket\controller\TicketController::class, 'edit']); + Route::any('/ticket/add', [app\ticket\controller\TicketController::class, 'add']); + Route::any('/ticket/edit', [app\ticket\controller\TicketController::class, 'edit']); Route::any('/ticket/list', [app\ticket\controller\TicketController::class, 'index']); - Route::post('/upload', [app\common\controller\UploadController::class, 'uploadFile']); + Route::any('/upload', [app\common\controller\UploadController::class, 'uploadFile']); }); From 8d36ffe13baebd0d85daba7a30ede7815f5eda1c Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 3 Jul 2025 15:28:19 +0800 Subject: [PATCH 05/20] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E6=B2=9F=E9=80=9A?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ConversationController.php | 46 +++++++++++++++++ app/ticket/controller/TicketController.php | 25 +++++++++- app/ticket/logic/ConversationLogic.php | 46 +++++++++++++++++ app/ticket/logic/TicketLogic.php | 6 +++ app/ticket/model/Conversation.php | 33 ++++++++++++ app/ticket/service/ConversationService.php | 50 +++++++++++++++++++ app/ticket/service/TicketService.php | 48 ++++++++++++++++++ config/constants/Constants.php | 37 ++++++++++++++ config/route.php | 10 ++++ 9 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 app/ticket/controller/ConversationController.php create mode 100644 app/ticket/logic/ConversationLogic.php create mode 100644 app/ticket/model/Conversation.php create mode 100644 app/ticket/service/ConversationService.php create mode 100644 config/constants/Constants.php diff --git a/app/ticket/controller/ConversationController.php b/app/ticket/controller/ConversationController.php new file mode 100644 index 0000000..0e1b7ec --- /dev/null +++ b/app/ticket/controller/ConversationController.php @@ -0,0 +1,46 @@ +input('ticket_id'); + if(empty($ticket_id)){ + return $this->error('ticket_id不能为空'); + } + $result = (new ConversationService())->list($request->all()); + return $this->success($this->page($result)); + } catch (\Throwable $e) { + return $this->error($e->getMessage().$e->getLine().$e->getFile()); + } + } + public function add(Request $request) + { + try { + $request->setPost('user_id', 1); + return (new ConversationService())->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 ConversationService())->edit($request->all()); + return $result + ? $this->success($result) + : $this->error(); + } catch (\Throwable $th) { + return $this->error($th->getMessage().' '.$th->getLine().' '.$th->getFile()); + } + } +} \ No newline at end of file diff --git a/app/ticket/controller/TicketController.php b/app/ticket/controller/TicketController.php index ff3defa..cc33459 100644 --- a/app/ticket/controller/TicketController.php +++ b/app/ticket/controller/TicketController.php @@ -39,7 +39,30 @@ class TicketController extends BaseController ? $this->success($result) : $this->error(); } catch (\Throwable $th) { - return $this->error($th->getMessage().' '.$th->getLine().' '.$th->getFile()); + return $this->error($th->getMessage()); + } + } + public function status(Request $request) + { + try { + $request->setPost('user_id', 1); + $result = (new TicketService())->status($request->all()); + return $result + ? $this->success($result) + : $this->error(); + } catch (\Throwable $th) { + return $this->error($th->getMessage()); + } + } + public function getStatus(Request $request) + { + try { + $result = (new TicketService())->getStatus($request->all()); + return $result + ? $this->success($result) + : $this->error(); + } catch (\Throwable $th) { + return $this->error($th->getMessage()); } } diff --git a/app/ticket/logic/ConversationLogic.php b/app/ticket/logic/ConversationLogic.php new file mode 100644 index 0000000..6ce3cbf --- /dev/null +++ b/app/ticket/logic/ConversationLogic.php @@ -0,0 +1,46 @@ +paginate($size, ['*'], 'page', $current); + } + public function add(array $data) + { + try { + return Conversation::create($data); + } catch (\Throwable $e) { + Log::error('会话创建失败', [ + 'data' => $data, + 'error' => $e->getMessage() + ]); + throw new BusinessException('会话创建失败,请稍后重试', 500); + } + } + public function edit(array $data) + { + try { + $conversation = Conversation::updateOrCreate(['id' => $data['id']], $data); + return $conversation; + } catch (\Throwable $e) { + Log::error('会话编辑失败', [ + 'data' => $data, + 'error' => $e->getMessage() + ]); + throw new BusinessException($e->getMessage().'会话编辑失败,请稍后重试', 500); + } + } +} \ No newline at end of file diff --git a/app/ticket/logic/TicketLogic.php b/app/ticket/logic/TicketLogic.php index 0037879..16fb5ce 100644 --- a/app/ticket/logic/TicketLogic.php +++ b/app/ticket/logic/TicketLogic.php @@ -50,6 +50,12 @@ class TicketLogic } } + public function find(int $id) + { + $ticket = Ticket::find($id); + return $ticket; + } + public static function generateSimpleTicketNo(): string { $date = date('Ymd'); // 日期 diff --git a/app/ticket/model/Conversation.php b/app/ticket/model/Conversation.php new file mode 100644 index 0000000..8839455 --- /dev/null +++ b/app/ticket/model/Conversation.php @@ -0,0 +1,33 @@ + 'datetime:Y-m-d H:i:s', + 'created_at' => 'datetime:Y-m-d H:i:s', + ]; + protected $fillable = [ + 'ticket_id', + 'user_id', + 'content', + ]; +} \ No newline at end of file diff --git a/app/ticket/service/ConversationService.php b/app/ticket/service/ConversationService.php new file mode 100644 index 0000000..cc3ef84 --- /dev/null +++ b/app/ticket/service/ConversationService.php @@ -0,0 +1,50 @@ +list($params); + + $status_fanyi = array_map(fn($v) => "{{{$v}}}", array_flip(Constants::TICKET_STATUS)); + foreach ($result as $key => $value) { + $result[$key]['content'] = str_replace($status_fanyi,$ticket_status,$value['content']); + } + return $result; + } + + public function add(array $data) + { + try { + return (new ConversationLogic())->add($data); + } catch (\Throwable $e) { + Db::rollback(); + throw $e; + } + } + + public function edit(array $data) + { + try { + Db::beginTransaction(); + $result = (new ConversationLogic())->edit($data); + Db::commit(); + return $result; + } catch (\Throwable $e) { + Db::rollback(); + throw $e; + } + } +} \ No newline at end of file diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index 650e163..f01d9c2 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -3,14 +3,17 @@ namespace app\ticket\service; use app\ticket\logic\AttachmentLogic; +use app\ticket\logic\ConversationLogic; use app\ticket\logic\TicketLogic; use app\ticket\model\Ticket; +use config\constants\Constants; use support\Db; use support\exception\BusinessException; use support\Log; class TicketService { + public function list($params) { $res = (new TicketLogic())->list($params); @@ -51,4 +54,49 @@ class TicketService throw $e; } } + + public function status(array $data) + { + try { + Db::beginTransaction(); + $msg = $data['msg']??[]; + $ticket = (new TicketLogic())->find($data['id']); + if(empty($ticket)){ + throw new BusinessException('工单不存在'); + } + if($data['status'] == $ticket->status){ + throw new BusinessException('状态未修改'); + } + +// if(!in_array($ticket->status, [Constants::TICKET_STATUS['PENDING'], Constants::TICKET_STATUS['CONFIRM']]) +// && empty($msg)){ +// throw new BusinessException('提交失败'); +// } + + $ticket->status = $data['status']; + $result = $ticket->save(); + + if(!empty($msg)){ + $conversation = [ + 'ticket_id' => $ticket->id, + 'user_id' => $data['user_id'], + 'content' => '状态更新为{{'.array_search($data['status'],Constants::TICKET_STATUS).'}}:'.$msg + ]; + $res = (new ConversationLogic())->add($conversation); + } + + Db::commit(); + return $result; + } catch (\Throwable $e) { + Db::rollback(); + throw $e; + } + } + + public function getStatus(array $data) + { + $locale = locale(); + $ticket_status = $locale == 'zh'? Constants::TICKET_STATUS_ZH:Constants::TICKET_STATUS_EN; + return $ticket_status; + } } diff --git a/config/constants/Constants.php b/config/constants/Constants.php new file mode 100644 index 0000000..e4c9284 --- /dev/null +++ b/config/constants/Constants.php @@ -0,0 +1,37 @@ + 1, // 待受理 + 'PROCESS' => 2, //处理中 + 'CONFIRM' => 3, // 待确认 + 'FINISH' => 4, // 已完成 + 'REJECTED' => 5, // 已驳回 + ]; + + public const TICKET_STATUS_ZH = [ + self::TICKET_STATUS['PENDING'] => '待受理', + self::TICKET_STATUS['PROCESS'] => '处理中', + self::TICKET_STATUS['CONFIRM'] => '待确认', + self::TICKET_STATUS['FINISH'] => '已完成', + self::TICKET_STATUS['REJECTED'] => '已驳回', + ]; + public const TICKET_STATUS_EN = [ + self::TICKET_STATUS['PENDING'] => 'Pending acceptance', + self::TICKET_STATUS['PROCESS'] => 'Processing', + self::TICKET_STATUS['CONFIRM'] => 'To be confirmed', + self::TICKET_STATUS['FINISH'] => 'Completed', + self::TICKET_STATUS['REJECTED'] => 'Rejected', + ]; + public const TICKET_STATUS_RU = [ + self::TICKET_STATUS['PENDING'] => 'Подлежит рассмотрению', + self::TICKET_STATUS['PROCESS'] => 'В процессе обработки', + self::TICKET_STATUS['CONFIRM'] => 'Подлежит подтверждению', + self::TICKET_STATUS['FINISH'] => 'Завершено', + self::TICKET_STATUS['REJECTED'] => 'Отклонено', + ]; + +} \ No newline at end of file diff --git a/config/route.php b/config/route.php index a1b8c64..6a53a53 100644 --- a/config/route.php +++ b/config/route.php @@ -35,9 +35,19 @@ Route::group('/common', function () { Route::group('/ticket', function () { + //工单 Route::any('/ticket/add', [app\ticket\controller\TicketController::class, 'add']); Route::any('/ticket/edit', [app\ticket\controller\TicketController::class, 'edit']); Route::any('/ticket/list', [app\ticket\controller\TicketController::class, 'index']); + Route::any('/ticket/status', [app\ticket\controller\TicketController::class, 'status']); + Route::any('/ticket/getStatus', [app\ticket\controller\TicketController::class, 'getStatus']); + Route::any('/upload', [app\common\controller\UploadController::class, 'uploadFile']); + + //工单沟通记录 + Route::any('/conversation/add', [app\ticket\controller\ConversationController::class, 'add']); + Route::any('/conversation/edit', [app\ticket\controller\ConversationController::class, 'edit']); + Route::any('/conversation/list', [app\ticket\controller\ConversationController::class, 'index']); + }); From fec7988a2656e752da5d75e324ec0ce56627b085 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 3 Jul 2025 15:42:06 +0800 Subject: [PATCH 06/20] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=97=B6=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E5=8E=9F=E5=A7=8B=E6=96=87=E4=BB=B6=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/controller/UploadController.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/common/controller/UploadController.php b/app/common/controller/UploadController.php index c01f084..9d39a05 100644 --- a/app/common/controller/UploadController.php +++ b/app/common/controller/UploadController.php @@ -44,6 +44,7 @@ class UploadController if (!$file || !$file->isValid()) { return $this->error('上传失败'); } + $originalName = $file->getUploadName(); $result = Storage::adapter('oss') ->path('vehicle_album/'.date('Ymd')) @@ -53,6 +54,7 @@ class UploadController $ossservice = new OssService(); $data = [ + 'original_name' => $originalName, 'file_name' => $result->file_name, 'file_url' => $ossservice->generatePrivateUrl($result->file_name) ]; From 6bb4e87280361be0820e732dfaae430482c8a740 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 3 Jul 2025 15:46:08 +0800 Subject: [PATCH 07/20] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=9B=BE=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/route.php | 1 + 1 file changed, 1 insertion(+) diff --git a/config/route.php b/config/route.php index 6a53a53..c7b7413 100644 --- a/config/route.php +++ b/config/route.php @@ -43,6 +43,7 @@ Route::group('/ticket', function () { Route::any('/ticket/getStatus', [app\ticket\controller\TicketController::class, 'getStatus']); Route::any('/upload', [app\common\controller\UploadController::class, 'uploadFile']); + Route::any('/upload/image', [app\common\controller\UploadController::class, 'uploadImage']); //工单沟通记录 Route::any('/conversation/add', [app\ticket\controller\ConversationController::class, 'add']); From b9d909527825fec1b96d9b5c56af7251484c5056 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 3 Jul 2025 15:53:34 +0800 Subject: [PATCH 08/20] =?UTF-8?q?=E7=8A=B6=E6=80=81=E4=B8=8B=E6=8B=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/service/TicketService.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index f01d9c2..4ca7c73 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -97,6 +97,11 @@ class TicketService { $locale = locale(); $ticket_status = $locale == 'zh'? Constants::TICKET_STATUS_ZH:Constants::TICKET_STATUS_EN; - return $ticket_status; + + $status = []; + foreach ($ticket_status as $key => $value) { + $status[] = ['value' => $key, 'text' => $value]; + } + return $status; } } From 92abd946b047b7d95343a0809345759ea7f41ceb Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 3 Jul 2025 16:36:00 +0800 Subject: [PATCH 09/20] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E7=BB=93=E6=9E=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/controller/UploadController.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/common/controller/UploadController.php b/app/common/controller/UploadController.php index 9d39a05..f47cd90 100644 --- a/app/common/controller/UploadController.php +++ b/app/common/controller/UploadController.php @@ -85,13 +85,16 @@ class UploadController $ossservice = new OssService(); $data = [ - 'image_name' => $result->file_name, - 'image_url' => $ossservice->generatePrivateUrl($result->file_name) + 'url' => $result->file_name, + 'alt' => '', + 'href' => $ossservice->generatePrivateUrl($result->file_name) ]; - return $this->success($data); - }catch (\Throwable $e){ - return $this->error($e->getMessage()); + return json(['errno' => 0, 'data' => $data]); +// return $this->success($data); + } catch (\Throwable $e) { + return json(['errno' => 1, 'message' => $e->getMessage()]); +// return $this->error($e->getMessage()); } } From 2be25889ea2ea2af9be3437dfc8f614b2b156845 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 3 Jul 2025 16:37:56 +0800 Subject: [PATCH 10/20] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=9B=BE=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/controller/UploadController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/common/controller/UploadController.php b/app/common/controller/UploadController.php index f47cd90..9d8959d 100644 --- a/app/common/controller/UploadController.php +++ b/app/common/controller/UploadController.php @@ -85,9 +85,9 @@ class UploadController $ossservice = new OssService(); $data = [ - 'url' => $result->file_name, + 'href' => $result->file_name, 'alt' => '', - 'href' => $ossservice->generatePrivateUrl($result->file_name) + 'url' => $ossservice->generatePrivateUrl($result->file_name) ]; return json(['errno' => 0, 'data' => $data]); From 3be2ae983c2af8246b8f2a9bcfdb698f03e0fc07 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 4 Jul 2025 13:45:50 +0800 Subject: [PATCH 11/20] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E5=88=86=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/functions.php | 22 +++ app/queue/translation/config/trans.php | 14 ++ app/queue/translation/jobs/TranslationJob.php | 64 +++++++++ app/queue/translation/queue/Translation.php | 50 +++++++ .../service/TranslationService.php | 41 ++++++ .../translation/service/TranslatorClient.php | 38 +++++ app/queue/utils/Translat.php | 21 +++ app/queue/utils/XunfeiFanyi.php | 134 ++++++++++++++++++ app/ticket/controller/CategorieController.php | 52 +++++++ app/ticket/logic/CategorieLogic.php | 52 +++++++ app/ticket/logic/TicketLogic.php | 8 +- app/ticket/model/TicketCategorie.php | 47 ++++++ .../model/TicketCategorieTranslation.php | 35 +++++ app/ticket/service/CategorieService.php | 85 +++++++++++ app/ticket/service/ConversationService.php | 5 +- app/ticket/service/TicketService.php | 2 +- composer.json | 4 +- composer.lock | 131 ++++++++++++++++- config/plugin/webman/redis-queue/app.php | 4 + config/plugin/webman/redis-queue/command.php | 7 + config/plugin/webman/redis-queue/log.php | 32 +++++ config/plugin/webman/redis-queue/process.php | 12 ++ config/plugin/webman/redis-queue/redis.php | 22 +++ config/route.php | 6 + resource/translations/ar/messages.php | 5 + resource/translations/en/messages.php | 5 + resource/translations/ru/messages.php | 5 + resource/translations/zh/messages.php | 5 + 28 files changed, 900 insertions(+), 8 deletions(-) create mode 100644 app/queue/translation/config/trans.php create mode 100644 app/queue/translation/jobs/TranslationJob.php create mode 100644 app/queue/translation/queue/Translation.php create mode 100644 app/queue/translation/service/TranslationService.php create mode 100644 app/queue/translation/service/TranslatorClient.php create mode 100644 app/queue/utils/Translat.php create mode 100644 app/queue/utils/XunfeiFanyi.php create mode 100644 app/ticket/controller/CategorieController.php create mode 100644 app/ticket/logic/CategorieLogic.php create mode 100644 app/ticket/model/TicketCategorie.php create mode 100644 app/ticket/model/TicketCategorieTranslation.php create mode 100644 app/ticket/service/CategorieService.php create mode 100644 config/plugin/webman/redis-queue/app.php create mode 100644 config/plugin/webman/redis-queue/command.php create mode 100644 config/plugin/webman/redis-queue/log.php create mode 100644 config/plugin/webman/redis-queue/process.php create mode 100644 config/plugin/webman/redis-queue/redis.php create mode 100644 resource/translations/ar/messages.php create mode 100644 resource/translations/en/messages.php create mode 100644 resource/translations/ru/messages.php create mode 100644 resource/translations/zh/messages.php diff --git a/app/functions.php b/app/functions.php index 5c9c58d..c0c16fa 100644 --- a/app/functions.php +++ b/app/functions.php @@ -2,3 +2,25 @@ /** * Here is your custom functions. */ + +use support\exception\BusinessException; + +/** + * 获取配置 + */ +function getConfig($filePath = null) +{ + // 构建文件路径 + $config_file = app_path($filePath); + // 检查文件是否存在 + if (!file_exists($config_file)) { + return []; + } + // 包含文件并获取返回的数组 + $config = include $config_file; + // 验证是否为数组 + if (!is_array($config)) { + return []; + } + return $config; +} \ No newline at end of file diff --git a/app/queue/translation/config/trans.php b/app/queue/translation/config/trans.php new file mode 100644 index 0000000..73b55b1 --- /dev/null +++ b/app/queue/translation/config/trans.php @@ -0,0 +1,14 @@ + [ + 'ticket_categorie' => [ + 'translation_model' => \app\ticket\model\TicketCategorieTranslation::class, + 'foreign_key' => 'categorie_id', + ], + ], + + // 默认支持的目标语种列表 + 'locales' => ['zh','en','ru','ar'], +]; diff --git a/app/queue/translation/jobs/TranslationJob.php b/app/queue/translation/jobs/TranslationJob.php new file mode 100644 index 0000000..eb5e704 --- /dev/null +++ b/app/queue/translation/jobs/TranslationJob.php @@ -0,0 +1,64 @@ +config = getConfig('/queue/translation/config/trans.php'); + $this->payload = $payload; + } + + public function handle(): void + { + $cfgAll = $this->config['entities']; + $pt = $this->payload; + $type = $pt['entityType']; + $id = $pt['entityId']; + $locale = $pt['locale']; + $sourceLocale = $pt['sourceLocale']; + $sourceFields = $pt['sourceFields']; + $clientFields = $pt['clientFields']; + + if (! isset($cfgAll[$type])) { + Log::warning("TranslationJob: 未配置实体 {$type}"); + return; + } + + $cfg = $cfgAll[$type]; + $modelClass = $cfg['translation_model']; + $foreignKey = $cfg['foreign_key']; + + // 决定采用前端提供、源语种还是第三方翻译 + if (! empty($clientFields)) { + $fields = $clientFields; + } elseif ($locale === $sourceLocale) { + $fields = $sourceFields; + } else { + $translator = new TranslatorClient(); + $fields = []; + foreach ($sourceFields as $key => $text) { + $fields[$key] = $translator->translate($text, $sourceLocale, $locale); + } + } + + // 写库 + try { + $modelClass::updateOrCreate( + [ + $foreignKey => $id, + 'locale' => $locale, + ], + array_merge($fields, ['locale' => $locale]) + ); + } catch (\Throwable $e) { + Log::error("TranslationJob 保存失败: {$type}#{$id} locale={$locale}: ".$e->getMessage()); + } + } +} diff --git a/app/queue/translation/queue/Translation.php b/app/queue/translation/queue/Translation.php new file mode 100644 index 0000000..0b5841a --- /dev/null +++ b/app/queue/translation/queue/Translation.php @@ -0,0 +1,50 @@ + 'tom@gmail.com', 'content' => 'hello'] + + $job = new TranslationJob($data); + $job->handle(); + } catch (\Throwable $e) { + Log::error("TranslationService 异步任务异常: ".$e->getMessage()); + } + } + // 消费失败回调 + /* + $package = [ + 'id' => 1357277951, // 消息ID + 'time' => 1709170510, // 消息时间 + 'delay' => 0, // 延迟时间 + 'attempts' => 2, // 消费次数 + 'queue' => 'send-mail', // 队列名 + 'data' => ['to' => 'tom@gmail.com', 'content' => 'hello'], // 消息内容 + 'max_attempts' => 5, // 最大重试次数 + 'error' => '错误信息' // 错误信息 + ] + */ + public function onConsumeFailure(\Throwable $e, $package) + { + echo "consume failure\n"; + echo $e->getMessage() . "\n"; + // 无需反序列化 + var_export($package); + } +} \ No newline at end of file diff --git a/app/queue/translation/service/TranslationService.php b/app/queue/translation/service/TranslationService.php new file mode 100644 index 0000000..3578d89 --- /dev/null +++ b/app/queue/translation/service/TranslationService.php @@ -0,0 +1,41 @@ +config = getConfig('/queue/translation/config/trans.php'); + } + + /** + * 异步排队所有语种的翻译任务 + * + * @param string $entityType 实体名,如 'vehicle' + * @param int $entityId 主表 ID + * @param string $sourceLocale 源语种,如 'zh' + * @param array $sourceFields 源语种字段 ['name'=>…,'condition_desc'=>…] + * @param array $clientFields 前端已传翻译 ['en'=>[...], …] + */ + public function queueTranslations(string $entityType, int $entityId, string $sourceLocale, array $sourceFields, array $clientFields = []): void + { + foreach ($this->config['locales'] as $locale) { + $payload = [ + 'entityType' => $entityType, + 'entityId' => $entityId, + 'locale' => $locale, + 'sourceLocale' => $sourceLocale, + 'sourceFields' => $sourceFields, + 'clientFields' => $clientFields[$locale] ?? [], + ]; + Redis::send('transTask', $payload); + } + } +} \ No newline at end of file diff --git a/app/queue/translation/service/TranslatorClient.php b/app/queue/translation/service/TranslatorClient.php new file mode 100644 index 0000000..3abc1df --- /dev/null +++ b/app/queue/translation/service/TranslatorClient.php @@ -0,0 +1,38 @@ +endpoint = env('TRANSLATION_API_URL'); + // $this->apiKey = env('TRANSLATION_API_KEY'); + // } + + /** + * 翻译文本 + * @throws \RuntimeException + */ + public function translate(string $text, string $from = 'cn', string $to = 'ru'): string + { + try { + $xunfei = new XunfeiFanyi(); + $rst_dst = $xunfei->fanyi($text, $from, $to); + if ($rst_dst) { + return $rst_dst["trans_result"]["dst"]; + } else { + return ''; + } + } catch (\Throwable $e) { + Log::error("TranslatorClient 错误: ".$e->getMessage()); + throw new \RuntimeException('翻译服务调用失败'); + } + } +} diff --git a/app/queue/utils/Translat.php b/app/queue/utils/Translat.php new file mode 100644 index 0000000..3000756 --- /dev/null +++ b/app/queue/utils/Translat.php @@ -0,0 +1,21 @@ + $header,'body' => $response); + return $data; + } + + + public function xfyun($text = "中华人民共和国于1949年成立", $from = "cn", $to = "en") + { + //在控制台-我的应用-机器翻译获取 + $app_id = "3d46198c"; + //在控制台-我的应用-机器翻译获取 + $api_sec = "ZWY2MmUyNjJjYmFkOTFlYTVmYWVhMGYy"; + //在控制台-我的应用-机器翻译获取 + $api_key = "b6d805f240176ecaea85130cb5f2bca1"; + // 机器翻译接口地址 + $url = "https://ntrans.xfyun.cn/v2/ots"; + //body组装 + // $text = "中华人民共和国于1949年成立";//待翻译文本 + $body = json_encode($this->getBody($app_id, $from, $to, $text)); + + // 组装http请求头 + $date =gmdate('D, d M Y H:i:s') . ' GMT'; + + $digestBase64 = "SHA-256=".base64_encode(hash("sha256", $body, true)); + $builder = sprintf("host: %s +date: %s +POST /v2/ots HTTP/1.1 +digest: %s", "ntrans.xfyun.cn", $date, $digestBase64); + // echo($builder); + $sha = base64_encode(hash_hmac("sha256", $builder, $api_sec, true)); + + $authorization = sprintf("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", $api_key,"hmac-sha256", + "host date request-line digest", $sha); + + $header = [ + "Authorization: ".$authorization, + 'Content-Type: application/json', + 'Accept: application/json,version=1.0', + 'Host: ntrans.xfyun.cn', + 'Date: ' .$date, + 'Digest: '.$digestBase64 + ]; + $response = $this->tocurl($url, $header, $body); + + // var_dump($response['body']); + return $response; + } + + + public function getBody($app_id, $from, $to, $text) + { + $common_param = [ + 'app_id' => $app_id + ]; + + $business = [ + 'from' => $from, + 'to' => $to, + ]; + + $data = [ + "text" => base64_encode($text) + ]; + + return $body = [ + 'common' => $common_param, + 'business' => $business, + 'data' => $data + ]; + } + + // 翻译 + public function fanyi($text = "", $from = "", $to = "") + { + try { + $res = $this->xfyun($text, $from, $to); + $data = json_decode($res["body"], true); + if ($data["code"] === 0) { + return $data["data"]["result"]; + } else { + $this->error = $data["message"]; + return false; + } + } catch (\Throwable $th) { + $this->error = $th->getMessage(); + return false; + } + } + + // 异常 + public function error() + { + return $this->error; + } + +} \ No newline at end of file diff --git a/app/ticket/controller/CategorieController.php b/app/ticket/controller/CategorieController.php new file mode 100644 index 0000000..d9fe422 --- /dev/null +++ b/app/ticket/controller/CategorieController.php @@ -0,0 +1,52 @@ +list($request->all()); + return $this->success($this->page($result)); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + public function getAll(Request $request) + { + try { + $result = (new CategorieService())->getAll($request->all()); + return $this->success($result); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + public function add(Request $request) + { + try { + return (new CategorieService())->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 { + $result = (new CategorieService())->edit($request->all()); + return $result + ? $this->success($result) + : $this->error(); + } catch (\Throwable $th) { + return $this->error($th->getMessage().' '.$th->getLine().' '.$th->getFile()); + } + } +} \ No newline at end of file diff --git a/app/ticket/logic/CategorieLogic.php b/app/ticket/logic/CategorieLogic.php new file mode 100644 index 0000000..ab100b4 --- /dev/null +++ b/app/ticket/logic/CategorieLogic.php @@ -0,0 +1,52 @@ +where($where)->paginate($size, ['*'], 'page', $current); + } + + public function getAll($params) + { + $where = []; + $where[] = ['status', '=', 1]; + return TicketCategorie::with('translation')->where($where)->get(); + } + + public function add(array $data) + { + try { + return TicketCategorie::create($data); + } catch (\Throwable $e) { + Log::error('分类创建失败', [ + 'data' => $data, + 'error' => $e->getMessage() + ]); + throw new BusinessException($e->getMessage().'分类创建失败,请稍后重试', 500); + } + } + + public function edit(array $data) + { + try { + $categorie = TicketCategorie::updateOrCreate(['id' => $data['id']], $data); + return $categorie; + } catch (\Throwable $e) { + Log::error('分类编辑失败', [ + 'data' => $data, + 'error' => $e->getMessage() + ]); + throw new BusinessException($e->getMessage().'分类编辑失败,请稍后重试', 500); + } + } +} \ No newline at end of file diff --git a/app/ticket/logic/TicketLogic.php b/app/ticket/logic/TicketLogic.php index 16fb5ce..21e8539 100644 --- a/app/ticket/logic/TicketLogic.php +++ b/app/ticket/logic/TicketLogic.php @@ -17,9 +17,15 @@ class TicketLogic public function list($params) { $where = []; + if(!empty($params['categorie_id'])){ + $where[] = ['categorie_id', '=', $params['categorie_id']]; + } + if(!empty($params['status'])){ + $where[] = ['status', '=', $params['status']]; + } $size = $params['size']; $current = $params['current']; - return Ticket::with('attachments')->where($where)->paginate($size, ['*'], 'page', $current); + return Ticket::with('attachments')->where($where)->orderBy('id','desc')->paginate($size, ['*'], 'page', $current); } public function add(array $data) { diff --git a/app/ticket/model/TicketCategorie.php b/app/ticket/model/TicketCategorie.php new file mode 100644 index 0000000..79f4f75 --- /dev/null +++ b/app/ticket/model/TicketCategorie.php @@ -0,0 +1,47 @@ + 'datetime:Y-m-d H:i:s', + 'created_at' => 'datetime:Y-m-d H:i:s', + ]; + protected $fillable = [ + 'name', + 'description', + ]; + + /** + * 单条翻译 + */ + public function translation() + { + return $this->hasOne(TicketCategorieTranslation::class, 'categorie_id')->where('locale', locale()); + } + + /** + * 多条翻译 + */ + public function translations() + { + return $this->hasMany(TicketCategorieTranslation::class, 'categorie_id'); + } +} \ No newline at end of file diff --git a/app/ticket/model/TicketCategorieTranslation.php b/app/ticket/model/TicketCategorieTranslation.php new file mode 100644 index 0000000..66a8f95 --- /dev/null +++ b/app/ticket/model/TicketCategorieTranslation.php @@ -0,0 +1,35 @@ + 'datetime:Y-m-d H:i:s', + 'created_at' => 'datetime:Y-m-d H:i:s', + ]; + protected $fillable = [ + 'categorie_id', + 'locale', + 'name', + 'description', + ]; +} \ No newline at end of file diff --git a/app/ticket/service/CategorieService.php b/app/ticket/service/CategorieService.php new file mode 100644 index 0000000..5a0e9ee --- /dev/null +++ b/app/ticket/service/CategorieService.php @@ -0,0 +1,85 @@ +list($params); + + foreach ($result as $key => &$value) { + $value['name'] = isset($item['translation']) ? $item['translation']['name'] : ''; + unset($value['translation']); + } + unset($value); + + return $result; + } + + public function getAll($params) + { + $result = (new CategorieLogic())->getAll($params); + foreach ($result as $key => &$value) { + $value['name'] =isset($item['translation']) ? $item['translation']['name'] : ''; + unset($value['translation']); + } + unset($value); + + return $result; + } + + public $translatFields = ['name']; + + public function add(array $data) + { + try { + Db::beginTransaction(); + $sourceLocale = locale(); + $traitsourceFields = Translat::extractSourceFields($data, $this->translatFields); + + $result = (new CategorieLogic())->add($data); + + (new TranslationService())->queueTranslations( + 'ticket_categorie', + $result->id, + $sourceLocale, + $traitsourceFields + ); + + Db::commit(); + return $result; + } catch (\Throwable $e) { + Db::rollback(); + throw $e; + } + } + public function edit(array $data) + { + try { + Db::beginTransaction(); + $sourceLocale = locale(); + $traitsourceFields = Translat::extractSourceFields($data, $this->translatFields); + + $result = (new CategorieLogic())->edit($data); + + (new TranslationService())->queueTranslations( + 'ticket_categorie', + $data['id'], + $sourceLocale, + $traitsourceFields + ); + Db::commit(); + return $result; + } catch (\Throwable $e) { + Db::rollback(); + throw $e; + } + } +} \ No newline at end of file diff --git a/app/ticket/service/ConversationService.php b/app/ticket/service/ConversationService.php index cc3ef84..1716b8f 100644 --- a/app/ticket/service/ConversationService.php +++ b/app/ticket/service/ConversationService.php @@ -11,8 +11,8 @@ class ConversationService { public function list($params) { -// $locale = locale(); - $locale = 'zh'; + $locale = locale(); +// $locale = 'zh'; $ticket_status = $locale == 'zh'? Constants::TICKET_STATUS_ZH:Constants::TICKET_STATUS_EN; // $ticket_status = Constants::TICKET_STATUS_ZH; // $params['locale'] = locale(); @@ -30,7 +30,6 @@ class ConversationService try { return (new ConversationLogic())->add($data); } catch (\Throwable $e) { - Db::rollback(); throw $e; } } diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index 4ca7c73..a20c20b 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -65,7 +65,7 @@ class TicketService throw new BusinessException('工单不存在'); } if($data['status'] == $ticket->status){ - throw new BusinessException('状态未修改'); + throw new BusinessException(trans('status_not_modified')); } // if(!in_array($ticket->status, [Constants::TICKET_STATUS['PENDING'], Constants::TICKET_STATUS['CONFIRM']]) diff --git a/composer.json b/composer.json index 20cf41f..ccf259e 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,9 @@ "league/oauth2-server": "^9.2", "topthink/think-validate": "^3.0", "shopwwi/webman-filesystem": "1.1", - "shopwwi/filesystem-oss": "^1.0" + "shopwwi/filesystem-oss": "^1.0", + "webman/redis-queue": "^1.3", + "symfony/translation": "^7.3" }, "suggest": { "ext-event": "For better performance. " diff --git a/composer.lock b/composer.lock index d34c290..01843a4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7421030f864dacf31b06378e1045d034", + "content-hash": "acb636fcb8774558a04bd674f9f95f55", "packages": [ { "name": "aliyuncs/oss-sdk-php", @@ -5365,7 +5365,13 @@ "type": "zip", "url": "https://api.github.com/repos/symfony/translation/zipball/4aba29076a29a3aa667e09b791e5f868973a8667", "reference": "4aba29076a29a3aa667e09b791e5f868973a8667", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=8.2", @@ -6147,6 +6153,43 @@ }, "time": "2025-03-14T03:52:14+00:00" }, + { + "name": "webman/redis-queue", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/webman-php/redis-queue.git", + "reference": "6fd491b19acb006d60931724aa2577a046ccb612" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webman-php/redis-queue/zipball/6fd491b19acb006d60931724aa2577a046ccb612", + "reference": "6fd491b19acb006d60931724aa2577a046ccb612", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "workerman/redis-queue": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Webman\\RedisQueue\\": "./src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "description": "Redis message queue plugin for webman.", + "support": { + "issues": "https://github.com/webman-php/redis-queue/issues", + "source": "https://github.com/webman-php/redis-queue/tree/v1.3.1" + }, + "time": "2024-02-28T07:21:52+00:00" + }, { "name": "workerman/coroutine", "version": "v1.1.3", @@ -6186,6 +6229,90 @@ }, "time": "2025-02-17T03:34:21+00:00" }, + { + "name": "workerman/redis", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/walkor/redis.git", + "reference": "82b398c5bdd5d683a3458aaf645b159b7b39b84e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/walkor/redis/zipball/82b398c5bdd5d683a3458aaf645b159b7b39b84e", + "reference": "82b398c5bdd5d683a3458aaf645b159b7b39b84e", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7", + "workerman/workerman": "^4.1.0||^5.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Workerman\\Redis\\": "./src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "homepage": "http://www.workerman.net", + "support": { + "issues": "https://github.com/walkor/redis/issues", + "source": "https://github.com/walkor/redis/tree/v2.0.4" + }, + "time": "2025-04-05T07:45:12+00:00" + }, + { + "name": "workerman/redis-queue", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/walkor/redis-queue.git", + "reference": "75dbf7ed2ea228c45dc0df82c0fea35879b715d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/walkor/redis-queue/zipball/75dbf7ed2ea228c45dc0df82c0fea35879b715d0", + "reference": "75dbf7ed2ea228c45dc0df82c0fea35879b715d0", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.0", + "workerman/redis": "^1.0||^2.0", + "workerman/workerman": ">=4.0.20" + }, + "type": "library", + "autoload": { + "psr-4": { + "Workerman\\RedisQueue\\": "./src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Message queue system written in PHP based on workerman and backed by Redis.", + "homepage": "http://www.workerman.net", + "support": { + "issues": "https://github.com/walkor/redis-queue/issues", + "source": "https://github.com/walkor/redis-queue/tree/v1.2.1" + }, + "time": "2025-01-02T09:21:45+00:00" + }, { "name": "workerman/webman-framework", "version": "v2.1.2", diff --git a/config/plugin/webman/redis-queue/app.php b/config/plugin/webman/redis-queue/app.php new file mode 100644 index 0000000..8f9c426 --- /dev/null +++ b/config/plugin/webman/redis-queue/app.php @@ -0,0 +1,4 @@ + true, +]; \ No newline at end of file diff --git a/config/plugin/webman/redis-queue/command.php b/config/plugin/webman/redis-queue/command.php new file mode 100644 index 0000000..8bfe2a1 --- /dev/null +++ b/config/plugin/webman/redis-queue/command.php @@ -0,0 +1,7 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + 'default' => [ + 'handlers' => [ + [ + 'class' => Monolog\Handler\RotatingFileHandler::class, + 'constructor' => [ + runtime_path() . '/logs/redis-queue/queue.log', + 7, //$maxFiles + Monolog\Logger::DEBUG, + ], + 'formatter' => [ + 'class' => Monolog\Formatter\LineFormatter::class, + 'constructor' => [null, 'Y-m-d H:i:s', true], + ], + ] + ], + ] +]; diff --git a/config/plugin/webman/redis-queue/process.php b/config/plugin/webman/redis-queue/process.php new file mode 100644 index 0000000..9fac733 --- /dev/null +++ b/config/plugin/webman/redis-queue/process.php @@ -0,0 +1,12 @@ + [ + 'handler' => Webman\RedisQueue\Process\Consumer::class, + 'count' => getenv('REDIS_QUEUE_PROCESS_COUNT'), // 可以设置多进程同时消费 + 'constructor' => [ + // 消费者类目录 + // 'consumer_dir' => app_path() . '/queue/redis' + 'consumer_dir' => app_path() . getenv('REDIS_QUEUE_CONSUMER_DIR') + ] + ] +]; \ No newline at end of file diff --git a/config/plugin/webman/redis-queue/redis.php b/config/plugin/webman/redis-queue/redis.php new file mode 100644 index 0000000..420914d --- /dev/null +++ b/config/plugin/webman/redis-queue/redis.php @@ -0,0 +1,22 @@ + [ +// 'host' => 'redis://127.0.0.1:6379', + 'host' => getenv('REDIS_QUEUE_HOST'), + 'options' => [ + 'auth' => getenv('REDIS_QUEUE_AUTH'), // 密码,字符串类型,可选参数 + 'db' => getenv('REDIS_QUEUE_DB'), // 数据库 + 'prefix' => getenv('REDIS_QUEUE_PREFIX'), // key 前缀 + 'max_attempts' => getenv('REDIS_QUEUE_MAX_ATTEMPTS'), // 消费失败后,重试次数 + 'retry_seconds' => getenv('REDIS_QUEUE_RETRY_SECONDS'), // 重试间隔,单位秒 + ], + // Connection pool, supports only Swoole or Swow drivers. + 'pool' => [ + 'max_connections' => 5, + 'min_connections' => 1, + 'wait_timeout' => 3, + 'idle_timeout' => 60, + 'heartbeat_interval' => 50, + ] + ], +]; diff --git a/config/route.php b/config/route.php index c7b7413..76a9435 100644 --- a/config/route.php +++ b/config/route.php @@ -50,5 +50,11 @@ Route::group('/ticket', function () { Route::any('/conversation/edit', [app\ticket\controller\ConversationController::class, 'edit']); Route::any('/conversation/list', [app\ticket\controller\ConversationController::class, 'index']); + //工单分类 + Route::any('/categorie/add', [app\ticket\controller\CategorieController::class, 'add']); + Route::any('/categorie/edit', [app\ticket\controller\CategorieController::class, 'edit']); + Route::any('/categorie/list', [app\ticket\controller\CategorieController::class, 'index']); + Route::any('/categorie/getAll', [app\ticket\controller\CategorieController::class, 'getAll']); + }); diff --git a/resource/translations/ar/messages.php b/resource/translations/ar/messages.php new file mode 100644 index 0000000..342a451 --- /dev/null +++ b/resource/translations/ar/messages.php @@ -0,0 +1,5 @@ + 'الوضع لم يتغير', +]; \ No newline at end of file diff --git a/resource/translations/en/messages.php b/resource/translations/en/messages.php new file mode 100644 index 0000000..53c6d07 --- /dev/null +++ b/resource/translations/en/messages.php @@ -0,0 +1,5 @@ + 'status not modified', +]; \ No newline at end of file diff --git a/resource/translations/ru/messages.php b/resource/translations/ru/messages.php new file mode 100644 index 0000000..fc398a5 --- /dev/null +++ b/resource/translations/ru/messages.php @@ -0,0 +1,5 @@ + 'Статус не изменен', +]; \ No newline at end of file diff --git a/resource/translations/zh/messages.php b/resource/translations/zh/messages.php new file mode 100644 index 0000000..7c95aaf --- /dev/null +++ b/resource/translations/zh/messages.php @@ -0,0 +1,5 @@ + '状态未修改', +]; \ No newline at end of file From 345e2391b12e015e51adb97e7145bb7f9bfb8665 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 4 Jul 2025 14:21:21 +0800 Subject: [PATCH 12/20] =?UTF-8?q?=E9=99=84=E4=BB=B6oss?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/service/CategorieService.php | 6 +++--- app/ticket/service/TicketService.php | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/ticket/service/CategorieService.php b/app/ticket/service/CategorieService.php index 5a0e9ee..a6843e1 100644 --- a/app/ticket/service/CategorieService.php +++ b/app/ticket/service/CategorieService.php @@ -13,9 +13,9 @@ class CategorieService public function list($params) { $result = (new CategorieLogic())->list($params); - + $value=$result[0]->toArray(); foreach ($result as $key => &$value) { - $value['name'] = isset($item['translation']) ? $item['translation']['name'] : ''; + $value['name'] = isset($value['translation']) ? $value['translation']['name'] : ''; unset($value['translation']); } unset($value); @@ -27,7 +27,7 @@ class CategorieService { $result = (new CategorieLogic())->getAll($params); foreach ($result as $key => &$value) { - $value['name'] =isset($item['translation']) ? $item['translation']['name'] : ''; + $value['name'] = isset($value['translation']) ? $value['translation']['name'] : ''; unset($value['translation']); } unset($value); diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index a20c20b..98ad7b1 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -17,6 +17,14 @@ class TicketService public function list($params) { $res = (new TicketLogic())->list($params); + foreach ($res as $k => &$v) { + foreach ($v['attachments'] as &$attachments) { + $attachments['storage_path_full'] = (new \app\common\service\OssService())->generatePrivateUrl($attachments['storage_path']); + } + } + unset($v); + unset($attachments); + return $res; } From 1b73974d46b4ea8e8ac2628162f1a9c474019fd5 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 4 Jul 2025 14:38:00 +0800 Subject: [PATCH 13/20] 1 --- app/ticket/controller/CategorieController.php | 12 ++++++++++++ app/ticket/logic/AttachmentLogic.php | 4 ++-- app/ticket/logic/CategorieLogic.php | 18 ++++++++++++++++-- app/ticket/logic/ConversationLogic.php | 2 +- app/ticket/logic/TicketLogic.php | 4 ++-- app/ticket/model/TicketCategorie.php | 3 +++ app/ticket/service/CategorieService.php | 12 ++++++++++++ config/route.php | 1 + 8 files changed, 49 insertions(+), 7 deletions(-) diff --git a/app/ticket/controller/CategorieController.php b/app/ticket/controller/CategorieController.php index d9fe422..a7a4d3d 100644 --- a/app/ticket/controller/CategorieController.php +++ b/app/ticket/controller/CategorieController.php @@ -49,4 +49,16 @@ class CategorieController extends BaseController return $this->error($th->getMessage().' '.$th->getLine().' '.$th->getFile()); } } + + public function delete(Request $request) + { + try { + $result = (new CategorieService())->delete($request->get('id')); + return $result + ? $this->success($result) + : $this->error(); + } catch (\Throwable $th) { + return $this->error($th->getMessage().' '.$th->getLine().' '.$th->getFile()); + } + } } \ No newline at end of file diff --git a/app/ticket/logic/AttachmentLogic.php b/app/ticket/logic/AttachmentLogic.php index ad3f52d..dac59f9 100644 --- a/app/ticket/logic/AttachmentLogic.php +++ b/app/ticket/logic/AttachmentLogic.php @@ -29,7 +29,7 @@ class AttachmentLogic 'data' => $data, 'error' => $e->getMessage() ]); - throw new BusinessException($e->getMessage().'工单创建失败,请稍后重试', 500); + throw new BusinessException('工单创建失败,请稍后重试', 500); } } @@ -67,7 +67,7 @@ class AttachmentLogic 'data' => $data, 'error' => $e->getMessage() ]); - throw new BusinessException($e->getMessage().'工单创建失败,请稍后重试', 500); + throw new BusinessException('工单创建失败,请稍后重试', 500); } } diff --git a/app/ticket/logic/CategorieLogic.php b/app/ticket/logic/CategorieLogic.php index ab100b4..4f63ebe 100644 --- a/app/ticket/logic/CategorieLogic.php +++ b/app/ticket/logic/CategorieLogic.php @@ -32,7 +32,7 @@ class CategorieLogic 'data' => $data, 'error' => $e->getMessage() ]); - throw new BusinessException($e->getMessage().'分类创建失败,请稍后重试', 500); + throw new BusinessException('分类创建失败,请稍后重试', 500); } } @@ -46,7 +46,21 @@ class CategorieLogic 'data' => $data, 'error' => $e->getMessage() ]); - throw new BusinessException($e->getMessage().'分类编辑失败,请稍后重试', 500); + throw new BusinessException('分类编辑失败,请稍后重试', 500); + } + } + + public function delete(int $id) + { + try { + $categorie = TicketCategorie::where(['id'=>$id])->delete(); + return $categorie; + } catch (\Throwable $e) { + Log::error('分类删除失败', [ + 'id' => $id, + 'error' => $e->getMessage() + ]); + throw new BusinessException('分类删除失败,请稍后重试', 500); } } } \ No newline at end of file diff --git a/app/ticket/logic/ConversationLogic.php b/app/ticket/logic/ConversationLogic.php index 6ce3cbf..d47a709 100644 --- a/app/ticket/logic/ConversationLogic.php +++ b/app/ticket/logic/ConversationLogic.php @@ -40,7 +40,7 @@ class ConversationLogic 'data' => $data, 'error' => $e->getMessage() ]); - throw new BusinessException($e->getMessage().'会话编辑失败,请稍后重试', 500); + throw new BusinessException('会话编辑失败,请稍后重试', 500); } } } \ No newline at end of file diff --git a/app/ticket/logic/TicketLogic.php b/app/ticket/logic/TicketLogic.php index 21e8539..8293654 100644 --- a/app/ticket/logic/TicketLogic.php +++ b/app/ticket/logic/TicketLogic.php @@ -38,7 +38,7 @@ class TicketLogic 'data' => $data, 'error' => $e->getMessage() ]); - throw new BusinessException($e->getMessage().'工单创建失败,请稍后重试', 500); + throw new BusinessException('工单创建失败,请稍后重试', 500); } } public function edit(array $data) @@ -52,7 +52,7 @@ class TicketLogic 'data' => $data, 'error' => $e->getMessage() ]); - throw new BusinessException($e->getMessage().'工单提取方法…失败,请稍后重试', 500); + throw new BusinessException('工单提取方法…失败,请稍后重试', 500); } } diff --git a/app/ticket/model/TicketCategorie.php b/app/ticket/model/TicketCategorie.php index 79f4f75..6d0c675 100644 --- a/app/ticket/model/TicketCategorie.php +++ b/app/ticket/model/TicketCategorie.php @@ -2,6 +2,7 @@ namespace app\ticket\model; +use Illuminate\Database\Eloquent\SoftDeletes; use support\Model; /** @@ -11,9 +12,11 @@ use support\Model; * @property string $description 分类描述 * @property string $created_at 创建时间 * @property string $updated_at 更新时间 + * @property string $deleted_at 删除时间 */ class TicketCategorie extends Model { + use SoftDeletes; protected $connection = 'mysql'; protected $table = 'ticket_categorie'; protected $primaryKey = 'id'; diff --git a/app/ticket/service/CategorieService.php b/app/ticket/service/CategorieService.php index a6843e1..d769a58 100644 --- a/app/ticket/service/CategorieService.php +++ b/app/ticket/service/CategorieService.php @@ -82,4 +82,16 @@ class CategorieService throw $e; } } + public function delete(int $id) + { + if(empty($id)){ + throw new BusinessException('id不能为空'); + } + try { + $result = (new CategorieLogic())->delete($id); + return $result; + } catch (\Throwable $e) { + throw $e; + } + } } \ No newline at end of file diff --git a/config/route.php b/config/route.php index 76a9435..6d7ce98 100644 --- a/config/route.php +++ b/config/route.php @@ -55,6 +55,7 @@ Route::group('/ticket', function () { Route::any('/categorie/edit', [app\ticket\controller\CategorieController::class, 'edit']); Route::any('/categorie/list', [app\ticket\controller\CategorieController::class, 'index']); Route::any('/categorie/getAll', [app\ticket\controller\CategorieController::class, 'getAll']); + Route::any('/categorie/delete', [app\ticket\controller\CategorieController::class, 'delete']); }); From b70fc6c4f84234d1d838688adc0238b1b8ded7ea Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 4 Jul 2025 14:44:46 +0800 Subject: [PATCH 14/20] 1 --- app/ticket/controller/CategorieController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/ticket/controller/CategorieController.php b/app/ticket/controller/CategorieController.php index a7a4d3d..84e8bd7 100644 --- a/app/ticket/controller/CategorieController.php +++ b/app/ticket/controller/CategorieController.php @@ -53,7 +53,7 @@ class CategorieController extends BaseController public function delete(Request $request) { try { - $result = (new CategorieService())->delete($request->get('id')); + $result = (new CategorieService())->delete($request->input('id')); return $result ? $this->success($result) : $this->error(); From 388747634a2e35ecba352410c1e3a3810973fe6d Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 4 Jul 2025 15:04:29 +0800 Subject: [PATCH 15/20] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/queue/translation/config/trans.php | 2 +- app/ticket/logic/CategorieLogic.php | 12 ++++++------ app/ticket/logic/TicketLogic.php | 2 +- .../model/{TicketCategorie.php => Categorie.php} | 10 +++++++--- ...gorieTranslation.php => CategorieTranslation.php} | 2 +- app/ticket/model/Ticket.php | 4 ++++ app/ticket/service/TicketService.php | 2 ++ 7 files changed, 22 insertions(+), 12 deletions(-) rename app/ticket/model/{TicketCategorie.php => Categorie.php} (76%) rename app/ticket/model/{TicketCategorieTranslation.php => CategorieTranslation.php} (95%) diff --git a/app/queue/translation/config/trans.php b/app/queue/translation/config/trans.php index 73b55b1..e2c7702 100644 --- a/app/queue/translation/config/trans.php +++ b/app/queue/translation/config/trans.php @@ -4,7 +4,7 @@ return [ // 定义所有需要多语言支持的实体 'entities' => [ 'ticket_categorie' => [ - 'translation_model' => \app\ticket\model\TicketCategorieTranslation::class, + 'translation_model' => \app\ticket\model\CategorieTranslation::class, 'foreign_key' => 'categorie_id', ], ], diff --git a/app/ticket/logic/CategorieLogic.php b/app/ticket/logic/CategorieLogic.php index 4f63ebe..c11bd64 100644 --- a/app/ticket/logic/CategorieLogic.php +++ b/app/ticket/logic/CategorieLogic.php @@ -2,7 +2,7 @@ namespace app\ticket\logic; -use app\ticket\model\TicketCategorie; +use app\ticket\model\Categorie; use support\Log; use support\exception\BusinessException; @@ -13,20 +13,20 @@ class CategorieLogic $where = []; $size = $params['size'] ?? 10; $current = $params['current'] ?? 1; - return TicketCategorie::with('translation')->where($where)->paginate($size, ['*'], 'page', $current); + return Categorie::with('translation')->where($where)->paginate($size, ['*'], 'page', $current); } public function getAll($params) { $where = []; $where[] = ['status', '=', 1]; - return TicketCategorie::with('translation')->where($where)->get(); + return Categorie::with('translation')->where($where)->get(); } public function add(array $data) { try { - return TicketCategorie::create($data); + return Categorie::create($data); } catch (\Throwable $e) { Log::error('分类创建失败', [ 'data' => $data, @@ -39,7 +39,7 @@ class CategorieLogic public function edit(array $data) { try { - $categorie = TicketCategorie::updateOrCreate(['id' => $data['id']], $data); + $categorie = Categorie::updateOrCreate(['id' => $data['id']], $data); return $categorie; } catch (\Throwable $e) { Log::error('分类编辑失败', [ @@ -53,7 +53,7 @@ class CategorieLogic public function delete(int $id) { try { - $categorie = TicketCategorie::where(['id'=>$id])->delete(); + $categorie = Categorie::where(['id'=>$id])->delete(); return $categorie; } catch (\Throwable $e) { Log::error('分类删除失败', [ diff --git a/app/ticket/logic/TicketLogic.php b/app/ticket/logic/TicketLogic.php index 8293654..ca5532f 100644 --- a/app/ticket/logic/TicketLogic.php +++ b/app/ticket/logic/TicketLogic.php @@ -25,7 +25,7 @@ class TicketLogic } $size = $params['size']; $current = $params['current']; - return Ticket::with('attachments')->where($where)->orderBy('id','desc')->paginate($size, ['*'], 'page', $current); + return Ticket::with('attachments')->with('categorie')->with('categorie.translation')->where($where)->orderBy('id','desc')->paginate($size, ['*'], 'page', $current); } public function add(array $data) { diff --git a/app/ticket/model/TicketCategorie.php b/app/ticket/model/Categorie.php similarity index 76% rename from app/ticket/model/TicketCategorie.php rename to app/ticket/model/Categorie.php index 6d0c675..70a92cf 100644 --- a/app/ticket/model/TicketCategorie.php +++ b/app/ticket/model/Categorie.php @@ -14,7 +14,7 @@ use support\Model; * @property string $updated_at 更新时间 * @property string $deleted_at 删除时间 */ -class TicketCategorie extends Model +class Categorie extends Model { use SoftDeletes; protected $connection = 'mysql'; @@ -37,7 +37,7 @@ class TicketCategorie extends Model */ public function translation() { - return $this->hasOne(TicketCategorieTranslation::class, 'categorie_id')->where('locale', locale()); + return $this->hasOne(CategorieTranslation::class, 'categorie_id')->where('locale', locale()); } /** @@ -45,6 +45,10 @@ class TicketCategorie extends Model */ public function translations() { - return $this->hasMany(TicketCategorieTranslation::class, 'categorie_id'); + return $this->hasMany(CategorieTranslation::class, 'categorie_id'); + } + + public function ticket(){ + return $this->hasOne(Ticket::class, 'categorie_id', 'id'); } } \ No newline at end of file diff --git a/app/ticket/model/TicketCategorieTranslation.php b/app/ticket/model/CategorieTranslation.php similarity index 95% rename from app/ticket/model/TicketCategorieTranslation.php rename to app/ticket/model/CategorieTranslation.php index 66a8f95..5d72369 100644 --- a/app/ticket/model/TicketCategorieTranslation.php +++ b/app/ticket/model/CategorieTranslation.php @@ -14,7 +14,7 @@ use support\Model; * @property string $created_at 创建时间 * @property string $updated_at 更新时间 */ -class TicketCategorieTranslation extends Model +class CategorieTranslation extends Model { protected $connection = 'mysql'; protected $table = 'ticket_categorie_translation'; diff --git a/app/ticket/model/Ticket.php b/app/ticket/model/Ticket.php index 0327a87..d10672c 100644 --- a/app/ticket/model/Ticket.php +++ b/app/ticket/model/Ticket.php @@ -70,4 +70,8 @@ class Ticket extends Model public function attachments(){ return $this->hasMany(Attachment::class, 'ticket_id', 'id'); } + + public function categorie(){ + return $this->belongsTo(Categorie::class, 'categorie_id', 'id'); + } } diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index 98ad7b1..28afe14 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -18,6 +18,8 @@ class TicketService { $res = (new TicketLogic())->list($params); foreach ($res as $k => &$v) { + $v['categorie']['name'] = isset($v['categorie']['translation']) ? $v['categorie']['translation']['name'] : ''; + unset($v['categorie']['translation']); foreach ($v['attachments'] as &$attachments) { $attachments['storage_path_full'] = (new \app\common\service\OssService())->generatePrivateUrl($attachments['storage_path']); } From 510fec0533046090bbc836bcb7aaeaa6215f65d3 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 4 Jul 2025 15:06:41 +0800 Subject: [PATCH 16/20] 1 --- app/ticket/service/TicketService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index 28afe14..a1f1825 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -18,7 +18,7 @@ class TicketService { $res = (new TicketLogic())->list($params); foreach ($res as $k => &$v) { - $v['categorie']['name'] = isset($v['categorie']['translation']) ? $v['categorie']['translation']['name'] : ''; + $res[$k]['categorie']['name'] = isset($v['categorie']['translation']) ? $v['categorie']['translation']['name'] : ''; unset($v['categorie']['translation']); foreach ($v['attachments'] as &$attachments) { $attachments['storage_path_full'] = (new \app\common\service\OssService())->generatePrivateUrl($attachments['storage_path']); From 6fa4b8ddfd5d1d10e7804ab130053d3fe629c73b Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 4 Jul 2025 15:27:09 +0800 Subject: [PATCH 17/20] =?UTF-8?q?=E7=8A=B6=E6=80=81=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/service/TicketService.php | 5 +++-- config/constants/Constants.php | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index a1f1825..fd39be0 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -18,8 +18,9 @@ class TicketService { $res = (new TicketLogic())->list($params); foreach ($res as $k => &$v) { - $res[$k]['categorie']['name'] = isset($v['categorie']['translation']) ? $v['categorie']['translation']['name'] : ''; - unset($v['categorie']['translation']); + $name = isset($v['categorie']['translation']) ? $v['categorie']['translation']['name'] : ''; + $res[$k]['categorie']['name'] = $name; + unset($res[$k]['categorie']['translation']); foreach ($v['attachments'] as &$attachments) { $attachments['storage_path_full'] = (new \app\common\service\OssService())->generatePrivateUrl($attachments['storage_path']); } diff --git a/config/constants/Constants.php b/config/constants/Constants.php index e4c9284..1e77a2b 100644 --- a/config/constants/Constants.php +++ b/config/constants/Constants.php @@ -17,21 +17,21 @@ class Constants self::TICKET_STATUS['PROCESS'] => '处理中', self::TICKET_STATUS['CONFIRM'] => '待确认', self::TICKET_STATUS['FINISH'] => '已完成', - self::TICKET_STATUS['REJECTED'] => '已驳回', + self::TICKET_STATUS['REJECTED'] => '关闭', ]; public const TICKET_STATUS_EN = [ self::TICKET_STATUS['PENDING'] => 'Pending acceptance', self::TICKET_STATUS['PROCESS'] => 'Processing', self::TICKET_STATUS['CONFIRM'] => 'To be confirmed', self::TICKET_STATUS['FINISH'] => 'Completed', - self::TICKET_STATUS['REJECTED'] => 'Rejected', + self::TICKET_STATUS['REJECTED'] => 'close', ]; public const TICKET_STATUS_RU = [ self::TICKET_STATUS['PENDING'] => 'Подлежит рассмотрению', self::TICKET_STATUS['PROCESS'] => 'В процессе обработки', self::TICKET_STATUS['CONFIRM'] => 'Подлежит подтверждению', self::TICKET_STATUS['FINISH'] => 'Завершено', - self::TICKET_STATUS['REJECTED'] => 'Отклонено', + self::TICKET_STATUS['REJECTED'] => 'Закрыть', ]; } \ No newline at end of file From 92fd6d4d9f690b12f756e70dcdaff45dffe94679 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 4 Jul 2025 15:42:03 +0800 Subject: [PATCH 18/20] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=88=86=E7=B1=BB=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/service/TicketService.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index fd39be0..5d1ee0a 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -19,8 +19,12 @@ class TicketService $res = (new TicketLogic())->list($params); foreach ($res as $k => &$v) { $name = isset($v['categorie']['translation']) ? $v['categorie']['translation']['name'] : ''; - $res[$k]['categorie']['name'] = $name; - unset($res[$k]['categorie']['translation']); + if(isset($res[$k]['categorie'])){ + $res[$k]['categorie']['name'] = $name; + } + if (isset($v['categorie']['translation'])){ + unset($res[$k]['categorie']['translation']); + } foreach ($v['attachments'] as &$attachments) { $attachments['storage_path_full'] = (new \app\common\service\OssService())->generatePrivateUrl($attachments['storage_path']); } From bb1f105021e3cba700fa9a304014101640aa25de Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 4 Jul 2025 16:10:16 +0800 Subject: [PATCH 19/20] =?UTF-8?q?=E7=8A=B6=E6=80=81=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=EF=BC=88=E4=B8=8D=E8=83=BD=E5=80=92=E9=80=80?= =?UTF-8?q?=E7=8A=B6=E6=80=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/controller/TicketController.php | 2 +- app/ticket/logic/AttachmentLogic.php | 4 ++-- app/ticket/logic/TicketLogic.php | 2 +- app/ticket/service/TicketService.php | 2 +- resource/translations/ar/messages.php | 2 +- resource/translations/en/messages.php | 2 +- resource/translations/ru/messages.php | 2 +- resource/translations/zh/messages.php | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/ticket/controller/TicketController.php b/app/ticket/controller/TicketController.php index cc33459..782dc74 100644 --- a/app/ticket/controller/TicketController.php +++ b/app/ticket/controller/TicketController.php @@ -26,7 +26,7 @@ class TicketController extends BaseController ? $this->success() : $this->error(); } catch (\Throwable $th) { - return $this->error($th->getMessage().' '.$th->getLine().' '.$th->getFile()); + return $this->error($th->getMessage()); } } diff --git a/app/ticket/logic/AttachmentLogic.php b/app/ticket/logic/AttachmentLogic.php index dac59f9..b498f7e 100644 --- a/app/ticket/logic/AttachmentLogic.php +++ b/app/ticket/logic/AttachmentLogic.php @@ -63,11 +63,11 @@ class AttachmentLogic $res = Attachment::whereNotIn('id', $attachmentsId)->where('ticket_id',$ticket_id)->delete(); return $res; } catch (\Throwable $e) { - Log::error('工单创建失败', [ + Log::error('工单编辑(附件)失败', [ 'data' => $data, 'error' => $e->getMessage() ]); - throw new BusinessException('工单创建失败,请稍后重试', 500); + throw new BusinessException('工单编辑失败,请稍后重试', 500); } } diff --git a/app/ticket/logic/TicketLogic.php b/app/ticket/logic/TicketLogic.php index ca5532f..e22cdb7 100644 --- a/app/ticket/logic/TicketLogic.php +++ b/app/ticket/logic/TicketLogic.php @@ -52,7 +52,7 @@ class TicketLogic 'data' => $data, 'error' => $e->getMessage() ]); - throw new BusinessException('工单提取方法…失败,请稍后重试', 500); + throw new BusinessException('工单编辑失败,请稍后重试', 500); } } diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index 5d1ee0a..f5a0d72 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -79,7 +79,7 @@ class TicketService if(empty($ticket)){ throw new BusinessException('工单不存在'); } - if($data['status'] == $ticket->status){ + if($data['status'] <= $ticket->status){ throw new BusinessException(trans('status_not_modified')); } diff --git a/resource/translations/ar/messages.php b/resource/translations/ar/messages.php index 342a451..a701f87 100644 --- a/resource/translations/ar/messages.php +++ b/resource/translations/ar/messages.php @@ -1,5 +1,5 @@ 'الوضع لم يتغير', + 'status_not_modified' => 'الدولة لا يمكن تعديلها عكسيا', ]; \ No newline at end of file diff --git a/resource/translations/en/messages.php b/resource/translations/en/messages.php index 53c6d07..c676eb2 100644 --- a/resource/translations/en/messages.php +++ b/resource/translations/en/messages.php @@ -1,5 +1,5 @@ 'status not modified', + 'status_not_modified' => 'The status cannot be reversed for modification', ]; \ No newline at end of file diff --git a/resource/translations/ru/messages.php b/resource/translations/ru/messages.php index fc398a5..96ab3a4 100644 --- a/resource/translations/ru/messages.php +++ b/resource/translations/ru/messages.php @@ -1,5 +1,5 @@ 'Статус не изменен', + 'status_not_modified' => 'Статус не может быть изменен в обратном направлении', ]; \ No newline at end of file diff --git a/resource/translations/zh/messages.php b/resource/translations/zh/messages.php index 7c95aaf..229d7ee 100644 --- a/resource/translations/zh/messages.php +++ b/resource/translations/zh/messages.php @@ -1,5 +1,5 @@ '状态未修改', + 'status_not_modified' => '状态不能逆向修改', ]; \ No newline at end of file From 03a6d65b009012c882e4efc70e9701a028c09d61 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Mon, 7 Jul 2025 15:27:48 +0800 Subject: [PATCH 20/20] =?UTF-8?q?=E8=A1=A8=E5=89=8D=E7=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/model/Attachment.php | 2 +- app/ticket/model/Categorie.php | 2 +- app/ticket/model/CategorieTranslation.php | 2 +- app/ticket/model/Conversation.php | 2 +- app/ticket/model/Ticket.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/ticket/model/Attachment.php b/app/ticket/model/Attachment.php index b29af53..f5fc843 100644 --- a/app/ticket/model/Attachment.php +++ b/app/ticket/model/Attachment.php @@ -33,7 +33,7 @@ class Attachment extends Model * * @var string */ - protected $table = 'ticket_attachment'; + protected $table = 'tkt_ticket_attachment'; /** * The primary key associated with the table. diff --git a/app/ticket/model/Categorie.php b/app/ticket/model/Categorie.php index 70a92cf..610c693 100644 --- a/app/ticket/model/Categorie.php +++ b/app/ticket/model/Categorie.php @@ -18,7 +18,7 @@ class Categorie extends Model { use SoftDeletes; protected $connection = 'mysql'; - protected $table = 'ticket_categorie'; + protected $table = 'tkt_ticket_categorie'; protected $primaryKey = 'id'; public $timestamps = true; protected $dateFormat = 'U'; diff --git a/app/ticket/model/CategorieTranslation.php b/app/ticket/model/CategorieTranslation.php index 5d72369..6660dea 100644 --- a/app/ticket/model/CategorieTranslation.php +++ b/app/ticket/model/CategorieTranslation.php @@ -17,7 +17,7 @@ use support\Model; class CategorieTranslation extends Model { protected $connection = 'mysql'; - protected $table = 'ticket_categorie_translation'; + protected $table = 'tkt_ticket_categorie_translation'; protected $primaryKey = 'id'; public $timestamps = true; protected $dateFormat = 'U'; diff --git a/app/ticket/model/Conversation.php b/app/ticket/model/Conversation.php index 8839455..6d63cb5 100644 --- a/app/ticket/model/Conversation.php +++ b/app/ticket/model/Conversation.php @@ -16,7 +16,7 @@ use support\Model; class Conversation extends Model { protected $connection = 'mysql'; - protected $table = 'ticket_conversation'; + protected $table = 'tkt_ticket_conversation'; protected $primaryKey = 'id'; public $timestamps = true; protected $dateFormat = 'U'; diff --git a/app/ticket/model/Ticket.php b/app/ticket/model/Ticket.php index d10672c..cf71b2a 100644 --- a/app/ticket/model/Ticket.php +++ b/app/ticket/model/Ticket.php @@ -33,7 +33,7 @@ class Ticket extends Model * * @var string */ - protected $table = 'ticket'; + protected $table = 'tkt_ticket'; /** * The primary key associated with the table.