增加了手机操作端
This commit is contained in:
@@ -5,6 +5,7 @@ namespace app\controller\admin;
|
||||
use app\support\AppraisalEvidenceService;
|
||||
use app\support\ContentService;
|
||||
use app\support\EnterpriseWebhookService;
|
||||
use app\support\FulfillmentFlowService;
|
||||
use app\support\MessageDispatcher;
|
||||
use app\support\MaterialTagService;
|
||||
use app\support\PublicAssetUrlService;
|
||||
@@ -19,9 +20,14 @@ class AppraisalTasksController
|
||||
$taskStage = trim((string)$request->input('task_stage', ''));
|
||||
$status = trim((string)$request->input('status', ''));
|
||||
$serviceProvider = trim((string)$request->input('service_provider', ''));
|
||||
$scope = trim((string)$request->input('scope', ''));
|
||||
$paginationEnabled = $request->input('page', null) !== null || $request->input('page_size', null) !== null;
|
||||
$page = max(1, (int)$request->input('page', 1));
|
||||
$pageSize = max(1, min(100, (int)$request->input('page_size', 20)));
|
||||
|
||||
$query = $this->buildTaskBaseQuery()
|
||||
->whereRaw($this->workbenchVisibleOrderStatusSql());
|
||||
$this->applyTaskScopeFilter($query, $request, $scope);
|
||||
|
||||
if ($keyword !== '') {
|
||||
$query->where(function ($builder) use ($keyword) {
|
||||
@@ -49,7 +55,12 @@ class AppraisalTasksController
|
||||
|
||||
$matchedRows = $query->select()->toArray();
|
||||
if (!$matchedRows) {
|
||||
return api_success(['list' => []]);
|
||||
return api_success($paginationEnabled ? [
|
||||
'list' => [],
|
||||
'total' => 0,
|
||||
'page' => $page,
|
||||
'page_size' => $pageSize,
|
||||
] : ['list' => []]);
|
||||
}
|
||||
|
||||
$orderIds = array_values(array_unique(array_map(fn (array $item) => (int)$item['order_id'], $matchedRows)));
|
||||
@@ -58,12 +69,26 @@ class AppraisalTasksController
|
||||
$allRows = $this->buildTaskBaseQuery()
|
||||
->whereRaw($this->workbenchVisibleOrderStatusSql())
|
||||
->whereIn('t.order_id', $orderIds)
|
||||
->group('t.id')
|
||||
->order('t.order_id', 'desc')
|
||||
->order('t.id', 'desc')
|
||||
->select()
|
||||
->toArray();
|
||||
$this->applyTaskScopeFilterRows($allRows, $request, $scope);
|
||||
|
||||
$list = $this->buildGroupedTaskList($allRows, $reportMap);
|
||||
$total = count($list);
|
||||
if ($paginationEnabled) {
|
||||
$offset = ($page - 1) * $pageSize;
|
||||
$list = array_slice($list, $offset, $pageSize);
|
||||
|
||||
return api_success([
|
||||
'list' => $list,
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'page_size' => $pageSize,
|
||||
]);
|
||||
}
|
||||
|
||||
return api_success(['list' => $list]);
|
||||
}
|
||||
@@ -81,7 +106,10 @@ class AppraisalTasksController
|
||||
->leftJoin('order_products p', 'p.order_id = t.order_id')
|
||||
->leftJoin('order_extras e', 'e.order_id = t.order_id')
|
||||
->leftJoin('appraisal_task_results r', 'r.task_id = t.id')
|
||||
->leftJoin('reports rp', 'rp.order_id = t.order_id AND rp.report_type = "appraisal"')
|
||||
->leftJoin('report_contents rc', 'rc.report_id = rp.id')
|
||||
->leftJoin('enterprise_customer_order_refs ecr', 'ecr.order_id = t.order_id')
|
||||
->order('rp.id', 'desc')
|
||||
->field([
|
||||
't.id',
|
||||
't.order_id',
|
||||
@@ -123,6 +151,11 @@ class AppraisalTasksController
|
||||
'r.attachments_json as result_attachments_json',
|
||||
'r.external_remark',
|
||||
'r.internal_remark',
|
||||
'rp.zhongjian_report_no',
|
||||
'rp.report_entry_admin_id',
|
||||
'rp.report_entry_admin_name',
|
||||
'rp.report_entered_at',
|
||||
'rc.zhongjian_report_files_json',
|
||||
])
|
||||
->where('t.id', $id)
|
||||
->find();
|
||||
@@ -195,6 +228,7 @@ class AppraisalTasksController
|
||||
|
||||
$stageTaskRows = $this->buildTaskBaseQuery()
|
||||
->where('t.order_id', (int)$task['order_id'])
|
||||
->group('t.id')
|
||||
->order('t.id', 'asc')
|
||||
->select()
|
||||
->toArray();
|
||||
@@ -279,6 +313,13 @@ class AppraisalTasksController
|
||||
'report_status_text' => $this->reportStatusText($report['report_status']),
|
||||
] : null,
|
||||
'material_tag' => $materialTag,
|
||||
'zhongjian_report' => [
|
||||
'report_no' => (string)($task['zhongjian_report_no'] ?? ''),
|
||||
'report_entry_admin_id' => (int)($task['report_entry_admin_id'] ?? 0),
|
||||
'report_entry_admin_name' => (string)($task['report_entry_admin_name'] ?? ''),
|
||||
'report_entered_at' => (string)($task['report_entered_at'] ?? ''),
|
||||
'files' => $this->evidenceService()->normalize($task['zhongjian_report_files_json'] ?? null, $request),
|
||||
],
|
||||
'product_info' => [
|
||||
'product_name' => $task['product_name'] ?: '',
|
||||
'category_id' => (int)($task['category_id'] ?? 0),
|
||||
@@ -332,6 +373,9 @@ class AppraisalTasksController
|
||||
if (!$task) {
|
||||
return api_error('任务不存在', 404);
|
||||
}
|
||||
if (($task['service_provider'] ?? '') === 'zhongjian') {
|
||||
return api_error('中检订单不使用平台验真吊牌', 422);
|
||||
}
|
||||
|
||||
$operatorGuard = $this->guardTaskOperator($request, $task);
|
||||
if ($operatorGuard['error']) {
|
||||
@@ -354,6 +398,193 @@ class AppraisalTasksController
|
||||
], '吊牌已绑定');
|
||||
}
|
||||
|
||||
public function scanTransferTag(Request $request)
|
||||
{
|
||||
try {
|
||||
return api_success((new FulfillmentFlowService())->scanTransferForAppraisal(
|
||||
(string)$request->input('internal_tag_no', ''),
|
||||
$request
|
||||
));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 404);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('内部流转码识别失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function publishWithMaterialTag(Request $request)
|
||||
{
|
||||
$id = (int)$request->input('id', 0);
|
||||
$qrInput = trim((string)$request->input('qr_input', ''));
|
||||
if ($id <= 0 || $qrInput === '') {
|
||||
return api_error('任务 ID 和验真吊牌不能为空', 422);
|
||||
}
|
||||
|
||||
$task = Db::name('appraisal_tasks')->where('id', $id)->find();
|
||||
if (!$task) {
|
||||
return api_error('任务不存在', 404);
|
||||
}
|
||||
if (($task['service_provider'] ?? '') === 'zhongjian') {
|
||||
return api_error('中检订单不使用平台验真吊牌', 422);
|
||||
}
|
||||
|
||||
try {
|
||||
$tag = (new MaterialTagService())->bindTagToReportByTask($id, $qrInput, $request);
|
||||
$report = $this->findLatestAppraisalReport((int)$task['order_id']);
|
||||
if (!$report) {
|
||||
return api_error('请先提交鉴定结论生成报告草稿', 422);
|
||||
}
|
||||
$publish = $this->publishReportRecord($report, $request);
|
||||
(new FulfillmentFlowService())->markReportPublished((int)$task['order_id'], $request);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 404);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('验真吊牌绑定或报告发布失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
return api_success([
|
||||
'id' => $id,
|
||||
'material_tag' => $tag,
|
||||
'report' => $publish,
|
||||
], '验真吊牌已绑定,报告已发布');
|
||||
}
|
||||
|
||||
public function saveZhongjianReport(Request $request)
|
||||
{
|
||||
$id = (int)$request->input('id', 0);
|
||||
$reportNo = trim((string)$request->input('zhongjian_report_no', ''));
|
||||
$files = $this->evidenceService()->normalize($request->input('report_files', []), $request, true);
|
||||
if ($id <= 0) {
|
||||
return api_error('任务 ID 不能为空', 422);
|
||||
}
|
||||
if ($reportNo === '') {
|
||||
return api_error('中检报告编号不能为空', 422);
|
||||
}
|
||||
if (!$files) {
|
||||
return api_error('请至少上传 1 个中检报告文件', 422);
|
||||
}
|
||||
|
||||
$task = Db::name('appraisal_tasks')->where('id', $id)->find();
|
||||
if (!$task) {
|
||||
return api_error('任务不存在', 404);
|
||||
}
|
||||
if (($task['service_provider'] ?? '') !== 'zhongjian') {
|
||||
return api_error('非中检订单不能录入中检报告', 422);
|
||||
}
|
||||
|
||||
$operatorGuard = $this->guardTaskOperator($request, $task);
|
||||
if ($operatorGuard['error']) {
|
||||
return $operatorGuard['error'];
|
||||
}
|
||||
|
||||
$operatorId = (int)$request->header('x-admin-id', 0);
|
||||
$operatorName = trim((string)$request->header('x-admin-name', ''));
|
||||
$now = date('Y-m-d H:i:s');
|
||||
|
||||
Db::startTrans();
|
||||
try {
|
||||
if ($operatorGuard['task_update']) {
|
||||
Db::name('appraisal_tasks')->where('id', $id)->update(array_merge($operatorGuard['task_update'], [
|
||||
'updated_at' => $now,
|
||||
]));
|
||||
$task = array_merge($task, $operatorGuard['task_update']);
|
||||
}
|
||||
|
||||
Db::name('appraisal_tasks')->where('id', $id)->update([
|
||||
'status' => 'completed',
|
||||
'started_at' => $task['started_at'] ?: $now,
|
||||
'submitted_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
Db::name('orders')->where('id', (int)$task['order_id'])->update([
|
||||
'order_status' => 'generating_report',
|
||||
'display_status' => '正在生成报告',
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
$resultPayload = [
|
||||
'task_id' => $id,
|
||||
'order_id' => (int)$task['order_id'],
|
||||
'result_status' => 'zhongjian_report',
|
||||
'result_text' => '以中检报告为准',
|
||||
'result_desc' => '中检报告已回传并由平台录入。',
|
||||
'condition_grade' => '',
|
||||
'condition_desc' => '',
|
||||
'valuation_min' => 0,
|
||||
'valuation_max' => 0,
|
||||
'valuation_desc' => '',
|
||||
'attachments_json' => json_encode($files, JSON_UNESCAPED_UNICODE),
|
||||
'external_remark' => '',
|
||||
'internal_remark' => '中检报告编号:' . $reportNo,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
$resultId = Db::name('appraisal_task_results')->where('task_id', $id)->value('id');
|
||||
if ($resultId) {
|
||||
Db::name('appraisal_task_results')->where('id', (int)$resultId)->update($resultPayload);
|
||||
} else {
|
||||
$resultPayload['created_at'] = $now;
|
||||
Db::name('appraisal_task_results')->insert($resultPayload);
|
||||
}
|
||||
|
||||
$this->createOrUpdateReportDraft((int)$task['order_id'], $task, $resultPayload, $now);
|
||||
$report = $this->findLatestAppraisalReport((int)$task['order_id']);
|
||||
if (!$report) {
|
||||
Db::rollback();
|
||||
return api_error('中检报告草稿生成失败', 500);
|
||||
}
|
||||
|
||||
Db::name('reports')->where('id', (int)$report['id'])->update([
|
||||
'zhongjian_report_no' => $reportNo,
|
||||
'report_entry_admin_id' => $operatorId,
|
||||
'report_entry_admin_name' => $operatorName,
|
||||
'report_entered_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
$content = Db::name('report_contents')->where('report_id', (int)$report['id'])->find();
|
||||
if ($content) {
|
||||
Db::name('report_contents')->where('id', (int)$content['id'])->update([
|
||||
'zhongjian_report_files_json' => json_encode($files, JSON_UNESCAPED_UNICODE),
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
Db::name('order_timelines')->insert([
|
||||
'order_id' => (int)$task['order_id'],
|
||||
'node_code' => 'zhongjian_report_entered',
|
||||
'node_text' => '中检报告已录入',
|
||||
'node_desc' => '报告录入人已录入中检报告编号并上传报告文件。',
|
||||
'operator_type' => 'admin',
|
||||
'operator_id' => $operatorId,
|
||||
'occurred_at' => $now,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
|
||||
Db::commit();
|
||||
|
||||
$freshReport = $this->findLatestAppraisalReport((int)$task['order_id']);
|
||||
$publish = $this->publishReportRecord($freshReport, $request);
|
||||
(new FulfillmentFlowService())->markReportPublished((int)$task['order_id'], $request);
|
||||
|
||||
return api_success([
|
||||
'id' => $id,
|
||||
'report' => $publish,
|
||||
], '中检报告已录入并发布');
|
||||
} catch (\Throwable $e) {
|
||||
try {
|
||||
Db::rollback();
|
||||
} catch (\Throwable $rollbackError) {
|
||||
// Transaction may already be committed before publishing.
|
||||
}
|
||||
return api_error('中检报告录入失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function assignableAdmins(Request $request)
|
||||
{
|
||||
$id = (int)$request->input('id', 0);
|
||||
@@ -537,7 +768,7 @@ class AppraisalTasksController
|
||||
'node_text' => '正在生成报告',
|
||||
'node_desc' => '鉴定已完成,系统正在生成正式报告草稿',
|
||||
'operator_type' => 'admin',
|
||||
'operator_id' => 1,
|
||||
'operator_id' => (int)$request->header('x-admin-id', 0),
|
||||
'occurred_at' => $now,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
@@ -654,7 +885,7 @@ class AppraisalTasksController
|
||||
'reason' => $reason,
|
||||
'deadline' => $deadline !== '' ? $deadline : null,
|
||||
'status' => 'pending',
|
||||
'created_by' => 1,
|
||||
'created_by' => (int)$request->header('x-admin-id', 0),
|
||||
'submitted_at' => null,
|
||||
'approved_at' => null,
|
||||
'created_at' => $now,
|
||||
@@ -704,7 +935,7 @@ class AppraisalTasksController
|
||||
'node_text' => '待补资料',
|
||||
'node_desc' => $reason,
|
||||
'operator_type' => 'admin',
|
||||
'operator_id' => 1,
|
||||
'operator_id' => (int)$request->header('x-admin-id', 0),
|
||||
'occurred_at' => $now,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
@@ -797,10 +1028,43 @@ class AppraisalTasksController
|
||||
'p.category_name',
|
||||
'p.brand_id',
|
||||
'p.brand_name',
|
||||
'r.result_text',
|
||||
'r.result_text',
|
||||
]);
|
||||
}
|
||||
|
||||
private function applyTaskScopeFilter($query, Request $request, string $scope): void
|
||||
{
|
||||
if ($scope !== 'my') {
|
||||
return;
|
||||
}
|
||||
|
||||
$adminId = (int)$request->header('x-admin-id', 0);
|
||||
if ($adminId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query->whereRaw('(t.assignee_id = :scope_admin_id OR t.assignee_id IS NULL OR t.assignee_id = 0)', [
|
||||
'scope_admin_id' => $adminId,
|
||||
]);
|
||||
}
|
||||
|
||||
private function applyTaskScopeFilterRows(array &$rows, Request $request, string $scope): void
|
||||
{
|
||||
if ($scope !== 'my') {
|
||||
return;
|
||||
}
|
||||
|
||||
$adminId = (int)$request->header('x-admin-id', 0);
|
||||
if ($adminId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rows = array_values(array_filter($rows, function (array $row) use ($adminId) {
|
||||
$assigneeId = (int)($row['assignee_id'] ?? 0);
|
||||
return $assigneeId <= 0 || $assigneeId === $adminId;
|
||||
}));
|
||||
}
|
||||
|
||||
private function normalizeTaskListRow(array $item, ?array $report = null): array
|
||||
{
|
||||
$effectiveStatus = $this->effectiveTaskStatus($item, $report);
|
||||
@@ -1602,6 +1866,176 @@ class AppraisalTasksController
|
||||
return $admin;
|
||||
}
|
||||
|
||||
private function publishReportRecord(array $report, Request $request): array
|
||||
{
|
||||
if (!$report) {
|
||||
throw new \RuntimeException('报告不存在', 404);
|
||||
}
|
||||
if (!in_array((string)$report['report_status'], ['draft', 'pending_publish', 'updated', 'published'], true)) {
|
||||
throw new \InvalidArgumentException('当前报告状态不支持发布');
|
||||
}
|
||||
|
||||
$operatorId = (int)$request->header('x-admin-id', 0);
|
||||
$now = date('Y-m-d H:i:s');
|
||||
$effectivePublishTime = $report['publish_time'] ?: $now;
|
||||
$usesPlatformVerify = (string)($report['service_provider'] ?? '') !== 'zhongjian';
|
||||
$verify = [];
|
||||
|
||||
Db::startTrans();
|
||||
try {
|
||||
if (($report['report_status'] ?? '') !== 'published') {
|
||||
Db::name('reports')->where('id', (int)$report['id'])->update([
|
||||
'report_status' => 'published',
|
||||
'publish_time' => $effectivePublishTime,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
$report['report_status'] = 'published';
|
||||
$report['publish_time'] = $effectivePublishTime;
|
||||
}
|
||||
|
||||
if ($usesPlatformVerify) {
|
||||
$verify = $this->createOrUpdateVerifyRecord($report, $now);
|
||||
}
|
||||
|
||||
if (($report['report_type'] ?? 'appraisal') === 'appraisal' && (int)($report['order_id'] ?? 0) > 0) {
|
||||
Db::name('orders')->where('id', (int)$report['order_id'])->update([
|
||||
'order_status' => 'report_published',
|
||||
'display_status' => '报告已出具',
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
$order = Db::name('orders')->where('id', (int)$report['order_id'])->find();
|
||||
$product = Db::name('order_products')->where('order_id', (int)$report['order_id'])->find();
|
||||
|
||||
$timelineExists = Db::name('order_timelines')
|
||||
->where('order_id', (int)$report['order_id'])
|
||||
->where('node_code', 'report_published')
|
||||
->where('node_text', '报告已出具')
|
||||
->find();
|
||||
if (!$timelineExists) {
|
||||
Db::name('order_timelines')->insert([
|
||||
'order_id' => (int)$report['order_id'],
|
||||
'node_code' => 'report_published',
|
||||
'node_text' => '报告已出具',
|
||||
'node_desc' => '正式报告已发布,用户可查看报告。',
|
||||
'operator_type' => 'admin',
|
||||
'operator_id' => $operatorId ?: null,
|
||||
'occurred_at' => $now,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
(new MessageDispatcher())->sendInboxEvent('report_published', [
|
||||
'user_id' => (int)($order['user_id'] ?? 0),
|
||||
'biz_type' => 'report',
|
||||
'biz_id' => (int)$report['id'],
|
||||
'report_no' => (string)$report['report_no'],
|
||||
'report_title' => (string)$report['report_title'],
|
||||
'product_name' => $product['product_name'] ?? '',
|
||||
'publish_time' => $effectivePublishTime,
|
||||
'verify_url' => $usesPlatformVerify ? (string)($verify['verify_url'] ?? '') : '',
|
||||
'fallback_title' => '报告已出具',
|
||||
'fallback_content' => '您的正式报告已生成,可前往报告中心查看。',
|
||||
]);
|
||||
}
|
||||
|
||||
Db::commit();
|
||||
} catch (\Throwable $e) {
|
||||
Db::rollback();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (($report['report_type'] ?? 'appraisal') === 'appraisal' && (int)($report['order_id'] ?? 0) > 0) {
|
||||
(new EnterpriseWebhookService())->recordOrderEvent((int)$report['order_id'], 'report_published', [
|
||||
'report_id' => (int)$report['id'],
|
||||
'report_no' => (string)$report['report_no'],
|
||||
'report_title' => (string)$report['report_title'],
|
||||
'publish_time' => $effectivePublishTime,
|
||||
'verify_url' => $usesPlatformVerify ? (string)($verify['verify_url'] ?? '') : '',
|
||||
'report_page_url' => $usesPlatformVerify ? (string)($verify['report_page_url'] ?? '') : '',
|
||||
]);
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => (int)$report['id'],
|
||||
'report_status' => 'published',
|
||||
'publish_time' => $effectivePublishTime,
|
||||
'verify_url' => $usesPlatformVerify ? (string)($verify['verify_url'] ?? '') : '',
|
||||
'report_page_url' => $usesPlatformVerify ? (string)($verify['report_page_url'] ?? '') : '',
|
||||
];
|
||||
}
|
||||
|
||||
private function createOrUpdateVerifyRecord(array $report, string $now): array
|
||||
{
|
||||
$reportNo = (string)$report['report_no'];
|
||||
$verifyToken = 'verify_' . strtolower((string)preg_replace('/[^a-zA-Z0-9]/', '', $reportNo));
|
||||
$verifyUrl = $this->buildPublicPageUrl('/pages/verify/result', ['report_no' => $reportNo]);
|
||||
$reportPageUrl = $this->buildPublicPageUrl('/pages/report/detail', ['report_no' => $reportNo]);
|
||||
|
||||
$payload = [
|
||||
'report_id' => (int)$report['id'],
|
||||
'report_no' => $reportNo,
|
||||
'verify_token' => $verifyToken,
|
||||
'verify_qrcode_url' => $reportPageUrl,
|
||||
'verify_url' => $verifyUrl,
|
||||
'verify_status' => 'valid',
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
$verify = Db::name('report_verifies')->where('report_id', (int)$report['id'])->find();
|
||||
if ($verify) {
|
||||
Db::name('report_verifies')->where('id', (int)$verify['id'])->update($payload);
|
||||
} else {
|
||||
$payload['last_verified_at'] = null;
|
||||
$payload['verify_count'] = 0;
|
||||
$payload['created_at'] = $now;
|
||||
Db::name('report_verifies')->insert($payload);
|
||||
}
|
||||
|
||||
$fresh = Db::name('report_verifies')->where('report_id', (int)$report['id'])->find() ?: $payload;
|
||||
$fresh['report_page_url'] = $reportPageUrl;
|
||||
return $fresh;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return $baseUrl === '' ? $hashPath : $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();
|
||||
|
||||
@@ -51,6 +51,30 @@ class MaterialsController
|
||||
}
|
||||
|
||||
public function download(Request $request)
|
||||
{
|
||||
$file = $this->resolveDownloadFile($request);
|
||||
if ($file instanceof \support\Response) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return redirect($file['url'], 302);
|
||||
}
|
||||
|
||||
public function downloadLink(Request $request)
|
||||
{
|
||||
$file = $this->resolveDownloadFile($request);
|
||||
if ($file instanceof \support\Response) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return api_success([
|
||||
'filename' => $file['filename'],
|
||||
'url' => $file['url'],
|
||||
'size' => $file['size'],
|
||||
], '下载链接已生成');
|
||||
}
|
||||
|
||||
private function resolveDownloadFile(Request $request): array|\support\Response
|
||||
{
|
||||
$id = (int)$request->input('id', 0);
|
||||
if ($id <= 0) {
|
||||
@@ -65,12 +89,43 @@ class MaterialsController
|
||||
return api_error('物料批次下载失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
$filename = rawurlencode($file['filename']);
|
||||
return response($file['content'], 200, [
|
||||
'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'Content-Disposition' => "attachment; filename=\"{$file['filename']}\"; filename*=UTF-8''{$filename}",
|
||||
'Cache-Control' => 'no-store, no-cache, must-revalidate',
|
||||
]);
|
||||
return $file;
|
||||
}
|
||||
|
||||
public function invalidateBatch(Request $request)
|
||||
{
|
||||
$id = (int)$request->input('id', 0);
|
||||
if ($id <= 0) {
|
||||
return api_error('物料批次 ID 不能为空', 422);
|
||||
}
|
||||
|
||||
try {
|
||||
return api_success($this->service()->invalidateBatch($id, $request), '物料批次已失效');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 500);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('物料批次失效失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function invalidateTag(Request $request)
|
||||
{
|
||||
$id = (int)$request->input('id', 0);
|
||||
if ($id <= 0) {
|
||||
return api_error('物料条码 ID 不能为空', 422);
|
||||
}
|
||||
|
||||
try {
|
||||
return api_success($this->service()->invalidateTag($id, $request), '物料条码已失效');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 500);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('物料条码失效失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
private function service(): MaterialTagService
|
||||
|
||||
@@ -16,6 +16,9 @@ class OrdersController
|
||||
$status = trim((string)$request->input('status', ''));
|
||||
$serviceProvider = trim((string)$request->input('service_provider', ''));
|
||||
$sourceChannel = $this->normalizeOrderSourceChannel((string)$request->input('source_channel', ''));
|
||||
$paginationEnabled = $request->input('page', null) !== null || $request->input('page_size', null) !== null;
|
||||
$page = max(1, (int)$request->input('page', 1));
|
||||
$pageSize = max(1, min(100, (int)$request->input('page_size', 20)));
|
||||
|
||||
$query = Db::name('orders')
|
||||
->alias('o')
|
||||
@@ -51,11 +54,38 @@ class OrdersController
|
||||
});
|
||||
}
|
||||
|
||||
$specialStatusFilters = ['returning', 'completed_signed'];
|
||||
$warehouseStatusFilters = [
|
||||
'warehouse_active',
|
||||
'warehouse_in_transit',
|
||||
'warehouse_received',
|
||||
'warehouse_pending_return',
|
||||
];
|
||||
$specialStatusFilters = array_merge(['returning', 'completed_signed'], $warehouseStatusFilters);
|
||||
if ($status !== '' && !in_array($status, $specialStatusFilters, true)) {
|
||||
$query->where('o.order_status', $status);
|
||||
}
|
||||
|
||||
if (in_array($status, $warehouseStatusFilters, true)) {
|
||||
$warehouseActiveStatuses = [
|
||||
'pending_shipping',
|
||||
'received',
|
||||
'in_first_review',
|
||||
'pending_supplement',
|
||||
'in_final_review',
|
||||
'generating_report',
|
||||
'report_published',
|
||||
];
|
||||
if ($status === 'warehouse_in_transit') {
|
||||
$query->where('o.order_status', 'pending_shipping');
|
||||
} elseif ($status === 'warehouse_received') {
|
||||
$query->whereIn('o.order_status', array_values(array_diff($warehouseActiveStatuses, ['pending_shipping', 'report_published'])));
|
||||
} elseif ($status === 'warehouse_pending_return') {
|
||||
$query->where('o.order_status', 'report_published');
|
||||
} else {
|
||||
$query->whereIn('o.order_status', $warehouseActiveStatuses);
|
||||
}
|
||||
}
|
||||
|
||||
if ($serviceProvider !== '') {
|
||||
$query->where('o.service_provider', $serviceProvider);
|
||||
}
|
||||
@@ -66,28 +96,23 @@ class OrdersController
|
||||
|
||||
$rows = $query->select()->toArray();
|
||||
|
||||
$returnTrackingMap = [];
|
||||
if ($rows) {
|
||||
$returnRows = Db::name('order_logistics')
|
||||
->whereIn('order_id', array_column($rows, 'id'))
|
||||
->where('logistics_type', 'return_to_user')
|
||||
->order('id', 'desc')
|
||||
->select()
|
||||
->toArray();
|
||||
foreach ($returnRows as $row) {
|
||||
$orderId = (int)($row['order_id'] ?? 0);
|
||||
if ($orderId > 0 && !isset($returnTrackingMap[$orderId])) {
|
||||
$returnTrackingMap[$orderId] = [
|
||||
'tracking_no' => (string)($row['tracking_no'] ?? ''),
|
||||
'tracking_status' => (string)($row['tracking_status'] ?? ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
$orderIds = array_map('intval', array_column($rows, 'id'));
|
||||
$sendTrackingMap = $this->latestLogisticsMap($orderIds, 'send_to_center');
|
||||
$returnTrackingMap = $this->latestLogisticsMap($orderIds, 'return_to_user');
|
||||
|
||||
$list = array_map(function (array $item) use ($sendTrackingMap, $returnTrackingMap) {
|
||||
$orderId = (int)$item['id'];
|
||||
$sendTrackingNo = $sendTrackingMap[$orderId]['tracking_no'] ?? '';
|
||||
$sendTrackingStatus = $sendTrackingMap[$orderId]['tracking_status'] ?? '';
|
||||
$warehouseBucket = $this->warehouseOrderBucket(
|
||||
(string)$item['order_status'],
|
||||
$sendTrackingNo,
|
||||
$sendTrackingStatus,
|
||||
(string)($item['display_status'] ?? '')
|
||||
);
|
||||
|
||||
$list = array_map(function (array $item) use ($returnTrackingMap) {
|
||||
return [
|
||||
'id' => (int)$item['id'],
|
||||
'id' => $orderId,
|
||||
'order_no' => $item['order_no'],
|
||||
'appraisal_no' => $item['appraisal_no'],
|
||||
'product_name' => $item['product_name'] ?: '待完善物品信息',
|
||||
@@ -102,9 +127,11 @@ class OrdersController
|
||||
'display_status' => $this->displayStatus(
|
||||
(string)$item['order_status'],
|
||||
(string)$item['display_status'],
|
||||
$returnTrackingMap[(int)$item['id']]['tracking_no'] ?? '',
|
||||
$returnTrackingMap[(int)$item['id']]['tracking_status'] ?? '',
|
||||
$returnTrackingMap[$orderId]['tracking_no'] ?? '',
|
||||
$returnTrackingMap[$orderId]['tracking_status'] ?? '',
|
||||
),
|
||||
'warehouse_bucket' => $warehouseBucket,
|
||||
'warehouse_bucket_text' => $this->warehouseOrderBucketText($warehouseBucket),
|
||||
'estimated_finish_time' => $item['estimated_finish_time'],
|
||||
'pay_amount' => (float)$item['pay_amount'],
|
||||
'created_at' => $item['created_at'],
|
||||
@@ -123,6 +150,33 @@ class OrdersController
|
||||
}));
|
||||
}
|
||||
|
||||
if (in_array($status, $warehouseStatusFilters, true)) {
|
||||
$list = array_values(array_filter($list, function (array $item) use ($status) {
|
||||
if ($status === 'warehouse_active') {
|
||||
return in_array($item['warehouse_bucket'], [
|
||||
'warehouse_in_transit',
|
||||
'warehouse_received',
|
||||
'warehouse_pending_return',
|
||||
], true);
|
||||
}
|
||||
|
||||
return $item['warehouse_bucket'] === $status;
|
||||
}));
|
||||
}
|
||||
|
||||
$total = count($list);
|
||||
if ($paginationEnabled) {
|
||||
$offset = ($page - 1) * $pageSize;
|
||||
$list = array_slice($list, $offset, $pageSize);
|
||||
|
||||
return api_success([
|
||||
'list' => $list,
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'page_size' => $pageSize,
|
||||
]);
|
||||
}
|
||||
|
||||
return api_success([
|
||||
'list' => $list,
|
||||
]);
|
||||
@@ -355,9 +409,11 @@ class OrdersController
|
||||
'items' => $supplementItems,
|
||||
] : null,
|
||||
'report_summary' => $report ? [
|
||||
'id' => (int)$report['id'],
|
||||
'report_no' => $report['report_no'],
|
||||
'report_title' => $report['report_title'],
|
||||
'report_status' => $report['report_status'],
|
||||
'report_status_text' => $this->reportStatusText((string)$report['report_status']),
|
||||
'publish_time' => $report['publish_time'],
|
||||
] : null,
|
||||
]);
|
||||
@@ -469,7 +525,7 @@ class OrdersController
|
||||
'node_text' => '仓库已改派',
|
||||
'node_desc' => sprintf('订单收货仓库已改派至 %s', $snapshot['warehouse_name']),
|
||||
'operator_type' => 'admin',
|
||||
'operator_id' => 1,
|
||||
'operator_id' => (int)$request->header('x-admin-id', 0) ?: null,
|
||||
'occurred_at' => $now,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
@@ -581,7 +637,7 @@ class OrdersController
|
||||
? '包裹已由鉴定中心签收,订单已进入鉴定流程'
|
||||
: '大客户推送订单已确认到仓,订单已进入鉴定流程',
|
||||
'operator_type' => 'admin',
|
||||
'operator_id' => 1,
|
||||
'operator_id' => (int)$request->header('x-admin-id', 0) ?: null,
|
||||
'occurred_at' => $now,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
@@ -729,7 +785,7 @@ class OrdersController
|
||||
'node_text' => $nodeText,
|
||||
'node_desc' => $nodeDesc,
|
||||
'operator_type' => 'admin',
|
||||
'operator_id' => 1,
|
||||
'operator_id' => (int)$request->header('x-admin-id', 0) ?: null,
|
||||
'occurred_at' => $now,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
@@ -821,7 +877,7 @@ class OrdersController
|
||||
'node_text' => '用户已签收',
|
||||
'node_desc' => '回寄商品已由用户签收,本次订单已完成。',
|
||||
'operator_type' => 'admin',
|
||||
'operator_id' => 1,
|
||||
'operator_id' => (int)$request->header('x-admin-id', 0) ?: null,
|
||||
'occurred_at' => $now,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
@@ -870,6 +926,18 @@ class OrdersController
|
||||
};
|
||||
}
|
||||
|
||||
private function reportStatusText(string $status): string
|
||||
{
|
||||
return match ($status) {
|
||||
'draft' => '草稿中',
|
||||
'pending_publish' => '待发布',
|
||||
'published' => '已发布',
|
||||
'updated' => '已更新',
|
||||
'invalid' => '已作废',
|
||||
default => $status,
|
||||
};
|
||||
}
|
||||
|
||||
private function displayStatus(string $orderStatus, string $displayStatus, string $returnTrackingNo = '', string $returnTrackingStatus = ''): string
|
||||
{
|
||||
if ($orderStatus === 'report_published') {
|
||||
@@ -888,6 +956,77 @@ class OrdersController
|
||||
return $displayStatus;
|
||||
}
|
||||
|
||||
private function latestLogisticsMap(array $orderIds, string $logisticsType): array
|
||||
{
|
||||
$orderIds = array_values(array_unique(array_filter(array_map('intval', $orderIds))));
|
||||
if (!$orderIds) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$rows = Db::name('order_logistics')
|
||||
->whereIn('order_id', $orderIds)
|
||||
->where('logistics_type', $logisticsType)
|
||||
->order('id', 'desc')
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
$map = [];
|
||||
foreach ($rows as $row) {
|
||||
$orderId = (int)($row['order_id'] ?? 0);
|
||||
if ($orderId > 0 && !isset($map[$orderId])) {
|
||||
$map[$orderId] = [
|
||||
'tracking_no' => (string)($row['tracking_no'] ?? ''),
|
||||
'tracking_status' => (string)($row['tracking_status'] ?? ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
private function warehouseOrderBucket(
|
||||
string $orderStatus,
|
||||
string $sendTrackingNo = '',
|
||||
string $sendTrackingStatus = '',
|
||||
string $displayStatus = ''
|
||||
): string
|
||||
{
|
||||
if ($orderStatus === 'pending_shipping') {
|
||||
$hasSubmittedTracking = $sendTrackingNo !== '' && $sendTrackingStatus !== 'received';
|
||||
$hasSubmittedDisplayStatus = in_array($displayStatus, ['已提交运单', '用户已提交运单'], true)
|
||||
&& $sendTrackingStatus !== 'received';
|
||||
if ($hasSubmittedTracking || $hasSubmittedDisplayStatus) {
|
||||
return 'warehouse_in_transit';
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($orderStatus, [
|
||||
'received',
|
||||
'in_first_review',
|
||||
'pending_supplement',
|
||||
'in_final_review',
|
||||
'generating_report',
|
||||
], true)) {
|
||||
return 'warehouse_received';
|
||||
}
|
||||
|
||||
if ($orderStatus === 'report_published') {
|
||||
return 'warehouse_pending_return';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function warehouseOrderBucketText(string $bucket): string
|
||||
{
|
||||
return match ($bucket) {
|
||||
'warehouse_in_transit' => '在途',
|
||||
'warehouse_received' => '已入仓',
|
||||
'warehouse_pending_return' => '待寄回',
|
||||
default => '',
|
||||
};
|
||||
}
|
||||
|
||||
private function normalizeOrderSourceChannel(string $sourceChannel): string
|
||||
{
|
||||
$sourceChannel = trim($sourceChannel);
|
||||
|
||||
@@ -16,6 +16,9 @@ class ReportsController
|
||||
$keyword = trim((string)$request->input('keyword', ''));
|
||||
$status = trim((string)$request->input('status', ''));
|
||||
$serviceProvider = trim((string)$request->input('service_provider', ''));
|
||||
$paginationEnabled = $request->input('page', null) !== null || $request->input('page_size', null) !== null;
|
||||
$page = max(1, (int)$request->input('page', 1));
|
||||
$pageSize = max(1, min(100, (int)$request->input('page_size', 20)));
|
||||
|
||||
$query = Db::name('reports')
|
||||
->alias('r')
|
||||
@@ -32,6 +35,9 @@ class ReportsController
|
||||
'r.service_provider',
|
||||
'r.institution_name',
|
||||
'r.publish_time',
|
||||
'r.zhongjian_report_no',
|
||||
'r.report_entry_admin_name',
|
||||
'r.report_entered_at',
|
||||
'o.order_no',
|
||||
'p.product_name',
|
||||
'p.category_name',
|
||||
@@ -68,6 +74,9 @@ class ReportsController
|
||||
'service_provider_text' => $this->serviceProviderText($item['service_provider']),
|
||||
'institution_name' => $item['institution_name'] ?: $this->defaultInstitutionName($item['service_provider']),
|
||||
'publish_time' => $item['publish_time'],
|
||||
'zhongjian_report_no' => (string)($item['zhongjian_report_no'] ?? ''),
|
||||
'report_entry_admin_name' => (string)($item['report_entry_admin_name'] ?? ''),
|
||||
'report_entered_at' => (string)($item['report_entered_at'] ?? ''),
|
||||
'product_name' => $item['product_name'] ?: (string)($productSnapshot['product_name'] ?? ''),
|
||||
'category_name' => $item['category_name'] ?: (string)($productSnapshot['category_name'] ?? ''),
|
||||
'brand_name' => $item['brand_name'] ?: (string)($productSnapshot['brand_name'] ?? ''),
|
||||
@@ -80,6 +89,19 @@ class ReportsController
|
||||
$list[] = $mapped;
|
||||
}
|
||||
|
||||
$total = count($list);
|
||||
if ($paginationEnabled) {
|
||||
$offset = ($page - 1) * $pageSize;
|
||||
$list = array_slice($list, $offset, $pageSize);
|
||||
|
||||
return api_success([
|
||||
'list' => $list,
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'page_size' => $pageSize,
|
||||
]);
|
||||
}
|
||||
|
||||
return api_success(['list' => $list]);
|
||||
}
|
||||
|
||||
@@ -100,22 +122,24 @@ class ReportsController
|
||||
$resultSnapshot = $this->decodeJsonField($content['result_snapshot_json'] ?? null);
|
||||
$appraisalSnapshot = $this->decodeJsonField($content['appraisal_snapshot_json'] ?? null);
|
||||
$valuationSnapshot = $this->decodeJsonField($content['valuation_snapshot_json'] ?? null);
|
||||
$zhongjianReportFiles = $this->evidenceService()->normalize($content['zhongjian_report_files_json'] ?? null, $request);
|
||||
$appraisalSnapshot = $this->enrichAppraisalSnapshot($report, $appraisalSnapshot);
|
||||
$evidenceAttachments = $this->evidenceService()->normalize($content['evidence_attachments_json'] ?? null, $request);
|
||||
|
||||
$verify = Db::name('report_verifies')->where('report_id', $id)->find() ?: [];
|
||||
if (($report['report_status'] ?? '') === 'published') {
|
||||
$usesPlatformVerify = (string)($report['service_provider'] ?? '') !== 'zhongjian';
|
||||
$verify = $usesPlatformVerify ? (Db::name('report_verifies')->where('report_id', $id)->find() ?: []) : [];
|
||||
if ($usesPlatformVerify && ($report['report_status'] ?? '') === 'published') {
|
||||
$verify = $this->createOrUpdateVerifyRecord($report, date('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
$reportPageUrl = $this->buildPublicPageUrl('/pages/report/detail', ['report_no' => $report['report_no']]);
|
||||
$verifyUrl = $this->buildPublicPageUrl('/pages/verify/result', ['report_no' => $report['report_no']]);
|
||||
$reportPageUrl = $usesPlatformVerify ? $this->buildPublicPageUrl('/pages/report/detail', ['report_no' => $report['report_no']]) : '';
|
||||
$verifyUrl = $usesPlatformVerify ? $this->buildPublicPageUrl('/pages/verify/result', ['report_no' => $report['report_no']]) : '';
|
||||
if (!$verify) {
|
||||
$verify = [];
|
||||
}
|
||||
$verify['report_page_url'] = $verify['report_page_url'] ?? $reportPageUrl;
|
||||
$verify['verify_qrcode_url'] = $verify['verify_qrcode_url'] ?? $reportPageUrl;
|
||||
$verify['verify_url'] = $verify['verify_url'] ?? $verifyUrl;
|
||||
$verify['report_page_url'] = $usesPlatformVerify ? ($verify['report_page_url'] ?? $reportPageUrl) : '';
|
||||
$verify['verify_qrcode_url'] = $usesPlatformVerify ? ($verify['verify_qrcode_url'] ?? $reportPageUrl) : '';
|
||||
$verify['verify_url'] = $usesPlatformVerify ? ($verify['verify_url'] ?? $verifyUrl) : '';
|
||||
$defaultRiskNotice = (new ContentService())->getReportRiskNotice((string)($report['report_type'] ?? 'appraisal'));
|
||||
|
||||
return api_success([
|
||||
@@ -132,12 +156,17 @@ class ReportsController
|
||||
'service_provider_text' => $this->serviceProviderText($report['service_provider']),
|
||||
'institution_name' => $report['institution_name'] ?: $this->defaultInstitutionName($report['service_provider']),
|
||||
'publish_time' => $report['publish_time'],
|
||||
'zhongjian_report_no' => (string)($report['zhongjian_report_no'] ?? ''),
|
||||
'report_entry_admin_id' => (int)($report['report_entry_admin_id'] ?? 0),
|
||||
'report_entry_admin_name' => (string)($report['report_entry_admin_name'] ?? ''),
|
||||
'report_entered_at' => (string)($report['report_entered_at'] ?? ''),
|
||||
],
|
||||
'product_info' => $productSnapshot,
|
||||
'result_info' => $resultSnapshot,
|
||||
'appraisal_info' => $appraisalSnapshot,
|
||||
'valuation_info' => $valuationSnapshot,
|
||||
'evidence_attachments' => $evidenceAttachments,
|
||||
'zhongjian_report_files' => $zhongjianReportFiles,
|
||||
'risk_notice_text' => ($content['risk_notice_text'] ?? '') !== '' ? $content['risk_notice_text'] : $defaultRiskNotice,
|
||||
'verify_info' => [
|
||||
'verify_status' => $verify['verify_status'] ?? (($report['report_status'] ?? '') === 'published' ? 'valid' : 'pending'),
|
||||
@@ -304,8 +333,9 @@ class ReportsController
|
||||
'verify_url' => '',
|
||||
'report_page_url' => '',
|
||||
];
|
||||
$usesPlatformVerify = $serviceProvider !== 'zhongjian';
|
||||
|
||||
if ($reportStatus === 'published' && $reportRecord) {
|
||||
if ($reportStatus === 'published' && $reportRecord && $usesPlatformVerify) {
|
||||
$verifyInfo = $this->createOrUpdateVerifyRecord($reportRecord, $now);
|
||||
} else {
|
||||
Db::name('report_verifies')->where('report_id', $reportId)->delete();
|
||||
@@ -351,6 +381,7 @@ class ReportsController
|
||||
}
|
||||
|
||||
$effectivePublishTime = $report['publish_time'] ?: $now;
|
||||
$usesPlatformVerify = (string)($report['service_provider'] ?? '') !== 'zhongjian';
|
||||
if ($report['report_status'] !== 'published') {
|
||||
Db::name('reports')->where('id', $id)->update([
|
||||
'report_status' => 'published',
|
||||
@@ -365,7 +396,12 @@ class ReportsController
|
||||
$this->refreshAppraisalSnapshot((int)$report['id'], (int)$report['order_id'], $report['service_provider'], $now);
|
||||
}
|
||||
|
||||
$verify = $this->createOrUpdateVerifyRecord($report, $now);
|
||||
$verify = [];
|
||||
if ($usesPlatformVerify) {
|
||||
$verify = $this->createOrUpdateVerifyRecord($report, $now);
|
||||
} else {
|
||||
Db::name('report_verifies')->where('report_id', $id)->delete();
|
||||
}
|
||||
|
||||
if (($report['report_type'] ?? 'appraisal') === 'appraisal' && (int)($report['order_id'] ?? 0) > 0) {
|
||||
Db::name('orders')->where('id', $report['order_id'])->update([
|
||||
@@ -388,9 +424,9 @@ class ReportsController
|
||||
'order_id' => $report['order_id'],
|
||||
'node_code' => 'report_published',
|
||||
'node_text' => '报告已出具',
|
||||
'node_desc' => '正式报告已发布,用户可查看报告并进行验真。',
|
||||
'node_desc' => $usesPlatformVerify ? '正式报告已发布,用户可查看报告并进行验真。' : '中检报告已发布,用户可查看报告。',
|
||||
'operator_type' => 'admin',
|
||||
'operator_id' => 1,
|
||||
'operator_id' => (int)$request->header('x-admin-id', 0) ?: null,
|
||||
'occurred_at' => $now,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
@@ -404,9 +440,9 @@ class ReportsController
|
||||
'report_title' => $report['report_title'],
|
||||
'product_name' => $product['product_name'] ?? '',
|
||||
'publish_time' => $report['publish_time'] ?: $now,
|
||||
'verify_url' => $verify['verify_url'],
|
||||
'verify_url' => $usesPlatformVerify ? (string)($verify['verify_url'] ?? '') : '',
|
||||
'fallback_title' => '报告已出具',
|
||||
'fallback_content' => '您的正式报告已生成,可前往报告中心查看并完成验真。',
|
||||
'fallback_content' => $usesPlatformVerify ? '您的正式报告已生成,可前往报告中心查看并完成验真。' : '您的中检报告已生成,可前往报告中心查看。',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -418,8 +454,8 @@ class ReportsController
|
||||
'report_no' => (string)$report['report_no'],
|
||||
'report_title' => (string)$report['report_title'],
|
||||
'publish_time' => $effectivePublishTime,
|
||||
'verify_url' => (string)($verify['verify_url'] ?? ''),
|
||||
'report_page_url' => (string)($verify['report_page_url'] ?? ''),
|
||||
'verify_url' => $usesPlatformVerify ? (string)($verify['verify_url'] ?? '') : '',
|
||||
'report_page_url' => $usesPlatformVerify ? (string)($verify['report_page_url'] ?? '') : '',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -427,8 +463,8 @@ class ReportsController
|
||||
'id' => $id,
|
||||
'report_status' => 'published',
|
||||
'publish_time' => $effectivePublishTime,
|
||||
'verify_url' => $verify['verify_url'],
|
||||
'report_page_url' => $verify['report_page_url'],
|
||||
'verify_url' => $usesPlatformVerify ? (string)($verify['verify_url'] ?? '') : '',
|
||||
'report_page_url' => $usesPlatformVerify ? (string)($verify['report_page_url'] ?? '') : '',
|
||||
], '报告已发布');
|
||||
} catch (\Throwable $e) {
|
||||
Db::rollback();
|
||||
|
||||
144
server-api/app/controller/admin/WarehouseWorkbenchController.php
Normal file
144
server-api/app/controller/admin/WarehouseWorkbenchController.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use app\support\FulfillmentFlowService;
|
||||
use support\Request;
|
||||
|
||||
class WarehouseWorkbenchController
|
||||
{
|
||||
public function inboundLookup(Request $request)
|
||||
{
|
||||
try {
|
||||
return api_success($this->service()->lookupInboundByTrackingNo((string)$request->input('tracking_no', '')));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 404);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('入库匹配失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function inboundReceive(Request $request)
|
||||
{
|
||||
try {
|
||||
return api_success($this->service()->receiveInbound(
|
||||
(string)$request->input('tracking_no', ''),
|
||||
(string)$request->input('internal_tag_no', ''),
|
||||
$request
|
||||
), '入库完成');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 404);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('入库失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function zhongjianLookup(Request $request)
|
||||
{
|
||||
try {
|
||||
return api_success($this->service()->lookupZhongjianTransfer((string)$request->input('internal_tag_no', '')));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 404);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('中检流转查询失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function zhongjianOutbound(Request $request)
|
||||
{
|
||||
try {
|
||||
return api_success($this->service()->zhongjianOutbound((string)$request->input('internal_tag_no', ''), $request), '送检出库完成');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 404);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('送检出库失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function zhongjianInbound(Request $request)
|
||||
{
|
||||
try {
|
||||
return api_success($this->service()->zhongjianInbound((string)$request->input('internal_tag_no', ''), $request), '送检入库完成');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 404);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('送检入库失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function returnLookup(Request $request)
|
||||
{
|
||||
try {
|
||||
return api_success($this->service()->lookupReturn((string)$request->input('internal_tag_no', ''), $request));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 404);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('寄回查询失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function verifyReturnMaterialTag(Request $request)
|
||||
{
|
||||
try {
|
||||
return api_success($this->service()->verifyReturnMaterialTag(
|
||||
(string)$request->input('internal_tag_no', ''),
|
||||
(string)$request->input('qr_input', ''),
|
||||
$request
|
||||
), '验真吊牌已确认');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 404);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('验真吊牌确认失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function confirmZhongjianReturn(Request $request)
|
||||
{
|
||||
try {
|
||||
return api_success($this->service()->confirmZhongjianReturn((string)$request->input('internal_tag_no', ''), $request), '中检报告已确认');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 404);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('中检报告确认失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function shipReturn(Request $request)
|
||||
{
|
||||
try {
|
||||
return api_success($this->service()->shipReturn(
|
||||
(string)$request->input('internal_tag_no', ''),
|
||||
(string)$request->input('express_company', ''),
|
||||
(string)$request->input('tracking_no', ''),
|
||||
$request
|
||||
), '回寄运单已登记');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), $e->getCode() ?: 404);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('回寄运单登记失败', 500, ['detail' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
private function service(): FulfillmentFlowService
|
||||
{
|
||||
return new FulfillmentFlowService();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\app;
|
||||
|
||||
use app\support\MaterialTagService;
|
||||
use support\Request;
|
||||
|
||||
class MaterialTagRedirectController
|
||||
{
|
||||
public function redirect(Request $request)
|
||||
{
|
||||
$token = trim((string)($request->route?->param('token', '') ?? ''));
|
||||
if ($token === '') {
|
||||
return response('Material tag token is required', 400);
|
||||
}
|
||||
|
||||
try {
|
||||
$url = (new MaterialTagService())->buildMaterialTagDetailUrl($token);
|
||||
} catch (\Throwable $e) {
|
||||
return response($e->getMessage(), 500);
|
||||
}
|
||||
|
||||
return redirect($url, 302);
|
||||
}
|
||||
}
|
||||
@@ -92,10 +92,12 @@ class ReportsController
|
||||
|
||||
$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 ?: []);
|
||||
$isZhongjian = (string)($reportData['service_provider'] ?? '') === 'zhongjian';
|
||||
$verify = $isZhongjian ? [] : (Db::name('report_verifies')->where('report_id', $reportData['id'])->find() ?: []);
|
||||
$verify = $isZhongjian ? [] : $this->normalizeVerifyInfo($reportData, $verify);
|
||||
$pdfUrl = $this->ensurePdfFile($request, $reportData, $content ?: [], $verify ?: []);
|
||||
$evidenceAttachments = $this->evidenceService()->normalize($content['evidence_attachments_json'] ?? null, $request);
|
||||
$zhongjianReportFiles = $this->evidenceService()->normalize($content['zhongjian_report_files_json'] ?? null, $request);
|
||||
$defaultRiskNotice = (new ContentService())->getReportRiskNotice((string)($reportData['report_type'] ?? 'appraisal'));
|
||||
$payload = [
|
||||
'product_snapshot' => $this->decodeJsonField($content['product_snapshot_json'] ?? null),
|
||||
@@ -115,18 +117,22 @@ class ReportsController
|
||||
'service_provider' => $reportData['service_provider'],
|
||||
'institution_name' => $reportData['institution_name'],
|
||||
'publish_time' => $reportData['publish_time'],
|
||||
'zhongjian_report_no' => (string)($reportData['zhongjian_report_no'] ?? ''),
|
||||
'report_entry_admin_name' => (string)($reportData['report_entry_admin_name'] ?? ''),
|
||||
'report_entered_at' => (string)($reportData['report_entered_at'] ?? ''),
|
||||
],
|
||||
'result_info' => $payload['result_snapshot'],
|
||||
'product_info' => $payload['product_snapshot'],
|
||||
'appraisal_info' => $payload['appraisal_snapshot'],
|
||||
'valuation_info' => $payload['valuation_snapshot'],
|
||||
'evidence_attachments' => $evidenceAttachments,
|
||||
'zhongjian_report_files' => $zhongjianReportFiles,
|
||||
'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'] ?? '',
|
||||
'verify_status' => $isZhongjian ? '' : ($verify['verify_status'] ?? 'valid'),
|
||||
'verify_url' => $isZhongjian ? '' : ($verify['verify_url'] ?? ''),
|
||||
'verify_qrcode_url' => $isZhongjian ? '' : ($verify['verify_qrcode_url'] ?? ''),
|
||||
],
|
||||
'file_info' => [
|
||||
'pdf_url' => $pdfUrl,
|
||||
@@ -212,7 +218,9 @@ class ReportsController
|
||||
'verify_info' => sprintf(
|
||||
'%s / %s',
|
||||
$verify['report_no'] ?? ($report['report_no'] ?? '-'),
|
||||
($verify['verify_status'] ?? 'valid') === 'valid' ? '有效' : ($verify['verify_status'] ?? '-')
|
||||
($report['service_provider'] ?? '') === 'zhongjian'
|
||||
? '中检报告'
|
||||
: (($verify['verify_status'] ?? 'valid') === 'valid' ? '有效' : ($verify['verify_status'] ?? '-'))
|
||||
),
|
||||
'risk_notice_text' => ($content['risk_notice_text'] ?? '') !== '' ? $content['risk_notice_text'] : ($defaultRiskNotice !== '' ? $defaultRiskNotice : '-'),
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user