80 Commits

Author SHA1 Message Date
mzl92 1c6e43170f 修改手动分组为自动查询 2026-01-22 10:03:46 +08:00
mzl92 a0d5a766a1 Merge branch 'master' into develop 2026-01-22 09:15:03 +08:00
mzl92 403ac7a271 Merge branch 'master' into develop 2026-01-08 15:08:44 +08:00
mzl92 433b2dd915 Merge branch 'master' into develop 2026-01-08 15:04:47 +08:00
mzl92 bed833f790 Merge branch 'master' into develop 2026-01-08 15:02:06 +08:00
mzl92 5570e025b4 Merge branch 'master' into develop 2026-01-08 14:49:54 +08:00
mzl92 67139e4161 Merge branch 'master' into develop 2026-01-08 09:14:35 +08:00
18338781771 9f96d4da3f Merge branch 'feature/inv' into develop 2026-01-07 17:38:14 +08:00
18338781771 736df0ebdf 1 2026-01-07 17:27:29 +08:00
18338781771 4c9853f72a 1 2026-01-07 17:23:37 +08:00
18338781771 90dca83487 Merge branch 'feature/inv' into develop 2026-01-07 17:23:15 +08:00
18338781771 35f80aab1a Revert "Merge branch 'feature/inv' into develop"
This reverts commit facf0b4c10, reversing
changes made to 1221e42917.
2026-01-07 17:21:09 +08:00
18338781771 b35e536c79 物品领用审核 2026-01-07 17:20:21 +08:00
18338781771 facf0b4c10 Merge branch 'feature/inv' into develop 2026-01-07 13:39:12 +08:00
18338781771 1221e42917 Merge branch 'feature/inv' into develop 2026-01-07 11:32:18 +08:00
18338781771 4dc708e133 Merge branch 'feature/inv' into develop 2026-01-07 11:08:07 +08:00
18338781771 5bcca5cb12 Merge branch 'feature/inv' into develop 2026-01-07 10:58:15 +08:00
18338781771 9b36bbf227 Merge branch 'feature/inv' into develop 2026-01-07 10:49:42 +08:00
18338781771 502740e106 Merge branch 'feature/inv' into develop 2026-01-07 09:44:29 +08:00
18338781771 52eac05d43 Merge branch 'feature/inv' into develop 2026-01-05 10:42:16 +08:00
18338781771 fec079ef58 Merge branch 'feature/inv' into develop 2026-01-05 10:18:35 +08:00
18338781771 134ced1a31 Merge branch 'hotfix/email' into develop 2026-01-05 09:44:48 +08:00
18338781771 472f8e39a7 Merge branch 'feature/inv' into develop 2026-01-04 17:23:19 +08:00
18338781771 90aebf9956 Merge branch 'feature/inv' into develop 2026-01-04 16:42:25 +08:00
18338781771 edee50aaf9 移动端回调 2026-01-04 16:39:37 +08:00
18338781771 615e9745a0 Merge branch 'feature/inv' into develop
# Conflicts:
#	composer.lock
#	config/route.php
2026-01-04 16:29:36 +08:00
18338781771 fd4fa0fbf3 Merge branch 'hotfix/email' into develop 2026-01-04 16:14:12 +08:00
18338781771 8003ef49d1 Merge branch 'hotfix/email' into develop 2026-01-04 15:51:06 +08:00
18338781771 fddcbc2df8 Merge branch 'hotfix/email' into develop 2026-01-04 14:41:13 +08:00
18338781771 f60b365361 Merge branch 'hotfix/email' into develop 2026-01-04 13:39:40 +08:00
18338781771 ded377a758 Merge branch 'hotfix/email' into develop 2026-01-04 13:26:27 +08:00
18338781771 4537df63c2 Merge branch 'hotfix/email' into develop 2026-01-04 11:46:15 +08:00
18338781771 d76fec4624 Merge branch 'hotfix/email' into develop 2026-01-04 11:03:18 +08:00
mzl92 62d86c634c Merge branch 'master' into develop 2026-01-04 10:48:04 +08:00
18338781771 9fc890f8cd Merge branch 'feature/eamil' into develop 2025-12-26 14:13:36 +08:00
mzl92 6289b545f5 Merge branch 'master' into develop 2025-12-25 16:11:53 +08:00
mzl92 376411dd79 Merge branch 'hotfix/Hotfix-1' into develop
# Conflicts:
#	app/common/service/StockOrdersService.php
2025-12-25 16:10:24 +08:00
mzl92 83ff52c1a0 Merge branch 'hotfix/Hotfix-1' into develop
# Conflicts:
#	app/common/service/StockOrdersService.php
2025-12-25 16:08:10 +08:00
mzl92 db7f5d568c Merge branch 'hotfix/Hotfix-1' into develop 2025-12-25 16:00:35 +08:00
18338781771 bcf39b6037 Merge branch 'hotfix/stock' into develop 2025-12-24 13:42:40 +08:00
mzl92 9d050f4211 Merge branch 'master' into develop 2025-12-23 14:44:52 +08:00
mzl92 034b278b40 Merge branch 'master' into develop 2025-12-23 14:36:07 +08:00
mzl92 ebcabb23df Merge branch 'master' into develop
# Conflicts:
#	app/inquiry/service/FbFileImportService.php
2025-12-22 16:23:05 +08:00
mzl92 4acb89e56a Merge branch 'master' into develop
# Conflicts:
#	config/inquiry_channel.php
2025-12-18 15:11:12 +08:00
mzl92 d16bddcc32 Merge branch 'master' into develop
# Conflicts:
#	config/inquiry_channel.php
2025-12-16 14:22:47 +08:00
mzl92 6434c8769e Merge branch 'master' into develop
# Conflicts:
#	config/inquiry_channel.php
2025-12-16 13:45:20 +08:00
mzl92 c796d01703 Finish mzl_inquery 2025-12-15 15:57:57 +08:00
mzl92 ab6a8806af Merge branch 'develop' into feature/mzl_inquery 2025-12-15 15:56:43 +08:00
mzl92 9f8a241e35 Merge branch 'feature/mzl_inquery' of origin 2025-12-15 07:54:28 +00:00
mzl92 8f699d5ca9 email 2025-12-15 07:51:07 +00:00
mzl92 e6f68a9946 Merge branch 'master' into develop
# Conflicts:
#	app/inquiry/utils/FbLeadHeaderMapper.php
2025-12-12 18:37:36 +08:00
mzl92 7ac6201925 Merge branch 'master' into develop
# Conflicts:
#	app/inquiry/service/FbFileImportService.php
2025-12-12 18:12:13 +08:00
mzl92 358cb64fe4 Finish mzl_inquery 2025-12-12 17:50:42 +08:00
mzl92 aede027ae2 Merge branch 'develop' into feature/mzl_inquery 2025-12-12 17:50:27 +08:00
mzl92 dbe5e2e96f ts 2025-12-12 09:50:10 +00:00
mzl92 91c313f2ca Finish mzl_inquery 2025-12-12 17:48:25 +08:00
mzl92 f99b2a84ca inquiry 2025-12-12 09:47:34 +00:00
mzl92 909f169aae auto inquiry 2025-12-11 11:04:41 +00:00
mzl92 cdd6d78995 Merge branch 'master' into develop
# Conflicts:
#	app/queue/redis/InquiryToCrmNew.php
2025-12-11 15:33:06 +08:00
mzl92 133cd0a801 Merge branch 'master' into develop
# Conflicts:
#	app/command/InquiryReissueCommand.php
2025-12-11 15:23:36 +08:00
mzl92 8cdf9e9e39 Finish mzl_inquery 2025-12-11 15:07:20 +08:00
mzl92 e21f41701a Merge branch 'develop' into feature/mzl_inquery 2025-12-11 15:07:06 +08:00
mzl92 9f77b93b25 bf 2025-12-11 07:06:25 +00:00
mzl92 70fa843970 Merge branch 'master' into develop
# Conflicts:
#	app/command/InquiryAssignInquiryCommand.php
2025-12-10 20:27:06 +08:00
mzl92 0050ef6829 Finish mzl_inquery 2025-12-10 20:16:50 +08:00
mzl92 ba7c00e942 inquiry 2025-12-10 12:15:17 +00:00
mzl92 460de92912 派卡社媒脚本 2025-12-10 17:23:59 +08:00
18338781771 c85f07cff4 Merge branch 'feature/merge' into develop 2025-12-10 13:42:14 +08:00
18338781771 638be73988 Merge branch 'feature/merge' into develop 2025-12-10 13:35:13 +08:00
18338781771 cab55847e4 Merge branch 'feature/merge' into develop 2025-12-09 11:51:42 +08:00
18338781771 07f9280327 Merge branch 'master' into develop 2025-12-09 11:28:51 +08:00
18338781771 a3da2cfc23 Merge branch 'feature/merge' into develop 2025-12-05 16:27:32 +08:00
18338781771 521cfec00a Merge branch 'feature/merge' into develop 2025-12-05 10:34:41 +08:00
18338781771 ac982b0957 Merge branch 'feature/merge' into develop 2025-12-05 10:28:48 +08:00
18338781771 d9e2c89c0e Merge branch 'feature/merge' into develop 2025-12-04 18:11:52 +08:00
18338781771 81445a7096 Merge branch 'feature/merge' into develop 2025-12-04 18:10:16 +08:00
18338781771 1413a93d6d Merge branch 'feature/merge' into develop 2025-12-04 18:08:32 +08:00
18338781771 65f0be0a5d Merge branch 'feature/merge' into develop 2025-12-04 17:54:46 +08:00
18338781771 b65f8090cf Merge branch 'feature/merge' into develop 2025-12-04 15:06:43 +08:00
18338781771 5c1304e239 Merge branch 'feature/merge' into develop 2025-12-04 14:35:03 +08:00
44 changed files with 128 additions and 3363 deletions
+3 -87
View File
@@ -4,7 +4,6 @@ namespace app\admin\controller;
use app\common\controller\BaseController;
use app\common\model\Corp;
use app\common\model\User;
use app\common\service\OssService;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\InvItemService;
use support\Request;
@@ -41,8 +40,8 @@ class InvItemController extends BaseController
* @param array $data
* @return array
*/
protected function indexFormat($data)
{
protected function indexFormat($data)
{
if (isset($data['created_at']))
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
if (isset($data['updated_at']))
@@ -51,89 +50,6 @@ class InvItemController extends BaseController
$data['company_name'] = Corp::where('id', $data['company_id'])->value('name');
if (isset($data['manage_user_id']))
$data['manage_user_name'] = User::where('id', $data['manage_user_id'])->value('name');
if (!empty($data['qr_code']))
$data['qr_code_pull'] = (new OssService)->generatePrivateUrl($data['qr_code']);;
return $data;
}
/**
* 生成物品二维码
*
* @param Request $request
* @return mixed
*/
public function generateQrCode(Request $request)
{
try {
$id = $request->post('id');
$num = $request->post('num');
if (!$id) {
return $this->error('物品ID不能为空');
}
$item = \app\common\model\InvItem::find($id);
if (!$item) {
return $this->error('物品不存在');
}
// 获取应用访问地址
$appUrl = 'https://'.$request->host();
$qrCodeService = new \app\common\service\QrCodeService();
$content = $qrCodeService->generateItemQrCode($id, $appUrl);
$fileName = 'qr_item_' . $id . '_' . time() . '.png';
$result = $qrCodeService->generateAndUploadQrCode($id, $content, $fileName);
// 更新物品记录
$item->qr_code = $result['path'];
//$item->qr_code_num = !empty($num)?$num:0;
$item->qr_code_url = $result['url'];
$item->save();
return $this->success([
'qr_code_url' => $result['url'],
'content' => $content,
], '二维码生成成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 删除物品二维码
*
* @param Request $request
* @return mixed
*/
public function deleteQrCode(Request $request)
{
try {
$id = $request->post('id');
if (!$id) {
return $this->error('物品ID不能为空');
}
$item = \app\common\model\InvItem::find($id);
if (!$item) {
return $this->error('物品不存在');
}
// 删除 OSS 文件
if ($item->qr_code) {
$qrCodeService = new \app\common\service\QrCodeService();
$qrCodeService->deleteQrCode($item->qr_code);
}
// 清空物品记录中的二维码字段
$item->qr_code = '';
//$item->qr_code_num = 0;
$item->qr_code_url = '';
$item->save();
return $this->success([], '二维码删除成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
}
@@ -2,12 +2,8 @@
namespace app\admin\controller;
use app\common\controller\BaseController;
use app\common\model\InvRequisitionApprove;
use app\common\model\InvRequisitionAttachment;
use app\common\model\InvRequisitionItem;
use app\common\service\OssService;
use app\common\traits\crud\CrudControllerTrait;
use app\admin\service\InvRequisitionService;
use app\common\service\InvRequisitionService;
use support\Request;
class InvRequisitionController extends BaseController
@@ -21,160 +17,18 @@ class InvRequisitionController extends BaseController
$this->service = new InvRequisitionService();
}
/**
* 审核
*
* @param Request $request
* @return \support\Response
*/
public function approve(Request $request)
{
try {
$data = $this->service->serviceApprove($request);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 获取列表
*
* @param Request $request 请求对象
* @return mixed 返回分页数据及总数
*/
public function index(Request $request)
{
try {
$applicant_id = $request->get('applicant_id');
$uid = $request->user->uid;
$raw = $this->service->serviceList($request);
$data = $this->formatindex($raw,$applicant_id,$uid);
// $data = $this->transformData($raw, method_exists($this, 'indexFormat')
// ? [$this, 'indexFormat']
// : null);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function formatindex($p,$applicant_id,$uid){
$records = $p->getCollection()
->map(fn($item) => $this->indexFormat($item, $applicant_id,$uid))
->toArray();
return [
'records' => $records,
'total' => $p->total(),
'current' => $p->currentPage(),
'size' => $p->perPage(),
];
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function indexFormat($data, $applicant_id, $uid)
{
if (isset($data['id'])){
//$data['approve'] = InvRequisitionApprove::where('requisition_id', $data['id'])->get();
$data = $data->toArray();
}
if (isset($data['created_at'])){
$data['created_at'] = is_int($data['created_at'])?$data['created_at']:strtotime($data['created_at']);
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
}
if (isset($data['updated_at'])){
$data['updated_at'] = is_int($data['updated_at'])?$data['updated_at']:strtotime($data['updated_at']);
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
}
if (isset($data['id'])){
$data['item'] = InvRequisitionItem::where('requisition_id', $data['id'])->get();
}
if($applicant_id != 'self' && isset($data['id'])){ //不是查询自己数据时查询是否已审核
$approve = InvRequisitionApprove::where('requisition_id', $data['id'])
->where('approver_id', $uid)
->first();
$data['action'] = $approve['action']??3;//查询人审核状态:0待审核 1通过 2驳回 3非审核人
}
return $data;
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function showFormat($data)
{
if (isset($data['id'])){
$data['approve'] = InvRequisitionApprove::where('requisition_id', $data['id'])->orderBy('id')->get()->toArray();
$approve_id = 0;
foreach ($data['approve'] as $key => $value) {
if (isset($value['created_at'])){
$value['created_at'] = is_int($value['created_at'])?$value['created_at']:strtotime($value['created_at']);
$data['approve'][$key]['created_at'] = date('Y-m-d H:i:s', $value['created_at']);
}
if (isset($value['updated_at'])){
$value['updated_at'] = is_int($value['updated_at'])?$value['updated_at']:strtotime($value['updated_at']);
$data['approve'][$key]['updated_at'] = date('Y-m-d H:i:s', $value['updated_at']);
}
$data['approve'][$key]['action_at'] = date('Y-m-d H:i:s', $data['approve'][$key]['action_at']);
$approve_id = $value['id'];
}
$data['approve_id'] = $approve_id;
}
if (isset($data['created_at']))
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
if (isset($data['updated_at']))
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
if (isset($data['id'])){
$data['item'] = InvRequisitionItem::where('requisition_id', $data['id'])->get();
$data['attachment'] = InvRequisitionAttachment::where('requisition_id', $data['id'])->get();
$oss = new OssService();
foreach ($data['attachment'] as $key => $value) {
$data['attachment'][$key]['file_path_pull'] = $oss->generatePrivateUrl($value['file_path']);
}
}
return $data;
}
/**
* 管理员代领
*
* @param Request $request
* @return mixed
*/
public function proxyClaim(Request $request)
{
try {
$data = $this->service->proxyClaim($request, $request->post());
return $this->success($data, '代领成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 扫码/代领记录查询
*
* @param Request $request
* @return mixed
*/
public function qrClaims(Request $request)
{
try {
$data = $this->service->qrClaimsList($request);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
// protected function indexFormat($data)
// {
// if (isset($data['created_at']))
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
// if (isset($data['updated_at']))
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
// return $data;
// }
}
@@ -1,45 +0,0 @@
<?php
namespace app\admin\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\InvRequisitionReturnService;
use support\Request;
class InvRequisitionReturnController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new InvRequisitionReturnService();
}
// /**
// * 列表页数据格式化
// *
// * @param array $data
// * @return array
// */
// protected function indexFormat($data)
// {
// if (isset($data['created_at']))
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
// if (isset($data['updated_at']))
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
// return $data;
// }
public function returnConfirm(Request $request){
try {
// 处理申请逻辑
$result = $this->service->serviceReturnConfirm($request);
return $this->success($result, '申请提交成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
@@ -1,32 +0,0 @@
<?php
namespace app\admin\controller;
use app\common\controller\BaseController;
use app\common\service\InvStockLogService;
use support\Request;
class InvStockLogController extends BaseController
{
protected $service;
public function __construct()
{
$this->service = new InvStockLogService();
}
/**
* 库存变化记录列表
*
* @param Request $request
* @return mixed
*/
public function list(Request $request)
{
try {
$data = $this->service->getList($request->get());
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
+5 -106
View File
@@ -398,39 +398,21 @@ class BrandSeriesService
*/
public function crawlKeywordCreate(Request $request)
{
$brand_id = $request->input('brand_id');
$brand_name = $request->input('brand_name');
$brand_code = $request->input('brand_code');
$series_id = $request->input('series_id');
$brand_id = $request->input('brand_id');
$series_name = $request->input('series_name');
$models = $request->input('models');
if(empty($brand_id) && empty($brand_name)){
if(empty($brand_id)){
throw new \Exception("请选择品牌");
}
if(empty($series_id) && empty($series_name)){
throw new \Exception("请选择车系");
}
// 获取品牌信息
if (empty($brand_id)) {
$brand = Brand::where('id', $brand_id)->where('brand_name', $brand_name)->first();
if (empty($brand)) { //如果没有该车系则创建
$brandService = new \app\admin\service\BrandService();
$brandData = [
'brand_code' => $brandService->generateUniqueCode(),
'brand_name' => $brand_name,
];
$brand = CrudUtil::create(Brand::class, $brandData);
}
$brand_id = $brand->id;
}else{
$brand = Brand::where('id', $brand_id)->first();
}
if (empty($series_id)) {
$series = BrandSeries::where('brand_id', $brand_id)->where('series_name', $series_name)->first();
if (empty($series)) { //如果没有该车系则创建
if (empty($brandseries)) { //如果没有该车系则创建
$seriesService = new \app\admin\service\BrandSeriesService();
$seriesData = [
'brand_id' => $brand_id,
@@ -443,6 +425,8 @@ class BrandSeriesService
}else{
$series = BrandSeries::where('id', $series_id)->first();
}
// 获取品牌信息
$brand = Brand::where('id', $series->brand_id)->first();
// 保存车型数据
$createdCount = 0;
@@ -497,91 +481,6 @@ class BrandSeriesService
return $msg;
}
/**
* 抓取
*/
public function crawl(Request $request): array
{
$keyword = $request->get('keyword');
if(filter_var($keyword, FILTER_VALIDATE_URL)){
return $this->crawlUrl($request);
}else{
return $this->crawlKeyword($request);
}
}
/**
* 抓取车型数据(通过接口)
* @param Request $request
* @return array
* @throws \Exception
*/
public function crawlUrl(Request $request): array
{
//$url = $request->get('url');
$url = $request->get('keyword');
// 执行抓取
$crawlService = new CrawlService();
//懂车帝提取车系id
$seriesId = $this->get_series_from_url($url); //懂车帝车系id
if (empty($seriesId)) {
throw new \Exception('抓取失败,未找到该系列车型');
}
$brandSerieses = [];
//抓取品牌与系列
$brandSeries = $crawlService->crawlBrandSeries($seriesId);
$brandSerieses[] = ['brand' => $brandSeries['brand'], 'series' => $brandSeries['series']];
$result = [];
try {
foreach ($brandSerieses as $brandSeries) {
$item = [];
// 验证品牌是否存在
$brand = Brand::where('brand_name', $brandSeries['brand'])->first();
// 获取品牌信息
$series = BrandSeries::where('series_name', $brandSeries['series'])->first();
$item['brand'] = ['brand_name' => $brandSeries['brand'], 'exists' => $brand ? 1 : 0];
if ($brand) {
$item['brand']['id'] = $brand['id'];
}
$item['series'] = ['series_name' => $brandSeries['series'], 'exists' => $series ? 1 : 0];
if ($series) {
$item['series']['id'] = $series['id'];
if (empty($item['brand']['id'])) {
$item['brand']['id'] = $series['brand_id'];
}
}
//获取车型数据
$item['model'] = [];
if (count($brandSerieses)<2) {
$item['model'] = $this->crawlSeriesModel($seriesId);
}
$result[] = $item;
}
return ['is_series' => (count($brandSerieses)<2)?1:0, 'data' => $result];
} catch (\Exception $e) {
throw new \Exception($e->getMessage());
}
}
public function get_series_from_url($url) {
// 使用正则表达式匹配 "https://www.dongchedi.com/auto/series/{数字}"
$pattern = '/^https:\/\/www\.dongchedi\.com\/auto\/series\/(\d+)$/';
if (preg_match($pattern, $url, $matches)) {
// 提取数字部分作为 series ID
$series_id = $matches[1];
return $series_id; // 返回系列ID
} else {
throw new \Exception("URL格式不匹配");
}
}
/**
* 获取车系下车型数据
* @return array
-33
View File
@@ -151,37 +151,4 @@ class BrandService
$msg .= (!empty($fail))?',失败' . $fail . '条':'';
return $msg;
}
/**
* 生成唯一的7位颜色编码
* 格式:C + (O/I) + 5位字母数字组合
*
* @param int $type 类型
* @return string 7位唯一编码
*/
public function generateUniqueCode()
{
$chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$maxAttempts = 10; // 防止无限循环
for ($attempt = 0; $attempt < $maxAttempts; $attempt++) {
// 生成后5位随机字符
$suffix = '';
for ($i = 0; $i < 8; $i++) {
$suffix .= $chars[rand(0, strlen($chars) - 1)];
}
$code = $suffix;
// 检查是否已存在
$existing = Brand::where('brand_code', $code)->first();
if (!$existing) {
return $code;
}
}
// 如果1000次尝试后仍然重复,使用时间戳确保唯一性
$timestamp = substr(time(), -6);
return $suffix . $timestamp;
}
}
-120
View File
@@ -1,120 +0,0 @@
<?php
namespace app\admin\service;
use app\common\validate\InvRequisitionValidate;
use app\common\traits\crud\CrudServiceTrait;
use app\common\model\InvRequisition;
use support\Request;
class InvRequisitionService
{
use CrudServiceTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = InvRequisition::class;
/**
* 验证器
*/
protected $validator = InvRequisitionValidate::class;
/**
* 获取验证器
*/
public function getValidator()
{
return new $this->validator;
}
/**
* 构造 CrudUtil 查询配置
*/
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
{
$p = $request->all();
$config = [];
$config['model'] = $this->modelClass;
switch ($scene) {
case 'default':
//$config['where']['status'] = 1;
$config['order']['id'] = 'desc';
break;
case 'index':
if(isset($p['status']) && $p['status']){
$config['where']['status'] = $p['status'];
}
if (isset($p['applicant_id']) && $p['applicant_id'] == 'self') { //自己的领用申请
$config['where']['applicant_id'] = $request->user->uid;
} elseif (isset($p['applicant_id']) && $p['applicant_id']) { //指定人员的申请
$config['where']['applicant_id'] = $p['applicant_id'];
} else { //审批人对应的记录
$config['where']['approval.approver_id'] = $request->user->uid;
$config['where']['approval.action'] = 0;
}
if(isset($p['phase']) && $p['phase'] == 'approve'){//借用审批中
$config['where']['status'] = ['in',[10,11,13]];
}elseif(isset($p['phase']) && $p['phase'] == 'repaid'){//已全部归还
$config['where']['status'] = 17;
}elseif(isset($p['phase']) && $p['phase'] == 'unreturned'){ //未归还
$config['where']['status'] = ['in',[12,14,15,16,18]];
}
$config['order']['id'] = 'desc';
break;
case 'show':
$config['where']['id'] = $p['id'];
//$config['where']['status'] = 1;
break;
case 'store':
break;
case 'update':
$config['where']['id'] = $p['id'];
break;
case 'destroy':
$config['where']['id'] = $p['id'];
break;
}
return $config;
}
/**
* 审批
* @param Request $request
* @return mixed|string[]|null
*/
public function serviceApprove(Request $request)
{
$param = $request->all();
$attachment = $param['attachment']??[];
//$appro = new \app\common\utils\approval\service\ApprovalFlowService();
$appro = new \app\common\service\InvRequisitionApproveService();
//requisition_id:申请id
//approve_id:审核步骤id
//action:审批动作:1通过 2驳回
//comment:审批意见
return $appro->approve($param['requisition_id'], $param['approve_id'], $request->user->uid, $param['action'], $param['comment'], $attachment);
}
/**
* 管理员代领
* 调用 common 服务层方法
*/
public function proxyClaim(Request $request, array $data): array
{
return (new \app\common\service\InvRequisitionService())->proxyClaim($request, $data);
}
/**
* 扫码/代领记录查询
* 调用 common 服务层方法
*/
public function qrClaimsList(Request $request): array
{
return (new \app\common\service\InvRequisitionService())->qrClaimsList($request);
}
}
+1 -17
View File
@@ -4,7 +4,6 @@ namespace app\common\controller;
use app\common\service\AuthService;
use app\common\validate\UserValidate;
use Exception;
use support\Request;
class AuthController extends BaseController
@@ -32,7 +31,7 @@ class AuthController extends BaseController
public function feishuScope(Request $request)
{
try {
$is_mob = $request->get('is_mob', 0);
$is_mob = $request->get('is_mob',0);
$result = (new AuthService())->feishuAuthorize($request->corp_abbr, $request->system_code, $is_mob);
return $this->success($result);
} catch (\Throwable $e) {
@@ -114,19 +113,4 @@ class AuthController extends BaseController
// (new AuthService())->blockToken($token, $systemCode);
// return $this->success([], '已强制停用该token');
// }
public function getJsApi(Request $request)
{
try {
$url = $request->get('url');
if(empty($url)){
throw new Exception("url不能为空");
}
$result = (new AuthService())->getJsApiConfig($request->corp_abbr, $request->system_code,$url);
return $this->success($result);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
@@ -101,42 +101,6 @@ class BrandSeriesController extends BaseController
}
}
/**
* URL抓取品牌、车系、车型
* @param Request $request
* @return \support\Response
*/
public function crawlUrl(Request $request){
try {
$result = $this->service->crawlUrl($request);
if($result){
return $this->success($result,'抓取成功');
}else{
return $this->error('抓取任务失败');
}
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
/**
* 抓取品牌、车系、车型
* @param Request $request
* @return \support\Response
*/
public function crawl(Request $request){
try {
$result = $this->service->crawl($request);
if($result){
return $this->success($result,'抓取成功');
}else{
return $this->error('抓取任务失败');
}
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
/**
* 保存抓取的系列车型
* @param Request $request
@@ -2,14 +2,8 @@
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\model\InvItem;
use app\common\model\InvRequisitionItem;
use app\common\model\InvRequisitionItemReturn;
use app\common\model\InvRequisitionItemReturnAttachment;
use app\common\service\OssService;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\InvRequisitionItemReturnService;
use support\Request;
class InvRequisitionItemReturnController extends BaseController
{
@@ -22,160 +16,18 @@ class InvRequisitionItemReturnController extends BaseController
$this->service = new InvRequisitionItemReturnService();
}
/**
* 获取列表
*
* @param Request $request 请求对象
* @return mixed 返回分页数据及总数
*/
public function index(Request $request)
{
try {
//$request->setGet('$request');
$raw = $this->service->serviceList($request);
$data = $this->transformData($raw, method_exists($this, 'indexFormat')
? [$this, 'indexFormat']
: null);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function indexFormat($data)
{
if(isset($data['id'])){
$data['return_item'] = InvRequisitionItemReturn::where('return_id', $data['id'])->get();
foreach ($data['return_item'] as $key => $value) {
$data['return_item'][$key]['item'] = InvItem::where('id', $value['item_id'])->get();
}
}
if (isset($data['return_at']))
$data['return_at'] = date('Y-m-d H:i:s', $data['return_at']);
if (isset($data['created_at']))
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
if (isset($data['updated_at']))
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
return $data;
}
/**
* 获取详情
*
* @param Request $request 请求对象
* @param int|string $id 资源 ID
* @return mixed 返回资源详情数据
*/
public function show(Request $request)
{
try {
$raw = $this->service->serviceShow($request);
$data = $this->transformData($raw, method_exists($this, 'showFormat')
? [$this, 'showFormat']
: null);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function showFormat($data)
{
foreach ($data['item_return'] as $key => $item){
$data['item_return'][$key]['requisition_item'] = InvRequisitionItem::where('id', $item['requisition_item_id'])->first();
}
if (isset($data['return_at']))
$data['return_at'] = date('Y-m-d H:i:s', $data['return_at']);
if (isset($data['id'])){
//归还附件
$data['return_attachment'] = InvRequisitionItemReturnAttachment::where('return_id', $data['id'])->get();
$ossservice = new OssService();
foreach ($data['return_attachment'] as $item){
$item['file_path_pull'] = $ossservice->generatePrivateUrl($item['file_path']);
}
//归还审核附件
$data['return_approve_attachment'] = InvRequisitionItemReturnAttachment::where('return_id', $data['id'])->get();
foreach ($data['return_approve_attachment'] as $item){
$item['file_path_pull'] = $ossservice->generatePrivateUrl($item['file_path']);
}
}
/*if (isset($data['created_at']))
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
if (isset($data['updated_at']))
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);*/
return $data;
}
/**
* 更新
*
* @param Request $request 请求对象
* @return mixed 返回更新成功的数据或信息
*/
public function update(Request $request)
{
try {
$data = $this->validate($this->service->getValidator(), $request->post(), 'update');
$res = $this->service->serviceUpdate($request, $data);
return $this->success([], '更新成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 物品归还确认
*
* @param Request $request
* @return mixed
*/
public function returnItemConfirm(Request $request)
{
try {
// 验证申请数据
$data = $this->validate($this->service->getValidator(), $request->post(), 'returnConfirm');
// 处理申请逻辑
$result = $this->service->serviceReturnItemConfirm($request, $data, 'returnConfirm');
return $this->success($result, '申请提交成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 物品归还确认
*
* @param Request $request
* @return mixed
*/
public function returnConfirm(Request $request)
{
try {
// 验证申请数据
$data = $this->validate($this->service->getValidator(), $request->post(), 'returnConfirm');
// 处理申请逻辑
$result = $this->service->serviceReturnConfirm($request, $data, 'returnConfirm');
return $this->success($result, '申请提交成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
// protected function indexFormat($data)
// {
// if (isset($data['created_at']))
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
// if (isset($data['updated_at']))
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
// return $data;
// }
}
-211
View File
@@ -1,211 +0,0 @@
<?php
namespace app\common\controller;
use app\common\traits\ResponseTrait;
use support\Request;
use support\Response;
use app\common\utils\SystemAuth;
use app\common\utils\Jwt;
use app\common\model\User;
use app\common\model\Systems;
use support\Redis;
class SystemController
{
use ResponseTrait;
protected $noNeedLogin = ['auth'];
protected $noNeedHeaderData = ['auth'];
/**
* 系统间认证接口
* POST /api/system/auth
*/
public function auth(Request $request): Response
{
$userId = $request->post('user_id');
$timestamp = (int)$request->post('timestamp');
$signature = $request->post('signature');
$systemCode = $request->post('system_code');
// 参数验证
if (empty($userId) || empty($timestamp) || empty($signature)) {
return $this->error('参数不完整', 400);
}
// 获取配置
$secret = config('system_auth.shared_secret');
$expire = config('system_auth.signature_expire', 600);
// 验证时间戳(10分钟有效期)
if (!SystemAuth::verifyTimestamp($timestamp, $expire)) {
return $this->error('请求已过期', 401);
}
// 验证签名
if (!SystemAuth::verifySignature($userId, $timestamp, $signature, $secret)) {
return $this->error('签名验证失败', 401);
}
// 查找用户
$user = User::find($userId);
if (!$user) {
return $this->error('用户不存在', 404);
}
// 验证系统(如果提供了 system_code)
$system = null;
if ($systemCode) {
$system = Systems::where('code', $systemCode)->first();
if (!$system) {
return $this->error('系统不存在', 404);
}
}
// 获取 corp_abbr(优先从请求参数获取,否则通过用户 corp_id 查询)
$corpAbbr = $request->post('corp_abbr');
if (!$corpAbbr && $user->corp_id) {
$corp = \app\common\model\Corp::find($user->corp_id);
$corpAbbr = $corp ? $corp->abbr : '';
}
// 构建 JWT payload
$payload = $this->buildJwtPayload($user, $system);
// 生成 access_token
$jwt = new Jwt();
$token = $jwt->generateToken($payload);
// 生成 refresh_token
$refreshToken = $this->generateRefreshToken($user->id, $systemCode ?? '');
// 获取 home_url
$homeUrl = $system ? $this->getHome($system->id, $payload) : '';
// 记录 token 到 Redis 和 MySQL
$this->recordUserToken($user->id, $token, $systemCode ?? '');
// 构建用户信息(去除敏感信息)
$userInfo = [
'id' => $user->id,
'sn' => $user->sn ?? '',
'name' => $user->name ?? '',
'avatar' => $user->avatar ?? '',
'phone' => $user->phone ?? '',
'email' => $user->email ?? '',
'sex' => $user->sex ?? '',
'position' => $user->position ?? '',
'status' => $user->status ?? 1,
'corp_id' => $user->corp_id,
];
return $this->success([
'access_token' => $token,
'refresh_token' => $refreshToken,
'expires_in' => config('jwt.jwt_expiration'),
'system_code' => $systemCode ?? '',
'corp_abbr' => $corpAbbr ?? '',
'login_type' => 'system',
'home_url' => $homeUrl,
'user_info' => $userInfo,
], '认证成功');
}
/**
* 构建 JWT payload
*/
private function buildJwtPayload(User $user, ?Systems $system): array
{
$now = time();
$exp = $now + config('jwt.jwt_expiration');
$system_ids = $user->systems ? $user->systems->pluck('id')->toArray() : [];
$role_ids = $user->roles ? $user->roles->pluck('id')->toArray() : [];
$payload = [
'sub' => 'user_' . $user->id,
'aud' => $system->code,
'iat' => $now,
'exp' => $exp,
'nbf' => $now,
'typ' => 'access',
'uid' => $user->id,
'uname' => $user->name,
'role_ids' => $role_ids,
'system_ids' => $system_ids,
// 'user_id' => $user->id,
// 'sn' => $user->sn ?? '',
// 'name' => $user->name ?? '',
];
if ($system) {
$payload['system_code'] = $system->code;
$payload['system_id'] = $system->id;
}
return $payload;
}
/**
* 生成 refresh_token
*/
private function generateRefreshToken(int $userId, string $systemCode): string
{
$refreshToken = bin2hex(random_bytes(32));
// 存储到 Redis
$key = "refresh_token:{$refreshToken}";
$expire = config('jwt.jwt_refresh_token_expiration');
Redis::setex($key, $expire, json_encode([
'user_id' => $userId,
'system_code' => $systemCode,
]));
return $refreshToken;
}
/**
* 获取用户首页地址
*/
private function getHome(int $systemId, array $payload): string
{
// 简单实现,可以根据实际需求调整
return '';
}
/**
* 记录用户token到 Redis 和 MySQL
*/
private function recordUserToken(int $userId, string $token, string $systemCode): void
{
$request = request();
$ip = $request ? $request->getRealIp() : '';
$ua = $request ? $request->header('user-agent', '') : '';
$now = time();
$expireAt = $now + config('jwt.jwt_expiration');
// Redis Set 用户token集合
Redis::sAdd("user_tokens:{$userId}:{$systemCode}", $token);
Redis::expire("user_tokens:{$userId}:{$systemCode}", config('jwt.jwt_expiration'));
// Redis Hash token元信息
$meta = [
'system_code' => $systemCode,
'login_ip' => $ip,
'user_agent' => $ua,
'login_time' => $now,
'expired_at' => $expireAt,
];
Redis::hMSet("user_token_meta:{$token}", $meta);
Redis::expire("user_token_meta:{$token}", config('jwt.jwt_expiration'));
// MySQL 持久化
\app\common\model\UserTokenLog::create([
'user_id' => $userId,
'token' => $token,
'system_code' => $systemCode,
'login_ip' => $ip,
'user_agent' => $ua,
'expired_at' => $expireAt,
]);
}
}
+2 -3
View File
@@ -40,9 +40,8 @@ class InvItem extends Model
/**
* 允许自动填充模型字段
*/
protected $fillable = ['id', 'company_id', 'item_code', 'item_name',
'category_id', 'spec_model', 'unit', 'is_consumable', 'allow_qr_claim', 'qr_code', 'qr_code_num', 'qr_code_url',
'stock_qty', 'manage_user_id', 'location', 'remark',
protected $fillable = ['id', 'company_id', 'item_code', 'item_name',
'category_id', 'spec_model', 'unit', 'is_consumable', 'stock_qty', 'manage_user_id', 'location', 'remark',
'sort', 'status',
'created_at', 'updated_at'];
+7 -30
View File
@@ -40,42 +40,19 @@ class InvRequisition extends Model
/**
* 允许自动填充模型字段
*/
protected $fillable = ['id', 'order_no', 'applicant_company_id', 'dept_id', 'applicant_id', 'applicant_name', 'leader_id', 'manager_id', 'borrow_reason', 'use_start_date', 'use_end_date', 'status', 'claim_type', 'qr_claim_time', 'proxy_claim_user_id', 'proxy_claim_user_name', 'is_returned', 'remark', 'created_at', 'updated_at'];
protected $fillable = ['id', 'order_no', 'applicant_company_id', 'dept_id', 'applicant_id', 'applicant_name', 'leader_id', 'manager_id', 'borrow_reason', 'use_start_date', 'use_end_date', 'status', 'is_returned', 'remark', 'created_at', 'updated_at'];
/**
* 不允许自动填充模型字段
*/
protected $guarded = [];
// 领取方式常量
const CLAIM_TYPE_NORMAL = 1; // 正常申请
const CLAIM_TYPE_QR = 2; // 扫码领取
const CLAIM_TYPE_PROXY = 3; // 管理员代领
/**
* 领取方式文本
*/
public static function getClaimTypeText($type)
{
return [
self::CLAIM_TYPE_NORMAL => '正常申请',
self::CLAIM_TYPE_QR => '扫码领取',
self::CLAIM_TYPE_PROXY => '管理员代领',
][$type] ?? '未知';
}
const STATUS_DRAFT = 0; // 草稿
const STATUS_LEADER = 10; // 待直属上级审批
const STATUS_MANAGE = 20; // 待管理员审批
const STATUS_APPROVED = 30; // 已通过
const STATUS_REJECTEDT = 40; // 已驳回
const STATUS_CANCELED = 50; // 已取消
public function approval()
{
return $this->hasMany('app\common\model\InvRequisitionApprove',
'requisition_id', 'id');
}
/**
* 领用明细关联
*/
public function items()
{
return $this->hasMany('app\common\model\InvRequisitionItem',
'requisition_id', 'id');
}
}
@@ -46,10 +46,4 @@ class InvRequisitionApprove extends Model
* 不允许自动填充模型字段
*/
protected $guarded = [];
public function requisition()
{
return $this->belongsTo('app\common\model\InvRequisition',
'requisition_id','id');
}
}
@@ -1,49 +0,0 @@
<?php
namespace app\common\model;
use support\Model;
class InvRequisitionApproveAttachment extends Model
{
/**
* The connection name for the model.
*
* @var string|null
*/
protected $connection = 'mysql';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'inv_requisition_approve_attachment';
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = true;
protected $dateFormat = 'U';
/**
* 允许自动填充模型字段
*/
protected $fillable = ['id', 'requisition_id', 'approve_id', 'file_name', 'file_path', 'file_size', 'created_at', 'updated_at'];
/**
* 不允许自动填充模型字段
*/
protected $guarded = [];
}
-8
View File
@@ -46,12 +46,4 @@ class InvRequisitionItem extends Model
* 不允许自动填充模型字段
*/
protected $guarded = [];
/**
* 关联领用申请主表
*/
public function requisition()
{
return $this->belongsTo('app\common\model\InvRequisition', 'requisition_id', 'id');
}
}
@@ -40,7 +40,7 @@ class InvRequisitionItemReturn extends Model
/**
* 允许自动填充模型字段
*/
protected $fillable = ['id', 'return_id', 'requisition_id', 'requisition_item_id', 'item_id', 'apply_user_id', 'apply_user_name', 'return_qty', 'status', 'handler_id', 'handler_name', 'return_status', 'apply_remark', 'handle_remark', 'return_at', 'created_at', 'updated_at'];
protected $fillable = ['id', 'requisition_id', 'requisition_item_id', 'item_id', 'apply_user_id', 'apply_user_name', 'return_qty', 'status', 'handler_id', 'handler_name', 'return_status', 'apply_remark', 'handle_remark', 'return_at', 'created_at', 'updated_at'];
/**
* 不允许自动填充模型字段
@@ -1,49 +0,0 @@
<?php
namespace app\common\model;
use support\Model;
class InvRequisitionReturnApproveAttachment extends Model
{
/**
* The connection name for the model.
*
* @var string|null
*/
protected $connection = 'mysql';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'inv_requisition_return_approve_attachment';
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = true;
protected $dateFormat = 'U';
/**
* 允许自动填充模型字段
*/
protected $fillable = [];
/**
* 不允许自动填充模型字段
*/
protected $guarded = [];
}
-88
View File
@@ -1,88 +0,0 @@
<?php
namespace app\common\model;
use support\Model;
/**
* 物品库存变化记录模型
*/
class InvStockLog extends Model
{
protected $table = 'inv_stock_log';
protected $fillable = [
'company_id',
'item_id',
'item_name_snap',
'change_type',
'change_qty',
'before_qty',
'after_qty',
'biz_type',
'biz_no',
'operator_id',
'operator_name',
'remark',
'updated_at',
'created_at',
];
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = true;
protected $dateFormat = 'U';
public const CHANGE_TYPE_IN = 1; // 入库
public const CHANGE_TYPE_OUT_CLAIM = 2; // 出库(领用)
public const CHANGE_TYPE_OUT_LOSS = 3; // 出库(损耗)
public const CHANGE_TYPE_IN_RETURN = 4; // 入库(归还)
public const BIZ_TYPE_PURCHASE = 1; // 采购入库
public const BIZ_TYPE_QR_CLAIM = 2; // 扫码领取
public const BIZ_TYPE_PROXY_CLAIM = 3; // 管理员代领
public const BIZ_TYPE_NORMAL_CLAIM = 4; // 正常领用(审批后)
public const BIZ_TYPE_RETURN = 5; // 归还入库
public const BIZ_TYPE_LOSS = 6; // 损耗出库
/**
* 变动类型文本
*/
public static function getChangeTypeText($type)
{
return [
self::CHANGE_TYPE_IN => '入库',
self::CHANGE_TYPE_OUT_CLAIM => '出库(领用)',
self::CHANGE_TYPE_OUT_LOSS => '出库(损耗)',
self::CHANGE_TYPE_IN_RETURN => '入库(归还)',
][$type] ?? '未知';
}
/**
* 业务类型文本
*/
public static function getBizTypeText($type)
{
return [
self::BIZ_TYPE_PURCHASE => '采购入库',
self::BIZ_TYPE_QR_CLAIM => '扫码领取',
self::BIZ_TYPE_PROXY_CLAIM => '管理员代领',
self::BIZ_TYPE_NORMAL_CLAIM => '正常领用',
self::BIZ_TYPE_RETURN => '归还入库',
self::BIZ_TYPE_LOSS => '损耗出库',
][$type] ?? '未知';
}
/**
* 关联物品
*/
public function item()
{
return $this->belongsTo(InvItem::class, 'item_id', 'id');
}
}
-16
View File
@@ -86,20 +86,4 @@ class AuthService
{
(new AuthLogic())->blockToken($token, $systemCode);
}
/**
* 获取jsapi配置
* @param string $corpAbbr
* @param string $systemCcode
* @param string $url 当前页面完整 URL(不包含 # 后面的内容)
* @return array
*/
public function getJsApiConfig(string $corpAbbr, string $systemCcode, string $url)
{
$logic = new AuthLogic();
$certificate = $logic->feishuAppInfo($corpAbbr, $systemCcode);
$feishu = new Feishu($certificate['app_id'], $certificate['app_secret'], $certificate['abbr']);
$jsApi = $feishu->getJsApiConfig($url);
return $jsApi;
}
}
+11 -132
View File
@@ -3,11 +3,9 @@
namespace app\common\service;
use app\common\logic\InvItemLogic;
use app\common\model\User;
use app\common\validate\InvItemValidate;
use app\common\traits\crud\CrudServiceTrait;
use app\common\model\InvItem;
use support\Redis;
use support\Request;
use support\exception\BusinessException;
@@ -113,55 +111,12 @@ class InvItemService
$data['category_id'] = 0;
$data['spec_model'] = '';
$data['unit'] = '件';
$data['is_consumable'] = 0;
$data['stock_qty'] = $data['stock_qty']??1;
$data['location'] = '';
Redis::set('inv_store_u_stock', $request->user->uid, 'EX', 30);
return $data;
}
public function afterServiceStore($res)
{
$uid = redis::get('inv_store_u_stock');
$name = $uid ? User::where('id', $uid)->value('name') : '';
Redis::del('inv_store_u_stock');
// 记录库存变化日志
$this->recordStockLog([
'item_id' => $res['id'],
'item_name_snap' => $res['item_name'],
'change_qty' => $res['stock_qty'],
'before_qty' => 0,
'after_qty' => $res['stock_qty'],
'biz_type' => 1,
'biz_no' => '',
'operator_id' => $uid,
'operator_name' => $name,
'remark' => '初始数量',
], $res['stock_qty']);
}
public function beforeServiceUpdate($data, Request $request)
{
$uid = $request->user->uid;
$name = $uid ? User::where('id', $uid)->value('name') : '';
$item = InvItem::where('id', $data['id'])->first();
$change_qty = $data['stock_qty'] - $item['stock_qty'];
// 记录库存变化日志
$this->recordStockLog([
'item_id' => $data['id'],
'item_name_snap' => $data['item_name'],
'change_qty' => $change_qty,
'before_qty' => $item['stock_qty'],
'after_qty' => $data['stock_qty'],
'biz_type' => 1,
'biz_no' => '',
'operator_id' => $uid,
'operator_name' => $name,
'remark' => '管理员修改数量',
], $change_qty);
return $data;
}
/**
* 变动物品库存数量
@@ -169,29 +124,16 @@ class InvItemService
* @param int $itemId 物品ID
* @param int $changeQty 变动数量:>0 入库,<0 出库
* @param bool $allowNegative 是否允许库存变成负数,默认不允许
* @param array $options 额外选项(用于记录日志)
* - change_type: 变动类型
* - biz_type: 业务类型
* - biz_no: 单据号
* - operator_id: 操作人ID
* - operator_name: 操作人姓名
* - remark: 备注
*
* @return InvItem 最新的物品记录
* @throws BusinessException
*/
public function changeStock(int $itemId, int $changeQty, bool $allowNegative = false, array $options = []): InvItem
public function changeStock(int $itemId, int $changeQty, bool $allowNegative = false): InvItem
{
if ($changeQty === 0) {
throw new BusinessException('库存变动数量不能为 0');
}
// 获取变动前的库存(用于日志)
$itemBefore = InvItem::query()->find($itemId);
if (!$itemBefore) {
throw new BusinessException('物品不存在');
}
$beforeQty = $itemBefore->stock_qty;
$now = time();
// 构建查询
@@ -212,102 +154,39 @@ class InvItemService
// 更新不到行:
// 1) 物品不存在
// 2) 或者库存不足(不允许负数时)
$exists = InvItem::query()->where('id', $itemId)->exists();
if (! $exists) {
throw new BusinessException('物品不存在');
}
throw new BusinessException('库存不足,无法完成库存变动');
}
// 再查一次最新数据返回(在外层事务中也会保持一致)
/** @var InvItem $item */
$item = InvItem::query()->find($itemId);
// 记录库存变化日志
$this->recordStockLog([
'item_id' => $itemId,
'item_name_snap' => $item->item_name,
'change_qty' => $changeQty,
'before_qty' => $beforeQty,
'after_qty' => $item->stock_qty,
'change_type' => $options['change_type'] ?? null,
'biz_type' => $options['biz_type'] ?? null,
'biz_no' => $options['biz_no'] ?? null,
'operator_id' => $options['operator_id'] ?? null,
'operator_name' => $options['operator_name'] ?? null,
'remark' => $options['remark'] ?? null,
], $changeQty);
return $item;
}
/**
* 出库(减库存,默认不允许负数)
*
* @param int $itemId 物品ID
* @param int $qty 出库数量
* @param bool $allowNegative 是否允许负数
* @param array $options 日志选项(同 changeStock)
* @return InvItem
* @throws BusinessException
*/
public function stockOut(int $itemId, int $qty, bool $allowNegative = false, array $options = []): InvItem
public function stockOut(int $itemId, int $qty, bool $allowNegative = false): InvItem
{
if ($qty <= 0) {
throw new BusinessException('出库数量必须大于 0');
}
// 确定变动类型:2-出库(领用)或 3-出库(损耗)
$changeType = $options['change_type'] ?? \app\common\model\InvStockLog::CHANGE_TYPE_OUT_CLAIM;
return $this->changeStock($itemId, -$qty, $allowNegative, array_merge($options, [
'change_type' => $changeType,
'remark' => $options['remark'] ?? '领用出库',
]));
return $this->changeStock($itemId, -$qty, $allowNegative);
}
/**
* 入库(加库存)
*
* @param int $itemId 物品ID
* @param int $qty 入库数量
* @param array $options 日志选项(同 changeStock)
* @return InvItem
* @throws BusinessException
*/
public function stockIn(int $itemId, int $qty, array $options = []): InvItem
public function stockIn(int $itemId, int $qty): InvItem
{
if ($qty <= 0) {
throw new BusinessException('入库数量必须大于 0');
}
// 确定变动类型:1-入库 或 4-入库(归还)
$changeType = $options['change_type'] ?? \app\common\model\InvStockLog::CHANGE_TYPE_IN;
return $this->changeStock($itemId, $qty, true, array_merge($options, [
'change_type' => $changeType,
'remark' => $options['remark'] ?? '入库',
]));
}
/**
* 记录库存变化日志
*
* @param array $logData
* @param int $changeQty 变动数量
* @return void
*/
private function recordStockLog(array $logData, int $changeQty): void
{
try {
// 根据变动数量确定变动类型(如果未指定)
if (!isset($logData['change_type'])) {
if ($changeQty > 0) {
$logData['change_type'] = \app\common\model\InvStockLog::CHANGE_TYPE_IN;
} else {
$logData['change_type'] = \app\common\model\InvStockLog::CHANGE_TYPE_OUT_CLAIM;
}
}
(new InvStockLogService())->record($logData);
} catch (\Throwable $e) {
// 日志记录失败不影响主业务,仅记录错误
error_log('库存日志记录失败: ' . $e->getMessage());
}
return $this->changeStock($itemId, $qty, true);
}
/**
@@ -2,13 +2,9 @@
namespace app\common\service;
use app\common\model\InvItem;
use app\common\model\User;
use app\common\validate\InvRequisitionApproveValidate;
use app\common\traits\crud\CrudServiceTrait;
use app\common\model\InvRequisitionApprove;
use support\Db;
use support\exception\BusinessException;
class InvRequisitionApproveService
{
@@ -33,239 +29,5 @@ class InvRequisitionApproveService
return new $this->validator;
}
/**
* @param string $flowType
* @param string $bizType
* @param string $bizId
* @param array $formData ['manage_user_id'=>23]//物品管理员
* @param int $initiatorId //申请人id
* @return array
*/
public function start(string $flowType, string $bizType, string $bizId, array $formData, int $initiatorId): array
{
return Db::transaction(function () use ($flowType, $bizType, $bizId, $formData, $initiatorId) {
$flow = Db::table('approval_flows')->where('type', $flowType)->where('is_active', 1)->first();
if (!$flow) throw new BusinessException("审批流程未找到或已停用: {$flowType}");
$steps = json_decode($flow->steps, true);
if (!is_array($steps) || empty($steps)) throw new BusinessException("流程步骤配置错误");
// 找首个有效步骤索引(考虑条件)
$firstIndex = $this->getNextStepIndex($steps, $formData, -1);
if ($firstIndex === null) throw new BusinessException("未找到可执行的审批步骤");
$firstStep = $steps[$firstIndex];
//$now = date('Y-m-d H:i:s');
$now = time();
$service = new \app\common\utils\approval\service\ApprovalFlowService();
// 解析首步审批人(支持 role_id 或 roles.name)
$instance = (object)[
'initiator_id' => $initiatorId,
'form_data'=>json_encode($formData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
];
$approverIds = $service->StetApprovers($firstStep, $instance, true);
if(empty($approverIds)){
throw new BusinessException('未解析到任何审批人');
}
$uid = array_shift($approverIds);
$approver = User::where('id', $uid)->first();
$approveId = Db::table('inv_requisition_approve')->insertGetId([
'requisition_id' => $bizId, //申请单ID
'node_type' => $bizType,
'approver_id' => $approver->id,
'approver_name' => $approver->name,
'action' => 0,
'comment' => '',
'created_at' => $now,
'updated_at' => $now,
]);
// foreach ($approverIds as $uid) {
// $this->insertApprovalRecord($instance, $firstIndex, $uid);
// }
return ['instance_id' => $approveId];
});
}
/** 执行审批 */
public function approve(int $requisitionId, int $approverId, int $uid, string $action, string $comment = '', array $attachment = [])
{
if (!in_array($action, ['1','2'], true)) { //审批动作:1通过 2驳回
throw new BusinessException("无效的审批操作");
}
return Db::transaction(function () use ($requisitionId, $approverId, $uid, $action, $comment, $attachment) {
// $instance = Db::table('approval_instances')->where('id', $instanceId)->lockForUpdate()->first();
$requisition = Db::table('inv_requisition')->where('id', $requisitionId)->lockForUpdate()->first();
if (!$requisition) throw new BusinessException("审批实例未找到");
if ($requisition->status !== 10 && $requisition->status !== 11) {
return ['status' => 'noop', 'msg' => '实例未处理'];
}
//审批流程
$flow = Db::table('approval_flows')->where('type', 'inv_requisition')->first();
if (!$flow) throw new BusinessException("审批流程定义未找到");
$steps = json_decode($flow->steps, true);
//$idx = (int)$requisition->current_step;
//$step = $steps[$idx] ?? null;
//if (!$step) throw new BusinessException("当前步骤配置错误");
// 找到该用户在本步的 pending 记录(加锁)
$pendingRecord = Db::table('inv_requisition_approve')
->where('requisition_id', $requisitionId)
->where('id', $approverId)
->where('action', 0)
->lockForUpdate()
->first();
if (!$pendingRecord) {
// 已处理过?
$anyRecord = Db::table('inv_requisition_approve')
->where('requisition_id', $requisitionId)
->where('id', $approverId)
->first();
if ($anyRecord && $anyRecord->action > 0) {
return ['status' => 'noop', 'msg' => '已处理'];
}
// 步骤已推进
// if ((int)$requisition->current_step !== $idx) {
// return ['status' => 'noop', 'msg' => '非当前审批'];
// }
return ['status' => 'noop', 'msg' => '无待处理记录'];
} else if ($pendingRecord->approver_id != $uid) { //检查当前用户是否为审核人
return ['status' => 'noop', 'msg' => '无审核权限'];
}
$now = time();
// 1) 更新当前人的审批记录
Db::table('inv_requisition_approve')->where('id', $pendingRecord->id)->update([
'action' => $action,
'comment' => $comment,
'action_at' => $now,
'updated_at' => $now,
]);
foreach ($attachment as $attac) {
Db::table('inv_requisition_approve_attachment')->insertGetId([
'requisition_id' => $requisitionId,
'approve_id' => $approverId,
'file_name' => $attac['original_name'],
'file_path' => $attac['file_path'],
'created_at' => $now,
]);
}
// 2) 已通过步骤与总步数相等则结束审核流程
$pass = Db::table('inv_requisition_approve')
->where('requisition_id', $requisitionId)
->where('action', 1)
->count();
if($action == 1){
if(count($steps) == $pass){
//判断是否都是消耗品,是否需要归还
$requisitionItem = Db::table('inv_requisition_item')
->where('requisition_id', $requisition->id)
->where('is_consumable_snap', 0)
->get();
if($requisitionItem){
Db::table('inv_requisition')->where('id', $requisition->id)->update(['status'=>12]);
}else{
Db::table('inv_requisition')->where('id', $requisition->id)->update(['status'=>19]);
}
//更改库存
$requisitionItem = Db::table('inv_requisition_item')
->where('requisition_id', $requisition->id)
->get();
foreach ($requisitionItem as $item) {
//$invItem = InvItem::where('id', $item->item_id)->first();
(new InvItemService())->stockOut($item->item_id,$item->approved_qty);
}
// $requisition->status = 12;
// $requisition->save();
return ['status' => 'complete', 'msg' => '已通过'];
}
}
// 3) 拒绝 => 结束
if($action == 2){
Db::table('inv_requisition_approve')->where('id', $pendingRecord->id)->update([
'action' => $action,
'comment' => $comment,
'approved_at' => $now,
'updated_at' => $now,
]);
//if(count($steps) == $pass){
Db::table('inv_requisition')->where('id', $requisition->id)->update(['status'=>13]);
return ['status' => 'complete', 'msg' => '拒绝'];
//}
}
// 4) 通过 => 进入下一步
Db::table('inv_requisition')->where('id', $requisitionId)->update(['status'=>11]);
$requisitionItem = Db::table('inv_requisition_item')->where('requisition_id', $requisitionId)->first();
$item_id = Db::table('inv_item')->where('id', $requisitionItem->item_id)->first();
$formData = ['manage_user_id'=>$item_id->manage_user_id];
$nextIndex = $pass;
$nextStep = $steps[$nextIndex];
$service = new \app\common\utils\approval\service\ApprovalFlowService();
$instance = (object)[
'initiator_id' => $requisition->applicant_id, //申请人id
'form_data'=>json_encode($formData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
];
$approverIds = $service->StetApprovers($nextStep, $instance, true);
// if($approverIds == "manage_user_id"){ //物品管理人审核步骤查询管理人
// $requisitionItem = Db::table('inv_requisition_item')->where('id', $requisitionId)->first();
// $invItem = Db::table('inv_requisition_item')->where('id', $requisitionItem->item_id)->first();
//
// if(empty($invItem)){
// return ['status' => 'noop', 'msg' => '未查询到物品管理人'];
// }
// $approverIds = [$invItem->manage_user_id];
// }
$approver = User::where('id', array_pop($approverIds))->first();
Db::table('inv_requisition_approve')->insertGetId([
'requisition_id' => $requisitionId, //申请单ID
'node_type' => $nextStep['approvers'][0]['value'],
'approver_id' => $approver->id,
'approver_name' => $approver->name,
'action' => 0,
'comment' => '',
'created_at' => $now,
'updated_at' => $now,
]);;
return ['status' => 'complete', 'msg' => '已通过'];
});
}
// public function insertApprovalRecord()
// {
// }
/** 获取下一个有效步骤索引 */
private function getNextStepIndex(array $steps, array $formData, int $currentStepIndex): ?int
{
for ($i = $currentStepIndex + 1; $i < count($steps); $i++) {
$s = $steps[$i];
if (empty($s['condition'])) {
return $i;
}
}
return null;
}
}
@@ -2,19 +2,16 @@
namespace app\common\service;
use app\common\model\InvItem;
use app\common\model\InvRequisition;
use app\common\model\InvRequisitionItem;
use app\common\model\InvRequisitionReturn;
use app\common\model\InvStockLog;
use app\common\model\User;
use app\common\service\UserService;
use app\common\validate\InvRequisitionItemReturnValidate;
use app\common\traits\crud\CrudServiceTrait;
use app\common\model\InvRequisitionItemReturn;
use support\Request;
use support\Db;
use support\exception\BusinessException;
use app\common\service\UserService;
use Illuminate\Database\Eloquent\Model;
use app\common\model\InvRequisitionItemReturnAttachment;
use function Symfony\Component\String\u;
@@ -122,16 +119,14 @@ class InvRequisitionItemReturnService
$data['applicant_id'] = $user['user']['id'];
$data['applicant_name'] = $user['user']['name'];
//$reqItemId = $data['requisition_id'];
$reqItemId = $data['requisition_id'];
$arr = [];
foreach ($reqItemsArr as $reqItem) {
$reqItemId = $reqItem['id'];
// 检查是否有对应的新申请项数据
if (!isset($newReqItems[$reqItemId])) {
continue;
}
$item = InvItem::where('id', $reqItem['item_id'])->first();
$manage = User::where('id',$item['manage_user_id'])->first();
$arr[] = [
'requisition_id' => $data['requisition_id'],
@@ -140,15 +135,11 @@ class InvRequisitionItemReturnService
'apply_user_id' => $user['user']['id'],
'apply_user_name' => $user['user']['name'],
'return_qty' => $newReqItems[$reqItemId]['return_qty'] ?: '1',
'apply_remark' => $data['apply_remark'] ?? '',
'handler_id' => $item['manage_user_id'] ?? 0,
'handler_name' => $manage['name'] ?? '',
'apply_remark' => $newReqItems[$reqItemId]['apply_remark'] ?? '',
//'attachment' => $newReqItems[$reqItemId]['attachment'],
//'return_at' => time(),
'return_at' => $data['return_at'],
];
$data['handler_id'] = $item['manage_user_id'] ?? 0;
$data['handler_name'] = $manage['name'] ?? '';
}
$data['items'] =$arr;
@@ -184,18 +175,10 @@ class InvRequisitionItemReturnService
$created = [];
foreach ($items as $item) {
//$created = $this->logicCreate($item, $dl);
$item['return_id'] = $res->id;
$item['requisition_id'] = $data['requisition_id'];
$item['return_at'] = $data['return_at'];
$item['apply_remark'] = $data['apply_remark'];
$created = $this->logicCreate($item);
}
$this->processRequisitionItemReturnAttachment($res, $attachment);
InvRequisition::where('id',$request->post('requisition_id'))->update(
['status' => 14] //审批状态:10默认、11审批中、12已审批(待归还)、13拒绝、14申请归还、15归还审核中、16部分归还、17已全部归还、18已拒绝、19已审批(无需归还)
);
$this->postProcess('Store', $created);
return $res;
return $this->postProcess('Store', $created);
});
} catch (\Throwable $e) {
throw new BusinessException("创建物品申请失败:" . $e->getMessage().$e->getTraceAsString());
@@ -233,72 +216,9 @@ class InvRequisitionItemReturnService
// ]
// ]
// ];
try {
$approved = InvRequisitionItemReturn::where('return_id',$data['id'])
->where('status','>',0)
->count();
if ($approved > 0) {
throw new BusinessException('已审核禁止编辑');
}
// 获取所有申请项ID
$reqItemIds = array_column($data['items'], 'requisition_item_id');
// 参数校验
if (empty($reqItemIds)) {
throw new BusinessException('未提供有效的申请项ID');
}
// 将申请项按 ID 重组为关联数组
$newReqItems = $this->groupArrayByKey($data['items'], 'requisition_item_id');
$data['return_at'] = is_int($data['return_at']) ? $data['return_at']: strtotime($data['return_at']);
// 获取申请项明细
$reqItemsArr = InvRequisitionItem::whereIn('id', $reqItemIds)->get()->toArray();
// 检查是否获取到有效数据
if (empty($reqItemsArr)) {
throw new BusinessException('未找到对应的申请项');
}
// 获取用户信息
$userService = new UserService();
$user = $userService->getUserInfo($request->user->uid, '');
$data['applicant_id'] = $user['user']['id'];
$data['applicant_name'] = $user['user']['name'];
//$reqItemId = $data['requisition_id'];
$arr = [];
foreach ($reqItemsArr as $reqItem) {
$reqItemId = $reqItem['id'];
// 检查是否有对应的新申请项数据
if (!isset($newReqItems[$reqItemId])) {
continue;
}
$arr[] = [
'requisition_id' => $data['requisition_id'],
'requisition_item_id' => $reqItem['id'],
'item_id' => $reqItem['item_id'],
'apply_user_id' => $user['user']['id'],
'apply_user_name' => $user['user']['name'],
'return_qty' => $newReqItems[$reqItemId]['return_qty'] ?: '1',
'apply_remark' => $data['apply_remark'] ?? '',
//'attachment' => $newReqItems[$reqItemId]['attachment'],
//'return_at' => time(),
'return_at' => $data['return_at'],
];
}
$data['items'] =$arr;
return $data;
} catch (BusinessException $e) {
throw $e;
} catch (\Throwable $th) {
throw new BusinessException('创建物品归还申请失败:' . $th->getMessage());
}
$data['return_at'] = time();
return $data;
}
/**
@@ -314,37 +234,20 @@ class InvRequisitionItemReturnService
// 关联表增加事务处理
return Db::transaction(function () use ($request, $data) {
$data = $this->preProcess('Update', $data, $request);
//$config = $this->buildQueryConfig($request, 'update');
$config = $this->buildQueryConfig($request, 'update');
$attachment = $data['attachment'];
unset($data['attachment']);
$items = $data['items'];
unset($data['items']);
$config = [];
$config['model'] = InvRequisitionReturn::class;
$config['where']['id'] = $request->post('id');
$returnService = new InvRequisitionReturnService();
$returnService->logicUpdateBy($config, $data);
InvRequisitionItemReturn::where('return_id',$data['id'])->delete();
foreach ($items as $item) {
$item['return_id'] = $data['id'];
$item['requisition_id'] = $data['requisition_id'];
$item['return_at'] = $data['return_at'];
$item['apply_remark'] = $data['apply_remark'];
$created = $this->logicCreate($item);
//$this->logicUpdateBy($config, $data);
}
$this->logicUpdateBy($config, $data);
// 获取更新后的完整记录
$updated = $returnService->logicShow($config);
$updated = $this->logicShow($config);
// 处理附件更新
$this->processRequisitionItemReturnAttachment($updated, $attachment, true);
return $this->postProcess('Update', $updated);
});
} catch (\Throwable $e) {
throw new BusinessException("更新物品归还申请失败:" . $e->getMessage().$e->getLine().$e->getFile().$e->getTraceAsString());
throw new BusinessException("更新物品归还申请失败:" . $e->getMessage());
}
}
@@ -392,13 +295,11 @@ class InvRequisitionItemReturnService
* @return array|bool
* @throws BusinessException
*/
public function serviceReturnItemConfirm(Request $request, array $data, string $scene = 'returnConfirm')
public function serviceReturnConfirm(Request $request, array $data, string $scene = 'returnConfirm')
{
try {
$attachment = $request->post('attachment') ?? [];
unset($data['attachment']);
// 归还确认是业务顶层方法,这里统一使用事务
return Db::transaction(function () use ($request, $data, $scene, $attachment) {
return Db::transaction(function () use ($request, $data, $scene) {
// 1. 当前操作人信息
$userInfo = (new UserService())->getUserInfo($request->user->uid, '');
@@ -440,23 +341,10 @@ class InvRequisitionItemReturnService
// 4. 更新归还记录(状态 + 审核人 + 备注等)
$updateResult = $this->logicUpdateBy($config, $data);
$resultItem = $this->logicShow($config);
InvRequisitionReturn::where('id',$resultItem['return_id'])->update(['status' => $data['status']]);
foreach ($attachment as $attac) {
Db::table('inv_requisition_return_approve_attachment')->insertGetId([
'requisition_id' => $resultItem['requisition_id'],
'return_id' => $resultItem['return_id'],
'file_name' => $attac['original_name'],
'file_path' => $attac['file_path'],
'created_at' => time(),
]);
}
if ($updateResult === 0) {
throw new BusinessException('更新归还申请失败,可能记录不存在或已被处理');
}
//InvRequisitionReturn::where('return_id', $data['id'])->update(['status' => $status]);
// 5. 若是拒绝,直接返回(不改库存、不改已归还数量)
if ($status === 2) {
// 拒绝:这里你返回 true 或者返回更新后的记录都可以
@@ -517,7 +405,6 @@ class InvRequisitionItemReturnService
// 全部非耗材都已归还
$affected = InvRequisition::where('id', $requisitionId)->update([
'is_returned' => 1,
'status' => 17,
'updated_at' => time(),
]);
@@ -525,12 +412,6 @@ class InvRequisitionItemReturnService
if ($affected === 0) {
throw new BusinessException('更新领用单状态失败,可能记录不存在');
}
}else{
// 非耗材未全部归还
$affected = InvRequisition::where('id', $requisitionId)->update([
'status' => 16,
'updated_at' => time(),
]);
}
// 7. 返回处理结果(保持你原来的 postProcess 习惯)
@@ -544,179 +425,6 @@ class InvRequisitionItemReturnService
}
}
/**
* 物品领用归还确认
*
* @param Request $request
* @param array $data
* @param string $scene
* @return array|bool
* @throws BusinessException
*/
public function serviceReturnConfirm(Request $request, array $data, string $scene = 'returnConfirm')
{
try {
if(empty($data['return_id'])) {
$data['return_id'] = $data['requisition_item_return_id'];
}
$attachment = $request->post('attachment') ?? [];
unset($data['attachment']);
// 归还确认是业务顶层方法,这里统一使用事务
return Db::transaction(function () use ($request, $data, $scene, $attachment) {
// 1. 当前操作人信息
$userInfo = (new UserService())->getUserInfo($request->user->uid, '');
if (empty($userInfo['user']['id']) || empty($userInfo['user']['name'])) {
throw new BusinessException('无法获取当前用户信息');
}
$handlerId = (int)$userInfo['user']['id'];
$handlerName = (string)$userInfo['user']['name'];
$data['handler_id'] = $handlerId;
$data['handler_name'] = $handlerName;
// 确认状态:1=通过,2=拒绝
$status = isset($data['status']) ? (int)$data['status'] : null;
if (!in_array($status, [1, 2], true)) {
throw new BusinessException('非法的归还处理状态');
}
// 2. 构建查询配置,定位到这条归还记录
$returnService = new InvRequisitionReturnService();
$return = InvRequisitionReturn::where('id', $data['return_id'])->first();
if (!$return) {
throw new BusinessException('未找到对应的领用归还记录');
}
$requisitionId = (int)$return->requisition_id;
$existingStatus = (int)($return->status ?? 0);
if (in_array($existingStatus, [1, 2], true)) {
throw new BusinessException('该归还申请已经被处理过了');
}
$return->status = $status;
$return->save();
if($status == 1){
//更改库存
$returnItem = Db::table('inv_requisition_item_return')
->where('return_id', $return->id)
->get();
foreach ($returnItem as $item) {
//$invItem = InvItem::where('id', $item->item_id)->first();
(new InvItemService())->stockIn($item->item_id,$item->return_qty,['change_type'=>InvStockLog::CHANGE_TYPE_IN_RETURN,
'biz_type'=>InvStockLog::BIZ_TYPE_RETURN,]);
}
}
// 保存归还审核附件
foreach ($attachment as $attac) {
Db::table('inv_requisition_return_approve_attachment')->insertGetId([
'requisition_id' => $requisitionId,
'return_id' => $data['return_id'],
'file_name' => $attac['original_name'],
'file_path' => $attac['file_path'],
'created_at' => time(),
]);
}
//查询归还明细
$itemReturns = InvRequisitionItemReturn::where('return_id', $data['return_id'])->get();
foreach ($itemReturns as $itemReturn) {
$itemReturn->status = $status;
$itemReturn->handle_remark = $data['handle_remark'];
$itemReturn->save();
// 5. 若是拒绝,直接跳出(不改库存、不改已归还数量)
if ($status === 2) {
// 拒绝:这里你返回 true 或者返回更新后的记录都可以
continue;
}
// 6. 审核通过:继续处理领用明细 & 库存 & 领用单状态
// 注意:requisition_item_id、item_id、return_qty 等字段在本次确认流程中不会被修改,
// 所以可以直接使用 $existingRecord 中的值(都是只读字段)
$requisitionItemId = (int)$itemReturn->requisition_item_id;
$itemId = (int)$itemReturn->item_id;
$returnQty = (int)$itemReturn->return_qty;
if ($requisitionItemId <= 0 || $itemId <= 0 || $returnQty <= 0 || $requisitionId <= 0) {
throw new BusinessException('归还申请记录缺少必要字段,无法处理');
}
// 6.2 处理领用明细
/** @var \app\model\InvRequisitionItem|null $item */
$item = InvRequisitionItem::find($requisitionItemId);
if (!$item) {
throw new BusinessException('未找到对应的领用明细记录');
}
$approvedQty = (int)($item->approved_qty ?? 0);
$returnedQty = (int)($item->returned_qty ?? 0);
if ($approvedQty <= 0) {
throw new BusinessException('该物品尚未审批出库,无法归还');
}
if ($returnedQty + $returnQty > $approvedQty) {
throw new BusinessException('归还数量超过已借数量,无法确认');
}
$item->returned_qty = $returnedQty + $returnQty;
if ($item->returned_qty >= $approvedQty) {
$item->is_finished = 1;
}
$item->updated_at = time();
if ($item->save() === false) {
throw new BusinessException('更新领用明细失败');
}
// 6.3 处理库存(入库)
(new InvItemService())->stockIn($itemId, $returnQty);
}
// 5. 若是拒绝,直接返回(不修改领用申请状态)
if ($status === 2) {
// 拒绝:这里你返回 true 或者返回更新后的记录都可以
return $return;
}
// 6.3 检查整张单是否已全部归还(只看非耗材)
$notFinishedCount = InvRequisitionItem::query()
->where('requisition_id', $requisitionId)
->where('is_consumable_snap', 0)
->where('is_finished', 0)
->count();
if ($notFinishedCount === 0) {
// 全部非耗材都已归还
$affected = InvRequisition::where('id', $requisitionId)->update([
'is_returned' => 1,
'status' => 17,
'updated_at' => time(),
]);
// Eloquent::update 返回的是影响行数,0 表示未更新到任何行
if ($affected === 0) {
throw new BusinessException('更新领用单状态失败,可能记录不存在');
}
}else{
// 非耗材未全部归还
$affected = InvRequisition::where('id', $requisitionId)->update([
'status' => 16,
'updated_at' => time(),
]);
}
// 7. 返回处理结果(保持你原来的 postProcess 习惯)
//return $this->postProcess(ucfirst($scene), $existingRecord);
return $return;
});
} catch (BusinessException $e) {
throw $e;
} catch (\Throwable $e) {
throw new BusinessException("确认归还物品失败:" . $e->getMessage());
}
}
/**
* 构建查询配置
*
@@ -735,18 +443,13 @@ class InvRequisitionItemReturnService
$config['where']['id'] = $p['requisition_item_return_id'];
break;
case 'index':
// if(isset($p['status']) && $p['status']!=''){
// $config['where']['status'] = $p['status'];
// }
// if(isset($p['handler_id']) && $p['handler_id']=='self'){
// $config['where']['applicant_id'] = $request->user->uid;
// }else{
// $config['where']['handler_id'] = $request->user->uid;
// }
// $config['order']['id'] = 'desc';
$config['where']['status'] = 1;
$config['order']['sort'] = 'desc';
$config['order']['id'] = 'desc';
break;
case 'show':
$config['where']['id'] = $p['id'];
$config['where']['status'] = 1;
break;
case 'store':
break;
@@ -761,22 +464,6 @@ class InvRequisitionItemReturnService
return $config;
}
/** 分页列表 */
public function serviceList(Request $request, string $scene = 'index')
{
$InvRequisitionReturn = new InvRequisitionReturnService();
return $InvRequisitionReturn->serviceList($request, $scene);
}
/** 查看单条 */
public function serviceShow(Request $request, string $scene = 'show')
{
$id = $request->get('id');
$return = InvRequisitionReturn::where('id', $id)->first();
$return['item_return'] = InvRequisitionItemReturn::where('return_id', $return['id'])->orderBy('id', 'desc')->get();
return $return;
}
/**
* 生成申请单号
*
@@ -5,8 +5,6 @@ namespace app\common\service;
use app\common\validate\InvRequisitionReturnValidate;
use app\common\traits\crud\CrudServiceTrait;
use app\common\model\InvRequisitionReturn;
use support\exception\BusinessException;
use support\Request;
class InvRequisitionReturnService
{
@@ -30,64 +28,4 @@ class InvRequisitionReturnService
{
return new $this->validator;
}
public function serviceReturnConfirm(Request$request)
{
$status = $request->post('status');
if(in_array($status,[1,2])){
throw new BusinessException("状态不正确");
}
$requisitionReturn = InvRequisitionReturn::where(['id' => $request['id']])->first();
if (!$requisitionReturn && $requisitionReturn->handler_id == $request->user->uid) {
$requisitionReturn->status = $status;
return $requisitionReturn->save();
}else{
throw new BusinessException("审核示例不正确或非物品管理员");
}
}
/**
* 构建查询配置
*
* @param Request $request
* @param string $scene
* @return array
*/
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
{
$p = $request->all();
$config = [];
$config['model'] = $this->modelClass;
switch ($scene) {
case 'returnConfirm':
$config['where']['id'] = $p['requisition_item_return_id'];
break;
case 'index':
if(isset($p['status']) && $p['status']!=''){
$config['where']['status'] = $p['status'];
}
if (isset($p['handler_id']) && $p['handler_id'] == 'self') {
$config['where']['applicant_id'] = $request->user->uid;
} else {
$config['where']['handler_id'] = $request->user->uid;
}
$config['order']['id'] = 'desc';
break;
case 'show':
$config['where']['id'] = $p['id'];
break;
case 'store':
break;
case 'update':
$config['where']['id'] = $p['id'];
break;
case 'destroy':
$config['where']['id'] = $p['id'];
break;
}
return $config;
}
}
+7 -354
View File
@@ -3,7 +3,6 @@
namespace app\common\service;
use app\common\model\InvItem;
use app\common\model\InvStockLog;
use app\common\validate\InvRequisitionValidate;
use app\common\traits\crud\CrudServiceTrait;
use app\common\model\InvRequisition;
@@ -53,44 +52,7 @@ class InvRequisitionService
$config['order']['id'] = 'desc';
break;
case 'index':
if(isset($p['status']) && $p['status']){
$config['where']['status'] = $p['status'];
}
if (isset($p['applicant_id']) && $p['applicant_id'] == 'self') { //自己的领用申请
$config['where']['applicant_id'] = $request->user->uid;
} elseif (isset($p['applicant_id']) && $p['applicant_id']) { //指定人员的申请
$config['where']['applicant_id'] = $p['applicant_id'];
}
/* else { //审批人对应的记录
$config['with'] = ['approval'];
$config['where']['approval.approver_id'] = $request->user->uid;
//$config['where']['approval.action'] = 0;
}*/
if(isset($p['phase']) && $p['phase'] == 'approve'){//借用审批中
$config['where']['status'] = ['in',[10,11]];
if(isset($p['scene']) && $p['scene'] == 'approval'){
$config['with'] = ['approval'];
$config['where']['approval.action'] = 0;
}
}elseif(isset($p['phase']) && $p['phase'] == 'repaid'){//已全部归还
$config['where']['status'] = 17;
}elseif(isset($p['phase']) && $p['phase'] == 'unreturned'){ //未归还
$config['where']['status'] = ['in',[11,12,13,14,15,16,18,19]];
}
//审核列表
elseif(isset($p['phase']) && $p['phase'] == 'pending'){ //待审核
$config['where']['status'] = ['in',[10,11]];
$config['with'] = ['approval'];
$config['where']['approval.approver_id'] = $request->user->uid;
$config['where']['approval.action'] = 0;
}elseif(isset($p['phase']) && $p['phase'] == 'approved'){ //已通过
$config['where']['status'] = ['in',[11,12,14,15,16,17,18,19]];
$config['with'] = ['approval'];
$config['where']['approval.approver_id'] = $request->user->uid;
$config['where']['approval.action'] = [">",0];
}elseif(isset($p['phase']) && $p['phase'] == 'refuse'){ //拒绝,未通过
$config['where']['status'] = ['in',[13]];
}
$config['where']['applicant_id'] = $request->user->uid;
$config['order']['id'] = 'desc';
break;
case 'show':
@@ -128,7 +90,7 @@ class InvRequisitionService
$data['applicant_id'] = (int)$user['user']['id'];
$data['applicant_name'] = (string)$user['user']['name'];
$data['leader_id'] = $user['user']['report_to'];
$data['status'] = 10;
$data['status'] = InvRequisition::STATUS_LEADER;
//查询物品管理人是否是一个
if(count($data['items'])>=2){
@@ -138,7 +100,7 @@ class InvRequisitionService
}
$manage_user = array_unique($manage_user);
if(count($manage_user)>1){
throw new BusinessException("物品管理员不是同一人");
throw new BusinessException("审批实例未找到");
}
}
@@ -177,7 +139,7 @@ class InvRequisitionService
return $res;
});
} catch (\Throwable $e) {
throw new BusinessException("创建物品申请失败:".$e->getMessage());
throw new BusinessException("创建物品申请失败:" . $e->getMessage());
}
}
@@ -187,12 +149,11 @@ class InvRequisitionService
public function startApproval($requisition)
{
// 启动审批
//$appro = new \app\common\utils\approval\service\ApprovalFlowService();
$appro = new \app\common\service\InvRequisitionApproveService();
$appro = new \app\common\utils\approval\service\ApprovalFlowService();
$formData = [
'manage_user_id' => $requisition['manage_user_id'],
];
return $appro->start('inv_requisition', 'inv_requisition', $requisition['id'], $formData, $requisition['applicant_id']);
$appro->start('inv_requisition', 'inv_requisition', $requisition['id'], $formData, $requisition['applicant_id']);
}
/**
@@ -249,14 +210,13 @@ class InvRequisitionService
}
foreach ($items as $item) {
$invitem = InvItem::where('id',$item)->first();
$itemData = [
'requisition_id' => $created->id,
'item_id' => $item['item_id'],
'item_name_snap' => $item['item_name_snap'], // 修改:使用 snap 字段
'spec_model_snap' => $item['spec_model_snap']??'', // 修改:使用 snap 字段
'unit_snap' => $item['unit_snap']??'', // 修改:使用 snap 字段
'is_consumable_snap' => $item['is_consumable_snap']?? ($invitem['is_consumable_snap']??0), // 修改:使用 snap 字段
'is_consumable_snap' => $item['is_consumable_snap']?? 0, // 修改:使用 snap 字段
'request_qty' => (int) $item['request_qty'] ?? 1, // 动态获取数量,转为整型
'approved_qty' => (int) $item['request_qty'] ?? 1, // 初始审批数量等于申请数量
'remark' => $item['remark'] ?? ''
@@ -319,311 +279,4 @@ class InvRequisitionService
{
return 'RQ' . date('Ymd') . strtoupper(substr(uniqid(), -6));
}
/**
* 扫码领取物品
*
* @param Request $request
* @param array $data
* @return array
* @throws BusinessException
*/
public function qrClaim(Request $request, array $data): array
{
return Db::transaction(function () use ($request, $data) {
$itemId = (int)($data['item_id'] ?? 0);
$qty = (int)($data['qty'] ?? 1);
if ($itemId <= 0) {
throw new BusinessException('物品ID无效');
}
if ($qty <= 0) {
throw new BusinessException('领取数量必须大于0');
}
// 获取物品信息
$item = InvItem::find($itemId);
if (!$item) {
throw new BusinessException('物品不存在');
}
// 检查是否允许扫码领取
if (!$item->allow_qr_claim) {
throw new BusinessException('该物品不允许扫码领取');
}
// 获取用户信息
$user = (new UserService())->getUserInfo($request->user->uid, '');
$applicantId = (int)$user['user']['id'];
$applicantName = (string)$user['user']['name'];
// 检查扫码领取数量限制
if ($item->qr_code_num > 0) {
// 查询该用户已扫码领取该物品的数量
$claimedQty = InvRequisitionItem::whereHas('requisition', function ($q) use ($applicantId) {
$q->where('applicant_id', $applicantId)
->where('claim_type', InvRequisition::CLAIM_TYPE_QR);
})->where('item_id', $itemId)
->sum('approved_qty');
if (($claimedQty + $qty) > $item->qr_code_num) {
throw new BusinessException("扫码领取数量超限,每人最多可领取 {$item->qr_code_num} {$item->unit},已领取 {$claimedQty} {$item->unit}");
}
}
// 检查库存
if ($item->stock_qty < $qty) {
throw new BusinessException('库存不足,当前库存: ' . $item->stock_qty);
}
// 创建领用申请记录(直接完成)
$requisition = InvRequisition::create([
'order_no' => $this->generateOrderNo(),
'applicant_company_id' => $user['user']['company_id'] ?? 0,
'dept_id' => $user['user']['dept_id'] ?? 0,
'applicant_id' => $applicantId,
'applicant_name' => $applicantName,
'leader_id' => $user['user']['report_to'] ?? 0,
'manager_id' => $item->manage_user_id,
'borrow_reason' => '扫码领取',
'use_start_date' => date('Y-m-d', time()),
'use_end_date' => date('Y-m-d', time()),
'status' => 19, // 已审批(无需归还)
'claim_type' => InvRequisition::CLAIM_TYPE_QR,
'qr_claim_time' => time(),
'remark' => $data['remark'] ?? '扫码领取',
]);
// 创建领用明细
InvRequisitionItem::create([
'requisition_id' => $requisition->id,
'item_id' => $itemId,
'item_name_snap' => $item->item_name,
'spec_model_snap' => $item->spec_model,
'unit_snap' => $item->unit,
'is_consumable_snap' => $item->is_consumable,
'request_qty' => $qty,
'approved_qty' => $qty,
'remark' => '扫码领取',
]);
// 扣减库存
(new InvItemService())->stockOut($itemId, $qty, false, [
'biz_type' => InvStockLog::BIZ_TYPE_QR_CLAIM,
'biz_no' => $requisition->order_no,
'operator_id' => $applicantId,
'operator_name' => $applicantName,
'remark' => '扫码领取',
]);
return $requisition->toArray();
});
}
/**
* 管理员代领(支持多人)
*
* @param Request $request
* @param array $data
* @return array
* @throws BusinessException
*/
public function proxyClaim(Request $request, array $data): array
{
return Db::transaction(function () use ($request, $data) {
$itemId = (int)($data['item_id'] ?? 0);
$qty = (int)($data['qty'] ?? 1);
$targetUserIds = $data['target_user_id'];
if ($itemId <= 0) {
throw new BusinessException('物品ID无效');
}
if ($qty <= 0) {
throw new BusinessException('领取数量必须大于0');
}
if (empty($targetUserIds)) {
throw new BusinessException('请选择代领用户');
}
// 获取物品信息
$item = InvItem::find($itemId);
if (!$item) {
throw new BusinessException('物品不存在');
}
$targetUserIds = explode(',', $targetUserIds);
// 获取操作人(管理员)信息
$proxyUser = (new UserService())->getUserInfo($request->user->uid, '');
$proxyUserId = (int)$proxyUser['user']['id'];
$proxyUserName = (string)$proxyUser['user']['name'];
// 验证操作人是否是物品管理员
if ($item->manage_user_id != $proxyUserId) {
throw new BusinessException('您不是该物品的管理员,无权代领');
}
// 计算总需求量
$totalQty = $qty * count($targetUserIds);
// 检查库存
if ($item->stock_qty < $totalQty) {
throw new BusinessException('库存不足,当前库存: ' . $item->stock_qty . ',需要: ' . $totalQty);
}
$createdRequisitions = [];
$remark = $data['remark'] ?? '管理员代领';
// 为每个目标用户创建领用记录
foreach ($targetUserIds as $targetUserId) {
$targetUserId = (int)$targetUserId;
if ($targetUserId <= 0) {
continue;
}
// 获取目标用户信息
$targetUser = (new UserService())->getUserInfo($targetUserId, '');
if (!$targetUser['user']) {
throw new BusinessException('用户ID ' . $targetUserId . ' 不存在');
}
// 创建领用申请记录(直接完成)
$requisition = InvRequisition::create([
'order_no' => $this->generateOrderNo(),
'applicant_company_id' => $targetUser['user']['company_id'] ?? 0,
'dept_id' => $targetUser['user']['dept_id'] ?? 0,
'applicant_id' => $targetUserId,
'applicant_name' => $targetUser['user']['name'],
'leader_id' => $targetUser['user']['report_to'] ?? 0,
'manager_id' => $item->manage_user_id,
'borrow_reason' => $data['borrow_reason'] ?? '管理员代领',
'use_start_date' => date('Y-m-d', time()),
'use_end_date' => date('Y-m-d', time()),
'status' => 19, // 已审批(无需归还)
'claim_type' => InvRequisition::CLAIM_TYPE_PROXY,
'proxy_claim_user_id' => $proxyUserId,
'proxy_claim_user_name' => $proxyUserName,
'remark' => $remark,
]);
// 创建领用明细
InvRequisitionItem::create([
'requisition_id' => $requisition->id,
'item_id' => $itemId,
'item_name_snap' => $item->item_name,
'spec_model_snap' => $item->spec_model,
'unit_snap' => $item->unit,
'is_consumable_snap' => $item->is_consumable,
'request_qty' => $qty,
'approved_qty' => $qty,
'remark' => $remark,
]);
$createdRequisitions[] = $requisition->toArray();
}
// 一次性扣减总库存
(new InvItemService())->stockOut($itemId, $totalQty, false, [
'biz_type' => InvStockLog::BIZ_TYPE_PROXY_CLAIM,
'biz_no' => 'PROXY_' . time(),
'operator_id' => $proxyUserId,
'operator_name' => $proxyUserName,
'remark' => '管理员代领(' . count($targetUserIds) . '人×' . $qty . ')',
]);
return [
'created_count' => count($createdRequisitions),
'requisitions' => $createdRequisitions,
'total_qty' => $totalQty,
];
});
}
/**
* 查询扫码/代领记录列表
*
* @param Request $request
* @return array
*/
public function qrClaimsList(Request $request): array
{
$query = InvRequisition::query()->with(['items']);
// 只查询扫码领取和代领记录
$query->whereIn('claim_type', [
InvRequisition::CLAIM_TYPE_QR,
InvRequisition::CLAIM_TYPE_PROXY
]);
// 按申请人筛选(移动端"我的记录"功能)
if ($request->get('applicant_id') === 'self') {
$query->where('applicant_id', $request->user->uid);
} elseif (!empty($request->get('applicant_id'))) {
$query->where('applicant_id', $request->get('applicant_id'));
}
// 按领取方式筛选
if (!empty($request->get('claim_type'))) {
$query->where('claim_type', $request->get('claim_type'));
}
// 按代领操作人筛选
if (!empty($request->get('proxy_user_id'))) {
$query->where('proxy_claim_user_id', $request->get('proxy_user_id'));
}
// 按物品ID筛选
if (!empty($request->get('item_id'))) {
$query->whereHas('items', function ($q) use ($request) {
$q->where('item_id', $request->get('item_id'));
});
}
// 时间范围筛选
if (!empty($request->get('start_time'))) {
$query->where('created_at', '>=', strtotime($request->get('start_time')));
}
if (!empty($request->get('end_time'))) {
$query->where('created_at', '<=', strtotime($request->get('end_time')));
}
// 排序
$query->orderBy('id', 'desc');
// 分页
$perPage = $request->get('size', 20);
$page = $request->get('current', 1);
$result = $query->paginate($perPage, ['*'], 'page', $page);
return [
'records' => $result->getCollection()->map(function ($req) {
return [
'id' => $req->id,
'order_no' => $req->order_no,
'applicant_id' => $req->applicant_id,
'applicant_name' => $req->applicant_name,
'claim_type' => $req->claim_type,
'claim_type_text' => InvRequisition::getClaimTypeText($req->claim_type),
'qr_claim_time' => $req->qr_claim_time ? date('Y-m-d H:i:s', $req->qr_claim_time) : null,
'proxy_claim_user_id' => $req->proxy_claim_user_id,
'proxy_claim_user_name' => $req->proxy_claim_user_name,
'status' => $req->status,
'borrow_reason' => $req->borrow_reason,
'remark' => $req->remark,
'created_at' => $req->created_at ? $req->created_at->format('Y-m-d H:i:s') : null,
'items' => $req->items->map(function ($item) {
return [
'item_id' => $item->item_id,
'item_name_snap' => $item->item_name_snap,
'approved_qty' => $item->approved_qty,
];
})->toArray(),
];
})->toArray(),
'total' => $result->total(),
'current' => $result->currentPage(),
'size' => $result->perPage(),
];
}
}
-119
View File
@@ -1,119 +0,0 @@
<?php
namespace app\common\service;
use app\common\model\InvStockLog;
use support\exception\BusinessException;
/**
* 物品库存变化记录服务
*/
class InvStockLogService
{
/**
* 记录库存变化
*
* @param array $data 日志数据
* @return InvStockLog
* @throws BusinessException
*/
public function record(array $data): InvStockLog
{
$required = ['item_id', 'change_type', 'change_qty', 'before_qty', 'after_qty'];
foreach ($required as $field) {
if (!isset($data[$field])) {
throw new BusinessException("库存日志缺少必需字段: {$field}");
}
}
return InvStockLog::create([
'company_id' => $data['company_id'] ?? 0,
'item_id' => $data['item_id'],
'item_name_snap' => $data['item_name_snap'] ?? null,
'change_type' => $data['change_type'],
'change_qty' => $data['change_qty'],
'before_qty' => $data['before_qty'],
'after_qty' => $data['after_qty'],
'biz_type' => $data['biz_type'] ?? null,
'biz_no' => $data['biz_no'] ?? null,
'operator_id' => $data['operator_id'] ?? null,
'operator_name' => $data['operator_name'] ?? null,
'remark' => $data['remark'] ?? null,
'updated_at' => time(),
'created_at' => time(),
]);
}
/**
* 查询库存变化记录列表
*
* @param array $params 查询参数
* @return array
*/
public function getList(array $params): array
{
$query = InvStockLog::query()->with(['item']);
// 物品ID筛选
if (!empty($params['item_id'])) {
$query->where('item_id', $params['item_id']);
}
// 变动类型筛选
if (!empty($params['change_type'])) {
$query->where('change_type', $params['change_type']);
}
// 业务类型筛选
if (!empty($params['biz_type'])) {
$query->where('biz_type', $params['biz_type']);
}
// 单据号筛选
if (!empty($params['biz_no'])) {
$query->where('biz_no', 'like', '%' . $params['biz_no'] . '%');
}
// 时间范围筛选
if (!empty($params['start_time'])) {
$query->where('created_at', '>=', strtotime($params['start_time']));
}
if (!empty($params['end_time'])) {
$query->where('created_at', '<=', strtotime($params['end_time']));
}
// 排序
$query->orderBy('id', 'desc');
// 分页
$perPage = $params['size'] ?? 20;
$page = $params['current'] ?? 1;
$result = $query->paginate($perPage, ['*'], 'page', $page);
return [
'records' => $result->getCollection()->map(function ($log) {
return [
'id' => $log->id,
'item_id' => $log->item_id,
'item_name' => $log->item_name_snap,
'change_type' => $log->change_type,
'change_type_text' => InvStockLog::getChangeTypeText($log->change_type),
'change_qty' => $log->change_qty,
'before_qty' => $log->before_qty,
'after_qty' => $log->after_qty,
'biz_type' => $log->biz_type,
'biz_type_text' => $log->biz_type ? InvStockLog::getBizTypeText($log->biz_type) : null,
'biz_no' => $log->biz_no,
'operator_id' => $log->operator_id,
'operator_name' => $log->operator_name,
'remark' => $log->remark,
'created_at' => date('Y-m-d H:i:s', is_int($log->created_at)?$log->created_at:strtotime($log->created_at)),
];
})->toArray(),
'total' => $result->total(),
'current' => $result->currentPage(),
'size' => $result->perPage(),
];
}
}
-187
View File
@@ -1,187 +0,0 @@
<?php
namespace app\common\service;
use support\exception\BusinessException;
/**
* 二维码生成服务
*/
class QrCodeService
{
/**
* 生成物品二维码
*
* @param int $itemId 物品ID
* @param string $appUrl 应用访问地址
* @return string 二维码内容URL
*/
public function generateItemQrCode(int $itemId, string $appUrl): string
{
//return rtrim($appUrl, '/') . '/mobile/inv/claim/' . $itemId;
return "https://mweb-fdesk.hnxinyouhe.com/pages/scan/external-scan?id=" . $itemId;
}
/**
* 生成二维码图片并上传到 OSS
*
* @param int $itemId 物品ID
* @param string $content 二维码内容
* @param string $fileName 文件名
* @return array 返回OSS路径和完整URL
* @throws BusinessException
*/
public function generateAndUploadQrCode(int $itemId, string $content, string $fileName): array
{
// 使用 endroid/qr-code 库生成二维码
// 如果未安装,使用 API 方式生成
$tempPath = $this->generateQrCodeImage($content, $fileName);
if (!$tempPath) {
throw new BusinessException('二维码生成失败');
}
try {
// 上传到 OSS
$ossService = new OssService();
$ossPath = 'qr/' . $fileName;
$ossUrl = $ossService->uploadImage($tempPath, $ossPath);
// 删除临时文件
if (file_exists($tempPath)) {
unlink($tempPath);
}
return [
'path' => $ossPath,
'url' => $ossUrl,
];
} catch (\Throwable $e) {
// 删除临时文件
if (file_exists($tempPath)) {
unlink($tempPath);
}
throw new BusinessException('二维码上传失败:' . $e->getMessage());
}
}
/**
* 生成二维码图片(使用 QR Server API 或本地库)
*
* @param string $content 二维码内容
* @param string $fileName 文件名
* @return string 临时文件路径,失败返回 false
*/
private function generateQrCodeImage(string $content, string $fileName)
{
$tempDir = runtime_path() . '/qr_temp/';
if (!is_dir($tempDir)) {
mkdir($tempDir, 0755, true);
}
$tempPath = $tempDir . $fileName;
// 方式1: 使用 endroid/qr-code 库(推荐)
if (class_exists('\Endroid\QrCode\QrCode')) {
return $this->generateWithEndroid($content, $tempPath);
}
// 方式2: 使用在线 API(备用方案)
return $this->generateWithApi($content, $tempPath);
}
/**
* 使用 endroid/qr-code 生成二维码
*/
private function generateWithEndroid(string $content, string $tempPath): string
{
try {
// 5.x 版本使用静态工厂方法
if (method_exists(\Endroid\QrCode\QrCode::class, 'create')) {
$qrCode = \Endroid\QrCode\QrCode::create($content)
->setSize(300)
->setMargin(10);
} else {
// 4.x 及以下版本
$qrCode = new \Endroid\QrCode\QrCode($content);
if (method_exists($qrCode, 'setSize')) {
$qrCode->setSize(300);
}
if (method_exists($qrCode, 'setMargin')) {
$qrCode->setMargin(10);
}
}
// 获取 Writer
if (class_exists('\Endroid\QrCode\Writer\PngWriter')) {
$writer = new \Endroid\QrCode\Writer\PngWriter();
} else {
// 旧版本可能使用不同的命名空间
$writer = new \Endroid\QrCode\Writer();
}
$result = $writer->write($qrCode);
// 保存文件
if (method_exists($result, 'getString')) {
file_put_contents($tempPath, $result->getString());
} else {
// 更旧版本可能直接返回字符串
file_put_contents($tempPath, $result);
}
return $tempPath;
} catch (\Throwable $e) {
// 如果 endroid 库使用失败,回退到在线 API
error_log('endroid/qr-code 生成失败: ' . $e->getMessage() . ',使用在线 API 备用方案');
return $this->generateWithApi($content, $tempPath);
}
}
/**
* 使用在线 API 生成二维码(备用方案)
*/
private function generateWithApi(string $content, string $tempPath): string
{
$apiUrl = 'https://api.qrserver.com/v1/create-qr-code/?';
$params = [
'size' => '300x300',
'data' => $content,
'margin' => '10',
];
$url = $apiUrl . http_build_query($params);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$imageData = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200 || !$imageData) {
return false;
}
file_put_contents($tempPath, $imageData);
return $tempPath;
}
/**
* 删除 OSS 上的二维码文件
*
* @param string $ossPath OSS路径
* @return bool
*/
public function deleteQrCode(string $ossPath): bool
{
try {
$ossService = new OssService();
return $ossService->deleteFile($ossPath);
} catch (\Throwable $e) {
return false;
}
}
}
-97
View File
@@ -225,101 +225,4 @@ class Feishu
// ];
// return $this->requestResult($url);
// }
/**
* 获取 JSAPI 配置(签名)
* @param string $url 当前页面完整 URL(不包含 # 后面的内容)
* @return array
*/
public function getJsApiConfig($url)
{
// 1. 获取 tenant_access_token
//$accessToken = $this->getTenantAccessToken();
$accessToken = $this->tenantAccessToken();
// 2. 获取 jsapi_ticket
$ticket = $this->getJsapiTicket($accessToken);
// 3. 生成签名参数
$timestamp = (int) round(microtime(true) * 1000);
$nonceStr = $this->generateNonceStr();
// 4. 生成签名
$signature = $this->generateSignature($ticket, $nonceStr, $timestamp, $url);
return [
'appId' => $this->appId,
'timestamp' => $timestamp,
'nonceStr' => $nonceStr,
'signature' => $signature,
'url' => $url
];
}
/**
* 获取 jsapi_ticket
* @param string $accessToken
* @return string
*/
private function getJsapiTicket($accessToken)
{
// 检查缓存
$cachedTicket = Cache::get($this->abbr.'-feishu:jsapi_ticket');
// $cachedTicket = $this->getCachedData('feishu:jsapi_ticket');
if ($cachedTicket) {
return $cachedTicket;
}
// 使用 requestResult 方法发起请求,而不是 httpGet
$this->options["headers"] = [
"Authorization" => "Bearer " . $accessToken,
"Content-Type" => "application/json; charset=utf-8"
];
$result = $this->requestResult('jssdk/ticket/get', 'GET');
if (!$result) {
throw new BusinessException('获取 jsapi_ticket 失败: ' . $this->error());
}
$ticket = $result['data']['ticket'];
$expire = $result['data']['expire_in'] - 300; // 提前5分钟过期
// 缓存 ticket
Cache::set($this->abbr.'-feishu:jsapi_ticket', $ticket, $expire);
// $this->setCachedData('feishu:jsapi_ticket', $ticket, $expire);
return $ticket;
}
/**
* 生成签名
* @param string $ticket
* @param string $nonceStr
* @param int $timestamp
* @param string $url
* @return string
*/
private function generateSignature($ticket, $nonceStr, $timestamp, $url)
{
// 拼接待签名字符串(注意顺序)
$signStr = "jsapi_ticket={$ticket}&noncestr={$nonceStr}&timestamp={$timestamp}&url={$url}";
return sha1($signStr);
}
/**
* 生成随机字符串
* @param int $length
* @return string
*/
private function generateNonceStr($length = 16)
{
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$str = '';
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
}
-46
View File
@@ -1,46 +0,0 @@
<?php
namespace app\common\utils;
class SystemAuth
{
/**
* 生成签名
* @param string $userId 用户ID
* @param int $timestamp Unix时间戳
* @param string $secret 共享密钥
* @return string
*/
public static function generateSignature(string $userId, int $timestamp, string $secret): string
{
$data = $userId . $timestamp;
return hash_hmac('md5', $data, $secret);
}
/**
* 验证签名
* @param string $userId 用户ID
* @param int $timestamp Unix时间戳
* @param string $receivedSignature 接收到的签名
* @param string $secret 共享密钥
* @return bool
*/
public static function verifySignature(string $userId, int $timestamp, string $receivedSignature, string $secret): bool
{
$expectedSignature = self::generateSignature($userId, $timestamp, $secret);
return hash_equals($expectedSignature, $receivedSignature);
}
/**
* 验证时间戳是否在有效期内
* @param int $timestamp Unix时间戳
* @param int $maxSeconds 有效期(秒)
* @return bool
*/
public static function verifyTimestamp(int $timestamp, int $maxSeconds = 600): bool
{
$now = time();
$diff = abs($now - $timestamp);
return $diff <= $maxSeconds;
}
}
@@ -403,8 +403,4 @@ trait ApprovalResolverTrait
return $ids;
}
public function StetApprovers(array $step, object $instance, bool $avoidSelf = true){
return$this->resolveApprovers($step, $instance, $avoidSelf);
}
}
+8 -4
View File
@@ -8,18 +8,22 @@ class InvItemValidate extends Validate
{
// 规则
protected $rule = [
];
// 提示
protected $message = [
];
// 场景
protected $scene = [
'update' => [
'store' => [
],
'qrCode' => [
],
'update' => [
]
];
}
}
+4 -39
View File
@@ -15,13 +15,6 @@ class InvRequisitionValidate extends Validate
'items' => 'require|array',
'items.*.item_id' => 'require|number',
'items.*.request_qty' => 'require|number|gt:0',
// 扫码领取规则
'item_id' => 'require|integer|gt:0',
'qty' => 'require|integer|gt:0',
// 管理员代领规则
'target_user_id' => 'integer|gt:0',
'target_user_ids' => 'array',
'target_user_ids.*' => 'integer|gt:0',
];
// 提示
@@ -39,52 +32,24 @@ class InvRequisitionValidate extends Validate
'items.*.request_qty.require' => '申请数量不能为空',
'items.*.request_qty.number' => '申请数量格式错误',
'items.*.request_qty.gt' => '申请数量必须大于0',
'item_id.require' => '物品ID不能为空',
'item_id.integer' => '物品ID必须为整数',
'item_id.gt' => '物品ID必须大于0',
'qty.require' => '领取数量不能为空',
'qty.integer' => '领取数量必须为整数',
'qty.gt' => '领取数量必须大于0',
'target_user_id.require' => '代领用户不能为空',
];
// 场景
protected $scene = [
'store' => [
'applicant_id',
'borrow_reason',
'use_start_date',
'use_end_date',
'items'
],
'update' => [
'applicant_id',
'borrow_reason',
'use_start_date',
'use_end_date',
'items'
],
'apply' => [
'applicant_id',
'borrow_reason',
'use_start_date',
'use_end_date',
'items'
],
'qrClaim' => [
'item_id',
'qty',
],
'proxyClaim' => [
'item_id',
'qty',
'target_user_id',
'target_user_ids',
'borrow_reason',
],
]
];
}
+7 -7
View File
@@ -73,26 +73,26 @@ class IndexController
{
$options = [
'controller' => [
'module' => 'common',
'name' => 'usedcar_crawl_results_images'
'module' => 'mobile',
'name' => 'inv_requisition_return'
],
'model' => [
'module' => 'common',
'name' => 'usedcar_crawl_results_images'
'name' => 'inv_requisition_return'
],
'service' => [
'module' => 'common',
'name' => 'usedcar_crawl_results_images'
'name' => 'inv_requisition_return'
],
'logic' => [
'module' => 'common',
'name' => 'usedcar_crawl_results_images'
'name' => 'inv_requisition_return'
],
'validate' => [
'module' => 'common',
'name' => 'usedcar_crawl_results_images'
'name' => 'inv_requisition_return'
],
'table' => 'usedcar_crawl_results_images'
'table' => 'inv_requisition_return'
];
$result = (new Generate($options))->doGenerate();
+1 -1
View File
@@ -120,7 +120,7 @@ class CustomerService
if($corpId == 1){
$query->whereIn('channel_id', [1,2,3,4,5,6,7,8]);
} elseif($corpId == 3) {
$query->whereIn('channel_id', [9,10,11,16,17]);
$query->whereIn('channel_id', [9,10,11]);
} else{
$query->whereIn('channel_id', [0]);
}
-4
View File
@@ -60,14 +60,10 @@ class StockOrdersService extends \app\common\service\StockOrdersService
->pluck('user_id')
->toArray();
$config['where']['salesperson_id'] = ['in',$report];
$config['where']['approval_status'] = ['>=',1];
}else{ //内勤没有负责的组时
$config['where']['salesperson_id'] = $request->user->uid;
}
} elseif (in_array(1,$roles_id)) { //超管可以看所有的
//$config['where']['approval_status'] = ['>=',1];
$config['orWhere'][] = ['approval_status','>=',1];
$config['orWhere'][] = ['salesperson_id','=',$request->user->uid];
unset($config['where']['salesperson_id']);
}else{
$config['where']['salesperson_id'] = $request->user->uid;
-5
View File
@@ -79,11 +79,6 @@ class FbLeadHeaderMapper
// '阶段' => 'lead_status', // 或 extra_data
// '所有者' => 'owner', // 建议 extra_data
// '标签' => 'tags', // 建议 extra_data
// ===== Google 表格(大写表头)兼容(防御式)=====
'FULL_NAME' => 'full_name',
'EMAIL' => 'email',
'PHONE_NUMBER' => 'phone',
];
/**
@@ -4,8 +4,6 @@ namespace app\mobile\controller;
use app\common\controller\BaseController;
use app\common\model\Corp;
use app\common\model\InvItem;
use app\common\model\InvRequisitionApprove;
use app\common\model\InvRequisitionApproveAttachment;
use app\common\model\InvRequisitionAttachment;
use app\common\model\InvRequisitionItem;
use app\common\service\OssService;
@@ -45,78 +43,24 @@ class InvRequisitionController extends BaseController
}
}
/**
* 获取列表
*
* @param Request $request 请求对象
* @return mixed 返回分页数据及总数
*/
public function index(Request $request)
{
try {
$param = $request->all();
$applicant_id = $request->get('applicant_id');
$raw = $this->service->serviceList($request);
$uid = $request->user->uid;
$data = $this->formatindex($raw,$applicant_id,$uid,$param);
// $data = $this->transformData($raw, method_exists($this, 'indexFormat')
// ? [$this, 'indexFormat']
// : null);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function formatindex($p,$applicant_id,$uid,$param){
$records = $p->getCollection()
->map(fn($item) => $this->indexFormat($item, $applicant_id,$uid))
->toArray();
if(isset($param['phase']) && $param['phase'] == 'pending'){
foreach ($records as $key => $record) {
if($record['action']==1 || $record['action']==2)
unset($records[$key]);
}
$records = array_values($records);
}
return [
'records' => $records,
'total' => $p->total(),
'current' => $p->currentPage(),
'size' => $p->perPage(),
];
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function indexFormat($data, $applicant_id, $uid)
protected function indexFormat($data)
{
if(isset($data['id']) && is_object($data)){
$data = $data->toArray();
}
if (isset($data['created_at'])){
$data['created_at'] = is_int($data['created_at'])?$data['created_at']:strtotime($data['created_at']);
if (isset($data['created_at']))
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
}
if (isset($data['updated_at'])){
$data['updated_at'] = is_int($data['updated_at'])?$data['updated_at']:strtotime($data['updated_at']);
if (isset($data['updated_at']))
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
}
if (isset($data['id'])){
$data['item'] = InvRequisitionItem::where('requisition_id', $data['id'])->get();
}
if($applicant_id != 'self' && isset($data['id'])){ //不是查询自己数据时查询是否已审核
$approve = InvRequisitionApprove::where('requisition_id', $data['id'])
->where('approver_id', $uid)
->first();
$data['action'] = $approve['action']??3;//查询人审核状态:0待审核 1通过 2驳回 3非审核人
foreach ($data['item'] as $key => $item){
$corpId = InvItem::where('id', $item->item_id)->value('company_id');
$item['company_name'] = Corp::where('id', $corpId)->value('name');
}
}
return $data;
}
@@ -129,20 +73,6 @@ class InvRequisitionController extends BaseController
*/
protected function showFormat($data)
{
$oss = new OssService();
if (isset($data['id'])){
$data['approve'] = InvRequisitionApprove::where('requisition_id', $data['id'])->get()->toArray();
foreach ($data['approve'] as $key => $item){
$attachment = InvRequisitionApproveAttachment::where('approve_id', $item['id'])->get();
foreach ($attachment as $k => $v){
$attachment[$k] = $v->toArray();
$attachment[$k]['file_path_pull'] = $oss->generatePrivateUrl($v['file_path']);
}
$data['approve'][$key]['attachment'] = $attachment;
}
$approve_id = !empty($data['approve'])?array_pop($data['approve'])['id']:null;
$data['approve_id'] = $approve_id;
}
if (isset($data['created_at']))
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
if (isset($data['updated_at']))
@@ -150,44 +80,11 @@ class InvRequisitionController extends BaseController
if (isset($data['id'])){
$data['item'] = InvRequisitionItem::where('requisition_id', $data['id'])->get();
$data['attachment'] = InvRequisitionAttachment::where('requisition_id', $data['id'])->get();
$oss = new OssService();
foreach ($data['attachment'] as $key => $value) {
$data['attachment'][$key]['file_path_pull'] = $oss->generatePrivateUrl($value['file_path']);
}
}
return $data;
}
/**
* 扫码领取物品
*
* @param Request $request
* @return mixed
*/
public function qrClaim(Request $request)
{
try {
$data = $this->service->qrClaim($request, $request->post());
return $this->success($data, '领取成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 我的扫码/代领记录
*
* @param Request $request
* @return mixed
*/
public function myQrClaims(Request $request)
{
try {
// 只查询当前用户的扫码记录,通过设置 applicant_id=self 实现
$request->setGet('applicant_id','self');
$data = $this->service->qrClaimsList($request);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
@@ -2,12 +2,6 @@
namespace app\mobile\controller;
use app\common\controller\BaseController;
use app\common\model\Corp;
use app\common\model\InvItem;
use app\common\model\InvRequisitionItem;
use app\common\model\InvRequisitionItemReturn;
use app\common\model\InvRequisitionItemReturnAttachment;
use app\common\service\OssService;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\InvRequisitionItemReturnService;
use support\Request;
@@ -23,143 +17,24 @@ class InvRequisitionItemReturnController extends BaseController
$this->service = new InvRequisitionItemReturnService();
}
/**
* 获取列表
*
* @param Request $request 请求对象
* @return mixed 返回分页数据及总数
*/
public function index(Request $request)
{
try {
//$request->setGet('$request');
$raw = $this->service->serviceList($request);
$data = $this->transformData($raw, method_exists($this, 'indexFormat')
? [$this, 'indexFormat']
: null);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function indexFormat($data)
{
if(isset($data['id'])){
$data['return_item'] = InvRequisitionItemReturn::where('return_id', $data['id'])->get();
foreach ($data['return_item'] as $key => $value) {
$data['return_item'][$key]['item'] = InvItem::where('id', $value['item_id'])->get();
}
}
if (isset($data['return_at']))
$data['return_at'] = date('Y-m-d H:i:s', $data['return_at']);
if (isset($data['created_at']))
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
if (isset($data['updated_at']))
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
return $data;
}
/**
* 获取详情
*
* @param Request $request 请求对象
* @param int|string $id 资源 ID
* @return mixed 返回资源详情数据
*/
public function show(Request $request)
{
try {
$raw = $this->service->serviceShow($request);
$data = $this->transformData($raw, method_exists($this, 'showFormat')
? [$this, 'showFormat']
: null);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function showFormat($data)
{
foreach ($data['item_return'] as $key => $item){
$data['item_return'][$key]['requisition_item'] = InvRequisitionItem::where('id', $item['requisition_item_id'])->first();
}
if (isset($data['return_at']))
$data['return_at'] = date('Y-m-d H:i:s', $data['return_at']);
if (isset($data['id'])){
$data['return_attachment'] = InvRequisitionItemReturnAttachment::where('return_id', $data['id'])->get();
$ossservice = new OssService();
foreach ($data['return_attachment'] as $item){
$item['file_path_pull'] = $ossservice->generatePrivateUrl($item['file_path']);
}
//归还审核附件
$data['return_approve_attachment'] = InvRequisitionItemReturnAttachment::where('return_id', $data['id'])->get();
foreach ($data['return_approve_attachment'] as $item){
$item['file_path_pull'] = $ossservice->generatePrivateUrl($item['file_path']);
}
}
/*if (isset($data['created_at']))
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
if (isset($data['updated_at']))
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);*/
return $data;
}
// protected function indexFormat($data)
// {
// if (isset($data['created_at']))
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
// if (isset($data['updated_at']))
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
// return $data;
// }
/**
* 更新
*
* @param Request $request 请求对象
* @return mixed 返回更新成功的数据或信息
*/
public function update(Request $request)
{
try {
$data = $this->validate($this->service->getValidator(), $request->post(), 'update');
$res = $this->service->serviceUpdate($request, $data);
return $this->success([], '更新成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 物品归还确认
*
* @param Request $request
* @return mixed
*/
public function returnItemConfirm(Request $request)
{
try {
// 验证申请数据
$data = $this->validate($this->service->getValidator(), $request->post(), 'returnConfirm');
// 处理申请逻辑
$result = $this->service->serviceReturnItemConfirm($request, $data, 'returnConfirm');
return $this->success($result, '申请提交成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 物品归还确认
* 物品兑换确认
*
* @param Request $request
* @return mixed
@@ -169,9 +44,10 @@ class InvRequisitionItemReturnController extends BaseController
try {
// 验证申请数据
$data = $this->validate($this->service->getValidator(), $request->post(), 'returnConfirm');
// 处理申请逻辑
$result = $this->service->serviceReturnConfirm($request, $data, 'returnConfirm');
return $this->success($result, '申请提交成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
@@ -2,7 +2,6 @@
namespace app\mobile\controller;
use app\common\controller\BaseController;
use app\common\model\InvRequisitionItem;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\InvRequisitionReturnService;
@@ -23,15 +22,12 @@ class InvRequisitionReturnController extends BaseController
* @param array $data
* @return array
*/
protected function indexFormat($data)
{
if (isset($data['id'])) {
$data['item'] = InvRequisitionItem::where('requisition_id', $data['id'])->get();
}
if (isset($data['created_at']))
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
if (isset($data['updated_at']))
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
return $data;
}
// protected function indexFormat($data)
// {
// if (isset($data['created_at']))
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
// if (isset($data['updated_at']))
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
// return $data;
// }
}
+1 -2
View File
@@ -49,8 +49,7 @@
"mpdf/mpdf": "^8.2",
"jaeger/querylist": "^4.4",
"zoujingli/ip2region": "^3.0",
"webman/log": "^2.1",
"endroid/qr-code": "^6.0"
"webman/log": "^2.1"
},
"suggest": {
"ext-event": "For better performance. "
Generated
+1 -154
View File
@@ -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": "28a80d57e5dbc1da167b66780b6dfd00",
"content-hash": "bf987c3cd5510fc0637d6b64d460dde1",
"packages": [
{
"name": "aliyuncs/oss-sdk-php",
@@ -51,55 +51,6 @@
},
"time": "2024-10-28T10:41:12+00:00"
},
{
"name": "bacon/bacon-qr-code",
"version": "v3.0.3",
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/bacon/bacon-qr-code/v3.0.3/bacon-bacon-qr-code-v3.0.3.zip",
"reference": "36a1cb2b81493fa5b82e50bf8068bf84d1542563",
"shasum": ""
},
"require": {
"dasprid/enum": "^1.0.3",
"ext-iconv": "*",
"php": "^8.1"
},
"require-dev": {
"phly/keep-a-changelog": "^2.12",
"phpunit/phpunit": "^10.5.11 || ^11.0.4",
"spatie/phpunit-snapshot-assertions": "^5.1.5",
"spatie/pixelmatch-php": "^1.2.0",
"squizlabs/php_codesniffer": "^3.9"
},
"suggest": {
"ext-imagick": "to generate QR code images"
},
"type": "library",
"autoload": {
"psr-4": {
"BaconQrCode\\": "src/"
}
},
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Ben Scholzen 'DASPRiD'",
"email": "mail@dasprids.de",
"homepage": "https://dasprids.de/",
"role": "Developer"
}
],
"description": "BaconQrCode is a QR code generator for PHP.",
"homepage": "https://github.com/Bacon/BaconQrCode",
"support": {
"issues": "https://github.com/Bacon/BaconQrCode/issues",
"source": "https://github.com/Bacon/BaconQrCode/tree/v3.0.3"
},
"time": "2025-11-19T17:15:36+00:00"
},
{
"name": "brick/math",
"version": "0.14.1",
@@ -308,50 +259,6 @@
],
"time": "2024-11-12T16:29:46+00:00"
},
{
"name": "dasprid/enum",
"version": "1.0.7",
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/dasprid/enum/1.0.7/dasprid-enum-1.0.7.zip",
"reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce",
"shasum": ""
},
"require": {
"php": ">=7.1 <9.0"
},
"require-dev": {
"phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11",
"squizlabs/php_codesniffer": "*"
},
"type": "library",
"autoload": {
"psr-4": {
"DASPRiD\\Enum\\": "src/"
}
},
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Ben Scholzen 'DASPRiD'",
"email": "mail@dasprids.de",
"homepage": "https://dasprids.de/",
"role": "Developer"
}
],
"description": "PHP 7.1 enum implementation",
"keywords": [
"enum",
"map"
],
"support": {
"issues": "https://github.com/DASPRiD/Enum/issues",
"source": "https://github.com/DASPRiD/Enum/tree/1.0.7"
},
"time": "2025-09-16T12:23:56+00:00"
},
{
"name": "doctrine/inflector",
"version": "2.1.0",
@@ -442,66 +349,6 @@
],
"time": "2025-08-10T19:31:58+00:00"
},
{
"name": "endroid/qr-code",
"version": "6.0.9",
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/endroid/qr-code/6.0.9/endroid-qr-code-6.0.9.zip",
"reference": "21e888e8597440b2205e2e5c484b6c8e556bcd1a",
"shasum": ""
},
"require": {
"bacon/bacon-qr-code": "^3.0",
"php": "^8.2"
},
"require-dev": {
"endroid/quality": "dev-main",
"ext-gd": "*",
"khanamiryan/qrcode-detector-decoder": "^2.0.2",
"setasign/fpdf": "^1.8.2"
},
"suggest": {
"ext-gd": "Enables you to write PNG images",
"khanamiryan/qrcode-detector-decoder": "Enables you to use the image validator",
"roave/security-advisories": "Makes sure package versions with known security issues are not installed",
"setasign/fpdf": "Enables you to use the PDF writer"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "6.x-dev"
}
},
"autoload": {
"psr-4": {
"Endroid\\QrCode\\": "src/"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "Jeroen van den Enden",
"email": "info@endroid.nl"
}
],
"description": "Endroid QR Code",
"homepage": "https://github.com/endroid/qr-code",
"keywords": [
"code",
"endroid",
"php",
"qr",
"qrcode"
],
"support": {
"issues": "https://github.com/endroid/qr-code/issues",
"source": "https://github.com/endroid/qr-code/tree/6.0.9"
},
"time": "2025-07-13T19:59:45+00:00"
},
{
"name": "firebase/php-jwt",
"version": "v6.11.1",
+1 -1
View File
@@ -34,7 +34,7 @@ return [
// 合塑社媒
'fb_hesu_shemei' => [
'watch_dir' => 'excel/fb_hesu_shemei',
'enter_user_id' => 17,
'enter_user_id' => 186,
'channel_id' => 6,
'sales_user_ids' => [
22, 23, 34, 44, 49, 71, 72, 73, 96, 104, 125, 135, 142, 155, 187
+6 -58
View File
@@ -29,11 +29,6 @@ use Webman\Route;
Route::any('/c', [app\controller\IndexController::class, 'createResource']);
Route::any('/perm', [app\controller\IndexController::class, 'perm']);
// 系统间认证接口
Route::group('/api/system', function () {
Route::any('/auth', [app\common\controller\SystemController::class, 'auth']);
});
// 飞书
Route::any('/feishu/event', [app\common\controller\NotifyController::class, 'feishuEvent']);
// 飞书回调
@@ -56,7 +51,7 @@ Route::group('/common', function () {
Route::any('/register', [app\common\controller\AuthController::class, 'register']);
Route::any('/feishu/scope', [app\common\controller\AuthController::class, 'feishuScope']);
Route::any('/refresh/token', [app\common\controller\AuthController::class, 'refresh']);
Route::any('/feishu/jsapi', [app\common\controller\AuthController::class, 'getJsApi']);
// // 调试
Route::any('/feishu/auth', [app\common\controller\AuthController::class, 'feishuAuth']);
@@ -121,8 +116,6 @@ Route::group('/common', function () {
Route::any('/crawlModelCreate', [app\common\controller\BrandSeriesController::class, 'crawlModelCreate']);
Route::any('/crawlKeyword', [app\common\controller\BrandSeriesController::class, 'crawlKeyword']);
Route::any('/crawlKeywordCreate', [app\common\controller\BrandSeriesController::class, 'crawlKeywordCreate']);
Route::any('/crawlUrl', [app\common\controller\BrandSeriesController::class, 'crawlUrl']);
Route::any('/crawl', [app\common\controller\BrandSeriesController::class, 'crawl']);
});
});
@@ -531,37 +524,6 @@ Route::group('/admin', function () {
Route::any('/item/update', [app\admin\controller\InvItemController::class, 'update']);
Route::any('/item/show', [app\admin\controller\InvItemController::class, 'show']);
Route::any('/item/destroy', [app\admin\controller\InvItemController::class, 'destroy']);
Route::any('/item/qr-code', [app\admin\controller\InvItemController::class, 'generateQrCode']);
Route::any('/item/qr-code/delete', [app\admin\controller\InvItemController::class, 'deleteQrCode']);
Route::group('/requisition', function () {
Route::any('/list', [app\admin\controller\InvRequisitionController::class, 'index']);
Route::any('/show', [app\admin\controller\InvRequisitionController::class, 'show']);
Route::any('/approve', [app\admin\controller\InvRequisitionController::class, 'approve']);
});
// 物品归还
Route::group('/requisition/return', function () {
Route::any('/store', [app\common\controller\InvRequisitionItemReturnController::class, 'store']);
Route::any('/update', [app\common\controller\InvRequisitionItemReturnController::class, 'update']);
Route::any('/list', [app\common\controller\InvRequisitionItemReturnController::class, 'index']);
Route::any('/show', [app\common\controller\InvRequisitionItemReturnController::class, 'show']);
Route::any('/confirm', [app\common\controller\InvRequisitionItemReturnController::class, 'returnConfirm']);
// Route::any('/confirmItem', [app\common\controller\InvRequisitionItemReturnController::class, 'returnItemConfirm']);
});
});
// 库存变化记录
Route::group('/stock-log', function () {
Route::any('/list', [app\admin\controller\InvStockLogController::class, 'list']);
});
Route::group('/requisition', function () {
// Route::any('/list', [app\admin\controller\InvRequisitionController::class, 'index']);
// Route::any('/show', [app\admin\controller\InvRequisitionController::class, 'show']);
// Route::any('/approve', [app\admin\controller\InvRequisitionController::class, 'approve']);
Route::any('/proxy-claim', [app\admin\controller\InvRequisitionController::class, 'proxyClaim']);
Route::any('/qr-claims', [app\admin\controller\InvRequisitionController::class, 'qrClaims']);
});
});
@@ -694,28 +656,14 @@ Route::group('/mobile', function () {
Route::any('/item/preset', [app\mobile\controller\InvItemController::class, 'preset']);
// 物品领用申请
// Route::any('/requisition/list', [app\mobile\controller\InvRequisitionController::class, 'index']);
// Route::any('/requisition/show', [app\mobile\controller\InvRequisitionController::class, 'show']);
Route::any('/requisition/list', [app\mobile\controller\InvRequisitionController::class, 'index']);
Route::any('/requisition/show', [app\mobile\controller\InvRequisitionController::class, 'show']);
Route::any('/requisition/apply', [app\mobile\controller\InvRequisitionController::class, 'apply']);
Route::any('/requisition/update', [app\mobile\controller\InvRequisitionController::class, 'update']);
Route::group('/requisition', function () {
Route::any('/list', [app\mobile\controller\InvRequisitionController::class, 'index']);
Route::any('/show', [app\mobile\controller\InvRequisitionController::class, 'show']);
// Route::any('/approve', [app\mobile\controller\InvRequisitionController::class, 'approve']);
Route::any('/qr-claim', [app\mobile\controller\InvRequisitionController::class, 'qrClaim']);
Route::any('/my-qr-claims', [app\mobile\controller\InvRequisitionController::class, 'myQrClaims']);
});
// 物品归还
Route::group('/requisition/return', function () {
Route::any('/store', [app\mobile\controller\InvRequisitionItemReturnController::class, 'store']);
Route::any('/update', [app\mobile\controller\InvRequisitionItemReturnController::class, 'update']);
Route::any('/list', [app\mobile\controller\InvRequisitionItemReturnController::class, 'index']);
Route::any('/show', [app\mobile\controller\InvRequisitionItemReturnController::class, 'show']);
Route::any('/confirm', [app\mobile\controller\InvRequisitionItemReturnController::class, 'returnConfirm']);
// Route::any('/confirmItem', [app\mobile\controller\InvRequisitionItemReturnController::class, 'returnItemConfirm']);
});
Route::any('/requisition/item/return', [app\mobile\controller\InvRequisitionItemReturnController::class, 'store']);
Route::any('/requisition/item/return/update', [app\mobile\controller\InvRequisitionItemReturnController::class, 'update']);
Route::any('/requisition/item/return/confirm', [app\mobile\controller\InvRequisitionItemReturnController::class, 'returnConfirm']);
});
});
-12
View File
@@ -1,12 +0,0 @@
<?php
return [
// 共享密钥(双方约定同一个字符串)
'shared_secret' => env('SYSTEM_AUTH_SHARED_SECRET', 'your-shared-secret-string'),
// 签名有效期(秒),默认10分钟
'signature_expire' => 600,
// Token 有效期(秒)
'token_expire' => 86400,
];