Hola a todos
Yo trabajo en una oficina. Desarrollador de software. Y a veces como. Si todos los dias. El empleador nos proporciona almuerzos: los trabajadores ordenan el almuerzo para mañana y mañana el proveedor de almuerzos trae lo que los empleados ordenaron. Lo que se ordenó y lo que se trajo no siempre coincide, pero este no es el caso. El almuerzo se ordena en la página de orden de almuerzo. Pero ...
Pero primero, sobre cómo se forma la página de pedido de almuerzo: el proveedor envía un archivo XLS con una lista de precios durante una semana.
Ejemplo de lista de precios enviada por el proveedorLa persona responsable de las cenas analiza a través de una utilidad desarrollada por alguien en las entrañas de nuestra empresa, traduciéndola en una forma que nuestro portal corporativo puede mostrar. Y lo muestra ...
Captura de pantalla con cenas ordenadas
Captura de pantalla de la página de pedidos de almuerzo.Las posiciones se dividen incómodamente en categorías. La información sobre el nombre y la composición está en texto completo y es difícil de navegar.
Quiero entender que es mejor no ordenar, y lo que puedes probar, porque a otros les gusta. Es decir, quiero una calificación. También quiero recibir mi pedido en Telegram para no recordar lo que ordené en el comedor.
Entonces los objetivos son claros. Debo decir de inmediato: el camino que mi colega y yo hemos tomado está lejos de ser el más correcto y racional. Aun así: es un juego completo en términos de arquitectura / seguridad / soporte / tolerancia a fallos. Pero lo que ha crecido ha crecido.
No tenemos acceso al servidor, por lo que solo puede cambiar la apariencia de la página con scripts de usuario. ¿Pero qué hay de la calificación? Tampoco hay acceso a la base de datos. Bueno, necesitamos un servidor para el procesamiento de pedidos, calificación e interacción con Telegram. Esta función fue tomada por el servidor NodeJS.
Lado del servidor
Yo me ocuparé del servidor, y un colega se encargará de un script de usuario que agrega funcionalidad a la página. Tomamos el servidor nodejs, conectamos express, agregamos MySQL.
Poner Sequelize en la parte superior . E interactuaremos con Telegram a través de
node-telegram-bot-api :
Brevemente sobre la funcionalidad:
La ruta
/ dinners / user_menu devuelve un script de usuario:
res.sendFile(__dirname + '/public_html/user_script.js');
Esto se hace para no distraer a los colegas que lo usan instalando una nueva versión del script. Se corrigió, lo lanzó al servidor, todos se actualizaron.
Sí, sé que desde un punto de vista de seguridad esto es malo, pero la funcionalidad en sí misma no es crítica y consideraremos que el servidor en el que se almacena el script es bastante seguro.
Además, a lo largo de la ruta
/ dinners / r /: id, puede obtener una calificación para todas las posiciones y guardar la calificación, es decir, votar por los platos.
La ruta
/ dinners / reenviar /: id sirve para enviar un mensaje a Telegram. El texto del mensaje se genera en el cliente, solo se produce interacción con Telegram en el servidor:
const parseMode: TelegramBot.SendMessageOptions = {parse_mode: "HTML"}; await this.bot.sendMessage(telegramId, htmlMessage, {...options, ...parseMode});
Después de eso, el Bot envía un mensaje con la orden.

A continuación, a lo largo de la ruta
/ cenas / orden , se guarda la
orden . Dado que la solicitud de pedido original es difícil de determinar (después de hacer clic en el botón "Guardar", aparece una alerta con el botón de confirmación de pedido), se envía una solicitud al servidor con pedidos cuando se carga la página de pedidos (y todo el sistema de pedidos en el sitio se divide en 2 páginas: la página de pedidos y la página de menú - selección de platos para un día específico, es decir, la formación del pedido). No es racional enviar solicitudes cada vez que ingresa a la página de pedido, pero no había una mejor opción para un complemento.
Finalmente, la ruta
/ dinners / days establece los días para ordenar el almuerzo. Esta parte de la funcionalidad ha aparecido para el correcto funcionamiento de los recordatorios sobre un pedido inacabado: debe saber cuál es el próximo día del pedido (hay fines de semana y feriados a mediados de la semana). En lugar de tomar la implementación del calendario de producción, simplemente analizo las fechas en la página de pedido, donde los días laborables y no laborables ya están marcados (no puede hacer un pedido para un día no laborable). Los días no laborables están marcados en el portal con la clase isHoliday:
Oh sí, usa jquery para recoger. Es muy conveniente profundizar en el árbol de páginas.
Telegram bot
Otra parte de todo el complemento es el bot de telegramas.
Con tal funcionalidadObtener una identificación es un sistema de identificación de este tipo. Para asociar un script de usuario en un navegador específico con userId en telegrama.
Vea el pedido de hoy, vea la lista de pedidos (últimos 5), establezca un recordatorio.
El almuerzo se envía automáticamente al proveedor a la misma hora todos los días, por lo que es importante realizar un pedido antes de una determinada hora, por ejemplo, a las 13:00.
Después de eso, se bloquea la capacidad de realizar un pedido.
Recordatorios:
El bot brinda la oportunidad de elegir un recordatorio: 9, 10 u 11 horas.Además, si después de un recordatorio no realizó un pedido, cada 10 minutos siguientes el bot le recordará el pedido hasta que lo solicite o hasta que el pedido esté bloqueado.
Esto se hace mediante la tarea cron (usando
node-schedule ):
schedule.scheduleJob('*/10 9-13 * * 1-5', async function() {
Parte del cliente. Menu
Repito que la interfaz actual junto con el texto de los elementos del menú que envía el proveedor es simplemente horrible (ver pantalla 2). Y en un momento, dejas de ver nada en toneladas de texto monótono sólido y poco útil.
Después de buscar a través de Internet que podría ayudarnos, encontramos un complemento bastante bueno para los scripts personalizados de Greasemonkey, y decidieron usarlo.
En primer lugar, creamos un script de usuario y le damos el derecho de comunicarse con el portal corporativo y el servidor, en el que se atornillan la calificación y la capacidad de enviar solicitudes
Además, para modificar la página del almuerzo, usamos jQuery, conectándolo usando
// @requireAhora comencemos palear la página del almuerzo. Después de mirar el código html de la página, encontramos el identificador de la mesa del almuerzo, obtenemos la tabla y la modificamos.
const table = $(".dinner__innerData"); const categoryList = [];
Quiero señalar que en la página de formación del almuerzo, al calcular el monto del pedido, se considera en todas las filas de la tabla, recibiendo el número del artículo pedido multiplicado por el precio. Por estas razones, si agrega una fila con el nombre de la categoría, todo se romperá ... Tuve que ingresar columnas ocultas con cantidad y cantidad cero para esta fila.
Ahora pasemos a limpiar el texto y agregar información sobre la calificación del plato. Primero, algunas funciones auxiliares. El plato en la clasificación se identifica por su nombre sin basura en forma de gramos, puntuación y espacios. Es decir, un plato llamado “Caldo de pollo con huevo (caldo de pollo, zanahorias, cebollas, huevos, verduras). En 100 g: proteínas-3.43; grasas-2.86; carbohidratos-1.0; en.value-43.39kcal (200gr) "se identifica como" cuajada de caldo ". Esto se debe al hecho de que el proveedor puede arrastrarse en espacios adicionales, letreros y algo más. Como la práctica ha demostrado, esto fue suficiente para identificar con precisión el plato en el 90% de los casos, y decidimos no molestarnos e ingresar una búsqueda de texto completo.
function findByName(items, tdText) { tdText = clearTrash(tdText, true, true, true); return items.find(({clear_name}) => { return clear_name.trim().toLowerCase() === tdText; }); } function clearTrash(text, clearDescr, clearGrams, clearSymbols) {
Y esta es la formación de una calificación:
const table = $(".dinner__innerData"); const nameTd = $(table).find(“tr td:nth-child(2)”); for (let index = 0; index <= nameTd.length; index++) { const tdText = $(nameTd[index]).text();
Y eso es lo que pasó.
De acuerdo, mucho más agradable y más conveniente?Parte del cliente. Votar
A continuación, pasaremos a agregar la capacidad de votar por los platos ordenados, así como a enviar un mensaje con la orden a Telegram.
Página con pedidos sin guiónEn la página de platos ordenados, agregue la calificación:
async function addRatingForm() { const table = $(".dinner__innerData"); const nameTd = $(table).find("tr td:nth-child(1)");
Y esto es lo que obtuvimos en la salida:

Sí, el código es terrible. Sí, no optimizado. Y sí, en algunos lugares ilógico. Pero el tiempo empleado fue mínimo, y la funcionalidad y la conveniencia aumentaron significativamente.
El objetivo era hacer que ordenar la cena fuera más agradable para mí y para mis camaradas, y este objetivo, en mi opinión, se logró.