diff --git a/app/common/controller/UsedCarDetailController.php b/app/common/controller/UsedCarDetailController.php new file mode 100644 index 0000000..f13d80f --- /dev/null +++ b/app/common/controller/UsedCarDetailController.php @@ -0,0 +1,305 @@ +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()); + } + } +} \ No newline at end of file diff --git a/app/common/logic/UsedCarDetailLogic.php b/app/common/logic/UsedCarDetailLogic.php new file mode 100644 index 0000000..b3d3fe1 --- /dev/null +++ b/app/common/logic/UsedCarDetailLogic.php @@ -0,0 +1,17 @@ + '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); + } +} \ No newline at end of file diff --git a/app/common/model/UsedCarDetailAudit.php b/app/common/model/UsedCarDetailAudit.php new file mode 100644 index 0000000..d9acc0d --- /dev/null +++ b/app/common/model/UsedCarDetailAudit.php @@ -0,0 +1,108 @@ + '待审核', + 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); + } +} diff --git a/app/common/model/UsedCarFaq.php b/app/common/model/UsedCarFaq.php new file mode 100644 index 0000000..2e5663b --- /dev/null +++ b/app/common/model/UsedCarFaq.php @@ -0,0 +1,58 @@ +belongsTo(UsedCarDetail::class, 'car_id', 'id'); + } +} diff --git a/app/common/service/UsedCarDetailService.php b/app/common/service/UsedCarDetailService.php new file mode 100644 index 0000000..fd293b3 --- /dev/null +++ b/app/common/service/UsedCarDetailService.php @@ -0,0 +1,458 @@ +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(), + ]; + } +} \ No newline at end of file diff --git a/app/common/validate/UsedCarDetailValidate.php b/app/common/validate/UsedCarDetailValidate.php new file mode 100644 index 0000000..c58b99b --- /dev/null +++ b/app/common/validate/UsedCarDetailValidate.php @@ -0,0 +1,33 @@ + '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'], + ]; +} diff --git a/config/route.php b/config/route.php index 88ad406..5aee935 100644 --- a/config/route.php +++ b/config/route.php @@ -71,6 +71,25 @@ Route::group('/common', function () { 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::any('/info', [app\common\controller\UserController::class, 'show']); Route::any('/edit', [app\common\controller\UserController::class, 'edit']); diff --git a/public/db_log/used_car_detail.sql b/public/db_log/used_car_detail.sql new file mode 100644 index 0000000..9852fde --- /dev/null +++ b/public/db_log/used_car_detail.sql @@ -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`; diff --git a/public/db_log/used_car_detail_audit.sql b/public/db_log/used_car_detail_audit.sql new file mode 100644 index 0000000..5824b62 --- /dev/null +++ b/public/db_log/used_car_detail_audit.sql @@ -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='二手车审核记录表'; diff --git a/public/db_log/used_car_faq.sql b/public/db_log/used_car_faq.sql new file mode 100644 index 0000000..2ebd34e --- /dev/null +++ b/public/db_log/used_car_faq.sql @@ -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='二手车常见问题表'; diff --git a/public/db_log/审批.sql b/public/db_log/审批.sql deleted file mode 100644 index 42e65da..0000000 --- a/public/db_log/审批.sql +++ /dev/null @@ -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='审批讨论'; \ No newline at end of file diff --git a/public/db_log/物品领用.sql b/public/db_log/物品领用.sql deleted file mode 100644 index 570a17e..0000000 --- a/public/db_log/物品领用.sql +++ /dev/null @@ -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;