Webview 2 + Html + ChatGPT !

Webview 2 + Html + ChatGPT !

Postby TOTOVIOTTI » Thu Sep 19, 2024 10:23 pm

Hola amigos..
estoy intentando probar webview2 con un código html que simula un dashboard.
Si lo ejecuto por afuera, el html me muestra la pantalla que está en el código, pero,
cuando lo mando desde el prg, la pantalla sale en blanco, que puede ser??

Adjunto el código como para probar:

#include "fivewin.ch"

//----------------------------------------------------------------------------//

function Main()

local oWebView := TWebView():New()

oWebView:bOnBind = { | cJson, nCalls | MsgInfo( cJson, nCalls ) }
oWebView:Bind( "SendToFWH" )
oWebView:Navigate( Html() )
Sleep( 200 )
oWebView:Run()
oWebView:Destroy()

return nil

//----------------------------------------------------------------------------//

function Html()

local cHtml

TEXT INTO cHtml

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tablero de Control Empresarial</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #8b93bb; /* Beige claro */
}
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}
.ventana {
background-color: white;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: all 0.3s ease;
}
.ventana:hover {
transform: translateY(-5px);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
h1 {
text-align: center;
color: #333;
}
h3 {
margin-top: 0;
color: #fff;
display: flex;
align-items: center;
padding: 10px;
border-radius: 5px 5px 0 0;
}
h3 i {
margin-right: 10px;
}
.valor {
font-size: 20px;
font-weight: bold;
color: #333;
margin: 10px 0;
}
.finanzas { background-color: #4CAF50; }
.ventas { background-color: #2196F3; }
.operaciones { background-color: #FFC107; }
.marketing { background-color: #E91E63; }
</style>
</head>
<body>
<h1>Tablero de Control Empresarial</h1>
<div id="dashboard" class="dashboard">
<!-- Las ventanas del dashboard se insertarán aquí dinámicamente -->
</div>

<script>
// Datos de ejemplo (en una aplicación real, estos datos podrían venir de FiveWin)
const datos = {
'ventas_mensuales': 150000,
'compras_mensuales': 100000,
'clientes_activos': 500,
'productos_en_stock': 1000,
'pedidos_pendientes': 50,
'ingresos_anuales': 2000000,
'gastos_anuales': 1500000,
'empleados': 100,
'proyectos_activos': 10,
'tasa_conversion': 3.5,
'satisfaccion_cliente': 4.2,
'crecimiento_ventas': 7.5,
'retorno_inversion': 15.2,
'rotacion_inventario': 12,
'cuentas_por_cobrar': 200000,
'cuentas_por_pagar': 150000,
'flujo_caja': 300000,
'margen_beneficio': 25,
'cuota_mercado': 8.5,
'valor_marca': 5000000
};

function crearVentana(titulo, valor, unidad = '', icono = 'fa-chart-line', categoria = 'finanzas') {
const ventana = document.createElement('div');
ventana.className = 'ventana';
ventana.innerHTML = `
<h3 class="${categoria}"><i class="fas ${icono}"></i>${titulo}</h3>
<p class="valor">${formatearNumero(valor)} ${unidad}</p>
`;
return ventana;
}

function formatearNumero(numero) {
return numero.toLocaleString('es-ES');
}

function inicializarDashboard() {
const dashboard = document.getElementById('dashboard');
const ventanas = [
{ titulo: 'Ventas de Contado', valor: datos.ventas_mensuales, unidad: '$', icono: 'fa-shopping-cart', categoria: 'finanzas' },
{ titulo: 'Ventas en Cuenta Corriente', valor: datos.compras_mensuales, unidad: '$', icono: 'fa-shopping-cart', categoria: 'finanzas' },
{ titulo: 'Compras de Contado', valor: datos.clientes_activos, unidad: '$', icono: 'fa-solid fa-basket-shopping', categoria: 'marketing' },
{ titulo: 'Compras en Cuenta Corriente', valor: datos.productos_en_stock, unidad: '$', icono: 'fa-solid fa-basket-shopping', categoria: 'marketing' },
{ titulo: 'Cobranzas por Recibos', valor: datos.pedidos_pendientes, unidad: '$', icono: 'fa-hand-holding-usd', categoria: 'finanzas' },
{ titulo: 'Otros Ingresos', valor: datos.ingresos_anuales, unidad: '$', icono: 'fa-money-bill-wave', categoria: 'finanzas' },
{ titulo: 'Pagos por Órdenes de Pago', valor: datos.gastos_anuales, unidad: '$', icono: 'fa-file-invoice-dollar', categoria: 'marketing' },
{ titulo: 'Otros Egresos', valor: datos.empleados, unidad: '$', icono: 'fa-solid fa-comment-dollar', categoria: 'marketing' },
{ titulo: 'Saldo CC Clientes a fecha', valor: datos.proyectos_activos, unidad: '$', icono: 'fa-users', categoria: 'finanzas' },
{ titulo: 'Saldo Total CC Clientes', valor: datos.tasa_conversion, unidad: '$', icono: 'fa-users', categoria: 'finanzas' },
{ titulo: 'Saldo CC Proveedores a fecha', valor: datos.satisfaccion_cliente, unidad: '$', icono: 'fa-regular fa-user', categoria: 'marketing' },
{ titulo: 'Saldo Total CC Proveedores', valor: datos.crecimiento_ventas, unidad: '$', icono: 'fa-regular fa-user', categoria: 'marketing' },
{ titulo: 'Cheques a Vencer al', valor: datos.retorno_inversion, unidad: '$', icono: 'fa-solid fa-money-check', categoria: 'operaciones' },
{ titulo: 'Cheques en Cartera', valor: datos.rotacion_inventario, unidad: '$', icono: 'fa-solid fa-money-check', categoria: 'operaciones' },
{ titulo: 'Cheques Recibidos entre', valor: datos.cuentas_por_cobrar, unidad: '$', icono: 'fa-solid fa-money-check', categoria: 'operaciones' },
{ titulo: 'Cheques Transferidos entre', valor: datos.cuentas_por_pagar, unidad: '$', icono: 'fa-solid fa-money-check', categoria: 'operaciones' },
{ titulo: 'Cheques Emitidos', valor: datos.flujo_caja, unidad: '$', icono: 'fa-solid fa-building-columns', categoria: 'ventas' },
{ titulo: 'Transferencias Realizadas', valor: datos.margen_beneficio, unidad: '$', icono: 'fa-exchange-alt', categoria: 'ventas' },
{ titulo: 'Transferencias Recibidas', valor: datos.cuota_mercado, unidad: '$', icono: 'fa-exchange-alt', categoria: 'ventas' }
];

ventanas.forEach(v => {
dashboard.appendChild(crearVentana(v.titulo, v.valor, v.unidad, v.icono, v.categoria));
});
}

// Inicializar el dashboard cuando la página se cargue
window.onload = inicializarDashboard;
</script>
</body>
</html>
ENDTEXT

return cHtml
Univ@c I.S.I.
Desarrolladores de Software
http://www.elcolegioencasa.edu.ar
User avatar
TOTOVIOTTI
 
Posts: 421
Joined: Fri Feb 05, 2010 11:30 am
Location: San Francisco - Córdoba - Argentina

Re: Webview 2 + Html

Postby Antonio Linares » Fri Sep 20, 2024 6:51 am

Hazlo asi:

test.prg
Code: Select all  Expand view  RUN
#include "FiveWin.ch"

//----------------------------------------------------------------------------//

function Main()

   local oWnd, oWebView

   DEFINE WINDOW oWnd

   oWebView = TWebView2():New( oWnd )
   oWebView:SetHtml( Html() )

   ACTIVATE WINDOW oWnd MAXIMIZED ;
      ON RESIZE oWebView:SetSize( nWidth, nHeight )

return nil

//----------------------------------------------------------------------------//

function Html()

local cHtml

TEXT INTO cHtml

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tablero de Control Empresarial</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #8b93bb; /* Beige claro */
}
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}
.ventana {
background-color: white;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: all 0.3s ease;
}
.ventana:hover {
transform: translateY(-5px);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
h1 {
text-align: center;
color: #333;
}
h3 {
margin-top: 0;
color: #fff;
display: flex;
align-items: center;
padding: 10px;
border-radius: 5px 5px 0 0;
}
h3 i {
margin-right: 10px;
}
.valor {
font-size: 20px;
font-weight: bold;
color: #333;
margin: 10px 0;
}
.finanzas { background-color: #4CAF50; }
.ventas { background-color: #2196F3; }
.operaciones { background-color: #FFC107; }
.marketing { background-color: #E91E63; }
</style>
</head>
<body>
<h1>Tablero de Control Empresarial</h1>
<div id="dashboard" class="dashboard">
<!-- Las ventanas del dashboard se insertarán aquí dinámicamente -->
</div>

<script>
// Datos de ejemplo (en una aplicación real, estos datos podrían venir de FiveWin)
const datos = {
'ventas_mensuales': 150000,
'compras_mensuales': 100000,
'clientes_activos': 500,
'productos_en_stock': 1000,
'pedidos_pendientes': 50,
'ingresos_anuales': 2000000,
'gastos_anuales': 1500000,
'empleados': 100,
'proyectos_activos': 10,
'tasa_conversion': 3.5,
'satisfaccion_cliente': 4.2,
'crecimiento_ventas': 7.5,
'retorno_inversion': 15.2,
'rotacion_inventario': 12,
'cuentas_por_cobrar': 200000,
'cuentas_por_pagar': 150000,
'flujo_caja': 300000,
'margen_beneficio': 25,
'cuota_mercado': 8.5,
'valor_marca': 5000000
};

function crearVentana(titulo, valor, unidad = '', icono = 'fa-chart-line', categoria = 'finanzas') {
const ventana = document.createElement('div');
ventana.className = 'ventana';
ventana.innerHTML = `
<h3 class="${categoria}"><i class="fas ${icono}"></i>${titulo}</h3>
<p class="valor">${formatearNumero(valor)} ${unidad}</p>
`;
return ventana;
}

function formatearNumero(numero) {
return numero.toLocaleString('es-ES');
}

function inicializarDashboard() {
const dashboard = document.getElementById('dashboard');
const ventanas = [
{ titulo: 'Ventas de Contado', valor: datos.ventas_mensuales, unidad: '$', icono: 'fa-shopping-cart', categoria: 'finanzas' },
{ titulo: 'Ventas en Cuenta Corriente', valor: datos.compras_mensuales, unidad: '$', icono: 'fa-shopping-cart', categoria: 'finanzas' },
{ titulo: 'Compras de Contado', valor: datos.clientes_activos, unidad: '$', icono: 'fa-solid fa-basket-shopping', categoria: 'marketing' },
{ titulo: 'Compras en Cuenta Corriente', valor: datos.productos_en_stock, unidad: '$', icono: 'fa-solid fa-basket-shopping', categoria: 'marketing' },
{ titulo: 'Cobranzas por Recibos', valor: datos.pedidos_pendientes, unidad: '$', icono: 'fa-hand-holding-usd', categoria: 'finanzas' },
{ titulo: 'Otros Ingresos', valor: datos.ingresos_anuales, unidad: '$', icono: 'fa-money-bill-wave', categoria: 'finanzas' },
{ titulo: 'Pagos por Órdenes de Pago', valor: datos.gastos_anuales, unidad: '$', icono: 'fa-file-invoice-dollar', categoria: 'marketing' },
{ titulo: 'Otros Egresos', valor: datos.empleados, unidad: '$', icono: 'fa-solid fa-comment-dollar', categoria: 'marketing' },
{ titulo: 'Saldo CC Clientes a fecha', valor: datos.proyectos_activos, unidad: '$', icono: 'fa-users', categoria: 'finanzas' },
{ titulo: 'Saldo Total CC Clientes', valor: datos.tasa_conversion, unidad: '$', icono: 'fa-users', categoria: 'finanzas' },
{ titulo: 'Saldo CC Proveedores a fecha', valor: datos.satisfaccion_cliente, unidad: '$', icono: 'fa-regular fa-user', categoria: 'marketing' },
{ titulo: 'Saldo Total CC Proveedores', valor: datos.crecimiento_ventas, unidad: '$', icono: 'fa-regular fa-user', categoria: 'marketing' },
{ titulo: 'Cheques a Vencer al', valor: datos.retorno_inversion, unidad: '$', icono: 'fa-solid fa-money-check', categoria: 'operaciones' },
{ titulo: 'Cheques en Cartera', valor: datos.rotacion_inventario, unidad: '$', icono: 'fa-solid fa-money-check', categoria: 'operaciones' },
{ titulo: 'Cheques Recibidos entre', valor: datos.cuentas_por_cobrar, unidad: '$', icono: 'fa-solid fa-money-check', categoria: 'operaciones' },
{ titulo: 'Cheques Transferidos entre', valor: datos.cuentas_por_pagar, unidad: '$', icono: 'fa-solid fa-money-check', categoria: 'operaciones' },
{ titulo: 'Cheques Emitidos', valor: datos.flujo_caja, unidad: '$', icono: 'fa-solid fa-building-columns', categoria: 'ventas' },
{ titulo: 'Transferencias Realizadas', valor: datos.margen_beneficio, unidad: '$', icono: 'fa-exchange-alt', categoria: 'ventas' },
{ titulo: 'Transferencias Recibidas', valor: datos.cuota_mercado, unidad: '$', icono: 'fa-exchange-alt', categoria: 'ventas' }
];

ventanas.forEach(v => {
dashboard.appendChild(crearVentana(v.titulo, v.valor, v.unidad, v.icono, v.categoria));
});
}

// Inicializar el dashboard cuando la página se cargue
window.onload = inicializarDashboard;
</script>
</body>
</html>
ENDTEXT

return cHtml
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42118
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Webview 2 + Html

Postby TOTOVIOTTI » Fri Sep 20, 2024 10:53 am

EXCELENTE!!!!!!!!!!!!!

GRACIAS ANTONIOOOOOOOOOO!!!!
Univ@c I.S.I.
Desarrolladores de Software
http://www.elcolegioencasa.edu.ar
User avatar
TOTOVIOTTI
 
Posts: 421
Joined: Fri Feb 05, 2010 11:30 am
Location: San Francisco - Córdoba - Argentina

Re: Webview 2 + Html

Postby cmsoft » Sun Sep 22, 2024 10:57 am

Tiro otra idea, usando como contenedor nuestra aplicacion y para que tenga interactividad con nuestro programa
Code: Select all  Expand view  RUN

#include "FiveWin.ch"

FUNCTION Main()
local oWebView, oBtn
Local oWnd, oExBar,  oPanelExplorer, oPanelWeb, oPanel, oGet := ARRAY(2), dDesde := DATE(), dHasta := DATE()
REQUEST HB_LANG_ESWIN
REQUEST HB_CODEPAGE_ESMWIN
SET DATE FORMAT "DD/MM/YYYY"
SET 3DLOOK ON
HB_LANGSELECT( 'ESWIN' )

//Si mi aplicacion es MDI asi debería definir la ventana
//DEFINE WINDOW oWnd MDICHILD OF oApp:oWnd TITLE "Dashboard " ICON oApp:oIco
DEFINE WINDOW oWnd TITLE "Dashboard "
   *** Paneles
   oPanelExplorer := TPanel():New( 0, 0, oWnd:nHeight, 280, oWnd )
   
   oPanelWeb := TPanel():New( 0, 281, oWnd:nHeight, oWnd:nWidth, oWnd )

   oExBar := TExplorerBar():New( 0, 0, 250, 300, oPanelExplorer )
   
   oPanelExplorer:oClient = oExBar
   
   oPanel := oExBar:AddPanel( "Seleccionar Fecha", "..\bitmaps\calendar.bmp", 255 )
   oPanel:AddLink( "Ventas del Periodo" , { || oWebView:SetHtml(memoread('ventas.html')) }, "..\bitmaps\go.bmp" )
   oPanel:AddLink( "Compras del Periodo " , { || oWebView:SetHtml(memoread('compras.html')) }, "..\bitmaps\go.bmp" )
   oPanel:AddLink( "Cobros del Periodo"  , { || oWebView:SetHtml(memoread('cobros.html'))  }, "..\bitmaps\go.bmp" )
   oPanel:AddLink( "Pagos del Periodo" , { || oWebView:SetHtml(memoread('pagos.html')) }, "..\bitmaps\go.bmp" )
   
   */
   @170, 15 SAY "Desde Fecha:"      OF oPanel TRANSPARENT PIXEL SIZE 40,12
   @200, 15 SAY "Hasta Fecha:"      OF oPanel TRANSPARENT PIXEL SIZE 40,12
       
   @170,90 GET oGet[1] VAR dDesde OF oPanel PIXEL
   @200,90 GET oGet[2] VAR dHasta OF oPanel PIXEL
   @230,50 BUTTON oBtn PROMPT "Cambiar Fechas" OF oPanel PIXEL SIZE 110,25
   
   oWebView := TWebView2():New(oPanelWeb)      
   oWebView:SetUserAgent( "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36" )  
   oWebView:SetHtml( memoread( 'ventas.html' ) )
   oWebView:Run()  

ACTIVATE WINDOW oWnd MAXIMIZED ON RESIZE (oPanelExplorer:Move( , , , oWnd:nHeight ),;
                                oPanelWeb:Move   ( , , oWnd:nWidth - oPanelExplorer:nRight, oWnd:nHeight - 60 ),;
                                oWebView:SetSize(oPanelWeb:nWidth,oPanelWeb:nHeight));
            ON INIT (oWebView:SetSize(oPanelWeb:nWidth,oPanelWeb:nHeight),oWnd:Move(0,0))
//Si mi app es MDI deberia agregar aqui
//ON INIT (oWnd:SetSize(oApp:oWnd:oWndclient:nWidth, oApp:oWnd:oWndclient:nHeight)            

RETURN nil
 

Quedaría algo asi:
Image
Este sería el html (Paso 1, los otros serían a la imaginacion de cada uno)
Code: Select all  Expand view  RUN
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dashboard</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.12.1/css/all.css" crossorigin="anonymous">
   

    <script type="text/javascript">
        // Cargar Google Charts
        google.charts.load('current', {'packages':['corechart']});
        google.charts.setOnLoadCallback(drawCharts);

        // Función para dibujar los gráficos
        function drawCharts() {
            drawPieChart();
            drawLineChart();
        }

        // Gráfico de torta
        function drawPieChart() {
            var data = google.visualization.arrayToDataTable([
                ['Concepto', 'Importe'],
                ['Efectivo', 800000],
                ['Mercadopago', 200000],
                ['Tarjetas', 300000],
                ['Transferencias', 500000],
                ['Otros', 150000]
            ]);

            var options = {
                title: 'Ingresos por ventas',
                widht: '100%',
                height: 300,
                is3D: true
            };

            var chart = new google.visualization.PieChart(document.getElementById('piechart'));
            chart.draw(data, options);
        }

        // Gráfico de líneas
        function drawLineChart() {
            var data = google.visualization.arrayToDataTable([
                ['Rubro', 'Totales'],
                ['Carniceria', 1000000],
                ['Fiambreria', 1170000],
                ['Comestibles', 660000],
                ['Bazar', 1030000]
            ]);

            var options = {
                title: 'Ventas Por Rubro',
                curveType: 'function',
                legend: { position: 'bottom' },
                widht: '100%',
                height: 300,
                is3D: true
            };

            var chart = new google.visualization.ColumnChart(document.getElementById('linechart'));
            chart.draw(data, options);
        }

        window.onresize = function () {
            drawCharts();  // Redibujar gráficos cuando la ventana cambia de tamaño
        };
       
    </script>

</head>
<body class="bg-gray-100">

    <div class="flex flex-col lg:flex-row min-h-screen">
        <!-- Sidebar -->        

        <!-- Main Content -->
        <div class="flex-1 p-8 overflow-y-auto">
            <!-- Valores Section -->
            <div id="values" class="section">
                <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
                    <!-- Ingresos -->
                    <div class="bg-white shadow-md p-6 h-50 rounded-lg text-center border-t-4 border-green-500">
                        <h3 class="text-lg font-bold text-green-500"><i class="fas fa-dollar-sign fa-3x"></i></h3>
                        <p class="text-xl mt-4 text-gray-700">Ventas</p>
                        <p class="text-3xl mt-2 text-green-500 font-bold">$1,000,000</p>
                    </div>
                    <!-- Productos -->
                    <div class="bg-white shadow-md p-6 h-50 rounded-lg text-center border-t-4 border-blue-500">
                        <h3 class="text-lg font-bold text-blue-500"><i class="fas fa-boxes fa-3x"></i></h3>
                        <p class="text-xl mt-4 text-gray-700">Costo</p>
                        <p class="text-3xl mt-2 text-blue-500 font-bold">$900,000</p>
                    </div>
                    <!-- Usuarios -->
                    <div class="bg-white shadow-md p-6 h-50 rounded-lg text-center border-t-4 border-yellow-500">
                        <h3 class="text-lg font-bold text-yellow-500"><i class="fas fa-users fa-3x"></i></h3>
                        <p class="text-xl mt-4 text-gray-700">Unidades</p>
                        <p class="text-3xl mt-2 text-yellow-500 font-bold">12,000</p>
                    </div>
                </div>
            </div>
            <div class="section p-2">
                <hr>
            </div>
            <!-- Gráficos Section -->
            <div id="charts" class="section">                
                <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-6">
                    <div class="bg-white shadow-md p-6 rounded-lg">
                        <h2 class="text-xl font-bold mb-4 text-green-500">Ventas</h2>
                        <div id="piechart"></div>
                    </div>
                    <div class="bg-white shadow-md p-6 rounded-lg">
                        <h2 class="text-xl font-bold mb-4 text-blue-500">Por Rubro</h2>
                        <div id="linechart"></div>
                    </div>
                </div>
            </div>

           
           
        </div>
    </div>

</body>
</html>
 
User avatar
cmsoft
 
Posts: 1291
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Webview 2 + Html

Postby cmsoft » Sun Sep 22, 2024 1:38 pm

Lo mismo pero con una clase que nos permita generar dinamicamente el html que vamos a mostrar
Code: Select all  Expand view  RUN

#include "FiveWin.ch"

FUNCTION Main()
local oWebView, oBtn
Local oWnd, oExBar,  oPanelExplorer, oPanelWeb, oPanel, oGet := ARRAY(2), dDesde := DATE(), dHasta := DATE()
REQUEST HB_LANG_ESWIN
REQUEST HB_CODEPAGE_ESMWIN
SET DATE FORMAT "DD/MM/YYYY"
SET 3DLOOK ON
HB_LANGSELECT( 'ESWIN' )

//Si mi aplicacion es MDI asi debería definir la ventana
//DEFINE WINDOW oWnd MDICHILD OF oApp:oWnd TITLE "Dashboard " ICON oApp:oIco
DEFINE WINDOW oWnd TITLE "Dashboard "
   *** Paneles
   oPanelExplorer := TPanel():New( 0, 0, oWnd:nHeight, 280, oWnd )
   
   oPanelWeb := TPanel():New( 0, 281, oWnd:nHeight, oWnd:nWidth, oWnd )

   oExBar := TExplorerBar():New( 0, 0, 250, 300, oPanelExplorer )
   
   oPanelExplorer:oClient = oExBar
   
   oPanel := oExBar:AddPanel( "Seleccionar Fecha", "..\bitmaps\calendar.bmp", 255 )
   oPanel:AddLink( "Ventas del Periodo" , { || oWebView:SetHtml(MiHtml(1)) }, "..\bitmaps\go.bmp" )
   oPanel:AddLink( "Compras del Periodo " , { || oWebView:SetHtml(MiHtml(2)) }, "..\bitmaps\go.bmp" )
   oPanel:AddLink( "Cobros del Periodo"  , { || oWebView:SetHtml(MiHtml(3))  }, "..\bitmaps\go.bmp" )
   oPanel:AddLink( "Pagos del Periodo" , { || oWebView:SetHtml(MiHtml(4)) }, "..\bitmaps\go.bmp" )
   
   
   oWebView := TWebView2():New(oPanelWeb)      
   oWebView:SetUserAgent( "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36" )  
   oWebView:SetHtml( MiHtml(1) )
   oWebView:Run()  

ACTIVATE WINDOW oWnd MAXIMIZED ON RESIZE (oPanelExplorer:Move( , , , oWnd:nHeight ),;
                                oPanelWeb:Move   ( , , oWnd:nWidth - oPanelExplorer:nRight, oWnd:nHeight - 60 ),;
                                oWebView:SetSize(oPanelWeb:nWidth,oPanelWeb:nHeight));
            ON INIT (oWebView:SetSize(oPanelWeb:nWidth,oPanelWeb:nHeight),oWnd:Move(0,0))
//Si mi app es MDI deberia agregar aqui
//ON INIT (oWnd:SetSize(oApp:oWnd:oWndclient:nWidth, oApp:oWnd:oWndclient:nHeight)            

RETURN nil

STATIC FUNCTION MiHtml(n)
LOCAL oDashBoard, aData
oDashBoard = TDashboard():New()
DO CASE
   CASE n = 1        
        oDashBoard:AddPanel('Ventas','$1,000,000','dollar-sign','green')
        oDashBoard:AddPanel('Costo' ,'$900,000','boxes','blue')
        oDashBoard:AddPanel('Productos' ,'12,000','cubes','lime')
        aData := {{'Carniceria', 1000000},;
                  {'Fiambreria', 1170000},;
                  {'Comestibles', 660000},;
                  {'Bazar', 1030000}}
        oDashBoard:AddGraph('Ventas', 'Ventas del periodo',  'PieChart', {'Rubro', 'Totales'}, aData, 'emerald' )
        aData := {{'Mercado Pago', 1000000},;
                  {'Efectivo', 1170000},;
                  {'Tarjeta', 660000},;
                  {'Transferencia', 1030000},;
                  {'Cuenta Corriente', 1030000}}
        oDashBoard:AddGraph('Cobros', 'Por Forma de pago',  'ColumnChart', {'Concepto', 'Importe'}, aData, 'purple' )
   CASE n = 2
        oDashBoard:AddPanel('Compras','$750,000','dollar-sign','emerald')
        oDashBoard:AddPanel('Gastos' ,'$350,000','desktop','indigo')
        oDashBoard:AddPanel('Stock' ,'7,000','cubes','indigo')
        oDashBoard:AddPanel('Reciclado' ,'$90,000','recycle','purple')
        aData := {{'Materia Prima', 300000},;
                  {'Productos Compraventa', 850000},;
                  {'Gastos', 690000}}
        oDashBoard:AddGraph('Compras', 'Por Tipo de compra',  'BarChart', {'Concepto', 'Importe'}, aData, 'purple' )
   CASE n = 3
        oDashBoard:AddPanel('Tarjetas','$960,000','credit-card','pink')
        oDashBoard:AddPanel('Efectivo','$1,050,000','dollar-sign','blue')
   CASE n = 4
        oDashBoard:AddPanel('Transferencias','$660,000','university','cyan')
        oDashBoard:AddPanel('Efectivo','$550,000','dollar-sign','orange')
ENDCASE
RETURN oDashBoard:cHtml

********************************************
** Generar Html
CLASS TDashboard
   DATA cHtml
   DATA aGraph INIT {}

   METHOD New() CONSTRUCTOR
   METHOD AddPanel(cTexto, cValor, cFaFaIcon, cColor )
   METHOD AddGraph (cNombre, cTitulo,  cTipo, aColumnsData, aData, cColor )  

ENDCLASS

//----------------------------------------------------------------//

METHOD New() CLASS TDashboard
      TEXT INTO ::cHtml
      <!DOCTYPE html>
         <html lang="es">
         <head>
             <meta charset="UTF-8">
             <meta name="viewport" content="width=device-width, initial-scale=1.0">
             <title>Dashboard</title>
             <script src="https://cdn.tailwindcss.com"></script>
             <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
             <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.12.1/css/all.css" crossorigin="anonymous">
             

             <script type="text/javascript">
                 // Cargar Google Charts
                 google.charts.load('current', {'packages':['corechart']});
                 google.charts.setOnLoadCallback(drawCharts);

                 // Función para dibujar los gráficos
                 function drawCharts() {
                     //AgregarChar                    
                 }

                 //FuncionGrafico                

                 window.onresize = function () {
                     drawCharts();  // Redibujar gráficos cuando la ventana cambia de tamaño
                 };
                 
             </script>

         </head>
         <body class="bg-gray-100">

             <div class="flex flex-col lg:flex-row min-h-screen">    

                 <!-- Main Content -->
                 <div class="flex-1 p-8 overflow-y-auto">
                     <div id="values" class="section">
                         <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
                             <!-- AddPanel -->                            
                         </div>
                     </div>
                     <div class="section p-2">
                         <hr>
                     </div>
                     <!-- Gráficos Section -->
                     <div id="charts" class="section">                
                         <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-6">
                             <!-- idgrafico -->
                         </div>
                     </div>
                 </div>
             </div>

         </body>
         </html>
ENDTEXT
   
return Self

METHOD AddPanel(cTexto, cValor, cFaFaIcon, cColor ) CLASS TDashboard
Local cPanel := '<div class="bg-white shadow-md p-6 h-50 rounded-lg text-center border-t-4 border-'+cColor+'-500">'+;
                 '   <h3 class="text-lg font-bold text-'+cColor+'-500"><i class="fas fa-'+cFaFaIcon+' fa-3x"></i></h3>'+;
                 '   <p class="text-xl mt-4 text-'+cColor+'-700">'+cTexto+'</p>'+;
                 '   <p class="text-3xl mt-2 text-'+cColor+'-500 font-bold">'+cValor+'</p>'+;
                 '</div>'+;
                 '<!-- AddPanel -->'
::cHtml := strtran(::cHtml,"<!-- AddPanel -->",cPanel)                
return Self

METHOD AddGraph (cNombre, cTitulo,  cTipo, aColumnsData, aData, cColor )
Local cGraph, cFuncion, cId, i
cGraph := cNombre+'();//AgregarChar'
::cHtml := strtran(::cHtml,"//AgregarChar",cGraph)  
cFuncion := "function "+cNombre+"() { "+;
                     "var data = google.visualization.arrayToDataTable(["+;
                     "    ['"+aColumnsData[1]+"', '"+aColumnsData[2]+"'], "
                      for i := 1 to len(aData)  
                         cFuncion := cFuncion + "['"+aData[i,1]+"', "+STR(aData[i,2])+"],"
                      next i
cFuncion := cFuncion + "   ]);"+;
                     "var options = { "+;
                     "   title: '"+cTitulo+"',"+;
                     "    widht: '100%',"+;
                     "    height: 300, "+;
                     "    is3D: true "+;
                     "};"+;
                     "var chart = new google.visualization."+cTipo+"(document.getElementById('"+cNombre+"'));"+;
                     "chart.draw(data, options);"+;
                 "}"+;
                 "//FuncionGrafico"
::cHtml := strtran(::cHtml,"//FuncionGrafico",cFuncion)
cId := '<div class="bg-white shadow-md p-6 rounded-lg">'+;
            '<h2 class="text-xl font-bold mb-4 text-'+cColor+'-500">'+cTitulo+'</h2>'+;
            '<div id="'+cNombre+'"></div>'+;
        '</div>'+;
        '<!-- idgrafico -->'
::cHtml := strtran(::cHtml,"<!-- idgrafico -->",cId)
return Self

 


La clase TDashboard tiene 2 metodos, uno para agregar un panel y otro para agregar un grafico
El método AddPanel tiene los siguientes parametros:
METHOD AddPanel(cTexto, cValor, cFaFaIcon, cColor )
cTexto -> El nombre del panel a mostrar
cValor -> El número que queremos mostrar en formato texto
cFaFaIcon -> El icono que queremos mostrar (Cualquiera de fa fa icons https://fontawesome.com/)
cColor -> Un color de la Tailwind https://tailwindcss.com/docs/customizing-colors que es el css que usa

El método AddGraph tiene los siguientes parametros:
METHOD AddGraph (cNombre, cTitulo, cTipo, aColumnsData, aData, cColor )
cNombre -> Nombre del grafico (que sea una sola palabra, porque lo convierte en la funcion a llamar por Javascrip)
cTitulo -> Titulo del grafico
cTipo -> Un tipo de grafico simple de google graph (PieChart, BarChart, ColumnChart, etc)
aColumnsData -> Array con los titulos de las columnas de los datos a mostrar en el grafico (2 columnas, 1 fila)
aData -> Array con los los datos a mostrar en el grafico (2 columnas, n filas)
cColor -> Un color de Tailwind para el color del titulo

Esto es muy mejorable, pero es un inicio, espero que los expertos sumen funcionalidades
User avatar
cmsoft
 
Posts: 1291
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Webview 2 + Html

Postby Antonio Linares » Mon Sep 23, 2024 4:15 am

Querido César,

Muy bueno y muy inspirador! :-)

muchas gracias
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42118
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Webview 2 + Html

Postby Antonio Linares » Mon Sep 23, 2024 10:12 am

César,

He simplificado mucho el modelo con la idea de usar la inteligencia artificial para hacer el trabajo :-)

buildit.prg
Code: Select all  Expand view  RUN
#include "FiveWin.ch"

function Main()

    local oWnd, oExplBar, oExplPanel, oWebView
    local cCategory := Space( 30 )

    DEFINE WINDOW oWnd TITLE "Build it"

    oExplBar = TExplorerBar():New( 0, 82, 480, 100, oWnd:oLeft )
    oWnd:oLeft = oExplBar
    oExplBar:AddPanel( "My App" )

    oExplPanel = oExplBar:AddPanel( "AI assistant" )
    oExplPanel:AddLink( "what is this app about ?",;
                        { || MsgGet( "App category", "Please specify it", @cCategory ) } )

    oWnd:oClient = TPanel():New( 0, 0, 100, 100, oWnd )
    oWebView = TWebView2():New( oWnd:oClient )
    oWebView:Navigate( "https://www.google.com" )

    ACTIVATE WINDOW oWnd MAXIMIZED ;
       ON RESIZE ( oWebView:SetSize( nWidth - oExplBar:nWidth, nHeight ), oExplBar:SetSize( 480, nHeight ) )

return nil    
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42118
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Webview 2 + Html

Postby cmsoft » Mon Sep 23, 2024 11:07 am

Antonio Linares wrote:He simplificado mucho el modelo con la idea de usar la inteligencia artificial para hacer el trabajo :-)

Si, esta mucho mas limpio.
Cual sería la idea de usar IA ? Para hacer los dashboard?
User avatar
cmsoft
 
Posts: 1291
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Webview 2 + Html

Postby Antonio Linares » Mon Sep 23, 2024 11:14 am

Un ejemplo:

1. Preguntamos de que es la aplicación

El usuario responde, por ejemplo, contabilidad

2. la IA lista en un json las categorias que tiene que tener la aplicación y rellena el explorer bar

3. Al seleccionar una de esas opciones, se le pregunta a la IA que categorias debe tener esa opción

4. Finalmente al seleccionar la opción, se genera el HTML para dicha opción

Es algo muy simple pero tengo curiosidad de ver hasta donde se puede llegar. El código HTML se guarda en un campo memo
de forma que podamos mantener un histórico de las distintas versiones probadas.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42118
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Webview 2 + Html

Postby cmsoft » Mon Sep 23, 2024 11:34 am

Genial!
Me gustaría ver el avance.
User avatar
cmsoft
 
Posts: 1291
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Webview 2 + Html

Postby TOTOVIOTTI » Mon Sep 23, 2024 11:36 am

Siiiiiiiiiiiiiiiiiii.. se viene algo muy interesante acá!!!
Univ@c I.S.I.
Desarrolladores de Software
http://www.elcolegioencasa.edu.ar
User avatar
TOTOVIOTTI
 
Posts: 421
Joined: Fri Feb 05, 2010 11:30 am
Location: San Francisco - Córdoba - Argentina

Re: Webview 2 + Html

Postby cmsoft » Mon Sep 23, 2024 12:01 pm

Muy interesante Antonio!
Esperamos el avance con entusiasmo
User avatar
cmsoft
 
Posts: 1291
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Webview 2 + Html

Postby ruben Dario » Mon Sep 23, 2024 9:01 pm

Excelente el curso, Y muy interesante lo de inteligencia Artificial, Gracias-
Ruben Dario Gonzalez
Cali-Colombia
rubendariogd@hotmail.com - rubendariogd@gmail.com
User avatar
ruben Dario
 
Posts: 1070
Joined: Thu Sep 27, 2007 3:47 pm
Location: Colombia

Re: Webview 2 + Html

Postby Antonio Linares » Wed Sep 25, 2024 4:39 am

Para probarlo necesitais registraros en OpenAI y obtener vuestra clave. Estamos usando el modelo "gpt-4o-mini" que es muy económico.
Ya hemos incluido la Clase TChatgpt para el próximo build de FWH.

Image
buildit.prg
Code: Select all  Expand view  RUN
#include "FiveWin.ch"

// get your OpenAI key from https://platform.openai.com/api-keys
static cKey := "sk-proj-..."  
static oChatgpt
static oTree
static cCategory := "                              "

function Main()

    local oWnd, oExplBar, oAppPanel, oExplPanel, oWebView

    oChatgpt = TChatgpt():New( cKey )

    DEFINE WINDOW oWnd TITLE "Build it"

    oExplBar = TExplorerBar():New( 0, 82, 480, 100, oWnd:oLeft, CLR_WHITE, RGB( 31, 31, 31 ) )
    oWnd:oLeft = oExplBar

    oExplPanel = oExplBar:AddPanel( "AI assistant" )
    oExplPanel:AddLink( "what is this app about ?",;
                        { || If( MsgGet( "App category", "Please specify it", @cCategory ), AddOptions( cCategory, oExplBar ),) } )
    oExplPanel:AddLink( "Add options to selected item", { || AddSubOptions() } )

    oWnd:oClient = TPanel():New( 0, 0, 100, 100, oWnd )

    oWebView = TWebView2():New( oWnd:oClient )
    oWebView:Navigate( "https://www.google.com" )

    ACTIVATE WINDOW oWnd MAXIMIZED ;
       ON RESIZE ( oWebView:SetSize( nWidth - oExplBar:nWidth, nHeight ), oExplBar:SetSize( 480, nHeight ) )

return nil    

function AddOptions( cCategory, oExplBar )

   local cOptions, aOptions, cOption, oAppPanel

   oChatgpt:cPrompt := "genera una lista separada por comas con las opciones de una aplicación de " + AllTrim( cCategory ) + ;
                        ". No des ninguna explicación"
   oChatgpt:Send()

   cOptions = oChatgpt:GetValue( "choices", "message", "content" )
   aOptions = hb_ATokens( cOptions, "," )

   oAppPanel = oExplBar:AddPanel( cCategory,, 700 )
   oTree = TTreeView():New( 2.5, 2, oAppPanel,,,,, 423, 675 )

   for each cOption in aOptions
      oTree:Add( cOption )
   next  
   
return nil    

function AddSubOptions()

   local oItem
   local cOption := If( ( oItem := oTree:GetSelected() ) != nil, oItem:cPrompt, "" )
   local cOptions, cSubOption, aOptions

   if ! Empty( cOption )
      oChatgpt:cPrompt := "genera una lista separada por comas con las opciones de " + cOption + ;
                          " para una aplicación de " + cCategory + ". No des ninguna explicación"
      oChatgpt:Send()

      cOptions = oChatgpt:GetValue( "choices", "message", "content" )
      aOptions = hb_ATokens( cOptions, "," )

      for each cSubOption in aOptions
        oItem:Add( cSubOption )
      next  

      oItem:Expand()
   endif  

return nil    

chatgpt.prg
Code: Select all  Expand view  RUN
#include "FiveWin.ch"
#include "hbcurl.ch"

//----------------------------------------------------------------------------//

CLASS TChatgpt

    DATA   cKey AS CHARACTER  INIT ""
    DATA   hCurl
    DATA   nHttpCode
    DATA   nError             INIT 0
 
    DATA   cResponse
    DATA   cPrompt

    DATA   cModel             INIT "gpt-4o-mini"
    DATA   cUrl               INIT "https://api.openai.com/v1/chat/completions"
 
    METHOD New( cKey )
    METHOD End()
    METHOD Send()
    METHOD Reset()
    METHOD GetValue( ... )
 
 ENDCLASS
 
//----------------------------------------------------------------------------//
 
 METHOD New( cKey ) CLASS TChatgpt

    ::cKey := cKey
    ::hCurl := curl_easy_init()
 
 return Self
 
//----------------------------------------------------------------------------//

METHOD Send() CLASS TChatgpt

    local aheaders, nHttpCode, cJson, h := { => }, hMessage := { => }
 
    curl_easy_setopt( ::hCurl, HB_CURLOPT_POST, .T. )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, ::cUrl )
     
    aheaders := { "Content-Type: application/json", ;
                  "Authorization: Bearer " + ::cKey }
   
    curl_easy_setopt( ::hCurl, HB_CURLOPT_HTTPHEADER, aheaders )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_USERNAME, '' )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_DL_BUFF_SETUP )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .F. )

    hb_HSet( h, "model", ::cModel )
    hb_HSet( hMessage, "role", "user" )
    hb_HSet( hMessage, "content", ::cPrompt )
    h["messages"] = { hMessage }
 
    cJson = hb_jsonEncode( h )  
    curl_easy_setopt( ::hcurl, HB_CURLOPT_POSTFIELDS, cJson )
 
    ::nError = curl_easy_perform( ::hCurl )
    curl_easy_getinfo( ::hCurl, HB_CURLINFO_RESPONSE_CODE, @nHttpCode )
 
    ::nHttpCode = nHttpCode
 
    if ::nError == HB_CURLE_OK
       ::cResponse = curl_easy_dl_buff_get( ::hCurl )
    else
    endif
 
return ::cResponse            
 
//----------------------------------------------------------------------------//
 
 METHOD Reset() CLASS TChatgpt
     
    curl_easy_reset( ::hCurl )
    ::nError := HB_CURLE_OK
    ::cResponse := nil
 
 return nil
 
//----------------------------------------------------------------------------//
 
 METHOD End() CLASS TChatgpt

    curl_easy_cleanup( ::hCurl )
    ::hCurl := nil  
 
 return nil
 
//----------------------------------------------------------------------------//

METHOD GetValue( ... ) CLASS TChatgpt

   local aKeys  := hb_AParams(), cKey
   local uValue := hb_jsonDecode( ::cResponse )

   for each cKey in aKeys
      if ValType( uValue[ cKey ] ) == "A"
         uValue = uValue[ cKey ][ 1 ]
      else    
         uValue = uValue[ cKey ]
      endif  
   next  
       
return uValue

//----------------------------------------------------------------------------//
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42118
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Webview 2 + Html

Postby Antonio Linares » Wed Sep 25, 2024 4:53 am

Image
Image
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42118
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Next

Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 48 guests