Files
Leantime/app/Domain/Bom/Controllers/Api.php

284 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Leantime\Domain\Bom\Controllers;
use Illuminate\Http\Request;
use Leantime\Domain\Bom\Services\Bom as BomService;
use Leantime\Domain\Bom\Services\MasterRef as MasterRefService;
use Symfony\Component\HttpFoundation\Response;
/**
* BOM JSON API原生 Laravel 控制器)。每个动作都在 Service 层按 BOM 所属项目自鉴权。
*/
class Api
{
public function __construct(
private BomService $bomService,
private MasterRefService $masterRefService,
) {}
public function detail(int $id): Response
{
$detail = $this->bomService->getBomDetail($id);
return $detail === false
? response()->json(['status' => 'error', 'message' => 'BOM not found'], 404)
: response()->json(['status' => 'success', 'data' => $detail]);
}
public function store(Request $request): Response
{
$projectId = (int) $request->input('projectId', session('currentProject'));
$id = $this->bomService->createBom($request->all() + ['projectId' => $projectId]);
return $id > 0
? response()->json(['status' => 'success', 'id' => $id])
: response()->json(['status' => 'error', 'message' => 'Create failed'], 500);
}
public function update(int $id, Request $request): Response
{
return $this->bomService->updateBom($id, $request->all())
? response()->json(['status' => 'success'])
: response()->json(['status' => 'error', 'message' => 'Update failed'], 500);
}
public function destroy(int $id): Response
{
return $this->bomService->deleteBom($id)
? response()->json(['status' => 'success'])
: response()->json(['status' => 'error', 'message' => 'Delete failed'], 500);
}
public function saveItem(int $id, Request $request): Response
{
$itemId = $request->input('itemId');
$itemId = $itemId !== null && $itemId !== '' ? (int) $itemId : null;
$newId = $this->bomService->saveItem($id, $request->all(), $itemId);
return $newId > 0
? response()->json(['status' => 'success', 'itemId' => $newId])
: response()->json(['status' => 'error', 'message' => 'Save item failed'], 500);
}
public function deleteItem(int $itemId): Response
{
return $this->bomService->deleteItem($itemId)
? response()->json(['status' => 'success'])
: response()->json(['status' => 'error', 'message' => 'Delete item failed'], 500);
}
public function uploadAttachment(int $id, Request $request): Response
{
if (! $request->hasFile('file')) {
return response()->json(['status' => 'error', 'message' => 'Missing file'], 400);
}
$result = $this->bomService->uploadAttachment($id, $_FILES);
if (is_string($result)) {
return response()->json(['status' => 'error', 'message' => $result], 500);
}
return response()->json(['status' => 'success', 'data' => $result]);
}
public function addColumn(int $id, Request $request): Response
{
$key = (string) $request->input('key', '');
$label = (string) $request->input('label', $key);
$columnId = $this->bomService->addColumn($id, $key, $label);
return $columnId > 0
? response()->json(['status' => 'success', 'columnId' => $columnId])
: response()->json(['status' => 'error', 'message' => 'Add column failed'], 500);
}
public function deleteColumn(int $columnId): Response
{
return $this->bomService->deleteColumn($columnId)
? response()->json(['status' => 'success'])
: response()->json(['status' => 'error', 'message' => 'Delete column failed'], 500);
}
public function setHiddenColumns(int $id, Request $request): Response
{
$keys = $request->input('keys', []);
$keys = is_array($keys) ? $keys : [];
return $this->bomService->setHiddenColumns($id, $keys)
? response()->json(['status' => 'success'])
: response()->json(['status' => 'error', 'message' => 'Save column visibility failed'], 500);
}
public function export(int $id, Request $request): Response
{
$format = strtolower((string) $request->input('format', 'xlsx'));
$result = $this->bomService->export($id, $format);
if ($result === false) {
return response()->json(['status' => 'error', 'message' => 'Export failed'], 500);
}
$content = file_get_contents($result['path']);
@unlink($result['path']);
return response($content, 200, [
'Content-Type' => $result['contentType'],
'Content-Disposition' => 'attachment; filename="'.$result['filename'].'"',
]);
}
public function exportTemplate(int $id): Response
{
$result = $this->bomService->exportTemplate($id);
if ($result === false) {
return response()->json(['status' => 'error', 'message' => 'Export failed'], 500);
}
$content = file_get_contents($result['path']);
@unlink($result['path']);
return response($content, 200, [
'Content-Type' => $result['contentType'],
'Content-Disposition' => 'attachment; filename="'.$result['filename'].'"',
]);
}
public function addSource(int $id, Request $request): Response
{
$sourceId = $this->bomService->addSource($id, $request->all());
return $sourceId > 0
? response()->json(['status' => 'success', 'sourceId' => $sourceId])
: response()->json(['status' => 'error', 'message' => 'Add source failed'], 500);
}
public function deleteSource(int $sourceId): Response
{
return $this->bomService->deleteSource($sourceId)
? response()->json(['status' => 'success'])
: response()->json(['status' => 'error', 'message' => 'Delete source failed'], 500);
}
public function parseTeable(Request $request): Response
{
$text = (string) $request->input('text', '');
$result = $this->bomService->parseTeableText($text);
return $result['success']
? response()->json(['status' => 'success', 'data' => $result])
: response()->json(['status' => 'error', 'message' => $result['message'] ?? '解析失败'], 400);
}
public function importTeablePaste(int $id, Request $request): Response
{
$text = (string) $request->input('text', '');
$result = $this->bomService->importFromTeableText($id, $text);
return $result['success']
? response()->json(['status' => 'success', 'imported' => $result['imported'] ?? 0, 'errors' => $result['errors'] ?? [], 'source' => $result['source'] ?? null])
: response()->json(['status' => 'error', 'message' => $result['message'] ?? '导入失败'], 500);
}
public function importTeable(int $id): Response
{
$result = $this->bomService->importFromTeable($id);
return $result['success']
? response()->json(['status' => 'success', 'imported' => $result['imported'] ?? 0, 'errors' => $result['errors'] ?? []])
: response()->json(['status' => 'error', 'message' => $result['message'] ?? 'Import failed'], 500);
}
public function importExcel(int $id, Request $request): Response
{
if (! $request->hasFile('file')) {
return response()->json(['status' => 'error', 'message' => 'Missing file'], 400);
}
$file = $request->file('file');
$ext = strtolower($file->getClientOriginalExtension() ?: 'xlsx');
// tempnam 会创建一个无扩展名的空文件;我们拼接扩展名得到目标路径,
// 目标文件本身不存在,直接写入内容即可(避免 move 到已存在路径的兼容问题)。
$tmp = tempnam(sys_get_temp_dir(), 'bom.');
$target = $tmp.'.'.$ext;
try {
file_put_contents($target, $file->getContent());
$result = $this->bomService->importFromExcel($id, $target);
} catch (\Throwable $e) {
@unlink($tmp);
@unlink($target);
return response()->json(['status' => 'error', 'message' => $e->getMessage()], 500);
}
// 清理临时文件tempnam 的空文件 + 带扩展名的数据文件)
@unlink($tmp);
@unlink($target);
return $result['success']
? response()->json(['status' => 'success', 'imported' => $result['imported'] ?? 0])
: response()->json(['status' => 'error', 'message' => $result['message'] ?? 'Import failed'], 500);
}
// ---- 全局主数据:项目引用层(单向,不写回全局) ----
public function linkMaster(Request $request): Response
{
$projectId = (int) $request->input('projectId', session('currentProject'));
$masterId = (int) $request->input('masterId', 0);
$refId = $this->masterRefService->link($projectId, $masterId);
return $refId > 0
? response()->json(['status' => 'success', 'refId' => $refId])
: response()->json(['status' => 'error', 'message' => 'Link failed'], 500);
}
public function unlinkMaster(int $refId): Response
{
return $this->masterRefService->unlink($refId)
? response()->json(['status' => 'success'])
: response()->json(['status' => 'error', 'message' => 'Unlink failed'], 500);
}
public function refDetail(int $refId): Response
{
$detail = $this->masterRefService->getRefDetail($refId);
return $detail === false
? response()->json(['status' => 'error', 'message' => 'Ref not found'], 404)
: response()->json(['status' => 'success', 'data' => $detail]);
}
public function addRefColumn(int $refId, Request $request): Response
{
$key = (string) $request->input('key', '');
$label = (string) $request->input('label', $key);
$columnId = $this->masterRefService->addColumn($refId, $key, $label);
return $columnId > 0
? response()->json(['status' => 'success', 'columnId' => $columnId])
: response()->json(['status' => 'error', 'message' => 'Add column failed'], 500);
}
public function deleteRefColumn(int $columnId): Response
{
return $this->masterRefService->deleteColumn($columnId)
? response()->json(['status' => 'success'])
: response()->json(['status' => 'error', 'message' => 'Delete column failed'], 500);
}
public function saveRefValue(int $refId, Request $request): Response
{
$columnId = (int) $request->input('columnId', 0);
$itemId = (int) $request->input('itemId', 0);
$value = (string) $request->input('value', '');
return $this->masterRefService->saveValue($refId, $columnId, $itemId, $value)
? response()->json(['status' => 'success'])
: response()->json(['status' => 'error', 'message' => 'Save value failed'], 500);
}
}