跟gpt合作完成一个oa审核推送
2025-07-17
问:
public static function getGroupProjectList($projectGroupUuid): array
{
// 第一步:获取该项目组下最新一条主推送记录(正评或初审)
$latestPushLog = self::find()
->where(['project_group_uuid' => $projectGroupUuid])
->andWhere(['is_deleted' => 0])
->orderBy(['id' => SORT_DESC])
->one();
if (!$latestPushLog) {
return [];
}
$pushLogId = $latestPushLog->id;
// 第二步:获取这条主推送记录下的所有底稿详情
$details = OaPushRetryLogDetail::find()
->where(['oa_push_retry_log_id' => $pushLogId])
->asArray()
->all();
if (empty($details)) {
return [];
}
// 第三步:查找该项目组下所有的推送记录(用于统计初审/正评推送情况)
$allPushLogs = self::find()
->where(['project_group_uuid' => $projectGroupUuid])
->andWhere(['is_deleted' => 0])
->orderBy(['id' => SORT_DESC])
->asArray()
->all();
// 整理推送记录(根据被评估项目id + 推送类型)
$pushMap = [];
// 有可能提交初审或者正评的时候,是在任意一条OA推过来的推送记录上,所以用oa_project_create_receive_id
foreach ($allPushLogs as $log) {
$key = $log['oa_project_create_receive_id'] . '_' . $log['push_type'];
$pushMap[$key][] = $log;
}
// 组装最终数据
$result = [];
foreach ($details as $detail) {
$projectId = $detail['oa_project_create_receive_id'];
$initialLogs = $pushMap[$projectId . '_初审推送'] ?? [];
$initialPush = $initialLogs[0] ?? null;
$finalLogs = $pushMap[$projectId . '_正评推送'] ?? [];
$finalPush = $finalLogs[0] ?? null;
$result[] = [
// 智评云底稿字段
'income_approach_related_draft_id' => $detail['income_approach_related_draft_id'],
'income_approach_related_draft_name' => $detail['income_approach_related_draft_name'],
'market_approach_related_draft_id' => $detail['market_approach_related_draft_id'],
'market_approach_related_draft_name' => $detail['market_approach_related_draft_name'],
'asset_based_approach_related_draft_id' => $detail['asset_based_approach_related_draft_id'],
'asset_based_approach_related_draft_name' => $detail['asset_based_approach_related_draft_name'],
'single_asset_draft_id' => $detail['single_asset_draft_id'],
'single_asset_draft_name' => $detail['single_asset_draft_name'],
'income_approach_draft_check_status' => $detail['income_approach_draft_check_status'],
'market_approach_draft_check_status' => $detail['market_approach_draft_check_status'],
'asset_based_approach_draft_check_status' => $detail['asset_based_approach_draft_check_status'],
'single_asset_draft_check_status' => $detail['single_asset_draft_check_status'],
'related_report_id' => $detail['related_report_id'],
'related_explanation_id' => $detail['related_explanation_id'],
// 推送信息
'initial_review_push_status' => $initialPush['status'] ?? null,
'initial_review_push_time' => $initialPush['create_time'] ?? null,
'initial_review_push_user' => $initialPush['create_by'] ?? null,
'final_review_push_status' => $finalPush['status'] ?? null,
'final_review_push_time' => $finalPush['create_time'] ?? null,
'final_review_push_user' => $finalPush['create_by'] ?? null,
// 总提交次数
'submission_count' => count($initialLogs) + count($finalLogs),
];
}
return $result;
}
这个方法请重写,返回字段不变。
但是需要根据project_group_uuid通过TJ_Projects中的WorkingGroupId(该字段还得写一个方法转换一下,因为他是自增id,而project_group_uuid是雪花id,也就是从Frame这个模型里通过Id查询到对应的Uuid,加上IsDeleted=0),查询到所有这个项目组里的项目。
还要通过 $allow_projects = $controller->hasMethod("filterProjectsList") ? $controller->filterProjectsList(false) : [];过滤出有权限的项目。通过$everything_where = array_keys($allow_projects);取到合乎要求的项目id。
income_approach_related_draft_id这个通过TJFileHistory这个model拿到其版本Id,需要通过ProjectId、EvaluationMethodType=1、IsDeprecated=0来获取,然后通过版本记录里的FileId,去TJFiles表的Uuid拿到Path或者ZipPath,这两个是文件路径,取到他的名字作为income_approach_related_draft_name。
market_approach_related_draft_id,market_approach_related_draft_name也一样,不过EvaluationMethodType=2。
asset_based_approach_related_draft_id,asset_based_approach_related_draft_name则是通过TJFileHistoryV2表获取,查询条件ProjectId、EvaluationMethodType=3、IsDeleted=0,这个拿到的文件是FileSignCompound,然后通过$project = TJProjectStatistics::project($projectId);
$relativeFile = HelperV2::getFilePathBySign($params['FileSignCompound'], $project);
可以拿到文件路径,进而取到文件名。
另外以上取版本最最新一条。
而single_asset_draft_id,single_asset_draft_name则是通过TJFileHistorySingleAsset获取,这个的逻辑:
通过TJFileHistorySingleAsset这个model拿到其版本Id,需要通过ProjectId、IsDeprecated=0来获取,然后通过版本记录里的FileId,去TJFiles表的Uuid拿到Path或者ZipPath,这两个是文件路径,取到他的名字作为single_asset_draft_name。
income_approach_draft_check_status、market_approach_draft_check_status、asset_based_approach_draft_check_status,则需要通过接口去获取,接口请求类似下面,请你独立成方法:
/**
* 获取振涛全量模型
* @param $modelId
* @return mixed
* @throws Exception
*/
public static function fetchFullModelData($modelId)
{
/** @var $client yii\httpclient\Client */
$client = Yii::$app->HttpClient;
$transport = 'yii\httpclient\StreamTransport';
$client->setTransport($transport);
$uri = Yii::$app->params['NewForcostModelServer'] . Yii::$app->params['NewForcostModelServerApi']['FetchFullModel'] . DIRECTORY_SEPARATOR . $modelId; // 振涛模型生成API
$data = SocketRequest::httpRequest([], TJProjectManage::ACTIONTYPE_CREATE_COSTAPPROACH, $uri, 'GET',
$transport, true, yii\httpclient\Client::FORMAT_URLENCODED);
return $data->data['data'];
}
获取到的结果是true或者false,可以直接填到这个判断的部分。
related_report_id这个则从ReportProjects取,条件是IsCurrent=1,ReportType=1,而related_explanation_id还是从这个表取,但ReportType=2。
而:
// 推送信息
'initial_review_push_status' => $initialPush['status'] ?? null,
'initial_review_push_time' => $initialPush['create_time'] ?? null,
'initial_review_push_user' => $initialPush['create_by'] ?? null,
'final_review_push_status' => $finalPush['status'] ?? null,
'final_review_push_time' => $finalPush['create_time'] ?? null,
'final_review_push_user' => $finalPush['create_by'] ?? null,
这些推送信息就要拿项目id去oa_push_retry_log,oa_push_retry_log_detail表去匹配,
initial_review_push_status,这是初审状态,状态是oa_push_retry_log这个表里的status,是否推送给oa成功,initial_review_push_time这个时间则是oa_push_retry_log的update_time,因为可能多次重试,取最新成功推送的,如果没成功,则留空。initial_review_push_user也取这个表的create_by,通过ProUser拿到RealName。下面的final_*是正评,逻辑类似,不过获取的是正评的数据。另外这个记录次数是当前这个项目底稿总共提交的次数。
答:
public static function getGroupProjectList($projectGroupUuid): array { // 1. 通过 Frame 表获取 WorkingGroupId $frame = Frame::find()->where(['Id' => $projectGroupUuid, 'IsDeleted' => 0])->one(); if (!$frame) return []; $workingGroupId = $frame->WorkingGroupId; // 2. 过滤出有权限的项目 $controller = Yii::$app->controller; $allowProjects = $controller->hasMethod("filterProjectsList") ? $controller->filterProjectsList(false) : []; $everythingWhere = array_keys($allowProjects); // 3. 获取该项目组下所有 TJProjects 中符合条件的项目 $projects = TJProjects::find() ->where(['WorkingGroupId' => $workingGroupId]) ->andWhere(['IN', 'Id', $everythingWhere]) ->andWhere(['IsDeleted' => 0]) ->asArray() ->all(); $result = []; foreach ($projects as $project) { $projectId = $project['Id']; // === 收益法底稿 === $incomeDraft = TJFileHistory::find()->where([ 'ProjectId' => $projectId, 'EvaluationMethodType' => 1, 'IsDeprecated' => 0 ])->orderBy(['Id' => SORT_DESC])->one(); $incomeFile = $incomeDraft ? TJFiles::findOne(['Uuid' => $incomeDraft->FileId]) : null; $incomeName = $incomeFile ? basename($incomeFile->Path ?: $incomeFile->ZipPath) : null; $incomeStatus = self::fetchDraftCheckStatus($incomeDraft->ModelId ?? null); // === 市场法底稿 === $marketDraft = TJFileHistory::find()->where([ 'ProjectId' => $projectId, 'EvaluationMethodType' => 2, 'IsDeprecated' => 0 ])->orderBy(['Id' => SORT_DESC])->one(); $marketFile = $marketDraft ? TJFiles::findOne(['Uuid' => $marketDraft->FileId]) : null; $marketName = $marketFile ? basename($marketFile->Path ?: $marketFile->ZipPath) : null; $marketStatus = self::fetchDraftCheckStatus($marketDraft->ModelId ?? null); // === 资产基础法底稿 === $assetDraft = TJFileHistoryV2::find()->where([ 'ProjectId' => $projectId, 'EvaluationMethodType' => 3, 'IsDeleted' => 0 ])->orderBy(['Id' => SORT_DESC])->one(); $assetName = null; $assetStatus = null; if ($assetDraft) { $projectObj = TJProjectStatistics::project($projectId); $path = HelperV2::getFilePathBySign($assetDraft->FileSignCompound, $projectObj); $assetName = $path ? basename($path) : null; $assetStatus = self::fetchDraftCheckStatus($assetDraft->ModelId ?? null); } // === 单项资产底稿 === $singleDraft = TJFileHistorySingleAsset::find()->where([ 'ProjectId' => $projectId, 'IsDeprecated' => 0 ])->orderBy(['Id' => SORT_DESC])->one(); $singleFile = $singleDraft ? TJFiles::findOne(['Uuid' => $singleDraft->FileId]) : null; $singleName = $singleFile ? basename($singleFile->Path ?: $singleFile->ZipPath) : null; // === 报告、说明文档 === $report = ReportProjects::find()->where([ 'ProjectId' => $projectId, 'IsCurrent' => 1, 'ReportType' => 1 ])->one(); $explanation = ReportProjects::find()->where([ 'ProjectId' => $projectId, 'IsCurrent' => 1, 'ReportType' => 2 ])->one(); // === 推送记录(初审) === $initialPush = OaPushRetryLog::find() ->where([ 'oa_project_create_receive_id' => $projectId, 'push_type' => '初审推送', 'is_deleted' => 0, 'status' => 1 ])->orderBy(['id' => SORT_DESC])->one(); $initialUser = $initialPush ? ProUser::find()->select('RealName')->where(['Id' => $initialPush->create_by])->scalar() : null; // === 推送记录(正评) === $finalPush = OaPushRetryLog::find() ->where([ 'oa_project_create_receive_id' => $projectId, 'push_type' => '正评推送', 'is_deleted' => 0, 'status' => 1 ])->orderBy(['id' => SORT_DESC])->one(); $finalUser = $finalPush ? ProUser::find()->select('RealName')->where(['Id' => $finalPush->create_by])->scalar() : null; // === 总推送次数 === $submissionCount = OaPushRetryLog::find() ->where(['oa_project_create_receive_id' => $projectId]) ->andWhere(['is_deleted' => 0]) ->count(); // === 返回结构 === $result[] = [ 'income_approach_related_draft_id' => $incomeDraft->Id ?? null, 'income_approach_related_draft_name' => $incomeName, 'market_approach_related_draft_id' => $marketDraft->Id ?? null, 'market_approach_related_draft_name' => $marketName, 'asset_based_approach_related_draft_id' => $assetDraft->Id ?? null, 'asset_based_approach_related_draft_name' => $assetName, 'single_asset_draft_id' => $singleDraft->Id ?? null, 'single_asset_draft_name' => $singleName, 'income_approach_draft_check_status' => $incomeStatus, 'market_approach_draft_check_status' => $marketStatus, 'asset_based_approach_draft_check_status' => $assetStatus, 'single_asset_draft_check_status' => null, // 无对应接口 'related_report_id' => $report->Id ?? null, 'related_explanation_id' => $explanation->Id ?? null, 'initial_review_push_status' => $initialPush->status ?? null, 'initial_review_push_time' => $initialPush->update_time ?? null, 'initial_review_push_user' => $initialUser, 'final_review_push_status' => $finalPush->status ?? null, 'final_review_push_time' => $finalPush->update_time ?? null, 'final_review_push_user' => $finalUser, 'submission_count' => (int) $submissionCount, ]; } return $result; }
辅助方法:
private static function fetchDraftCheckStatus($modelId) { if (!$modelId) return null; try { $client = Yii::$app->HttpClient; $transport = 'yii\\httpclient\\StreamTransport'; $client->setTransport($transport); $uri = Yii::$app->params['NewForcostModelServer'] . Yii::$app->params['NewForcostModelServerApi']['FetchFullModel'] . '/' . $modelId; $data = SocketRequest::httpRequest( [], TJProjectManage::ACTIONTYPE_CREATE_COSTAPPROACH, $uri, 'GET', $transport, true, yii\\httpclient\\Client::FORMAT_URLENCODED ); return $data->data['data'] ?? null; } catch (Exception $e) { return null; } }
问:
OaPushRetryLogDetail这个表中才存有company_project_id,主表的oa_project_create_receive_id是oa给我们推送的id,在此处不能使用。请考虑这个重写以上方法。
答:
public static function getGroupProjectList($projectGroupUuid): array { $frame = Frame::find()->where(['Id' => $projectGroupUuid, 'IsDeleted' => 0])->one(); if (!$frame) return []; $workingGroupId = $frame->WorkingGroupId; $controller = Yii::$app->controller; $allowProjects = $controller->hasMethod("filterProjectsList") ? $controller->filterProjectsList(false) : []; $everythingWhere = array_keys($allowProjects); $projects = TJProjects::find() ->where(['WorkingGroupId' => $workingGroupId]) ->andWhere(['IN', 'Id', $everythingWhere]) ->andWhere(['IsDeleted' => 0]) ->asArray() ->all(); $result = []; foreach ($projects as $project) { $projectId = $project['Id']; // 收益法底稿 $incomeDraft = TJFileHistory::find() ->where(['ProjectId' => $projectId, 'EvaluationMethodType' => 1, 'IsDeprecated' => 0]) ->orderBy(['Id' => SORT_DESC]) ->one(); $incomeFile = $incomeDraft ? TJFiles::findOne(['Uuid' => $incomeDraft->FileId]) : null; $incomeName = $incomeFile ? basename($incomeFile->Path ?: $incomeFile->ZipPath) : null; $incomeStatus = self::fetchDraftCheckStatus($incomeDraft->ModelId ?? null); // 市场法底稿 $marketDraft = TJFileHistory::find() ->where(['ProjectId' => $projectId, 'EvaluationMethodType' => 2, 'IsDeprecated' => 0]) ->orderBy(['Id' => SORT_DESC]) ->one(); $marketFile = $marketDraft ? TJFiles::findOne(['Uuid' => $marketDraft->FileId]) : null; $marketName = $marketFile ? basename($marketFile->Path ?: $marketFile->ZipPath) : null; $marketStatus = self::fetchDraftCheckStatus($marketDraft->ModelId ?? null); // 资产基础法底稿 $assetDraft = TJFileHistoryV2::find() ->where(['ProjectId' => $projectId, 'EvaluationMethodType' => 3, 'IsDeleted' => 0]) ->orderBy(['Id' => SORT_DESC]) ->one(); $assetName = null; $assetStatus = null; if ($assetDraft) { $projectInfo = TJProjectStatistics::project($projectId); $path = HelperV2::getFilePathBySign($assetDraft->FileSignCompound, $projectInfo); $assetName = $path ? basename($path) : null; $assetStatus = self::fetchDraftCheckStatus($assetDraft->ModelId ?? null); } // 单项资产底稿 $singleDraft = TJFileHistorySingleAsset::find() ->where(['ProjectId' => $projectId, 'IsDeprecated' => 0]) ->orderBy(['Id' => SORT_DESC]) ->one(); $singleFile = $singleDraft ? TJFiles::findOne(['Uuid' => $singleDraft->FileId]) : null; $singleName = $singleFile ? basename($singleFile->Path ?: $singleFile->ZipPath) : null; // 报告和说明 $report = ReportProjects::find() ->where(['ProjectId' => $projectId, 'IsCurrent' => 1, 'ReportType' => 1]) ->one(); $explanation = ReportProjects::find() ->where(['ProjectId' => $projectId, 'IsCurrent' => 1, 'ReportType' => 2]) ->one(); // 推送记录(通过 detail 表找 projectId) $details = OaPushRetryLogDetail::find() ->where(['company_project_id' => $projectId]) ->all(); $initialPush = null; $finalPush = null; $initialUser = null; $finalUser = null; $submissionCount = 0; foreach ($details as $detail) { $log = OaPushRetryLog::findOne(['id' => $detail->oa_push_retry_log_id, 'is_deleted' => 0]); if (!$log) continue; $submissionCount++; if ($log->push_type === '初审推送' && $log->status == 1 && !$initialPush) { $initialPush = $log; $initialUser = ProUser::find()->select('RealName')->where(['Id' => $log->create_by])->scalar(); } if ($log->push_type === '正评推送' && $log->status == 1 && !$finalPush) { $finalPush = $log; $finalUser = ProUser::find()->select('RealName')->where(['Id' => $log->create_by])->scalar(); } } $result[] = [ 'income_approach_related_draft_id' => $incomeDraft->Id ?? null, 'income_approach_related_draft_name' => $incomeName, 'market_approach_related_draft_id' => $marketDraft->Id ?? null, 'market_approach_related_draft_name' => $marketName, 'asset_based_approach_related_draft_id' => $assetDraft->Id ?? null, 'asset_based_approach_related_draft_name' => $assetName, 'single_asset_draft_id' => $singleDraft->Id ?? null, 'single_asset_draft_name' => $singleName, 'income_approach_draft_check_status' => $incomeStatus, 'market_approach_draft_check_status' => $marketStatus, 'asset_based_approach_draft_check_status' => $assetStatus, 'single_asset_draft_check_status' => null, 'related_report_id' => $report->Id ?? null, 'related_explanation_id' => $explanation->Id ?? null, 'initial_review_push_status' => $initialPush->status ?? null, 'initial_review_push_time' => $initialPush->update_time ?? null, 'initial_review_push_user' => $initialUser, 'final_review_push_status' => $finalPush->status ?? null, 'final_review_push_time' => $finalPush->update_time ?? null, 'final_review_push_user' => $finalUser, 'submission_count' => $submissionCount ]; } return $result; }
辅助方法:
private static function fetchDraftCheckStatus($modelId) { if (!$modelId) return null; try { $client = Yii::$app->HttpClient; $transport = 'yii\\httpclient\\StreamTransport'; $client->setTransport($transport); $uri = Yii::$app->params['NewForcostModelServer'] . Yii::$app->params['NewForcostModelServerApi']['FetchFullModel'] . '/' . $modelId; $data = SocketRequest::httpRequest( [], TJProjectManage::ACTIONTYPE_CREATE_COSTAPPROACH, $uri, 'GET', $transport, true, yii\\httpclient\\Client::FORMAT_URLENCODED ); return $data->data['data'] ?? null; } catch (Exception $e) { return null; } }
如夜话,至此。
发表评论: