< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_OrderStatusFlow_OrderStatus
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/OrderStatusFlow/OrderStatus.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 16
Coverable lines: 16
Total lines: 243
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 34
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ExecuteAsync()0%1190340%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/OrderStatusFlow/OrderStatus.cshtml

#LineLine coverage
 1@model OzonDomains.Models.Order
 2@using System.Text.Json
 3@{
 04    Layout = "~/Views/Shared/_Layout.cshtml";
 05    var statusColors = ViewBag.StatusColors as Dictionary<string, string> ?? new Dictionary<string, string>();
 06    var currentStatus = ViewBag.CurrentStatus as string ?? "Не указан";
 07    var currentStatusId = ViewBag.CurrentStatusId as int?;
 08    var currentStatusColor = statusColors.TryGetValue(currentStatus, out var c) ? c : "#e9ecef";
 09    var order = ViewBag.Order as OzonDomains.Models.Order;
 010    var orderTitle = order?.ShipmentNumber ?? $"Заказ #{order?.Id}";
 011    var transitionsJson = ViewBag.TransitionsJson as string ?? "[]";
 12}
 13
 14<div class="container-fluid py-3">
 15    <div class="d-flex justify-content-between align-items-center mb-3">
 16        <div>
 017            <h4 class="mb-1">Статус заказа: @orderTitle</h4>
 18            <div class="text-muted">
 19                Текущий статус:
 20                <span class="badge-status"
 21                      style="background-color:@currentStatusColor; color:#fff; padding:4px 8px; border-radius:6px;">
 022                    @currentStatus
 23                </span>
 24            </div>
 25        </div>
 26        <div>
 27            <a class="btn btn-outline-secondary btn-sm" asp-area="Studio2" asp-controller="Orders" asp-action="Index"
 28               target="_blank">
 29                К списку заказов
 30            </a>
 31        </div>
 32    </div>
 33
 34    <div class="graph-panel mb-4">
 35        <div id="orderStatusGraph" style="height: 600px; border: 1px solid #dee2e6; border-radius: 0.25rem; background-c
 36    </div>
 37
 38    <div class="alert alert-info">
 39        <i class="fas fa-info-circle me-2"></i>
 40        Текущий статус заказа подсвечен оранжевой рамкой. Масштаб — колёсиком мыши. Нажмите на название транзакции (на л
 41    </div>
 42</div>
 43
 44<style>
 45    .graph-panel {
 46        background-color: #fff;
 47        border: 1px solid #e9ecef;
 48        border-radius: 0.375rem;
 49        padding: 1rem;
 50    }
 51</style>
 52
 53<script>
 054    var orderStatusTransitions = @Html.Raw(transitionsJson);
 055    var orderStatusCurrentStatus = '@Html.Raw(currentStatus?.Replace("'", "\\'"))'.trim();
 056    var orderStatusCurrentStatusId = @(currentStatusId.HasValue ? currentStatusId.Value.ToString() : "null");
 057    var orderStatusColors = @Html.Raw(JsonSerializer.Serialize(statusColors));
 058    var orderTitleText = '@Html.Raw(orderTitle?.Replace("'", "\\'").Replace("\r", "").Replace("\n", " "))';
 059    var orderIdForTransaction = @(order?.Id ?? 0);
 60
 61    function darkenColor(color, percent) {
 62        if (!color || !color.startsWith('#')) return color;
 63        var num = parseInt(color.replace('#', ''), 16);
 64        var amt = Math.round(2.55 * percent);
 65        var R = Math.max(0, (num >> 16) - amt);
 66        var G = Math.max(0, (num >> 8 & 0x00FF) - amt);
 67        var B = Math.max(0, (num & 0x0000FF) - amt);
 68        return '#' + (0x1000000 + R * 0x10000 + G * 0x100 + B).toString(16).slice(1);
 69    }
 70    function isLightColor(color) {
 71        if (!color || !color.startsWith('#') || color.length < 7) return true;
 72        var hex = color.replace('#', '');
 73        var r = parseInt(hex.substr(0, 2), 16);
 74        var g = parseInt(hex.substr(2, 2), 16);
 75        var b = parseInt(hex.substr(4, 2), 16);
 76        return ((r * 299) + (g * 587) + (b * 114)) / 1000 > 155;
 77    }
 78    function getEdgeColorFromCssClass(cssClass) {
 79        var map = { 'link-success': '#198754', 'link-secondary': '#6c757d', 'link-info': '#0dcaf0', 'link-warning': '#ff
 80        return map[cssClass] || '#6c757d';
 81    }
 82    function normalizeStatus(s) {
 83        if (!s) return '';
 84        var t = s.trim().toLowerCase().replace(/\s+/g, ' ');
 85        if (t === 'принятнаскладе') return 'принят на складе';
 86        return t;
 87    }
 88    var transactionTypeToUrl = {
 89        0: '/Studio2/OrderToSupplierTransaction/CreateOrderToSupplierTransactionV2',
 90        2: '/Studio2/ShippedBySupplierTransaction/CreateShippedBySupplierTransaction',
 91        3: '/Studio2/ShippedToSellerTransaction/CreateShippedToSellerTransaction',
 92        4: '/Studio2/OrderedToSellerTransaction/CreateOrderedToSellerTransaction',
 93        6: '/Studio2/ShippedToClientTransaction/CreateShippedToClientTransaction',
 94        9: '/Studio2/AcceptedToWarehouseTransaction/AcceptedToWarehouseTransaction',
 95        10: '/Studio2/ToCancellationTransaction/CreateToCancellationTransaction',
 96        11: '/Studio2/CancelledTransaction/CreateCancelledTransaction',
 97        12: '/Studio2/CustomerReturnTransaction/CreateCustomerReturnTransaction',
 98        13: '/Studio2/WarehouseChangeTransaction/CreateWarehouseChangeTransaction',
 99        14: '/Studio2/ReturnToSupplierTransaction/CreateReturnToSupplierTransaction',
 100        15: '/Studio2/ReturnToWarehouseTransaction/CreateReturnToWarehouseTransaction',
 101        16: '/Studio2/WarehouseTransferTransaction/CreateWarehouseTransferTransaction',
 102        17: '/Studio2/ShippedToCommissionerTransaction/CreateShippedToCommissionerTransaction'
 103    };
 104    function getTransactionUrl(transactionType, orderId) {
 105        var path = transactionTypeToUrl[transactionType];
 106        if (!path) return null;
 107        return path + '?ids=' + orderId + '&page=1';
 108    }
 109
 110    function initializeOrderStatusGraph() {
 111        if (typeof vis === 'undefined') {
 112            document.getElementById('orderStatusGraph').innerHTML = '<div style="padding: 2rem; text-align: center; colo
 113            return;
 114        }
 115        var transitions = orderStatusTransitions || [];
 116        var statusMap = {};
 117        transitions.forEach(function(t) {
 118            if (!statusMap[t.fromStatusId]) {
 119                statusMap[t.fromStatusId] = { id: t.fromStatusId, label: t.fromStatusName, color: t.fromStatusColor || o
 120            }
 121            if (!statusMap[t.toStatusId]) {
 122                statusMap[t.toStatusId] = { id: t.toStatusId, label: t.toStatusName, color: t.toStatusColor || orderStat
 123            }
 124        });
 125        if (transitions.length === 0 && Object.keys(orderStatusColors).length > 0) {
 126            var id = 1;
 127            Object.keys(orderStatusColors).forEach(function(name) {
 128                statusMap[id] = { id: id, label: name, color: orderStatusColors[name] || '#e9ecef' };
 129                id++;
 130            });
 131        }
 132        var nodeList = Object.keys(statusMap).map(function(k) { return statusMap[k]; });
 133        var normalizedCurrent = normalizeStatus(orderStatusCurrentStatus);
 134        var currentNodeId = orderStatusCurrentStatusId;
 135        if (currentNodeId == null && normalizedCurrent) {
 136            var found = nodeList.find(function(s) { return normalizeStatus(s.label) === normalizedCurrent; });
 137            if (found) currentNodeId = found.id;
 138        }
 139        var graphNodes = new vis.DataSet(nodeList.map(function(s) {
 140            var isCurrent = (currentNodeId != null && s.id === currentNodeId);
 141            var color = s.color;
 142            return {
 143                id: s.id,
 144                label: s.label + (isCurrent ? '\n(' + orderTitleText + ')' : ''),
 145                color: {
 146                    background: color,
 147                    border: isCurrent ? '#ff6b35' : darkenColor(color, 20),
 148                    highlight: { background: color, border: isCurrent ? '#ff6b35' : darkenColor(color, 40) }
 149                },
 150                font: { color: isLightColor(color) ? '#000' : '#fff', size: 14, face: 'Arial' },
 151                shape: 'box',
 152                margin: 10,
 153                borderWidth: isCurrent ? 6 : 2
 154            };
 155        }));
 156        var edgesData = transitions.map(function(t, i) {
 157            return {
 158                id: i,
 159                from: t.fromStatusId,
 160                to: t.toStatusId,
 161                label: t.displayName,
 162                transactionType: t.transactionType != null ? t.transactionType : -1,
 163                color: { color: getEdgeColorFromCssClass(t.transactionCssClass), opacity: 1 },
 164                arrows: { to: { enabled: true, scaleFactor: 0.8 } },
 165                font: { size: 11, color: '#495057' },
 166                smooth: { enabled: true, type: 'curvedCW', roundness: 0.2 }
 167            };
 168        });
 169        var graphEdges = new vis.DataSet(edgesData);
 170        var container = document.getElementById('orderStatusGraph');
 171        var data = { nodes: graphNodes, edges: graphEdges };
 172        var options = {
 173            layout: { randomSeed: 1 },
 174            physics: {
 175                enabled: true,
 176                stabilization: { iterations: 200, updateInterval: 25, onlyDynamicEdges: false, fit: true },
 177                barnesHut: {
 178                    gravitationalConstant: -1400,
 179                    centralGravity: 0.35,
 180                    springLength: 110,
 181                    springConstant: 0.06,
 182                    damping: 0.25,
 183                    avoidOverlap: 0.9
 184                }
 185            },
 186            interaction: {
 187                hover: true,
 188                tooltipDelay: 100,
 189                zoomView: true,
 190                dragView: false,
 191                dragNodes: false,
 192                zoomSpeed: 1.2
 193            },
 194            edges: { smooth: { enabled: true, type: 'cubicBezier', roundness: 0.25 } }
 195        };
 196        var network = new vis.Network(container, data, options);
 197        network.on('click', function(params) {
 198            if (params.edges.length > 0 && orderIdForTransaction > 0) {
 199                var edgeId = params.edges[0];
 200                var edgeData = edgesData[edgeId];
 201                if (edgeData && edgeData.transactionType >= 0) {
 202                    var url = getTransactionUrl(edgeData.transactionType, orderIdForTransaction);
 203                    if (url) window.location.href = url;
 204                }
 205            }
 206        });
 207        network.on('hoverEdge', function() { container.style.cursor = 'pointer'; });
 208        network.on('blurEdge', function() { container.style.cursor = 'default'; });
 209        network.once('stabilizationIterationsDone', function() {
 210            network.setOptions({ physics: { enabled: false } });
 211            network.fit({ animation: { duration: 400, easingFunction: 'easeInOutQuad' } });
 212            if (currentNodeId != null) {
 213                network.focus(currentNodeId, { scale: 1.1, animation: { duration: 400, easingFunction: 'easeInOutQuad' }
 214            }
 215        });
 216    }
 217</script>
 218
 219@section Scripts {
 220    <link href="https://cdn.jsdelivr.net/npm/vis-network@9.1.9/dist/dist/vis-network.min.css" rel="stylesheet" type="tex
 221    <script>
 222        (function() {
 223            var link = document.createElement('link');
 224            link.rel = 'stylesheet';
 225            link.href = 'https://cdn.jsdelivr.net/npm/vis-network@9.1.9/dist/dist/vis-network.min.css';
 226            link.type = 'text/css';
 227            document.head.appendChild(link);
 228            var script = document.createElement('script');
 229            script.src = 'https://cdn.jsdelivr.net/npm/vis-network@9.1.9/standalone/umd/vis-network.min.js';
 230            script.async = false;
 231            script.onload = function() {
 232                if (typeof vis !== 'undefined' && typeof initializeOrderStatusGraph === 'function') {
 233                    initializeOrderStatusGraph();
 234                }
 235            };
 236            script.onerror = function() {
 237                var el = document.getElementById('orderStatusGraph');
 238                if (el) el.innerHTML = '<div style="padding: 2rem; text-align: center; color: #dc3545;"><i class="fas fa
 239            };
 240            document.head.appendChild(script);
 241        })();
 242    </script>
 243}

Methods/Properties

ExecuteAsync()