// BIBLIOTECAS NECESSÁRIAS #Include "TOTVS.ch" #Include "FWMVCDEF.ch" // FUNÇÃO PRINCIPAL User Function T172MONIT() Local aArea := GetArea() // SALVA A ÁREA ANTERIOR Local oBrowse := FwLoadBrw("T172MONIT") // HERDA O NAVEGADOR // ATIVA E EXIBE O NAVEGADOR oBrowse:Activate() // APÓS A MANIPULAÇÃO, FECHA O ARQUIVO DE TRABALHO DbSelectArea(oBrowse:Alias()) DbCloseArea() // RESTAURA A ÁREA ANTERIOR RestArea(aArea) Return (NIL) // DEFINIÇÕES DO BROWSER (POSSÍVEL HERDAR) Static Function BrowseDef() Local cAlias := GetNextAlias() // GERA UM ALIAS ALEATÓRIO Local oBrowse := FwMBrowse():New() // OBJETO DO NAVEGADOR Local aTblAux := GenTableStr(cAlias) // ESTRUTURA DA TABELA TEMPORÁRIA Local oTable := aTblAux[1] // OBJETO DA TABELA TEMPORÁRIA Local aFields := aTblAux[2] // CAMPOS DA ESTRUTURA // CONFIGURAÇÕES DO NAVEGADOR oBrowse:SetAlias(cAlias) oBrowse:SetQueryIndex(GetTableInd(oTable)) oBrowse:SetTemporary(.T.) oBrowse:SetFields(aFields) oBrowse:DisableDetails() oBrowse:SetDescription("Monitor de Threads") oBrowse:SetMenuDef("T172MONIT") // oBrowse:SetTimer() // CONFIGURAR TIMER PARA ATUALIZAÇÃO Return (oBrowse) // OPERAÇÕES DA ROTINA (POSSÍVEL HERDAR) Static Function MenuDef() Local aRotina := {} // VETOR DE OPERAÇÕES // OPERAÇÕES DA ROTINA ADD OPTION aRotina TITLE "Desconectar" ACTION "U_DISCONN" OPERATION MODEL_OPERATION_DELETE ACCESS 0 ADD OPTION aRotina TITLE "Atualizar" ACTION "U_REFRESH" OPERATION MODEL_OPERATION_VIEW ACCESS 0 Return (aRotina) // CRIA A ESTRUTURA DA TABELA TEMPORÁRIA COM BASE // NO RETORNO DA FUNÇÃO GETUSERINFOARRAY() Static Function GenTableStr(cAlias) Local aFields := {} // VETOR DE CAMPOS DO BROWSER Local aTblFld := {} // VETOR DE CAMPOS DA TABELA Local oTable := FwTemporaryTable():New(cAlias) // OBJETO DA TABELA TEMPORÁRIA Local nX := 0 // CONTROLADOR DO LAÇO DE REPETIÇÃO // CAMPOS DA TABELA AAdd(aFields, {"Usuário", "TMP_USERID", "C", 30, 00}) AAdd(aFields, {"Módulo", "TMP_MODULE", "C", 10, 00}) AAdd(aFields, {"Rotina", "TMP_ROUTIN", "C", 40, 00}) AAdd(aFields, {"Função", "TMP_FUNCT", "C", 25, 00}) AAdd(aFields, {"Ambiente", "TMP_ENV", "C", 20, 00}) AAdd(aFields, {"Data", "TMP_DATE", "D", 08, 00}) AAdd(aFields, {"Hora", "TMP_TIME", "C", 08, 00}) AAdd(aFields, {"Id da Máquina", "TMP_COMPUT", "C", 30, 00}) AAdd(aFields, {"Thread", "TMP_THREAD", "N", 8, 00}) AAdd(aFields, {"Balance", "TMP_SERVER", "C", 20, 00}) For nX := 1 To Len(aFields) AAdd(aTblFld, {aFields[nX][2], aFields[nX][3], aFields[nX][4], aFields[nX][5]}) Next nX // INSERE OS CAMPOS NA TABELA TEMPORÁRIA oTable:SetFields(aTblFld) // ÍNDICES DA TABELA TEMPORÁRIA oTable:AddIndex("01", {"TMP_USERID"}) // ÍNDICE POR USUÁRIO oTable:AddIndex("02", {"TMP_DATE", "TMP_TIME"}) // ÍNDICE POR DATE E HORA oTable:AddIndex("03", {"TMP_FUNCT"}) // ÍNDICE POR FUNÇÃO oTable:AddIndex("04", {"TMP_MODULE"}) // ÍNDICE POR MÓDULO oTable:AddIndex("05", {"TMP_ROUTIN"}) // ÍNDICE POR ROTINA oTable:AddIndex("06", {"TMP_SERVER"}) // ÍNDICE SERVIDOR (BALANCE) // CRIA A TABELA oTable:Create() // PREENCHE A TABELA COM DADOS FillTable(cAlias) Return ({oTable, aFields}) // RETORNA O ÍNDICE JÁ CRIADO NA TABELA TEMPORÁRIA // **NÃO É NECESSÁRIO ALTERAR O COMPORTAMENTO Static Function GetTableInd(oTable) Local aIndex := {} // ÍNDICES PARA ENVIO AO BROWSER Local aIndAux := oTable:oStruct:GetIndexes() // ÍNDICES JÁ CRIADOS NA TABELA Local cIndAux := "" // AUXILIAR DA MONTAGEM DOS ÍNDICES DO BROWSER Local nX := 0 // CONTROLADOR DO LAÇO DE REPETIÇÃO // LAÇO DE REPETIÇÃO PARA MONTAGEM DO ÍNDICE DO BROWSER For nX := 1 To Len(aIndAux) AEval(aIndAux[nX][2], {|cIndex| cIndAux += cIndex + "+"}) AAdd(aIndex, SubStr(cIndAux, 1, Len(cIndAux) - 1)) cIndAux := "" Next nX Return (aIndex) // REALIZA O PREENCHIMENTO DA TABELA TEMPORÁRIA COM // BASE NO RETORNO DA FUNÇÃO GETUSERINFOARRAY() Static Function FillTable(cAlias) Local aMonitor := GetUserInfoArray() // DADOS DE CONEXÃO DE TODAS AS THREADS Local nX := 0 // CONTROLADOR DO LAÇO DE REPETIÇÃO // SELECIONA A ÁREA PARA NÃO PRECISAR APONTAR DbSelectArea(cAlias) // GRAVA OS DADOS RETORNADOS PELA FUNÇÃO GETUSERINFOARRAY() For nX := 1 To Len(aMonitor) // REMOVE ANOTAÇÕES DE SIGAMDI If (!AllTrim(aMonitor[nX][5]) == "SIGAMDI") RecLock(cAlias, .T.) TMP_USERID := aMonitor[nX][1] TMP_COMPUT := aMonitor[nX][2] TMP_THREAD := aMonitor[nX][3] TMP_SERVER := aMonitor[nX][4] TMP_FUNCT := aMonitor[nX][5] TMP_ENV := aMonitor[nX][6] TMP_DATE := GetDate(aMonitor[nX][7]) TMP_TIME := SubStr(aMonitor[nX][7], At(":", aMonitor[nX][7]) - 2, 8) TMP_MODULE := IIf(!SubStr(aMonitor[nX][11], 1, 3) == "###", AllTrim(SubStr(aMonitor[nX][11], At("SIGA", aMonitor[nX][11]), 8)), "TDS") TMP_ROUTIN := IIf(!SubStr(aMonitor[nX][11], 1, 3) == "###", AllTrim(SubStr(aMonitor[nX][11], At("Obj ", aMonitor[nX][11]) + 5, Len(aMonitor[nX][11]))), aMonitor[nX][11]) MsUnlock() EndIf Next nX // POSICIONA NO INÍCIO DO ARQUIVO DbGoTop() Return (NIL) // MONTA A DATA CONFORME STRING RETORNADA // PELA FUNÇÃO GETUSERINFOARRAY() Static Function GetDate(cDtMonitor) Local cDate := SubStr(cDtMonitor, 1, Len(cDtMonitor) - 1) // EXTRAI A DATA SEM O SALTO DE LINHA Local cMonth := SubStr(cDate, 5, 3) // EXTRAI O MÊS Local cDay := StrZero(Val(SubStr(cDate, 9, 2)), 2) // EXTRAI O DIA Local cYear := SubStr(cDate, Len(cDate) - 3) // EXTRAI O ANO Local dDate := dDataBase // INICIA A DATA // TRANSFORMA OS TRÊS CARACTERES DO MÊS NO NÚMERO CORRESPONDENTE Do Case Case (cMonth == SubStr(CMonth(CToD("02/01/2019")), 1, 3)) cMonth := "01" Case (cMonth == SubStr(CMonth(CToD("02/02/2019")), 1, 3)) cMonth := "02" Case (cMonth == SubStr(CMonth(CToD("02/03/2019")), 1, 3)) cMonth := "03" Case (cMonth == SubStr(CMonth(CToD("02/04/2019")), 1, 3)) cMonth := "04" Case (cMonth == SubStr(CMonth(CToD("02/05/2019")), 1, 3)) cMonth := "05" Case (cMonth == SubStr(CMonth(CToD("02/06/2019")), 1, 3)) cMonth := "06" Case (cMonth == SubStr(CMonth(CToD("02/07/2019")), 1, 3)) cMonth := "07" Case (cMonth == SubStr(CMonth(CToD("02/08/2019")), 1, 3)) cMonth := "08" Case (cMonth == SubStr(CMonth(CToD("02/09/2019")), 1, 3)) cMonth := "09" Case (cMonth == SubStr(CMonth(CToD("02/10/2019")), 1, 3)) cMonth := "10" Case (cMonth == SubStr(CMonth(CToD("02/11/2019")), 1, 3)) cMonth := "11" Case (cMonth == SubStr(CMonth(CToD("02/12/2019")), 1, 3)) cMonth := "12" EndCase // MONTA A DATA CONFORME DIA, MÊS E ANO dDate := CTod(cDay + "/" + cMonth + "/" + cYear) Return (dDate) // ENCERRA A CONEXÃO DE UM USUÁRIO User Function Disconn(cAlias, nReg, nOpc) // POSICIONA NA TABELA E NO REGISTRO ESCOLHIDO DbSelectArea(cAlias) DbGoTo(nReg) If (!ThreadID() == TMP_THREAD) // FINALIZA A CONEXÃO DO USUÁRIO If (KillUser(AllTrim(TMP_USERID), AllTrim(TMP_COMPUT), TMP_THREAD, AllTrim(TMP_ENV)) != NIL) MsgInfo("Usuário " + AllTrim(TMP_USERID) + " desconectado da thread " + CValToChar(TMP_THREAD) + " com sucesso!") // ATUALIZA A GRID DE DADOS U_Refresh(cAlias, nReg, nOpc) Else MsgInfo("Não foi possível desconectar o usuário " + AllTrim(TMP_USERID) + " da thread " + CValToChar(TMP_THREAD)) EndIf Else // MENSAGEM CASO O USUÁRIO TENTE DESCONECTAR A THREAD EM USO MsgInfo("Não foi possível realizar a desconexão da thread atual") EndIf Return (NIL) // ATUALIZA A GRID DE DADOS User Function Refresh(cAlias, nReg, nOpc) // POSICIONA NO INÍCIO DbSelectArea(cAlias) DbGoTop() // DELETA OS REGISTROS While(!EOF()) RecLock(cAlias, .F.) DbDelete() MsUnlock() DbSkip() End // PREENCHE A TABELA COM NOVOS VALORES FillTable(cAlias) Return (NIL)