X3D_Web / code.gs
Edoruin's picture
add dbs
2a86d2e
// Script para Google Sheets con visor 3D interactivo y gesti贸n de productos/pedidos
// Hojas: "Productos" y "Pedidos"
// Variables globales
var productosSheet = "Productos";
var pedidosSheet = "Pedidos";
var productosData = [];
var stlFiles = {};
var currentColor = "#000000";
var currentModel = null;
// Inicializar al abrir el documento
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('3D Viewer')
.addItem('Agregar al carrito', 'addToCart')
.addSeparator()
.addItem('Limpiar carrito', 'clearCart')
.addToUi();
// Cargar datos de productos
loadProducts();
// Inicializar visor 3D
init3DViewer();
}
// Cargar productos desde la hoja de c谩lculo
function loadProducts() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(productosSheet);
if (!sheet) return;
var data = sheet.getDataRange().getValues();
productosData = [];
for (var i = 1; i < data.length; i++) {
if (data[i][0] && data[i][1]) {
productosData.push({
nombre: data[i][0],
precio: data[i][1],
vida: data[i][2],
inventario: data[i][3],
id: data[i][4]
});
}
}
Logger.log('Productos cargados: ' + productosData.length);
}
// Inicializar visor 3D
function init3DViewer() {
// Crear HTML para el visor
var html = HtmlService.createHtmlOutputFromFile('viewer')
.setWidth(400)
.setHeight(400);
SpreadsheetApp.getUi().showModelessDialog(html, 'Visor 3D');
}
// Funci贸n para agregar al carrito
function addToCart(productName, quantity, client) {
// Buscar el producto
var product = productosData.find(p =>
p.nombre.toLowerCase() === productName.toLowerCase()
);
if (!product) {
SpreadsheetApp.getUi().alert('Producto no encontrado: ' + productName);
return;
}
if (product.inventario <= 0) {
SpreadsheetApp.getUi().alert('Producto sin inventario: ' + productName);
return;
}
// Agregar a la hoja de pedidos
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(pedidosSheet);
if (!sheet) {
SpreadsheetApp.getUi().alert('Hoja de pedidos no encontrada');
return;
}
sheet.appendRow([
product.nombre,
quantity,
client,
product.inventario,
product.id
]);
// Actualizar inventario
updateInventory(product.nombre, -quantity);
SpreadsheetApp.getUi().alert('Producto agregado al carrito: ' + product.nombre);
}
// Actualizar inventario
function updateInventory(productName, quantity) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(productosSheet);
if (!sheet) return;
var data = sheet.getDataRange().getValues();
for (var i = 1; i < data.length; i++) {
if (data[i][0] && data[i][0].toLowerCase() === productName.toLowerCase()) {
var currentInv = parseInt(data[i][3]) || 0;
var newInv = currentInv + quantity;
sheet.getRange(i+1, 4).setValue(newInv);
break;
}
}
}
// Limpiar carrito (eliminar 煤ltimas filas de pedidos)
function clearCart() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(pedidosSheet);
if (!sheet) return;
var lastRow = sheet.getLastRow();
if (lastRow > 1) {
sheet.deleteRows(2, lastRow - 1);
SpreadsheetApp.getUi().alert('Carrito limpiado');
}
}
// Cargar STL files (simulado - en producci贸n conectar铆a con Google Drive o base de datos)
function loadSTLFiles() {
// Esta funci贸n simula la carga de archivos STL
// En producci贸n, conectar铆a con Google Drive API o base de datos
stlFiles = {
'greca': 'data/stl/greca.stl',
'minimalista': 'data/stl/minimalista.stl',
'cl谩sico': 'data/stl/cl谩sico.stl',
'moderno': 'data/stl/moderno.stl'
};
Logger.log('STL files cargados: ' + Object.keys(stlFiles).length);
}
// Cambiar color del modelo 3D
function changeColor(color) {
currentColor = color;
// Enviar mensaje al visor para actualizar color
var app = UiApp.getActiveApplication();
if (app) {
app.getElementById('modelColor').setStyleAttribute('color', color);
}
SpreadsheetApp.getUi().showModelessDialog(
HtmlService.createHtmlOutput(
'<div id="modelColor" style="color:' + color + '">Color actualizado</div>'
).setWidth(200).setHeight(100),
'Color'
);
}
// Cargar modelo espec铆fico
function loadModel(modelName) {
currentModel = modelName;
// En producci贸n, cargar铆a el STL correspondiente
Logger.log('Cargando modelo: ' + modelName);
}
// Funci贸n para el visor HTML (contenido del archivo viewer.html)
function getViewerHTML() {
return `
<!DOCTYPE html>
<html>
<head>
<title>Visor 3D Interactivo</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
body {
margin: 0;
padding: 10px;
background: #f0f0f0;
font-family: Arial, sans-serif;
}
#viewer {
width: 100%;
height: 300px;
border: 1px solid #ccc;
background: #ffffff;
}
.color-picker {
display: flex;
gap: 5px;
margin-top: 10px;
}
.color-btn {
width: 30px;
height: 30px;
border: none;
border-radius: 50%;
cursor: pointer;
}
</style>
</head>
<body>
<h3>Visor 3D - Selecciona un modelo</h3>
<div id="viewer"></div>
<div class="color-picker">
<button class="color-btn" style="background: #000000" onclick="selectColor('#000000')"></button>
<button class="color-btn" style="background: #ff0000" onclick="selectColor('#ff0000')"></button>
<button class="color-btn" style="background: #00ff00" onclick="selectColor('#00ff00')"></button>
<button class="color-btn" style="background: #0000ff" onclick="selectColor('#0000ff')"></button>
<button class="color-btn" style="background: #ffff00" onclick="selectColor('#ffff00')"></button>
<button class="color-btn" style="background: #ff00ff" onclick="selectColor('#ff00ff')"></button>
<button class="color-btn" style="background: #00ffff" onclick="selectColor('#00ffff')"></button>
</div>
<script>
let scene, camera, renderer, model;
let currentColor = '#000000';
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
camera.position.z = 5;
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(380, 280);
document.getElementById('viewer').appendChild(renderer.domElement);
// Crear grid
const gridHelper = new THREE.GridHelper(10, 10);
scene.add(gridHelper);
animate();
}
function animate() {
requestAnimationFrame(animate);
if (model) {
model.rotation.y += 0.01;
}
renderer.render(scene, camera);
}
function selectColor(color) {
currentColor = color;
if (model) {
model.traverse((child) => {
if (child.isMesh) {
child.material.color.set(color);
}
});
}
google.script.run.withSuccessHandler(function() {}).changeColor(color);
}
function loadModel(modelName) {
// Simular carga de modelo
if (model) {
scene.remove(model);
}
// Crear modelo simple para demostraci贸n
const geometry = new THREE.BoxGeometry(2, 2, 2);
const material = new THREE.MeshPhongMaterial({
color: currentColor,
shininess: 100
});
model = new THREE.Mesh(geometry, material);
scene.add(model);
// A帽adir luz
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(10, 10, 10);
scene.add(pointLight);
google.script.run.withSuccessHandler(function() {}).loadModel(modelName);
}
// Inicializar al cargar
window.onload = function() {
init();
// Cargar un modelo por defecto
loadModel('greca');
};
</script>
</body>
</html>
`;
}
// Funci贸n para obtener HTML del visor (llamada desde Google Sheets)
function showViewer() {
var html = HtmlService.createHtmlOutput(getViewerHTML())
.setWidth(420)
.setHeight(450);
SpreadsheetApp.getUi().showModelessDialog(html, 'Visor 3D');
}