无尘阁日记

无尘阁日记

跟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;
    }
}

如夜话,至此。