297 lines
12 KiB
PHP
297 lines
12 KiB
PHP
<?php
|
|
|
|
namespace app\controller\app;
|
|
|
|
use app\model\Report;
|
|
use app\support\AppraisalEvidenceService;
|
|
use app\support\AppAuthService;
|
|
use app\support\ContentService;
|
|
use app\support\FileStorageService;
|
|
use app\support\ReportPdfGenerator;
|
|
use support\Request;
|
|
use support\think\Db;
|
|
|
|
class ReportsController
|
|
{
|
|
public function index(Request $request)
|
|
{
|
|
$userId = app_user_id($request);
|
|
$rows = Db::name('orders')
|
|
->alias('o')
|
|
->leftJoin('reports r', 'r.order_id = o.id AND r.report_status = "published"')
|
|
->leftJoin('order_products p', 'p.order_id = o.id')
|
|
->field([
|
|
'o.id AS order_id',
|
|
'o.order_status',
|
|
'o.display_status',
|
|
'o.service_provider',
|
|
'p.product_name',
|
|
'p.product_cover',
|
|
'r.id AS report_id',
|
|
'r.report_no',
|
|
'r.institution_name',
|
|
'r.publish_time',
|
|
])
|
|
->where('o.user_id', $userId)
|
|
->whereIn('o.order_status', ['in_first_review', 'in_final_review', 'generating_report', 'report_published', 'completed'])
|
|
->order('o.id', 'desc')
|
|
->select()
|
|
->toArray();
|
|
|
|
$list = array_map(function (array $item) {
|
|
$published = !empty($item['report_id']);
|
|
return [
|
|
'report_id' => $published ? (int)$item['report_id'] : null,
|
|
'order_id' => (int)$item['order_id'],
|
|
'report_no' => $item['report_no'] ?: '',
|
|
'product_name' => $item['product_name'] ?: '',
|
|
'product_cover' => $item['product_cover'] ?: '',
|
|
'service_provider' => $item['service_provider'],
|
|
'status' => $published ? '已出报告' : '待出报告',
|
|
'result_text' => $published ? '正品' : '待出报告',
|
|
'institution_name' => $item['institution_name'] ?: '安心验',
|
|
'publish_time' => $item['publish_time'],
|
|
];
|
|
}, $rows);
|
|
|
|
return api_success(['list' => $list]);
|
|
}
|
|
|
|
public function detail(Request $request)
|
|
{
|
|
$id = (int)$request->input('id', 0);
|
|
$reportNo = trim((string)$request->input('report_no', ''));
|
|
if (!$id && $reportNo === '') {
|
|
return api_error('报告标识不能为空', 422);
|
|
}
|
|
|
|
$report = null;
|
|
if ($reportNo !== '') {
|
|
$report = Report::where('report_status', 'published')
|
|
->where('report_no', $reportNo)
|
|
->find();
|
|
} elseif ($id > 0) {
|
|
$userInfo = app_user($request) ?: (new AppAuthService())->current($request);
|
|
if (!$userInfo) {
|
|
return api_error('未登录或登录已过期', 401);
|
|
}
|
|
|
|
$report = Db::name('reports')
|
|
->alias('r')
|
|
->join('orders o', 'o.id = r.order_id')
|
|
->where('r.id', $id)
|
|
->where('r.report_status', 'published')
|
|
->where('o.user_id', (int)$userInfo['id'])
|
|
->field('r.*')
|
|
->find();
|
|
}
|
|
|
|
if (!$report) {
|
|
return api_error('报告不存在', 404);
|
|
}
|
|
|
|
$reportData = is_array($report) ? $report : $report->toArray();
|
|
$content = Db::name('report_contents')->where('report_id', $reportData['id'])->find();
|
|
$verify = Db::name('report_verifies')->where('report_id', $reportData['id'])->find();
|
|
$verify = $this->normalizeVerifyInfo($reportData, $verify ?: []);
|
|
$pdfUrl = $this->ensurePdfFile($request, $reportData, $content ?: [], $verify ?: []);
|
|
$evidenceAttachments = $this->evidenceService()->normalize($content['evidence_attachments_json'] ?? null, $request);
|
|
$defaultRiskNotice = (new ContentService())->getReportRiskNotice((string)($reportData['report_type'] ?? 'appraisal'));
|
|
$payload = [
|
|
'product_snapshot' => $this->decodeJsonField($content['product_snapshot_json'] ?? null),
|
|
'result_snapshot' => $this->decodeJsonField($content['result_snapshot_json'] ?? null),
|
|
'appraisal_snapshot' => $this->decodeJsonField($content['appraisal_snapshot_json'] ?? null),
|
|
'valuation_snapshot' => $this->decodeJsonField($content['valuation_snapshot_json'] ?? null),
|
|
'risk_notice_text' => ($content['risk_notice_text'] ?? '') !== '' ? $content['risk_notice_text'] : $defaultRiskNotice,
|
|
];
|
|
|
|
return api_success([
|
|
'report_header' => [
|
|
'report_id' => (int)$reportData['id'],
|
|
'report_no' => $reportData['report_no'],
|
|
'report_type' => $reportData['report_type'] ?? 'appraisal',
|
|
'report_title' => $reportData['report_title'],
|
|
'report_status' => $reportData['report_status'],
|
|
'service_provider' => $reportData['service_provider'],
|
|
'institution_name' => $reportData['institution_name'],
|
|
'publish_time' => $reportData['publish_time'],
|
|
],
|
|
'result_info' => $payload['result_snapshot'],
|
|
'product_info' => $payload['product_snapshot'],
|
|
'appraisal_info' => $payload['appraisal_snapshot'],
|
|
'valuation_info' => $payload['valuation_snapshot'],
|
|
'evidence_attachments' => $evidenceAttachments,
|
|
'risk_notice_text' => $payload['risk_notice_text'],
|
|
'verify_info' => [
|
|
'report_no' => $reportData['report_no'],
|
|
'verify_status' => $verify['verify_status'] ?? 'valid',
|
|
'verify_url' => $verify['verify_url'] ?? '',
|
|
'verify_qrcode_url' => $verify['verify_qrcode_url'] ?? '',
|
|
],
|
|
'file_info' => [
|
|
'pdf_url' => $pdfUrl,
|
|
],
|
|
]);
|
|
}
|
|
|
|
private function decodeJsonField(mixed $value): array
|
|
{
|
|
if (is_array($value)) {
|
|
return $value;
|
|
}
|
|
if (is_string($value) && $value !== '') {
|
|
return json_decode($value, true) ?: [];
|
|
}
|
|
return [];
|
|
}
|
|
|
|
private function normalizeVerifyInfo(array $report, array $verify): array
|
|
{
|
|
$reportNo = (string)($report['report_no'] ?? '');
|
|
$verifyPageUrl = $this->buildPublicPageUrl('/pages/verify/result', ['report_no' => $reportNo]);
|
|
|
|
$verify['report_no'] = $verify['report_no'] ?? $reportNo;
|
|
$verify['verify_status'] = $verify['verify_status'] ?? 'valid';
|
|
|
|
$rawVerifyUrl = trim((string)($verify['verify_url'] ?? ''));
|
|
if ($rawVerifyUrl === '' || str_starts_with($rawVerifyUrl, '/api/app/verify')) {
|
|
$verify['verify_url'] = $verifyPageUrl;
|
|
}
|
|
|
|
$rawQrValue = trim((string)($verify['verify_qrcode_url'] ?? ''));
|
|
if ($rawQrValue === '' || str_starts_with($rawQrValue, '/api/app/verify') || str_contains($rawQrValue, '/pages/report/detail')) {
|
|
$verify['verify_qrcode_url'] = $verify['verify_url'];
|
|
}
|
|
|
|
return $verify;
|
|
}
|
|
|
|
private function ensurePdfFile(Request $request, array $report, array $content, array $verify): string
|
|
{
|
|
$existingFile = Db::name('report_files')
|
|
->where('report_id', (int)$report['id'])
|
|
->where('file_type', 'pdf')
|
|
->find();
|
|
|
|
if ($existingFile && !empty($existingFile['file_url'])) {
|
|
$relativeUrl = ltrim((string)$existingFile['file_url'], '/');
|
|
if ($this->storage()->exists($relativeUrl)) {
|
|
return $this->storage()->publicUrl($request, $relativeUrl);
|
|
}
|
|
}
|
|
|
|
$productInfo = $this->decodeJsonField($content['product_snapshot_json'] ?? null);
|
|
$resultInfo = $this->decodeJsonField($content['result_snapshot_json'] ?? null);
|
|
$appraisalInfo = $this->decodeJsonField($content['appraisal_snapshot_json'] ?? null);
|
|
$valuationInfo = $this->decodeJsonField($content['valuation_snapshot_json'] ?? null);
|
|
|
|
$publishTime = (string)($report['publish_time'] ?: date('Y-m-d H:i:s'));
|
|
$defaultRiskNotice = (new ContentService())->getReportRiskNotice((string)($report['report_type'] ?? 'appraisal'));
|
|
$relativeDir = 'uploads/reports/' . date('Ymd', strtotime($publishTime));
|
|
$filename = $report['report_no'] . '.pdf';
|
|
$relativePath = $relativeDir . '/' . $filename;
|
|
$generator = new ReportPdfGenerator();
|
|
$pdfBinary = $generator->generate([
|
|
'report_title' => $report['report_title'] ?? '鉴定报告',
|
|
'service_provider_text' => ($report['service_provider'] ?? 'anxinyan') === 'zhongjian' ? '中检鉴定' : '实物鉴定',
|
|
'institution_name' => $report['institution_name'] ?? '安心验',
|
|
'report_no' => $report['report_no'] ?? '',
|
|
'publish_time' => $publishTime,
|
|
'result_text' => $resultInfo['result_text'] ?? '-',
|
|
'result_desc' => $resultInfo['result_desc'] ?? '-',
|
|
'product_name' => $productInfo['product_name'] ?? '-',
|
|
'category_brand' => trim(($productInfo['category_name'] ?? '-') . ' / ' . ($productInfo['brand_name'] ?? '-')),
|
|
'spec_info' => trim(($productInfo['color'] ?? '-') . ' / ' . ($productInfo['size_spec'] ?? '-')),
|
|
'appraisers' => trim((string)($appraisalInfo['appraiser_name'] ?? '-')),
|
|
'condition_grade' => $valuationInfo['condition_grade'] ?? '-',
|
|
'valuation_range' => sprintf(
|
|
'¥%s - ¥%s',
|
|
$valuationInfo['valuation_min'] ?? 0,
|
|
$valuationInfo['valuation_max'] ?? 0
|
|
),
|
|
'verify_info' => sprintf(
|
|
'%s / %s',
|
|
$verify['report_no'] ?? ($report['report_no'] ?? '-'),
|
|
($verify['verify_status'] ?? 'valid') === 'valid' ? '有效' : ($verify['verify_status'] ?? '-')
|
|
),
|
|
'risk_notice_text' => ($content['risk_notice_text'] ?? '') !== '' ? $content['risk_notice_text'] : ($defaultRiskNotice !== '' ? $defaultRiskNotice : '-'),
|
|
]);
|
|
|
|
$this->storage()->putContents($relativePath, $pdfBinary);
|
|
|
|
$now = date('Y-m-d H:i:s');
|
|
$filePayload = [
|
|
'report_id' => (int)$report['id'],
|
|
'file_type' => 'pdf',
|
|
'file_url' => '/' . $relativePath,
|
|
'file_status' => 'ready',
|
|
'updated_at' => $now,
|
|
];
|
|
|
|
if ($existingFile) {
|
|
Db::name('report_files')->where('id', $existingFile['id'])->update($filePayload);
|
|
} else {
|
|
$filePayload['created_at'] = $now;
|
|
Db::name('report_files')->insert($filePayload);
|
|
}
|
|
|
|
return $this->storage()->publicUrl($request, $relativePath);
|
|
}
|
|
|
|
private function buildPublicPageUrl(string $pagePath, array $query = []): string
|
|
{
|
|
$baseUrl = $this->normalizeH5BaseUrl($this->getSystemConfigValue('h5', 'page_base_url'));
|
|
$page = ltrim($pagePath, '/');
|
|
$queryString = http_build_query($query);
|
|
$hashPath = '/#/' . $page;
|
|
if ($queryString !== '') {
|
|
$hashPath .= '?' . $queryString;
|
|
}
|
|
|
|
if ($baseUrl === '') {
|
|
return $hashPath;
|
|
}
|
|
|
|
return $baseUrl . $hashPath;
|
|
}
|
|
|
|
private function normalizeH5BaseUrl(string $value): string
|
|
{
|
|
$baseUrl = trim($value);
|
|
if ($baseUrl === '') {
|
|
return '';
|
|
}
|
|
|
|
$hashPos = strpos($baseUrl, '#');
|
|
if ($hashPos !== false) {
|
|
$baseUrl = substr($baseUrl, 0, $hashPos);
|
|
}
|
|
|
|
if (!preg_match('/^https?:\/\//i', $baseUrl)) {
|
|
$baseUrl = 'https://' . ltrim($baseUrl, '/');
|
|
}
|
|
|
|
return rtrim($baseUrl, '/');
|
|
}
|
|
|
|
private function getSystemConfigValue(string $groupCode, string $configKey): string
|
|
{
|
|
$row = Db::name('system_configs')
|
|
->where('config_group', $groupCode)
|
|
->where('config_key', $configKey)
|
|
->find();
|
|
|
|
return trim((string)($row['config_value'] ?? ''));
|
|
}
|
|
|
|
private function evidenceService(): AppraisalEvidenceService
|
|
{
|
|
return new AppraisalEvidenceService();
|
|
}
|
|
|
|
private function storage(): FileStorageService
|
|
{
|
|
return new FileStorageService();
|
|
}
|
|
}
|