]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
feat(ERP-292): web-контроллер и views авторазметки
authorfomichev <vladimir.fomichev@erp-flowers.ru>
Fri, 17 Apr 2026 14:04:10 +0000 (17:04 +0300)
committerfomichev <vladimir.fomichev@erp-flowers.ru>
Fri, 17 Apr 2026 14:04:10 +0000 (17:04 +0300)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
erp24/controllers/AutoMarkController.php [new file with mode: 0644]
erp24/views/auto-mark/index.php [new file with mode: 0644]
erp24/views/auto-mark/review.php [new file with mode: 0644]

diff --git a/erp24/controllers/AutoMarkController.php b/erp24/controllers/AutoMarkController.php
new file mode 100644 (file)
index 0000000..c5d6271
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+
+declare(strict_types=1);
+
+namespace app\controllers;
+
+use Yii;
+use yii\web\Controller;
+use yii\web\NotFoundHttpException;
+use yii\data\ActiveDataProvider;
+use yii_app\records\Products1cAutomarkPrediction;
+use yii_app\services\AutoMarkService;
+
+class AutoMarkController extends Controller
+{
+    public function actionIndex(): string
+    {
+        $query = Products1cAutomarkPrediction::find()
+            ->with('product')
+            ->orderBy(['confidence' => SORT_DESC, 'created_at' => SORT_DESC]);
+
+        $status = Yii::$app->request->get('status');
+        if ($status !== null) {
+            $query->andWhere(['status' => (int) $status]);
+        } else {
+            $query->andWhere(['status' => Products1cAutomarkPrediction::STATUS_PENDING]);
+        }
+
+        $dataProvider = new ActiveDataProvider([
+            'query'      => $query,
+            'pagination' => ['pageSize' => 50],
+        ]);
+
+        return $this->render('index', ['dataProvider' => $dataProvider]);
+    }
+
+    public function actionReview(int $id): string
+    {
+        $prediction = $this->findPrediction($id);
+
+        if (Yii::$app->request->isPost) {
+            $action = Yii::$app->request->post('action');
+            $service = new AutoMarkService();
+
+            if ($action === 'approve') {
+                $prediction->status      = Products1cAutomarkPrediction::STATUS_APPROVED;
+                $prediction->approved_by = Yii::$app->user->id;
+                $prediction->updated_at  = date('Y-m-d H:i:s');
+                $prediction->save();
+                $service->applyApprovedPrediction($prediction->id);
+                Yii::$app->session->setFlash('success', 'Разметка применена.');
+            } elseif ($action === 'reject') {
+                $prediction->status     = Products1cAutomarkPrediction::STATUS_REJECTED;
+                $prediction->updated_at = date('Y-m-d H:i:s');
+                $prediction->save();
+                Yii::$app->session->setFlash('info', 'Предсказание отклонено.');
+            }
+
+            return $this->redirect(['index']);
+        }
+
+        return $this->render('review', ['prediction' => $prediction]);
+    }
+
+    private function findPrediction(int $id): Products1cAutomarkPrediction
+    {
+        $model = Products1cAutomarkPrediction::find()->with('product')->where(['id' => $id])->one();
+        if ($model === null) {
+            throw new NotFoundHttpException("Предсказание #{$id} не найдено.");
+        }
+        return $model;
+    }
+}
diff --git a/erp24/views/auto-mark/index.php b/erp24/views/auto-mark/index.php
new file mode 100644 (file)
index 0000000..1bf8a9d
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/** @var \yii\data\ActiveDataProvider $dataProvider */
+use yii\grid\GridView;
+use yii\helpers\Html;
+use yii_app\records\Products1cAutomarkPrediction;
+
+$this->title = 'Авторазметка товаров';
+?>
+<div class="container-fluid">
+    <h2><?= Html::encode($this->title) ?></h2>
+
+    <div class="mb-3">
+        <?= Html::a('Pending', ['index', 'status' => Products1cAutomarkPrediction::STATUS_PENDING], ['class' => 'btn btn-warning']) ?>
+        <?= Html::a('Одобренные', ['index', 'status' => Products1cAutomarkPrediction::STATUS_APPROVED], ['class' => 'btn btn-success']) ?>
+        <?= Html::a('Отклонённые', ['index', 'status' => Products1cAutomarkPrediction::STATUS_REJECTED], ['class' => 'btn btn-secondary']) ?>
+    </div>
+
+    <?= GridView::widget([
+        'dataProvider' => $dataProvider,
+        'columns' => [
+            'id',
+            [
+                'label' => 'Товар',
+                'value' => fn($m) => $m->product?->name ?? $m->product_id,
+            ],
+            'category',
+            'species',
+            'sort',
+            'color',
+            'size',
+            [
+                'label' => 'Confidence',
+                'value' => fn($m) => number_format($m->confidence * 100, 1) . '%',
+            ],
+            'method',
+            [
+                'label' => 'Действия',
+                'format' => 'raw',
+                'value' => fn($m) => Html::a('Проверить', ['review', 'id' => $m->id], ['class' => 'btn btn-sm btn-primary']),
+            ],
+        ],
+    ]) ?>
+</div>
diff --git a/erp24/views/auto-mark/review.php b/erp24/views/auto-mark/review.php
new file mode 100644 (file)
index 0000000..8e3a27c
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+/** @var \yii_app\records\Products1cAutomarkPrediction $prediction */
+use yii\helpers\Html;
+use yii_app\records\Products1cAutomarkPrediction;
+
+$this->title = 'Проверка разметки #' . $prediction->id;
+?>
+<div class="container">
+    <h2><?= Html::encode($this->title) ?></h2>
+
+    <div class="card mb-4">
+        <div class="card-header"><strong>Товар из 1С</strong></div>
+        <div class="card-body">
+            <p><strong>GUID:</strong> <?= Html::encode($prediction->product_id) ?></p>
+            <p><strong>Название:</strong> <?= Html::encode($prediction->product?->name ?? '—') ?></p>
+            <p><strong>Код:</strong> <?= Html::encode($prediction->product?->code ?? '—') ?></p>
+        </div>
+    </div>
+
+    <div class="card mb-4">
+        <div class="card-header">
+            <strong>Предсказание</strong>
+            — метод: <code><?= Html::encode($prediction->method) ?></code>,
+            уверенность: <strong><?= number_format($prediction->confidence * 100, 1) ?>%</strong>
+        </div>
+        <div class="card-body">
+            <table class="table table-bordered">
+                <tr><th>Категория</th><td><?= Html::encode($prediction->category ?? '—') ?></td></tr>
+                <tr><th>Подкатегория</th><td><?= Html::encode($prediction->subcategory ?? '—') ?></td></tr>
+                <tr><th>Вид</th><td><?= Html::encode($prediction->species ?? '—') ?></td></tr>
+                <tr><th>Сорт</th><td><?= Html::encode($prediction->sort ?? '—') ?></td></tr>
+                <tr><th>Тип</th><td><?= Html::encode($prediction->type ?? '—') ?></td></tr>
+                <tr><th>Размер</th><td><?= $prediction->size ?? '—' ?></td></tr>
+                <tr><th>Цвет</th><td><?= Html::encode($prediction->color ?? '—') ?></td></tr>
+            </table>
+        </div>
+    </div>
+
+    <?php if ($prediction->isPending()): ?>
+    <div class="d-flex gap-2">
+        <?= Html::beginForm(['review', 'id' => $prediction->id], 'post') ?>
+            <?= Html::hiddenInput('action', 'approve') ?>
+            <?= Html::submitButton('Применить разметку', ['class' => 'btn btn-success']) ?>
+        <?= Html::endForm() ?>
+
+        <?= Html::beginForm(['review', 'id' => $prediction->id], 'post') ?>
+            <?= Html::hiddenInput('action', 'reject') ?>
+            <?= Html::submitButton('Отклонить', ['class' => 'btn btn-danger']) ?>
+        <?= Html::endForm() ?>
+    </div>
+    <?php endif; ?>
+
+    <div class="mt-3">
+        <?= Html::a('← Назад к списку', ['index'], ['class' => 'btn btn-secondary']) ?>
+    </div>
+</div>