跟AI协作封装上传底稿
2025-04-22
问:
在上传底稿的这个方法前面加一个判断是否单项资产项目的逻辑。
public function actionUpload()
{
// file_put_contents(Yii::$app->basePath . "/uploadProject.json", json_encode(array_merge(Yii::$app->request->requestParams(), Yii::$app->request->post()), JSON_UNESCAPED_UNICODE));
$params = array_merge(Yii::$app->request->requestParams(), Yii::$app->request->post());
$result = $this->checkParams($params);
if ($result !== true) return $result;
如果是,则走新分支,新分支调用一个写在SingleAssetHelper这个类里的静态独立方法,要求实现的逻辑是:
1. 上传来的文件存到两个地方,一个是更新当前项目底稿路径,一个是生成版本。
当前底稿路径为:TJProjectStatistics这个模型里的ManuscriptFile那里,覆盖就行。
版本则是新生成一条版本记录,目录路径为:
$curDay = date('Ymd', time());
$createAt = time();
$ext = pathinfo($data['OriginalMbFile'], PATHINFO_EXTENSION);
$versionPath = Util::addTenantIdToDir(Yii::$app->params['user.headOfficeUid'], DIRECTORY_SEPARATOR
. Yii::$app->params['globalVariables']['versionDir'], $curDay . DIRECTORY_SEPARATOR . 'SingleAsset' .
DIRECTORY_SEPARATOR);
Yii::error($versionPath, '项目版本文件');
if (!file_exists(Yii::$app->basePath . $versionPath)) {
mkdir(Yii::$app->basePath . $versionPath, 0777, true);
}
这段代码是生成版本文件路径的。
另外呢生成版本的调用代码如下:
TJProjectStatistics::updateAll(['ManuscriptFile' => $fileResolveData['Data']['CurrentPath'], 'UpdatedAt' => time()], ['Id' => $data['Id']]);
$filePath = Yii::$app->basePath . $fileResolveData['Data']['VersionPath'];
$sizeInBytes = filesize($filePath); // 返回文件大小(字节);
$fileName = pathinfo($fileResolveData['Data']['VersionPath'], PATHINFO_FILENAME);
$file = [
'FilePath' => $fileResolveData['Data']['VersionPath'], // 文件在服务器上的存储路径或唯一标识
'FileName' => $fileName, // 原始文件名
'Size' => $sizeInBytes, // 文件大小(字节),可选
];
$versionType = TJFileHistory::VERSION_TYPE_AUTOUPLOAD + TJFileHistory::VERSION_TYPE_DENY;
$historyParams = [
'UserId' => $data['UserId'], // 当前登录用户的ID
'ProjectId' => $data['Id'], // 所属项目ID
'Remark' => '首次上传审计底稿', // 系统备注(记录上传原因)
'VersionType' => $versionType, // 版本类型:例如 2 = 模型同步前版本
'UserRemark' => '项目初稿', // 用户备注(允许后续修改)
];
// 调用保存方法
$result = TJFileHistorySingleAsset::saveFileAndHistory($file, $historyParams);
if ($result['success']) {
Yii::info("版本生成成功,FileId: {$result['fileId']},HistoryId: {$result['historyId']}");
} else {
Yii::error("版本生成失败:{$result['message']}");
}
你帮我把这个独立方法封装一下,有不明白的问我。
答:
太好了,你已经提供了所有关键细节。我来帮你做以下三件事:
✅ 1. 修改 actionUpload
开头,判断是否是单项资产项目
public function actionUpload() { $params = array_merge(Yii::$app->request->requestParams(), Yii::$app->request->post()); $result = $this->checkParams($params); if ($result !== true) return $result; // 新增逻辑:判断是否单项资产项目 $project = TJProjectStatistics::findOne($params['ProjectId']); if ($project && (int)$project->ProjectType === TJProjectStatistics::PROJECT_TYPE_SINGLE_ASSET) { return SingleAssetHelper::handleUpload($project, $params); } // 继续原本普通项目逻辑... }
✅ 2. 新建 SingleAssetHelper::handleUpload()
静态方法
class SingleAssetHelper { /** * 处理单项资产项目的底稿上传逻辑 */ public static function handleUpload($project, $params) { try { $curDay = date('Ymd'); $createAt = time(); $ext = pathinfo($params['OriginalMbFile'], PATHINFO_EXTENSION); // 构建版本路径 $versionPath = Util::addTenantIdToDir( Yii::$app->params['user.headOfficeUid'], DIRECTORY_SEPARATOR . Yii::$app->params['globalVariables']['versionDir'], $curDay . DIRECTORY_SEPARATOR . 'SingleAsset' . DIRECTORY_SEPARATOR ); Yii::error($versionPath, '项目版本文件'); $fullVersionDir = Yii::$app->basePath . $versionPath; if (!file_exists($fullVersionDir)) { mkdir($fullVersionDir, 0777, true); } // 构建文件实际路径 $fileName = uniqid('single_', true) . '.' . $ext; $targetPath = $fullVersionDir . $fileName; $versionRelPath = $versionPath . $fileName; // 保存上传文件到目标路径 $uploadFilePath = Yii::$app->basePath . $params['OriginalMbFile']; if (!file_exists($uploadFilePath)) { return ['IsSuccess' => 0, 'ErrMsg' => '上传文件不存在']; } if (!copy($uploadFilePath, $targetPath)) { return ['IsSuccess' => 0, 'ErrMsg' => '文件保存失败']; } // 更新项目当前底稿路径 TJProjectStatistics::updateAll([ 'ManuscriptFile' => $params['OriginalMbFile'], 'UpdatedAt' => time() ], ['Id' => $project->Id]); // 构造版本文件数据结构 $fileSize = filesize($targetPath); $fileInfo = [ 'FilePath' => $versionRelPath, 'FileName' => pathinfo($fileName, PATHINFO_FILENAME), 'Size' => $fileSize ]; $versionType = TJFileHistory::VERSION_TYPE_AUTOUPLOAD + TJFileHistory::VERSION_TYPE_DENY; $historyParams = [ 'UserId' => $params['UserId'], 'ProjectId' => $project->Id, 'Remark' => '首次上传审计底稿', 'VersionType' => $versionType, 'UserRemark' => '项目初稿', ]; // 调用生成版本方法 $result = TJFileHistorySingleAsset::saveFileAndHistory($fileInfo, $historyParams); if ($result['success']) { Yii::info("版本生成成功,FileId: {$result['fileId']},HistoryId: {$result['historyId']}"); return ['IsSuccess' => 1, 'ErrMsg' => '上传成功']; } else { Yii::error("版本生成失败:" . $result['message']); return ['IsSuccess' => 0, 'ErrMsg' => '版本生成失败:' . $result['message']]; } } catch (\Exception $e) { Yii::error("handleUpload异常:" . $e->getMessage()); return ['IsSuccess' => 0, 'ErrMsg' => '系统异常:' . $e->getMessage()]; } } }
✅ 3. 参数说明与依赖提醒
这个方法需要:
$params['OriginalMbFile']
:上传文件的路径,相对路径,例如/uploads/tmp/somefile.xlsx
Util::addTenantIdToDir()
、Yii::$app->params['user.headOfficeUid']
:你已有函数和配置TJFileHistorySingleAsset::saveFileAndHistory()
:昨天实现过,压缩加密并入库文件和历史表
问:
// 保存上传文件到目标路径
$uploadFilePath = Yii::$app->basePath . $params['OriginalMbFile'];
if (!file_exists($uploadFilePath)) {
return ['IsSuccess' => 0, 'ErrMsg' => '上传文件不存在'];
}
你这保存是不对的。我的意思是:
用户通过file上传来的文件流,需要保存到$project['ManuscriptFile']这个路径和$targetPath底下。
上传的文件要落盘到这两个位置。你需要实现这个落盘的过程,用yii2的文件保存方法、检测等。
答:
非常清楚了!你想要的是:
用户通过 file 表单上传的底稿文件;
保存到两个路径:
TJProjectStatistics.ManuscriptFile
记录的路径(当前底稿);$targetPath
(新生成的版本文件路径);使用 Yii2 的文件上传处理方法(不能用
copy()
,必须用UploadedFile
的方式落盘);然后更新数据库、生成版本。
那我来重构这部分核心逻辑,确保它能正确落盘到两个位置,并符合你的实际使用方式。
✅ 重构后的落盘保存逻辑(支持双路径保存)
请替换你之前 handleUpload()
方法中处理文件保存的部分:
use yii\web\UploadedFile; public static function handleUpload($project, $params) { try { $curDay = date('Ymd'); $createAt = time(); $uploadFile = UploadedFile::getInstanceByName('file'); // 获取上传的文件对象 if (!$uploadFile) { return ['IsSuccess' => 0, 'ErrMsg' => '未收到上传文件']; } // 判断原始扩展名 $ext = $uploadFile->getExtension(); $fileName = uniqid('single_', true) . '.' . $ext; // 生成版本文件路径 $versionPath = Util::addTenantIdToDir( Yii::$app->params['user.headOfficeUid'], DIRECTORY_SEPARATOR . Yii::$app->params['globalVariables']['versionDir'], $curDay . DIRECTORY_SEPARATOR . 'SingleAsset' . DIRECTORY_SEPARATOR ); $fullVersionDir = Yii::$app->basePath . $versionPath; if (!file_exists($fullVersionDir)) { mkdir($fullVersionDir, 0777, true); } $targetPath = $fullVersionDir . $fileName; $versionRelPath = $versionPath . $fileName; // 生成当前底稿路径(覆盖项目底稿) $currentPath = '/uploads/single_asset/' . $project->Id . '.' . $ext; $absCurrentPath = Yii::$app->basePath . $currentPath; $currentDir = dirname($absCurrentPath); if (!file_exists($currentDir)) { mkdir($currentDir, 0777, true); } // 保存到两个路径 if (!$uploadFile->saveAs($absCurrentPath)) { return ['IsSuccess' => 0, 'ErrMsg' => '保存当前底稿失败']; } if (!$uploadFile->saveAs($targetPath)) { return ['IsSuccess' => 0, 'ErrMsg' => '保存版本底稿失败']; } // 更新当前底稿路径 TJProjectStatistics::updateAll([ 'ManuscriptFile' => $currentPath, 'UpdatedAt' => time() ], ['Id' => $project->Id]); // 构造版本入库文件结构 $fileSize = filesize($targetPath); $fileInfo = [ 'FilePath' => $versionRelPath, 'FileName' => pathinfo($fileName, PATHINFO_FILENAME), 'Size' => $fileSize ]; $versionType = TJFileHistory::VERSION_TYPE_AUTOUPLOAD + TJFileHistory::VERSION_TYPE_DENY; $historyParams = [ 'UserId' => $params['UserId'], 'ProjectId' => $project->Id, 'Remark' => '首次上传审计底稿', 'VersionType' => $versionType, 'UserRemark' => '项目初稿', ]; $result = TJFileHistorySingleAsset::saveFileAndHistory($fileInfo, $historyParams); if ($result['success']) { Yii::info("版本生成成功,FileId: {$result['fileId']},HistoryId: {$result['historyId']}"); return ['IsSuccess' => 1, 'ErrMsg' => '上传成功']; } else { Yii::error("版本生成失败:" . $result['message']); return ['IsSuccess' => 0, 'ErrMsg' => '版本生成失败:' . $result['message']]; } } catch (\Exception $e) { Yii::error("handleUpload异常:" . $e->getMessage()); return ['IsSuccess' => 0, 'ErrMsg' => '系统异常:' . $e->getMessage()]; } }
✅ 说明与注意事项
文件字段名必须是
file
,对应<input type="file" name="file">
;底稿路径存一份在
/uploads/single_asset/{项目ID}.{ext}
,用作当前版本;另一份是版本目录文件,生成版本记录;
入库过程依赖昨天写好的
TJFileHistorySingleAsset::saveFileAndHistory()
方法。
发表评论: