wp车辆信息
This commit is contained in:
@@ -0,0 +1,305 @@
|
|||||||
|
<?php
|
||||||
|
namespace app\common\controller;
|
||||||
|
|
||||||
|
use app\common\controller\BaseController;
|
||||||
|
use app\common\traits\crud\CrudControllerTrait;
|
||||||
|
use app\common\service\UsedCarDetailService;
|
||||||
|
use app\common\service\OssService;
|
||||||
|
use support\Request;
|
||||||
|
use support\exception\BusinessException;
|
||||||
|
|
||||||
|
class UsedCarDetailController extends BaseController
|
||||||
|
{
|
||||||
|
use CrudControllerTrait;
|
||||||
|
|
||||||
|
protected $service;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->service = new UsedCarDetailService();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表页数据格式化
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function indexFormat($data)
|
||||||
|
{
|
||||||
|
if (isset($data['created_at'])) {
|
||||||
|
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||||
|
}
|
||||||
|
if (isset($data['updated_at'])) {
|
||||||
|
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理图片
|
||||||
|
if (!empty($data['images'])) {
|
||||||
|
$images = is_array($data['images']) ? $data['images'] : json_decode($data['images'], true);
|
||||||
|
if ($images) {
|
||||||
|
$ossService = new OssService();
|
||||||
|
$images_pull = [];
|
||||||
|
foreach ($images as $image) {
|
||||||
|
$images_pull[] = $ossService->generatePrivateUrl($image);
|
||||||
|
}
|
||||||
|
$data['images_pull'] = $images_pull;
|
||||||
|
} else {
|
||||||
|
$data['images_pull'] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 详情页数据格式化
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function showFormat($data)
|
||||||
|
{
|
||||||
|
if (isset($data['created_at'])) {
|
||||||
|
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||||
|
}
|
||||||
|
if (isset($data['updated_at'])) {
|
||||||
|
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理主图
|
||||||
|
if (!empty($data['images'])) {
|
||||||
|
$images = is_array($data['images']) ? $data['images'] : json_decode($data['images'], true);
|
||||||
|
if ($images) {
|
||||||
|
$ossService = new OssService();
|
||||||
|
$images_pull = [];
|
||||||
|
$process = 'image/resize,w_800/quality,Q_40/format,webp';
|
||||||
|
foreach ($images as $image) {
|
||||||
|
$images_pull[] = $ossService->generatePrivateUrlResize($image, 3600, $process);
|
||||||
|
}
|
||||||
|
$data['images_pull'] = $images_pull;
|
||||||
|
} else {
|
||||||
|
$data['images_pull'] = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$data['images_pull'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理介绍图片
|
||||||
|
if (!empty($data['intro_images'])) {
|
||||||
|
$introImages = is_array($data['intro_images']) ? $data['intro_images'] : json_decode($data['intro_images'], true);
|
||||||
|
if ($introImages) {
|
||||||
|
$ossService = new OssService();
|
||||||
|
$intro_images_pull = [];
|
||||||
|
foreach ($introImages as $image) {
|
||||||
|
$intro_images_pull[] = $ossService->generatePrivateUrl($image);
|
||||||
|
}
|
||||||
|
$data['intro_images_pull'] = $intro_images_pull;
|
||||||
|
} else {
|
||||||
|
$data['intro_images_pull'] = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$data['intro_images_pull'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理附件
|
||||||
|
if (!empty($data['attachment'])) {
|
||||||
|
$attachments = is_array($data['attachment']) ? $data['attachment'] : json_decode($data['attachment'], true);
|
||||||
|
if ($attachments) {
|
||||||
|
$ossService = new OssService();
|
||||||
|
$attachment_pull = [];
|
||||||
|
foreach ($attachments as $attachment) {
|
||||||
|
$attachment_pull[] = [
|
||||||
|
'name' => $attachment['name'] ?? '',
|
||||||
|
'src' => $attachment['src'] ?? '',
|
||||||
|
'src_pull' => $ossService->generatePrivateUrl($attachment['src'] ?? ''),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$data['attachment_pull'] = $attachment_pull;
|
||||||
|
} else {
|
||||||
|
$data['attachment_pull'] = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$data['attachment_pull'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新状态
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return \support\Response
|
||||||
|
*/
|
||||||
|
public function status(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->post();
|
||||||
|
$res = $this->service->serviceUpdateStatus($request, $data);
|
||||||
|
return $this->success([], '更新成功');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return $this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存FAQ
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return \support\Response
|
||||||
|
*/
|
||||||
|
public function saveFaqs(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$carId = $request->post('id');
|
||||||
|
$faqs = $request->post('faqs', []);
|
||||||
|
|
||||||
|
if (empty($carId)) {
|
||||||
|
throw new BusinessException('车辆ID不能为空');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->service->saveFaqs($carId, $faqs);
|
||||||
|
|
||||||
|
return $this->success([], '保存成功');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return $this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建车辆(含FAQ)
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return \support\Response
|
||||||
|
*/
|
||||||
|
public function storeWithFaqs(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->post();
|
||||||
|
$faqs = $data['faqs'] ?? [];
|
||||||
|
|
||||||
|
// 先创建车辆
|
||||||
|
$result = $this->service->serviceStore($request);
|
||||||
|
|
||||||
|
// 再保存FAQ
|
||||||
|
if (!empty($faqs) && isset($result['id'])) {
|
||||||
|
$this->service->saveFaqs($result['id'], $faqs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->success($result, '创建成功');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return $this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新车辆(含FAQ)
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return \support\Response
|
||||||
|
*/
|
||||||
|
public function updateWithFaqs(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->post();
|
||||||
|
$faqs = $data['faqs'] ?? [];
|
||||||
|
$carId = $data['id'] ?? null;
|
||||||
|
|
||||||
|
// 先更新车辆
|
||||||
|
$result = $this->service->serviceUpdate($request);
|
||||||
|
|
||||||
|
// 再更新FAQ
|
||||||
|
if (!empty($faqs) && $carId) {
|
||||||
|
$this->service->saveFaqs($carId, $faqs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->success($result, '更新成功');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return $this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交审核
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return \support\Response
|
||||||
|
*/
|
||||||
|
public function submitAudit(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$carId = $request->post('id');
|
||||||
|
|
||||||
|
if (empty($carId)) {
|
||||||
|
throw new BusinessException('车辆ID不能为空');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->service->submitAudit($request, $carId);
|
||||||
|
|
||||||
|
return $this->success([], '提交审核成功');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return $this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核车辆
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return \support\Response
|
||||||
|
*/
|
||||||
|
public function audit(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->post();
|
||||||
|
|
||||||
|
$this->service->audit($request, $data);
|
||||||
|
|
||||||
|
$statusText = $data['audit_status'] == 1 ? '通过' : '拒绝';
|
||||||
|
return $this->success([], "审核{$statusText}成功");
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return $this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取审核记录
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return \support\Response
|
||||||
|
*/
|
||||||
|
public function auditRecords(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$carId = $request->get('id');
|
||||||
|
|
||||||
|
if (empty($carId)) {
|
||||||
|
throw new BusinessException('车辆ID不能为空');
|
||||||
|
}
|
||||||
|
|
||||||
|
$records = $this->service->getAuditRecords($carId);
|
||||||
|
|
||||||
|
return $this->success($records);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return $this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取审核统计
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return \support\Response
|
||||||
|
*/
|
||||||
|
public function auditStats(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$stats = $this->service->getAuditStats($request);
|
||||||
|
|
||||||
|
return $this->success($stats);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return $this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\logic;
|
||||||
|
|
||||||
|
use app\common\traits\crud\CrudLogicTrait;
|
||||||
|
use app\common\model\UsedCarDetail;
|
||||||
|
|
||||||
|
class UsedCarDetailLogic
|
||||||
|
{
|
||||||
|
use CrudLogicTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定当前要操作的模型
|
||||||
|
*/
|
||||||
|
protected string $modelClass = UsedCarDetail::class;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\model;
|
||||||
|
|
||||||
|
use support\Model;
|
||||||
|
|
||||||
|
class UsedCarDetail extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The connection name for the model.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $connection = 'mysql';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The table associated with the model.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = 'used_car_detail';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The primary key associated with the table.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the model should be timestamped.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $timestamps = true;
|
||||||
|
|
||||||
|
|
||||||
|
protected $dateFormat = 'U';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许自动填充模型字段
|
||||||
|
*/
|
||||||
|
protected $fillable = ['id', 'code', 'user_id', 'role_wp', 'product_name', 'vin', 'price', 'source_place', 'plate_place', 'plate_time', 'displacement', 'mileage', 'power', 'body_color', 'images', 'condition_desc', 'attachment', 'pdf_src', 'source_url', 'crawl_title', 'crawl_brand', 'crawl_brand_id', 'crawl_series', 'crawl_series_id', 'crawl_year', 'crawl_msrp', 'crawl_car_id', 'status', 'sort', 'simple_desc', 'intro_images', 'intro_text', 'intro_video', 'official_guide_price', 'manufacturer', 'level', 'energy_type', 'listing_time', 'engine', 'electric_motor', 'nedc_range', 'cltc_range', 'fast_charge_platform', 'charging_time', 'fast_charge_percent', 'max_power_kw', 'max_torque_nm', 'transmission', 'dimensions', 'body_structure', 'max_speed', 'acceleration_100', 'nedc_fuel_consumption', 'power_consumption_100', 'equivalent_fuel_consumption', 'maintenance_cost_60k', 'body_length', 'body_width', 'body_height', 'wheelbase', 'door_count', 'door_open_type', 'seat_count', 'transmission_desc', 'gear_count', 'transmission_type', 'drive_mode', 'front_suspension', 'rear_suspension', 'steering_type', 'has_abs', 'has_ebd', 'has_bra', 'has_tcs', 'has_esp', 'has_active_brake', 'has_lane_assist', 'has_lka', 'has_lane_centering', 'has_fatigue_remind', 'front_brake_type', 'rear_brake_type', 'parking_brake_type', 'front_tire_spec', 'rear_tire_spec', 'created_at', 'updated_at'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不允许自动填充模型字段
|
||||||
|
*/
|
||||||
|
protected $guarded = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON 类型字段自动转换
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'images' => 'array',
|
||||||
|
'attachment' => 'array',
|
||||||
|
'intro_images' => 'array',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联 FAQ
|
||||||
|
*/
|
||||||
|
public function faqs()
|
||||||
|
{
|
||||||
|
return $this->hasMany(UsedCarFaq::class, 'car_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联用户
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(\app\common\model\User::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联审核记录
|
||||||
|
*/
|
||||||
|
public function auditRecords()
|
||||||
|
{
|
||||||
|
return $this->hasMany(UsedCarDetailAudit::class, 'car_id', 'id')->orderBy('created_at', 'desc');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最新审核记录
|
||||||
|
*/
|
||||||
|
public function latestAudit()
|
||||||
|
{
|
||||||
|
return $this->hasOne(UsedCarDetailAudit::class, 'car_id', 'id')->orderBy('created_at', 'desc');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核状态文本
|
||||||
|
*/
|
||||||
|
public static $auditStatusText = [
|
||||||
|
0 => '待审核',
|
||||||
|
1 => '审核通过',
|
||||||
|
2 => '审核拒绝',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作用域:待审核
|
||||||
|
*/
|
||||||
|
public function scopePending($query)
|
||||||
|
{
|
||||||
|
return $query->where('status', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作用域:已通过
|
||||||
|
*/
|
||||||
|
public function scopeApproved($query)
|
||||||
|
{
|
||||||
|
return $query->where('status', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作用域:已拒绝
|
||||||
|
*/
|
||||||
|
public function scopeRejected($query)
|
||||||
|
{
|
||||||
|
return $query->where('status', 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\model;
|
||||||
|
|
||||||
|
use support\Model;
|
||||||
|
|
||||||
|
class UsedCarDetailAudit extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The connection name for the model.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $connection = 'mysql';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The table associated with the model.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = 'used_car_detail_audit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The primary key associated with the table.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the model should be timestamped.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $timestamps = true;
|
||||||
|
|
||||||
|
protected $dateFormat = 'U';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许自动填充模型字段
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'id', 'car_id', 'auditor_id', 'audit_status', 'audit_reason',
|
||||||
|
'before_status', 'after_status', 'created_at', 'updated_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不允许自动填充模型字段
|
||||||
|
*/
|
||||||
|
protected $guarded = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核状态文本
|
||||||
|
*/
|
||||||
|
public static $statusText = [
|
||||||
|
0 => '待审核',
|
||||||
|
1 => '审核通过',
|
||||||
|
2 => '审核拒绝',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联车辆
|
||||||
|
*/
|
||||||
|
public function car()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(UsedCarDetail::class, 'car_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联审核人
|
||||||
|
*/
|
||||||
|
public function auditor()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(\app\common\model\User::class, 'auditor_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取审核状态文本
|
||||||
|
*/
|
||||||
|
public function getAuditStatusTextAttribute()
|
||||||
|
{
|
||||||
|
return self::$statusText[$this->audit_status] ?? '未知';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作用域:通过审核
|
||||||
|
*/
|
||||||
|
public function scopeApproved($query)
|
||||||
|
{
|
||||||
|
return $query->where('audit_status', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作用域:拒绝审核
|
||||||
|
*/
|
||||||
|
public function scopeRejected($query)
|
||||||
|
{
|
||||||
|
return $query->where('audit_status', 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作用域:待审核
|
||||||
|
*/
|
||||||
|
public function scopePending($query)
|
||||||
|
{
|
||||||
|
return $query->where('audit_status', 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\model;
|
||||||
|
|
||||||
|
use support\Model;
|
||||||
|
|
||||||
|
class UsedCarFaq extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The connection name for the model.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $connection = 'mysql';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The table associated with the model.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = 'used_car_faq';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The primary key associated with the table.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the model should be timestamped.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $timestamps = true;
|
||||||
|
|
||||||
|
protected $dateFormat = 'U';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许自动填充模型字段
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'id', 'car_id', 'question', 'answer', 'sort', 'status', 'created_at', 'updated_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不允许自动填充模型字段
|
||||||
|
*/
|
||||||
|
protected $guarded = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联车辆详情
|
||||||
|
*/
|
||||||
|
public function car()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(UsedCarDetail::class, 'car_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,458 @@
|
|||||||
|
<?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(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\validate;
|
||||||
|
|
||||||
|
use think\Validate;
|
||||||
|
|
||||||
|
class UsedCarDetailValidate extends Validate
|
||||||
|
{
|
||||||
|
// 规则
|
||||||
|
protected $rule = [
|
||||||
|
'id' => 'requireWith:id',
|
||||||
|
'product_name' => 'require|max:255',
|
||||||
|
'price' => 'require|float|>=:0',
|
||||||
|
'user_id' => 'require|integer',
|
||||||
|
'role' => 'integer|in:1,2,3,4',
|
||||||
|
];
|
||||||
|
|
||||||
|
// 提示
|
||||||
|
protected $message = [
|
||||||
|
'product_name.require' => '产品名称不能为空',
|
||||||
|
'product_name.max' => '产品名称最多255个字符',
|
||||||
|
'price.require' => '车辆价格不能为空',
|
||||||
|
'price.float' => '车辆价格格式不正确',
|
||||||
|
'price.>=' => '车辆价格不能为负数',
|
||||||
|
'role.in' => '角色值不正确',
|
||||||
|
];
|
||||||
|
|
||||||
|
// 场景
|
||||||
|
protected $scene = [
|
||||||
|
'store' => ['product_name', 'price', 'user_id', 'role'],
|
||||||
|
'update' => ['id', 'product_name', 'price'],
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -71,6 +71,25 @@ Route::group('/common', function () {
|
|||||||
Route::any('/mobile/url_crawl', [app\common\controller\UsedCarController::class, 'crawlMobileCar']);
|
Route::any('/mobile/url_crawl', [app\common\controller\UsedCarController::class, 'crawlMobileCar']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 二手车详情(扩展版)
|
||||||
|
Route::group('/usedcardetail', function () {
|
||||||
|
Route::any('/list', [app\common\controller\UsedCarDetailController::class, 'index']);
|
||||||
|
Route::any('/show', [app\common\controller\UsedCarDetailController::class, 'show']);
|
||||||
|
Route::any('/store', [app\common\controller\UsedCarDetailController::class, 'store']);
|
||||||
|
Route::any('/update', [app\common\controller\UsedCarDetailController::class, 'update']);
|
||||||
|
Route::any('/update/status', [app\common\controller\UsedCarDetailController::class, 'status']);
|
||||||
|
Route::any('/destroy', [app\common\controller\UsedCarDetailController::class, 'destroy']);
|
||||||
|
Route::any('/store/faqs', [app\common\controller\UsedCarDetailController::class, 'storeWithFaqs']);
|
||||||
|
Route::any('/update/faqs', [app\common\controller\UsedCarDetailController::class, 'updateWithFaqs']);
|
||||||
|
Route::any('/save/faqs', [app\common\controller\UsedCarDetailController::class, 'saveFaqs']);
|
||||||
|
|
||||||
|
// 审核相关
|
||||||
|
Route::any('/audit/submit', [app\common\controller\UsedCarDetailController::class, 'submitAudit']);
|
||||||
|
Route::any('/audit', [app\common\controller\UsedCarDetailController::class, 'audit']);
|
||||||
|
Route::any('/audit/records', [app\common\controller\UsedCarDetailController::class, 'auditRecords']);
|
||||||
|
Route::any('/audit/stats', [app\common\controller\UsedCarDetailController::class, 'auditStats']);
|
||||||
|
});
|
||||||
|
|
||||||
Route::group('/user', function () {
|
Route::group('/user', function () {
|
||||||
Route::any('/info', [app\common\controller\UserController::class, 'show']);
|
Route::any('/info', [app\common\controller\UserController::class, 'show']);
|
||||||
Route::any('/edit', [app\common\controller\UserController::class, 'edit']);
|
Route::any('/edit', [app\common\controller\UserController::class, 'edit']);
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
-- 二手车主表(扩展版)
|
||||||
|
CREATE TABLE `used_car_detail` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
|
||||||
|
-- 基本信息(继承自 used_car)
|
||||||
|
`code` varchar(50) DEFAULT NULL COMMENT '车辆编号',
|
||||||
|
`user_id` bigint(20) unsigned NOT NULL COMMENT '用户ID',
|
||||||
|
`role_wp` tinyint(1) NOT NULL DEFAULT '2' COMMENT 'wp数据角色:1:业务,2:外部供应商,3:管理员',
|
||||||
|
`product_name` varchar(255) NOT NULL COMMENT '产品名称',
|
||||||
|
`vin` varchar(50) DEFAULT NULL COMMENT '车架号',
|
||||||
|
`price` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '车辆价格',
|
||||||
|
`source_place` varchar(100) DEFAULT NULL COMMENT '来源地',
|
||||||
|
`plate_place` varchar(100) DEFAULT NULL COMMENT '上牌地',
|
||||||
|
`plate_time` varchar(20) DEFAULT NULL COMMENT '上牌时间',
|
||||||
|
`displacement` varchar(50) DEFAULT NULL COMMENT '排量',
|
||||||
|
`mileage` varchar(50) DEFAULT NULL COMMENT '里程',
|
||||||
|
`power` varchar(50) DEFAULT NULL COMMENT '马力',
|
||||||
|
`body_color` varchar(50) DEFAULT NULL COMMENT '车身颜色',
|
||||||
|
`images` text COMMENT '车辆图片JSON',
|
||||||
|
`condition_desc` text COMMENT '车况描述',
|
||||||
|
`attachment` text COMMENT '附件JSON',
|
||||||
|
`pdf_src` varchar(255) DEFAULT NULL COMMENT 'PDF文件路径',
|
||||||
|
`source_url` varchar(500) DEFAULT NULL COMMENT '来源链接',
|
||||||
|
`crawl_title` varchar(255) DEFAULT NULL COMMENT '爬取标题',
|
||||||
|
`crawl_brand` varchar(100) DEFAULT NULL COMMENT '爬取品牌',
|
||||||
|
`crawl_brand_id` varchar(50) DEFAULT NULL COMMENT '爬取品牌ID',
|
||||||
|
`crawl_series` varchar(100) DEFAULT NULL COMMENT '爬取车系',
|
||||||
|
`crawl_series_id` varchar(50) DEFAULT NULL COMMENT '爬取车系ID',
|
||||||
|
`crawl_year` varchar(10) DEFAULT NULL COMMENT '爬取年份',
|
||||||
|
`crawl_msrp` decimal(10,2) unsigned DEFAULT NULL COMMENT '爬取厂商指导价',
|
||||||
|
`crawl_car_id` varchar(50) DEFAULT NULL COMMENT '爬取车型ID',
|
||||||
|
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '审核状态:0=待审核,1=审核通过,2=审核拒绝',
|
||||||
|
`sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
|
||||||
|
|
||||||
|
-- 车辆信息简单描述(新增)
|
||||||
|
`simple_desc` text COMMENT '车辆信息简单描述',
|
||||||
|
|
||||||
|
-- 车辆介绍(新增)
|
||||||
|
`intro_images` text COMMENT '车辆介绍图片JSON',
|
||||||
|
`intro_text` text COMMENT '车辆介绍文本',
|
||||||
|
`intro_video` varchar(500) DEFAULT NULL COMMENT '车辆介绍视频URL',
|
||||||
|
|
||||||
|
-- 1. 基本信息(新增)
|
||||||
|
`official_guide_price` decimal(10,2) unsigned DEFAULT NULL COMMENT '官方指导价',
|
||||||
|
`manufacturer` varchar(100) DEFAULT NULL COMMENT '厂商',
|
||||||
|
`level` varchar(50) DEFAULT NULL COMMENT '级别',
|
||||||
|
`energy_type` varchar(50) DEFAULT NULL COMMENT '能源类型',
|
||||||
|
`listing_time` varchar(20) DEFAULT NULL COMMENT '上市时间',
|
||||||
|
`engine` varchar(255) DEFAULT NULL COMMENT '发动机',
|
||||||
|
`electric_motor` varchar(255) DEFAULT NULL COMMENT '电动机',
|
||||||
|
`nedc_range` int(11) unsigned DEFAULT NULL COMMENT '纯电续航里程(km)工信部',
|
||||||
|
`cltc_range` int(11) unsigned DEFAULT NULL COMMENT '纯电续航里程(km)CLTC',
|
||||||
|
`fast_charge_platform` varchar(100) DEFAULT NULL COMMENT '高压快充平台',
|
||||||
|
`charging_time` decimal(5,2) unsigned DEFAULT NULL COMMENT '充电时间(小时)',
|
||||||
|
`fast_charge_percent` tinyint(3) unsigned DEFAULT NULL COMMENT '快充电量(%)',
|
||||||
|
`max_power_kw` int(11) unsigned DEFAULT NULL COMMENT '最大功率(kW)',
|
||||||
|
`max_torque_nm` int(11) unsigned DEFAULT NULL COMMENT '最大扭矩(N·m)',
|
||||||
|
`transmission` varchar(100) DEFAULT NULL COMMENT '变速箱',
|
||||||
|
`dimensions` varchar(50) DEFAULT NULL COMMENT '长x宽x高(mm)',
|
||||||
|
`body_structure` varchar(50) DEFAULT NULL COMMENT '车身结构',
|
||||||
|
`max_speed` int(11) unsigned DEFAULT NULL COMMENT '最高车速(km/h)',
|
||||||
|
`acceleration_100` decimal(4,2) unsigned DEFAULT NULL COMMENT '官方百公里加速时间(s)',
|
||||||
|
`nedc_fuel_consumption` decimal(5,2) unsigned DEFAULT NULL COMMENT 'NEDC综合油耗(L/100km)',
|
||||||
|
`power_consumption_100` decimal(5,2) unsigned DEFAULT NULL COMMENT '百公里耗电量(kWh/100km)',
|
||||||
|
`equivalent_fuel_consumption` decimal(5,2) unsigned DEFAULT NULL COMMENT '电能当量燃料消耗量(L/100km)',
|
||||||
|
`maintenance_cost_60k` decimal(10,2) unsigned DEFAULT NULL COMMENT '6万公里保养总成本预估',
|
||||||
|
|
||||||
|
-- 2. 车身信息(新增)
|
||||||
|
`body_length` int(11) unsigned DEFAULT NULL COMMENT '长(mm)',
|
||||||
|
`body_width` int(11) unsigned DEFAULT NULL COMMENT '宽(mm)',
|
||||||
|
`body_height` int(11) unsigned DEFAULT NULL COMMENT '高(mm)',
|
||||||
|
`wheelbase` int(11) unsigned DEFAULT NULL COMMENT '轴距(mm)',
|
||||||
|
`door_count` tinyint(3) unsigned DEFAULT NULL COMMENT '车门数(个)',
|
||||||
|
`door_open_type` varchar(50) DEFAULT NULL COMMENT '车门开启方式',
|
||||||
|
`seat_count` tinyint(3) unsigned DEFAULT NULL COMMENT '座位数(个)',
|
||||||
|
|
||||||
|
-- 3. 变速箱(新增)
|
||||||
|
`transmission_desc` varchar(255) DEFAULT NULL COMMENT '变速箱描述',
|
||||||
|
`gear_count` tinyint(3) unsigned DEFAULT NULL COMMENT '挡位数',
|
||||||
|
`transmission_type` varchar(50) DEFAULT NULL COMMENT '变速箱类型',
|
||||||
|
|
||||||
|
-- 4. 底盘/转向(新增)
|
||||||
|
`drive_mode` varchar(50) DEFAULT NULL COMMENT '驱动方式',
|
||||||
|
`front_suspension` varchar(100) DEFAULT NULL COMMENT '前悬挂形式',
|
||||||
|
`rear_suspension` varchar(100) DEFAULT NULL COMMENT '后悬挂形式',
|
||||||
|
`steering_type` varchar(50) DEFAULT NULL COMMENT '转向类型',
|
||||||
|
|
||||||
|
-- 5. 主动安全(新增)
|
||||||
|
`has_abs` varchar(20) DEFAULT NULL COMMENT 'ABS防抱死',
|
||||||
|
`has_ebd` varchar(20) DEFAULT NULL COMMENT '制动力分配(EBD/CBC等)',
|
||||||
|
`has_bra` varchar(20) DEFAULT NULL COMMENT '刹车辅助(EBA/BA等)',
|
||||||
|
`has_tcs` varchar(20) DEFAULT NULL COMMENT '牵引力控制(TCS/ASR等)',
|
||||||
|
`has_esp` varchar(20) DEFAULT NULL COMMENT '车身稳定系统(ESP/DSC等)',
|
||||||
|
`has_active_brake` varchar(20) DEFAULT NULL COMMENT '主动刹车',
|
||||||
|
`has_lane_assist` varchar(20) DEFAULT NULL COMMENT '并线辅助',
|
||||||
|
`has_lka` varchar(20) DEFAULT NULL COMMENT '车道保持辅助系统',
|
||||||
|
`has_lane_centering` varchar(20) DEFAULT NULL COMMENT '车道居中保持',
|
||||||
|
`has_fatigue_remind` varchar(20) DEFAULT NULL COMMENT '疲劳驾驶提示',
|
||||||
|
|
||||||
|
-- 6. 车轮/制动(新增)
|
||||||
|
`front_brake_type` varchar(50) DEFAULT NULL COMMENT '前制动器类型',
|
||||||
|
`rear_brake_type` varchar(50) DEFAULT NULL COMMENT '后制动器类型',
|
||||||
|
`parking_brake_type` varchar(50) DEFAULT NULL COMMENT '驻车制动类型',
|
||||||
|
`front_tire_spec` varchar(50) DEFAULT NULL COMMENT '前轮胎规格尺寸',
|
||||||
|
`rear_tire_spec` varchar(50) DEFAULT NULL COMMENT '后轮胎规格尺寸',
|
||||||
|
|
||||||
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_code` (`code`),
|
||||||
|
KEY `idx_user_id` (`user_id`),
|
||||||
|
KEY `idx_role_wp` (`role_wp`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_brand_series` (`crawl_brand_id`, `crawl_series_id`),
|
||||||
|
KEY `idx_price` (`price`),
|
||||||
|
KEY `idx_created_at` (`created_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='二手车详情表(扩展版)';
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE `useds`.`user`
|
||||||
|
ADD COLUMN `role_wp` TINYINT (2) DEFAULT 1 NULL COMMENT 'wp数据角色:1:业务,2:外部供应商,3:管理员' AFTER `role`;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
-- 二手车审核记录表
|
||||||
|
CREATE TABLE `used_car_detail_audit` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`car_id` bigint(20) unsigned NOT NULL COMMENT '关联used_car_detail.id',
|
||||||
|
`auditor_id` bigint(20) unsigned NOT NULL COMMENT '审核人ID',
|
||||||
|
`audit_status` tinyint(1) NOT NULL COMMENT '审核状态:0=待审核,1=通过,2=拒绝',
|
||||||
|
`audit_reason` varchar(500) DEFAULT NULL COMMENT '审核理由/拒绝原因',
|
||||||
|
`before_status` tinyint(1) DEFAULT NULL COMMENT '审核前状态',
|
||||||
|
`after_status` tinyint(1) DEFAULT NULL COMMENT '审核后状态',
|
||||||
|
`created_at` timestamp NULL DEFAULT NULL COMMENT '审核时间',
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_car_id` (`car_id`),
|
||||||
|
KEY `idx_auditor_id` (`auditor_id`),
|
||||||
|
KEY `idx_audit_status` (`audit_status`),
|
||||||
|
KEY `idx_created_at` (`created_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='二手车审核记录表';
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
-- 二手车FAQ关联表
|
||||||
|
CREATE TABLE `used_car_faq` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`car_id` bigint(20) unsigned NOT NULL COMMENT '关联used_car_detail.id',
|
||||||
|
`question` varchar(500) NOT NULL COMMENT '问题',
|
||||||
|
`answer` text NOT NULL COMMENT '答案',
|
||||||
|
`sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
|
||||||
|
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:0=禁用,1=启用',
|
||||||
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_car_id` (`car_id`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_sort` (`sort`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='二手车常见问题表';
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
CREATE TABLE `approval_flows` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`name` varchar(255) NOT NULL COMMENT '流程名称',
|
|
||||||
`type` varchar(100) NOT NULL COMMENT '业务类型标识,如 leave, reimbursement',
|
|
||||||
`steps` json NOT NULL COMMENT '审批步骤配置',
|
|
||||||
`is_active` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否启用',
|
|
||||||
`timeout_hours` int(11) NOT NULL DEFAULT '0' COMMENT '实例级超时时间(小时),0为不超时',
|
|
||||||
`timeout_action` varchar(20) NOT NULL DEFAULT 'auto_reject' COMMENT 'auto_approve | auto_reject',
|
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `uk_flow_type` (`type`)
|
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='审批流程定义';
|
|
||||||
|
|
||||||
CREATE TABLE `approval_instances` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`flow_type` varchar(100) NOT NULL COMMENT '关联 approval_flows.type',
|
|
||||||
`biz_id` varchar(255) NOT NULL COMMENT '业务ID',
|
|
||||||
`biz_type` varchar(100) NOT NULL COMMENT '业务标识/表名',
|
|
||||||
`form_data` json NOT NULL COMMENT '提交表单快照',
|
|
||||||
`initiator_id` bigint(20) unsigned NOT NULL COMMENT '发起人',
|
|
||||||
`status` varchar(20) NOT NULL DEFAULT 'processing' COMMENT 'processing|approved|rejected|revoked|timed_out',
|
|
||||||
`current_step` int(11) NOT NULL DEFAULT '0' COMMENT '当前步骤索引',
|
|
||||||
`round` int(11) NOT NULL DEFAULT '1' COMMENT '当前轮次:1=首次,重提+1',
|
|
||||||
`finished_at` timestamp NULL DEFAULT NULL,
|
|
||||||
`deadline_at` timestamp NULL DEFAULT NULL,
|
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `idx_flow_type` (`flow_type`),
|
|
||||||
KEY `idx_biz` (`biz_type`,`biz_id`),
|
|
||||||
KEY `idx_initiator` (`initiator_id`),
|
|
||||||
KEY `idx_status_updated` (`status`,`updated_at`)
|
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=68 DEFAULT CHARSET=utf8mb4 COMMENT='审批实例';
|
|
||||||
|
|
||||||
CREATE TABLE `approval_records` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`instance_id` bigint(20) unsigned NOT NULL COMMENT 'approval_instances.id',
|
|
||||||
`approver_id` bigint(20) unsigned NOT NULL COMMENT '审批人',
|
|
||||||
`step_index` int(11) NOT NULL COMMENT '步骤索引',
|
|
||||||
`round` int(11) NOT NULL DEFAULT '1' COMMENT '所属轮次',
|
|
||||||
`action` varchar(20) DEFAULT NULL COMMENT 'approve|reject,待办时为NULL',
|
|
||||||
`status` varchar(20) NOT NULL DEFAULT 'pending' COMMENT 'pending|approved|rejected|skipped|timeout',
|
|
||||||
`comment` text COMMENT '审批意见',
|
|
||||||
`approved_at` timestamp NULL DEFAULT NULL COMMENT '审批时间/关闭时间',
|
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `uk_instance_step_approver` (`instance_id`,`step_index`,`approver_id`),
|
|
||||||
KEY `idx_instance_step_status` (`instance_id`,`step_index`,`status`),
|
|
||||||
KEY `idx_approver` (`approver_id`),
|
|
||||||
KEY `idx_instance_step_round` (`instance_id`,`step_index`,`round`)
|
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=105 DEFAULT CHARSET=utf8mb4 COMMENT='审批记录';
|
|
||||||
|
|
||||||
CREATE TABLE `approval_transfers` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`instance_id` bigint(20) unsigned NOT NULL,
|
|
||||||
`step_index` int(11) NOT NULL,
|
|
||||||
`record_id` bigint(20) unsigned NOT NULL COMMENT '转交后仍然有效的记录ID(若合并则为目标记录ID)',
|
|
||||||
`from_user_id` bigint(20) unsigned NOT NULL,
|
|
||||||
`to_user_id` bigint(20) unsigned NOT NULL,
|
|
||||||
`reason` text,
|
|
||||||
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `idx_record` (`record_id`),
|
|
||||||
KEY `idx_instance_step` (`instance_id`,`step_index`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审批转交日志';
|
|
||||||
|
|
||||||
CREATE TABLE `approval_ccs` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`instance_id` bigint(20) unsigned NOT NULL,
|
|
||||||
`user_id` bigint(20) unsigned NOT NULL,
|
|
||||||
`notified_at` timestamp NULL DEFAULT NULL,
|
|
||||||
`read_at` timestamp NULL DEFAULT NULL,
|
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `uk_instance_user` (`instance_id`,`user_id`),
|
|
||||||
KEY `idx_user` (`user_id`),
|
|
||||||
KEY `idx_instance` (`instance_id`)
|
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COMMENT='审批抄送';
|
|
||||||
|
|
||||||
CREATE TABLE `approval_discussions` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`instance_id` bigint(20) unsigned NOT NULL,
|
|
||||||
`user_id` bigint(20) unsigned NOT NULL,
|
|
||||||
`is_internal` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0=公开,1=仅审批人可见',
|
|
||||||
`content` text NOT NULL,
|
|
||||||
`attachments` json DEFAULT NULL,
|
|
||||||
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `idx_instance_id` (`instance_id`)
|
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='审批讨论';
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
SET NAMES utf8mb4;
|
|
||||||
SET FOREIGN_KEY_CHECKS = 0;
|
|
||||||
|
|
||||||
-- 1. 物品主数据表:增加 company_id
|
|
||||||
DROP TABLE IF EXISTS inv_item;
|
|
||||||
CREATE TABLE inv_item (
|
|
||||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
|
||||||
company_id BIGINT(20) UNSIGNED DEFAULT NULL COMMENT '物品所属公司ID',
|
|
||||||
item_code VARCHAR(64) NOT NULL COMMENT '物品编号(公司内部编码)',
|
|
||||||
item_name VARCHAR(128) NOT NULL COMMENT '物品名称',
|
|
||||||
category_id BIGINT(20) UNSIGNED DEFAULT NULL COMMENT '物品分类ID(可选,指向分类表)',
|
|
||||||
spec_model VARCHAR(128) DEFAULT NULL COMMENT '规格型号',
|
|
||||||
unit VARCHAR(32) DEFAULT '件' COMMENT '计量单位,如 件/盒/包',
|
|
||||||
is_consumable TINYINT(1) DEFAULT 1 COMMENT '是否耗材:1耗材(不需归还),0非耗材(需归还)',
|
|
||||||
stock_qty INT(11) DEFAULT 0 COMMENT '当前库存数量',
|
|
||||||
manage_user_id BIGINT(20) UNSIGNED DEFAULT NULL COMMENT '物品管理员用户ID',
|
|
||||||
location VARCHAR(255) DEFAULT NULL COMMENT '存放位置说明',
|
|
||||||
remark VARCHAR(255) DEFAULT NULL COMMENT '备注',
|
|
||||||
created_at INT(11) NOT NULL DEFAULT 0 COMMENT '创建时间时间戳',
|
|
||||||
updated_at INT(11) NOT NULL DEFAULT 0 COMMENT '更新时间时间戳',
|
|
||||||
PRIMARY KEY (id),
|
|
||||||
UNIQUE KEY uk_item_code (item_code),
|
|
||||||
KEY idx_company (company_id),
|
|
||||||
KEY idx_category (category_id),
|
|
||||||
KEY idx_manage_user (manage_user_id)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物品主数据表';
|
|
||||||
|
|
||||||
|
|
||||||
-- 2. 物品领用/借用申请单(主表)
|
|
||||||
DROP TABLE IF EXISTS inv_requisition;
|
|
||||||
CREATE TABLE inv_requisition (
|
|
||||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
|
||||||
order_no VARCHAR(64) NOT NULL COMMENT '申请单号',
|
|
||||||
|
|
||||||
applicant_company_id BIGINT(20) UNSIGNED DEFAULT NULL COMMENT '申请人所在公司ID(可选)',
|
|
||||||
dept_id BIGINT(20) UNSIGNED DEFAULT NULL COMMENT '申请人部门ID',
|
|
||||||
applicant_id BIGINT(20) UNSIGNED NOT NULL COMMENT '申请人用户ID',
|
|
||||||
applicant_name VARCHAR(64) DEFAULT NULL COMMENT '申请人姓名快照',
|
|
||||||
leader_id BIGINT(20) UNSIGNED DEFAULT NULL COMMENT '直属上级用户ID',
|
|
||||||
manager_id BIGINT(20) UNSIGNED DEFAULT NULL COMMENT '物品管理员用户ID(主负责人)',
|
|
||||||
|
|
||||||
borrow_reason VARCHAR(255) NOT NULL COMMENT '领用/借用事由',
|
|
||||||
use_start_date DATE NOT NULL COMMENT '借用/预计使用开始日期',
|
|
||||||
use_end_date DATE DEFAULT NULL COMMENT '预计归还日期(耗材可为空)',
|
|
||||||
|
|
||||||
-- 0草稿 10待直属上级审批 20直属上级通过待物品管理员审批
|
|
||||||
-- 30全部通过 40已驳回 50已取消
|
|
||||||
status TINYINT(3) NOT NULL DEFAULT 10 COMMENT '审批状态',
|
|
||||||
|
|
||||||
is_returned TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否已全部归还(针对需要归还的物品):0否 1是',
|
|
||||||
|
|
||||||
remark VARCHAR(255) DEFAULT NULL COMMENT '备注',
|
|
||||||
created_at INT(11) NOT NULL DEFAULT 0 COMMENT '创建时间时间戳',
|
|
||||||
updated_at INT(11) NOT NULL DEFAULT 0 COMMENT '更新时间时间戳',
|
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
|
||||||
UNIQUE KEY uk_order_no (order_no),
|
|
||||||
KEY idx_applicant (applicant_id),
|
|
||||||
KEY idx_status (status)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物品领用/借用申请单';
|
|
||||||
|
|
||||||
|
|
||||||
-- 3. 申请单明细表:支持部分、多次归还
|
|
||||||
DROP TABLE IF EXISTS inv_requisition_item;
|
|
||||||
CREATE TABLE inv_requisition_item (
|
|
||||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
|
||||||
requisition_id BIGINT(20) UNSIGNED NOT NULL COMMENT '申请单ID',
|
|
||||||
item_id BIGINT(20) UNSIGNED NOT NULL COMMENT '物品ID',
|
|
||||||
|
|
||||||
item_name_snap VARCHAR(128) DEFAULT NULL COMMENT '物品名称快照',
|
|
||||||
spec_model_snap VARCHAR(128) DEFAULT NULL COMMENT '规格型号快照',
|
|
||||||
unit_snap VARCHAR(32) DEFAULT NULL COMMENT '单位快照',
|
|
||||||
is_consumable_snap TINYINT(1) DEFAULT NULL COMMENT '是否耗材快照:1耗材 0非耗材',
|
|
||||||
|
|
||||||
request_qty INT(11) NOT NULL DEFAULT 1 COMMENT '申请数量',
|
|
||||||
approved_qty INT(11) DEFAULT NULL COMMENT '实批数量(可与申请数量不同)',
|
|
||||||
returned_qty INT(11) NOT NULL DEFAULT 0 COMMENT '已归还数量(累加)',
|
|
||||||
|
|
||||||
-- 对于非耗材:returned_qty >= approved_qty 时置为1
|
|
||||||
is_finished TINYINT(1) NOT NULL DEFAULT 0 COMMENT '该物品是否已完成归还:0否 1是',
|
|
||||||
|
|
||||||
remark VARCHAR(255) DEFAULT NULL COMMENT '行备注',
|
|
||||||
created_at INT(11) NOT NULL DEFAULT 0 COMMENT '创建时间时间戳',
|
|
||||||
updated_at INT(11) NOT NULL DEFAULT 0 COMMENT '更新时间时间戳',
|
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
|
||||||
KEY idx_req (requisition_id),
|
|
||||||
KEY idx_item (item_id)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物品领用申请明细表';
|
|
||||||
|
|
||||||
|
|
||||||
-- 4. 审批记录表(同上一版,略微无改动)
|
|
||||||
DROP TABLE IF EXISTS inv_requisition_approve;
|
|
||||||
CREATE TABLE inv_requisition_approve (
|
|
||||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
|
||||||
requisition_id BIGINT(20) UNSIGNED NOT NULL COMMENT '申请单ID',
|
|
||||||
node_type VARCHAR(32) NOT NULL COMMENT '审批节点类型:leader=直属上级,manager=物品管理员,other=其他',
|
|
||||||
approver_id BIGINT(20) UNSIGNED NOT NULL COMMENT '审批人用户ID',
|
|
||||||
approver_name VARCHAR(64) DEFAULT NULL COMMENT '审批人姓名快照',
|
|
||||||
action TINYINT(3) NOT NULL COMMENT '审批动作:1通过 2驳回',
|
|
||||||
comment VARCHAR(255) DEFAULT NULL COMMENT '审批意见',
|
|
||||||
action_at INT(11) NOT NULL DEFAULT 0 COMMENT '审批时间时间戳',
|
|
||||||
|
|
||||||
created_at INT(11) NOT NULL DEFAULT 0 COMMENT '创建时间时间戳',
|
|
||||||
updated_at INT(11) NOT NULL DEFAULT 0 COMMENT '更新时间时间戳',
|
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
|
||||||
KEY idx_req (requisition_id),
|
|
||||||
KEY idx_node (node_type),
|
|
||||||
KEY idx_approver (approver_id)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物品领用申请审批记录表';
|
|
||||||
|
|
||||||
|
|
||||||
-- 5. 申请单附件表(申请时上传)
|
|
||||||
DROP TABLE IF EXISTS inv_requisition_attachment;
|
|
||||||
CREATE TABLE inv_requisition_attachment (
|
|
||||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
|
||||||
requisition_id BIGINT(20) UNSIGNED NOT NULL COMMENT '申请单ID',
|
|
||||||
file_name VARCHAR(255) NOT NULL COMMENT '文件原始名称',
|
|
||||||
file_path VARCHAR(255) NOT NULL COMMENT '文件存储路径/URL',
|
|
||||||
file_size INT(11) DEFAULT NULL COMMENT '文件大小(字节)',
|
|
||||||
created_at INT(11) NOT NULL DEFAULT 0 COMMENT '创建时间时间戳',
|
|
||||||
updated_at INT(11) NOT NULL DEFAULT 0 COMMENT '更新时间时间戳',
|
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
|
||||||
KEY idx_req (requisition_id)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物品领用申请附件表';
|
|
||||||
|
|
||||||
|
|
||||||
/* ================= 归 还 相 关 表 ================= */
|
|
||||||
|
|
||||||
-- 6. 归还记录表:一次归还动作(可归还一个明细的一部分)
|
|
||||||
DROP TABLE IF EXISTS inv_requisition_item_return;
|
|
||||||
CREATE TABLE inv_requisition_item_return (
|
|
||||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
|
||||||
requisition_id BIGINT(20) UNSIGNED NOT NULL COMMENT '申请单ID',
|
|
||||||
requisition_item_id BIGINT(20) UNSIGNED NOT NULL COMMENT '申请单明细ID',
|
|
||||||
item_id BIGINT(20) UNSIGNED NOT NULL COMMENT '物品ID',
|
|
||||||
|
|
||||||
return_qty INT(11) NOT NULL DEFAULT 0 COMMENT '本次归还数量',
|
|
||||||
handler_id BIGINT(20) UNSIGNED NOT NULL COMMENT '办理归还的人(通常是物品管理员)',
|
|
||||||
handler_name VARCHAR(64) DEFAULT NULL COMMENT '办理人姓名快照',
|
|
||||||
|
|
||||||
return_status TINYINT(3) NOT NULL DEFAULT 1 COMMENT '归还状态:1正常归还 2损坏 3其他',
|
|
||||||
remark VARCHAR(255) DEFAULT NULL COMMENT '归还备注',
|
|
||||||
|
|
||||||
return_at INT(11) NOT NULL DEFAULT 0 COMMENT '归还时间时间戳',
|
|
||||||
created_at INT(11) NOT NULL DEFAULT 0 COMMENT '创建时间时间戳',
|
|
||||||
updated_at INT(11) NOT NULL DEFAULT 0 COMMENT '更新时间时间戳',
|
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
|
||||||
KEY idx_req (requisition_id),
|
|
||||||
KEY idx_req_item (requisition_item_id),
|
|
||||||
KEY idx_item (item_id),
|
|
||||||
KEY idx_handler (handler_id)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物品归还记录表(支持多次、部分归还)';
|
|
||||||
|
|
||||||
|
|
||||||
-- 7. 归还附件表:归还时拍照留底
|
|
||||||
DROP TABLE IF EXISTS inv_requisition_item_return_attachment;
|
|
||||||
CREATE TABLE inv_requisition_item_return_attachment (
|
|
||||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
|
||||||
return_id BIGINT(20) UNSIGNED NOT NULL COMMENT '归还记录ID',
|
|
||||||
file_name VARCHAR(255) NOT NULL COMMENT '文件原始名称',
|
|
||||||
file_path VARCHAR(255) NOT NULL COMMENT '文件存储路径/URL(通常为照片)',
|
|
||||||
file_size INT(11) DEFAULT NULL COMMENT '文件大小(字节)',
|
|
||||||
created_at INT(11) NOT NULL DEFAULT 0 COMMENT '创建时间时间戳',
|
|
||||||
updated_at INT(11) NOT NULL DEFAULT 0 COMMENT '更新时间时间戳',
|
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
|
||||||
KEY idx_return (return_id)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物品归还记录附件表(归还拍照留底)';
|
|
||||||
|
|
||||||
SET FOREIGN_KEY_CHECKS = 1;
|
|
||||||
Reference in New Issue
Block a user