458 lines
13 KiB
PHP
458 lines
13 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace app\common\service;
|
||
|
|
|
||
|
|
use app\common\validate\UsedCarDetailValidate;
|
||
|
|
use app\common\traits\crud\CrudServiceTrait;
|
||
|
|
use app\common\model\UsedCarDetail;
|
||
|
|
use app\common\model\User;
|
||
|
|
use support\exception\BusinessException;
|
||
|
|
use support\Log;
|
||
|
|
use support\Request;
|
||
|
|
use support\Redis;
|
||
|
|
|
||
|
|
class UsedCarDetailService
|
||
|
|
{
|
||
|
|
|
||
|
|
use CrudServiceTrait;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 指定当前要操作的模型
|
||
|
|
*/
|
||
|
|
protected string $modelClass = UsedCarDetail::class;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 验证器
|
||
|
|
*/
|
||
|
|
protected $validator = UsedCarDetailValidate::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';
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'index':
|
||
|
|
// 默认只显示审核通过的数据
|
||
|
|
$config['where']['status'] = 1;
|
||
|
|
|
||
|
|
// 审核状态筛选
|
||
|
|
if (isset($p['status'])) {
|
||
|
|
$config['where']['status'] = $p['status'];
|
||
|
|
}
|
||
|
|
|
||
|
|
// 我的车辆
|
||
|
|
if (isset($p['scene']) && $p['scene'] == 'self') {
|
||
|
|
$config['where']['user_id'] = $request->user['id'];
|
||
|
|
unset($config['where']['status']);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 关键字搜索
|
||
|
|
if (isset($p['keyword']) && $p['keyword']) {
|
||
|
|
$k = '%' . $p['keyword'] . '%';
|
||
|
|
foreach (['product_name', 'code', 'vin', 'manufacturer'] as $col) {
|
||
|
|
$config['orWhere'][] = [$col, 'like', $k];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 品牌筛选
|
||
|
|
if (isset($p['crawl_brand_id']) && $p['crawl_brand_id']) {
|
||
|
|
$config['where']['crawl_brand_id'] = $p['crawl_brand_id'];
|
||
|
|
}
|
||
|
|
|
||
|
|
// 车系筛选
|
||
|
|
if (isset($p['crawl_series_id']) && $p['crawl_series_id']) {
|
||
|
|
$config['where']['crawl_series_id'] = $p['crawl_series_id'];
|
||
|
|
}
|
||
|
|
|
||
|
|
// 价格区间
|
||
|
|
if (isset($p['min_price']) && $p['min_price']) {
|
||
|
|
$config['where'][] = ['price', '>=', $p['min_price']];
|
||
|
|
}
|
||
|
|
if (isset($p['max_price']) && $p['max_price']) {
|
||
|
|
$config['where'][] = ['price', '<=', $p['max_price']];
|
||
|
|
}
|
||
|
|
|
||
|
|
$config['order']['sort'] = 'desc';
|
||
|
|
$config['order']['id'] = 'desc';
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'show':
|
||
|
|
$config['where']['id'] = $p['id'];
|
||
|
|
// 关联FAQ
|
||
|
|
$config['with'] = ['faqs'];
|
||
|
|
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): array
|
||
|
|
{
|
||
|
|
if (empty($data['product_name'])) {
|
||
|
|
throw new BusinessException('产品名称不能为空');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 设置用户信息
|
||
|
|
$data['user_id'] = $request->user['id'];
|
||
|
|
$user = User::where('id', $request->user['id'])->first();
|
||
|
|
$data['role_wp'] = $user['role_wp'] ?? 1;
|
||
|
|
|
||
|
|
// 默认待审核状态
|
||
|
|
if (!isset($data['status'])) {
|
||
|
|
$data['status'] = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 生成车辆编号
|
||
|
|
$data['code'] = $this->getCode($request->user['id']);
|
||
|
|
|
||
|
|
// 处理图片数据
|
||
|
|
if (!empty($data['images'])) {
|
||
|
|
if (is_array($data['images'])) {
|
||
|
|
$data['images'] = json_encode($data['images']);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
$data['images'] = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
// 处理附件数据
|
||
|
|
if (!empty($data['attachment'])) {
|
||
|
|
if (is_array($data['attachment'])) {
|
||
|
|
$data['attachment'] = json_encode($data['attachment']);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
$data['attachment'] = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
// 处理介绍图片
|
||
|
|
if (!empty($data['intro_images'])) {
|
||
|
|
if (is_array($data['intro_images'])) {
|
||
|
|
$data['intro_images'] = json_encode($data['intro_images']);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
$data['intro_images'] = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
// 检查来源URL是否重复
|
||
|
|
if (!empty($data['source_url'])) {
|
||
|
|
$exists = UsedCarDetail::where('source_url', $data['source_url']);
|
||
|
|
$exists = $exists->where('user_id', $data['user_id']);
|
||
|
|
if ($exists->exists()) {
|
||
|
|
throw new BusinessException('该车源已收录');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 更新前数据处理
|
||
|
|
*/
|
||
|
|
public function beforeServiceUpdate($data, Request $request): array
|
||
|
|
{
|
||
|
|
if (empty($data['product_name'])) {
|
||
|
|
throw new BusinessException('产品名称不能为空');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取车辆信息
|
||
|
|
$carId = $data['id'] ?? null;
|
||
|
|
if ($carId) {
|
||
|
|
$car = UsedCarDetail::find($carId);
|
||
|
|
if (!$car) {
|
||
|
|
throw new BusinessException('车辆不存在');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 审核通过的车辆禁止修改
|
||
|
|
if ($car->status == 1) {
|
||
|
|
throw new BusinessException('审核通过的车辆禁止修改');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 审核拒绝的车辆修改后状态改为待审核
|
||
|
|
if ($car->status == 2) {
|
||
|
|
$data['status'] = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 处理图片数据
|
||
|
|
if (isset($data['images'])) {
|
||
|
|
if (is_array($data['images'])) {
|
||
|
|
$data['images'] = json_encode($data['images']);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 处理附件数据
|
||
|
|
if (isset($data['attachment'])) {
|
||
|
|
if (is_array($data['attachment'])) {
|
||
|
|
$data['attachment'] = json_encode($data['attachment']);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 处理介绍图片
|
||
|
|
if (isset($data['intro_images'])) {
|
||
|
|
if (is_array($data['intro_images'])) {
|
||
|
|
$data['intro_images'] = json_encode($data['intro_images']);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 更新状态
|
||
|
|
*/
|
||
|
|
public function serviceUpdateStatus(Request $request, array $data)
|
||
|
|
{
|
||
|
|
if (empty($data['id'])) {
|
||
|
|
throw new BusinessException('id不能为空');
|
||
|
|
}
|
||
|
|
if (!isset($data['status'])) {
|
||
|
|
throw new BusinessException('status错误');
|
||
|
|
}
|
||
|
|
return UsedCarDetail::where('id', $data['id'])->update(['status' => $data['status']]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 保存FAQ
|
||
|
|
*/
|
||
|
|
public function saveFaqs(int $carId, array $faqs)
|
||
|
|
{
|
||
|
|
// 删除旧的FAQ
|
||
|
|
\app\common\model\UsedCarFaq::where('car_id', $carId)->delete();
|
||
|
|
|
||
|
|
// 创建新的FAQ
|
||
|
|
if (!empty($faqs)) {
|
||
|
|
foreach ($faqs as $faq) {
|
||
|
|
\app\common\model\UsedCarFaq::create([
|
||
|
|
'car_id' => $carId,
|
||
|
|
'question' => $faq['question'] ?? '',
|
||
|
|
'answer' => $faq['answer'] ?? '',
|
||
|
|
'sort' => $faq['sort'] ?? 0,
|
||
|
|
'status' => $faq['status'] ?? 1,
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 生成车辆编号
|
||
|
|
*/
|
||
|
|
public function getCode(int $userId): string
|
||
|
|
{
|
||
|
|
$userCount = Redis::get('used_car_detail_count_' . $userId, 0);
|
||
|
|
$todayStart = strtotime('today');
|
||
|
|
$count = UsedCarDetail::where('user_id', $userId)
|
||
|
|
->where('created_at', '>=', $todayStart)
|
||
|
|
->count();
|
||
|
|
$count = $count < $userCount ? $userCount + 1 : $count + 1;
|
||
|
|
$countCode = str_pad($count, 3, '0', STR_PAD_LEFT);
|
||
|
|
$userCode = str_pad($userId, 3, '0', STR_PAD_LEFT);
|
||
|
|
Redis::set('used_car_detail_count_' . $userId, $count, 86400);
|
||
|
|
|
||
|
|
$user = User::where('id', $userId)->first();
|
||
|
|
$nameInitials = $this->getNameInitials($user['name'] ?? '');
|
||
|
|
|
||
|
|
return 'UCD' . $nameInitials . $userCode . date('Ymd') . $countCode;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取中文名拼音首字母
|
||
|
|
*/
|
||
|
|
private function getNameInitials(string $name): string
|
||
|
|
{
|
||
|
|
$initials = '';
|
||
|
|
$len = mb_strlen($name);
|
||
|
|
for ($i = 0; $i < $len; $i++) {
|
||
|
|
$char = mb_substr($name, $i, 1);
|
||
|
|
$initials .= $this->getFirstChar($char);
|
||
|
|
}
|
||
|
|
return strtoupper($initials);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取单个字符的首字母
|
||
|
|
*/
|
||
|
|
private function getFirstChar(string $char): string
|
||
|
|
{
|
||
|
|
$s = iconv('UTF-8', 'GB2312//IGNORE', $char);
|
||
|
|
$asc = ord($s[0]);
|
||
|
|
|
||
|
|
if ($asc >= 65 && $asc <= 90) {
|
||
|
|
return $char;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($s === false || strlen($s) < 2) {
|
||
|
|
return '';
|
||
|
|
}
|
||
|
|
|
||
|
|
$code = ord($s[0]) * 256 + ord($s[1]) - 65536;
|
||
|
|
|
||
|
|
$map = [
|
||
|
|
[-20319, -20284, 'A'],
|
||
|
|
[-20283, -19776, 'B'],
|
||
|
|
[-19775, -19219, 'C'],
|
||
|
|
[-19218, -18711, 'D'],
|
||
|
|
[-18710, -18527, 'E'],
|
||
|
|
[-18526, -18240, 'F'],
|
||
|
|
[-18239, -17923, 'G'],
|
||
|
|
[-17922, -17418, 'H'],
|
||
|
|
[-17417, -16475, 'J'],
|
||
|
|
[-16474, -16213, 'K'],
|
||
|
|
[-16212, -15641, 'L'],
|
||
|
|
[-15640, -15166, 'M'],
|
||
|
|
[-15165, -14923, 'N'],
|
||
|
|
[-14922, -14915, 'O'],
|
||
|
|
[-14914, -14631, 'P'],
|
||
|
|
[-14630, -14150, 'Q'],
|
||
|
|
[-14149, -14091, 'R'],
|
||
|
|
[-14090, -13319, 'S'],
|
||
|
|
[-13318, -12839, 'T'],
|
||
|
|
[-12838, -12557, 'W'],
|
||
|
|
[-12556, -11848, 'X'],
|
||
|
|
[-11847, -11056, 'Y'],
|
||
|
|
[-11055, -10247, 'Z']
|
||
|
|
];
|
||
|
|
|
||
|
|
foreach ($map as [$start, $end, $letter]) {
|
||
|
|
if ($code >= $start && $code <= $end) {
|
||
|
|
return $letter;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return '';
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 提交审核
|
||
|
|
*/
|
||
|
|
public function submitAudit(Request $request, int $carId)
|
||
|
|
{
|
||
|
|
$car = UsedCarDetail::find($carId);
|
||
|
|
if (!$car) {
|
||
|
|
throw new BusinessException('车辆不存在');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 检查权限:只能提交自己创建的车辆
|
||
|
|
if ($car->user_id != $request->user['id']) {
|
||
|
|
throw new BusinessException('无权操作');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 只有待审核状态才能提交
|
||
|
|
if ($car->status != 0) {
|
||
|
|
throw new BusinessException('当前状态不允许提交审核');
|
||
|
|
}
|
||
|
|
|
||
|
|
return UsedCarDetail::where('id', $carId)->update(['status' => 0]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 审核车辆
|
||
|
|
*/
|
||
|
|
public function audit(Request $request, array $data)
|
||
|
|
{
|
||
|
|
$carId = $data['car_id'] ?? null;
|
||
|
|
$auditStatus = $data['audit_status'] ?? null;
|
||
|
|
$auditReason = $data['audit_reason'] ?? '';
|
||
|
|
|
||
|
|
if (empty($carId)) {
|
||
|
|
throw new BusinessException('车辆ID不能为空');
|
||
|
|
}
|
||
|
|
if (!isset($auditStatus) || !in_array($auditStatus, [1, 2])) {
|
||
|
|
throw new BusinessException('审核状态错误');
|
||
|
|
}
|
||
|
|
|
||
|
|
$car = UsedCarDetail::find($carId);
|
||
|
|
if (!$car) {
|
||
|
|
throw new BusinessException('车辆不存在');
|
||
|
|
}
|
||
|
|
|
||
|
|
$beforeStatus = $car->status;
|
||
|
|
|
||
|
|
// 创建审核记录
|
||
|
|
\app\common\model\UsedCarDetailAudit::create([
|
||
|
|
'car_id' => $carId,
|
||
|
|
'auditor_id' => $request->user['id'],
|
||
|
|
'audit_status' => $auditStatus,
|
||
|
|
'audit_reason' => $auditReason,
|
||
|
|
'before_status' => $beforeStatus,
|
||
|
|
'after_status' => $auditStatus,
|
||
|
|
]);
|
||
|
|
|
||
|
|
// 更新车辆状态
|
||
|
|
return UsedCarDetail::where('id', $carId)->update(['status' => $auditStatus]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取审核记录列表
|
||
|
|
*/
|
||
|
|
public function getAuditRecords(int $carId)
|
||
|
|
{
|
||
|
|
return \app\common\model\UsedCarDetailAudit::where('car_id', $carId)
|
||
|
|
->with(['auditor:id,name'])
|
||
|
|
->orderBy('created_at', 'desc')
|
||
|
|
->get()
|
||
|
|
->map(function ($item) {
|
||
|
|
return [
|
||
|
|
'id' => $item->id,
|
||
|
|
'audit_status' => $item->audit_status,
|
||
|
|
'audit_status_text' => $item->audit_status_text,
|
||
|
|
'audit_reason' => $item->audit_reason,
|
||
|
|
'before_status' => $item->before_status,
|
||
|
|
'after_status' => $item->after_status,
|
||
|
|
'auditor_name' => $item->auditor->name ?? '',
|
||
|
|
'created_at' => date('Y-m-d H:i:s', $item->created_at),
|
||
|
|
];
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取审核统计数据
|
||
|
|
*/
|
||
|
|
public function getAuditStats(Request $request)
|
||
|
|
{
|
||
|
|
$query = UsedCarDetail::query();
|
||
|
|
|
||
|
|
// 如果不是管理员,只能看到自己的数据
|
||
|
|
if ($request->user['role_wp'] != 3) {
|
||
|
|
$query->where('user_id', $request->user['id']);
|
||
|
|
}
|
||
|
|
|
||
|
|
return [
|
||
|
|
'pending' => (clone $query)->where('status', 0)->count(),
|
||
|
|
'approved' => (clone $query)->where('status', 1)->count(),
|
||
|
|
'rejected' => (clone $query)->where('status', 2)->count(),
|
||
|
|
'total' => $query->count(),
|
||
|
|
];
|
||
|
|
}
|
||
|
|
}
|