登录
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\ApprovalFlowsValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\ApprovalFlows;
|
||||
use support\Request;
|
||||
|
||||
class ApprovalFlowsService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = ApprovalFlows::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = ApprovalFlowsValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'index'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'index':
|
||||
$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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\ApprovalInstancesValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\ApprovalInstances;
|
||||
|
||||
class ApprovalInstancesService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = ApprovalInstances::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = ApprovalInstancesValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\ApprovalRecordsValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\ApprovalRecords;
|
||||
use support\Request;
|
||||
|
||||
class ApprovalRecordsService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = ApprovalRecords::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = ApprovalRecordsValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'index':
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
$config['with'] = [
|
||||
'instance',
|
||||
'approver',
|
||||
'instance.flows',
|
||||
'instance.initiator',
|
||||
'instance.bizInfo'
|
||||
];
|
||||
|
||||
// $config['dataLimit']['type'] = 'relation';
|
||||
// $config['dataLimit']['userId'] = $request->user->uid;
|
||||
// $config['dataLimit']['userField'] = 'approver_id';
|
||||
break;
|
||||
case 'todo':
|
||||
|
||||
if ($p['scene'] === 'todo') {
|
||||
if (!in_array(1, $request->user->role_ids)) {
|
||||
$config['where']['approver_id'] = $request->user->uid;
|
||||
}
|
||||
$config['where']['status'] = 'pending';
|
||||
$config['where']['instance.status'] = 'processing';
|
||||
}
|
||||
|
||||
if ($p['scene'] === 'history') {
|
||||
if (!in_array(1, $request->user->role_ids)) {
|
||||
$config['where']['approver_id'] = $request->user->uid;
|
||||
}
|
||||
$config['where']['status'] = ['!=', 'pending'];
|
||||
}
|
||||
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
$config['with'] = [
|
||||
'instance',
|
||||
'approver',
|
||||
'instance.flows',
|
||||
'instance.initiator',
|
||||
'instance.bizInfo'
|
||||
];
|
||||
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;
|
||||
case 'logs':
|
||||
$config['where']['instance_id'] = $p['instance_id'];
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'border':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['order']['id'] = 'desc';
|
||||
$config['with'] = [
|
||||
'instance',
|
||||
'approver',
|
||||
'instance.flows',
|
||||
'instance.initiator',
|
||||
'instance.bizInfo'
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
public function serviceApprove(Request $request)
|
||||
{
|
||||
$param = $request->all();
|
||||
$appro = new \app\common\utils\approval\service\ApprovalFlowService();
|
||||
return $appro->approve($param['instance_id'], $request->user->uid, $param['action'], $param['comment']);
|
||||
}
|
||||
|
||||
|
||||
public function serviceLogs(Request $request)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'logs');
|
||||
$item = $this->logicListAll($config);
|
||||
return $this->postProcess('Logs', $item);
|
||||
}
|
||||
|
||||
|
||||
public function serviceBusinessOrder(Request $request, array $data = [])
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'border');
|
||||
$config = $this->borderConfig($config, $data['flow_type']);
|
||||
$item = $this->logicShow($config);
|
||||
$bizInfo = [];
|
||||
$service = match ($data['flow_type']) {
|
||||
'stock_orders' => new \app\common\service\StockOrdersService(),
|
||||
'stock_orders_nullify' => new \app\common\service\StockOrdersService(),
|
||||
'purchase_orders' => new \app\common\service\PurchaseOrdersService(),
|
||||
default => new \app\common\service\StockOrdersService()
|
||||
};
|
||||
$bizInfo = $service->formatData($item->instance->bizInfo);
|
||||
return $this->postProcess('Border', $bizInfo);
|
||||
}
|
||||
|
||||
public function borderConfig($config, $type = 'stock_orders')
|
||||
{
|
||||
$with = match ($type) {
|
||||
'stock_orders' => [
|
||||
'instance.bizInfo.items',
|
||||
'instance.bizInfo.items.options',
|
||||
'instance.bizInfo.items.moneyValues',
|
||||
'instance.bizInfo.accounts',
|
||||
'instance.bizInfo.moneyValues',
|
||||
'instance.bizInfo.salesperson',
|
||||
],
|
||||
'stock_orders_nullify' => [
|
||||
'instance.bizInfo.items',
|
||||
'instance.bizInfo.items.options',
|
||||
'instance.bizInfo.items.moneyValues',
|
||||
'instance.bizInfo.accounts',
|
||||
'instance.bizInfo.moneyValues',
|
||||
'instance.bizInfo.salesperson',
|
||||
],
|
||||
'purchase_orders' => [
|
||||
'instance.bizInfo.items',
|
||||
'instance.bizInfo.items.stockOrder',
|
||||
'instance.bizInfo.items.stockOrderItems'
|
||||
]
|
||||
};
|
||||
$config['with'] = array_merge($config['with'], $with);
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
public function transferApproval(Request $request, array $data = [])
|
||||
{
|
||||
$service = new \app\common\utils\approval\service\ApprovalFlowService();
|
||||
$result = $service->transferApproval($data['instance_id'], $data['step_index'], $request->user->uid, $data['to_uid'], $data['reason'], 'name');
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
public function serviceApprovalTimeline(Request $request, array $data = [])
|
||||
{
|
||||
$instance = \app\common\model\ApprovalInstances::where('biz_id', $data['id'])->where('flow_type', $data['flow_type'])->first();
|
||||
if (!$instance) {
|
||||
return [];
|
||||
}
|
||||
$result = \app\common\model\ApprovalRecords::where('instance_id', $instance->id)->with('approver')->orderBy('id', 'desc')->get();
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\AuthLogic;
|
||||
use app\common\model\User;
|
||||
use app\common\utils\Feishu;
|
||||
use support\Db;
|
||||
|
||||
class AuthService
|
||||
{
|
||||
|
||||
/**
|
||||
* 飞书授权
|
||||
*/
|
||||
public function feishuAuthorize(string $app_id, string $systemCcode, $mobile)
|
||||
{
|
||||
$logic = new AuthLogic();
|
||||
$certificate = $logic->feishuAppInfo($app_id, $systemCcode);
|
||||
$feishu = new Feishu($certificate['app_id'], $certificate['app_secret'], 'xinyouhe');
|
||||
return ['auth_url' => $feishu->authorize($certificate, $mobile)];
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录,支持多类型
|
||||
*/
|
||||
public function login(array $data): array
|
||||
{
|
||||
$loginType = $data['login_type'] ?? 'feishu';
|
||||
$logic = new AuthLogic();
|
||||
|
||||
return match ($loginType) {
|
||||
'feishu' => $logic->feishuLogin($data),
|
||||
// 'qrcode' => $logic->qrCodeLogin($data),
|
||||
default => $logic->uPwdLogin($data),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
*/
|
||||
public function register(array $data)
|
||||
{
|
||||
$logic = new AuthLogic();
|
||||
try {
|
||||
Db::beginTransaction();
|
||||
$result = $logic->register($data);
|
||||
Db::commit();
|
||||
return $result;
|
||||
} catch (\Throwable $e) {
|
||||
Db::rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验token
|
||||
*/
|
||||
public function verifyToken(string $token, string $systemCode): array
|
||||
{
|
||||
return (new AuthLogic())->verifyToken($token, $systemCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新token
|
||||
* @param string $refreshToken
|
||||
* @param string|null $systemCode
|
||||
*/
|
||||
public function refreshToken(string $refreshToken, string $systemCode): array
|
||||
{
|
||||
return (new AuthLogic())->refreshToken($refreshToken, $systemCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出(失效token)
|
||||
*/
|
||||
public function logout(?string $token, string $systemCode): void
|
||||
{
|
||||
(new AuthLogic())->logout($token, $systemCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制拉黑token
|
||||
*/
|
||||
public function blockToken(string $token, string $systemCode): void
|
||||
{
|
||||
(new AuthLogic())->blockToken($token, $systemCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\Corp;
|
||||
use app\common\model\Systems;
|
||||
use support\Redis;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class BasicDataService
|
||||
{
|
||||
// 定义Redis键名前缀常量
|
||||
const LOGIN_TYPE_KEY = 'login_types';
|
||||
const SYSTEM_CODE_KEY = 'system_codes';
|
||||
const CORP_ABBR_KEY = 'corp_abbrs';
|
||||
|
||||
/**
|
||||
* 检查并缓存独立的基础参数
|
||||
*/
|
||||
public function checkAndCacheBaseParams($loginType, $systemCode, $corpAbbr)
|
||||
{
|
||||
if (!$loginType && !$systemCode) {
|
||||
throw new BusinessException('header缺少必要参数');
|
||||
}
|
||||
|
||||
// 检查并缓存登录类型
|
||||
if (!$this->checkParamInCache(self::LOGIN_TYPE_KEY, $loginType)) {
|
||||
$this->cacheLoginTypes();
|
||||
if (!$this->checkParamInCache(self::LOGIN_TYPE_KEY, $loginType)) {
|
||||
throw new BusinessException('无效的登录方式');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查参数是否在Redis集合中
|
||||
*/
|
||||
private function checkParamInCache($cacheKey, $param)
|
||||
{
|
||||
return Redis::sIsMember($cacheKey, $param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存所有登录类型到集合
|
||||
*/
|
||||
private function cacheLoginTypes()
|
||||
{
|
||||
$cacheKey = self::LOGIN_TYPE_KEY;
|
||||
|
||||
// 如果集合已存在,直接返回
|
||||
if (Redis::exists($cacheKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$loginTypes = $this->getAllLoginTypes();
|
||||
if (empty($loginTypes)) {
|
||||
throw new BusinessException('未获取到登录类型数据');
|
||||
}
|
||||
|
||||
// 批量添加值到集合
|
||||
Redis::sAdd($cacheKey, ...$loginTypes);
|
||||
Redis::expire($cacheKey, 3600); // 1小时有效期
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存所有系统码到集合
|
||||
*/
|
||||
private function cacheSystemCodes()
|
||||
{
|
||||
$cacheKey = self::SYSTEM_CODE_KEY;
|
||||
|
||||
// 如果集合已存在,直接返回
|
||||
if (Redis::exists($cacheKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$systemCodes = $this->getAllSystemCodes();
|
||||
if (empty($systemCodes)) {
|
||||
throw new BusinessException('未获取到系统码数据');
|
||||
}
|
||||
|
||||
// 批量添加值到集合
|
||||
Redis::sAdd($cacheKey, ...$systemCodes);
|
||||
Redis::expire($cacheKey, 3600); // 1小时有效期
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存所有公司标识到集合
|
||||
*/
|
||||
private function cacheCorpAbbrs()
|
||||
{
|
||||
$cacheKey = self::CORP_ABBR_KEY;
|
||||
|
||||
// 如果集合已存在,直接返回
|
||||
if (Redis::exists($cacheKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$corpAbbrs = $this->getAllCorpAbbrs();
|
||||
if (empty($corpAbbrs)) {
|
||||
throw new BusinessException('未获取到公司标识数据');
|
||||
}
|
||||
|
||||
// 批量添加值到集合
|
||||
Redis::sAdd($cacheKey, ...$corpAbbrs);
|
||||
Redis::expire($cacheKey, 3600); // 1小时有效期
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有有效的登录类型
|
||||
*/
|
||||
private function getAllLoginTypes()
|
||||
{
|
||||
return ['upwd', 'feishu', 'qrcode']; // 示例数据
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有有效的系统码
|
||||
*/
|
||||
private function getAllSystemCodes()
|
||||
{
|
||||
return Systems::pluck('code')->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有有效的公司标识
|
||||
*/
|
||||
private function getAllCorpAbbrs()
|
||||
{
|
||||
return Corp::pluck('abbr')->toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\admin\validate\BrandSeriesValidate;
|
||||
use app\common\logic\BrandSeriesLogic;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\BrandSeries;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
|
||||
class BrandSeriesService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new BrandSeriesLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public function getList($params)
|
||||
{
|
||||
if (empty($params['brand_id']))
|
||||
throw new BusinessException('品牌id不能为空');
|
||||
$where = [];
|
||||
if(isset($params['brand_id']) && $params['brand_id'])
|
||||
$where[] = ['brand_id', '=', $params['brand_id']];
|
||||
return $this->logic->getList($where);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\BrandLogic;
|
||||
|
||||
class BrandService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new BrandLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
return $this->logic->getList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\CorpFeishuAppLogic;
|
||||
|
||||
class CorpFeishuAppService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new CorpFeishuAppLogic());
|
||||
}
|
||||
|
||||
public function getFeishuApp(int $corpId, int $systemId)
|
||||
{
|
||||
return $this->logic->getFeishuApp($corpId, $systemId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\CorpLogic;
|
||||
|
||||
class CorpService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new CorpLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取公司list
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
return $this->logic->getList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\BrandLogic;
|
||||
use QL\QueryList;
|
||||
|
||||
class CrawlService
|
||||
{
|
||||
public function brandSeries($brand)
|
||||
{
|
||||
$url = "https://www.dongchedi.com/search?currTab=6&keyword=".$brand.'&from=search_tab_er&api_param={"en_qc":+0}';
|
||||
$ql = QueryList::get($url );
|
||||
$series = [];
|
||||
$ql->find('div.card-name')->texts()->map(function($item) use(&$series) {
|
||||
$series[] = $item;
|
||||
});
|
||||
return $series;
|
||||
}
|
||||
|
||||
public function seriesModel($series)
|
||||
{
|
||||
$href = $this->modelSearch($series);
|
||||
|
||||
//例如 $seriesUrl = "https://www.dongchedi.com/auto/series/4865?anchorId=carModels"
|
||||
if (empty($href)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$seriesUrl = (strpos($href, 'http') === 0) ? $href : ("https://www.dongchedi.com" . $href);
|
||||
$ql = QueryList::get($seriesUrl);
|
||||
|
||||
$nodes = $ql->find('div.tw-grid div.tw-relative div.tw-items-center>a');
|
||||
$texts = $nodes->texts()->all();
|
||||
$links = $nodes->attrs('href')->all();
|
||||
$nodes = $ql->find('div.tw-grid div.tw-text-color-gray-800');
|
||||
$price = $nodes->texts()->all();
|
||||
|
||||
$results = [];
|
||||
foreach ($texts as $index => $text) {
|
||||
$link = $links[$index] ?? '';
|
||||
if (!empty($link) && strpos($link, 'http') !== 0) {
|
||||
$link = 'https://www.dongchedi.com' . $link;
|
||||
}
|
||||
$results[] = [
|
||||
'title' => trim($text),
|
||||
'link' => $link,
|
||||
'msrp' => (int)(str_replace("万", "", $price[$index]) * 10000) ?? 0,
|
||||
];
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
// public function modelDesc(array $models)
|
||||
// {
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* 返回车系地址
|
||||
* @param $series
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function modelSearch($series)
|
||||
{
|
||||
$url = "https://www.dongchedi.com/search?keyword=".$series;
|
||||
$ql = QueryList::get($url );
|
||||
$href = '';
|
||||
$ql->find('a.fold-btn')->attrs('href')
|
||||
->map(function ($item) use(&$href) {
|
||||
$href = $item;
|
||||
});
|
||||
return $href;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关键词搜索的更多页面,通过面包屑抓取品牌与系列
|
||||
* @param $series
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function crawlBrandSeries($series)
|
||||
{
|
||||
$url = "https://www.dongchedi.com/auto/series/" . $series . "?anchorId=carModels";
|
||||
$ql = QueryList::get($url);
|
||||
$result = $ql->find('div.breadcrumb_wrap__2GLeU span')->texts()->all();
|
||||
|
||||
return ['brand' => $result[2], 'series' => $result[3]];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\FinPaymentStock;
|
||||
use app\common\model\FinReceipt;
|
||||
use app\common\validate\FinPaymentApplyValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\FinPaymentApply;
|
||||
use support\Redis;
|
||||
use support\Request;
|
||||
|
||||
class FinPaymentApplyService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = FinPaymentApply::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = FinPaymentApplyValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'index'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'index':
|
||||
// ====== ====== 排序 ====== ======
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
// ====== ====== 筛选 ====== ======
|
||||
// 汇款国家
|
||||
if (isset($p['country_id']) && !empty($p['country_id'])) {
|
||||
$config['where']['country_id'] = $p['country_id'];
|
||||
}
|
||||
|
||||
// 收款账户筛选
|
||||
if (isset($p['account_id']) && !empty($p['account_id'])) {
|
||||
$config['where']['account_id'] = $p['account_id'];
|
||||
}
|
||||
|
||||
// 入账资料超时
|
||||
if (isset($p['scene']) && $p['scene'] == 'file_timeout') {
|
||||
$config['where']['claimed_at'] = ['between', [1, time()-24*60*60]];
|
||||
}
|
||||
|
||||
// 关键字
|
||||
if (isset($p['keyword']) && $p['keyword']) {
|
||||
$k = '%' . $p['keyword'] . '%';
|
||||
$config['orWhere'][] = ['remitter', 'like', $k];
|
||||
}
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'update':
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
$data['apply_no'] = $this->generateUniqueApplyNo();
|
||||
$data['doc_user_id'] = $request->user->uid;
|
||||
$data['voucher_file'] = json_encode($data['voucher_file']);
|
||||
$data['submit_files'] = json_encode($data['submit_files']);
|
||||
redis::set('stock_' . $data['doc_user_id'], json_encode($request->post('stock')), 'EX', 30);
|
||||
unset($data['stock']);
|
||||
if($data['voucher_file'] == '[]' || $data['voucher_file'] == '{}' || $data['voucher_file'] == '""')
|
||||
$data['voucher_file'] = '';
|
||||
if($data['submit_files'] == '[]' || $data['submit_files'] == '{}' || $data['submit_files'] == '""')
|
||||
$data['submit_files'] = '';
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
public function afterServiceStore($res)
|
||||
{
|
||||
$data = [
|
||||
'payment_apply_id' => $res['id'],
|
||||
];
|
||||
$piStock = json_decode(redis::get('stock_' . $res['doc_user_id']), true);
|
||||
redis::del('stock' . $res['doc_user_id']);
|
||||
foreach ($piStock as $stock) {
|
||||
foreach ($stock['stock_id'] as $v) {
|
||||
$data['stock_id'] = $v;
|
||||
$data['pi_no'] = $stock['pi_on'];
|
||||
FinPaymentStock::create($data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function beforeServiceUpdate($data, Request $request)
|
||||
{
|
||||
unset($data['stock']);
|
||||
$data['submit_files'] = json_encode($data['submit_files']);
|
||||
if($data['submit_files'] == '[]' || $data['submit_files'] == '{}' || $data['submit_files'] == '""')
|
||||
$data['submit_files'] = '';
|
||||
$data['voucher_file'] = json_encode($data['voucher_file']);
|
||||
if($data['voucher_file'] == '[]' || $data['voucher_file'] == '{}' || $data['voucher_file'] == '""')
|
||||
$data['voucher_file'] = '';
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
public function afterServiceUpdate($res, Request $request)
|
||||
{
|
||||
if($res->submit_files != '' && $res->receipt_id != 0)
|
||||
FinReceipt::where('id', $res->receipt_id)->update(['submit_files' => $res->submit_files]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一的付款申请编码
|
||||
* 格式:PA + 日期 + 6位字母数字组合
|
||||
*
|
||||
* @return string 唯一编码
|
||||
*/
|
||||
public function generateUniqueApplyNo()
|
||||
{
|
||||
$chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
$maxAttempts = 10; // 防止无限循环
|
||||
$secondChar = 'PA' . date('Ymd');
|
||||
|
||||
for ($attempt = 0; $attempt < $maxAttempts; $attempt++) {
|
||||
// 生成后6位随机字符
|
||||
$suffix = '';
|
||||
for ($i = 0; $i < 6; $i++) {
|
||||
$suffix .= $chars[rand(0, strlen($chars) - 1)];
|
||||
}
|
||||
|
||||
$applyNo = $secondChar . $suffix;
|
||||
|
||||
// 检查是否已存在
|
||||
$existing = FinPaymentApply::where('apply_no', $applyNo)->first();
|
||||
if (!$existing) {
|
||||
return $applyNo;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果1000次尝试后仍然重复,使用时间戳确保唯一性
|
||||
$timestamp = substr(time(), -6);
|
||||
return $secondChar . $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据相似度排序付款记录
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|\Illuminate\Pagination\LengthAwarePaginator
|
||||
*/
|
||||
public function complexQueryIndex(Request $request)
|
||||
{
|
||||
$limit = (int)$request->get('size', 15);
|
||||
$page = (int)$request->get('current', 1);
|
||||
$param = $request->all();
|
||||
|
||||
$where = [];
|
||||
$orWhere = [];
|
||||
|
||||
// 汇款国家
|
||||
if (isset($param['country_id']) && !empty($param['country_id'])) {
|
||||
$where[] = ['country_id', $param['country_id']];
|
||||
}
|
||||
// 收款账户筛选
|
||||
if (isset($param['account_id']) && !empty($param['account_id'])) {
|
||||
$where[] = ['account_id', $param['account_id']];
|
||||
}
|
||||
|
||||
// 入账资料超时
|
||||
if (isset($param['scene']) && $param['scene'] == 'file_timeout') {
|
||||
$where[] = ['submit_files', ''];
|
||||
$where[] = ['claimed_at', '<', time()-24*60*60];
|
||||
$where[] = ['claimed_at', '>', 1];
|
||||
}
|
||||
|
||||
// 关键字
|
||||
if (isset($param['keyword']) && $param['keyword']) {
|
||||
$k = '%' . $param['keyword'] . '%';
|
||||
$where[] = ['remitter', 'like', $k];
|
||||
}
|
||||
|
||||
// 构建查询
|
||||
$query = $this->modelClass::where($where);
|
||||
|
||||
// 是否已关联收款记录的筛选
|
||||
$correlation = $param['correlation']??'';
|
||||
if ($correlation === 'receipt') { //已关联
|
||||
$query->whereHas('receipt');
|
||||
} elseif ($correlation === 'unbind') { //未关联
|
||||
$query->whereDoesntHave('receipt');
|
||||
}
|
||||
|
||||
if(isset($param['scene']) && $param['scene'] == 'pending'){ //待入账列表
|
||||
$query->where('receipt_id', '>' ,'0');
|
||||
$query->where('submit_files','!=','');
|
||||
$query->whereNull('received_at');
|
||||
}
|
||||
|
||||
if($param['scene'] == 'delete'){ //查询作废数据
|
||||
$query->onlyTrashed();
|
||||
}elseif ($param['scene'] == 'all'){ //查询包含作废数据的全量数据
|
||||
$query->withTrashed();
|
||||
}
|
||||
|
||||
if ((isset($param['scene']) && ($param['scene'] == 'list' || $param['scene'] == 'pending'))|| empty($param['receipt_id']) ) {
|
||||
return $query->orderBy('id','desc')->paginate($limit, ['*'], 'page', $page);
|
||||
}
|
||||
|
||||
$receipt = FinReceipt::where('id', $param['receipt_id'])->first();
|
||||
$account_id = $receipt->account_id;
|
||||
$currency_id = $receipt->currency_id;
|
||||
$remitter = $receipt->remitter;
|
||||
$amount = $receipt->amount;
|
||||
|
||||
// 计算十天前的时间戳
|
||||
$sevenDaysAgo = time() - (10 * 24 * 60 * 60);
|
||||
|
||||
// 构建相似度排序逻辑
|
||||
$similarityOrder = [];
|
||||
|
||||
// 如果有传入参数,计算相似度
|
||||
if (!empty($account_id)) {
|
||||
$similarityOrder[] = "CASE WHEN account_id = {$account_id} THEN 0 ELSE 1 END";
|
||||
}
|
||||
|
||||
if (!empty($currency_id)) {
|
||||
$similarityOrder[] = "CASE WHEN currency_id = {$currency_id} THEN 0 ELSE 1 END";
|
||||
}
|
||||
|
||||
if (!empty($remitter)) {
|
||||
$similarityOrder[] = "CASE WHEN remitter = '{$remitter}' THEN 0 ELSE 1 END";
|
||||
}
|
||||
|
||||
if (!empty($amount)) {
|
||||
$amount = (float)$amount;
|
||||
$similarityOrder[] = "ABS(amount - {$amount})";
|
||||
$similarityOrder[] = "CASE WHEN (ABS(amount - {$amount}) / {$amount} * 100) <= 5 THEN 0 ELSE 1 END";
|
||||
}
|
||||
|
||||
// 构建排序SQL
|
||||
$orderByClause = "";
|
||||
if (!empty($similarityOrder)) {
|
||||
$orderByClause = "CASE
|
||||
WHEN created_at >= {$sevenDaysAgo} THEN
|
||||
(" . implode(' + ', $similarityOrder) . ")
|
||||
ELSE 0
|
||||
END ASC, ";
|
||||
}
|
||||
|
||||
$orderByClause .= "CASE
|
||||
WHEN created_at > {$sevenDaysAgo} THEN id
|
||||
ELSE 999999
|
||||
END DESC, ";
|
||||
|
||||
$orderByClause .= "id DESC";
|
||||
|
||||
$query->orderByRaw($orderByClause);
|
||||
|
||||
return $query->paginate($limit, ['*'], 'page', $page);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$res = FinPaymentApply::where('id', $id)->delete();
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\FinReceiptHisValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\FinReceiptHis;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
|
||||
class FinReceiptHisService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = FinReceiptHis::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = FinReceiptHisValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'index'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'index':
|
||||
if(empty($p['receipt_id'])){
|
||||
throw new BusinessException('receipt_id不能为空');
|
||||
}
|
||||
// ====== ====== 排序 ====== ======
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
// ====== ====== 筛选 ====== ======
|
||||
$config['where']['receipt_id'] = $p['receipt_id'];
|
||||
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\FinReceiptLogic;
|
||||
use app\common\model\FinPaymentApply;
|
||||
use app\common\model\FinPaymentStock;
|
||||
use app\common\model\FinReceiptHis;
|
||||
use app\common\validate\FinReceiptValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\FinReceipt;
|
||||
use support\exception\BusinessException;
|
||||
use support\Redis;
|
||||
use support\Request;
|
||||
|
||||
class FinReceiptService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = FinReceipt::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = FinReceiptValidate::class;
|
||||
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new FinReceiptLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'index'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'index':
|
||||
// ====== ====== 排序 ====== ======
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
// ====== ====== 筛选 ====== ======
|
||||
// 汇款国家
|
||||
if (isset($p['country_id']) && !empty($p['country_id'])) {
|
||||
$config['where']['country_id'] = $p['country_id'];
|
||||
}
|
||||
|
||||
// 没有付款记录的收款记录
|
||||
if (isset($p['payment_apply']) && $p['payment_apply'] == 'not') { //未认领
|
||||
$config['where']['payment_apply_id'] = 0;
|
||||
} elseif (isset($p['payment_apply']) && $p['payment_apply'] == 'already') { //已认领
|
||||
$config['where']['payment_apply_id'] = ['>', 0];
|
||||
} elseif (isset($p['payment_apply']) && $p['payment_apply'] == 'timeout') { //超时未认领
|
||||
$config['where']['payment_apply_id'] = 0;
|
||||
$config['where']['created_at'] = ['<' ,time() - 24*60*60];
|
||||
}
|
||||
|
||||
// 收款申请筛选
|
||||
if (isset($p['payment_apply_id']) && !empty($p['payment_apply_id'])) {
|
||||
$config['where']['payment_apply_id'] = $p['payment_apply_id'];
|
||||
}
|
||||
|
||||
// 收款账户筛选
|
||||
if (isset($p['account_id']) && !empty($p['account_id'])) {
|
||||
$config['where']['account_id'] = $p['account_id'];
|
||||
}
|
||||
|
||||
// 关键字
|
||||
if (isset($p['keyword']) && $p['keyword']) {
|
||||
$k = '%' . $p['keyword'] . '%';
|
||||
$config['orWhere'][] = ['remitter', 'like', $k];
|
||||
}
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'update':
|
||||
case 'payment':
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
if(isset($data['payment_apply_id']) && empty($data['payment_apply_id'])){
|
||||
unset($data['payment_apply_id']);
|
||||
}
|
||||
$data['receipt_no'] = $this->generateUniqueReceipt();
|
||||
$data['arrived_at'] = strtotime( $data['arrived_at']);
|
||||
$data['created_by'] = $request->user->uid;
|
||||
$data['updated_by'] = $request->user->uid;
|
||||
$data['fx_receipt_file'] = json_encode($data['fx_receipt_file']);
|
||||
if($data['fx_receipt_file'] == '[]' || $data['fx_receipt_file'] == '{}' || $data['fx_receipt_file'] == '""')
|
||||
$data['fx_receipt_file'] = '';
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function afterServiceStore($res)
|
||||
{
|
||||
$receipt = FinReceipt::where('id',$res->id)->first()->toArray();
|
||||
$receipt = array_merge($receipt,['receipt_id' => $res->id]);
|
||||
unset($receipt['id']);
|
||||
FinReceiptHis::create($receipt);
|
||||
}
|
||||
|
||||
public function beforeServiceUpdate($data, Request $request)
|
||||
{
|
||||
$data['updated_by'] = $request->user->uid;
|
||||
if(isset($data['arrived_at']))
|
||||
$data['arrived_at'] = strtotime($data['arrived_at']);
|
||||
if(isset($data['received_at']))
|
||||
$data['received_at'] = strtotime($data['received_at']);
|
||||
|
||||
$data['fx_receipt_file'] = json_encode($data['fx_receipt_file']);
|
||||
if($data['fx_receipt_file'] == '[]' || $data['fx_receipt_file'] == '{}' || $data['fx_receipt_file'] == '""')
|
||||
$data['fx_receipt_file'] = '';
|
||||
return $data;
|
||||
}
|
||||
public function afterServiceUpdate($res)
|
||||
{
|
||||
$receipt = FinReceipt::where('id',$res['id'])->first()->toArray();
|
||||
$receipt = array_merge($receipt,['receipt_id' => $res['id']]);
|
||||
unset($receipt['id']);
|
||||
FinReceiptHis::create($receipt);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成唯一的付款申请编码
|
||||
* 格式:PA + 日期 + 6位字母数字组合
|
||||
*
|
||||
* @return string 唯一编码
|
||||
*/
|
||||
public function generateUniqueReceipt()
|
||||
{
|
||||
$chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
$maxAttempts = 10; // 防止无限循环
|
||||
$secondChar = 'RE' . date('Ymd');
|
||||
|
||||
for ($attempt = 0; $attempt < $maxAttempts; $attempt++) {
|
||||
// 生成后6位随机字符
|
||||
$suffix = '';
|
||||
for ($i = 0; $i < 6; $i++) {
|
||||
$suffix .= $chars[rand(0, strlen($chars) - 1)];
|
||||
}
|
||||
|
||||
$ReceiptNo = $secondChar . $suffix;
|
||||
|
||||
// 检查是否已存在
|
||||
$existing = FinReceipt::where('receipt_no', $ReceiptNo)->first();
|
||||
if (!$existing) {
|
||||
return $ReceiptNo;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果1000次尝试后仍然重复,使用时间戳确保唯一性
|
||||
$timestamp = substr(time(), -6);
|
||||
return $secondChar . $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据相似度排序付款记录
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|\Illuminate\Pagination\LengthAwarePaginator
|
||||
*/
|
||||
public function complexQueryIndex(Request $request)
|
||||
{
|
||||
$limit = (int)$request->get('size', 15);
|
||||
$page = (int)$request->get('current', 1);
|
||||
$param = $request->all();
|
||||
|
||||
if(isset($param['voucher_no_timeout_hour'])){
|
||||
redis::set('voucher_no_timeout_hour', $param['voucher_no_timeout_hour'], 'EX', 30);
|
||||
}
|
||||
|
||||
$where = [];
|
||||
|
||||
// 汇款国家
|
||||
if (isset($param['country_id']) && !empty($param['country_id'])) {
|
||||
$where[] = ['country_id', $param['country_id']];
|
||||
}
|
||||
// 收款账户筛选
|
||||
if (isset($param['account_id']) && !empty($param['account_id'])) {
|
||||
$where[] = ['account_id', $param['account_id']];
|
||||
}
|
||||
// 收款申请筛选
|
||||
if (isset($param['payment_apply_id']) && !empty($param['payment_apply_id'])) {
|
||||
$where[]['payment_apply_id'] = $param['payment_apply_id'];
|
||||
}
|
||||
|
||||
// 关键字
|
||||
if (isset($param['keyword']) && $param['keyword']) {
|
||||
$k = '%' . $param['keyword'] . '%';
|
||||
$where[] = ['remitter', 'like', $k];
|
||||
}
|
||||
|
||||
// 构建查询
|
||||
$query = $this->modelClass::where($where);
|
||||
|
||||
// 收款记录绑定情况
|
||||
if (isset($param['payment_apply']) && $param['payment_apply'] == 'not') {
|
||||
$query->where('payment_apply_id', 0);
|
||||
} elseif (isset($param['payment_apply']) && $param['payment_apply'] == 'already') {
|
||||
$query->where('payment_apply_id', '>', 0);
|
||||
} elseif (isset($param['payment_apply']) && $param['payment_apply'] == 'timeout') { //超时未认领
|
||||
$query->where('payment_apply_id', 0);
|
||||
$query->where('created_at', '<' ,time() - 24*60*60);
|
||||
}
|
||||
|
||||
if(isset($param['scene']) && $param['scene'] == 'pending'){ //待入账列表
|
||||
$query->where('payment_apply_id', '>' ,'0');
|
||||
$query->where('submit_files','!=','');
|
||||
}
|
||||
|
||||
if (isset($param['scene']) && ($param['scene'] == 'list' ||$param['scene'] == 'pending')) {
|
||||
return $query->paginate($limit, ['*'], 'page', $page);
|
||||
}
|
||||
|
||||
// 计算七天前的时间戳
|
||||
$sevenDaysAgo = time() - (10 * 24 * 60 * 60);
|
||||
|
||||
// 构建相似度排序逻辑
|
||||
$similarityOrder = [];
|
||||
|
||||
// 如果有传入参数,计算相似度
|
||||
if (isset($param['account_id']) && !empty($param['account_id'])) {
|
||||
$similarityOrder[] = "CASE WHEN account_id = {$param['account_id']} THEN 0 ELSE 1 END";
|
||||
}
|
||||
|
||||
if (isset($param['country_id']) && !empty($param['country_id'])) {
|
||||
$similarityOrder[] = "CASE WHEN country_id = {$param['country_id']} THEN 0 ELSE 1 END";
|
||||
}
|
||||
|
||||
if (isset($param['keyword']) && $param['keyword']) {
|
||||
$keyword = addslashes($param['keyword']);
|
||||
$similarityOrder[] = "CASE WHEN remitter LIKE '%{$keyword}%' THEN 0 ELSE 1 END";
|
||||
}
|
||||
|
||||
if (isset($param['amount']) && !empty($param['amount'])) {
|
||||
$amount = (float)$param['amount'];
|
||||
$similarityOrder[] = "ABS(amount - {$amount})";
|
||||
}
|
||||
|
||||
// 构建排序SQL
|
||||
$orderByClause = "";
|
||||
if (!empty($similarityOrder)) {
|
||||
$orderByClause = "CASE
|
||||
WHEN created_at >= {$sevenDaysAgo} THEN
|
||||
(" . implode(' + ', $similarityOrder) . ")
|
||||
ELSE 999999
|
||||
END ASC, ";
|
||||
}
|
||||
|
||||
$orderByClause .= "CASE
|
||||
WHEN created_at < {$sevenDaysAgo} THEN id
|
||||
ELSE 0
|
||||
END DESC";
|
||||
|
||||
$query->orderByRaw($orderByClause);
|
||||
|
||||
return $query->paginate($limit, ['*'], 'page', $page);
|
||||
}
|
||||
|
||||
public function credit($id, $exchange_rate)
|
||||
{
|
||||
$finReceipt = FinReceipt::find($id);
|
||||
if(!empty($finReceipt->received_at)){
|
||||
throw new BusinessException('该记录已将确认入账');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'received_at' => time(),
|
||||
'exchange_rate' => $exchange_rate,
|
||||
'total_amount_cny' => round($finReceipt['amount']*$exchange_rate,2),
|
||||
];
|
||||
$res = $this->logic->credit($id,$data);
|
||||
FinPaymentApply::where('id', $finReceipt->payment_apply_id)->update(['received_at' => $data['received_at']]);
|
||||
$this->afterServiceUpdate(['id'=>$id]);
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新:绑定收款记录,计算折让金额
|
||||
* @param Request $request
|
||||
* @param array $data
|
||||
* @param string $scene
|
||||
* @return mixed
|
||||
*/
|
||||
public function serviceUpdatePayment(Request $request, array $data = [], string $scene = 'payment')
|
||||
{
|
||||
$payment_apply_id = $request->input('payment_apply_id');
|
||||
|
||||
$id = $request->input('id');
|
||||
$data = $this->preProcess(ucfirst($scene), $data, $request);
|
||||
$config = $this->buildQueryConfig($request, $scene);
|
||||
FinPaymentApply::where('id', $payment_apply_id)->update(['receipt_id' => $id, 'claimed_at' => time(), 'claimed_by' => $request->user->uid]);
|
||||
FinPaymentStock::where('payment_apply_id', $payment_apply_id)->update(['receipt_id' => $id]);
|
||||
|
||||
//折让金额
|
||||
$payment = FinPaymentApply::where('id', $payment_apply_id)->first();
|
||||
$receipt = FinReceipt::find($id);
|
||||
$data['discount_amount'] = $payment->amount - $receipt->amount ?? 0;
|
||||
$data['submit_files'] = $payment->submit_files ?? '';
|
||||
|
||||
$updated = $this->logicUpdateBy($config, $data);
|
||||
return $this->postProcess(ucfirst($scene), $data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\FinanceReconDubaiFilesValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\FinanceReconDubaiFiles;
|
||||
use app\common\utils\excel\ExcelImportTrait;
|
||||
use support\Request;
|
||||
|
||||
/**
|
||||
* FinanceReconDubaiFilesService
|
||||
*
|
||||
* - 提供两类导入:
|
||||
* 1) M项目对账明细(sheet: M项目对账明细)
|
||||
* 2) 迪拜两表合并(sheets: Stock in Jebel Ali / Under shipping)
|
||||
*
|
||||
* - 公共导入流程复用 ExcelImportTrait
|
||||
* - OSS 读取通过你的 OssService->generatePrivateUrl() 完成
|
||||
*/
|
||||
class FinanceReconDubaiFilesService
|
||||
{
|
||||
use CrudServiceTrait;
|
||||
use ExcelImportTrait; // 复用通用导入方法
|
||||
|
||||
/** 指定当前要操作的模型(用于 CrudServiceTrait) */
|
||||
protected string $modelClass = FinanceReconDubaiFiles::class;
|
||||
|
||||
/** 验证器 */
|
||||
protected $validator = FinanceReconDubaiFilesValidate::class;
|
||||
|
||||
/** 获取验证器实例 */
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入前置:将上传组件的结构转为 *_url / *_name,并记录创建人
|
||||
*/
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
$data['created_by'] = $request->user->uid ?? 0;
|
||||
$data['caiwu_file_url'] = $data['caiwu_file']['url'] ?? '';
|
||||
$data['caiwu_file_name'] = $data['caiwu_file']['name'] ?? '';
|
||||
$data['dubai_file_url'] = $data['dubai_file']['url'] ?? '';
|
||||
$data['dubai_file_name'] = $data['dubai_file']['name'] ?? '';
|
||||
return $data;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 一、M项目对账明细 导入配置(sheet: M项目对账明细)
|
||||
* ============================================================ */
|
||||
|
||||
/** 中文表头 => 目标字段名 */
|
||||
protected array $headerMapM = [
|
||||
'车架号' => 'vin',
|
||||
'开票价' => 'invoice_price',
|
||||
'实际采购价' => 'actual_purchase_price',
|
||||
'开票价和实际采购价差额' => 'invoice_vs_purchase_diff',
|
||||
'车源中介费' => 'source_broker_fee',
|
||||
'配件' => 'parts_fee',
|
||||
'停车费' => 'parking_fee',
|
||||
'保险费' => 'insurance_fee',
|
||||
'车辆手续费' => 'vehicle_service_fee',
|
||||
'检测费' => 'inspection_fee',
|
||||
'购置税' => 'purchase_tax',
|
||||
'汽车其他费用' => 'other_vehicle_fee',
|
||||
'转移待出口' => 'transfer_to_export',
|
||||
'国际运费' => 'freight_international',
|
||||
'国内运费1' => 'freight_domestic_1',
|
||||
'国内运费2' => 'freight_domestic_2',
|
||||
'报关费及港杂费' => 'customs_port_fee',
|
||||
'注销费' => 'cancellation_fee',
|
||||
'车船税' => 'vehicle_vessel_tax',
|
||||
'其他财务费用' => 'other_finance_fee',
|
||||
'汽车小额杂费' => 'minor_vehicle_misc',
|
||||
'上牌费' => 'registration_fee',
|
||||
'其他保险费' => 'other_insurance_fee',
|
||||
'油补' => 'fuel_subsidy',
|
||||
'快递费' => 'express_fee',
|
||||
'国内成本合计' => 'domestic_cost_total',
|
||||
'退税额' => 'tax_refund_amount',
|
||||
'cif杰贝阿里成本价' => 'cif_jebel_ali_cost',
|
||||
'范经理发车看板CIF' => 'fan_manager_cif',
|
||||
'财务-范经理 差额' => 'finance_vs_fan_diff',
|
||||
];
|
||||
|
||||
/** 需要转为 decimal 的目标字段 */
|
||||
protected array $decimalFieldsM = [
|
||||
'invoice_price','actual_purchase_price','invoice_vs_purchase_diff',
|
||||
'source_broker_fee','parts_fee','parking_fee','insurance_fee','vehicle_service_fee','inspection_fee',
|
||||
'purchase_tax','other_vehicle_fee','transfer_to_export',
|
||||
'freight_international','freight_domestic_1','freight_domestic_2','customs_port_fee',
|
||||
'cancellation_fee','vehicle_vessel_tax','other_finance_fee','minor_vehicle_misc',
|
||||
'registration_fee','other_insurance_fee','fuel_subsidy','express_fee',
|
||||
'domestic_cost_total','tax_refund_amount','cif_jebel_ali_cost','fan_manager_cif','finance_vs_fan_diff',
|
||||
];
|
||||
|
||||
/**
|
||||
* M项目对账明细导入
|
||||
*
|
||||
* @param string $file 可为“签名 URL”或“OSS 对象键”
|
||||
* @param bool $isUrl 若传入的是已签名 URL,请设 true;若是对象键,设 false
|
||||
* @param bool $insertToDb 是否立即入库
|
||||
*
|
||||
* 返回:['sheet','total_rows','skipped','errors','to_import','inserted','preview_3',('error'?)]
|
||||
*/
|
||||
public function mImport(string $file, bool $isUrl = true, bool $insertToDb = true): array
|
||||
{
|
||||
$sheet = 'M项目对账明细';
|
||||
|
||||
// 允许传对象键:当 isUrl=false 且非 http(s) 时,自动用 OssService 签名
|
||||
if ($isUrl === false && !preg_match('#^https?://#i', $file)) {
|
||||
$file = $this->ossSignedUrl($file);
|
||||
$isUrl = true;
|
||||
}
|
||||
|
||||
$rows = $this->readSheetRows($file, $sheet, $isUrl, headerRow: 1);
|
||||
$mapped = [];
|
||||
$skipped = 0;
|
||||
$errors = 0;
|
||||
|
||||
foreach ($rows as $row) {
|
||||
try {
|
||||
if ($this->shouldSkipByVinAliases($row, ['车架号'])) { $skipped++; continue; }
|
||||
$rec = $this->mapAndNormalizeRow($row, $this->headerMapM, $this->decimalFieldsM);
|
||||
$this->stamp($rec);
|
||||
$mapped[] = $rec;
|
||||
} catch (\Throwable $e) {
|
||||
// 单行异常不阻断全局导入
|
||||
$errors++; continue;
|
||||
}
|
||||
}
|
||||
|
||||
$result = [
|
||||
'sheet' => $sheet,
|
||||
'total_rows' => count($rows),
|
||||
'skipped' => $skipped,
|
||||
'errors' => $errors,
|
||||
'to_import' => count($mapped),
|
||||
];
|
||||
|
||||
if ($insertToDb) {
|
||||
// 注意表名:按你的业务这里写入 finance_recon_m_detail
|
||||
$ret = $this->batchInsert('finance_recon_m_detail', $mapped);
|
||||
$result['inserted'] = $ret['inserted'];
|
||||
if ($ret['error']) $result['error'] = 'Database insert error: ' . $ret['error'];
|
||||
} else {
|
||||
$result['inserted'] = 0;
|
||||
}
|
||||
|
||||
$result['preview_3'] = array_slice($mapped, 0, 3);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/** M项目对账明细:从 OSS 对象键导入(语义化便捷入口) */
|
||||
public function mImportFromOssKey(string $objectKey, bool $insertToDb = true): array
|
||||
{
|
||||
$signedUrl = $this->ossSignedUrl($objectKey);
|
||||
return $this->mImport($signedUrl, true, $insertToDb);
|
||||
}
|
||||
|
||||
/** M项目对账明细:从已签名 URL 导入(语义化便捷入口) */
|
||||
public function mImportFromSignedUrl(string $signedUrl, bool $insertToDb = true): array
|
||||
{
|
||||
return $this->mImport($signedUrl, true, $insertToDb);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 二、迪拜两表合并 导入配置(sheets: Stock in Jebel Ali / Under shipping)
|
||||
* ============================================================ */
|
||||
|
||||
/** 表头映射(已兼容不一致列名:VIN NO/车架号、国际运费和杂费/SHIPPING COST) */
|
||||
protected array $headerMapDubai = [
|
||||
'VIN NO' => 'vin', '车架号' => 'vin',
|
||||
'开票价' => 'invoice_price',
|
||||
'中介费' => 'broker_fee',
|
||||
'购置税' => 'purchase_tax',
|
||||
'退税' => 'tax_refund',
|
||||
'不含税车价' => 'price_ex_vat',
|
||||
'费用' => 'fee_total',
|
||||
'国内运费' => 'domestic_freight',
|
||||
'FCA成本价' => 'fca_cost',
|
||||
'FCA成本价汇率' => 'fca_fx',
|
||||
'国际运费和杂费' => 'shipping_cost',
|
||||
'SHIPPING COST' => 'shipping_cost',
|
||||
'运费汇率' => 'shipping_fx',
|
||||
'CIF 杰贝阿里成本价' => 'cif_jebel_ali_cost',
|
||||
'CIF RMB' => 'cif_rmb', // Under shipping 没有该列,将在逻辑中推导
|
||||
];
|
||||
|
||||
/** 需要转为 decimal 的目标字段(汇率字段使用 DECIMAL(18,6) 建表) */
|
||||
protected array $decimalFieldsDubai = [
|
||||
'invoice_price','broker_fee','purchase_tax','tax_refund','price_ex_vat',
|
||||
'fee_total','domestic_freight','fca_cost','fca_fx',
|
||||
'shipping_cost','shipping_fx','cif_jebel_ali_cost','cif_rmb',
|
||||
];
|
||||
|
||||
/**
|
||||
* 迪拜两表合并导入(Stock in Jebel Ali / Under shipping)
|
||||
*
|
||||
* 缺失值规则:
|
||||
* - Under shipping 无 “CIF RMB”,尝试:cif_rmb = cif_jebel_ali_cost × shipping_fx
|
||||
* 若运费汇率缺失则用 fca_fx 兜底,都没有则置 NULL。
|
||||
*
|
||||
* 返回:['sheets','total_rows','skipped','to_import','inserted','preview_5',('error'?)]
|
||||
*/
|
||||
public function dImport(string $file, bool $isUrl = false, bool $insertToDb = true): array
|
||||
{
|
||||
// 允许传对象键:当 isUrl=false 且非 http(s) 时,自动用 OssService 签名
|
||||
if ($isUrl === false && !preg_match('#^https?://#i', $file)) {
|
||||
$file = $this->ossSignedUrl($file);
|
||||
$isUrl = true;
|
||||
}
|
||||
|
||||
$sheets = ['Stock in Jebel Ali', 'Under shipping'];
|
||||
$parsed = [];
|
||||
|
||||
// 逐 Sheet 读取
|
||||
foreach ($sheets as $sheet) {
|
||||
$parsed[$sheet] = $this->readSheetRows($file, $sheet, $isUrl, headerRow: 1);
|
||||
}
|
||||
|
||||
// 行处理与合并
|
||||
$rowsAll = [];
|
||||
$skipped = 0;
|
||||
|
||||
foreach ($sheets as $sheet) {
|
||||
foreach ($parsed[$sheet] as $row) {
|
||||
if ($this->shouldSkipByVinAliases($row, ['VIN NO','车架号'])) { $skipped++; continue; }
|
||||
|
||||
// 映射 + 数值规范化
|
||||
$rec = $this->mapAndNormalizeRow($row, $this->headerMapDubai, $this->decimalFieldsDubai);
|
||||
|
||||
// Under shipping 无 CIF RMB:尝试用汇率推导
|
||||
if (empty($rec['cif_rmb'])) {
|
||||
$cif = $rec['cif_jebel_ali_cost'] ?? null;
|
||||
$fx = $rec['shipping_fx'] ?? null;
|
||||
if ($cif !== null && $fx !== null) {
|
||||
$rec['cif_rmb'] = round($cif * $fx, 2);
|
||||
} elseif ($cif !== null && !empty($rec['fca_fx'])) {
|
||||
$rec['cif_rmb'] = round($cif * (float)$rec['fca_fx'], 2);
|
||||
} else {
|
||||
$rec['cif_rmb'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 统一 VIN 与来源
|
||||
$rec['vin'] = $this->pickFirstNonEmpty($row, ['VIN NO','车架号']);
|
||||
$rec['source_sheet'] = $sheet;
|
||||
|
||||
$this->stamp($rec);
|
||||
$rowsAll[] = $rec;
|
||||
}
|
||||
}
|
||||
|
||||
// 结果与入库
|
||||
$result = [
|
||||
'sheets' => $sheets,
|
||||
'total_rows' => array_sum(array_map('count', $parsed)),
|
||||
'skipped' => $skipped,
|
||||
'to_import' => count($rowsAll),
|
||||
];
|
||||
|
||||
if ($insertToDb) {
|
||||
// 注意表名:按你的业务这里写入 finance_recon_d_detail
|
||||
$ret = $this->batchInsert('finance_recon_d_detail', $rowsAll);
|
||||
$result['inserted'] = $ret['inserted'];
|
||||
if ($ret['error']) $result['error'] = 'Database insert error: ' . $ret['error'];
|
||||
} else {
|
||||
$result['inserted'] = 0;
|
||||
}
|
||||
|
||||
$result['preview_5'] = array_slice($rowsAll, 0, 5);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/** 迪拜两表:从 OSS 对象键导入(语义化便捷入口) */
|
||||
public function dImportFromOssKey(string $objectKey, bool $insertToDb = true): array
|
||||
{
|
||||
$signedUrl = $this->ossSignedUrl($objectKey);
|
||||
return $this->dImport($signedUrl, true, $insertToDb);
|
||||
}
|
||||
|
||||
/** 迪拜两表:从已签名 URL 导入(语义化便捷入口) */
|
||||
public function dImportFromSignedUrl(string $signedUrl, bool $insertToDb = true): array
|
||||
{
|
||||
return $this->dImport($signedUrl, true, $insertToDb);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\InquiryTransmitConfigValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\InquiryTransmitConfig;
|
||||
use support\Request;
|
||||
|
||||
class InquiryTransmitConfigService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = InquiryTransmitConfig::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = InquiryTransmitConfigValidate::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':
|
||||
$config['where']['status'] = 1;
|
||||
$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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\InquiryTransmitValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\InquiryTransmit;
|
||||
use support\Request;
|
||||
|
||||
class InquiryTransmitService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = InquiryTransmit::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = InquiryTransmitValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/** 创建 */
|
||||
public function serviceStore(Request $request, array $data = [], string $domain = '')
|
||||
{
|
||||
$data['email'] = $data['Email'];
|
||||
$data['name'] = $data['Name'];
|
||||
$data['tel'] = $data['Tel'];
|
||||
$data['company'] = $data['Company'];
|
||||
$data['country'] = $data['Country'];
|
||||
$data['form_Url'] = $data['Form Url'];
|
||||
$data['message'] = $data['Message'];
|
||||
$data['ip_location'] = $data['IpLocation'];
|
||||
$data['ip'] = $data['Ip'];
|
||||
$data['domain'] = $domain;
|
||||
|
||||
return InquiryTransmit::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 CrudUtil 查询配置
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'default':
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'index':
|
||||
// 域名
|
||||
if (isset($p['domain']) && !empty($p['domain'])) {
|
||||
$config['where']['domain'] = $p['domain'];
|
||||
}
|
||||
// 关键字
|
||||
if (isset($p['keyword']) && $p['keyword']) {
|
||||
$k = '%' . $p['keyword'] . '%';
|
||||
foreach (['email', 'name', 'tel', 'country', 'message', 'form_url'] as $col) {
|
||||
$config['orWhere'][] = [$col, 'like', $k];
|
||||
}
|
||||
}
|
||||
$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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\InvItemLogic;
|
||||
use app\common\validate\InvItemValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\InvItem;
|
||||
use support\Request;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class InvItemService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = InvItem::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = InvItemValidate::class;
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new InvItemLogic());
|
||||
}
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
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']['sort'] = 'desc';
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'index':
|
||||
$config['where']['status'] = 1;
|
||||
|
||||
// 关键字
|
||||
if (isset($p['keyword']) && $p['keyword']) {
|
||||
$k = '%' . $p['keyword'] . '%';
|
||||
foreach (['item_name'] as $col) {
|
||||
$config['orWhere'][] = [$col, 'like', $k];
|
||||
}
|
||||
}
|
||||
|
||||
$config['order']['sort'] = 'desc';
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 8-12 位的物品编码(默认10位)
|
||||
*
|
||||
* @param int $length 编码长度,默认为10(范围 8-12)
|
||||
* @return string 返回大写的字母数字组合编码
|
||||
*/
|
||||
private function generateItemCode($length = 10)
|
||||
{
|
||||
// 排除易混淆字符:0, O, o, 1, I, l
|
||||
$chars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
|
||||
$code = '';
|
||||
$maxIndex = strlen($chars) - 1;
|
||||
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$code .= $chars[mt_rand(0, $maxIndex)];
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
|
||||
public function beforeServiceStore($data, Request $request): array
|
||||
{
|
||||
$data['item_code'] = $this->generateItemCode();
|
||||
$data['category_id'] = 0;
|
||||
$data['spec_model'] = '';
|
||||
$data['unit'] = '件';
|
||||
$data['is_consumable'] = 0;
|
||||
$data['stock_qty'] = $data['stock_qty']??1;
|
||||
$data['location'] = '';
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 变动物品库存数量
|
||||
*
|
||||
* @param int $itemId 物品ID
|
||||
* @param int $changeQty 变动数量:>0 入库,<0 出库
|
||||
* @param bool $allowNegative 是否允许库存变成负数,默认不允许
|
||||
*
|
||||
* @return InvItem 最新的物品记录
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function changeStock(int $itemId, int $changeQty, bool $allowNegative = false): InvItem
|
||||
{
|
||||
if ($changeQty === 0) {
|
||||
throw new BusinessException('库存变动数量不能为 0');
|
||||
}
|
||||
|
||||
$now = time();
|
||||
|
||||
// 构建查询
|
||||
$query = InvItem::query()->where('id', $itemId);
|
||||
|
||||
// 如果不允许负数,并且是出库场景(变动为负)
|
||||
if (! $allowNegative && $changeQty < 0) {
|
||||
// 要保证:当前 stock_qty >= 出库数量
|
||||
$query->where('stock_qty', '>=', -$changeQty);
|
||||
}
|
||||
|
||||
// 使用 increment 实现:UPDATE inv_item SET stock_qty = stock_qty + ?, updated_at = ? WHERE ...
|
||||
$affected = $query->increment('stock_qty', $changeQty, [
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
if ($affected === 0) {
|
||||
// 更新不到行:
|
||||
// 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);
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* 出库(减库存,默认不允许负数)
|
||||
*/
|
||||
public function stockOut(int $itemId, int $qty, bool $allowNegative = false): InvItem
|
||||
{
|
||||
if ($qty <= 0) {
|
||||
throw new BusinessException('出库数量必须大于 0');
|
||||
}
|
||||
return $this->changeStock($itemId, -$qty, $allowNegative);
|
||||
}
|
||||
|
||||
/**
|
||||
* 入库(加库存)
|
||||
*/
|
||||
public function stockIn(int $itemId, int $qty): InvItem
|
||||
{
|
||||
if ($qty <= 0) {
|
||||
throw new BusinessException('入库数量必须大于 0');
|
||||
}
|
||||
return $this->changeStock($itemId, $qty, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取车型list
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
return $this->logic->getList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\InvRequisitionApproveValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\InvRequisitionApprove;
|
||||
|
||||
class InvRequisitionApproveService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = InvRequisitionApprove::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = InvRequisitionApproveValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\InvRequisitionAttachmentValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\InvRequisitionAttachment;
|
||||
|
||||
class InvRequisitionAttachmentService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = InvRequisitionAttachment::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = InvRequisitionAttachmentValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\InvRequisitionItemReturnAttachmentValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\InvRequisitionItemReturnAttachment;
|
||||
|
||||
class InvRequisitionItemReturnAttachmentService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = InvRequisitionItemReturnAttachment::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = InvRequisitionItemReturnAttachmentValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\InvRequisition;
|
||||
use app\common\model\InvRequisitionItem;
|
||||
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;
|
||||
|
||||
class InvRequisitionItemReturnService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = InvRequisitionItemReturn::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = InvRequisitionItemReturnValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将二维数组按指定 key 重组为关联数组,该 key 的值作为新数组的键,
|
||||
* 其余元素组成子数组作为值。
|
||||
*
|
||||
* @param array $array 原始二维数组
|
||||
* @param string $keyField 用作新键的字段名(如 'id')
|
||||
* @return array 重组后的数组
|
||||
*/
|
||||
private function groupArrayByKey($array, $keyField = 'id')
|
||||
{
|
||||
$result = [];
|
||||
foreach ($array as $item) {
|
||||
if (!isset($item[$keyField])) {
|
||||
continue; // 跳过没有该 key 的项
|
||||
}
|
||||
$key = $item[$keyField];
|
||||
// 移除用作键的字段
|
||||
unset($item[$keyField]);
|
||||
$result[$key] = $item;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建物品归还申请前置处理
|
||||
*
|
||||
* @param array $data 归还申请数据
|
||||
* @param Request $request 请求对象
|
||||
* @return array 处理后的数据
|
||||
*/
|
||||
public function beforeServiceStore($data, Request $request): array
|
||||
{
|
||||
try {
|
||||
// // 模拟数据
|
||||
// $data = [
|
||||
// [
|
||||
// 'requisition_item_id' => 9,
|
||||
// 'return_qty' => 1,
|
||||
// 'apply_remark' => '申请备注',
|
||||
// 'attachment' => [
|
||||
// [
|
||||
// 'original_name' => '附件1.jpg',
|
||||
// 'file_path' => '/uploads/2023/07/01/attachment1.jpg'
|
||||
// ],
|
||||
// [
|
||||
// 'original_name' => '附件2.jpg',
|
||||
// 'file_path' => '/uploads/2023/07/01/attachment2.jpg'
|
||||
// ]
|
||||
// ]
|
||||
// ]
|
||||
// ];
|
||||
|
||||
// 获取所有申请项ID
|
||||
$reqItemIds = array_column($data, 'requisition_item_id');
|
||||
|
||||
// 参数校验
|
||||
if (empty($reqItemIds)) {
|
||||
throw new BusinessException('未提供有效的申请项ID');
|
||||
}
|
||||
|
||||
// 将申请项按 ID 重组为关联数组
|
||||
$newReqItems = $this->groupArrayByKey($data, 'requisition_item_id');
|
||||
|
||||
// 获取申请项明细
|
||||
$reqItemsArr = InvRequisitionItem::whereIn('id', $reqItemIds)->get()->toArray();
|
||||
|
||||
// 检查是否获取到有效数据
|
||||
if (empty($reqItemsArr)) {
|
||||
throw new BusinessException('未找到对应的申请项');
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
$userService = new UserService();
|
||||
$user = $userService->getUserInfo($request->user->uid, '');
|
||||
|
||||
$arr = [];
|
||||
foreach ($reqItemsArr as $reqItem) {
|
||||
$reqItemId = $reqItem['id'];
|
||||
|
||||
// 检查是否有对应的新申请项数据
|
||||
if (!isset($newReqItems[$reqItemId])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arr[] = [
|
||||
'requisition_id' => $reqItem['requisition_id'],
|
||||
'requisition_item_id' => $reqItemId,
|
||||
'item_id' => $reqItem['item_id'],
|
||||
'apply_user_id' => $user['user']['id'],
|
||||
'apply_user_name' => $user['user']['name'],
|
||||
'return_qty' => $newReqItems[$reqItemId]['return_qty'],
|
||||
'apply_remark' => $newReqItems[$reqItemId]['apply_remark'] ?? '',
|
||||
'attachment' => $newReqItems[$reqItemId]['attachment'],
|
||||
'return_at' => time()
|
||||
];
|
||||
}
|
||||
|
||||
return $arr;
|
||||
} catch (BusinessException $e) {
|
||||
throw $e;
|
||||
} catch (\Throwable $th) {
|
||||
throw new BusinessException('创建物品归还申请失败:' . $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理物品申请
|
||||
*
|
||||
* @param Request $request
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function serviceStore(Request $request, array $data, string $scene = '')
|
||||
{
|
||||
try {
|
||||
// 关联表增加事务处理
|
||||
return Db::transaction(function () use ($request, $data) {
|
||||
$data = $this->preProcess('Store', $data, $request);
|
||||
$dl = $this->getDataLimitFromRequest($request);
|
||||
foreach ($data as $item) {
|
||||
$created = $this->logicCreate($item, $dl);
|
||||
$this->processRequisitionItemReturnAttachment($created, $item['attachment']);
|
||||
}
|
||||
return $this->postProcess('Store', $created);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
throw new BusinessException("创建物品申请失败:" . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新物品归还申请前置处理
|
||||
*
|
||||
* @param array $data 归还申请数据
|
||||
* @param Request $request 请求对象
|
||||
* @return array 处理后的数据
|
||||
*/
|
||||
public function beforeServiceUpdate($data, Request $request): array
|
||||
{
|
||||
// // 模拟数据
|
||||
// $data = [
|
||||
// 'id' => 1,
|
||||
// 'requisition_item_id' => 9,
|
||||
// 'return_qty' => 1,
|
||||
// 'apply_remark' => '申请备注22',
|
||||
// 'attachment' => [
|
||||
// [
|
||||
// 'original_name' => '附件1.jpg',
|
||||
// 'file_path' => '/uploads/2023/07/01/attachment1.jpg'
|
||||
// ],
|
||||
// [
|
||||
// 'original_name' => '附件2.jpg',
|
||||
// 'file_path' => '/uploads/2023/07/01/attachment2.jpg'
|
||||
// ],
|
||||
// [
|
||||
// 'original_name' => '附件3.jpg',
|
||||
// 'file_path' => '/uploads/2023/07/01/attachment3.jpg'
|
||||
// ]
|
||||
// ]
|
||||
// ];
|
||||
|
||||
$data['return_at'] = time();
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新物品归还申请
|
||||
*
|
||||
* @param Request $request
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function serviceUpdate(Request $request, array $data, string $scene = '')
|
||||
{
|
||||
try {
|
||||
// 关联表增加事务处理
|
||||
return Db::transaction(function () use ($request, $data) {
|
||||
$data = $this->preProcess('Update', $data, $request);
|
||||
$config = $this->buildQueryConfig($request, 'update');
|
||||
|
||||
$attachment = $data['attachment'];
|
||||
unset($data['attachment']);
|
||||
|
||||
$this->logicUpdateBy($config, $data);
|
||||
// 获取更新后的完整记录
|
||||
$updated = $this->logicShow($config);
|
||||
// 处理附件更新
|
||||
$this->processRequisitionItemReturnAttachment($updated, $attachment, true);
|
||||
return $this->postProcess('Update', $updated);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
throw new BusinessException("更新物品归还申请失败:" . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理物品申请附件
|
||||
*
|
||||
* @param Model $created
|
||||
* @param array $items
|
||||
* @param bool $isUpdate
|
||||
* @return void
|
||||
*/
|
||||
private function processRequisitionItemReturnAttachment(Model $created, array $attachment, bool $isUpdate = false): void
|
||||
{
|
||||
if ($isUpdate) {
|
||||
$this->clearRequisitionItemReturnAttachment($created->id);
|
||||
}
|
||||
|
||||
foreach ($attachment as $file) {
|
||||
$attachmentData = [
|
||||
'return_id' => $created->id,
|
||||
'file_name' => $file['original_name'],
|
||||
'file_path' => $file['file_path']
|
||||
];
|
||||
InvRequisitionItemReturnAttachment::create($attachmentData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空物品申请附件
|
||||
*
|
||||
* @param int $returnId
|
||||
* @return void
|
||||
*/
|
||||
private function clearRequisitionItemReturnAttachment(int $returnId): void
|
||||
{
|
||||
InvRequisitionItemReturnAttachment::where('return_id', $returnId)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 物品领用归还确认
|
||||
*
|
||||
* @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 {
|
||||
// 归还确认是业务顶层方法,这里统一使用事务
|
||||
return Db::transaction(function () use ($request, $data, $scene) {
|
||||
|
||||
// 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. 构建查询配置,定位到这条归还记录
|
||||
$config = $this->buildQueryConfig($request, $scene);
|
||||
|
||||
// 更新时不允许前端覆盖主键
|
||||
unset($data['requisition_item_return_id']);
|
||||
|
||||
// 3. 获取现有记录
|
||||
/** @var \app\model\InvRequisitionItemReturn|null $existingRecord */
|
||||
$existingRecord = $this->logicShow($config);
|
||||
|
||||
if (!$existingRecord) {
|
||||
throw new BusinessException('未找到对应的归还申请记录');
|
||||
}
|
||||
|
||||
// 已处理校验:只要归还记录的 status 已经是「通过或拒绝」,就不能再处理
|
||||
$existingStatus = (int)($existingRecord->status ?? 0);
|
||||
if (in_array($existingStatus, [1, 2], true) || !empty($existingRecord->handler_id)) {
|
||||
throw new BusinessException('该归还申请已经被处理过了');
|
||||
}
|
||||
|
||||
// 4. 更新归还记录(状态 + 审核人 + 备注等)
|
||||
$updateResult = $this->logicUpdateBy($config, $data);
|
||||
if ($updateResult === 0) {
|
||||
throw new BusinessException('更新归还申请失败,可能记录不存在或已被处理');
|
||||
}
|
||||
|
||||
// 5. 若是拒绝,直接返回(不改库存、不改已归还数量)
|
||||
if ($status === 2) {
|
||||
// 拒绝:这里你返回 true 或者返回更新后的记录都可以
|
||||
return true;
|
||||
}
|
||||
|
||||
// 6. 审核通过:继续处理领用明细 & 库存 & 领用单状态
|
||||
// 注意:requisition_item_id、item_id、return_qty 等字段在本次确认流程中不会被修改,
|
||||
// 所以可以直接使用 $existingRecord 中的值(都是只读字段)
|
||||
$requisitionItemId = (int)$existingRecord->requisition_item_id;
|
||||
$itemId = (int)$existingRecord->item_id;
|
||||
$returnQty = (int)$existingRecord->return_qty;
|
||||
$requisitionId = (int)$existingRecord->requisition_id;
|
||||
|
||||
if ($requisitionItemId <= 0 || $itemId <= 0 || $returnQty <= 0 || $requisitionId <= 0) {
|
||||
throw new BusinessException('归还申请记录缺少必要字段,无法处理');
|
||||
}
|
||||
|
||||
// 6.1 处理领用明细
|
||||
/** @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.2 处理库存(入库)
|
||||
(new InvItemService())->stockIn($itemId, $returnQty);
|
||||
|
||||
// 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,
|
||||
'updated_at' => time(),
|
||||
]);
|
||||
|
||||
// Eloquent::update 返回的是影响行数,0 表示未更新到任何行
|
||||
if ($affected === 0) {
|
||||
throw new BusinessException('更新领用单状态失败,可能记录不存在');
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 返回处理结果(保持你原来的 postProcess 习惯)
|
||||
return $this->postProcess(ucfirst($scene), $existingRecord);
|
||||
});
|
||||
|
||||
} catch (BusinessException $e) {
|
||||
throw $e;
|
||||
} catch (\Throwable $e) {
|
||||
throw new BusinessException("确认归还物品失败:" . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询配置
|
||||
*
|
||||
* @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':
|
||||
$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;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\InvRequisitionItemValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\InvRequisitionItem;
|
||||
|
||||
class InvRequisitionItemService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = InvRequisitionItem::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = InvRequisitionItemValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\InvRequisitionValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\InvRequisition;
|
||||
use app\common\model\InvRequisitionAttachment;
|
||||
use app\common\model\InvRequisitionItem;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use support\Request;
|
||||
use support\Db;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class InvRequisitionService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = InvRequisition::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = InvRequisitionValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建物品申请 前置
|
||||
*
|
||||
* @param array $data
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function beforeServiceStore($data, Request $request): array
|
||||
{
|
||||
$user = (new UserService())->getUserInfo($request->user->uid, '');
|
||||
|
||||
if (empty($user['user']['id']) || empty($user['user']['name'])) {
|
||||
throw new BusinessException('无法获取当前用户信息');
|
||||
}
|
||||
|
||||
$data['order_no'] = $this->generateOrderNo();
|
||||
$data['applicant_id'] = (int)$user['user']['id'];
|
||||
$data['applicant_name'] = (string)$user['user']['name'];
|
||||
$data['leader_id'] = $user['user']['report_to'];
|
||||
$data['status'] = InvRequisition::STATUS_LEADER;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理物品申请
|
||||
*
|
||||
* @param Request $request
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function serviceStore(Request $request, array $data, string $scene = '')
|
||||
{
|
||||
try {
|
||||
// 关联表增加事务处理
|
||||
return Db::transaction(function () use ($request, $data) {
|
||||
$data = $this->preProcess('Store', $data, $request);
|
||||
$dl = $this->getDataLimitFromRequest($request);
|
||||
$created = $this->logicCreate($data, $dl);
|
||||
// 处理物品申请项
|
||||
$this->processRequisitionItems($created, $data['items']);
|
||||
// 处理物品申请附件
|
||||
$this->processRequisitionAttachmentItems($created, $data['attachment']);
|
||||
return $this->postProcess('Store', $created);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
throw new BusinessException("创建物品申请失败:" . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新物品申请
|
||||
*
|
||||
* @param Request $request
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function serviceUpdate(Request $request, array $data, string $scene = '')
|
||||
{
|
||||
try {
|
||||
// 关联表增加事务处理
|
||||
return Db::transaction(function () use ($request, $data) {
|
||||
$data = $this->preProcess('Update', $data, $request);
|
||||
$config = $this->buildQueryConfig($request, 'update');
|
||||
|
||||
// 获取申请项/附件
|
||||
$items = $data['items'];
|
||||
$attachment = $data['attachment'];
|
||||
unset($data['items']);
|
||||
unset($data['attachment']);
|
||||
|
||||
// 执行更新操作
|
||||
$this->logicUpdateBy($config, $data);
|
||||
|
||||
// 获取更新后的完整记录
|
||||
$updated = $this->logicShow($config);
|
||||
|
||||
// 重新创建新的申请项
|
||||
$this->processRequisitionItems((object)$updated, $items, true);
|
||||
|
||||
// 重新创建新的附件
|
||||
$this->processRequisitionAttachmentItems((object)$updated, $attachment, true);
|
||||
|
||||
return $this->postProcess('Update', $updated);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
throw new BusinessException("更新物品申请失败:" . $e->getMessage()."|".$e->getLine()."|".$e->getFile());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理物品申请项
|
||||
*
|
||||
* @param Model $created
|
||||
* @param array $items
|
||||
* @return void
|
||||
*/
|
||||
private function processRequisitionItems(Model $created, array $items, bool $isUpdate = false): void
|
||||
{
|
||||
if ($isUpdate) {
|
||||
$this->clearRequisitionItems($created->id);
|
||||
}
|
||||
|
||||
foreach ($items as $item) {
|
||||
$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'], // 修改:使用 snap 字段
|
||||
'request_qty' => (int) $item['request_qty'] ?? 1, // 动态获取数量,转为整型
|
||||
'approved_qty' => (int) $item['request_qty'] ?? 1, // 初始审批数量等于申请数量
|
||||
'remark' => $item['remark'] ?? ''
|
||||
];
|
||||
InvRequisitionItem::create($itemData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理物品申请项
|
||||
*
|
||||
* @param Model $created
|
||||
* @param array $items
|
||||
* @return void
|
||||
*/
|
||||
private function processRequisitionAttachmentItems(Model $created, array $attachment, bool $isUpdate = false): void
|
||||
{
|
||||
if ($isUpdate) {
|
||||
$this->clearRequisitionAttachmentItems($created->id);
|
||||
}
|
||||
|
||||
foreach ($attachment as $file) {
|
||||
$attachmentData = [
|
||||
'requisition_id' => $created->id,
|
||||
'file_name' => $file['original_name'],
|
||||
'file_path' => $file['file_path']
|
||||
];
|
||||
InvRequisitionAttachment::create($attachmentData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除申请项
|
||||
*
|
||||
* @param int $requisitionId
|
||||
* @return void
|
||||
*/
|
||||
public function clearRequisitionItems(int $requisitionId): void
|
||||
{
|
||||
InvRequisitionItem::where('requisition_id', $requisitionId)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除申请项
|
||||
*
|
||||
* @param int $requisitionId
|
||||
* @return void
|
||||
*/
|
||||
public function clearRequisitionAttachmentItems(int $requisitionId): void
|
||||
{
|
||||
InvRequisitionAttachment::where('requisition_id', $requisitionId)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成申请单号
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generateOrderNo(): string
|
||||
{
|
||||
return 'RQ' . date('Ymd') . strtoupper(substr(uniqid(), -6));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
namespace app\common\service;
|
||||
|
||||
use support\Db;
|
||||
|
||||
class MenuBadgeService
|
||||
{
|
||||
/**
|
||||
* 构造某个节点向上的角标链路(根->叶),每一级返回“完整url + 角标”
|
||||
* @param int $menuId 叶子或中间节点ID(directory/menu均可)
|
||||
* @param int $leafCount 该节点需要向上累加的消息数(正数可表示新增)
|
||||
* @param bool $includeHidden 是否包含隐藏/禁用菜单(默认 false:过滤 status != 1)
|
||||
* @return array<int, array{id:int,name:string,type:string,url:string,badge:int}>
|
||||
*/
|
||||
public static function buildBadgeChain(
|
||||
int $menuId,
|
||||
int $leafCount,
|
||||
bool $includeHidden = false,
|
||||
bool $forceIncludeSelf = true
|
||||
): array {
|
||||
// 取到从“叶->根”的节点列表
|
||||
$nodes = self::getAncestorNodesIterative($menuId, $includeHidden, $forceIncludeSelf);
|
||||
if (empty($nodes)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 调整为“根->叶”
|
||||
$nodes = array_reverse($nodes);
|
||||
$segments = [];
|
||||
$result = [];
|
||||
$leafId = $menuId;
|
||||
|
||||
foreach ($nodes as $n) {
|
||||
$isLeaf = ((int)$n['id'] === $leafId);
|
||||
|
||||
// 中间层的 permission 不展示(但若有内部url段,仍需累计到segments)
|
||||
if (($n['type'] ?? '') === 'permission' && !$isLeaf) {
|
||||
// 若这是 internal 且有 url 段,仍拼到段里,便于子级正确拼接
|
||||
$openType = strtolower((string)($n['open_type'] ?? 'internal'));
|
||||
if ($openType === 'internal') {
|
||||
$seg = trim((string)($n['url'] ?? ''), '/');
|
||||
if ($seg !== '') {
|
||||
$segments[] = $seg;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 计算完整URL(internal 按段拼接;external/iframe 直接用 link/url)
|
||||
$fullUrl = self::composeFullUrl($segments, $n);
|
||||
|
||||
// 叶子(传入ID)必须返回;其他节点照常
|
||||
if ($isLeaf || ($n['type'] ?? '') !== 'permission') {
|
||||
$result[] = [
|
||||
'id' => (int)$n['id'],
|
||||
'name' => (string)$n['name'],
|
||||
'type' => (string)$n['type'],
|
||||
'url' => $fullUrl,
|
||||
'badge' => (int)$leafCount,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量聚合多个叶子节点的角标,把同一路径处的角标相加(父级=所有子级之和)
|
||||
* @param array<int, array{menu_id:int,count:int}> $items
|
||||
* @param bool $includeHidden
|
||||
* @return array<int, array{url:string,badge:int}>
|
||||
*/
|
||||
public static function aggregateChains(array $items, bool $includeHidden = false): array
|
||||
{
|
||||
$acc = []; // key = url
|
||||
|
||||
foreach ($items as $it) {
|
||||
$menuId = (int)($it['menu_id'] ?? 0);
|
||||
$leafCount = (int)($it['count'] ?? 0);
|
||||
if ($menuId <= 0 || $leafCount === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$chain = self::buildBadgeChain($menuId, $leafCount, $includeHidden);
|
||||
foreach ($chain as $node) {
|
||||
$key = $node['url'];
|
||||
if (!isset($acc[$key])) {
|
||||
$acc[$key] = ['url' => $node['url'], 'badge' => 0];
|
||||
}
|
||||
$acc[$key]['badge'] += $node['badge'];
|
||||
}
|
||||
}
|
||||
|
||||
// 父级在前(更短的路径在前),便于前端逐级渲染
|
||||
usort($acc, function ($a, $b) {
|
||||
return substr_count($a['url'], '/') <=> substr_count($b['url'], '/');
|
||||
});
|
||||
|
||||
return array_values($acc);
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代法:从叶子一路查到根(MySQL版本无关)
|
||||
* $forceIncludeSelf=true 时,无论叶子 status 是否为1,都会把叶子纳入;
|
||||
* 但祖先节点仍按 $includeHidden 规则过滤。
|
||||
*/
|
||||
private static function getAncestorNodesIterative(
|
||||
int $id,
|
||||
bool $includeHidden = false,
|
||||
bool $forceIncludeSelf = true
|
||||
): array {
|
||||
$cols = ['id', 'parent_id', 'name', 'type', 'url', 'open_type', 'link', 'is_hide', 'status'];
|
||||
$nodes = [];
|
||||
$seen = [];
|
||||
$cur = $id;
|
||||
$maxHop = 32; // 防环
|
||||
|
||||
$isFirst = true;
|
||||
for ($i = 0; $i < $maxHop && $cur > 0; $i++) {
|
||||
/** @var object|null $row */
|
||||
$row = Db::table('resources')->select($cols)->where('id', $cur)->first();
|
||||
if (!$row) break;
|
||||
|
||||
$rowArr = (array)$row;
|
||||
|
||||
if (!$includeHidden) {
|
||||
// 叶子节点:若 $forceIncludeSelf=true 则无视 status 过滤;祖先照常过滤
|
||||
if (!$isFirst && (int)$rowArr['status'] !== 1) {
|
||||
break;
|
||||
}
|
||||
if ($isFirst && !$forceIncludeSelf && (int)$rowArr['status'] !== 1) {
|
||||
// 如果明确不强制包含叶子,叶子也按规则过滤
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$nodes[] = $rowArr;
|
||||
|
||||
if (in_array($cur, $seen, true)) {
|
||||
break; // 防环
|
||||
}
|
||||
$seen[] = $cur;
|
||||
|
||||
$cur = (int)$rowArr['parent_id'];
|
||||
$isFirst = false;
|
||||
}
|
||||
|
||||
return $nodes; // 叶 -> 根
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装“完整路由”
|
||||
* - internal:把父级段 + 自身 url 段拼成形如 /a/b/c
|
||||
* - external/iframe:直接用 link(若无则退回自身 url)
|
||||
* - 忽略空段(避免出现重复斜杠)
|
||||
*/
|
||||
private static function composeFullUrl(array &$segments, array $node): string
|
||||
{
|
||||
$openType = strtolower((string)($node['open_type'] ?? 'internal'));
|
||||
|
||||
// 外链或 iframe:直接返回 link/url,不再参与分段拼接
|
||||
if ($openType !== 'internal') {
|
||||
$target = trim((string)($node['link'] ?? ''), " \t\r\n");
|
||||
if ($target === '') {
|
||||
$target = (string)($node['url'] ?? '');
|
||||
}
|
||||
return $target;
|
||||
}
|
||||
|
||||
// internal:把自身 url 作为一个“段”拼到前面来的 segments
|
||||
$seg = trim((string)($node['url'] ?? ''), '/');
|
||||
if ($seg !== '') {
|
||||
$segments[] = $seg;
|
||||
}
|
||||
|
||||
return '/' . implode('/', $segments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\MessageNotificationsLogic;
|
||||
use app\common\validate\MessageNotificationsValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\MessageNotifications;
|
||||
use app\common\model\MessageUserStatus;
|
||||
use app\common\model\User;
|
||||
use support\Db;
|
||||
use support\Request;
|
||||
|
||||
class MessageNotificationsService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = MessageNotifications::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = MessageNotificationsValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'index':
|
||||
$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;
|
||||
}
|
||||
|
||||
|
||||
public function serviceDestroy(Request $request)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'destroy');
|
||||
$deleted = (new MessageNotificationsLogic())->logicDeleteBy($config);
|
||||
return $this->postProcess('Destroy', $deleted);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加前置处理
|
||||
*/
|
||||
public function servicePush(Request $request, $data)
|
||||
{
|
||||
$pushData = [
|
||||
'sender_id' => $request->user->uid,
|
||||
'sender_type' => 'admin',
|
||||
'title' => $data['title'],
|
||||
'content' => $data['content'],
|
||||
'scene' => 1,
|
||||
'recipient' => $data['recipient'],
|
||||
'push_method' => 1
|
||||
];
|
||||
$msgId = (new MessageNotificationsService())->pushNotice($pushData);
|
||||
return ['msg_id' => $msgId];
|
||||
}
|
||||
|
||||
public function afterServiceIndex($data)
|
||||
{
|
||||
$data->each(function (&$item) {
|
||||
$temp = explode(',', $item->recipient);
|
||||
$item->recipient_list = User::whereIn('id', $temp)->pluck('name')->toArray();
|
||||
$item->scene_name = MessageNotifications::SCENE[$item->scene];
|
||||
$item->push_method_name = MessageNotifications::PUSH_METHOD[$item->push_method];
|
||||
});
|
||||
unset($item);
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function afterServiceShow($data)
|
||||
{
|
||||
$temp = explode(',', $data->recipient);
|
||||
$data->recipient_list = User::whereIn('id', $temp)->pluck('name')->toArray();
|
||||
$data->scene_name = MessageNotifications::SCENE[$data->scene];
|
||||
$data->push_method_name = MessageNotifications::PUSH_METHOD[$data->push_method];
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ====== ====== ====== 通知操作的处理 ====== ====== ======
|
||||
/**
|
||||
* 推送消息
|
||||
*/
|
||||
public function pushNotice(array $data = [], string $scene = "Default"): int
|
||||
{
|
||||
// 拼装数据(可能需要处理 消息标题、内容等等数据,可自行处理)
|
||||
$pushData = $this->assemblyProcess($scene, $data);
|
||||
// 写入消息
|
||||
$msgId = $this->insertMessage($pushData);
|
||||
// 推送
|
||||
$this->pushWs($msgId, $pushData);
|
||||
return $msgId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行推送
|
||||
*/
|
||||
public function pushWs(int $msgId, array $pushData)
|
||||
{
|
||||
foreach ($pushData['recipient'] as $userId) {
|
||||
// 查询消息数据
|
||||
$config['model'] = MessageUserStatus::class;
|
||||
$config['order']['id'] = 'desc';
|
||||
$config['with']['message'] = ['sender_id', 'sender_type', 'msg_no', 'title', 'content', 'scene', 'created_at'];
|
||||
$config['where']['uid'] = $userId;
|
||||
$config['where']['msg_id'] = $msgId;
|
||||
$config['where']['status'] = 0;
|
||||
$wsData = (new MessageUserStatusService())->logicShow($config)->toArray();
|
||||
|
||||
// 组装数据
|
||||
if (isset($wsData['message']) && $wsData['message']) {
|
||||
$wsData['message']['sender_name'] = User::where('id', $wsData['message']['sender_id'])->value('name') ?: '系统';
|
||||
$wsData['message']['scene_name'] = MessageNotifications::SCENE[$wsData['message']['scene']];
|
||||
$wsData['message']['created_at'] = date('Y-m-d H:i:s', $wsData['message']['created_at']);
|
||||
}
|
||||
|
||||
// 获取未读消息数
|
||||
$counts = MessageUserStatus::where('uid', $userId)->where('status', 0)->count('id');
|
||||
$data = [
|
||||
'notice_data' => $wsData,
|
||||
'unread_counts' => $counts
|
||||
];
|
||||
|
||||
// 执行推送
|
||||
(new \app\common\utils\WsEvents())->pushWebsocket('notify.receive', $userId, $data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入消息
|
||||
* @param array $data
|
||||
* @return int
|
||||
*/
|
||||
public function insertMessage(array $data): int
|
||||
{
|
||||
// 写消息
|
||||
$msgId = $this->createMessage([
|
||||
'sender_id' => $data['sender_id'],
|
||||
'sender_type' => $data['sender_type'],
|
||||
'title' => $data['title'],
|
||||
'content' => $data['content'],
|
||||
'scene' => $data['scene'],
|
||||
'recipient' => implode(',', $data['recipient']),
|
||||
'push_method' => $data['push_method'],
|
||||
]);
|
||||
// 写用户状态
|
||||
$this->addUserStatus($msgId, $data['recipient']);
|
||||
return $msgId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据拼装方法调用
|
||||
*/
|
||||
protected function assemblyProcess(string $op, mixed $data): mixed
|
||||
{
|
||||
$hook = "assembly{$op}";
|
||||
return method_exists($this, $hook)
|
||||
? $this->{$hook}($data)
|
||||
: $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认数据拼装
|
||||
*/
|
||||
public function assemblyDefault(array $data)
|
||||
{
|
||||
return [
|
||||
'sender_id' => isset($data['sender_id']) && $data['sender_id'] ? $data['sender_id'] : 0,
|
||||
'sender_type' => isset($data['sender_type']) && $data['sender_type'] ? $data['sender_type'] : 'system',
|
||||
'title' => isset($data['title']) && $data['title'] ? $data['title'] : '系统通知',
|
||||
'content' => isset($data['content']) && $data['content'] ? $data['content'] : '系统通知-默认',
|
||||
'scene' => isset($data['scene']) && $data['scene'] ? $data['scene'] : 1,
|
||||
'recipient' => isset($data['recipient']) && count($data['recipient']) > 0 ? $data['recipient'] : $this->getAllUserIds(),
|
||||
'push_method' => isset($data['push_method']) && $data['push_method'] ? $data['push_method'] : 0,
|
||||
];
|
||||
}
|
||||
|
||||
// *** *** 可以扩展数据组拼装方法 *** ***
|
||||
|
||||
// ====== ====== ====== 通知操作的基础方法 ====== ====== ======
|
||||
|
||||
/**
|
||||
* 创建一条消息
|
||||
*/
|
||||
public function createMessage(array $data): int
|
||||
{
|
||||
$msgId = Db::table('message_notifications')->insertGetId([
|
||||
'msg_no' => generateMsgId(),
|
||||
'sender_id' => $data['sender_id'],
|
||||
'sender_type' => $data['sender_type'],
|
||||
'title' => $data['title'],
|
||||
'content' => $data['content'],
|
||||
'scene' => $data['scene'],
|
||||
'recipient' => $data['recipient'],
|
||||
'push_method' => $data['push_method'],
|
||||
'created_at' => time(),
|
||||
]);
|
||||
|
||||
return $msgId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入用户消息状态
|
||||
*/
|
||||
public function addUserStatus(int $msgId, array $uids)
|
||||
{
|
||||
$rows = [];
|
||||
foreach ($uids as $uid) {
|
||||
$rows[] = [
|
||||
'msg_id' => $msgId,
|
||||
'uid' => $uid,
|
||||
'status' => 0,
|
||||
'read_at' => null
|
||||
];
|
||||
}
|
||||
if ($rows) {
|
||||
Db::table('message_user_status')->insert($rows);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记消息已读
|
||||
*/
|
||||
public function markAsRead(array|string $msgIds, int $uid)
|
||||
{
|
||||
$query = Db::table('message_user_status')->where('uid', $uid)->where('status', 0);
|
||||
if (is_array($msgIds)) {
|
||||
$query->whereIn('msg_id', $msgIds);
|
||||
}
|
||||
return $query->update([
|
||||
'status' => 1,
|
||||
'read_at' => time()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有用户ID
|
||||
*/
|
||||
public function getAllUserIds(): array
|
||||
{
|
||||
return User::where('status', 1)->pluck('id')->toArray();
|
||||
}
|
||||
|
||||
|
||||
public function getUserEmailsById(array $con = []): array
|
||||
{
|
||||
$user = User::where('status', 1);
|
||||
if (count($con) > 0) {
|
||||
return $user->whereIn('id', $con)->where('email', '!=', '')->pluck('email')->toArray();
|
||||
}
|
||||
return $user->where('email', '!=', '')->pluck('email')->toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\MessageNotifications;
|
||||
use app\common\validate\MessageUserStatusValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\MessageUserStatus;
|
||||
use support\Request;
|
||||
use app\common\model\User;
|
||||
|
||||
class MessageUserStatusService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = MessageUserStatus::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = MessageUserStatusValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'unread':
|
||||
$config['order']['id'] = 'desc';
|
||||
$config['with']['message'] = ['sender_id', 'sender_type', 'msg_no', 'title', 'content', 'scene', 'created_at'];
|
||||
$config['where']['uid'] = $request->user->uid;
|
||||
$config['where']['status'] = 0;
|
||||
break;
|
||||
case 'index':
|
||||
$config['order']['id'] = 'desc';
|
||||
$config['with']['message'] = ['sender_id', 'sender_type', 'msg_no', 'title', 'content', 'scene', 'created_at'];
|
||||
$config['where']['uid'] = $request->user->uid;
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['with']['message'] = ['sender_id', 'sender_type', 'msg_no', 'title', 'content', 'scene', 'created_at'];
|
||||
$config['where']['uid'] = $request->user->uid;
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
case 'read':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['msg_id'] = $p['msg_id'];
|
||||
$config['where']['uid'] = $request->user->uid;
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['uid'] = $request->user->uid;
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function serviceListUnRead(Request $request)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'unread');
|
||||
$result = $this->logicListAll($config);
|
||||
return $this->postProcess('ListUnRead', $result);
|
||||
}
|
||||
|
||||
public function serviceRead(Request $request, array $data = [])
|
||||
{
|
||||
return $this->noticeRead($request->post('msg_ids'), $request->user->uid);
|
||||
}
|
||||
|
||||
public function noticeRead(array|string $msgIds, int $uid): bool
|
||||
{
|
||||
$model = MessageUserStatus::where('uid', $uid)->where('status', 0);
|
||||
if (is_array($msgIds)) {
|
||||
$model->whereIn('msg_id', $msgIds);
|
||||
}
|
||||
$udata['read_at'] = time();
|
||||
$udata['status'] = 1;
|
||||
return $model->update($udata);
|
||||
}
|
||||
|
||||
|
||||
protected function afterServiceIndex($res)
|
||||
{
|
||||
$res->each(function (&$item) {
|
||||
if (isset($item->message)) {
|
||||
$item->message->sender_name = User::where('id', $item->message->sender_id)->value('name') ?: '系统';
|
||||
$item->message->scene_name = MessageNotifications::SCENE[$item->message->scene];
|
||||
}
|
||||
});
|
||||
unset($item);
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function afterServiceShow($res)
|
||||
{
|
||||
if (isset($res->message)) {
|
||||
$res->message->sender_name = User::where('id', $res->message->sender_id)->value('name') ?: '系统';
|
||||
$res->message->scene_name = MessageNotifications::SCENE[$res->message->scene];
|
||||
}
|
||||
// 标记已读
|
||||
if ($res->status == 0) {
|
||||
$this->noticeRead([$res->msg_id], $res->uid);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function afterServiceListUnRead($res)
|
||||
{
|
||||
$res->each(function (&$item) {
|
||||
if (isset($item->message)) {
|
||||
$item->message->sender_name = User::where('id', $item->message->sender_id)->value('name') ?: '系统';
|
||||
$item->message->scene_name = MessageNotifications::SCENE[$item->message->scene];
|
||||
}
|
||||
});
|
||||
unset($item);
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use OSS\OssClient;
|
||||
use OSS\Core\OssException;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class OssService
|
||||
{
|
||||
private $accessKeyId;
|
||||
private $accessKeySecret;
|
||||
private $bucket;
|
||||
private $endpoint;
|
||||
private $ossClient;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->accessKeyId = getenv('OSS_ACCESSID');
|
||||
$this->accessKeySecret = getenv('OSS_ACCESSSECRET');
|
||||
$this->bucket = getenv('OSS_BUCKET');
|
||||
$this->endpoint = getenv('OSS_ENDPOINT');
|
||||
$this->ossClient = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传图片到 OSS
|
||||
* @param string $filePath 本地文件路径
|
||||
* @param string $objectKey OSS上存储的对象名称
|
||||
* @return string 图片的 URL
|
||||
*/
|
||||
public function uploadImage($filePath, $objectKey)
|
||||
{
|
||||
try {
|
||||
// 上传文件到 OSS
|
||||
$this->ossClient->uploadFile($this->bucket, $objectKey, $filePath);
|
||||
// 构造图片的私有 URL
|
||||
$url = $this->generatePrivateUrl($objectKey);
|
||||
return $url;
|
||||
} catch (OssException $e) {
|
||||
// 错误处理
|
||||
throw new \RuntimeException('OSS Error: ' . $e->getMessage());
|
||||
} catch (\Throwable $th) {
|
||||
// 错误处理
|
||||
throw new BusinessException('Error: ' . $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成图片的私有访问 URL
|
||||
* @param string $objectKey
|
||||
* @return string
|
||||
*/
|
||||
public function generatePrivateUrl($objectKey, $expireTime = 3600)
|
||||
{
|
||||
// 生成 OSS 私有 URL(有效期为 3600 秒)
|
||||
return $this->ossClient->signUrl($this->bucket, $objectKey, $expireTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 OSS 上的文件
|
||||
* @param string $objectKey OSS上存储的对象名称
|
||||
* @return bool 删除是否成功
|
||||
*/
|
||||
public function deleteFile($objectKey)
|
||||
{
|
||||
try {
|
||||
// 删除 OSS 上的文件
|
||||
$this->ossClient->deleteObject($this->bucket, $objectKey);
|
||||
return true;
|
||||
} catch (OssException $e) {
|
||||
// 错误处理
|
||||
throw new \RuntimeException('OSS Delete Error: ' . $e->getMessage());
|
||||
} catch (\Throwable $th) {
|
||||
// 错误处理
|
||||
throw new BusinessException('Delete Error: ' . $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对应的 MIME 类型
|
||||
*/
|
||||
public function getMimeTypes($extensions)
|
||||
{
|
||||
$mimeMap = [
|
||||
'jpg' => 'image/jpeg',
|
||||
'jpeg' => 'image/jpeg',
|
||||
'png' => 'image/png',
|
||||
'gif' => 'image/gif',
|
||||
'bmp' => 'image/bmp',
|
||||
'webp' => 'image/webp',
|
||||
'pdf' => 'application/pdf',
|
||||
'doc' => 'application/msword',
|
||||
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'xls' => 'application/vnd.ms-excel',
|
||||
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'ppt' => 'application/vnd.ms-powerpoint',
|
||||
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'txt' => 'text/plain',
|
||||
'zip' => 'application/zip',
|
||||
'rar' => 'application/x-rar-compressed'
|
||||
];
|
||||
|
||||
$mimes = [];
|
||||
foreach ($extensions as $ext) {
|
||||
if (isset($mimeMap[$ext])) {
|
||||
$mimes[] = $mimeMap[$ext];
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($mimes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\PermLogic;
|
||||
use support\Cache;
|
||||
|
||||
class PermService
|
||||
{
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new PermLogic());
|
||||
}
|
||||
|
||||
// 用户资源缓存key
|
||||
protected static function cacheKey(int $userId, string $systemCode): string
|
||||
{
|
||||
return "user_resources_{$userId}_{$systemCode}";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户所有资源(合并角色+直接分配),结果缓存
|
||||
*/
|
||||
public function getUserResources(int $userId, string $systemCode)
|
||||
{
|
||||
$cacheKey = self::cacheKey($userId, $systemCode);
|
||||
$cached = Cache::get($cacheKey);
|
||||
if ($cached !== null) {
|
||||
return $cached;
|
||||
}
|
||||
// 调用 Logic 层获取资源
|
||||
$resources = $this->logic->getUserResources($userId, $systemCode);
|
||||
// 缓存结果
|
||||
Cache::set($cacheKey, $resources, 3600);
|
||||
return $resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建目录/菜单树,节点包含权限与打开方式
|
||||
*/
|
||||
public function getMenuTree(int $userId, string $systemCode): array
|
||||
{
|
||||
// 调用 Logic 层处理菜单构建
|
||||
$resources = $this->getUserResources($userId, $systemCode);
|
||||
return $this->logic->buildTree($resources);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户所有权限code
|
||||
*/
|
||||
public function getPermissionCodes(int $userId, string $systemCode): array
|
||||
{
|
||||
return $this->logic->getPermissionCodes($userId, $systemCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除资源相关缓存
|
||||
*/
|
||||
public function clearCache(int $userId, string $systemCode): void
|
||||
{
|
||||
Cache::delete(self::cacheKey($userId, $systemCode));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\User;
|
||||
use support\Cache;
|
||||
|
||||
class PermService_bak
|
||||
{
|
||||
|
||||
// 用户资源缓存key
|
||||
protected static function cacheKey(int $userId): string
|
||||
{
|
||||
return "user_resources_{$userId}";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户所有资源(合并角色+直接分配),结果缓存
|
||||
*/
|
||||
public static function getUserResources(int $userId)
|
||||
{
|
||||
$cacheKey = self::cacheKey($userId);
|
||||
$cached = Cache::get($cacheKey);
|
||||
if ($cached !== null) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$user = User::with(['roles.resources', 'resources'])->find($userId);
|
||||
if (!$user) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
$all = collect();
|
||||
foreach ($user->roles as $role) {
|
||||
$all = $all->merge($role->resources);
|
||||
}
|
||||
$all = $all->merge($user->resources);
|
||||
$unique = $all->unique('id')->values();
|
||||
|
||||
Cache::set($cacheKey, $unique, 3600);
|
||||
return $unique;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建目录/菜单树,节点包含权限与打开方式
|
||||
*/
|
||||
public static function getMenuTree(int $userId): array
|
||||
{
|
||||
$resources = self::getUserResources($userId);
|
||||
$menus = $resources
|
||||
->filter(fn($r) => in_array($r->type, ['directory','menu']))
|
||||
->values();
|
||||
return self::buildTree($menus, $resources);
|
||||
}
|
||||
|
||||
protected static function buildTree($nodes, $allResources, int $parentId = 0): array
|
||||
{
|
||||
$tree = [];
|
||||
foreach ($nodes as $node) {
|
||||
if ($node->parent_id !== $parentId) continue;
|
||||
|
||||
$children = self::buildTree($nodes, $allResources, $node->id);
|
||||
|
||||
$authList = $allResources
|
||||
->filter(fn($r) => $r->type === 'permission' && $r->parent_id === $node->id)
|
||||
->map(fn($r) => [
|
||||
'id' => $r->id,
|
||||
'title' => $r->name,
|
||||
'auth_mark' => $r->code,
|
||||
])->values()->all();
|
||||
|
||||
$tree[] = [
|
||||
'id' => $node->id,
|
||||
'name' => $node->name,
|
||||
'path' => $node->url,
|
||||
'meta' => [
|
||||
'title' => $node->name,
|
||||
'icon' => $node->icon,
|
||||
'keepAlive' => true,
|
||||
'authList' => $authList,
|
||||
'openType' => $node->open_type, // 'internal' | 'external' | 'iframe'
|
||||
],
|
||||
'children' => $children,
|
||||
];
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户所有权限code
|
||||
*/
|
||||
public static function getPermissionCodes(int $userId): array
|
||||
{
|
||||
return self::getUserResources($userId)
|
||||
->filter(fn($res) => $res->type === 'permission')
|
||||
->pluck('code')
|
||||
->unique()
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除资源相关缓存
|
||||
*/
|
||||
public static function clearCache(int $userId): void
|
||||
{
|
||||
Cache::delete(self::cacheKey($userId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\PurchaseOrderItemsValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\PurchaseOrderItems;
|
||||
|
||||
class PurchaseOrderItemsService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = PurchaseOrderItems::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = PurchaseOrderItemsValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\PurchaseOrdersValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\PurchaseOrders;
|
||||
use app\common\logic\PurchaseOrdersLogic;
|
||||
use app\common\model\PurchaseOrderItems;
|
||||
use app\common\model\User;
|
||||
use support\Db;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
|
||||
class PurchaseOrdersService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = PurchaseOrders::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = PurchaseOrdersValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
public function getLogic()
|
||||
{
|
||||
return new PurchaseOrdersLogic();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取前置预处理数据
|
||||
*
|
||||
* @param array $data 原始返回值
|
||||
* @return array 处理后的返回值
|
||||
*/
|
||||
public function preQueryData(array $data)
|
||||
{
|
||||
$result = match ($data['scene']) {
|
||||
'pi_no' => $this->getLogic()->getPiList(),
|
||||
'order_no' => $this->getLogic()->getOrderNoListByPiNo($data['pi_no']),
|
||||
'order_items' => $this->getLogic()->getOrderItemsListByOrderNo($data['order_id']),
|
||||
default => $data,
|
||||
};
|
||||
return $this->postProcess('PreData', $result->toArray());
|
||||
}
|
||||
|
||||
public function afterServicePreData(array $data)
|
||||
{
|
||||
foreach ($data as $key => &$item) {
|
||||
if (isset($item['biz_date'])) {
|
||||
$item['biz_date'] = date('Y-m-d', $item['biz_date']);
|
||||
}
|
||||
}
|
||||
unset($item);
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function beforeServiceStore(array $data, Request $request)
|
||||
{
|
||||
$data['order_no'] = generateStockNo('CG');
|
||||
$data['buyer_id'] = $request->user->uid;
|
||||
$data['buyer_name'] = User::where('id', $request->user->uid)->value('name');
|
||||
if ($data['is_draft'] == 0) {
|
||||
$data['status'] = 1;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function serviceStore(Request $request, array $data = [], string $scene = 'store')
|
||||
{
|
||||
// 使用事务确保数据一致性
|
||||
return Db::transaction(function () use ($request, $data, $scene) {
|
||||
$data = $this->preProcess(ucfirst($scene), $data, $request);
|
||||
$dl = $this->getDataLimitFromRequest($request);
|
||||
// 创建采购单
|
||||
$created = $this->logicCreate($data, $dl);
|
||||
if (isset($data['stock_order'])) {
|
||||
foreach ($data['stock_order'] as $order) {
|
||||
foreach ($order['stock_items'] as $item) {
|
||||
// 创建采购单明细
|
||||
PurchaseOrderItems::create([
|
||||
'purchase_order_id' => $created->id,
|
||||
'stock_id' => $order['stock_orders_id'],
|
||||
'stock_items_id' => $item['stock_order_items_id'],
|
||||
'stock_items_uqid' => $item['unique_id'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->postProcess(ucfirst($scene), $created);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询配置
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $scene
|
||||
* @return array
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'index'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
|
||||
switch ($scene) {
|
||||
case 'index':
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'] ?? 0;
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['with'] = [
|
||||
'items', 'items.stockOrder', 'items.stockOrderItems'
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除采购订单
|
||||
*
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function serviceDestroy(Request $request)
|
||||
{
|
||||
// 使用事务确保数据一致性
|
||||
return Db::transaction(function () use ($request) {
|
||||
// 构建查询条件
|
||||
$config = $this->buildQueryConfig($request, 'show');
|
||||
|
||||
// 软删除采购单明细
|
||||
$order = $this->logicShow($config);
|
||||
if ($order && $order->items) {
|
||||
foreach ($order->items as $item) {
|
||||
$item->delete();
|
||||
}
|
||||
}
|
||||
|
||||
// 软删除采购单主表
|
||||
$res = $order->delete();
|
||||
|
||||
return $this->postProcess('Destroy', $res);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建采购单成功后处理
|
||||
*/
|
||||
protected function afterServiceStore($res)
|
||||
{
|
||||
if ($res->is_draft == 0) {
|
||||
$this->startApproval($res, ['resubmitted'=>0]);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function startApproval($item)
|
||||
{
|
||||
$appro = new \app\common\utils\approval\service\ApprovalFlowService();
|
||||
$appro->start('purchase_orders', 'purchase_orders', $item->id, ['resubmitted'=>0], $item->buyer_id);
|
||||
}
|
||||
|
||||
public function beforeServiceUpdate(array $data, Request $request)
|
||||
{
|
||||
if ($data['is_draft'] == 0) {
|
||||
$data['status'] = 1;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新采购单
|
||||
*
|
||||
* @param Request $request
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function serviceUpdate(Request $request, array $data = [], string $scene = 'update')
|
||||
{
|
||||
// 使用事务确保数据一致性
|
||||
return Db::transaction(function () use ($request, $data, $scene) {
|
||||
$data = $this->preProcess(ucfirst($scene), $data, $request);
|
||||
|
||||
// 构建查询条件
|
||||
$config = $this->buildQueryConfig($request, $scene);
|
||||
|
||||
// 更新主表信息
|
||||
$udata = $data;
|
||||
unset($udata['stock_order']);
|
||||
unset($udata['is_resubmit']);
|
||||
unset($udata['approval_desc']);
|
||||
$this->logicUpdateBy($config, $udata);
|
||||
|
||||
// 获取更新后的数据
|
||||
$order = $this->logicShow($config);
|
||||
|
||||
// 更新采购单明细
|
||||
if (isset($data['stock_order'])) {
|
||||
// 先删除原有的明细
|
||||
PurchaseOrderItems::where('purchase_order_id', $order->id)->delete();
|
||||
|
||||
// 重新创建明细
|
||||
foreach ($data['stock_order'] as $orderData) {
|
||||
foreach ($orderData['stock_items'] as $item) {
|
||||
PurchaseOrderItems::create([
|
||||
'purchase_order_id' => $order->id,
|
||||
'stock_id' => $orderData['stock_orders_id'],
|
||||
'stock_items_id' => $item['stock_order_items_id'],
|
||||
'stock_items_uqid' => $item['unique_id'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->postProcess(
|
||||
ucfirst($scene),
|
||||
$order,
|
||||
[
|
||||
'is_resubmit'=>$data['is_resubmit'],
|
||||
'approval_desc'=>$data['approval_desc']
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
protected function afterServiceUpdate($res, $data)
|
||||
{
|
||||
if ($data['is_resubmit'] == 0 && $res->status == 1) {
|
||||
$this->startApproval($res);
|
||||
}
|
||||
if ($data['is_resubmit'] == 1) {
|
||||
$instance = \app\common\model\ApprovalInstances::where('biz_id', $res->id)->where('flow_type', 'purchase_orders')->first();
|
||||
if ( $instance === null) {
|
||||
throw new BusinessException('未找到审批实例');
|
||||
}
|
||||
// 审批服务
|
||||
$appro = new \app\common\utils\approval\service\ApprovalFlowService();
|
||||
// 重新提交
|
||||
$appro->resubmit($instance->id, $instance->initiator_id, ['resubmitted'=>1], $data['approval_desc']);
|
||||
// 添加到讨论
|
||||
if (!empty($data['approval_desc'])) {
|
||||
$appro->postDiscussion($instance->id, $instance->initiator_id, $data['approval_desc'], false, [], 'name');
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
public function serviceResubmit(Request $request, array $data = [])
|
||||
{
|
||||
$p = $request->all();
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['buyer_id'] = $request->user->uid;
|
||||
$info = $this->logicShow($config);
|
||||
if ($info === null) {
|
||||
throw new BusinessException('未找到采购单');
|
||||
}
|
||||
if ($info->status != 3) {
|
||||
throw new BusinessException('该状态不能重新提交');
|
||||
}
|
||||
$instance = \app\common\model\ApprovalInstances::where('biz_id', $info->id)->where('flow_type', 'purchase_orders')->first();
|
||||
if ( $instance === null) {
|
||||
throw new BusinessException('未找到审批实例');
|
||||
}
|
||||
// 审批服务
|
||||
$appro = new \app\common\utils\approval\service\ApprovalFlowService();
|
||||
// 重新提交
|
||||
$result = $appro->resubmit($instance->id, $instance->initiator_id, ['resubmitted'=>1], $data['remark']);
|
||||
// 添加到讨论
|
||||
if (!empty($data['remark'])) {
|
||||
$appro->postDiscussion($instance->id, $instance->initiator_id, $data['remark'], false, [], 'name');
|
||||
}
|
||||
|
||||
$info->status = 1;
|
||||
$info->save();
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
public function updateStatus(array $data = [])
|
||||
{
|
||||
|
||||
$info = PurchaseOrders::where('id', $data['id'])->first();
|
||||
if ($info === null) {
|
||||
throw new BusinessException('未找到采购单');
|
||||
}
|
||||
$info->status = $data['status'];
|
||||
return $info->save();
|
||||
}
|
||||
|
||||
|
||||
public function formatData($data)
|
||||
{
|
||||
$contractFile = $data['contract_file'] ? explode(',', $data['contract_file']) : [];
|
||||
$contractFileUrl = [];
|
||||
if (count($contractFile) > 0) {
|
||||
foreach ($contractFile as $file) {
|
||||
$contractFileUrl[] = (new \app\common\service\OssService)->generatePrivateUrl($file);
|
||||
}
|
||||
}
|
||||
$result = [
|
||||
'id' => $data['id'],
|
||||
'order_no' => $data['order_no'],
|
||||
'pi_no' => $data['pi_no'],
|
||||
'buyer_id' => $data['buyer_id'],
|
||||
'buyer_name' => $data['buyer_name'],
|
||||
'contract_file' => $contractFile,
|
||||
'contract_file_url' => $contractFileUrl,
|
||||
'status' => $data['status'],
|
||||
'remark' => $data['remark']
|
||||
];
|
||||
$temps = [];
|
||||
if (isset($data['items']) && count($data['items']) > 0) {
|
||||
foreach ($data['items'] as $record) {
|
||||
if (!in_array($record['stockOrder']['id'], array_keys($temps))) {
|
||||
$temps[$record['stockOrder']['id']] = [
|
||||
'id' => $record['stockOrder']['id'],
|
||||
'order_no' => $record['stockOrder']['order_no'],
|
||||
'salesperson_snapshot' => $record['stockOrder']['salesperson_snapshot'],
|
||||
'biz_date' => date('Y-m-d', $record['stockOrder']['biz_date'])
|
||||
];
|
||||
}
|
||||
$temps[$record['stockOrder']['id']]['stock_order_items'][] =[
|
||||
'id' => $record['stockOrderItems']['id'],
|
||||
'model_snapshot' => $record['stockOrderItems']['model_snapshot'],
|
||||
'unique_id' => $record['stockOrderItems']['unique_id'],
|
||||
];
|
||||
}
|
||||
}
|
||||
$result['stock_order'] = array_values($temps);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\ResourceLogic;
|
||||
use app\common\validate\ResourceValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\Resource;
|
||||
use app\common\utils\Tree;
|
||||
use support\Request;
|
||||
|
||||
class ResourceService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Resource::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = ResourceValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'default':
|
||||
$config['where']['system_id'] = ['in', [0, $p['system_id']]];
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'asc';
|
||||
$config['order']['id'] = 'asc';
|
||||
break;
|
||||
case 'menuList':
|
||||
$config['where']['status'] = 1;
|
||||
$config['where']['type'] = ['!=', 'permission'];
|
||||
$config['order']['sort'] = 'asc';
|
||||
$config['order']['id'] = 'asc';
|
||||
break;
|
||||
case 'menuTreeList':
|
||||
$config['where']['system_id'] = ['in', [0, $p['system_id']]];
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'asc';
|
||||
$config['order']['id'] = 'asc';
|
||||
break;
|
||||
case 'index':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'asc';
|
||||
$config['order']['id'] = 'asc';
|
||||
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;
|
||||
}
|
||||
|
||||
public function serviceMenuList(Request $request)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'menuList');
|
||||
$result = $this->logicListAll($config);
|
||||
return $this->postProcess('MenuList', $result);
|
||||
}
|
||||
|
||||
public function serviceMenuTreeList(Request $request)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'menuTreeList');
|
||||
$result = (new ResourceLogic())->logicListAllResources($request, $config);
|
||||
return $this->postProcess('MenuTreeList', $result);
|
||||
}
|
||||
|
||||
|
||||
protected function afterServiceDefault($data)
|
||||
{
|
||||
$data = Tree::buildMenuTreeWithReference($data->toArray());
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function afterServiceMenuList($data)
|
||||
{
|
||||
$data = Tree::buildMenuTree($data->toArray());
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function afterServiceMenuTreeList($data)
|
||||
{
|
||||
$data = Tree::buildMenuTree($data->toArray());
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
$data['parent_id'] = $data['parent_id'] != '' ? $data['parent_id'] : 0;
|
||||
$data['system_id'] = $data['system_id'] != '' ? $data['system_id'] : 0;
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function beforeServiceUpdate($data, Request $request)
|
||||
{
|
||||
$data['parent_id'] = $data['parent_id'] != '' ? $data['parent_id'] : 0;
|
||||
$data['system_id'] = $data['system_id'] != '' ? $data['system_id'] : 0;
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\StockOrderAccountsValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\StockOrderAccounts;
|
||||
|
||||
class StockOrderAccountsService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = StockOrderAccounts::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = StockOrderAccountsValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\StockOrderItemOptionsValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\StockOrderItemOptions;
|
||||
|
||||
class StockOrderItemOptionsService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = StockOrderItemOptions::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = StockOrderItemOptionsValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\StockOrderItemsValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\StockOrderItems;
|
||||
|
||||
class StockOrderItemsService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = StockOrderItems::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = StockOrderItemsValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\StockOrdersFilesValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\StockOrdersFiles;
|
||||
|
||||
class StockOrdersFilesService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = StockOrdersFiles::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = StockOrdersFilesValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\admin\validate\SysAccountValidate;
|
||||
use app\common\logic\SysAccountLogic;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\SysAccount;
|
||||
use support\Request;
|
||||
|
||||
class SysAccountService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new SysAccountLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
return $this->logic->getList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\SysConfigLogic;
|
||||
use app\common\logic\SysCurrencyLogic;
|
||||
use app\common\logic\SystemsLogic;
|
||||
use support\Redis;
|
||||
|
||||
class SysConfigService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new SysConfigLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public static function getConfig(string $config_key)
|
||||
{
|
||||
$value = Redis::get($config_key);
|
||||
if (empty($value)) {
|
||||
$config = (new SysConfigLogic())->findByKey($config_key);
|
||||
if (empty($config)) {
|
||||
return null;
|
||||
}
|
||||
$value = $config->config_value;
|
||||
Redis::set($config->config_key, $value, 'EX', 7200);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\SysCurrencyLogic;
|
||||
use app\common\logic\SystemsLogic;
|
||||
|
||||
class SysCurrencyService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new SysCurrencyLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
return $this->logic->getList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\admin\validate\SysDictItemValidate;
|
||||
use app\common\logic\SysDictItemLogic;
|
||||
use app\common\logic\SysDictLogic;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\SysDictItem;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
|
||||
class SysDictItemService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new SysDictItemLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public function getList($params)
|
||||
{
|
||||
if (empty($params['dict_id']) && empty($params['dict_code']))
|
||||
throw new BusinessException('未明确要查询的字典组');
|
||||
$where = [];
|
||||
if(isset($params['dict_id']) && $params['dict_id'])
|
||||
$where[] = ['dict_id', '=', $params['dict_id']];
|
||||
if(isset($params['dict_code']) && $params['dict_code']){
|
||||
$dict = (new SysDictLogic)->getDictByCode($params['dict_code']);
|
||||
if (empty($dict['id']))
|
||||
throw new BusinessException('字典组code错误');
|
||||
$where[] = ['dict_id', '=', $dict['id']];
|
||||
}
|
||||
|
||||
return $this->logic->getList($where);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\admin\validate\SysDictValidate;
|
||||
use app\common\logic\SysDictLogic;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\SysDict;
|
||||
use support\Request;
|
||||
|
||||
class SysDictService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new SysDictLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
return $this->logic->getList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static function pluckValuesByCode(string $dictCode): array
|
||||
{
|
||||
return SysDict::where('dict_code', $dictCode)
|
||||
->where('status', 1)
|
||||
->first()?->items()
|
||||
->where('status', 1)
|
||||
->orderBy('sort')
|
||||
->pluck('item_value')
|
||||
->toArray() ?? [];
|
||||
}
|
||||
|
||||
public static function pluckKeyValueByCode(string $dictCode): array
|
||||
{
|
||||
return SysDict::where('dict_code', $dictCode)
|
||||
->where('status', 1)
|
||||
->first()?->items()
|
||||
->where('status', 1)
|
||||
->orderBy('sort')
|
||||
->pluck('item_value', 'item_label')
|
||||
->toArray() ?? [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\SysOpLogValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\SysOpLog;
|
||||
use support\Request;
|
||||
|
||||
class SysOpLogService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = SysOpLog::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = SysOpLogValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'index':
|
||||
// ====== ====== 排序 ====== ======
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
// ====== ====== 筛选 ====== ======
|
||||
// 状态
|
||||
if (isset($p['user_id']) && $p['user_id']) {
|
||||
$config['where']['user_id'] = $p['user_id'];
|
||||
}
|
||||
// ip
|
||||
if (isset($p['ip']) && $p['ip']) {
|
||||
$config['where']['ip'] = $p['ip'];
|
||||
}
|
||||
// ip
|
||||
if (isset($p['method']) && $p['method']) {
|
||||
$config['where']['method'] = $p['method'];
|
||||
}
|
||||
// 关键字
|
||||
if (isset($p['keyword']) && $p['keyword']) {
|
||||
$k = '%' . $p['keyword'] . '%';
|
||||
foreach (['user_name', 'route', 'params_brief'] as $col) {
|
||||
$config['orWhere'][] = [$col, 'like', $k];
|
||||
}
|
||||
}
|
||||
//$config['where']['status'] = 1;
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
//$config['where']['status'] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\admin\validate\SysPortValidate;
|
||||
use app\common\logic\SysPortLogic;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\SysPort;
|
||||
use support\Request;
|
||||
|
||||
class SysPortService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new SysPortLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public function getList($params)
|
||||
{
|
||||
$where = [];
|
||||
if(isset($params['scene']) && $params['scene']) {
|
||||
if($params['scene'] == 'domestic'){
|
||||
$where['country_id'] = 45;
|
||||
}
|
||||
}
|
||||
return $this->logic->getList($where);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\SysUpdateLogValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\SysUpdateLog;
|
||||
use support\Request;
|
||||
|
||||
class SysUpdateLogService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = SysUpdateLog::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = SysUpdateLogValidate::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 'index':
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加前置处理
|
||||
*/
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
$data['update_time'] = !empty($data['update_time'])?strtotime($data['update_time']):0;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加前置处理
|
||||
*/
|
||||
public function beforeServiceupdate($data, Request $request)
|
||||
{
|
||||
$data['update_time'] = !empty($data['update_time'])?strtotime($data['update_time']):0;
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\SystemsLogic;
|
||||
|
||||
class SystemsService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new SystemsLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
return $this->logic->getList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use support\exception\BusinessException;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
|
||||
class UploadService
|
||||
{
|
||||
|
||||
/**
|
||||
* 从服务器本地路径上传文件到 OSS
|
||||
*
|
||||
* @param Request $request
|
||||
* - path: 本地文件绝对路径
|
||||
* - scene: 业务分区/场景
|
||||
* - category: 文件分类(可选)
|
||||
* - original_name: 原始文件名(可选)
|
||||
*/
|
||||
public function uploadLocalFile($param)
|
||||
{
|
||||
try {
|
||||
$filePath = $param['path'];
|
||||
$scene = $param['scene'];
|
||||
$category = $param['category']??'general';
|
||||
$providedOriginalName = $param['original_name']??'';
|
||||
|
||||
if (empty($filePath)) {
|
||||
Log::error('本地文件路径不能为空',$param);
|
||||
throw new BusinessException('本地文件路径不能为空');
|
||||
}
|
||||
|
||||
if (!file_exists($filePath) || !is_readable($filePath)) {
|
||||
Log::error('本地文件不存在或不可读',$param);
|
||||
throw new BusinessException('本地文件不存在或不可读');
|
||||
}
|
||||
if (empty($scene)) {
|
||||
Log::error('上传场景不能为空',$param);
|
||||
throw new BusinessException('上传场景不能为空');
|
||||
}
|
||||
|
||||
$basename = basename($filePath);
|
||||
$originalName = $providedOriginalName ?: $basename;
|
||||
$extensionFromName = pathinfo($originalName, PATHINFO_EXTENSION);
|
||||
$extensionFromPath = pathinfo($basename, PATHINFO_EXTENSION);
|
||||
$extension = $extensionFromName ?: $extensionFromPath;
|
||||
|
||||
$mime = mime_content_type($filePath) ?: 'application/octet-stream';
|
||||
$size = filesize($filePath) ?: 0;
|
||||
|
||||
$sceneUrl = $scene ? ($scene . '/') : '';
|
||||
$dir = config('oss.oss_main_dir') . $sceneUrl . date('Ymd') . '/';
|
||||
// 使用传入的 original_name 命名(缺少扩展名时补上推断的扩展名),并做简单安全处理
|
||||
$safeBaseName = preg_replace('/[\\\\\/]+/', '_', $originalName);
|
||||
if ($extension && strtolower(pathinfo($safeBaseName, PATHINFO_EXTENSION)) !== strtolower($extension)) {
|
||||
// 若提供的名称没有扩展名或扩展名不一致,则以推断扩展名为准
|
||||
$safeBaseName = pathinfo($safeBaseName, PATHINFO_FILENAME) . '.' . $extension;
|
||||
} elseif (!$extension && !pathinfo($safeBaseName, PATHINFO_EXTENSION)) {
|
||||
// 实在没有扩展名信息时,保持原名
|
||||
}
|
||||
|
||||
// 重名检测:同一目录、同名且同类型则在文件名后追加序号
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
$candidateName = $safeBaseName;
|
||||
$nameBody = pathinfo($safeBaseName, PATHINFO_FILENAME);
|
||||
$nameExt = pathinfo($safeBaseName, PATHINFO_EXTENSION);
|
||||
$counter = 1;
|
||||
while (true) {
|
||||
$candidatePath = $dir . $candidateName;
|
||||
$existing = $uploadedFilesService->findFile(['file_path' => $candidatePath]);
|
||||
if (!$existing) {
|
||||
break;
|
||||
}
|
||||
// 若存在同路径同名,且类型也相同,则追加序号
|
||||
if (isset($existing->file_type) && strtolower($existing->file_type) === strtolower($mime)) {
|
||||
$suffix = ' (' . $counter . ')';
|
||||
$candidateName = $nameBody . $suffix . ($nameExt !== '' ? ('.' . $nameExt) : '');
|
||||
$counter++;
|
||||
continue;
|
||||
}
|
||||
// 类型不同则允许同名,结束循环
|
||||
break;
|
||||
}
|
||||
|
||||
$objectKey = $dir . $candidateName;
|
||||
|
||||
$ossService = new OssService();
|
||||
$ossService->uploadImage($filePath, $objectKey);
|
||||
$privateUrl = $ossService->generatePrivateUrl($objectKey);
|
||||
|
||||
// 记录文件信息到数据库
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
$fileInfo = [
|
||||
'file_name' => basename($objectKey),
|
||||
'file_path' => $objectKey,
|
||||
'file_size' => $size,
|
||||
'file_type' => $mime,
|
||||
'original_name' => $originalName,
|
||||
];
|
||||
$recordResult = $uploadedFilesService->recordFileInfo($fileInfo, null, $scene, $category);
|
||||
|
||||
$data = [
|
||||
'original_name' => $originalName,
|
||||
'file_name' => $objectKey,
|
||||
'file_url' => $privateUrl,
|
||||
'file_id' => $recordResult['id'] ?? null,
|
||||
'partition' => $scene,
|
||||
'category' => $category,
|
||||
];
|
||||
|
||||
return $data;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error($e->getMessage(),$param);
|
||||
throw new BusinessException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 OSS 上的文件
|
||||
*
|
||||
* @param array $param
|
||||
* - object_key: OSS 对象键名-oss路径(必需)
|
||||
* - file_id: 数据库文件记录ID(可选,用于删除数据库记录)
|
||||
* @return bool 删除是否成功
|
||||
*
|
||||
* 示例
|
||||
* $uploadService = new UploadService();
|
||||
*
|
||||
* 只删除 OSS 文件
|
||||
* $uploadService->deleteOssFile([
|
||||
* 'object_key' => 'vehicle_album/documents/20241201/abc123.pdf'
|
||||
* ]);
|
||||
*
|
||||
* 同时删除 OSS 文件和数据库记录
|
||||
* $uploadService->deleteOssFile([
|
||||
* 'object_key' => 'vehicle_album/images/20241201/abc123.jpg',
|
||||
* 'file_id' => 123
|
||||
* ]);
|
||||
*/
|
||||
public function deleteOssFile($objectKey,$fileId = null)
|
||||
{
|
||||
try {
|
||||
|
||||
if (empty($objectKey)) {
|
||||
Log::error('OSS对象键名不能为空', $objectKey);
|
||||
throw new BusinessException('OSS对象键名不能为空');
|
||||
}
|
||||
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
// 如果提供了文件ID,同时删除数据库记录
|
||||
if ($fileId) {
|
||||
$uploadedFilesService->deleteFile($fileId);
|
||||
}else{
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
if (empty($fileId)) {
|
||||
$where = ['file_path' => $objectKey];
|
||||
$file = $uploadedFilesService->getFile($where);
|
||||
$fileId = $file->id;
|
||||
}
|
||||
if(!empty($fileId)){
|
||||
$uploadedFilesService->deleteFile($fileId);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除 OSS 上的文件
|
||||
$ossService = new OssService();
|
||||
$ossService->deleteFile($objectKey);
|
||||
|
||||
Log::info('OSS文件删除成功', ['object_key' => $objectKey, 'file_id' => $fileId]);
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('删除OSS文件失败: ' . $e->getMessage());
|
||||
throw new BusinessException('删除OSS文件失败: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\UploadedFilesValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\UploadedFiles;
|
||||
use support\Request;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class UploadedFilesService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = UploadedFiles::class;
|
||||
|
||||
/**
|
||||
* 文件上传分区配置
|
||||
*/
|
||||
protected array $uploadPartitions = [
|
||||
'image' => [
|
||||
'path' => 'images',
|
||||
'max_size' => 5 * 1024 * 1024, // 5MB
|
||||
'allowed_types' => ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
|
||||
'extensions' => ['jpg', 'jpeg', 'png', 'gif', 'webp']
|
||||
],
|
||||
'document' => [
|
||||
'path' => 'documents',
|
||||
'max_size' => 10 * 1024 * 1024, // 10MB
|
||||
'allowed_types' => ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
|
||||
'extensions' => ['pdf', 'doc', 'docx']
|
||||
],
|
||||
'audio' => [
|
||||
'path' => 'audios',
|
||||
'max_size' => 20 * 1024 * 1024, // 20MB
|
||||
'allowed_types' => ['audio/mp3', 'audio/wav', 'audio/ogg'],
|
||||
'extensions' => ['mp3', 'wav', 'ogg']
|
||||
],
|
||||
'other' => [
|
||||
'path' => 'others',
|
||||
'max_size' => 5 * 1024 * 1024, // 5MB
|
||||
'allowed_types' => [],
|
||||
'extensions' => []
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* 记录文件信息到数据库
|
||||
*
|
||||
* @param array $fileInfo 文件信息
|
||||
* @param Request|null $request 请求对象(可选)
|
||||
* @param string $partition 分区名称
|
||||
* @param string $category 文件分类
|
||||
* @return array
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function recordFileInfo(array $fileInfo, ?Request $request = null, string $partition = 'other', string $category = 'general'): array
|
||||
{
|
||||
|
||||
// 验证必需的文件信息
|
||||
$requiredFields = ['file_name', 'file_path', 'file_size', 'file_type'];
|
||||
foreach ($requiredFields as $field) {
|
||||
if (!isset($fileInfo[$field])) {
|
||||
throw new BusinessException("缺少必需的文件信息字段: {$field}");
|
||||
}
|
||||
}
|
||||
|
||||
// 获取文件扩展名
|
||||
$fileExtension = pathinfo($fileInfo['file_name'], PATHINFO_EXTENSION);
|
||||
|
||||
// 记录到数据库
|
||||
$uploadIp = $request ? $request->getRealIp() : '0.0.0.0';
|
||||
$userAgent = $request ? $request->header('User-Agent', '') : '';
|
||||
|
||||
$fileData = [
|
||||
'file_name' => $fileInfo['file_name'],
|
||||
'file_path' => $fileInfo['file_path'],
|
||||
'file_size' => $fileInfo['file_size'],
|
||||
'file_type' => $fileInfo['file_type'],
|
||||
'category' => $category,
|
||||
'original_name' => $fileInfo['original_name'] ?? '',
|
||||
'extension' => $fileExtension,
|
||||
'partition' => $partition,
|
||||
'upload_ip' => $uploadIp,
|
||||
'user_agent' => $userAgent,
|
||||
];
|
||||
|
||||
$uploadedFile = $this->logicCreate($fileData);
|
||||
|
||||
return [
|
||||
'id' => $uploadedFile->id,
|
||||
'file_name' => $fileInfo['file_name'],
|
||||
'file_path' => $fileInfo['file_path'],
|
||||
'file_url' => getenv('MAIN_DOMAIN') . $fileInfo['file_path'],
|
||||
'file_size' => $fileInfo['file_size'],
|
||||
'file_type' => $fileInfo['file_type'],
|
||||
'category' => $category,
|
||||
'partition' => $partition,
|
||||
'original_name' => $fileInfo['original_name'] ?? '',
|
||||
'extension' => $fileExtension,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件信息
|
||||
*
|
||||
* @param int $fileId
|
||||
* @return array|null
|
||||
*/
|
||||
public function getFileInfo(int $fileId): ?array
|
||||
{
|
||||
$file = $this->logicShow(['where' => ['id' => $fileId]]);
|
||||
|
||||
if (!$file) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $file->id,
|
||||
'file_name' => $file->file_name,
|
||||
'file_path' => $file->file_path,
|
||||
'file_url' => getenv('MAIN_DOMAIN') . $file->file_path,
|
||||
'file_size' => $file->file_size,
|
||||
'file_type' => $file->file_type,
|
||||
'category' => $file->category,
|
||||
'partition' => $file->partition ?? 'other',
|
||||
'original_name' => $file->original_name ?? '',
|
||||
'extension' => $file->extension ?? '',
|
||||
'created_at' => $file->created_at,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool|\Illuminate\Database\Eloquent\Model
|
||||
*/
|
||||
public function getFile(array $where)
|
||||
{
|
||||
$config['model'] = $this->modelClass;
|
||||
$config['where'] = $where;
|
||||
$file = $this->logicShow($config);
|
||||
|
||||
if (!$file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
/**
|
||||
* 获取文件
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool|\Illuminate\Database\Eloquent\Model
|
||||
*/
|
||||
public function findFile(array $where)
|
||||
{
|
||||
$file = UploadedFiles::where(['file_path' => $where['file_path']]);
|
||||
|
||||
if (!$file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param int $fileId
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteFile(int $fileId): bool
|
||||
{
|
||||
$config['model'] = $this->modelClass;
|
||||
$config['where'] = ['id' => $fileId];
|
||||
$file = $this->logicShow($config);
|
||||
|
||||
if (!$file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 删除数据库记录
|
||||
$config =[
|
||||
'model' => $this->modelClass,
|
||||
'where' => ['id' => $fileId],
|
||||
];
|
||||
return $this->logicDeleteBy($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分区配置
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPartitionConfig(): array
|
||||
{
|
||||
return $this->uploadPartitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成文件名
|
||||
*
|
||||
* @param $file
|
||||
* @return string
|
||||
*/
|
||||
protected function generateFileName($file): string
|
||||
{
|
||||
$extension = $file->getUploadExtension();
|
||||
$timestamp = time();
|
||||
$random = substr(md5(uniqid()), 0, 8);
|
||||
|
||||
return $timestamp . '_' . $random . '.' . $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文件大小
|
||||
*
|
||||
* @param int $bytes
|
||||
* @return string
|
||||
*/
|
||||
protected function formatFileSize(int $bytes): string
|
||||
{
|
||||
$units = ['B', 'KB', 'MB', 'GB'];
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
|
||||
$bytes /= pow(1024, $pow);
|
||||
|
||||
return round($bytes, 2) . ' ' . $units[$pow];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\UsedcarCrawlResultsImagesValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\UsedcarCrawlResultsImages;
|
||||
|
||||
class UsedcarCrawlResultsImagesService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = UsedcarCrawlResultsImages::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = UsedcarCrawlResultsImagesValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\UsedcarCrawlResultsValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\UsedcarCrawlResults;
|
||||
|
||||
class UsedcarCrawlResultsService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = UsedcarCrawlResults::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = UsedcarCrawlResultsValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\UserGroupMembersValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\UserGroupMembers;
|
||||
use app\common\model\UserGroup;
|
||||
use support\Request;
|
||||
|
||||
class UserGroupMembersService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = UserGroupMembers::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = UserGroupMembersValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\UserGroupLogic;
|
||||
use app\common\logic\UserGroupMembersLogic;
|
||||
use app\common\validate\UserGroupValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\UserGroup;
|
||||
use support\Request;
|
||||
|
||||
class UserGroupService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = UserGroup::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = UserGroupValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
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']['sort'] = 'desc';
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
$config['with'] = ['groupMembers', 'groupMembers.user'];
|
||||
break;
|
||||
case 'index':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'desc';
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
$config['with'] = ['groupMembers', 'groupMembers.user'];
|
||||
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;
|
||||
case 'userGroup':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'desc';
|
||||
$config['order']['id'] = 'desc';
|
||||
$config['fields'] = ['id', 'title'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function serviceStore(Request $request, array $data = [], string $scene = 'store')
|
||||
{
|
||||
$data = $this->preProcess(ucfirst($scene), $data, $request);
|
||||
$created = (new UserGroupLogic())->createGroup($data);
|
||||
return $this->postProcess(ucfirst($scene), $created);
|
||||
}
|
||||
|
||||
public function serviceUpdate(Request $request, array $data = [], string $scene = 'update')
|
||||
{
|
||||
$data = $this->preProcess(ucfirst($scene), $data, $request);
|
||||
$config = $this->buildQueryConfig($request, $scene);
|
||||
$userGroup = $this->logicShow($config);
|
||||
$updated = (new UserGroupLogic())->updateGroup($userGroup, $data);
|
||||
return $this->postProcess(ucfirst($scene), $updated);
|
||||
}
|
||||
|
||||
public function serviceDestroy(Request $request, string $scene = 'destroy')
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, $scene);
|
||||
$deleted = $this->logicDeleteBy($config);
|
||||
(new UserGroupMembersLogic())->deleteUserGroupMembers($config['where']['id']);
|
||||
return $this->postProcess(ucfirst($scene), $deleted);
|
||||
}
|
||||
|
||||
|
||||
public function userGroup(Request $request, string $scene = 'userGroup')
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, $scene);
|
||||
$result = $this->logicListAll($config);
|
||||
return $this->postProcess(ucfirst($scene), $result);
|
||||
}
|
||||
|
||||
public function userGroupScene(Request $request, string $scene = 'userGroup')
|
||||
{
|
||||
$data = (new \app\common\service\SysDictService())->pluckKeyValueByCode('user_group_scene');
|
||||
$result = [];
|
||||
foreach($data as $key => $value) {
|
||||
$result[] = [
|
||||
'name' => $key,
|
||||
'id' => $value,
|
||||
];
|
||||
}
|
||||
return $this->postProcess(ucfirst($scene), $result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\UserLogic;
|
||||
use app\common\model\Corp;
|
||||
use app\common\model\User;
|
||||
use app\common\model\UserGroup;
|
||||
use app\common\model\UserGroupMembers;
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\utils\CrudUtil;
|
||||
use app\crm\model\Country;
|
||||
use app\crm\model\Customer;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
|
||||
class UserService
|
||||
{
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = User::class;
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new UserLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息(包括菜单和权限)
|
||||
*/
|
||||
public function getUserInfo(int $uid, string $systemCode)
|
||||
{
|
||||
$user = $this->logic->userInfo($uid);
|
||||
// $permService = new PermService();
|
||||
// $menuTree = $permService->getMenuTree($uid, $systemCode);
|
||||
// $permissionCodes = $permService->getPermissionCodes($uid, $systemCode);
|
||||
$corp_name = Corp::where('abbr', $user->corp_id)->value('name');
|
||||
return [
|
||||
'user' => [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'avatar' => $user->avatar,
|
||||
'phone' => $user->phone,
|
||||
'email' => $user->email,
|
||||
'status' => $user->status,
|
||||
'roles' => $user->roles->pluck('name'),
|
||||
'sex' => $user->sex,
|
||||
'sn' => $user->sn,
|
||||
'corp_id' => $user->corp_id,
|
||||
'corp_name' => $corp_name,
|
||||
'report_to' => $user->report_to,
|
||||
'sign_img' => $user->sign_img,
|
||||
'sign_img_url' => (!empty($user->sign_img))?(new \app\common\service\OssService)->generatePrivateUrl($user->sign_img):'',
|
||||
],
|
||||
// 'menu' => $menuTree,
|
||||
// 'permissions' => $permissionCodes
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户信息(包括菜单和权限)
|
||||
*/
|
||||
public function getUser(int $uid, $corp_abbr)
|
||||
{
|
||||
$user = $this->logic->userInfo($uid);
|
||||
|
||||
// 查找直属上级 10.13 add
|
||||
$reportToInfo = [];
|
||||
if ($user->reportToInfo) {
|
||||
$reportToInfo = [
|
||||
'id' => $user->reportToInfo->id,
|
||||
'name' => $user->reportToInfo->name
|
||||
];
|
||||
}
|
||||
|
||||
// 查找绑定内勤 10.13 add
|
||||
$officeClerkInfo = [];
|
||||
$ugm = UserGroupMembers::where('user_id', $uid)->where('status', 1)->first();
|
||||
if ($ugm) {
|
||||
$lugm = UserGroupMembers::where('group_id', $ugm->group_id)->where('is_leader', 1)->first();
|
||||
if ($lugm) {
|
||||
$officeClerkInfo['id'] = $lugm->user_id;
|
||||
$officeClerkInfo['name'] = User::where('id', $lugm->user_id)->value('name');
|
||||
}
|
||||
}
|
||||
|
||||
$corp_name = Corp::where('abbr', $corp_abbr)->value('name');
|
||||
$ossservice = new OssService();
|
||||
return [
|
||||
'id' => $user->id,
|
||||
'sn' => $user->sn,
|
||||
'name' => $user->name,
|
||||
'position' => $user->position,
|
||||
'socialize' => $user->socialize,
|
||||
'socialize_pic' => $user->socialize_pic,
|
||||
'socialize_pic_full' => (!empty($user->socialize_pic))?$ossservice->generatePrivateUrl($user->socialize_pic):'',
|
||||
'country_id' => $user->country_id,
|
||||
'country_txt' => Country::where('id',$user->country_id)->value('cn_addr'),
|
||||
'avatar' => $user->avatar,
|
||||
'avatar_full' => $user->avatar,
|
||||
'phone' => $user->phone,
|
||||
'corp_name' => $corp_name,
|
||||
'email' => $user->email,
|
||||
'sex' => $user->sex,
|
||||
'status' => $user->status,
|
||||
'roles' => $user->roles->pluck('name'),
|
||||
'sign_img' => $user->sign_img,
|
||||
'sign_img_url' => (!empty($user->sign_img))?$ossservice->generatePrivateUrl($user->sign_img):'',
|
||||
'report_to_info' => $reportToInfo,
|
||||
'office_clerk_info' => $officeClerkInfo
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑用户信息
|
||||
*/
|
||||
public function edit(int $uid, array $data)
|
||||
{
|
||||
unset($data['password']);
|
||||
unset($data['phone']);
|
||||
unset($data['email']);
|
||||
unset($data['sn']);
|
||||
|
||||
$user = $this->logic->edit($uid,$data);
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
*/
|
||||
public function savePassword(int $uid, array $data)
|
||||
{
|
||||
// 对密码进行哈希处理
|
||||
$password = $data['password'];
|
||||
$user = User::find($uid);
|
||||
if (!password_verify($password, $user->password)) {
|
||||
throw new BusinessException('密码错误');
|
||||
}
|
||||
|
||||
$user = $this->logic->savePassword($uid,$data);
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
*/
|
||||
public function getList(Request $request)
|
||||
{
|
||||
return $this->logic->getList($request);
|
||||
}
|
||||
|
||||
/** 分页列表 */
|
||||
public function serviceTeam(Request $request)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'team');
|
||||
$limit = (int)$request->get('size', 15);
|
||||
$page = (int)$request->get('current', 1);
|
||||
$result = $this->logicList($config, $limit, $page);
|
||||
|
||||
foreach ($result as &$data){
|
||||
$data['customer_count'] = Customer::where('user_id', $data['id'])->count();
|
||||
unset($data['password']);
|
||||
unset($data['open_id']);
|
||||
unset($data['tenant_key']);
|
||||
unset($data['union_id']);
|
||||
}
|
||||
|
||||
return $this->postProcess('List', $result);
|
||||
}
|
||||
|
||||
/** 分页列表 */
|
||||
public function resignMember(Request $request)
|
||||
{
|
||||
$uid = $request->user->uid;
|
||||
$userId = $request->get('user_id');
|
||||
$user = User::find($userId);
|
||||
if ($user->report_to != $uid) {
|
||||
throw new BusinessException('禁止操作非组员');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'status' => 2,
|
||||
];
|
||||
$user = $this->logic->edit($userId,$data);
|
||||
$user = $user->toArray();
|
||||
unset($user['password']);
|
||||
unset($user['open_id']);
|
||||
unset($user['tenant_key']);
|
||||
unset($user['union_id']);
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 CrudUtil 查询配置
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'team':
|
||||
// $config['where']['status'] = 1; // 关键字
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
if (isset($p['status']) && $p['status']) {
|
||||
$config['where']['status'] = $p['status'];
|
||||
}
|
||||
|
||||
$config['with']= ['reportToInfo'];
|
||||
if (!in_array(1, $request->user->role_ids)) {
|
||||
$config['where']['reportToInfo.id'] = $request->user->uid;
|
||||
}
|
||||
|
||||
// $config['dataLimit']['type'] = 'relation';
|
||||
// $config['dataLimit']['userId'] = $request->user->uid;
|
||||
// $config['dataLimit']['userField'] = 'report_to';
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
public function checkBind($userId)
|
||||
{
|
||||
$user = \app\common\model\User::find($userId);
|
||||
if (!$user->report_to) {
|
||||
throw new BusinessException('请先前往个人中心-绑定直属上级');
|
||||
}
|
||||
|
||||
if ($user->sign_img === null || $user->sign_img === '') {
|
||||
throw new BusinessException('请先前往个人中心-操作签名');
|
||||
}
|
||||
|
||||
$ug = \app\common\model\UserGroupMembers::with(['group' => function($query) {
|
||||
$query->where('scenario_code', 'stock_orders');
|
||||
}])->where('user_id', $userId)->first();
|
||||
if (!$ug) {
|
||||
throw new BusinessException('请先前往个人中心-绑定内勤');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\admin\validate\VehColorValidate;
|
||||
use app\common\logic\VehColorLogic;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\VehColor;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class VehColorService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new VehColorLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public function getList($params)
|
||||
{
|
||||
if (empty($params['type']))
|
||||
throw new BusinessException('类型不能为空');
|
||||
$where = [];
|
||||
if(isset($params['type']) && $params['type'])
|
||||
$where[] = ['type', '=', $params['type']];
|
||||
return $this->logic->getList($where);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\VehDictI18nValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\VehDictI18n;
|
||||
|
||||
class VehDictI18nService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = VehDictI18n::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = VehDictI18nValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
/** 本进程缓存:[dict][code] => labels array */
|
||||
protected static array $labelsCache = [];
|
||||
|
||||
public static function label(string $dict=null, ?string $code=null, string $locale='zh-CN', ?string $fallbackZh=null): ?string
|
||||
{
|
||||
if (!$dict || !$code) return $fallbackZh;
|
||||
|
||||
$labels = self::labels($dict, $code);
|
||||
if (!$labels) return $fallbackZh ?? $code;
|
||||
|
||||
return $labels[$locale] ?? $labels['zh-CN'] ?? $code;
|
||||
}
|
||||
|
||||
/** 返回 labels 数组,命中缓存 */
|
||||
public static function labels(string $dict, string $code): ?array
|
||||
{
|
||||
$dict = strtoupper($dict);
|
||||
$code = (string)$code;
|
||||
|
||||
if (isset(self::$labelsCache[$dict][$code])) {
|
||||
return self::$labelsCache[$dict][$code];
|
||||
}
|
||||
|
||||
$term = DictTerm::where('dict',$dict)->where('code',$code)->first(['labels']);
|
||||
if (!$term) return null;
|
||||
|
||||
$labels = $term->labels ?? null;
|
||||
if (!is_array($labels)) return null;
|
||||
|
||||
self::$labelsCache[$dict][$code] = $labels;
|
||||
return $labels;
|
||||
}
|
||||
|
||||
/** 校验 code 是否存在于字典(用于必填维度) */
|
||||
public static function ensureExists(string $dict, ?string $code, string $fieldNameForError): void
|
||||
{
|
||||
if ($code === null || $code === '') {
|
||||
throw new \InvalidArgumentException("缺少必填字段:{$fieldNameForError}");
|
||||
}
|
||||
$ok = VehDictI18n::where('dict',$dict)->where('code',$code)->where('status', 1)->exists();
|
||||
if (!$ok) throw new \InvalidArgumentException("字典不存在或未启用:{$dict}.{$code}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\VehDictMappingValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\VehDictMapping;
|
||||
|
||||
class VehDictMappingService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = VehDictMapping::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = VehDictMappingValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
public static function all(): array
|
||||
{
|
||||
$rows = VehDictMapping::where('status', 1)->orderBy('sort')->orderBy('id')->get()->toArray();
|
||||
$out = [];
|
||||
foreach ($rows as $r) {
|
||||
$out[$r['dict']] = [
|
||||
'field' => $r['field'],
|
||||
'dict' => $r['dict'],
|
||||
'required' => (int)$r['required'] === 1,
|
||||
];
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public static function requiredDicts(): array
|
||||
{
|
||||
return array_keys(array_filter(self::all(), fn($x)=>$x['required']===true));
|
||||
}
|
||||
|
||||
public static function enabled(string $dict): bool
|
||||
{
|
||||
$all = self::all();
|
||||
return isset($all[$dict]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\admin\validate\VehModificationValidate;
|
||||
use app\common\logic\VehModificationLogic;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\VehModification;
|
||||
use support\Request;
|
||||
|
||||
class VehModificationService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new VehModificationLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
return $this->logic->getList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\VehMoneyValueValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\VehMoneyValue;
|
||||
use support\Db;
|
||||
|
||||
class VehMoneyValueService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = VehMoneyValue::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = VehMoneyValueValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 复制金额记录
|
||||
*
|
||||
* @param string $fromScene 源场景
|
||||
* @param int $fromId 源对象ID
|
||||
* @param string $toScene 目标场景
|
||||
* @param int $toId 目标对象ID
|
||||
* @return int 插入条数
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function copyMoneyValues(string $fromScene, int $fromId, string $toScene, int $toId): int
|
||||
{
|
||||
// 1. 查询源数据
|
||||
$rows = Db::table('veh_money_value')
|
||||
->where('object_scene', $fromScene)
|
||||
->where('object_id', $fromId)
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
if (empty($rows)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$now = time();
|
||||
$insertData = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$insertData[] = [
|
||||
'object_scene' => $toScene,
|
||||
'object_id' => $toId,
|
||||
'field' => $row->field,
|
||||
'currency' => $row->currency,
|
||||
'amount' => $row->amount,
|
||||
'exchange_rate' => $row->exchange_rate,
|
||||
'remark' => $row->remark,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
}
|
||||
|
||||
// 2. 插入新数据
|
||||
return Db::table('veh_money_value')->insert($insertData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\VehVehicleListingValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\VehVehicleListing;
|
||||
|
||||
class VehVehicleListingService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = VehVehicleListing::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = VehVehicleListingValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\Fingerprint;
|
||||
use app\common\logic\ModelNaming;
|
||||
use app\common\logic\SkuCodeBuilder;
|
||||
use app\common\logic\VehVehicleSkuLogic;
|
||||
use app\common\model\Brand;
|
||||
use app\common\model\BrandSeries;
|
||||
use app\common\validate\VehVehicleSkuValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\VehVehicleSku;
|
||||
use support\Request;
|
||||
|
||||
class VehVehicleSkuService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = VehVehicleSku::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = VehVehicleSkuValidate::class;
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new VehVehicleSkuLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
// // 枚举
|
||||
// private const MAPS = [
|
||||
// 'BODY' => [
|
||||
// 'SEDAN' => '三厢轿车', 'SUV'=>'SUV', 'HB'=>'两厢/掀背', 'MPV'=>'MPV', 'PICKUP'=>'皮卡'
|
||||
// ],
|
||||
// 'DRIVE' => [
|
||||
// 'FWD'=>'前驱', 'RWD'=>'后驱', 'AWD'=>'四驱(AWD)', '4WD'=>'四驱(4WD)'
|
||||
// ],
|
||||
// 'MOTOR_LAYOUT' => [
|
||||
// 'FWD'=>'前置单电机', 'RWD'=>'后置单电机', 'AWD'=>'双电机四驱', 'DM-I'=>'DM-i', 'DM-P'=>'DM-p'
|
||||
// ],
|
||||
// 'FUEL' => [
|
||||
// 'GAS'=>'汽油', 'HEV'=>'油电混动', 'PHEV'=>'插电混动', 'EV'=>'纯电', 'EREV'=>'增程'
|
||||
// ],
|
||||
// 'TRANS' => [
|
||||
// 'MT'=>'手动', 'AT'=>'自动', 'CVT'=>'无级', 'DCT'=>'双离合', '1SPEED'=>'单速'
|
||||
// ],
|
||||
// 'RANGE_STD' => [
|
||||
// 'CLTC'=>'CLTC', 'WLTP'=>'WLTP', 'EPA'=>'EPA', 'NEDC'=>'NEDC'
|
||||
// ],
|
||||
// 'EMISSION' => [
|
||||
// 'CHN6'=>'国六', 'EURO6'=>'欧6', 'EPA'=>'美国EPA'
|
||||
// ],
|
||||
// ];
|
||||
|
||||
// // *_code取中文
|
||||
// public function label(string $dict, ?string $code): ?string
|
||||
// {
|
||||
// if ($code === null || $code === '') return null;
|
||||
// $dict = strtoupper($dict);
|
||||
// $code = strtoupper($code);
|
||||
// return self::MAPS[$dict][$code] ?? $code;
|
||||
// }
|
||||
|
||||
// // 静态映射把 *_code → 中文
|
||||
// private function backfill(array $d): array
|
||||
// {
|
||||
// $d['body_type'] = $this->label('BODY', $d['body_type_code']);
|
||||
// $d['drive_type'] = $this->label('DRIVE', $d['drive_type_code']);
|
||||
// $d['motor_layout'] = $this->label('MOTOR_LAYOUT', $d['motor_layout_code']);
|
||||
// $d['fuel_type'] = $this->label('FUEL', $d['fuel_type_code']);
|
||||
// $d['transmission'] = $this->label('TRANS', $d['transmission_code']);
|
||||
// $d['range_std'] = $this->label('RANGE_STD', $d['range_std_code']);
|
||||
// $d['emission_std'] = $this->label('EMISSION', $d['emission_std_code']);
|
||||
// return $d;
|
||||
// }
|
||||
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'default':
|
||||
$config['where']['is_active'] = 1;
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
// 关键字筛选
|
||||
if (isset($p['keyword']) && $p['keyword']) {
|
||||
$k = '%' . $p['keyword'] . '%';
|
||||
foreach (['model_name','series_name','brand_name',] as $col) {
|
||||
$config['orWhere'][] = [$col, 'like', $k];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'index':
|
||||
$config['where']['is_active'] = 1;
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
// 关键字筛选
|
||||
if (isset($p['keyword']) && $p['keyword']) {
|
||||
$k = '%' . $p['keyword'] . '%';
|
||||
foreach (['model_name','series_name','brand_name',] as $col) {
|
||||
$config['orWhere'][] = [$col, 'like', $k];
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($p['brand_id']) && $p['brand_id']){
|
||||
$brand_code = Brand::where('id', $p['brand_id'])->value('brand_code');
|
||||
$config['where']['brand_code'] = $brand_code;
|
||||
}
|
||||
if(isset($p['series_id']) && $p['series_id']){
|
||||
$series_code = BrandSeries::where('id', $p['series_id'])->value('series_code');
|
||||
$config['where']['series_code'] = $series_code;
|
||||
}
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['is_active'] = 1;
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
// $data = $this->backfill($data);
|
||||
if (empty($data['model_code'])) {
|
||||
$data['model_code'] = ModelNaming::buildModelCode($data);
|
||||
}
|
||||
if (empty($data['model_name'])) {
|
||||
$data['model_name'] = ModelNaming::buildModelName($data);
|
||||
}
|
||||
if (empty($data['engine_disp_l'])) {
|
||||
$data['engine_disp_l'] = 0;
|
||||
}
|
||||
if (empty($data['engine_turbo'])) {
|
||||
$data['engine_turbo'] = 0;
|
||||
}
|
||||
if (empty($data['engine_power_kw'])) {
|
||||
$data['engine_power_kw'] = 0;
|
||||
}
|
||||
if (empty($data['battery_kwh'])) {
|
||||
$data['battery_kwh'] = 0;
|
||||
}
|
||||
if (empty($data['gears'])) {
|
||||
$data['gears'] = 1;
|
||||
}
|
||||
if (empty($data['range_km'])) { //续航
|
||||
$data['range_km'] = 0;
|
||||
}
|
||||
if (empty($data['doors'])) { //车位数
|
||||
$data['doors'] = 0;
|
||||
}
|
||||
if (empty($data['seats'])) { //座位数
|
||||
$data['seats'] = 0;
|
||||
}
|
||||
if (empty($data['weight_kg'])) { //整车质量
|
||||
$data['weight_kg'] = 0;
|
||||
}
|
||||
$data['sku_code'] = SkuCodeBuilder::build($data);
|
||||
$data['corp_id'] = 0;
|
||||
$data['created_by'] = $request->user->uid;
|
||||
$data['updated_by'] = $request->user->uid;
|
||||
//指纹数组
|
||||
$fingerprintArr = [
|
||||
'brand_name' => $data['brand_name'],
|
||||
'series_name' => $data['series_name'],
|
||||
'model_name' => $data['model_name'],
|
||||
'model_year' => $data['model_year'],
|
||||
'msrp' => $data['msrp'],
|
||||
];
|
||||
// 生成指纹
|
||||
$data['fingerprint'] = Fingerprint::makeFromArray($fingerprintArr);
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function afterServiceStore($res)
|
||||
{
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
public function beforeServiceUpdate($data, Request $request)
|
||||
{
|
||||
unset($data['created_at']);
|
||||
unset($data['updated_at']);
|
||||
// $data = $this->backfill($data);
|
||||
if (empty($data['model_code'])) {
|
||||
$data['model_code'] = ModelNaming::buildModelCode($data);
|
||||
}
|
||||
if (empty($data['model_name'])) {
|
||||
$data['model_name'] = ModelNaming::buildModelName($data);
|
||||
}
|
||||
// 填充系统字段
|
||||
$data['updated_by'] = $request->user->uid;
|
||||
//指纹数组
|
||||
$fingerprintArr = [
|
||||
'brand_name' => $data['brand_name'],
|
||||
'series_name' => $data['series_name'],
|
||||
'model_name' => $data['model_name'],
|
||||
'model_year' => $data['model_year'],
|
||||
'msrp' => $data['msrp'],
|
||||
];
|
||||
// 生成指纹
|
||||
$data['fingerprint'] = Fingerprint::makeFromArray($fingerprintArr);
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function afterServiceUpdate($res)
|
||||
{
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取车型list
|
||||
*/
|
||||
public function getList($data)
|
||||
{
|
||||
return $this->logic->getList($data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\VehVehicleUnitValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\VehVehicleUnit;
|
||||
|
||||
class VehVehicleUnitService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = VehVehicleUnit::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = VehVehicleUnitValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user