跟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.xlsxUtil::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()方法。
发表评论: