Olá pessoal.
Eu trabalho em um escritório. Desenvolvedor de software. E às vezes eu como. Sim todos os dias. O empregador nos fornece almoços - os trabalhadores pedem o almoço para amanhã e, amanhã, o fornecedor de almoços traz o que os funcionários pediram. O que foi pedido e o que foi trazido nem sempre coincide, mas esse não é o caso. O almoço é encomendado na página de pedidos do almoço. Mas ...
Mas primeiro, sobre como a página de pedido de almoço é formada: o fornecedor envia um arquivo XLS com uma lista de preços por uma semana.
Exemplo de lista de preços enviada pelo fornecedorA pessoa responsável pelos jantares analisa através de um utilitário desenvolvido por alguém nas entranhas da nossa empresa, traduzindo-o em uma forma que nosso portal corporativo pode exibir. E ele exibe ...
Captura de tela com jantares solicitados
Captura de tela da página de pedidos de almoçoAs posições são desconfortavelmente divididas em categorias. As informações sobre o nome e a composição estão em texto completo e são difíceis de navegar.
Quero entender que é melhor não pedir e o que você pode tentar, porque outros gostam. Ou seja, eu quero uma classificação. Também quero receber meu pedido no Telegram para não me lembrar do que pedi na sala de jantar.
Portanto, os objetivos são claros. Devo dizer imediatamente: o caminho que eu e meu colega seguimos está longe de ser o mais correto e racional. Mesmo assim: é um jogo completo em termos de arquitetura / segurança / suporte / tolerância a falhas. Mas o que cresceu cresceu.
Como não temos acesso ao servidor, você só pode alterar a aparência da página com scripts do usuário. Mas e a classificação? Também não há acesso ao banco de dados. Bem, precisamos de um servidor para processamento, classificação e interação com o Telegram. Esta função foi assumida pelo servidor NodeJS.
Lado do servidor
Eu cuidarei do servidor e um colega cuidará de um script de usuário que adiciona funcionalidade à página. Tomamos o servidor nodejs, conectamos express, adicionamos MySQL.
Coloque Sequelize em cima . E interagiremos com o Telegram através do
node-telegram-bot-api :
Brevemente sobre a funcionalidade:
O caminho
/ jantares / usuário_menu retorna um script de usuário:
res.sendFile(__dirname + '/public_html/user_script.js');
Isso é feito para não distrair os colegas que o utilizam instalando uma nova versão do script. Corrigido - jogou no servidor - todos atualizados.
Sim, eu sei que, do ponto de vista da segurança, isso é ruim, mas a funcionalidade em si não é crítica e consideraremos o servidor no qual o script está armazenado bastante seguro.
Além disso, no caminho
/ jantares / r /: id, você pode obter uma classificação para todas as posições e salvar a classificação, ou seja, votar nos pratos.
O caminho
/ jantares / reenviar /: id serve para enviar uma mensagem ao Telegram. O texto da mensagem é gerado no cliente, apenas a interação com o Telegram ocorre no servidor:
const parseMode: TelegramBot.SendMessageOptions = {parse_mode: "HTML"}; await this.bot.sendMessage(telegramId, htmlMessage, {...options, ...parseMode});
Depois disso, o Bot envia uma mensagem com o pedido.

Em seguida, ao longo do caminho
/ jantares / pedido , o
pedido é salvo. Como a solicitação de pedido original é difícil de determinar (após clicar no botão "Salvar", um alerta aparece com o botão de confirmação do pedido), uma solicitação ao servidor com pedidos é enviada quando a página do pedido é carregada (e todo o sistema de pedidos no site é dividido em 2 páginas - a página do pedido e a página do menu - seleção de pratos para um dia específico - ou seja, a formação do pedido). Não é racional enviar solicitações sempre que você entra na página do pedido, mas não havia opção melhor para um snap.
Finalmente, o caminho
/ jantares / dias define os dias nos quais pedir o almoço. Essa parte da funcionalidade apareceu para a operação correta dos lembretes sobre um pedido inacabado - você precisa saber qual é o próximo dia do pedido (há fins de semana e feriados no meio da semana). Em vez de adotar a implementação do calendário de produção, simplesmente analiso as datas na página do pedido, onde os dias úteis e não úteis já estão marcados (você não pode fazer um pedido para um dia não útil). Os dias não úteis são marcados no portal com a classe isHoliday:
Ah, sim, use jquery para escolher. É muito conveniente mergulhar na árvore de páginas.
Bot de telegrama
Outra parte de todo o complemento é o bot de telegrama.
Com essa funcionalidadeA obtenção de um ID é um sistema de identificação. Para associar um script de usuário em um navegador específico ao userId no telegrama.
Veja o pedido de hoje, veja a lista de pedidos (últimos 5), defina um lembrete.
O almoço é enviado automaticamente ao fornecedor na mesma hora todos os dias, por isso é importante fazer um pedido antes de um determinado horário, por exemplo, 13:00.
Depois disso, a capacidade de fazer um pedido é bloqueada.
Lembretes:
O bot oferece a oportunidade de escolher um horário de lembrete: 9, 10 ou 11 horas.Além disso, se após um lembrete você não fez um pedido, a cada 10 minutos seguintes o bot lembrará o pedido até você fazer o pedido ou até que o pedido seja bloqueado.
Isso é feito pela tarefa cron (usando o
nó-agendamento ):
schedule.scheduleJob('*/10 9-13 * * 1-5', async function() {
Parte do cliente. Menu
Repito que a interface atual em conjunto com o texto dos itens de menu que o fornecedor envia é péssima (consulte a tela 2). E, a certa altura, você para de ver algo em toneladas de texto sólido e monótono e pouco texto útil.
Depois de pesquisar na Internet que poderia nos ajudar, encontramos um bom plugin para scripts personalizados do Greasemonkey, e eles decidiram usá-lo.
Antes de tudo, criamos um script de usuário e damos o direito de se comunicar com o portal e o servidor corporativos, nos quais a classificação e a capacidade de enviar solicitações são fixadas
Além disso, para modificar a própria página do almoço, usamos o jQuery, conectando-o usando
// @requireAgora vamos começar a limpar a página do almoço. Tendo analisado o código html da página, encontramos o identificador da tabela de almoço, obtemos a tabela e a modificamos.
const table = $(".dinner__innerData"); const categoryList = [];
Quero observar que, na página de formação do almoço, ao calcular o valor do pedido, ele é considerado em todas as linhas da tabela, recebendo o número do item solicitado multiplicado pelo preço. Por esses motivos, se você adicionar uma linha com o nome da categoria, tudo irá quebrar ... Eu tive que inserir colunas ocultas com quantidade e quantidade zero para esta linha.
Agora vamos limpar o texto e adicionar informações sobre a classificação do prato. Primeiro, algumas funções auxiliares. O prato na classificação é identificado pelo nome, sem lixo na forma de gramas, sem pontuação e espaços. Ou seja, um prato chamado “Caldo de galinha com ovo (caldo de galinha, cenoura, cebola, ovos, verduras). Em 100 g: proteínas-3,43; gorduras-2,86; carboidratos-1,0; en.value-43,39kcal (200gr) "é identificado como" coalhada de caldo de carne ". Isso se deve ao fato de que o fornecedor pode se infiltrar em espaços extras, placas e outras coisas. Como a prática demonstrou, isso foi suficiente para identificar com precisão o prato em 90% dos casos, e decidimos não nos incomodar e inserir uma pesquisa 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) {
E esta é a formação de uma classificação:
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();
E foi o que aconteceu.
Concorda, muito melhor e mais conveniente?Parte do cliente. Votação
Em seguida, passaremos a adicionar a capacidade de votar nos pratos encomendados, além de enviar uma mensagem com o pedido ao telegrama.
Página com pedidos sem scriptNa página de pratos encomendados, adicione a classificação:
async function addRatingForm() { const table = $(".dinner__innerData"); const nameTd = $(table).find("tr td:nth-child(1)");
E aqui está o que obtivemos na saída:

Sim - o código é terrível. Sim - não otimizado. E sim - em alguns lugares ilógicos. Mas o tempo gasto foi no mínimo e a funcionalidade e a conveniência aumentaram significativamente.
O objetivo era tornar o jantar mais agradável para mim e meus companheiros, e esse objetivo, na minha opinião, foi alcançado.